- experimental opensessions
[mir.git] / source / mir / servlet / ServletModule.java
1 /*\r
2  * Copyright (C) 2001, 2002  The Mir-coders group\r
3  *\r
4  * This file is part of Mir.\r
5  *\r
6  * Mir is free software; you can redistribute it and/or modify\r
7  * it under the terms of the GNU General Public License as published by\r
8  * the Free Software Foundation; either version 2 of the License, or\r
9  * (at your option) any later version.\r
10  *\r
11  * Mir is distributed in the hope that it will be useful,\r
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
14  * GNU General Public License for more details.\r
15  *\r
16  * You should have received a copy of the GNU General Public License\r
17  * along with Mir; if not, write to the Free Software\r
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\r
19  *\r
20  * In addition, as a special exception, The Mir-coders gives permission to link\r
21  * the code of this program with the com.oreilly.servlet library, any library\r
22  * licensed under the Apache Software License, The Sun (tm) Java Advanced\r
23  * Imaging library (JAI), The Sun JIMI library (or with modified versions of\r
24  * the above that use the same license as the above), and distribute linked\r
25  * combinations including the two.  You must obey the GNU General Public\r
26  * License in all respects for all of the code used other than the above\r
27  * mentioned libraries.  If you modify this file, you may extend this exception\r
28  * to your version of the file, but you are not obligated to do so.  If you do\r
29  * not wish to do so, delete this exception statement from your version.\r
30  */\r
31 \r
32 package mir.servlet;\r
33 \r
34 import java.io.PrintWriter;\r
35 import java.util.HashMap;\r
36 import java.util.List;\r
37 import java.util.Locale;\r
38 import java.util.Map;\r
39 import javax.servlet.http.HttpServletRequest;\r
40 import javax.servlet.http.HttpServletResponse;\r
41 import javax.servlet.http.HttpSession;\r
42 \r
43 import freemarker.template.SimpleHash;\r
44 import freemarker.template.TemplateModelRoot;\r
45 import mir.config.MirPropertiesConfiguration;\r
46 import mir.config.MirPropertiesConfiguration$PropertiesConfigExc;\r
47 import mir.entity.EntityList;\r
48 import mir.log.LoggerWrapper;\r
49 import mir.misc.HTMLTemplateProcessor;\r
50 import mir.misc.LineFilterWriter;\r
51 import mir.module.AbstractModule;\r
52 import mir.storage.StorageObject;\r
53 import mir.util.HTTPRequestParser;\r
54 \r
55 \r
56 \r
57 \r
58 /**\r
59  * Abstract class ServletModule provides the base functionality for servlets.\r
60  * Deriving a class from ServletModule enables class to insert/edit/update/delete\r
61  * and list Entity from a Database via mainModule.\r
62  *\r
63  *\r
64  *  Abstrakte Klasse ServletModule stellt die Basisfunktionalitaet der\r
65  *  abgeleiteten ServletModule zur Verf?gung.\r
66  *\r
67  * @version 28.6.1999\r
68  * @author RK\r
69  */\r
70 \r
71 public abstract class ServletModule {\r
72 \r
73   public String defaultAction;\r
74   protected LoggerWrapper logger;\r
75   protected MirPropertiesConfiguration configuration;\r
76   protected AbstractModule mainModule;\r
77   protected Locale fallbackLocale;\r
78   protected String templateListString;\r
79   protected String templateObjektString;\r
80   protected String templateConfirmString;\r
81 \r
82 \r
83   public ServletModule(){\r
84     try {\r
85       configuration = MirPropertiesConfiguration.instance();\r
86     }\r
87     catch (PropertiesConfigExc e) {\r
88       throw new RuntimeException("Can't get configuration: " + e.getMessage());\r
89     }\r
90 \r
91     fallbackLocale = new Locale(configuration.getString("Mir.Admin.FallbackLanguage", "en"), "");\r
92   }\r
93 \r
94 \r
95   /**\r
96    * Singelton - Methode muss in den abgeleiteten Klassen ueberschrieben werden.\r
97    * @return ServletModule\r
98    */\r
99   public static ServletModule getInstance() {\r
100     return null;\r
101   }\r
102 \r
103   /**\r
104    * get the module name to be used for generic operations like delete.\r
105    */\r
106   protected String getOperationModuleName() {\r
107     return getClass().getName().substring((new String("mircoders.servlet.ServletModule")).length());\r
108   }\r
109 \r
110   /**\r
111    * get the locale either from the session or the accept-language header ot the request\r
112    * this supersedes getLanguage for the new i18n\r
113    */\r
114   public Locale getLocale(HttpServletRequest req) {\r
115     Locale loc = null;\r
116     HttpSession session = req.getSession(false);\r
117     if (session != null) {\r
118       // session can be null in case of logout\r
119       loc = (Locale) session.getAttribute("locale");\r
120     }\r
121     // if there is nothing in the session get it fron the accept-language\r
122     if (loc == null) {\r
123       loc = req.getLocale();\r
124     }\r
125     return loc;\r
126   }\r
127 \r
128   /**\r
129    * get the locale either from the session or the accept-language header ot the request\r
130    * this supersedes getLanguage for the new i18n\r
131    */\r
132   public Locale getFallbackLocale(HttpServletRequest req) {\r
133     return fallbackLocale;\r
134   }\r
135 \r
136   public void redirect(HttpServletResponse aResponse, String aQuery) throws ServletModuleExc, ServletModuleFailure {\r
137     try {\r
138       aResponse.sendRedirect(MirPropertiesConfiguration.instance().getString("RootUri") + "/Mir?"+aQuery);\r
139     }\r
140     catch (Throwable t) {\r
141       throw new ServletModuleFailure("ServletModule.redirect: " +t.getMessage(), t);\r
142     }\r
143   }\r
144 \r
145   /**\r
146    *  list(req,res) - generische Listmethode. Wennn die Funktionalitaet\r
147    *  nicht reicht, muss sie in der abgeleiteten ServletModule-Klasse\r
148    *  ueberschreiben werden.\r
149    *\r
150    * @param req Http-Request, das vom Dispatcher durchgereicht wird\r
151    * @param res Http-Response, die vom Dispatcher durchgereicht wird\r
152    */\r
153   public void list(HttpServletRequest req, HttpServletResponse res)\r
154       throws ServletModuleExc, ServletModuleUserExc, ServletModuleFailure {\r
155     try {\r
156       EntityList theList;\r
157       String offsetParam = req.getParameter("offset");\r
158       int offset = 0;\r
159       PrintWriter out = res.getWriter();\r
160 \r
161       // hier offsetcode bearbeiten\r
162       if (offsetParam != null && !offsetParam.equals("")) {\r
163         offset = Integer.parseInt(offsetParam);\r
164       }\r
165       if (req.getParameter("next") != null) {\r
166         offset = Integer.parseInt(req.getParameter("nextoffset"));\r
167       }\r
168       else {\r
169         if (req.getParameter("prev") != null) {\r
170           offset = Integer.parseInt(req.getParameter("prevoffset"));\r
171         }\r
172       }\r
173       theList = mainModule.getByWhereClause(null, offset);\r
174 \r
175       HTMLTemplateProcessor.process(res, templateListString, theList, null, null, out, getLocale(req), getFallbackLocale(req));\r
176     }\r
177     catch (Throwable e) {\r
178       throw new ServletModuleFailure(e);\r
179     }\r
180   }\r
181 \r
182   /**\r
183    *  add(req,res) - generische Addmethode. Wennn die Funktionalitaet\r
184    *  nicht reicht, muss sie in der abgeleiteten ServletModule-Klasse\r
185    *  ueberschreiben werden.\r
186    * @param req Http-Request, das vom Dispatcher durchgereicht wird\r
187    * @param res Http-Response, die vom Dispatcher durchgereicht wird\r
188    */\r
189   public void add(HttpServletRequest req, HttpServletResponse res)\r
190       throws ServletModuleExc, ServletModuleUserExc, ServletModuleFailure  {\r
191 \r
192     try {\r
193       SimpleHash mergeData = new SimpleHash();\r
194       mergeData.put("new", "1");\r
195       deliver(req, res, mergeData, templateObjektString);\r
196     }\r
197     catch (Throwable e) {\r
198       throw new ServletModuleFailure(e);\r
199     }\r
200   }\r
201 \r
202   /**\r
203    *  insert(req,res) - generische Insertmethode, folgt auf add.\r
204    *  Wennn die Funktionalitaet\r
205    *  nicht reicht, muss sie in der abgeleiteten ServletModule-Klasse\r
206    *  ueberschreiben werden.\r
207    *\r
208    * @param req Http-Request, das vom Dispatcher durchgereicht wird\r
209    * @param res Http-Response, die vom Dispatcher durchgereicht wird\r
210    */\r
211   public void insert(HttpServletRequest req, HttpServletResponse res)\r
212       throws ServletModuleExc, ServletModuleUserExc, ServletModuleFailure  {\r
213     try {\r
214       Map withValues = getIntersectingValues(req, mainModule.getStorageObject());\r
215       logger.debug("--trying to add...");\r
216       String id = mainModule.add(withValues);\r
217       logger.debug("--trying to deliver..." + id);\r
218       list(req, res);\r
219     }\r
220     catch (Throwable e) {\r
221       throw new ServletModuleFailure(e);\r
222     }\r
223   }\r
224 \r
225   /**\r
226    *  delete(req,res) - generic delete method. Can be overridden in subclasses.\r
227    *\r
228    */\r
229 \r
230   public void delete(HttpServletRequest req, HttpServletResponse res)\r
231       throws ServletModuleExc, ServletModuleUserExc, ServletModuleFailure  {\r
232     try {\r
233       String idParam = req.getParameter("id");\r
234 \r
235       if (idParam == null)\r
236         throw new ServletModuleExc("Invalid call to delete: no id supplied");\r
237 \r
238       String confirmParam = req.getParameter("confirm");\r
239       String cancelParam = req.getParameter("cancel");\r
240       if (confirmParam == null && cancelParam == null) {\r
241         SimpleHash mergeData = new SimpleHash();\r
242 \r
243         mergeData.put("module", getOperationModuleName());\r
244         mergeData.put("infoString", getOperationModuleName() + ": " + idParam);\r
245         mergeData.put("id", idParam);\r
246         mergeData.put("where", req.getParameter("where"));\r
247         mergeData.put("order", req.getParameter("order"));\r
248         mergeData.put("offset", req.getParameter("offset"));\r
249         // this stuff is to be compatible with the other more advanced\r
250         // search method used for media and comments\r
251         mergeData.put("query_media_folder", req.getParameter("query_media_folder"));\r
252         mergeData.put("query_is_published", req.getParameter("query_is_published"));\r
253         mergeData.put("query_text", req.getParameter("query_text"));\r
254         mergeData.put("query_field", req.getParameter("query_field"));\r
255 \r
256         deliver(req, res, mergeData, templateConfirmString);\r
257       }\r
258       else {\r
259         if (confirmParam != null && !confirmParam.equals("")) {\r
260           //theLog.printInfo("delete confirmed!");\r
261           mainModule.deleteById(idParam);\r
262           list(req, res); // back to list\r
263         }\r
264         else {\r
265           if (req.getParameter("where") != null)\r
266             list(req, res);\r
267           else\r
268             edit(req, res);\r
269         }\r
270       }\r
271     }\r
272     catch (Throwable e) {\r
273       throw new ServletModuleFailure(e);\r
274     }\r
275   }\r
276 \r
277   /**\r
278    *  edit(req,res) - generische Editmethode. Wennn die Funktionalitaet\r
279    *  nicht reicht, muss sie in der abgeleiteten ServletModule-Klasse\r
280    *  ueberschreiben werden.\r
281    *\r
282    * @param req Http-Request, das vom Dispatcher durchgereicht wird\r
283    * @param res Http-Response, die vom Dispatcher durchgereicht wird\r
284    */\r
285   public void edit(HttpServletRequest req, HttpServletResponse res)\r
286       throws ServletModuleExc, ServletModuleUserExc, ServletModuleFailure  {\r
287     edit(req, res, req.getParameter("id"));\r
288   }\r
289 \r
290   /**\r
291    *  edit(req,res) - generische Editmethode. Wennn die Funktionalitaet\r
292    *  nicht reicht, muss sie in der abgeleiteten ServletModule-Klasse\r
293    *  ueberschreiben werden.\r
294    *\r
295    * @param req Http-Request, das vom Dispatcher durchgereicht wird\r
296    * @param res Http-Response, die vom Dispatcher durchgereicht wird\r
297    */\r
298   public void edit(HttpServletRequest aRequest, HttpServletResponse aResponse, String anIdentifier)\r
299       throws ServletModuleExc, ServletModuleUserExc, ServletModuleFailure  {\r
300     try {\r
301       deliver(aRequest, aResponse, mainModule.getById(anIdentifier), templateObjektString);\r
302     }\r
303     catch (Throwable e) {\r
304       throw new ServletModuleFailure(e);\r
305     }\r
306   }\r
307 \r
308   /**\r
309    *  update(req,res) - generische Updatemethode. Wennn die Funktionalitaet\r
310    *  nicht reicht, muss sie in der abgeleiteten ServletModule-Klasse\r
311    *  ueberschreiben werden.\r
312    *\r
313    * @param req Http-Request, das vom Dispatcher durchgereicht wird\r
314    * @param res Http-Response, die vom Dispatcher durchgereicht wird\r
315    */\r
316 \r
317   public void update(HttpServletRequest req, HttpServletResponse res)\r
318       throws ServletModuleExc, ServletModuleUserExc, ServletModuleFailure  {\r
319     try {\r
320       String idParam = req.getParameter("id");\r
321       Map withValues = getIntersectingValues(req, mainModule.getStorageObject());\r
322 \r
323       String id = mainModule.set(withValues);\r
324       String whereParam = req.getParameter("where");\r
325       String orderParam = req.getParameter("order");\r
326 \r
327       if ((whereParam != null && !whereParam.equals("")) || (orderParam != null && !orderParam.equals(""))) {\r
328         list(req, res);\r
329       }\r
330       else {\r
331         edit(req, res);\r
332       }\r
333     }\r
334     catch (Throwable e) {\r
335       throw new ServletModuleFailure(e);\r
336     }\r
337   }\r
338 \r
339   /**\r
340    * deliver liefert das Template mit dem Filenamen templateFilename\r
341    * an den HttpServletResponse res aus, nachdem es mit den Daten aus\r
342    * TemplateModelRoot rtm gemischt wurde\r
343    *\r
344    * @param res Http-Response, die vom Dispatcher durchgereicht wird\r
345    * @param rtm beinahalten das freemarker.template.TempalteModelRoot mit den\r
346    *   Daten, die ins Template gemerged werden sollen.\r
347    * @param tmpl Name des Templates\r
348    * @exception ServletModuleException\r
349    */\r
350   public void deliver(HttpServletRequest req, HttpServletResponse res, TemplateModelRoot rtm,\r
351          TemplateModelRoot popups, String templateFilename) throws ServletModuleFailure  {\r
352     if (rtm == null)\r
353       rtm = new SimpleHash();\r
354 \r
355     try {\r
356       PrintWriter out = res.getWriter();\r
357       HTMLTemplateProcessor.process(res, templateFilename, rtm, popups, out, getLocale(req), getFallbackLocale(req));\r
358 \r
359       // we default to admin bundles here, which is not exactly beautiful...\r
360       // but this whole producer stuff is going to be rewritten soon.\r
361       // ServletModuleOpenIndy overwrites deliver() to use open bundles\r
362       // (br1)\r
363       out.close();\r
364     }\r
365     catch (Throwable e) {\r
366       throw new ServletModuleFailure(e);\r
367     }\r
368   }\r
369 \r
370 \r
371   /**\r
372    * deliver liefert das Template mit dem Filenamen templateFilename\r
373    * an den HttpServletResponse res aus, nachdem es mit den Daten aus\r
374    * TemplateModelRoot rtm gemischt wurde\r
375    *\r
376    * @param res Http-Response, die vom Dispatcher durchgereicht wird\r
377    * @param rtm beinahalten das freemarker.template.TempalteModelRoot mit den\r
378    *   Daten, die ins Template gemerged werden sollen.\r
379    * @param tmpl Name des Templates\r
380    * @exception ServletModuleException\r
381    */\r
382   public void deliver(HttpServletRequest req, HttpServletResponse res,\r
383         TemplateModelRoot rtm, String templateFilename) throws ServletModuleFailure {\r
384     deliver(req, res, rtm, null, templateFilename);\r
385   }\r
386 \r
387   /**\r
388    * deliver liefert das Template mit dem Filenamen templateFilename\r
389    * an den HttpServletResponse res aus, nachdem es mit den Daten aus\r
390    * TemplateModelRoot rtm gemischt wurde\r
391    *\r
392    * @param res Http-Response, die vom Dispatcher durchgereicht wird\r
393    * @param rtm beinahalten das freemarker.template.TempalteModelRoot mit den\r
394    *   Daten, die ins Template gemerged werden sollen.\r
395    * @param tmpl Name des Templates\r
396    * @exception ServletModuleException\r
397    */\r
398   public void deliver_compressed(HttpServletRequest req, HttpServletResponse res,\r
399                                  TemplateModelRoot rtm, String templateFilename)\r
400       throws ServletModuleFailure {\r
401     if (rtm == null) rtm = new SimpleHash();\r
402     try {\r
403       PrintWriter out = new LineFilterWriter(res.getWriter());\r
404       //PrintWriter out =  res.getWriter();\r
405       HTMLTemplateProcessor.process(res, templateFilename, rtm, null, out, getLocale(req), getFallbackLocale(req));\r
406       out.close();\r
407     }\r
408     catch (Throwable e) {\r
409       throw new ServletModuleFailure(e);\r
410     }\r
411   }\r
412 \r
413   /**\r
414    * deliver liefert das Template mit dem Filenamen templateFilename\r
415    * an den HttpServletResponse res aus, nachdem es mit den Daten aus\r
416    * TemplateModelRoot rtm gemischt wurde\r
417    *\r
418    * @param out ist der OutputStream, in den die gergten Daten geschickt werden sollen.\r
419    * @param rtm beinahalten das freemarker.template.TempalteModelRoot mit den\r
420    *   Daten, die ins Template gemerged werden sollen.\r
421    * @param tmpl Name des Templates\r
422    * @exception ServletModuleException\r
423    */\r
424   private void deliver(HttpServletResponse res, HttpServletRequest req, PrintWriter out,\r
425                        TemplateModelRoot rtm, String templateFilename)\r
426       throws ServletModuleFailure {\r
427     try {\r
428       HTMLTemplateProcessor.process(res, templateFilename, rtm, null, out, getLocale(req), getFallbackLocale(req));\r
429     }\r
430     catch (Throwable e) {\r
431       throw new ServletModuleFailure(e);\r
432     }\r
433   }\r
434 \r
435   /**\r
436    *  Wenn die abgeleitete Klasse diese Methode ueberschreibt und einen String mit einem\r
437    *  Methodennamen zurueckliefert, dann wird diese Methode bei fehlender Angabe des\r
438    *  doParameters ausgefuehrt.\r
439    *\r
440    * @return Name der Default-Action\r
441    */\r
442   public String defaultAction() {\r
443     return defaultAction;\r
444   }\r
445 \r
446   /**\r
447    * Gets the fields from a httprequest and matches them with the metadata from\r
448    * the storage object. Returns the keys that match, with their values.\r
449    *\r
450    * @return Map with the values\r
451    */\r
452   public Map getIntersectingValues(HttpServletRequest req, StorageObject theStorage)\r
453       throws ServletModuleExc, ServletModuleFailure {\r
454 \r
455     try {\r
456       HTTPRequestParser parser;\r
457       List theFieldList;\r
458 \r
459       logger.debug("using charset: " + req.getParameter("charset"));\r
460       logger.debug("using method: " + req.getParameter("do"));\r
461       if (req.getParameter("charset") != null) {\r
462         parser = new HTTPRequestParser(req, req.getParameter("charset"));\r
463         logger.debug("using charset: " + req.getParameter("charset"));\r
464         logger.debug("original charset: " + req.getCharacterEncoding());\r
465       }\r
466       else {\r
467         parser = new HTTPRequestParser(req);\r
468       }\r
469 \r
470       theFieldList = theStorage.getFields();\r
471 \r
472       Map withValues = new HashMap();\r
473       String aField, aValue;\r
474 \r
475       for (int i = 0; i < theFieldList.size(); i++) {\r
476         aField = (String) theFieldList.get(i);\r
477 \r
478         aValue = parser.getParameter(aField);\r
479         if (aValue != null)\r
480           withValues.put(aField, aValue);\r
481       }\r
482       return withValues;\r
483     }\r
484     catch (Throwable e) {\r
485       e.printStackTrace(logger.asPrintWriter(LoggerWrapper.DEBUG_MESSAGE));\r
486 \r
487       throw new ServletModuleFailure( "ServletModule.getIntersectingValues: " + e.getMessage(), e);\r
488     }\r
489   }\r
490 \r
491 }\r