All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.ow2.jonas.web.base.proxy.HttpOnDemandProxy Maven / Gradle / Ivy

There is a newer version: 5.3.0
Show newest version
/**
 * 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