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