001: package simpleorm.simplehtml;
002:
003: import java.io.PrintWriter;
004: import java.net.URLEncoder;
005: import java.util.LinkedHashMap;
006: import javax.servlet.http.HttpServlet;
007: import javax.servlet.http.HttpServletRequest;
008: import javax.servlet.http.HttpServletResponse;
009:
010: /**
011: * Common Super class for Servlet Requestlet Invocations.<p>
012: *
013: * A servlet's doGet|Post method creates an instance of a
014: * subclass of this class (DDriverRequestlet) that processes the request.
015: * So there is one instance per request, not shared, so can have state.
016: * Provides handy methods for output etc. <p>
017: *
018: * Ie. A Requestlet is like a Servlet but there is one instance per request, which is important.<p>
019: *
020: * Normally these are dispatched by the HMasterServlet based on the URI.<p>
021: *
022: * <p>$Id: HSuperRequestlet.java,v 1.8 2006/04/03 08:53:23 aberglas Exp $
023: * @see DDriverRequest which extends this class for the Driver project
024: * @author aberglas
025: */
026: abstract public class HSuperRequestlet {
027: HttpServletRequest request;
028: HttpServletResponse response;
029: HttpServlet servlet;
030: public PrintWriter out;
031: boolean isGet = false; // else Put.
032:
033: /** Yes, public! */
034: public final HBasicWidgets bw = new HBasicWidgets(this );
035: public final HPageWidgets pw = new HPageWidgets(this );
036:
037: /**
038: * Registry of all Requestlets that can be dispatched by the HMasterServlet.
039: * Need to call each requestlets .register() method in a main() in order to
040: * put it in this table.
041: * Used by HMasterServlet to dispatch calls.
042: **/
043: static LinkedHashMap<String, HSuperRequestlet> registry = new LinkedHashMap();
044:
045: /** Register the class in the DRegistry. Needs a dummy instance. */
046: public void register() {
047: registry.put(this Url(), this );
048: }
049:
050: /**
051: * Initializes the requestlet with information about the servlet and call.
052: * Note that there is also a dummy instance used in the registry table for
053: * which this is not called.
054: */
055: public HSuperRequestlet initRequestlet(HttpServlet servlet,
056: HttpServletRequest request, HttpServletResponse response,
057: boolean isGet) {
058: this .request = request;
059: this .response = response;
060: this .servlet = servlet;
061: try {
062: out = response.getWriter();
063: } catch (Exception ex) {
064: throw new RuntimeException(ex);
065: }
066: this .isGet = isGet;
067: return this ;
068: }
069:
070: /** Full title that appers in <Title>, <H1>, site map etc. */
071: abstract public String getTitle();
072:
073: /** (Consitent) Short name to appear in menus, links etc.
074: Normally overriden. */
075: public String getShortTitle() {
076: return getTitle();
077: }
078:
079: /** The web context, ie.
080: * The part of the Url between the port and the ap. No outer "/"s.
081: */
082: abstract public String getContext();
083:
084: /**
085: * URL of this requestlet. Used to generate links to this.
086: * (Could cache the result and save some garbage.)
087: */
088: public String this Url() {
089: return requestletUrl(this .getClass());
090: }
091:
092: /**
093: * Returns the Url of the requestlet class passed.
094: * Used for generating anchor href=
095: */
096: public String requestletUrl(Class clazz) {
097: String name = clazz.getSimpleName();
098: if (name.endsWith("Requestlet"))
099: name = name.substring(0, name.length() - 10);
100: String res = "/" + getContext() + "/" + name + ".rq";
101: return res;
102: }
103:
104: /** Returns the registered dummy instance of the requestlet. */
105: public HSuperRequestlet registeredInstance(Class clazz) {
106: String url = requestletUrl(clazz);
107: return registry.get(url);
108: }
109:
110: /**
111: * url of local resources such as images and style sheets.
112: * Strips of "Requestlet" if present, adds .rq.
113: */
114: public String localUrl(String name) {
115: return "/" + getContext() + "/" + name;
116: }
117:
118: /** Called for gets and posts, as set up from initRequestlet.
119: * Forms structure of a request: response, header, body, trailer...
120: * Traps exceptions and displays them.
121: */
122: public void doGetPost() {
123: try {
124: response.setContentType("text/html; charset=utf-8");
125: response.setCharacterEncoding("utf-8");
126: response.setHeader("Cache-Control", "no-cache"); // Http 1.1
127: response.addHeader("Pragma", "no-cache"); // Http 1.0
128:
129: doInitialize();
130: if (paramattr("f.submit") != null)
131: doSubmit();
132: outHtml("<HTML>\n<HEAD>\n");
133: doHead();
134: outHtml("\n</HEAD>\n");
135: doBodyTag();
136: doPreBody();
137: doBody();
138: doPostBody();
139: outHtml("\n</BODY></HTML>\n");
140: } catch (Exception ex) {
141: outHtml("<font color=red><p><b>Internal Error</b></font><p>\n");
142: outHtml("<xmp>");
143: ex.printStackTrace(out);
144: outHtml("</xmp>");
145: outHtml("<p>\n");
146: throw new RuntimeException(
147: "While Processing " + getTitle(), ex);
148: } finally {
149: out.close();
150: }
151: }
152:
153: /** Called before any html is output, can initialize application data structures. */
154: protected void doInitialize() throws Exception {
155: }
156:
157: /**
158: * Override to add validation and business logic.
159: * Usually calls bw.addFieldError etc.
160: * Only called if an "f.Submit" field is present.
161: * Called at very beginning, before any html is output, so can redirect.
162: * However, cannot produce any HTML output as there is no header yet.
163: * Can add error messages.
164: */
165: protected void doSubmit() throws Exception {
166: }
167:
168: /**
169: *Outputs HTML Header, title etc.
170: */
171: protected void doHead() throws Exception {
172: outHtml("<TITLE>");
173: outHtml(getTitle());
174: outHtml("</TITLE>\n");
175: outHtml("<link rel='STYLESHEET' type='text/css' href='");
176: outHtml(localUrl("styles.css"));
177: outHtml("'>\n");
178: }
179:
180: /** Output the actual BODY tag, can be used to add javascript triggers. */
181: protected void doBodyTag() throws Exception {
182: outHtml("<BODY>\n");
183: }
184:
185: /**
186: * output html before the Body. Eg. Menubars.
187: * Normally overriden.
188: */
189: protected void doPreBody() throws Exception {
190: outHtml("<H1>");
191: outEscaped(getTitle());
192: outHtml("</H1>\n");
193: bw.outputAllErrorMessages();
194: }
195:
196: /**
197: * Override this to add the bulk of the body code in normal requestlets.
198: */
199: protected abstract void doBody() throws Exception;
200:
201: /**
202: * output html after the Body. ie. footers.
203: * Normally overriden
204: */
205: protected void doPostBody() throws Exception {
206: }
207:
208: /**
209: * Outputs raw HTML, does NOT quote it.
210: * @see #outData
211: */
212: public void outHtml(String html) {
213: out.print(html);
214: }
215:
216: /** outEscaped(data, false) */
217: public void outEscaped(String data) {
218: outEscaped(data, false);
219: }
220:
221: /**
222: * Outputs data after escaping it so that '<' becomes '&lt;' etc.<p>
223: *
224: * Converts spaces to '&nbsp;' iff nbsp<p>
225: *
226: * Amazing that I need to write this myself!<p>
227: *
228: * @see #outHtml
229: */
230: public void outEscaped(String data, boolean nbsp) {
231: if (data == null)
232: out.print("");
233: else {
234: for (int dx = 0; dx < data.length(); dx++) {
235: char ch = data.charAt(dx);
236: switch (ch) {
237: case ' ':
238: out.print(nbsp ? " " : " ");
239: break;
240: case '<':
241: out.print("<");
242: break;
243: case '>':
244: out.print(">");
245: break;
246: case '\"':
247: out.print(""");
248: break;
249: case '\'':
250: out.print("'");
251: break;
252: case '\\':
253: out.print("\");
254: break;
255: case '&':
256: out.print("&");
257: break;
258: default:
259: out.print(ch); // Hopefully will be inlined
260: break;
261: }
262: }
263: }
264: }
265:
266: /**
267: * URL Encodes string in appropriate? encoding.
268: * used for ?=value Get parameters on links
269: */
270: public void outURLEncoded(String data) throws Exception {
271: out.print(URLEncoder.encode(data, "UTF-8"));
272: //response.encode();
273: }
274:
275: private static final String nullObject = new String(
276: "The Null Object"); // not interned, unique identity.
277:
278: /**
279: * returns request.getAttribute or request.getParameter if attribute not set.
280: * So a paramattrs is a settable parameter.<p>
281: * Prefix names to avoid conflicts in Attributes, for forms fields just f.field should do.
282: *
283: * The nullObject is used to set nulls instead of null because null attributes are simply removed by servlets.
284: * Conversion to nulls is automatic.
285: */
286: public String paramattr(String name, String defalt) {
287: String attr = (String) request.getAttribute(name);
288: if (attr == nullObject) { // ==, not .equals
289: attr = null;
290: } else if (attr == null)
291: attr = request.getParameter(name);
292: return attr == null ? defalt : attr;
293: }
294:
295: /** paramattr(name, null) */
296: public String paramattr(String name) {
297: return paramattr(name, null);
298: }
299:
300: /** paramattr == null or ""
301: */
302: public boolean paramattrEmpty(String name) {
303: String val = paramattr(name);
304: return val == null || "".equals(val);
305: }
306:
307: public void setParamattr(String name, String value) {
308: if (value == null)
309: value = nullObject;
310: request.setAttribute(name, value);
311: }
312:
313: /** Initialize paramattr to value iff it has no value.
314: Returns the resulting value of the paramattr. */
315: public String initParamattr(String name, String value) {
316: if (paramattr(name) == null)
317: setParamattr(name, value);
318: return paramattr(name);
319: }
320:
321: public PrintWriter getOut() {
322: return out;
323: }
324:
325: public HttpServletRequest getRequest() {
326: return request;
327: }
328:
329: public HttpServletResponse getResponse() {
330: return response;
331: }
332:
333: public HttpServlet getServlet() {
334: return servlet;
335: }
336: }
|