add in advanced query parameters used by media and comment search to mergeData so...
[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 module name to be used for generic operations like delete.
87      */
88     protected String getOperationModuleName() {
89       return getClass().getName().substring((new String("mircoders.servlet.ServletModule")).length());
90     }
91
92     /**
93      * get the session binded language
94      */
95     public String getLanguage(HttpServletRequest req) {
96         HttpSession session = req.getSession(false);
97         String language = (String) session.getAttribute("Language");
98         if (language == null) {
99             language = MirConfig.getProp("StandardLanguage");
100         }
101         return language;
102     }
103
104     /**
105      * get the locale either from the session or the accept-language header ot the request
106      * this supersedes getLanguage for the new i18n
107      */
108     public Locale getLocale(HttpServletRequest req) {
109         Locale loc = null;
110         HttpSession session = req.getSession(false);
111         if (session != null) {
112             // session can be null in case of logout
113             loc = (Locale) session.getAttribute("Locale");
114         }
115         // if there is nothing in the session get it fron the accept-language
116         if (loc == null) {
117             loc = req.getLocale();
118         }
119         return loc;
120     }
121
122     // ACHTUNG DEPRECATED::::
123     public void process(HttpServletRequest req, HttpServletResponse res) throws ServletModuleException {
124     }
125
126
127     /**
128      *  list(req,res) - generische Listmethode. Wennn die Funktionalitaet
129      *  nicht reicht, muss sie in der abgeleiteten ServletModule-Klasse
130      *  ueberschreiben werden.
131      *
132      * @param req Http-Request, das vom Dispatcher durchgereicht wird
133      * @param res Http-Response, die vom Dispatcher durchgereicht wird
134      */
135     public void list(HttpServletRequest req, HttpServletResponse res)
136             throws ServletModuleException {
137
138         try {
139             EntityList theList;
140             String offsetParam = req.getParameter("offset");
141             int offset = 0;
142             PrintWriter out = res.getWriter();
143
144             // hier offsetcode bearbeiten
145             if (offsetParam != null && !offsetParam.equals("")) {
146                 offset = Integer.parseInt(offsetParam);
147             }
148             if (req.getParameter("next") != null) {
149                 offset = Integer.parseInt(req.getParameter("nextoffset"));
150             }
151             else {
152                 if (req.getParameter("prev") != null) {
153                     offset = Integer.parseInt(req.getParameter("prevoffset"));
154                 }
155             }
156
157             theList = mainModule.getByWhereClause(null, offset);
158             //theList = mainModule.getByWhereClause((String)null, offset);
159             if (theList == null || theList.getCount() == 0 || theList.getCount() > 1) {
160                 HTMLTemplateProcessor.process(res, templateListString, theList, out, getLocale(req));
161             }
162             else {
163                 deliver(req, res, theList.elementAt(0), templateObjektString);
164             }
165         }
166         catch (Exception e) {
167             throw new ServletModuleException(e.toString());
168         }
169     }
170
171     /**
172      *  add(req,res) - generische Addmethode. Wennn die Funktionalitaet
173      *  nicht reicht, muss sie in der abgeleiteten ServletModule-Klasse
174      *  ueberschreiben werden.
175      * @param req Http-Request, das vom Dispatcher durchgereicht wird
176      * @param res Http-Response, die vom Dispatcher durchgereicht wird
177      */
178     public void add(HttpServletRequest req, HttpServletResponse res)
179             throws ServletModuleException {
180
181         try {
182             SimpleHash mergeData = new SimpleHash();
183             mergeData.put("new", "1");
184             deliver(req, res, mergeData, templateObjektString);
185         }
186         catch (Exception e) {
187             throw new ServletModuleException(e.toString());
188         }
189     }
190
191     /**
192      *  insert(req,res) - generische Insertmethode, folgt auf add.
193      *  Wennn die Funktionalitaet
194      *  nicht reicht, muss sie in der abgeleiteten ServletModule-Klasse
195      *  ueberschreiben werden.
196      *
197      * @param req Http-Request, das vom Dispatcher durchgereicht wird
198      * @param res Http-Response, die vom Dispatcher durchgereicht wird
199      */
200     public void insert(HttpServletRequest req, HttpServletResponse res)
201             throws ServletModuleException, ServletModuleUserException {
202         try {
203             HashMap withValues = getIntersectingValues(req, mainModule.getStorageObject());
204             theLog.printDebugInfo("--trying to add...");
205             String id = mainModule.add(withValues);
206             theLog.printDebugInfo("--trying to deliver..." + id);
207             list(req, res);
208         }
209         catch (Exception e) {
210             throw new ServletModuleException(e.toString());
211         }
212     }
213
214     /**
215      *  delete(req,res) - generische Deletemethode. Wennn die Funktionalitaet
216      *  nicht reicht, muss sie in der abgeleiteten ServletModule-Klasse
217      *  ueberschreiben werden.
218      *
219      * @param req Http-Request, das vom Dispatcher durchgereicht wird
220      * @param res Http-Response, die vom Dispatcher durchgereicht wird
221      */
222
223     public void delete(HttpServletRequest req, HttpServletResponse res)
224             throws ServletModuleException {
225         try {
226             String idParam = req.getParameter("id");
227             if (idParam == null) throw new ServletModuleException("Invalid call to delete: no id supplied");
228             // Hier code zum Loeschen
229             String confirmParam = req.getParameter("confirm");
230             String cancelParam = req.getParameter("cancel");
231             if (confirmParam == null && cancelParam == null) {
232                 // HTML Ausgabe zum Confirmen!
233                 SimpleHash mergeData = new SimpleHash();
234                 String moduleName = getOperationModuleName();
235                 mergeData.put("module", moduleName);
236                 mergeData.put("infoString", moduleName + ": " + idParam);
237                 mergeData.put("id", idParam);
238                 mergeData.put("where", req.getParameter("where"));
239                 mergeData.put("order", req.getParameter("order"));
240                 mergeData.put("offset", req.getParameter("offset"));
241                 // this stuff is to be compatible with the other more advanced
242                 // search method used for media and comments
243                 mergeData.put("query_media_folder", req.getParameter("query_media_folder"));
244                 mergeData.put("query_is_published", req.getParameter("query_is_published"));
245                 mergeData.put("query_text", req.getParameter("query_text"));
246                 mergeData.put("query_field", req.getParameter("query_field"));
247                 deliver(req, res, mergeData, templateConfirmString);
248             }
249             else {
250                 if (confirmParam != null && !confirmParam.equals("")) {
251                     //theLog.printInfo("delete confirmed!");
252                     mainModule.deleteById(idParam);
253                     list(req, res); // back to list
254                 }
255                 else {
256                     if (req.getParameter("where") != null)
257                         list(req, res);
258                     else
259                         edit(req, res);
260                 }
261             }
262         }
263         catch (Exception e) {
264             throw new ServletModuleException(e.toString());
265         }
266     }
267
268     /**
269      *  edit(req,res) - generische Editmethode. Wennn die Funktionalitaet
270      *  nicht reicht, muss sie in der abgeleiteten ServletModule-Klasse
271      *  ueberschreiben werden.
272      *
273      * @param req Http-Request, das vom Dispatcher durchgereicht wird
274      * @param res Http-Response, die vom Dispatcher durchgereicht wird
275      */
276     public void edit(HttpServletRequest req, HttpServletResponse res)
277             throws ServletModuleException {
278         try {
279             String idParam = req.getParameter("id");
280             deliver(req, res, mainModule.getById(idParam), templateObjektString);
281         }
282         catch (ModuleException e) {
283             throw new ServletModuleException(e.toString());
284         }
285     }
286
287     /**
288      *  update(req,res) - generische Updatemethode. Wennn die Funktionalitaet
289      *  nicht reicht, muss sie in der abgeleiteten ServletModule-Klasse
290      *  ueberschreiben werden.
291      *
292      * @param req Http-Request, das vom Dispatcher durchgereicht wird
293      * @param res Http-Response, die vom Dispatcher durchgereicht wird
294      */
295
296     public void update(HttpServletRequest req, HttpServletResponse res)
297             throws ServletModuleException {
298         try {
299             String idParam = req.getParameter("id");
300             HashMap withValues = getIntersectingValues(req, mainModule.getStorageObject());
301             String id = mainModule.set(withValues);
302             //theLog.printInfo("Showing Entity with id: " + id);
303             //edit(req,res);
304             String whereParam = req.getParameter("where");
305             String orderParam = req.getParameter("order");
306             if ((whereParam != null && !whereParam.equals("")) || (orderParam != null && !orderParam.equals(""))) {
307                 //theLog.printDebugInfo("update to list");
308                 list(req, res);
309             }
310             else {
311                 edit(req, res);
312             }
313             //list(req,res);
314         }
315         catch (Exception e) {
316             throw new ServletModuleException(e.toString());
317         }
318     }
319
320     /**
321      * deliver liefert das Template mit dem Filenamen templateFilename
322      * an den HttpServletResponse res aus, nachdem es mit den Daten aus
323      * TemplateModelRoot rtm gemischt wurde
324      *
325      * @param res Http-Response, die vom Dispatcher durchgereicht wird
326      * @param rtm beinahalten das freemarker.template.TempalteModelRoot mit den
327      *   Daten, die ins Template gemerged werden sollen.
328      * @param tmpl Name des Templates
329      * @exception ServletModuleException
330      */
331         public void deliver(HttpServletRequest req, HttpServletResponse res,
332                                                                                         TemplateModelRoot rtm, TemplateModelRoot popups,
333                                                                                         String templateFilename)
334         throws ServletModuleException {
335                 if (rtm == null) rtm = new SimpleHash();
336                 try {
337                         PrintWriter out = res.getWriter();
338                         HTMLTemplateProcessor.process(res, templateFilename, rtm, popups, out,
339                                                                                                                                                 getLocale(req));
340                         out.close();
341                 }       catch (HTMLParseException e) {
342                         throw new ServletModuleException(e.toString());
343                 } catch (IOException e) {
344                         throw new ServletModuleException(e.toString());
345                 }
346         }
347
348         
349         /**
350          * deliver liefert das Template mit dem Filenamen templateFilename
351          * an den HttpServletResponse res aus, nachdem es mit den Daten aus
352          * TemplateModelRoot rtm gemischt wurde
353          *
354          * @param res Http-Response, die vom Dispatcher durchgereicht wird
355          * @param rtm beinahalten das freemarker.template.TempalteModelRoot mit den
356          *   Daten, die ins Template gemerged werden sollen.
357          * @param tmpl Name des Templates
358          * @exception ServletModuleException
359          */
360         public void deliver(HttpServletRequest req, HttpServletResponse res,
361                                                                                         TemplateModelRoot rtm, String templateFilename)
362         throws ServletModuleException {
363                 deliver(req, res, rtm, null, templateFilename);
364         }
365         
366     /**
367      * deliver liefert das Template mit dem Filenamen templateFilename
368      * an den HttpServletResponse res aus, nachdem es mit den Daten aus
369      * TemplateModelRoot rtm gemischt wurde
370      *
371      * @param res Http-Response, die vom Dispatcher durchgereicht wird
372      * @param rtm beinahalten das freemarker.template.TempalteModelRoot mit den
373      *   Daten, die ins Template gemerged werden sollen.
374      * @param tmpl Name des Templates
375      * @exception ServletModuleException
376      */
377     public void deliver_compressed(HttpServletRequest req, HttpServletResponse res, TemplateModelRoot rtm, String templateFilename)
378             throws ServletModuleException {
379         if (rtm == null) rtm = new SimpleHash();
380         try {
381             PrintWriter out = new LineFilterWriter(res.getWriter());
382             //PrintWriter out =  res.getWriter();
383             HTMLTemplateProcessor.process(res, templateFilename, rtm, out, getLocale(req));
384             out.close();
385         }
386         catch (HTMLParseException e) {
387             throw new ServletModuleException(e.toString());
388         }
389         catch (IOException e) {
390             throw new ServletModuleException(e.toString());
391         }
392     }
393
394     /**
395      * deliver liefert das Template mit dem Filenamen templateFilename
396      * an den HttpServletResponse res aus, nachdem es mit den Daten aus
397      * TemplateModelRoot rtm gemischt wurde
398      *
399      * @param out ist der OutputStream, in den die gergten Daten geschickt werden sollen.
400      * @param rtm beinahalten das freemarker.template.TempalteModelRoot mit den
401      *   Daten, die ins Template gemerged werden sollen.
402      * @param tmpl Name des Templates
403      * @exception ServletModuleException
404      */
405     private void deliver(HttpServletResponse res, HttpServletRequest req, PrintWriter out, 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.toString());
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 }