org.ow2.jonas.web.base.proxy.HttpOnDemandProxy 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: HttpOnDemandProxy.java 18169 2009-08-04 08:26:09Z benoitf $
* --------------------------------------------------------------------------
*/
package org.ow2.jonas.web.base.proxy;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;
import java.net.URL;
import java.rmi.RemoteException;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import org.ow2.jonas.service.ServiceException;
import org.ow2.jonas.web.JWebContainerServiceException;
import org.ow2.jonas.web.base.BaseWebContainerService;
import org.ow2.util.archive.api.ArchiveException;
import org.ow2.util.archive.api.IArchive;
import org.ow2.util.archive.impl.ArchiveManager;
import org.ow2.util.log.Log;
import org.ow2.util.log.LogFactory;
import org.ow2.util.xml.DocumentParser;
import org.ow2.util.xml.DocumentParserException;
import org.ow2.util.xml.XMLUtils;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
/**
* This class provides proxy mechanism.
* This is used to intercept requests and then start the web container or deploy the associated war file.
* @author Florent Benoit
*/
public class HttpOnDemandProxy implements Runnable {
/**
* Thread count (to be written in the Thread name).
*/
private static int counter = 0;
/**
* Logger.
*/
private static Log logger = LogFactory.getLog(HttpOnDemandProxy.class);
/**
* Web container service.
*/
private BaseWebContainerService webContainerService;
/**
* Port number.
*/
private int httpPortNumber = 0;
/**
* Redirect Port number.
*/
private int redirectPortNumber = 0;
/**
* Server socket (for handling clients).
*/
private ServerSocket serverSocket = null;
/**
* Infinite loop for waiting clients ?
*/
private boolean listeningClients = true;
/**
* Map between URL context and info about this context.
*/
private Map contextMapping = null;
/**
* Default constructor.
*/
public HttpOnDemandProxy() {
this.contextMapping = new HashMap();
}
/**
* Start the thread for this service.
*/
public void run() {
// infinite loop until that the service is stopped
while (this.listeningClients) {
// Accepting connections...
Socket socket;
try {
socket = serverSocket.accept();
} catch (IOException e) {
// Exception but if we're no longer listening, just exit
if (!listeningClients) {
break;
}
logger.error("Unable to accept connections", e);
continue;
}
// invalid client
if (socket == null) {
continue;
}
// Handle the request
HttpSocketHandler handler = null;
try {
handler = new HttpSocketHandler(this, socket);
} catch (HttpOnDemandProxyException e) {
logger.error("Unable to handle connection", e);
}
// Socket present, we can handle the connection
if (handler != null) {
// Handle the request in a separate thread
Thread thread = new Thread(handler);
thread.setName(handler.getClass().getName() + "-" + (counter++));
thread.start();
}
}
}
/**
* Start this component.
* @throws HttpOnDemandProxyException if start-up failed
*/
public void enable() throws HttpOnDemandProxyException {
// Create server socket
try {
this.serverSocket = new ServerSocket(httpPortNumber);
} catch (IOException e) {
throw new ServiceException("Cannot use the given port number '" + httpPortNumber + "'.", e);
}
// Reuse address
try {
serverSocket.setReuseAddress(true);
} catch (SocketException e) {
throw new ServiceException("Cannot set setReuseAddress mode", e);
}
// Start thread
new Thread(this).start();
// debug info
logger.debug("Listening on ''{0}'' port number", httpPortNumber);
}
/**
* Stop the component
* @throws HttpOnDemandProxyException service stopping failed
*/
public void disable() throws HttpOnDemandProxyException {
// We're no longer accepting clients
this.listeningClients = false;
// Stop the server socket
if (serverSocket != null) {
try {
serverSocket.close();
} catch (IOException e) {
logger.error("Unable to close server socket", e);
}
}
}
/**
* @return the http port number used by the proxy.
*/
public int getHttpPortNumber() {
return httpPortNumber;
}
/**
* Sets the proxy port number.
* @param httpPortNumber the proxy port number
*/
public void setHttpPortNumber(final int httpPortNumber) {
this.httpPortNumber = httpPortNumber;
}
/**
* @return the server socket
*/
public ServerSocket getServerSocket() {
return serverSocket;
}
/**
* Sets the web container service that is linked to this component.
* @param webContainerService the service instance
*/
public void setWebContainerService(final BaseWebContainerService webContainerService) {
this.webContainerService = webContainerService;
}
/**
* @return the web container service instance.
*/
public BaseWebContainerService getWebContainerService() {
return webContainerService;
}
/**
* Starts the web container.
* @throws JWebContainerServiceException if container is not started
*/
public void startWebContainer() throws JWebContainerServiceException {
webContainerService.startInternalWebContainer();
}
/**
* @return the redirect port number (internal web container port)
*/
public int getRedirectPortNumber() {
return redirectPortNumber;
}
/**
* Sets the redirect port number (internal web container port)
* @param redirectPortNumber given port number
*/
public void setRedirectPortNumber(final int redirectPortNumber) {
this.redirectPortNumber = redirectPortNumber;
}
/**
* Checks if the context is available (can be started or not)
* @param context the name of the context
* @return true if context is available
*/
public boolean isAvailableContext(final String context) {
return contextMapping.get(context) != null;
}
/**
* @param context the given context used to get info
* @return data on the given context (or null if not found)
*/
public ContextInfo getContextInfo(final String context) {
return contextMapping.get(context);
}
/**
* Checks if the context is ready to be called by clients
* @param context the given context name
* @return true if it is deployed
*/
public boolean isContextDeployed(final String context) {
ContextInfo contextInfo = contextMapping.get(context);
// true if not null and deployed
return contextMapping.get(context) != null && webContainerService.isWarLoaded(contextInfo.getWarFile());
}
/**
* Called by the deployer if this proxy is enabled. It will store the data for the given war file.
* @param warFile the given file to deploy
* @throws HttpOnDemandProxyException if the file cannot be registered
*/
public void addWar(final String warFile) throws HttpOnDemandProxyException {
// Check the file exists
File file = new File(warFile);
if (!file.exists()) {
throw new HttpOnDemandProxyException("The given war file '" + warFile + "' doesn't exists");
}
// Get the archive
IArchive archive = ArchiveManager.getInstance().getArchive(file);
if (archive == null) {
throw new HttpOnDemandProxyException("The given war file '" + warFile + "' is invalid");
}
// On-Demand Feature enabled in the jonas-web.xml file ?
boolean onDemandEnabled = false;
// Value of the context
String contextRoot = null;
URL webxmlURL = null;
try {
webxmlURL = archive.getResource("WEB-INF/jonas-web.xml");
if (webxmlURL != null) {
// There is an entry
// analyze the stream
InputStream is;
try {
is = webxmlURL.openStream();
} catch (IOException e) {
throw new HttpOnDemandProxyException("Cannot analyze the given war file", e);
}
// Get document
Document document;
try {
document = DocumentParser.getDocument(is, false, null);
} catch (DocumentParserException e) {
throw new HttpOnDemandProxyException("Cannot analyze the given war file", e);
}
// Root element =
Element jonasWebAppElement = document.getDocumentElement();
// get context-root if defined
contextRoot = XMLUtils.getStringValueElement(jonasWebAppElement, "context-root");
// get on-demand if defined
onDemandEnabled = Boolean.parseBoolean(XMLUtils.getStringValueElement(jonasWebAppElement, "on-demand"));
// Handle special case of root context
if ("/".equals(contextRoot)) {
contextRoot = "";
}
}
} catch (ArchiveException e) {
throw new HttpOnDemandProxyException("Cannot get resource from war file", e);
} finally {
archive.close();
}
// This archive has not enabled the on-demand feature in the jonas-web.xml file
// Deploy now the archive without onDemand mode
if (!onDemandEnabled) {
logger.debug("The war file ''{0}'' has not the on-demand flag enabled. WEB-INF/jonas-web.xml path is ''{1}''", file.getName(), webxmlURL);
try {
webContainerService.registerWar(warFile);
} catch (JWebContainerServiceException e) {
throw new HttpOnDemandProxyException("Unable to deploy the war file '" + warFile + "'.", e);
} catch (RemoteException e) {
throw new HttpOnDemandProxyException("Unable to deploy the war file '" + warFile + "'.", e);
}
// this is a redirect, so stop the execution here
return;
}
// Compute context name by using the filename if not found in jonas-web.xml file
if (contextRoot == null) {
contextRoot = file.getName();
if (contextRoot.endsWith(".war")) {
contextRoot = contextRoot.substring(0, contextRoot.length() - 4);
}
}
// ContextInfo present ?
ContextInfo existingContextInfo = contextMapping.get(contextRoot);
if (existingContextInfo != null) {
throw new HttpOnDemandProxyException("Cannot register the war File '" + warFile + "' with context '" + contextRoot + "' as it is already in use for the war File '" + existingContextInfo.getWarFile() + "'");
}
// Build data
ContextInfo contextInfo = new ContextInfo();
contextInfo.setWarFile(warFile);
// Add the mapping --> context Info
contextMapping.put(contextRoot, contextInfo);
// info
logger.info("The war file ''{0}'' is available on demand at the context /{1}", file.getName(), contextRoot);
}
/**
* Unregister the given war file
* @param warFile the file to undeploy
*/
public void removeWar(final String warFile) {
// Remove the associated context if found
Set> entries = contextMapping.entrySet();
String context = null;
// For each entry, search a matching context (same war file)
if (entries != null) {
for (Map.Entry entry : entries) {
if (warFile.equals(entry.getValue().getWarFile())) {
context = entry.getKey();
break;
}
}
}
// Context is found, remove info on this context
if (context != null) {
contextMapping.remove(context);
}
// War loaded by the container, remove it
if (webContainerService.isWarLoaded(warFile)) {
try {
webContainerService.unRegisterWar(warFile);
} catch (RemoteException e) {
logger.error("Unable to remove the given war file", e);
}
}
logger.debug("Unregistering war file ''{0}''", warFile);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy