Mir goes GPL
[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.misc.*;
40 import mir.module.AbstractModule;
41 import mir.module.ModuleException;
42 import mir.storage.StorageObject;
43 import mir.storage.StorageObjectException;
44
45 import javax.servlet.http.HttpServletRequest;
46 import javax.servlet.http.HttpServletResponse;
47 import javax.servlet.http.HttpSession;
48 import java.io.IOException;
49 import java.io.PrintWriter;
50 import java.util.ArrayList;
51 import java.util.HashMap;
52 import java.util.Locale;
53
54
55 /**
56  * Abstract class ServletModule provides the base functionality for servlets.
57  * Deriving a class from ServletModule enables class to insert/edit/update/delete
58  * and list Entity from a Database via mainModule.
59  *
60  *
61  *  Abstrakte Klasse ServletModule stellt die Basisfunktionalitaet der
62  *  abgeleiteten ServletModule zur Verfügung.
63  *
64  * @version 28.6.1999
65  * @author RK
66  */
67
68 public abstract class ServletModule {
69
70     public String defaultAction;
71     protected Logfile theLog;
72     protected AbstractModule mainModule;
73     protected String templateListString;
74     protected String templateObjektString;
75     protected String templateConfirmString;
76
77     /**
78      * Singelton - Methode muss in den abgeleiteten Klassen ueberschrieben werden.
79      * @return ServletModule
80      */
81     public static ServletModule getInstance() {
82         return null;
83     }
84
85     /**
86      * get the session binded language
87      */
88     public String getLanguage(HttpServletRequest req) {
89         HttpSession session = req.getSession(false);
90         String language = (String) session.getAttribute("Language");
91         if (language == null) {
92             language = MirConfig.getProp("StandardLanguage");
93         }
94         return language;
95     }
96
97     /**
98      * get the locale either from the session or the accept-language header ot the request
99      * this supersedes getLanguage for the new i18n
100      */
101     public Locale getLocale(HttpServletRequest req) {
102         Locale loc = null;
103         HttpSession session = req.getSession(false);
104         if (session != null) {
105             // session can be null in case of logout
106             loc = (Locale) session.getAttribute("Locale");
107         }
108         // if there is nothing in the session get it fron the accept-language
109         if (loc == null) {
110             loc = req.getLocale();
111         }
112         return loc;
113     }
114
115     // ACHTUNG DEPRECATED::::
116     public void process(HttpServletRequest req, HttpServletResponse res) throws ServletModuleException {
117     }
118
119
120     /**
121      *  list(req,res) - generische Listmethode. Wennn die Funktionalitaet
122      *  nicht reicht, muss sie in der abgeleiteten ServletModule-Klasse
123      *  ueberschreiben werden.
124      *
125      * @param req Http-Request, das vom Dispatcher durchgereicht wird
126      * @param res Http-Response, die vom Dispatcher durchgereicht wird
127      */
128     public void list(HttpServletRequest req, HttpServletResponse res)
129             throws ServletModuleException {
130         try {
131             EntityList theList;
132             String offsetParam = req.getParameter("offset");
133             int offset = 0;
134             PrintWriter out = res.getWriter();
135
136             // hier offsetcode bearbeiten
137             if (offsetParam != null && !offsetParam.equals("")) {
138                 offset = Integer.parseInt(offsetParam);
139             }
140             if (req.getParameter("next") != null) {
141                 offset = Integer.parseInt(req.getParameter("nextoffset"));
142             }
143             else {
144                 if (req.getParameter("prev") != null) {
145                     offset = Integer.parseInt(req.getParameter("prevoffset"));
146                 }
147             }
148             theList = mainModule.getByWhereClause(null, offset);
149             //theList = mainModule.getByWhereClause((String)null, offset);
150             if (theList == null || theList.getCount() == 0 || theList.getCount() > 1) {
151                 HTMLTemplateProcessor.process(res, templateListString, theList, out, getLocale(req));
152             }
153             else {
154                 deliver(req, res, theList.elementAt(0), templateObjektString);
155             }
156         }
157         catch (Exception e) {
158             throw new ServletModuleException(e.toString());
159         }
160     }
161
162     /**
163      *  add(req,res) - generische Addmethode. Wennn die Funktionalitaet
164      *  nicht reicht, muss sie in der abgeleiteten ServletModule-Klasse
165      *  ueberschreiben werden.
166      * @param req Http-Request, das vom Dispatcher durchgereicht wird
167      * @param res Http-Response, die vom Dispatcher durchgereicht wird
168      */
169     public void add(HttpServletRequest req, HttpServletResponse res)
170             throws ServletModuleException {
171
172         try {
173             SimpleHash mergeData = new SimpleHash();
174             mergeData.put("new", "1");
175             deliver(req, res, mergeData, templateObjektString);
176         }
177         catch (Exception e) {
178             throw new ServletModuleException(e.toString());
179         }
180     }
181
182     /**
183      *  insert(req,res) - generische Insertmethode, folgt auf add.
184      *  Wennn die Funktionalitaet
185      *  nicht reicht, muss sie in der abgeleiteten ServletModule-Klasse
186      *  ueberschreiben werden.
187      *
188      * @param req Http-Request, das vom Dispatcher durchgereicht wird
189      * @param res Http-Response, die vom Dispatcher durchgereicht wird
190      */
191     public void insert(HttpServletRequest req, HttpServletResponse res)
192             throws ServletModuleException, ServletModuleUserException {
193         try {
194             HashMap withValues = getIntersectingValues(req, mainModule.getStorageObject());
195             theLog.printDebugInfo("--trying to add...");
196             String id = mainModule.add(withValues);
197             theLog.printDebugInfo("--trying to deliver..." + id);
198             list(req, res);
199         }
200         catch (Exception e) {
201             throw new ServletModuleException(e.toString());
202         }
203     }
204
205     /**
206      *  delete(req,res) - generische Deletemethode. Wennn die Funktionalitaet
207      *  nicht reicht, muss sie in der abgeleiteten ServletModule-Klasse
208      *  ueberschreiben werden.
209      *
210      * @param req Http-Request, das vom Dispatcher durchgereicht wird
211      * @param res Http-Response, die vom Dispatcher durchgereicht wird
212      */
213
214     public void delete(HttpServletRequest req, HttpServletResponse res)
215             throws ServletModuleException {
216         try {
217             String idParam = req.getParameter("id");
218             if (idParam == null) throw new ServletModuleException("Falscher Aufruf: (id) nicht angegeben");
219             // Hier code zum Loeschen
220             String confirmParam = req.getParameter("confirm");
221             String cancelParam = req.getParameter("cancel");
222             if (confirmParam == null && cancelParam == null) {
223                 // HTML Ausgabe zum Confirmen!
224                 SimpleHash mergeData = new SimpleHash();
225                 String moduleClassName = mainModule.getClass().getName();
226                 int i = moduleClassName.indexOf(".Module");
227                 String moduleName = moduleClassName.substring(i + 7);
228                 mergeData.put("module", moduleName);
229                 mergeData.put("infoString", moduleName + ": " + idParam);
230                 mergeData.put("id", idParam);
231                 mergeData.put("where", req.getParameter("where"));
232                 mergeData.put("order", req.getParameter("order"));
233                 mergeData.put("offset", req.getParameter("offset"));
234                 deliver(req, res, mergeData, templateConfirmString);
235             }
236             else {
237                 if (confirmParam != null && !confirmParam.equals("")) {
238                     //theLog.printInfo("delete confirmed!");
239                     mainModule.deleteById(idParam);
240                     list(req, res); // back to list
241                 }
242                 else {
243                     if (req.getParameter("where") != null)
244                         list(req, res);
245                     else
246                         edit(req, res);
247                 }
248             }
249         }
250         catch (Exception e) {
251             throw new ServletModuleException(e.toString());
252         }
253     }
254
255     /**
256      *  edit(req,res) - generische Editmethode. Wennn die Funktionalitaet
257      *  nicht reicht, muss sie in der abgeleiteten ServletModule-Klasse
258      *  ueberschreiben werden.
259      *
260      * @param req Http-Request, das vom Dispatcher durchgereicht wird
261      * @param res Http-Response, die vom Dispatcher durchgereicht wird
262      */
263     public void edit(HttpServletRequest req, HttpServletResponse res)
264             throws ServletModuleException {
265         try {
266             String idParam = req.getParameter("id");
267             deliver(req, res, mainModule.getById(idParam), templateObjektString);
268         }
269         catch (ModuleException e) {
270             throw new ServletModuleException(e.toString());
271         }
272     }
273
274     /**
275      *  update(req,res) - generische Updatemethode. Wennn die Funktionalitaet
276      *  nicht reicht, muss sie in der abgeleiteten ServletModule-Klasse
277      *  ueberschreiben werden.
278      *
279      * @param req Http-Request, das vom Dispatcher durchgereicht wird
280      * @param res Http-Response, die vom Dispatcher durchgereicht wird
281      */
282
283     public void update(HttpServletRequest req, HttpServletResponse res)
284             throws ServletModuleException {
285         try {
286             String idParam = req.getParameter("id");
287             HashMap withValues = getIntersectingValues(req, mainModule.getStorageObject());
288             String id = mainModule.set(withValues);
289             //theLog.printInfo("Showing Entity with id: " + id);
290             //edit(req,res);
291             String whereParam = req.getParameter("where");
292             String orderParam = req.getParameter("order");
293             if ((whereParam != null && !whereParam.equals("")) || (orderParam != null && !orderParam.equals(""))) {
294                 //theLog.printDebugInfo("update to list");
295                 list(req, res);
296             }
297             else {
298                 edit(req, res);
299             }
300             //list(req,res);
301         }
302         catch (Exception e) {
303             throw new ServletModuleException(e.toString());
304         }
305     }
306
307     /**
308      * deliver liefert das Template mit dem Filenamen templateFilename
309      * an den HttpServletResponse res aus, nachdem es mit den Daten aus
310      * TemplateModelRoot rtm gemischt wurde
311      *
312      * @param res Http-Response, die vom Dispatcher durchgereicht wird
313      * @param rtm beinahalten das freemarker.template.TempalteModelRoot mit den
314      *   Daten, die ins Template gemerged werden sollen.
315      * @param tmpl Name des Templates
316      * @exception ServletModuleException
317      */
318         public void deliver(HttpServletRequest req, HttpServletResponse res,
319                                                                                         TemplateModelRoot rtm, TemplateModelRoot popups,
320                                                                                         String templateFilename)
321         throws ServletModuleException {
322                 if (rtm == null) rtm = new SimpleHash();
323                 try {
324                         PrintWriter out = res.getWriter();
325                         HTMLTemplateProcessor.process(res, templateFilename, rtm, popups, out,
326                                                                                                                                                 getLocale(req));
327                         out.close();
328                 }       catch (HTMLParseException e) {
329                         throw new ServletModuleException(e.toString());
330                 } catch (IOException e) {
331                         throw new ServletModuleException(e.toString());
332                 }
333         }
334
335         
336         /**
337          * deliver liefert das Template mit dem Filenamen templateFilename
338          * an den HttpServletResponse res aus, nachdem es mit den Daten aus
339          * TemplateModelRoot rtm gemischt wurde
340          *
341          * @param res Http-Response, die vom Dispatcher durchgereicht wird
342          * @param rtm beinahalten das freemarker.template.TempalteModelRoot mit den
343          *   Daten, die ins Template gemerged werden sollen.
344          * @param tmpl Name des Templates
345          * @exception ServletModuleException
346          */
347         public void deliver(HttpServletRequest req, HttpServletResponse res,
348                                                                                         TemplateModelRoot rtm, String templateFilename)
349         throws ServletModuleException {
350                 deliver(req, res, rtm, null, templateFilename);
351         }
352         
353     /**
354      * deliver liefert das Template mit dem Filenamen templateFilename
355      * an den HttpServletResponse res aus, nachdem es mit den Daten aus
356      * TemplateModelRoot rtm gemischt wurde
357      *
358      * @param res Http-Response, die vom Dispatcher durchgereicht wird
359      * @param rtm beinahalten das freemarker.template.TempalteModelRoot mit den
360      *   Daten, die ins Template gemerged werden sollen.
361      * @param tmpl Name des Templates
362      * @exception ServletModuleException
363      */
364     public void deliver_compressed(HttpServletRequest req, HttpServletResponse res, TemplateModelRoot rtm, String templateFilename)
365             throws ServletModuleException {
366         if (rtm == null) rtm = new SimpleHash();
367         try {
368             PrintWriter out = new LineFilterWriter(res.getWriter());
369             //PrintWriter out =  res.getWriter();
370             HTMLTemplateProcessor.process(res, templateFilename, rtm, out, getLocale(req));
371             out.close();
372         }
373         catch (HTMLParseException e) {
374             throw new ServletModuleException(e.toString());
375         }
376         catch (IOException e) {
377             throw new ServletModuleException(e.toString());
378         }
379     }
380
381     /**
382      * deliver liefert das Template mit dem Filenamen templateFilename
383      * an den HttpServletResponse res aus, nachdem es mit den Daten aus
384      * TemplateModelRoot rtm gemischt wurde
385      *
386      * @param out ist der OutputStream, in den die gergten Daten geschickt werden sollen.
387      * @param rtm beinahalten das freemarker.template.TempalteModelRoot mit den
388      *   Daten, die ins Template gemerged werden sollen.
389      * @param tmpl Name des Templates
390      * @exception ServletModuleException
391      */
392     private void deliver(HttpServletResponse res, HttpServletRequest req, PrintWriter out, TemplateModelRoot rtm, String templateFilename)
393             throws HTMLParseException {
394         HTMLTemplateProcessor.process(res, templateFilename, rtm, out, getLocale(req));
395     }
396
397     /**
398      *  Wenn die abgeleitete Klasse diese Methode ueberschreibt und einen String mit einem
399      *  Methodennamen zurueckliefert, dann wird diese Methode bei fehlender Angabe des
400      *  doParameters ausgefuehrt.
401      *
402      * @return Name der Default-Action
403      */
404     public String defaultAction() {
405         return defaultAction;
406     }
407
408     /**
409      *  Hier kann vor der Datenaufbereitung schon mal ein response geschickt
410      *  werden (um das subjektive Antwortverhalten bei langsamen Verbindungen
411      *  zu verbessern).
412      */
413     public void predeliver(HttpServletRequest req, HttpServletResponse res) {
414         ;
415     }
416
417     /**
418      * Holt die Felder aus der Metadatenfelderliste des StorageObjects, die
419      * im HttpRequest vorkommen und liefert sie als HashMap zurueck
420      *
421      * @return HashMap mit den Werten
422      */
423     public HashMap getIntersectingValues(HttpServletRequest req, StorageObject theStorage)
424             throws ServletModuleException {
425         ArrayList theFieldList;
426         try {
427             theFieldList = theStorage.getFields();
428         }
429         catch (StorageObjectException e) {
430             throw new ServletModuleException("ServletModule.getIntersectingValues: " + e.toString());
431         }
432
433         HashMap withValues = new HashMap();
434         String aField, aValue;
435
436         for (int i = 0; i < theFieldList.size(); i++) {
437             aField = (String) theFieldList.get(i);
438             aValue = req.getParameter(aField);
439             if (aValue != null) withValues.put(aField, aValue);
440         }
441         return withValues;
442     }
443
444 }