/* * 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