001 // Copyright (c) 2001 Hursh Jain (http://www.mollypages.org)
002 // The Molly framework is freely distributable under the terms of an
003 // MIT-style license. For details, see the molly pages web site at:
004 // http://www.mollypages.org/. Use, modify, have fun !
005
006 package fc.web.page;
007
008 import java.io.*;
009 import java.util.*;
010
011 import javax.servlet.*;
012 import javax.servlet.http.*;
013
014 import fc.util.*;
015 import fc.io.*;
016
017 /**
018 A superclass for generated pages. All pages derive from this
019 class.
020
021 @author hursh jain
022 */
023 public class PageImpl implements Page
024 {
025 static private final boolean internal_dbg = false;
026
027 public Log log;
028 protected HttpServlet servlet;
029 private static ThreadLocal watchMap = new ThreadLocal();
030 private final ThreadLocal threadLocalOut = new ThreadLocal();
031 private String dbg_prefix = "";
032 private String dbg_suffix = "";
033
034 public void render(HttpServletRequest req, HttpServletResponse res)
035 throws Exception
036 {
037 throw new ServletException("Not implemented");
038 }
039
040 public void init(PageServlet servlet, String contextRelativePagePath)
041 {
042 //this.log = Log.get(contextRelativePagePath);
043 //this is easier, since the level of WebApp.defaultLog is set
044 //via webapp's app.cnf (and is easy to change)
045 this.log = fc.web.servlet.WebApp.getAppLog();
046 this.servlet = servlet;
047 if (internal_dbg) System.out.println(getClass().getName() + " init() called:" + ClassUtil.getClassLoaderInfo(PageImpl.class));
048 }
049
050 public void destroy() {
051 log.close();
052 if (internal_dbg) System.out.println(getClass().getName() + ClassUtil.getClassLoaderInfo(PageImpl.class));
053 }
054
055 public String getPagePath(HttpServletRequest req)
056 {
057 return req.getContextPath() + req.getServletPath();
058 }
059
060 public String getRealPath(HttpServletRequest req)
061 {
062 return
063 servlet.getServletConfig().getServletContext().getRealPath(getPagePath(req));
064 }
065
066 public void clientRedirect(
067 HttpServletRequest req, HttpServletResponse res, String newLocation)
068 throws IOException
069 {
070 String redirectURL = fc.web.servlet.WebUtil.absolutePath(req, newLocation);
071 res.sendRedirect(redirectURL);
072 }
073
074 public CharArrayWriter getThreadLocalWriter()
075 {
076 CharArrayWriter out = (CharArrayWriter) threadLocalOut.get();
077
078 if (out == null) {
079 out = new CharArrayWriter();
080 threadLocalOut.set(out);
081 }
082
083 return out;
084 }
085
086 /**
087 If set to <tt>true</tt>, a timer to calculate page render time
088 is started after this method call. Page render time can then be
089 displaying the value returned by invoking the {@link #getTime}
090 method.
091 <p>
092 */
093 public final void startTimer()
094 {
095 //each thread running thru the page has it's own watch.
096 Watch watch = getWatch();
097 if (watch == null) {
098 watch = new Watch();
099 watchMap.set(watch);
100 }
101 watch.start();
102 }
103
104 /**
105 Returns the time elapsed after invoking {@link startTime} method.
106 */
107 public final long getTime()
108 {
109 Watch watch = getWatch();
110 if (watch == null)
111 throw new RuntimeException("The startTimer() method must be invoked prior to invoking this method. Timers are thread local different processing threads get their own private timers. You must startTimer() and getTime() inside the render method, don't override the init() method to startTimer()..");
112 return watch.time();
113 }
114
115 private final Watch getWatch()
116 {
117 return (Watch) watchMap.get();
118 }
119
120 /**
121 Controls whether debugging is on or off. For expensive debug statements,
122 <code>if (dbg) bug(....)</code> type statements can be used in a page.
123 */
124 protected volatile boolean dbg = false;
125
126 /**
127 Starts/stop debugging with no dbg_prefix/dbg_suffix.
128
129 @param val true to enable debugging, false to disable.
130 */
131 public final void dbg(final boolean val)
132 {
133 this.dbg = val;
134 }
135
136 /**
137 Sets the prefix for debugging output.
138
139 @param dbg_prefix some html/text (such as <xmp><font color=red></xmp>) that
140 is printed before each debug statement
141 */
142 public final void dbgPrefix(String dbg_prefix)
143 {
144 this.dbg_prefix = dbg_prefix;
145 }
146
147 /**
148 Sets the suffix for debugging output.
149
150 @param dbg_suffix some html/text (such as <xmp></font></xmp>) that is printed
151 after each debug statement
152 */
153 public final void dbgSuffix(String dbg_suffix)
154 {
155 this.dbg_suffix = dbg_suffix;
156 }
157
158 /**
159 Prints a debug statement if debugging is turned on for this page.
160
161 <p>Typically the implicit page printwriter (the <code>out</code>
162 variable) will be passed to this method and debug statements will be
163 printed at the point where they are lexically invoked at the page.
164 <p>
165 However, each page request thread can collect debugging information
166 and print the output at some arbitrary location, such as the bottom
167 of the page. The method {@link #getThreadLocalOutput} exists for
168 this reason and can be used to collect thread-local output during
169 page execution.
170 */
171 public final void bug(final Writer writer, final Object str1) throws IOException
172 {
173 if (! dbg)
174 return;
175
176 writer.append(dbg_prefix);
177 writer.append(str1 != null ? str1.toString() : "null");
178 writer.append(dbg_suffix);
179 }
180
181 public final void bug(final Writer writer,
182 final Object str1, final Object str2) throws IOException
183 {
184 if (! dbg)
185 return;
186
187 writer.append(dbg_prefix);
188 writer.append(str1 != null ? str1.toString() : "null");
189 writer.append(str2 != null ? str2.toString() : "null");
190 writer.append(dbg_suffix);
191 }
192
193 public final void bug(final Writer writer,
194 final Object str1, final Object str2, final Object str3) throws IOException
195 {
196 if (! dbg)
197 return;
198
199 writer.append(dbg_prefix);
200 writer.append(str1 != null ? str1.toString() : "null");
201 writer.append(str2 != null ? str2.toString() : "null");
202 writer.append(str3 != null ? str3.toString() : "null");
203 writer.append(dbg_suffix);
204 }
205
206 public final void bug(final Writer writer,
207 final Object str1, final Object str2, final Object str3, final Object... args)
208 throws IOException
209 {
210 if (! dbg)
211 return;
212
213 writer.append(dbg_prefix);
214 writer.append(str1 != null ? str1.toString() : "null");
215 writer.append(str2 != null ? str2.toString() : "null");
216 writer.append(str3 != null ? str3.toString() : "null");
217 final int len = args.length;
218 for (int i = 0; i < len; i++) {
219 writer.append(args[i] != null ? args[i].toString() : "null");
220 }
221 writer.append(dbg_suffix);
222 }
223
224 }