various fixes/cleanup: old producers are now completely gone, old logfile class too
[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.IOException;\r
35 import java.io.PrintWriter;\r
36 import java.util.List;\r
37 import java.util.HashMap;\r
38 import java.util.Locale;\r
39 \r
40 import javax.servlet.http.HttpServletRequest;\r
41 import javax.servlet.http.HttpServletResponse;\r
42 import javax.servlet.http.HttpSession;\r
43 \r
44 import freemarker.template.SimpleHash;\r
45 import freemarker.template.TemplateModelRoot;\r
46 \r
47 import mir.config.MirPropertiesConfiguration;\r
48 import mir.config.MirPropertiesConfiguration.PropertiesConfigExc;\r
49 import mir.entity.EntityList;\r
50 import mir.log.LoggerWrapper;\r
51 import mir.misc.HTMLParseException;\r
52 import mir.misc.HTMLTemplateProcessor;\r
53 import mir.misc.LineFilterWriter;\r
54 import mir.module.AbstractModule;\r
55 import mir.module.ModuleException;\r
56 import mir.storage.StorageObject;\r
57 import mir.storage.StorageObjectFailure;\r
58 \r
59 import mir.util.*;\r
60 \r
61 \r
62 \r
63 \r
64 /**\r
65  * Abstract class ServletModule provides the base functionality for servlets.\r
66  * Deriving a class from ServletModule enables class to insert/edit/update/delete\r
67  * and list Entity from a Database via mainModule.\r
68  *\r
69  *\r
70  *  Abstrakte Klasse ServletModule stellt die Basisfunktionalitaet der\r
71  *  abgeleiteten ServletModule zur Verf?gung.\r
72  *\r
73  * @version 28.6.1999\r
74  * @author RK\r
75  */\r
76 \r
77 public abstract class ServletModule {\r
78 \r
79   public String defaultAction;\r
80   protected LoggerWrapper logger;\r
81         protected MirPropertiesConfiguration configuration;\r
82   protected AbstractModule mainModule;\r
83   protected String templateListString;\r
84   protected String templateObjektString;\r
85   protected String templateConfirmString;\r
86 \r
87 \r
88   public ServletModule(){\r
89     try {\r
90       configuration = MirPropertiesConfiguration.instance();\r
91     }\r
92     catch (PropertiesConfigExc e) {\r
93       throw new RuntimeException("Can't get configuration: " + e.getMessage());\r
94     }\r
95   }\r
96 \r
97 \r
98   /**\r
99    * Singelton - Methode muss in den abgeleiteten Klassen ueberschrieben werden.\r
100    * @return ServletModule\r
101    */\r
102   public static ServletModule getInstance() {\r
103     return null;\r
104   }\r
105 \r
106   /**\r
107    * get the module name to be used for generic operations like delete.\r
108    */\r
109   protected String getOperationModuleName() {\r
110     return getClass().getName().substring((new String("mircoders.servlet.ServletModule")).length());\r
111   }\r
112 \r
113   /**\r
114    * get the session binded language\r
115    */\r
116   public String getLanguage(HttpServletRequest req) {\r
117     HttpSession session = req.getSession(false);\r
118     String language = (String) session.getAttribute("Language");\r
119     if (language == null) {\r
120       language = configuration.getString("StandardLanguage");\r
121     }\r
122     return language;\r
123   }\r
124 \r
125   /**\r
126    * get the locale either from the session or the accept-language header ot the request\r
127    * this supersedes getLanguage for the new i18n\r
128    */\r
129   public Locale getLocale(HttpServletRequest req) {\r
130     Locale loc = null;\r
131     HttpSession session = req.getSession(false);\r
132     if (session != null) {\r
133       // session can be null in case of logout\r
134       loc = (Locale) session.getAttribute("Locale");\r
135     }\r
136     // if there is nothing in the session get it fron the accept-language\r
137     if (loc == null) {\r
138       loc = req.getLocale();\r
139     }\r
140     return loc;\r
141   }\r
142 \r
143   public void redirect(HttpServletResponse aResponse, String aQuery) throws ServletModuleException {\r
144     try {\r
145       aResponse.sendRedirect(MirPropertiesConfiguration.instance().getString("RootUri") + "/Mir?"+aQuery);\r
146     }\r
147     catch (Throwable t) {\r
148       throw new ServletModuleException(t.getMessage());\r
149     }\r
150   }\r
151 \r
152   /**\r
153    *  list(req,res) - generische Listmethode. Wennn die Funktionalitaet\r
154    *  nicht reicht, muss sie in der abgeleiteten ServletModule-Klasse\r
155    *  ueberschreiben werden.\r
156    *\r
157    * @param req Http-Request, das vom Dispatcher durchgereicht wird\r
158    * @param res Http-Response, die vom Dispatcher durchgereicht wird\r
159    */\r
160   public void list(HttpServletRequest req, HttpServletResponse res)\r
161       throws ServletModuleException {\r
162     try {\r
163       EntityList theList;\r
164       String offsetParam = req.getParameter("offset");\r
165       int offset = 0;\r
166       PrintWriter out = res.getWriter();\r
167 \r
168       // hier offsetcode bearbeiten\r
169       if (offsetParam != null && !offsetParam.equals("")) {\r
170         offset = Integer.parseInt(offsetParam);\r
171       }\r
172       if (req.getParameter("next") != null) {\r
173         offset = Integer.parseInt(req.getParameter("nextoffset"));\r
174       }\r
175       else {\r
176         if (req.getParameter("prev") != null) {\r
177           offset = Integer.parseInt(req.getParameter("prevoffset"));\r
178         }\r
179       }\r
180       theList = mainModule.getByWhereClause(null, offset);\r
181 \r
182       HTMLTemplateProcessor.process(res, templateListString, theList, out, getLocale(req));\r
183     }\r
184     catch (Exception e) {\r
185       throw new ServletModuleException(e.getMessage());\r
186     }\r
187   }\r
188 \r
189   /**\r
190    *  add(req,res) - generische Addmethode. Wennn die Funktionalitaet\r
191    *  nicht reicht, muss sie in der abgeleiteten ServletModule-Klasse\r
192    *  ueberschreiben werden.\r
193    * @param req Http-Request, das vom Dispatcher durchgereicht wird\r
194    * @param res Http-Response, die vom Dispatcher durchgereicht wird\r
195    */\r
196   public void add(HttpServletRequest req, HttpServletResponse res)\r
197       throws ServletModuleException {\r
198 \r
199     try {\r
200       SimpleHash mergeData = new SimpleHash();\r
201       mergeData.put("new", "1");\r
202       deliver(req, res, mergeData, templateObjektString);\r
203     }\r
204     catch (Exception e) {\r
205       throw new ServletModuleException(e.getMessage());\r
206     }\r
207   }\r
208 \r
209   /**\r
210    *  insert(req,res) - generische Insertmethode, folgt auf add.\r
211    *  Wennn die Funktionalitaet\r
212    *  nicht reicht, muss sie in der abgeleiteten ServletModule-Klasse\r
213    *  ueberschreiben werden.\r
214    *\r
215    * @param req Http-Request, das vom Dispatcher durchgereicht wird\r
216    * @param res Http-Response, die vom Dispatcher durchgereicht wird\r
217    */\r
218   public void insert(HttpServletRequest req, HttpServletResponse res)\r
219       throws ServletModuleException, ServletModuleUserException {\r
220     try {\r
221       HashMap withValues = getIntersectingValues(req, mainModule.getStorageObject());\r
222       logger.debug("--trying to add...");\r
223       String id = mainModule.add(withValues);\r
224       logger.debug("--trying to deliver..." + id);\r
225       list(req, res);\r
226     }\r
227     catch (Exception e) {\r
228       throw new ServletModuleException(e.getMessage());\r
229     }\r
230   }\r
231 \r
232   /**\r
233    *  delete(req,res) - generic delete method. Can be overridden in subclasses.\r
234    *\r
235    */\r
236 \r
237   public void delete(HttpServletRequest req, HttpServletResponse res) throws ServletModuleException {\r
238     try {\r
239       String idParam = req.getParameter("id");\r
240 \r
241       if (idParam == null)\r
242         throw new ServletModuleException("Invalid call to delete: no id supplied");\r
243 \r
244       String confirmParam = req.getParameter("confirm");\r
245       String cancelParam = req.getParameter("cancel");\r
246       if (confirmParam == null && cancelParam == null) {\r
247         SimpleHash mergeData = new SimpleHash();\r
248 \r
249         mergeData.put("module", getOperationModuleName());\r
250         mergeData.put("infoString", getOperationModuleName() + ": " + idParam);\r
251         mergeData.put("id", idParam);\r
252         mergeData.put("where", req.getParameter("where"));\r
253         mergeData.put("order", req.getParameter("order"));\r
254         mergeData.put("offset", req.getParameter("offset"));\r
255         // this stuff is to be compatible with the other more advanced\r
256         // search method used for media and comments\r
257         mergeData.put("query_media_folder", req.getParameter("query_media_folder"));\r
258         mergeData.put("query_is_published", req.getParameter("query_is_published"));\r
259         mergeData.put("query_text", req.getParameter("query_text"));\r
260         mergeData.put("query_field", req.getParameter("query_field"));\r
261 \r
262         deliver(req, res, mergeData, templateConfirmString);\r
263       }\r
264       else {\r
265         if (confirmParam != null && !confirmParam.equals("")) {\r
266           //theLog.printInfo("delete confirmed!");\r
267           mainModule.deleteById(idParam);\r
268           list(req, res); // back to list\r
269         }\r
270         else {\r
271           if (req.getParameter("where") != null)\r
272             list(req, res);\r
273           else\r
274             edit(req, res);\r
275         }\r
276       }\r
277     }\r
278     catch (Exception e) {\r
279       throw new ServletModuleException(e.getMessage());\r
280     }\r
281   }\r
282 \r
283   /**\r
284    *  edit(req,res) - generische Editmethode. Wennn die Funktionalitaet\r
285    *  nicht reicht, muss sie in der abgeleiteten ServletModule-Klasse\r
286    *  ueberschreiben werden.\r
287    *\r
288    * @param req Http-Request, das vom Dispatcher durchgereicht wird\r
289    * @param res Http-Response, die vom Dispatcher durchgereicht wird\r
290    */\r
291   public void edit(HttpServletRequest req, HttpServletResponse res)\r
292       throws ServletModuleException {\r
293     try {\r
294       String idParam = req.getParameter("id");\r
295       deliver(req, res, mainModule.getById(idParam), templateObjektString);\r
296     }\r
297     catch (ModuleException e) {\r
298       throw new ServletModuleException(e.getMessage());\r
299     }\r
300   }\r
301 \r
302   /**\r
303    *  update(req,res) - generische Updatemethode. Wennn die Funktionalitaet\r
304    *  nicht reicht, muss sie in der abgeleiteten ServletModule-Klasse\r
305    *  ueberschreiben werden.\r
306    *\r
307    * @param req Http-Request, das vom Dispatcher durchgereicht wird\r
308    * @param res Http-Response, die vom Dispatcher durchgereicht wird\r
309    */\r
310 \r
311   public void update(HttpServletRequest req, HttpServletResponse res)\r
312       throws ServletModuleException {\r
313     try {\r
314       String idParam = req.getParameter("id");\r
315       HashMap withValues = getIntersectingValues(req, mainModule.getStorageObject());\r
316 \r
317       String id = mainModule.set(withValues);\r
318       String whereParam = req.getParameter("where");\r
319       String orderParam = req.getParameter("order");\r
320 \r
321       if ((whereParam != null && !whereParam.equals("")) || (orderParam != null && !orderParam.equals(""))) {\r
322         list(req, res);\r
323       }\r
324       else {\r
325         edit(req, res);\r
326       }\r
327     }\r
328     catch (Exception e) {\r
329       throw new ServletModuleException(e.getMessage());\r
330     }\r
331   }\r
332 \r
333   /**\r
334    * deliver liefert das Template mit dem Filenamen templateFilename\r
335    * an den HttpServletResponse res aus, nachdem es mit den Daten aus\r
336    * TemplateModelRoot rtm gemischt wurde\r
337    *\r
338    * @param res Http-Response, die vom Dispatcher durchgereicht wird\r
339    * @param rtm beinahalten das freemarker.template.TempalteModelRoot mit den\r
340    *   Daten, die ins Template gemerged werden sollen.\r
341    * @param tmpl Name des Templates\r
342    * @exception ServletModuleException\r
343    */\r
344   public void deliver(HttpServletRequest req, HttpServletResponse res,\r
345                       TemplateModelRoot rtm, TemplateModelRoot popups,\r
346                       String templateFilename)\r
347       throws ServletModuleException {\r
348     if (rtm == null) rtm = new SimpleHash();\r
349     try {\r
350       PrintWriter out = res.getWriter();\r
351       HTMLTemplateProcessor.process(res, templateFilename, rtm, popups, out, getLocale(req));\r
352 \r
353       // we default to admin bundles here, which is not exactly beautiful...\r
354       // but this whole producer stuff is going to be rewritten soon.\r
355       // ServletModuleOpenIndy overwrites deliver() to use open bundles\r
356       // (br1)\r
357       out.close();\r
358     }\r
359     catch (HTMLParseException e) {\r
360       throw new ServletModuleException(e.getMessage());\r
361     } catch (IOException e) {\r
362       throw new ServletModuleException(e.getMessage());\r
363     }\r
364   }\r
365 \r
366 \r
367   /**\r
368    * deliver liefert das Template mit dem Filenamen templateFilename\r
369    * an den HttpServletResponse res aus, nachdem es mit den Daten aus\r
370    * TemplateModelRoot rtm gemischt wurde\r
371    *\r
372    * @param res Http-Response, die vom Dispatcher durchgereicht wird\r
373    * @param rtm beinahalten das freemarker.template.TempalteModelRoot mit den\r
374    *   Daten, die ins Template gemerged werden sollen.\r
375    * @param tmpl Name des Templates\r
376    * @exception ServletModuleException\r
377    */\r
378   public void deliver(HttpServletRequest req, HttpServletResponse res,\r
379                       TemplateModelRoot rtm, String templateFilename)\r
380       throws ServletModuleException {\r
381     deliver(req, res, rtm, null, templateFilename);\r
382   }\r
383 \r
384   /**\r
385    * deliver liefert das Template mit dem Filenamen templateFilename\r
386    * an den HttpServletResponse res aus, nachdem es mit den Daten aus\r
387    * TemplateModelRoot rtm gemischt wurde\r
388    *\r
389    * @param res Http-Response, die vom Dispatcher durchgereicht wird\r
390    * @param rtm beinahalten das freemarker.template.TempalteModelRoot mit den\r
391    *   Daten, die ins Template gemerged werden sollen.\r
392    * @param tmpl Name des Templates\r
393    * @exception ServletModuleException\r
394    */\r
395   public void deliver_compressed(HttpServletRequest req, HttpServletResponse res,\r
396                                  TemplateModelRoot rtm, String templateFilename)\r
397       throws ServletModuleException {\r
398     if (rtm == null) rtm = new SimpleHash();\r
399     try {\r
400       PrintWriter out = new LineFilterWriter(res.getWriter());\r
401       //PrintWriter out =  res.getWriter();\r
402       HTMLTemplateProcessor.process(res, templateFilename, rtm, out, getLocale(req));\r
403       out.close();\r
404     }\r
405     catch (HTMLParseException e) {\r
406       throw new ServletModuleException(e.getMessage());\r
407     }\r
408     catch (IOException e) {\r
409       throw new ServletModuleException(e.getMessage());\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 HTMLParseException {\r
427     HTMLTemplateProcessor.process(res, templateFilename, rtm, out, getLocale(req));\r
428   }\r
429 \r
430   /**\r
431    *  Wenn die abgeleitete Klasse diese Methode ueberschreibt und einen String mit einem\r
432    *  Methodennamen zurueckliefert, dann wird diese Methode bei fehlender Angabe des\r
433    *  doParameters ausgefuehrt.\r
434    *\r
435    * @return Name der Default-Action\r
436    */\r
437   public String defaultAction() {\r
438     return defaultAction;\r
439   }\r
440 \r
441   /**\r
442    *  Hier kann vor der Datenaufbereitung schon mal ein response geschickt\r
443    *  werden (um das subjektive Antwortverhalten bei langsamen Verbindungen\r
444    *  zu verbessern).\r
445    */\r
446   public void predeliver(HttpServletRequest req, HttpServletResponse res) {\r
447     ;\r
448   }\r
449 \r
450   /**\r
451    * Holt die Felder aus der Metadatenfelderliste des StorageObjects, die\r
452    * im HttpRequest vorkommen und liefert sie als HashMap zurueck\r
453    *\r
454    * @return HashMap mit den Werten\r
455    */\r
456   public HashMap getIntersectingValues(HttpServletRequest req, StorageObject theStorage)\r
457       throws ServletModuleException {\r
458 \r
459     try {\r
460       HTTPRequestParser parser;\r
461       List theFieldList;\r
462 \r
463       logger.debug("using charset: " + req.getParameter("charset"));\r
464       logger.debug("using method: " + req.getParameter("do"));\r
465       if (req.getParameter("charset") != null) {\r
466         parser = new HTTPRequestParser(req, req.getParameter("charset"));\r
467         logger.debug("using charset: " + req.getParameter("charset"));\r
468         logger.debug("original charset: " + req.getCharacterEncoding());\r
469       }\r
470       else {\r
471         parser = new HTTPRequestParser(req);\r
472       }\r
473 \r
474       theFieldList = theStorage.getFields();\r
475 \r
476       HashMap withValues = new HashMap();\r
477       String aField, aValue;\r
478 \r
479       for (int i = 0; i < theFieldList.size(); i++) {\r
480         aField = (String) theFieldList.get(i);\r
481 \r
482         logger.debug("field " + aField + " = " + parser.getParameter(aField));\r
483 \r
484         aValue = parser.getParameter(aField);\r
485         if (aValue != null)\r
486           withValues.put(aField, aValue);\r
487       }\r
488       return withValues;\r
489     }\r
490     catch (Throwable e) {\r
491       e.printStackTrace(logger.asPrintWriter(logger.DEBUG_MESSAGE));\r
492       throw new ServletModuleException(\r
493           "ServletModule.getIntersectingValues: " + e.getMessage());\r
494     }\r
495   }\r
496 \r
497 }\r