1 /*
2 * $Source: /usr/cvsroot/melati/melati/src/main/java/org/melati/servlet/ConfigServlet.java,v $
3 * $Revision: 1.37 $
4 *
5 * Copyright (C) 2000 Tim Joyce
6 *
7 * Part of Melati (http://melati.org), a framework for the rapid
8 * development of clean, maintainable web applications.
9 *
10 * Melati is free software; Permission is granted to copy, distribute
11 * and/or modify this software under the terms either:
12 *
13 * a) the GNU General Public License as published by the Free Software
14 * Foundation; either version 2 of the License, or (at your option)
15 * any later version,
16 *
17 * or
18 *
19 * b) any version of the Melati Software License, as published
20 * at http://melati.org
21 *
22 * You should have received a copy of the GNU General Public License and
23 * the Melati Software License along with this program;
24 * if not, write to the Free Software Foundation, Inc.,
25 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA to obtain the
26 * GNU General Public License and visit http://melati.org to obtain the
27 * Melati Software License.
28 *
29 * Feel free to contact the Developers of Melati (http://melati.org),
30 * if you would like to work out a different arrangement than the options
31 * outlined here. It is our intention to allow Melati to be used by as
32 * wide an audience as possible.
33 *
34 * This program is distributed in the hope that it will be useful,
35 * but WITHOUT ANY WARRANTY; without even the implied warranty of
36 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
37 * GNU General Public License for more details.
38 *
39 * Contact details for copyright holder:
40 *
41 * Tim Joyce <timj At paneris.org>
42 * http://paneris.org/
43 * 68 Sandbanks Rd, Poole, Dorset. BH14 8BY. UK
44 */
45
46 package org.melati.servlet;
47
48 import java.io.PrintWriter;
49 import java.io.IOException;
50
51 import javax.servlet.ServletConfig;
52 import javax.servlet.ServletException;
53 import javax.servlet.http.HttpServlet;
54 import javax.servlet.http.HttpServletRequest;
55 import javax.servlet.http.HttpServletResponse;
56
57 import org.melati.Melati;
58 import org.melati.PoemContext;
59 import org.melati.MelatiConfig;
60 import org.melati.util.ConnectionPendingException;
61 import org.melati.util.MelatiWriter;
62
63 /**
64 * Config Servlet is the simplest way to use Melati.
65 *
66 * All a ConfigServlet does is to configure a melati and combine the
67 * doGet and doPost methods. Importantly it does not establish a poem session
68 * leaving you to do this for yourself.
69 *
70 * If you want a poem session established, please extend PoemServlet.
71 *
72 * ConfigServlet does set up a basic PoemContext with the Method set,
73 * but not the POEM logicaldatabase, table or troid.
74 *
75 * The URL is expected to take one of the following form:
76 *
77 * <BLOCKQUOTE><TT>
78 * http://<I>h</I>/<I>s</I>/<I>meth</I>
79 * </TT></BLOCKQUOTE>
80 *
81 * the method is broken out of the path info and passed to
82 * your application code in the <TT>Melati</TT> and
83 * <TT>PoemContext</TT> parameter
84 *
85 * <TABLE>
86 * <TR>
87 * <TD><TT><I>h</I></TT></TD>
88 * <TD>host name, such as <TT>www.melati.org</TT></TD>
89 * </TR>
90 * <TR>
91 * <TD><TT><I>s</I></TT></TD>
92 * <TD>
93 * servlet-determining part, such as
94 * <TT>melati/org.melati.admin.Admin</TT>
95 * </TD>
96 * </TR>
97 * <TR>
98 * <TD><TT><I>meth</I></TT></TD>
99 * <TD>
100 * A freeform string telling your servlet what it is meant to do. This
101 * is automatically made available in templates as
102 * <TT>$melati.Method</TT>.
103 * </TD>
104 * </TR>
105 * </TABLE>
106 *
107 * You can change the way these things are determined by overriding
108 * <TT>poemContext(Melati)</TT>.
109 */
110
111 public abstract class ConfigServlet extends HttpServlet {
112
113 /**
114 * Eclipse generated.
115 */
116 private static final long serialVersionUID = 8995954958766276122L;
117
118 protected MelatiConfig melatiConfig;
119 protected String sysAdminName = "nobody";
120 protected String sysAdminEmail = "nobody@nobody.com";;
121
122 /**
123 * Inititialise Melati.
124 *
125 * @param config a <code>ServletConfig</code>
126 * @throws ServletException is anything goes wrong
127 */
128 public void init(ServletConfig config) throws ServletException {
129 super.init(config);
130 try {
131 melatiConfig = melatiConfig();
132 } catch (Exception e) {
133 // log it to system.err as ServletExceptions go to the
134 // servlet runner log (eg jserv.log), and don't have a stack trace!
135 e.printStackTrace(System.err);
136 throw new ServletException(e.toString ());
137 }
138 }
139
140 /**
141 * Handles GET.
142 *
143 * @param request the incoming <code>HttpServletRequest</code>
144 * @param response the outgoing <code>HttpServletResponse</code>
145 */
146 public void doGet(HttpServletRequest request,
147 HttpServletResponse response) {
148 doGetPostRequest(request, response);
149 }
150
151 /**
152 * Handle a POST.
153 *
154 * @param request the incoming <code>HttpServletRequest</code>
155 * @param response the outgoing <code>HttpServletResponse</code>
156 */
157 public void doPost(HttpServletRequest request,
158 HttpServletResponse response) {
159 doGetPostRequest(request, response);
160 }
161
162 /**
163 * Process the request.
164 *
165 * Exceptions are presented to the user if practicable, or written to the log.
166 *
167 * @param request the incoming <code>HttpServletRequest</code>
168 * @param response the outgoing <code>HttpServletResponse</code>
169 */
170 private void doGetPostRequest(final HttpServletRequest request,
171 final HttpServletResponse response) {
172 Melati melati = new Melati(melatiConfig, request, response);
173 try {
174 melati.establishCharsets();
175 PoemContext poemContext = poemContext(melati);
176 melati.setPoemContext(poemContext);
177 doConfiguredRequest(melati);
178 // send the output to the client
179 melati.write();
180 }
181 catch (Exception e) {
182 error(melati,e);
183 }
184 }
185
186 /**
187 * Send an error message.
188 *
189 * @param melati the {@link Melati}
190 * @param e the {@link Exception} to report
191 */
192 public void error(Melati melati, Exception e) {
193 // has it been trapped already, if so, we don't need to relog it here
194 if (! (e instanceof TrappedException)) {
195 try {
196 // log it
197 e.printStackTrace(System.err);
198 // and put it on the page
199 melati.setResponseContentType ("text/html");
200 MelatiWriter mw = melati.getWriter();
201 // get rid of anything that has been written so far
202 mw.reset();
203 PrintWriter out = mw.getPrintWriter();
204 if (e instanceof ConnectionPendingException) {
205 writeConnectionPendingException(out,e);
206 } else {
207 writeError(out,e);
208 }
209 melati.write();
210 } catch (IOException f) {
211 e.printStackTrace(System.err);
212 throw new TrappedException(f.toString());
213 }
214 }
215 }
216
217 /**
218 * Print an error directly to the client.
219 *
220 * This is rarely called, eg when the template engine
221 * fails to render the default error template.
222 *
223 * @param out the <code>PrintWriter</code> to print to
224 * @param e the {@link Exception} to report
225 */
226 public void writeError(PrintWriter out, Exception e) {
227 out.println("<html><head><title>Melati Error</title></head>");
228 out.println("<!-- HTML generated in " +
229 "org.melati.servlet.ConfigServlet.java -->");
230 out.println("<body><h2>Melati Error</h2>");
231 out.println("<h3>Reported from ConfigServlet</h3>");
232 out.println("<p>An error has occured in the application");
233 out.println("that runs this website, please contact <a href='mailto:");
234 out.println(getSysAdminEmail() + "'>" + getSysAdminName() + "</a>");
235 out.println(", with the information given below.</p>");
236 out.println("<h4><font color=red><pre>");
237 e.printStackTrace(out);
238 out.println("</pre></font></h4></body></html>");
239 }
240
241 /**
242 * Print the <code>ConnectionPendingException</code> directly to the client.
243 *
244 * This is called if a request is made whilst the system is
245 * still being initialised.
246 *
247 * @param out the <code>PrintWriter</code> to print to
248 * @param e the {@link Exception} to report
249 */
250 public void writeConnectionPendingException(PrintWriter out, Exception e) {
251 out.println("<html><head><title>Database Initialising</title>\n");
252 out.println("<META HTTP-EQUIV='Refresh' CONTENT='30'>\n</head>\n");
253 out.println("<!-- Generated in org.melati.servlet.ConfigServlet.java -->");
254 out.println("<body><center><h2>Database Initialising</h2><p> </p>");
255 out.println("<p><b>Sorry</b>, ");
256 out.println("the database that runs this website is just starting up.");
257 out.println("This takes a few seconds, ");
258 out.println("so you should be able to use the site in a moment.");
259 out.println("<p>This page will refresh in 30 seconds, ");
260 out.println("and you will be able to continue.</p>");
261 out.println("<!--");
262 e.printStackTrace(out);
263 out.println("--></center></body></html>");
264 }
265
266 /**
267 * This method <b>SHOULD</b> be overidden.
268 * @return the System Administrators name.
269 */
270 public String getSysAdminName () {
271 return sysAdminName;
272 }
273
274 /**
275 * This method <b>SHOULD</b> be overidden.
276 * @return the System Administrators email address.
277 */
278 public String getSysAdminEmail () {
279 return sysAdminEmail;
280 }
281
282 /**
283 * @param sysAdminEmail The sysAdminEmail to set.
284 */
285 protected void setSysAdminEmail(String sysAdminEmail) {
286 this.sysAdminEmail = sysAdminEmail;
287 }
288
289
290 /**
291 * @param sysAdminName The sysAdminName to set.
292 */
293 protected void setSysAdminName(String sysAdminName) {
294 this.sysAdminName = sysAdminName;
295 }
296
297 protected PoemContext poemContext(Melati melati)
298 throws PathInfoException {
299 PoemContext it = new PoemContext();
300 String[] parts = melati.getPathInfoParts();
301 if (parts.length > 0)
302 it.setMethod(parts[parts.length - 1]);
303 return it;
304 }
305
306 /**
307 * To override any setting from org.melati.MelatiConfig.properties,
308 * simply override this method and return a valid MelatiConfig.
309 *
310 * eg to use a different AccessHandler from the default:
311 *
312 * <PRE>
313 * protected MelatiConfig melatiConfig() throws MelatiException {
314 * MelatiConfig config = super.melatiConfig();
315 * config.setAccessHandler(new YourAccessHandler());
316 * return config;
317 * }
318 * </PRE>
319 *
320 * @return a new {@link MelatiConfig}
321 */
322 protected MelatiConfig melatiConfig() {
323 MelatiConfig m = new MelatiConfig();
324 String realPath = getServletConfig().getServletContext().getRealPath("/");
325 if (realPath == null)
326 throw new NullPointerException();
327 m.setRealPath(realPath);
328 return m;
329 }
330
331 /**
332 * Instantiate this method to build up your own output.
333 * @param melati
334 * @throws Exception if anything goes wrong
335 */
336 protected abstract void doConfiguredRequest(Melati melati)
337 throws Exception;
338
339
340 }