venice-main-classic/src/com/silverwrist/venice/ui/servlet/BaseServlet.java
Eric J. Bowersox 7d3c167733 added the Velocity renderer (from the new venice-dynamo project) to
Venice; will be used for the post box soon
2004-07-26 05:04:27 +00:00

460 lines
15 KiB
Java

/*
* 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 <http://www.mozilla.org/MPL/>.
*
* 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 <erbo@ricochet.com>,
* for Silverwrist Design Studios. Portions created by Eric J. Bowersox are
* Copyright (C) 2001-2004 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;
import com.silverwrist.venice.ui.velocity.VelocityRenderer;
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 Logger logger = Logger.getLogger(BaseServlet.class);
private static Logger memlog = Logger.getLogger("MEMLOG");
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 str_request = the_request.toString();
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());
// log start of request
if (logger.isDebugEnabled())
logger.debug("Begin Request: " + str_request);
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);
else if (my_output instanceof RuntimeException)
{ // throw all RuntimeExceptions we get at this level
logger.error("BaseServlet caught runtime exception" + my_output.getClass().getName()
+ " in commonProcess",(Throwable)my_output);
throw new ServletException((Throwable)my_output);
} // end else if
else if (my_output instanceof VirtualMachineError)
{ // OutOfMemoryError, StackOverflowError, and such come here
System.gc(); // garbage collect so we have enough space to handle the error
logger.error("Virtual machine failure " + my_output.getClass().getName() + " in commonProcess",
(Throwable)my_output);
throw new ServletException((Throwable)my_output);
} // end else if
} // 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 new ServletException(e);
} // end if
my_output = translateException(the_request,e);
} // end catch
catch (VirtualMachineError e)
{ // OutOfMemoryError and similar come here...
System.gc(); // garbage collect so we have enough space to handle the error
logger.error("Virtual machine failure " + e.getClass().getName() + " in commonProcess",e);
throw new ServletException(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
catch (VirtualMachineError e)
{ // OutOfMemoryError and similar come here...
System.gc(); // garbage collect so we have enough space to handle the error
logger.error("Virtual machine failure " + e.getClass().getName() + " in commonProcess(2)",e);
throw new ServletException(e);
} // end catch
finally
{ // end the request
the_request.end();
} // end finally
} // end try
finally
{ // log memory usage
Runtime r = Runtime.getRuntime();
memlog.info("After: " + str_request + " Cur: " + r.totalMemory() + " Max: " + r.maxMemory() + " Free: "
+ r.freeMemory());
// log end of request
if (logger.isDebugEnabled())
logger.debug("End Request: " + str_request);
// 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
VelocityRenderer.init(ctxt,rootconf); // initialize Velocity renderer
BrowserDatabase.get(ctxt); // initialize browser database
} // 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