/* * Copyright(c) 2005 Center for E-Commerce Infrastructure Development, The * University of Hong Kong (HKU). All Rights Reserved. * * This software is licensed under the GNU GENERAL PUBLIC LICENSE Version 2.0 [1] * * [1] http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt */ package hk.hku.cecid.piazza.commons.servlet; import hk.hku.cecid.piazza.commons.Sys; import hk.hku.cecid.piazza.commons.util.Instance; import java.util.Collection; import java.util.Iterator; import java.util.Vector; import javax.servlet.UnavailableException; /** * A StatefulServletContext represents a context of a stateful servlet. * A stateful servlet has two states, a halted state and a running state. * * @see StatefulServletContextListener * * @author Hugo Y. K. Lam * */ public class StatefulServletContext { /** * Creates a new instance of StatefulServletContext. */ public StatefulServletContext() { super(); } private Vector contextListeners = new Vector(); private boolean halted = false; private boolean haltRequested = false; private int threadCount = 0; private String requestEncoding = null; private String responseEncoding = null; /** * Halts this context. The calling thread will be blocked until a lock on the * context has been acquired and no more threads are running under this * context. Nothing will be done if the servlet is already halted. * * @return true if and only if this context is not halted or being halted. * */ public synchronized boolean halt() { if (!halted) { Sys.main.log.info(this.getClass().getName()+" is being halted"); halted = true; haltRequested = true; while (threadCount > 0) { try { wait(); } catch (Exception e) { } } Iterator listeners = contextListeners.iterator(); while (listeners.hasNext()) { StatefulServletContextListener listener = (StatefulServletContextListener) listeners .next(); try { listener.servletContextHalted(); } catch (Exception e) { Sys.main.log.error("Error in invoking listener '" + listener.getClass().getName() + "' after context halted", e); } } haltRequested = false; Sys.main.log.info(this.getClass().getName()+" has been halted"); return true; } else { return false; } } /** * Checks if the context is currently halted. * * @return true if the servlet is currently halted. */ public boolean isHalted() { return halted; } /** * Checks if the context is currently being halted. * * @return true if the servlet is currently being halted. */ public boolean isHalting() { return haltRequested; } /** * Gets the current count of threads running under this context. * * @return the current count of threads running under this context. */ public int getCurrentThreadCount() { return threadCount; } /** * Acquires a permission from this context. Any servlet which employs * this stateful context must call this method before processing any requests. * * @throws UnavailableException if the context is currently halted. */ public synchronized void acquire() throws UnavailableException { if (!halted) { threadCount++; return; } else { throw new UnavailableException("The servlet is halted", 0); } } /** * Releases a permission to this context. Any servlet which employs * this stateful context must call this method after processing any requests. */ public synchronized void release() { threadCount--; notify(); } /** * Resumes this context. The calling thread will be blocked until a lock on * the context has been acquired. Nothing will be done if the servlet is not * halted. * * @return true if and only if this context is halted and not being halted. */ public synchronized boolean resume() { if (halted && !haltRequested) { Sys.main.log.info(this.getClass().getName()+" is being resumed"); Iterator listeners = contextListeners.iterator(); while (listeners.hasNext()) { StatefulServletContextListener listener = (StatefulServletContextListener) listeners .next(); try { listener.servletContextResumed(); } catch (Exception e) { Sys.main.log.error("Error in invoking listener '" + listener.getClass().getName() + "' after context resumed", e); } } halted = false; Sys.main.log.info(this.getClass().getName()+" has been resumed"); return true; } else { return false; } } /** * Adds a context listener for receiving events from this context. * * @param contextListener the stateful servlet context listener. * @return true if the operation is successful, false otherwise. */ public boolean addContextListener(Object contextListener) { try { StatefulServletContextListener listener = (StatefulServletContextListener) new Instance( contextListener).getObject(); contextListeners.addElement(listener); return true; } catch (Exception e) { Sys.main.log.error("Unable to add context listener '" + contextListener + "'", e); return false; } } /** * Gets all the stateful servlet context listeners in this context. * * @return all the stateful servlet context listeners in this context. */ public Collection getContextListeners() { return contextListeners; } /** * Gets the request encoding that the servlet should use. * * @return the request encoding. */ public String getRequestEncoding() { return requestEncoding; } /** * Sets the request encoding that the servlet should use. * * @param requestEncoding the request encoding. */ public void setRequestEncoding(String requestEncoding) { this.requestEncoding = requestEncoding; } /** * Gets the response encoding that the servlet should use. * * @return the response encoding. */ public String getResponseEncoding() { return responseEncoding; } /** * Sets the response encoding that the servlet should use. * * @param responseEncoding the response encoding. */ public void setResponseEncoding(String responseEncoding) { this.responseEncoding = responseEncoding; } }