/* * The contents of this file are subject to the Mozilla Public License Version 1.1 * (the "License"); you may not use this file except in compliance with the License. * You may obtain a copy of the License at . * * Software distributed under the License is distributed on an "AS IS" basis, WITHOUT * WARRANTY OF ANY KIND, either express or implied. See the License for the specific * language governing rights and limitations under the License. * * The Original Code is the Venice Web Communities System. * * The Initial Developer of the Original Code is Eric J. Bowersox , * for Silverwrist Design Studios. Portions created by Eric J. Bowersox are * Copyright (C) 2001-02 Eric J. Bowersox/Silverwrist Design Studios. All Rights Reserved. * * Contributor(s): */ package com.silverwrist.venice.ui.servlet; import java.io.*; import javax.servlet.*; import javax.servlet.http.*; import org.apache.log4j.*; import org.apache.log4j.xml.DOMConfigurator; import com.silverwrist.util.StringUtil; import com.silverwrist.venice.core.*; import com.silverwrist.venice.except.*; import com.silverwrist.venice.ui.*; import com.silverwrist.venice.ui.config.*; import com.silverwrist.venice.ui.helpers.ErrorBox; import com.silverwrist.venice.ui.helpers.ThrowableContent; import com.silverwrist.venice.ui.script.ScriptingException; import com.silverwrist.venice.ui.script.ScriptManagerContainer; public abstract class BaseServlet extends HttpServlet { /*-------------------------------------------------------------------------------- * Internal session factory object *-------------------------------------------------------------------------------- */ static class HttpSessionFactory implements VeniceUISessionFactory { private static final String ATTR_NAME = VeniceUISession.class.getName(); HttpSessionFactory() { // do nothing } // end constructor public VeniceUISession createSession(ServletContext ctxt, HttpServletRequest request, HttpServletResponse response, VeniceEngine engine, RootConfig config) throws ServletException { HttpSession session = request.getSession(true); VeniceUISession rc = (VeniceUISession)(session.getAttribute(ATTR_NAME)); if (rc==null) { // return a new session rc = new HttpVeniceUISession(request,session,engine); session.setAttribute(ATTR_NAME,rc); } // end if return rc; } // end createSession } // end class HttpSessionFactory /*-------------------------------------------------------------------------------- * Static data members *-------------------------------------------------------------------------------- */ private static final String LOGGING_ATTRIBUTE = "com.silverwrist.venice.util.LoggingStarted"; private static final String ENGINE_ATTRIBUTE = "com.silverwrist.venice.core.Engine"; private static final String UICONFIG_ATTRIBUTE = "com.silverwrist.venice.ui.Config"; private static final String LOGGING_INIT_PARAM = "logging.config"; private static final String ENGINE_INIT_PARAM = "venice.config"; private static final String UICONFIG_INIT_PARAM = "ui.config"; private static Category logger = Category.getInstance(BaseServlet.class); private static VeniceUISessionFactory factory = new HttpSessionFactory(); /*-------------------------------------------------------------------------------- * Internal operations *-------------------------------------------------------------------------------- */ private Object translateException(RequestInput req, Exception e) { // try the servlet first Object rc = translateServletException(req,e); if (rc!=null) return rc; // otherwise, go it alone logger.info("BaseServlet.translateException translating exception",e); if (e instanceof ScriptingException) return new ErrorBox("Scripting Error",e,null); return new ErrorBox("Unhandled Exception Detected!",e.toString(),e,null); } // end translateException private void commonProcess(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // log remote address with all log messages NDC.push(request.getRemoteAddr()); try { // create the actual request implementation ServletContext ctxt = getServletContext(); RequestImpl the_request = null; try { // create the request object the_request = new RequestImpl(ctxt,request,response,getVeniceEngine(ctxt), getRootConfig(ctxt),getSessionFactory()); } // end try catch (ValidationException ve) { // error in formatting of the request - bug out response.sendError(HttpServletResponse.SC_BAD_REQUEST,ve.toString()); return; } // end catch String default_location = the_request.getLocation(); // log the username with all log messages, if the user is logged in boolean record_user = false; if (the_request.sessionBound()) { // has the session been bound? try { // find out whether they're logged in record_user = the_request.getUser().isLoggedIn(); } // end try catch (IllegalStateException e) { // if not, just forget about it record_user = false; } // end catch } // end if if (record_user) NDC.push(the_request.getUser().getUserName()); try { // run the actual operation! Object my_output; // the output we get from the user try { // process this request! my_output = process(the_request); if (my_output==null) // this shouldn't happen my_output = new ErrorBox("Internal Error!", "No content returned for request: " + the_request.getVerb() + ": /" + default_location,null); } // end try catch (ThrowableContent tc) { // special escape for ThrowableContent my_output = tc; } // end catch catch (Exception e) { // if an exception is thrown, translate it if (e instanceof RuntimeException) { // filter out RuntimeExceptions and rethrow them logger.error("BaseServlet caught runtime exception" + e.getClass().getName() + " in commonProcess",e); throw (RuntimeException)e; } // end if my_output = translateException(the_request,e); } // end catch if (logger.isDebugEnabled()) logger.debug("Outputting an object of type " + my_output.getClass().getName()); // if the output object needs automatic cleanup, register it if (my_output instanceof AutoCleanup) the_request.registerCleanup((AutoCleanup)my_output); try { // Output the resulting object. if (my_output instanceof ContentExecute) the_request.execute((ContentExecute)my_output); else if (my_output instanceof Content) the_request.output((Content)my_output); else the_request.outputRaw(my_output.toString()); } // end try finally { // end the request the_request.end(); } // end finally } // end try finally { // make sure and pop the diagnostic context, if it was pushed if (record_user) NDC.pop(); } // end finally } // end try finally { // make sure and pop the diagnostic context before we go NDC.pop(); } // end finally } // end commonProcess /*-------------------------------------------------------------------------------- * Abstract operations which MUST be overridden! *-------------------------------------------------------------------------------- */ public abstract Object process(RequestInput req) throws Exception, ThrowableContent; /*-------------------------------------------------------------------------------- * Overrideable operations *-------------------------------------------------------------------------------- */ protected void init(ServletConfig config, ServletContext ctxt, VeniceEngine engine, RootConfig root, String root_file_path) { // default does nothing } // end init protected VeniceUISessionFactory getSessionFactory() { return factory; } // end getSessionFactory protected Object translateServletException(RequestInput ri, Exception e) { return null; // does nothing by default } // end translateServletException /*-------------------------------------------------------------------------------- * Internal operations *-------------------------------------------------------------------------------- */ protected final VeniceEngine getVeniceEngine(ServletContext ctxt) { return (VeniceEngine)(ctxt.getAttribute(ENGINE_ATTRIBUTE)); } // end getVeniceEngine protected final VeniceEngine getVeniceEngine() { return this.getVeniceEngine(getServletContext()); } // end getVeniceEngine protected final RootConfig getRootConfig(ServletContext ctxt) { return (RootConfig)(ctxt.getAttribute(UICONFIG_ATTRIBUTE)); } // end getRootConfig protected final RootConfig getRootConfig() { return this.getRootConfig(getServletContext()); } // end getRootConfig /*-------------------------------------------------------------------------------- * Overrides from class GenericServlet *-------------------------------------------------------------------------------- */ public void init(ServletConfig config) throws ServletException { super.init(config); ServletContext ctxt = config.getServletContext(); String root_file_path = ctxt.getRealPath("/"); if (!(root_file_path.endsWith("/"))) root_file_path += "/"; synchronized (BaseServlet.class) { // initialize the logging if (ctxt.getAttribute(LOGGING_ATTRIBUTE)==null) { // get logging config file and initialize String log_cfg = ctxt.getInitParameter(LOGGING_INIT_PARAM); if (!(log_cfg.startsWith("/"))) log_cfg = root_file_path + log_cfg; DOMConfigurator.configure(log_cfg); logger.info("Initialized logging with config file: " + log_cfg); ctxt.setAttribute(LOGGING_ATTRIBUTE,Boolean.TRUE); } // end if } // end synchronized block NDC.push("[-servlet-init-]"); VeniceEngine engine = null; RootConfig rootconf = null; try { // check and initialize the Venice engine synchronized (BaseServlet.class) { // initialize the engine engine = (VeniceEngine)(ctxt.getAttribute(ENGINE_ATTRIBUTE)); if (engine==null) { // initialize the engine String engine_cfg = ctxt.getInitParameter(ENGINE_INIT_PARAM); if (!(engine_cfg.startsWith("/"))) engine_cfg = root_file_path + engine_cfg; logger.info("Initializing Venice engine using config file: " + engine_cfg); try { // extract the configuration file name and create the engine engine = Startup.createEngine(engine_cfg,root_file_path); ctxt.setAttribute(ENGINE_ATTRIBUTE,engine); } // end try catch (ConfigException e) { // configuration failed! post an error message logger.fatal("Engine configuration failed: " + e.getMessage(),e); throw new ServletException("Venice engine configuration failed: " + e.getMessage(),e); } // end catch catch (DataException e2) { // configuration failed! post an error message logger.fatal("Engine data load failed: " + e2.getMessage(),e2); throw new ServletException("Venice engine data load failed: " + e2.getMessage(),e2); } // end catch } // end if // check and initialize the root configuration for the UI rootconf = (RootConfig)(ctxt.getAttribute(UICONFIG_ATTRIBUTE)); if (rootconf==null) { // load the root configuration String ui_cfg = ctxt.getInitParameter(UICONFIG_INIT_PARAM); if (!(ui_cfg.startsWith("/"))) ui_cfg = root_file_path + ui_cfg; logger.info("Initializing Venice user interface using config file: " + ui_cfg); try { // create a root configuration rootconf = new RootConfig(ui_cfg,root_file_path); ctxt.setAttribute(UICONFIG_ATTRIBUTE,rootconf); } // end try catch (ConfigException e) { // user interface configuration failed... logger.fatal("User interface configuration failed: " + e.getMessage(),e); throw new ServletException("Venice user interface configuration failed: " + e.getMessage(),e); } // end catch } // end if ScriptManagerContainer.initialize(rootconf,ctxt); // make sure container initialized } // end synchronized block // now do per-servlet initialization init(config,ctxt,engine,rootconf,root_file_path); } // end try finally { // make sure and pop the diagnostic context before we go NDC.pop(); } // end finally } // end init public void destroy() { super.destroy(); } // end destroy /*-------------------------------------------------------------------------------- * Overrides from class HttpServlet *-------------------------------------------------------------------------------- */ protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { commonProcess(req,resp); } // end doGet protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { commonProcess(req,resp); } // end doPost } // end class BaseServlet