/*
* 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 Eric J. Bowersox/Silverwrist Design Studios. All Rights Reserved.
*
* Contributor(s):
*/
package com.silverwrist.venice.ui.servlet;
import java.awt.Dimension;
import java.io.*;
import java.lang.ref.*;
import java.sql.Blob;
import java.sql.SQLException;
import java.text.DateFormat;
import java.util.*;
import javax.servlet.*;
import javax.servlet.http.*;
import org.apache.log4j.*;
import org.w3c.dom.*;
import com.silverwrist.util.*;
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.dlg.Dialog;
import com.silverwrist.venice.ui.helpers.*;
import com.silverwrist.venice.ui.menus.CommunityMenu;
import com.silverwrist.venice.ui.menus.Menu;
import com.silverwrist.venice.ui.menus.MenuComponent;
import com.silverwrist.venice.ui.script.*;
public class RequestImpl implements RequestInput
{
/*--------------------------------------------------------------------------------
* Internal class which implements the output.
*--------------------------------------------------------------------------------
*/
class OutputImpl implements RequestOutput
{
private Writer wr = null;
OutputImpl()
{ // do nothing
} // end constructor
public Writer getWriter() throws IOException
{
if (wr==null)
wr = response.getWriter();
return wr;
} // end getWriter
public void write(String s) throws IOException
{
if (wr==null)
wr = response.getWriter();
wr.write(s);
} // end write
public void writeStackTrace(Throwable t) throws IOException
{
if (wr==null)
wr = response.getWriter();
PrintWriter tmp;
if (wr instanceof PrintWriter)
tmp = (PrintWriter)wr;
else
tmp = new PrintWriter(wr);
t.printStackTrace(tmp);
if (!(wr instanceof PrintWriter))
tmp.flush();
} // end writeStackTrace
public void flush() throws IOException
{
if (wr!=null)
wr.flush();
response.flushBuffer();
} // end flush
public void output(Content c) throws IOException, ServletException
{
if (c instanceof ContentDirect)
{ // render the content object here
ContentDirect cd = (ContentDirect)c;
if (wr!=null)
{ // attempt to flush the writer
try
{ // flush the output
wr.flush();
} // end try
catch (IOException e)
{ // do nothing
} // end catch
} // end if
response.flushBuffer(); // flush the previous stuff to disk
cd.render(this);
response.flushBuffer(); // flush the included page properly
return;
} // end if
if (c instanceof ContentJSP)
{ // include the JSP page here
ContentJSP cj = (ContentJSP)c;
RequestDispatcher disp = ctxt.getRequestDispatcher(config.getFormatJSPPath(cj.getJSPName()));
// Configure the request attributes.
request.setAttribute(REQUEST_INPUT,(RequestInput)(RequestImpl.this));
request.setAttribute(REQUEST_OUTPUT,(RequestOutput)this);
Object stack = request.getAttribute(REQUEST_CONTENT);
request.setAttribute(REQUEST_CONTENT,c);
// Configure the writer, if it's present.
if (wr!=null)
{ // attempt to flush the writer
try
{ // flush the output
wr.flush();
} // end try
catch (IOException e)
{ // do nothing
} // end catch
} // end if
Writer wr_stack = wr;
wr = null;
cj.initialize(RequestImpl.this);
try
{ // Include the content now!
response.flushBuffer(); // flush the previous stuff to disk
disp.include(request,response); // include the JSP
if (wr!=null)
wr.flush();
response.flushBuffer(); // flush the included page properly
} // end try
finally
{ // Clean up the stacked objects.
cj.terminate(RequestImpl.this);
wr = wr_stack;
if (stack==null)
request.removeAttribute(REQUEST_CONTENT);
else
request.setAttribute(REQUEST_CONTENT,stack);
} // end finally
return;
} // end if
// if nothing else...
this.write(c.toString());
} // end output
public void output(Writer out, Content c) throws IOException, ServletException
{
if (c instanceof ContentDirect)
{ // do a ContentDirect render, but replace the internal Writer with the specified one
// before we do so
ContentDirect cd = (ContentDirect)c;
if (wr!=null)
{ // attempt to flush the writer
try
{ // flush the output
wr.flush();
} // end try
catch (IOException e)
{ // do nothing
} // end catch
} // end if
Writer wr_stack = wr;
wr = out;
try
{ // do the actual output
cd.render(this);
wr.flush();
} // end try
finally
{ // restore the stacked stuff before we go
wr = wr_stack;
} // end finally
return;
} // end if
this.output(c); // fall back in ContentJSP case
} // end output
public void writeFrameHead(Writer out, Content c) throws IOException
{
out.write("\n" + config.getPageTitle(c.getPageTitle(this)) + "\n"
+ config.getBaseFontTag() + "\n");
if (config.usingStyleSheet())
out.write("\n");
String tmp = config.getPageIconTags();
if (tmp!=null)
out.write(tmp);
if (!(config.useSmartTags()))
out.write("\n");
out.write("\n");
} // end writeFrameHead
public void writeFrameHead(Content c) throws IOException
{
if (wr==null)
wr = response.getWriter();
this.writeFrameHead(wr,c);
} // end writeFrameHead
public void writeSiteImageTag(Writer out) throws IOException
{
String href = config.getSiteLogoLink();
if (href!=null)
out.write("");
out.write(config.getSiteLogoImageTag());
if (href!=null)
out.write("");
} // end writeSiteImageTag
public void writeSiteImageTag() throws IOException
{
if (wr==null)
wr = response.getWriter();
this.writeSiteImageTag(wr);
} // end writeSiteImageTag
public void writeVeniceLogo(Writer out) throws IOException
{
out.write(config.getVeniceLogoTag());
} // end writeVeniceLogo
public void writeVeniceLogo() throws IOException
{
if (wr==null)
wr = response.getWriter();
this.writeVeniceLogo(wr);
} // end writeVeniceLogo
public void writeContentHeader(Writer out, String primary, String secondary) throws IOException
{
out.write(config.getContentHeader(primary,secondary));
} // end writeContentHeader
public void writeContentHeader(String primary, String secondary) throws IOException
{
if (wr==null)
wr = response.getWriter();
wr.write(config.getContentHeader(primary,secondary));
} // end writeContentHeader
public String formatURL(String url, int type)
{
return RequestImpl.this.formatURL(url,type);
} // end formatURL
public String formatDate(Date date)
{
return RequestImpl.this.formatDate(date);
} // end formatDate
public String getColor(int selector)
{
return config.getColor(selector);
} // end getColor
public String getColor(String name)
{
return config.getColor(name);
} // end getColor
public String getFontTag(int colorsel, int size)
{
return config.getFontTag(colorsel,size);
} // end getFontTag
public String getFontTag(String color, int size)
{
return config.getFontTag(color,size);
} // end getFontTag
public String getFontTag(int colorsel, String size)
{
return config.getFontTag(colorsel,size);
} // end getFontTag
public String getFontTag(String color, String size)
{
return config.getFontTag(color,size);
} // end getFontTag
public String getStockMessage(String key)
{
return config.getStockMessage(key);
} // end getStockMessage
public String getStockMessage(String key, Map vars)
{
return config.getStockMessage(key,vars);
} // end getStockMessage
public String getStaticPath(String s)
{
return config.getStaticPath(s);
} // end getStaticPath
public String getExternalStaticPath(String s)
{
return config.getExternalStaticPath(s);
} // end getExternalStaticPath
public String getImagePath(String s)
{
return config.getImagePath(s);
} // end getImagePath
public String getButtonVisual(String id)
{
return config.getButtonVisual(id);
} // end getButtonVisual
public String getButtonInput(String id)
{
return config.getButtonInput(id);
} // end getButtonInput
public String getUserPhotoTag(String url)
{
return RequestImpl.this.getUserPhotoTag(url,engine.getUserPhotoSize());
} // end getUserPhotoTag
public String getUserPhotoTag(String url, Dimension size)
{
return RequestImpl.this.getUserPhotoTag(url,size);
} // end getUserPhotoTag
public String getActivityString(Date date)
{
return RequestImpl.this.getActivityString(date);
} // end getActivityString
public String getCommunityLogoTag(String url)
{
return RequestImpl.this.getCommunityLogoTag(url);
} // end getCommunityLogoTag
} // end class OutputImpl
/*--------------------------------------------------------------------------------
* Internal class which implements the execution output.
*--------------------------------------------------------------------------------
*/
class ExecImpl implements RequestExec
{
ExecImpl()
{ // do nothing
} // end constructor
public void error(int code) throws IOException
{
flushCookies();
if (logger.isDebugEnabled())
logger.debug("ExecImpl.error(): code " + code);
response.sendError(code);
} // end sendError
public void error(int code, String message) throws IOException
{
flushCookies();
if (logger.isDebugEnabled())
logger.debug("ExecImpl.error(): code " + code + ", msg: " + message);
if (message==null)
response.sendError(code);
else
response.sendError(code,message);
} // end sendError
public void redirect(String where, int type) throws IOException
{
flushCookies();
String fmt_url;
if (type==ABSOLUTE)
fmt_url = where;
else if (type==SERVLET)
fmt_url = response.encodeRedirectURL(request.getContextPath() + "/" + where);
else if (type==FRAME)
fmt_url = response.encodeRedirectURL(request.getContextPath() + "/frame/" + where);
else
throw new IndexOutOfBoundsException("invalid format type index for redirect");
if (logger.isDebugEnabled())
logger.debug("ExecImpl.redirect(): going to \"" + fmt_url + "\"");
response.sendRedirect(fmt_url);
} // end redirect
public void noContent()
{
flushCookies();
response.setStatus(HttpServletResponse.SC_NO_CONTENT);
} // end noContent
public void sendBinary(String type, String filename, int length, InputStream data) throws IOException
{
flushCookies();
if (logger.isDebugEnabled())
logger.debug("ExecImpl.sendBinary(): MIME " + type + ", filename \"" + filename
+ "\", length " + length);
response.setContentType(type);
response.setContentLength(length);
addDynamicHeaders();
if (filename!=null) // make sure we pass the filename along, too
response.setHeader("Content-Disposition","attachment; filename=\"" + filename + "\";");
// Copy the contents of the "data" stream to the output.
IOUtil.copy(data,response.getOutputStream());
response.flushBuffer();
} // end sendBinary
public void sendBinary(String type, int length, InputStream data) throws IOException
{
this.sendBinary(type,null,length,data);
} // end sendBinary
public void sendBinary(String type, String filename, Blob data) throws IOException, SQLException
{
this.sendBinary(type,filename,(int)(data.length()),data.getBinaryStream());
} // end sendBinary
public void sendBinary(String type, Blob data) throws IOException, SQLException
{
this.sendBinary(type,null,(int)(data.length()),data.getBinaryStream());
} // end sendBinary
public void sendBinary(String type, String filename, byte[] data) throws IOException
{
this.sendBinary(type,filename,data.length,new ByteArrayInputStream(data));
} // end sendBinary
public void sendBinary(String type, byte[] data) throws IOException
{
this.sendBinary(type,null,data.length,new ByteArrayInputStream(data));
} // end sendBinary
public void sendText(String type, String data) throws IOException
{
flushCookies();
if (logger.isDebugEnabled())
logger.debug("ExecImpl.sendText(): MIME " + type + ", length " + data.length());
response.setContentType(type);
response.setContentLength(data.length());
addDynamicHeaders();
Writer wr = response.getWriter();
wr.write(data);
wr.flush();
response.flushBuffer();
} // end sendText
public void sendText(String type, char[] data) throws IOException
{
flushCookies();
if (logger.isDebugEnabled())
logger.debug("ExecImpl.sendText(): MIME " + type + ", length " + data.length);
response.setContentType(type);
response.setContentLength(data.length);
addDynamicHeaders();
Writer wr = response.getWriter();
wr.write(data);
wr.flush();
response.flushBuffer();
} // end sendText
} // end class ExecImpl
/*--------------------------------------------------------------------------------
* Static data members
*--------------------------------------------------------------------------------
*/
private static Category logger = Category.getInstance(RequestImpl.class);
private static final String STYLESHEET_ATTRIBUTE = "com.silverwrist.venice.rendering.StyleSheet";
private static final String APP_ATTRIBUTE_STEM = "com.silverwrist.venice.ui.variables.";
private static final String USERCTXT_ATTRIBUTE = "user.context";
private static final String SESSION_ATTRIBUTE_STEM = "venice.vars.";
public static final String REQUEST_CONTENT = "com.silverwrist.venice.ui.Content";
public static final String REQUEST_INPUT = "com.silverwrist.venice.ui.RequestInput";
public static final String REQUEST_OUTPUT = "com.silverwrist.venice.ui.RequestOutput";
public static final String REQUEST_ATTRIBUTE_STEM = "com.silverwrist.venice.ui.variables.";
/*--------------------------------------------------------------------------------
* Attributes
*--------------------------------------------------------------------------------
*/
private ServletContext ctxt; // the servlet context
private HttpServletRequest request; // the servlet request data
private HttpServletResponse response; // the servlet response data
private HttpSession session; // the current HTTP session
private VeniceEngine engine; // the Venice engine context
private RootConfig config; // the UI configuration data
private UserContext user; // the current user context
private ServletMultipartHandler mphandler = null; // if this is a multipart/form-data POST
private ArrayList new_cookies = null; // cookies to be added to the response
private boolean end_response = true; // do we need to properly end the response?
private Locale my_locale; // user's current locale
private TimeZone my_timezone; // user's current time zone
private String location; // current servlet location
private boolean show_login = true; // do we show the login links?
private ScriptManager script_mgr; // the script manager to use for executing script
private DateFormat display_date = null; // format to use for displaying dates
private DateFormat activity_time = null; // format to use for activity string times
private CommunityContext community = null; // the current community
private LinkedList auto_cleanup = null; // auto-cleanup callbacks
/*--------------------------------------------------------------------------------
* Constructor
*--------------------------------------------------------------------------------
*/
RequestImpl(ServletContext ctxt, HttpServletRequest request, HttpServletResponse response,
VeniceEngine engine, RootConfig config) throws ServletException
{
// Set up the basic variables.
this.ctxt = ctxt;
this.request = request;
this.response = response;
this.session = request.getSession(true);
this.engine = engine;
this.config = config;
// Create or retrieve the user context.
user = (UserContext)(session.getAttribute(USERCTXT_ATTRIBUTE));
if (user==null)
{ // the user context isn't present yet
try
{ // tell the engine to create us a user context
user = engine.createUserContext(request.getRemoteAddr());
// Did the user send a Venice authentication cookie? If so, try to use it.
Cookie[] cookies = request.getCookies();
Cookie venice_cookie = null;
for (int i=0; (venice_cookie==null) && (ilimit)
script = script.substring(0,x);
} // end if
return config.getScriptPath(script);
} // end getScriptName
public String getScriptLoggerName(String raw_name)
{
// Strip all extensions from the end of the file.
int limit = raw_name.lastIndexOf('/');
int x = raw_name.lastIndexOf('.');
while (x>limit)
{ // remove all extensions from the end
raw_name = raw_name.substring(0,x);
x = raw_name.lastIndexOf('.');
} // end while
// convert the name to a logger name
StringBuffer rc = new StringBuffer("SCRIPT.");
for (x=0; x");
return buf.toString();
} // end getUserPhotoTag
public CommunityContext getCommunity()
{
return community;
} // end getCommunity
public CommunityContext getCommunity(boolean required, String on_error) throws ErrorBox
{
if (community!=null)
return community;
String parm = this.getParameter("cc"); // try the new parameter first
if (StringUtil.isStringEmpty(parm))
parm = this.getParameter("sig"); // try the old parameter
if (StringUtil.isStringEmpty(parm))
{ // the parameter is not specified...
if (required)
{ // no community parameter - bail out now!
logger.error("community parameter not specified!");
throw new ErrorBox(null,"No community specified.",on_error);
} // end if
else
{ // a null CommunityContext is permitted
logger.debug("no community specified");
return null;
} // end else
} // end if
try
{ // turn the string into a community ID, and thence to a CommunityContext
int tmp_id = Integer.parseInt(parm);
community = user.getCommunityContext(tmp_id);
if (community==null)
{ // trap any null results (may not be possible with communities, but you never know)
logger.error("Community #" + tmp_id + " was not found!");
throw new ErrorBox(null,"The specified community (#" + tmp_id + ") was not found in the database.",
on_error);
} // end if
if (logger.isDebugEnabled())
logger.debug("found community #" + community.getCommunityID());
} // end try
catch (NumberFormatException nfe)
{ // error in Integer.parseInt
logger.error("Cannot convert community parameter '" + parm + "'!");
throw new ErrorBox(null,"Invalid community parameter.",on_error);
} // end catch
catch (DataException de)
{ // error looking up the community
throw new ErrorBox("Database Error","Database error finding community: " + de.getMessage(),on_error);
} // end catch
return community;
} // end getCommunity
public String getActivityString(Date date)
{
if (date==null)
return "Never"; // safeguard
// Set up the two calendars we'll use for comparison.
Calendar c_last = new GregorianCalendar(my_timezone,my_locale);
c_last.setTime(date);
Calendar c_now = new GregorianCalendar(my_timezone,my_locale);
// Determine the exact number of days in the delta.
int delta_days = 0;
while ( (c_last.get(Calendar.YEAR)!=c_now.get(Calendar.YEAR))
|| (c_last.get(Calendar.DAY_OF_YEAR)!=c_now.get(Calendar.DAY_OF_YEAR)))
{ // advance until we're pointing at the same year and the same day of the year
delta_days++;
c_last.add(Calendar.DAY_OF_YEAR,1);
} // end while
// For today or yesterday, we want to paste the time in as well.
String s = null;
if (delta_days<=1)
{ // set up to convert the time into a string
if (activity_time==null)
{ // get the "activity" time formatter
activity_time = DateFormat.getTimeInstance(DateFormat.MEDIUM,my_locale);
activity_time.setTimeZone(my_timezone);
} // end if
s = activity_time.format(date);
} // end if
// Return the actual activity string.
if (delta_days==0)
return "Today, " + s;
else if (delta_days==1)
return "Yesterday, " + s;
else
return String.valueOf(delta_days) + " days ago";
} // end getActivityString
public String getDefaultServletAddress(CommunityContext comm)
{
return config.getDefaultServletAddress(this,comm);
} // end getDefaultServletAddress
public String getCommunityLogoTag(String url)
{
StringBuffer buf = new StringBuffer("");
return buf.toString();
} // end getCommunityLogoTag
public String expandServletPath(String spath)
{
StringBuffer buf = new StringBuffer("http://");
buf.append(request.getServerName());
if (request.getServerPort()!=80)
buf.append(':').append(request.getServerPort());
buf.append(request.getContextPath()).append('/').append(spath);
return buf.toString();
} // end expandServletPath
public void registerCleanup(AutoCleanup ac)
{
if (auto_cleanup==null)
auto_cleanup = new LinkedList();
auto_cleanup.addFirst(ac);
} // end registerCleanup
/*--------------------------------------------------------------------------------
* External static operations
*--------------------------------------------------------------------------------
*/
public final static Object getAppAttribute(ServletContext ctxt, String name)
{
return ctxt.getAttribute(APP_ATTRIBUTE_STEM + name);
} // end getAppAttribute
public final static void setAppAttribute(ServletContext ctxt, String name, Object o)
{
if (o==null)
ctxt.removeAttribute(APP_ATTRIBUTE_STEM + name);
else
ctxt.setAttribute(APP_ATTRIBUTE_STEM + name,o);
} // end setAppAttribute
public final static Object getSessionAttribute(HttpSession session, String name)
{
return session.getAttribute(SESSION_ATTRIBUTE_STEM + name);
} // end getSessionAttribute
public final static void setSessionAttribute(HttpSession session, String name, Object o)
{
if (o==null)
session.removeAttribute(SESSION_ATTRIBUTE_STEM + name);
else
session.setAttribute(SESSION_ATTRIBUTE_STEM + name,o);
} // end setSessionAttribute
public final static Object getSessionAttribute(HttpServletRequest request, String name)
{
HttpSession session = request.getSession(true);
return ((session!=null) ? getSessionAttribute(session,name) : null);
} // end getSessionAttribute
public final static void setSessionAttribute(HttpServletRequest request, String name, Object o)
{
HttpSession session = request.getSession(true);
if (session!=null)
setSessionAttribute(session,name,o);
} // end setSessionAttribute
public final static Object getRequestAttribute(ServletRequest request, String name)
{
return request.getAttribute(REQUEST_ATTRIBUTE_STEM + name);
} // end getRequestAttribute
public final static void setRequestAttribute(ServletRequest request, String name, Object o)
{
if (o==null)
request.removeAttribute(REQUEST_ATTRIBUTE_STEM + name);
else
request.setAttribute(REQUEST_ATTRIBUTE_STEM + name,o);
} // end setRequestAttribute
/*--------------------------------------------------------------------------------
* External operations
*--------------------------------------------------------------------------------
*/
void output(Content content) throws ServletException, IOException
{
if (content.needFrame())
{ // get the frame JSP and pass it along
RequestDispatcher disp = ctxt.getRequestDispatcher(config.getFrameJSPName());
request.setAttribute(REQUEST_INPUT,(RequestInput)this);
request.setAttribute(REQUEST_OUTPUT,(RequestOutput)(new OutputImpl()));
request.setAttribute(REQUEST_CONTENT,content);
updateMenus(content);
addDynamicHeaders();
flushCookies();
try
{ // forward it!
disp.forward(request,response);
} // end try
finally
{ // make sure we end the response properly
end_response = false;
} // end finally
} // end if
else if (content instanceof ContentJSP)
{ // transfer straight to the top-level JSP
ContentJSP cj = (ContentJSP)content;
RequestDispatcher disp = ctxt.getRequestDispatcher(config.getFormatJSPPath(cj.getJSPName()));
request.setAttribute(REQUEST_INPUT,(RequestInput)this);
request.setAttribute(REQUEST_OUTPUT,(RequestOutput)(new OutputImpl()));
request.setAttribute(REQUEST_CONTENT,content);
updateMenus(content);
addDynamicHeaders();
flushCookies();
cj.initialize(this);
try
{ // forward the response
disp.forward(request,response);
} // end try
finally
{ // make sure we terminate, even on error
cj.terminate(this);
end_response = false;
} // end finally
} // end else if
else
{ // use OutputImpl to handle the rest
OutputImpl oi = new OutputImpl();
response.setContentType("text/html");
updateMenus(content);
addDynamicHeaders();
flushCookies();
oi.output(content);
} // end else
} // end output
void outputRaw(String data) throws ServletException, IOException
{
OutputImpl oi = new OutputImpl();
response.setContentType("text/html");
updateMenus(Content.MENU_SELECTOR_NOCHANGE);
addDynamicHeaders();
flushCookies();
oi.write(data);
oi.flush();
} // end data
void execute(ContentExecute content) throws IOException
{
try
{ // perform the execute
content.execute(new ExecImpl());
} // end try
finally
{ // still set the flag on error
end_response = false;
} // end finally
} // end execute
void end()
{
if (end_response)
{ // we can touch the response object when we end...
try
{ // flush the response buffer
response.flushBuffer();
} // end try
catch (IOException e)
{ // just print a warning message
logger.warn("IOException flushing buffer in end()",e);
} // end catch
} // end if
// perform automatic cleanups
if (auto_cleanup!=null)
while (auto_cleanup.size()>0)
{ // pop items off and clean them up
AutoCleanup ac = (AutoCleanup)(auto_cleanup.removeFirst());
ac.cleanup();
} // end while and if
// blow a bunch of our object fields to hell (this might make garbage collection easier)
auto_cleanup = null;
community = null;
activity_time = null;
display_date = null;
my_locale = null;
my_timezone = null;
mphandler = null;
request = null;
response = null;
session = null;
// release the script manager
script_mgr.popContext();
ScriptManagerContainer cnr = ScriptManagerContainer.get(ctxt);
cnr.releaseScriptManager(script_mgr);
script_mgr = null;
} // end end
} // end class RequestImpl