/* * 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.http; import hk.hku.cecid.piazza.commons.Sys; import hk.hku.cecid.piazza.commons.servlet.StatefulServletContext; import hk.hku.cecid.piazza.commons.util.Instance; import java.util.Arrays; import java.util.Collection; import java.util.Enumeration; import java.util.Hashtable; import java.util.Properties; import java.util.Vector; import javax.servlet.http.HttpServletRequest; /** * An HttpDispatcherContext is a StatefulServletContext. Additionally * it manages the Http request listeners for the HttpDispatcher. * * @see HttpDispatcher * @see HttpRequestListener * * @author Hugo Y. K. Lam * */ public class HttpDispatcherContext extends StatefulServletContext { private static final Hashtable contexts = new Hashtable(); private static HttpDispatcherContext defaultContext = new HttpDispatcherContext(); /** * Adds an Http dispatcher context to the embeded context store. * * @param id the ID of the Http dispatcher context. * @param context the Http dispatcher context. */ public static void addContext(String id, HttpDispatcherContext context) { if (id!=null && context!=null) { contexts.put(id, context); } } /** * Gets an Http dispatcher context from the embeded context store. * * @param id the ID of the Http dispatcher context. * @return the Http dispatcher context. */ public static HttpDispatcherContext getContext(String id) { if (id == null) { return null; } else { return (HttpDispatcherContext)contexts.get(id); } } /** * Gets the default Http dispatcher context. * * @return the default Http dispatcher context. */ public static HttpDispatcherContext getDefaultContext() { return defaultContext; } private Hashtable requestListeners = new Hashtable(); private Vector requestFilters = new Vector(); /** * Creates a new instance of HttpDispatcherContext. */ public HttpDispatcherContext() { super(); } /** * Registers an Http request listener at a specified path which is relative to its * corresponding servlet's context path. * * @param pathInfo the path information. * @param requestListener the Http request listener, the class name of the listener, or the class of the listener. * @return true if the operation is successful, false otherwise. */ public boolean register(String pathInfo, Object requestListener) { return register(pathInfo, requestListener, null); } /** * Registers an Http request listener at a specified path which is relative to its * corresponding servlet's context path. * * @param pathInfo the path information. * @param requestListener the Http request listener, the class name of the listener, or the class of the listener. * @param params the parameters of the listener. * @return true if the operation is successful, false otherwise. */ public boolean register(String pathInfo, Object requestListener, Properties params) { try { HttpRequestListener listener = (HttpRequestListener) new Instance( requestListener).getObject(); if (params != null) { Properties listenerProps = listener.getParameters(); if (listenerProps != null) { listenerProps.putAll(params); } } if (!(requestListener instanceof HttpRequestListener)) { listener.listenerCreated(); } pathInfo = fixPathInfo(pathInfo); requestListeners.put(pathInfo, listener); Sys.main.log.info("HTTP request listener '" + listener.getClass().getName() + "' registered successfully at '" + pathInfo + "'"); return true; } catch (Exception e) { Sys.main.log.error("Unable to register listener '" + requestListener + "' at '" + pathInfo + "'", e); return false; } } /** * Unregisters an Http request listener at a specified path which is relative to its * corresponding servlet's context path. * * @param pathInfo the path information. * @return true if the operation is successful, false otherwise. */ public boolean unregister(String pathInfo) { pathInfo = fixPathInfo(pathInfo); HttpRequestListener listener = (HttpRequestListener) requestListeners .remove(pathInfo); if (listener == null) { return false; } else { try { listener.listenerDestroyed(); } catch (Exception e) { Sys.main.log.error("Error in destroying listener '" + listener.getClass().getName() + "'", e); } Sys.main.log.info("HTTP request listener '" + listener.getClass().getName() + "' unregistered successfully at '" + pathInfo + "'"); return true; } } /** * Unregisters all Http request listeners in this context. */ public void unregisterAll() { Enumeration keys = requestListeners.keys(); while (keys.hasMoreElements()) { unregister(keys.nextElement().toString()); } } /** * Gets the Http request listener for the specified path which is relative to its * corresponding servlet's context path. * * If there is an exact match on the specified path, the registered listener * will be returned. Else if there is a wildcard path which matches the * specified path, its corresponding registered listener will be returned. * Otherwise, null will be returned. * * @param pathInfo the path information. * @return the HttpRequestListener registered at the specified path. */ public HttpRequestListener getListener(String pathInfo) { pathInfo = fixPathInfo(pathInfo); HttpRequestListener listener = (HttpRequestListener) requestListeners .get(pathInfo); if (listener != null) { return listener; } else { String[] keys = (String[]) requestListeners.keySet().toArray( new String[]{}); Arrays.sort(keys); for (int i = keys.length - 1; i >= 0; i--) { if (keys[i].indexOf('*') > -1) { String srcPath = keys[i].endsWith("/*") ? (pathInfo + "/") : pathInfo; String pattern = keys[i].replaceAll("\\*", ".*"); if (srcPath.matches(pattern)) { return (HttpRequestListener) requestListeners .get(keys[i]); } } } return null; } } /** * Gets the information of all registered Http request listeners. * The resulted properties will contain a set of pathInfo-listenerName pairs. * * @return the information as properties. */ public Properties getRegisteredListenersInfo() { Properties info = new Properties(); Enumeration keys = requestListeners.keys(); while (keys.hasMoreElements()) { Object key = keys.nextElement(); String value = requestListeners.get(key).getClass().getName(); info.setProperty(key.toString(), value); } return info; } /** * Gets the path information from the specified request. * The path information will be fixed according to the * internal logic of this context if necessary. * * @param request the Http servlet request. * @return the path information. */ public String getPathInfo(HttpServletRequest request) { return fixPathInfo(request.getPathInfo()); } /** * Fixes a given path, if necessary, such that the path will conform to a * consistent format. * * @param pathInfo the path information. * @return the fixed path. */ private String fixPathInfo(String pathInfo) { pathInfo = pathInfo == null ? "/" : pathInfo.trim(); if (!pathInfo.startsWith("/")) { pathInfo = "/" + pathInfo; } if (pathInfo.endsWith("/") && pathInfo.length() > 1) { pathInfo = pathInfo.substring(0, pathInfo.length() - 1); } return pathInfo; } /** * Adds a request filter for receiving request events. * * @param requestFilter the request filter. * @return true if the operation is successful, false otherwise. */ public boolean addRequestFilter(Object requestFilter) { try { HttpRequestFilter filter = (HttpRequestFilter) new Instance( requestFilter).getObject(); requestFilters.addElement(filter); return true; } catch (Exception e) { Sys.main.log.error("Unable to add HTTP request filter '" + requestFilter + "'", e); return false; } } /** * Gets all the request filters in this context. * * @return all the request filters in this context. */ public Collection getRequestFilters() { return requestFilters; } }