org.ow2.jonas.web.base.proxy.HttpSocketHandler Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jonas-web-container-base Show documentation
Show all versions of jonas-web-container-base Show documentation
Abstract Web Container used by different implementations
/**
* JOnAS: Java(TM) Open Application Server
* Copyright (C) 2009 Bull S.A.S.
* Contact: [email protected]
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
* USA
*
* --------------------------------------------------------------------------
* $Id: HttpSocketHandler.java 18255 2009-08-14 12:02:04Z benoitf $
* --------------------------------------------------------------------------
*/
package org.ow2.jonas.web.base.proxy;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.rmi.RemoteException;
import java.util.Arrays;
import org.ow2.jonas.service.ServiceException;
import org.ow2.util.log.Log;
import org.ow2.util.log.LogFactory;
/**
* Class that is handling the client socket.
* @author Florent Benoit
*/
public class HttpSocketHandler implements Runnable {
/**
* Logger.
*/
private static Log logger = LogFactory.getLog(HttpSocketHandler.class);
/**
* Thread count.
*/
private static int counter = 0;
/**
* Link to the OnDemand service.
*/
private HttpOnDemandProxy onDemandProxy = null;
/**
* Client Socket.
*/
private Socket clientSocket = null;
/**
* Client socket input stream.
*/
private InputStream clientInputStream = null;
/**
* Client socket output stream.
*/
private OutputStream clientOutputStream = null;
/**
* Remote connection output stream.
*/
private OutputStream remoteOutputStream = null;
/**
* Remote connection input stream.
*/
private InputStream remoteInputStream = null;
/**
* A request has been sent to the web container in order to be started ?
*/
private boolean webContainerStartRequested = false;
/**
* Create a new handler for the given socket.
* @param onDemandProxy the http on demand proxy
* @param clientSocket the given client socket
* @throws HttpOnDemandProxyException if unable to get streams
*/
public HttpSocketHandler(final HttpOnDemandProxy onDemandProxy, final Socket clientSocket)
throws HttpOnDemandProxyException {
this.onDemandProxy = onDemandProxy;
this.clientSocket = clientSocket;
// Get client's input stream
try {
this.clientInputStream = clientSocket.getInputStream();
} catch (IOException e) {
throw new HttpOnDemandProxyException("Cannot get input stream", e);
}
// Get client's output stream
try {
this.clientOutputStream = clientSocket.getOutputStream();
} catch (IOException e) {
throw new HttpOnDemandProxyException("Cannot get output stream", e);
}
}
/**
* Analyze the request sent by the client.
* @throws HttpOnDemandProxyException if request cannot be analyzed
*/
protected void analyzeRequest() throws HttpOnDemandProxyException {
// Analyze stream in order to get the context
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
// The request has been found ?
boolean requestFound = false;
// Initialize data
int bytesRead;
byte[] buffer = new byte[128];
// First line submitted by the client
String firstLine = null;
try {
while (!requestFound && (bytesRead = clientInputStream.read(buffer)) > 0) {
// Search if we've the CRLF
String line = new String(buffer);
String[] splitLines = line.split("\r\n");
// Keep the analyzed bytes for later.
byteArrayOutputStream.write(buffer, 0, bytesRead);
// We've a first line, keep it ?
if (splitLines.length >= 1) {
firstLine = splitLines[0];
logger.debug("Request is: ''{0}''", firstLine);
requestFound = true;
}
}
} catch (IOException e) {
cleanup("Unable to handle request", e);
throw new ServiceException("Unable to handle request", e);
}
// Wrong request
if (firstLine == null || !requestFound) {
cleanup("Invalid header");
return;
}
// Analyse context asked
String[] args = firstLine.split(" ");
String contextValue = null;
String askedURL = null;
if (args.length > 1) {
// get second token (line is like : GET /myContext/.... HTTP1/0)
askedURL = args[1];
// Request should begin by a /
if (askedURL.startsWith("/")) {
// search the second / or go to the end
int index = askedURL.substring(1).indexOf("/");
if (index == -1) {
// take the whole part
contextValue = askedURL.substring(1);
} else {
// extract the part
contextValue = askedURL.substring(1, index + 1);
}
}
}
if (contextValue == null) {
logger.warn("Unable to find context in the given request ''{0}''", firstLine);
}
// Analyze the request and start the web container if not started or deploy the module if not started.
// Handle special requests
if ("jonasOnDemandProxy".equals(contextValue)) {
if ("/jonasOnDemandProxy/wait.gif".equals(askedURL)) {
sendWaitGif();
}
return;
}
// Check if web container is launched ?
if (!onDemandProxy.getWebContainerService().isInternalContainerStarted()) {
// Redirect to a page telling that web container is starting...
webContainerIsStarting();
// Start request not yet asked
synchronized (this) {
if (!webContainerStartRequested) {
webContainerStartRequested = true;
startWebContainer();
}
}
return;
}
// We know the context, check if it is available on our list
if (contextValue != null) {
logger.debug("Extracted context ''{0}'' from the line", contextValue, firstLine);
// managed by ourself
if (onDemandProxy.isAvailableContext(contextValue)) {
// Not yet deployed
if (!onDemandProxy.isContextDeployed(contextValue)) {
// Get Context info
ContextInfo contextInfo = onDemandProxy.getContextInfo(contextValue);
// needs to start or not the application ?
boolean startApplication = false;
// not yet send a start request ?
if (!contextInfo.isStarting()) {
startApplication = true;
contextInfo.setStarting(true);
}
// Redirect to a page telling that the context is starting...
contextIsStarting(contextValue);
// Needs to start the application
if (startApplication) {
// get war file
String warFile = contextInfo.getWarFile();
// start the context
try {
onDemandProxy.getWebContainerService().registerWar(warFile);
} catch (RemoteException e) {
cleanup("Unable to deploy application '" + warFile + "'.", e);
}
}
return;
}
}
}
// Now connect on the web container
Socket remoteServerSocket;
try {
remoteServerSocket = new Socket(onDemandProxy.getServerSocket()
.getInetAddress(), onDemandProxy.getRedirectPortNumber());
} catch (IOException e) {
// exception while connecting to the remote host
cleanup("Unable to connect to the remote host '" + onDemandProxy.getServerSocket()
.getInetAddress() + "' on the port number '" + onDemandProxy.getRedirectPortNumber() + "'", e);
return;
}
// Get streams of the remote host
try {
remoteOutputStream = remoteServerSocket.getOutputStream();
} catch (IOException e) {
cleanup("Unable to get remote stream of server socket '" + remoteServerSocket + "'", e);
return;
}
// remote input stream
try {
remoteInputStream = remoteServerSocket.getInputStream();
} catch (IOException e) {
cleanup("Unable to get remote stream of server socket '" + remoteServerSocket + "'", e);
return;
}
// Define a thread that will copy stream of the client to the remote stream
// It will first send the analyzed bytes, then it will send the remaining bytes
CopyingStream t = new CopyingStream(this, byteArrayOutputStream, clientInputStream, remoteOutputStream);
t.setName(t.getClass().getName() + "-" + (counter++));
t.start();
// Copy the answer of the remote host to the client.
byte[] buf = new byte[1024];
int count;
try {
while (((count = remoteInputStream.read(buf)) > 0)) {
clientOutputStream.write(buf, 0, count);
}
} catch (Exception e) {
cleanup("Unable to handle data from server to the client", e);
return;
}
cleanup();
}
public void cleanup() {
try {
if (clientInputStream != null) {
clientInputStream.close();
}
} catch (IOException e) {
logger.debug("Unable to close stream", e);
}
try {
if (clientOutputStream != null) {
clientOutputStream.close();
}
} catch (IOException e) {
logger.debug("Unable to close stream", e);
}
try {
if (remoteOutputStream != null) {
remoteOutputStream.close();
}
} catch (IOException e) {
logger.debug("Unable to close stream", e);
}
try {
if (remoteInputStream != null) {
remoteInputStream.close();
}
} catch (IOException e) {
logger.debug("Unable to close stream", e);
}
try {
clientSocket.close();
} catch (IOException e) {
logger.debug("Unable to close socket", e);
}
}
/**
* Send an error message.
* @param message the given error message
*/
public void cleanup(final String message) {
cleanup(message, null);
}
/**
* Send an error message with its exception
* @param message the given message
* @param exception the given exception
*/
public void cleanup(final String message, final Exception exception) {
HTTPResponse httpResponse = new HTTPResponse("HTTP/1.0 500");
httpResponse.println(message);
httpResponse.println("
");
if (exception != null) {
httpResponse.println(Arrays.asList(exception.getStackTrace()).toString());
}
sendBytesToClient(httpResponse);
}
/**
* Send the given response to the client.
* @param httpResponse the given response
*/
protected void sendBytesToClient(final HTTPResponse httpResponse) {
// write content
try {
clientOutputStream.write(httpResponse.getContent());
clientOutputStream.flush();
} catch (IOException ioe) {
logger.debug("Unable to send error message. Stream may be already closed.", ioe);
}
// Needs to shutdown streams
try {
clientSocket.shutdownOutput();
} catch (IOException e) {
logger.debug("Unable to close the socket", e);
}
}
/**
* Asked to start the web container
*/
protected void startWebContainer() {
onDemandProxy.startWebContainer();
}
/**
* Tell to the client that the web container is starting.
*/
protected void webContainerIsStarting() {
// Send to the client that the web container is starting...
HTTPResponse httpResponse = new HTTPResponse();
httpResponse.setRefresh(true);
String txt = "The HTTP Web Container is starting. Please wait.";
httpResponse.setTitle(txt);
txt = "
" + txt;
httpResponse.print(txt);
sendBytesToClient(httpResponse);
}
/**
* Send the wait gif
*/
protected void sendWaitGif() {
String waitGifResource = "/" + HttpSocketHandler.class.getPackage().getName().replace(".", "/") + "/wait.gif";
InputStream is = null;
// Send to the client the given gif
HTTPResponse httpResponse = new HTTPResponse();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try {
is = HttpSocketHandler.class.getClassLoader().getResourceAsStream(waitGifResource);
httpResponse.setContentType("image/gif");
httpResponse.setRefresh(true);
byte[] buf = new byte[1024];
int count;
try {
while (((count = is.read(buf)) > 0)) {
baos.write(buf, 0, count);
}
} catch (Exception e) {
logger.error("Cannot get data", e);
}
} finally {
try {
if (is != null) {
is.close();
}
} catch (IOException e) {
logger.debug("unable to close", e);
}
}
httpResponse.setBodyBytes(baos.toByteArray());
sendBytesToClient(httpResponse);
}
/**
* Tell to the client that the context is starting.
*/
protected void contextIsStarting(final String contextName) {
// Send to the client that the module is starting...
HTTPResponse httpResponse = new HTTPResponse();
httpResponse.setRefresh(true);
String txt = "The .war file associated with the context '/" + contextName + "' is loading. Please wait.";
httpResponse.setTitle(txt);
txt = "
" + txt;
httpResponse.print(txt);
sendBytesToClient(httpResponse);
}
/**
* Handle the request on the selected socket.
*/
public void run() {
try {
analyzeRequest();
} catch (HttpOnDemandProxyException e) {
logger.error("Unable to handle request", e);
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy