460 lines
15 KiB
Java
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
|