add hidden fields for media search functions
[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 module name to be used for generic operations like delete.
89    */
90   protected String getOperationModuleName() {
91     return getClass().getName().substring((new String("mircoders.servlet.ServletModule")).length());
92   }
93
94   /**
95    * get the session binded language
96    */
97   public String getLanguage(HttpServletRequest req) {
98     HttpSession session = req.getSession(false);
99     String language = (String) session.getAttribute("Language");
100     if (language == null) {
101       language = MirConfig.getProp("StandardLanguage");
102     }
103     return language;
104   }
105
106   /**
107    * get the locale either from the session or the accept-language header ot the request
108    * this supersedes getLanguage for the new i18n
109    */
110   public Locale getLocale(HttpServletRequest req) {
111     Locale loc = null;
112     HttpSession session = req.getSession(false);
113     if (session != null) {
114       // session can be null in case of logout
115       loc = (Locale) session.getAttribute("Locale");
116     }
117     // if there is nothing in the session get it fron the accept-language
118     if (loc == null) {
119       loc = req.getLocale();
120     }
121     return loc;
122   }
123
124   public void redirect(HttpServletResponse aResponse, String aQuery) throws ServletModuleException {
125     try {
126       aResponse.sendRedirect(MirConfig.getProp("RootUri") + "/Mir?"+aQuery);
127     }
128     catch (Throwable t) {
129       throw new ServletModuleException(t.getMessage());
130     }
131   }
132
133   /**
134    *  list(req,res) - generische Listmethode. Wennn die Funktionalitaet
135    *  nicht reicht, muss sie in der abgeleiteten ServletModule-Klasse
136    *  ueberschreiben werden.
137    *
138    * @param req Http-Request, das vom Dispatcher durchgereicht wird
139    * @param res Http-Response, die vom Dispatcher durchgereicht wird
140    */
141   public void list(HttpServletRequest req, HttpServletResponse res)
142       throws ServletModuleException {
143     try {
144       EntityList theList;
145       String offsetParam = req.getParameter("offset");
146       int offset = 0;
147       PrintWriter out = res.getWriter();
148
149       // hier offsetcode bearbeiten
150       if (offsetParam != null && !offsetParam.equals("")) {
151         offset = Integer.parseInt(offsetParam);
152       }
153       if (req.getParameter("next") != null) {
154         offset = Integer.parseInt(req.getParameter("nextoffset"));
155       }
156       else {
157         if (req.getParameter("prev") != null) {
158           offset = Integer.parseInt(req.getParameter("prevoffset"));
159         }
160       }
161       theList = mainModule.getByWhereClause(null, offset);
162
163       HTMLTemplateProcessor.process(res, templateListString, theList, out, getLocale(req));
164     }
165     catch (Exception e) {
166       throw new ServletModuleException(e.getMessage());
167     }
168   }
169
170   /**
171    *  add(req,res) - generische Addmethode. Wennn die Funktionalitaet
172    *  nicht reicht, muss sie in der abgeleiteten ServletModule-Klasse
173    *  ueberschreiben werden.
174    * @param req Http-Request, das vom Dispatcher durchgereicht wird
175    * @param res Http-Response, die vom Dispatcher durchgereicht wird
176    */
177   public void add(HttpServletRequest req, HttpServletResponse res)
178       throws ServletModuleException {
179
180     try {
181       SimpleHash mergeData = new SimpleHash();
182       mergeData.put("new", "1");
183       deliver(req, res, mergeData, templateObjektString);
184     }
185     catch (Exception e) {
186       throw new ServletModuleException(e.getMessage());
187     }
188   }
189
190   /**
191    *  insert(req,res) - generische Insertmethode, folgt auf add.
192    *  Wennn die Funktionalitaet
193    *  nicht reicht, muss sie in der abgeleiteten ServletModule-Klasse
194    *  ueberschreiben werden.
195    *
196    * @param req Http-Request, das vom Dispatcher durchgereicht wird
197    * @param res Http-Response, die vom Dispatcher durchgereicht wird
198    */
199   public void insert(HttpServletRequest req, HttpServletResponse res)
200       throws ServletModuleException, ServletModuleUserException {
201     try {
202       HashMap withValues = getIntersectingValues(req, mainModule.getStorageObject());
203       logger.debug("--trying to add...");
204       String id = mainModule.add(withValues);
205       logger.debug("--trying to deliver..." + id);
206       list(req, res);
207     }
208     catch (Exception e) {
209       throw new ServletModuleException(e.getMessage());
210     }
211   }
212
213   /**
214    *  delete(req,res) - generic delete method. Can be overridden in subclasses.
215    *
216    */
217
218   public void delete(HttpServletRequest req, HttpServletResponse res) throws ServletModuleException {
219     try {
220       String idParam = req.getParameter("id");
221
222       if (idParam == null)
223         throw new ServletModuleException("Invalid call to delete: no id supplied");
224
225       String confirmParam = req.getParameter("confirm");
226       String cancelParam = req.getParameter("cancel");
227       if (confirmParam == null && cancelParam == null) {
228         SimpleHash mergeData = new SimpleHash();
229
230         mergeData.put("module", getOperationModuleName());
231         mergeData.put("infoString", getOperationModuleName() + ": " + idParam);
232         mergeData.put("id", idParam);
233         mergeData.put("where", req.getParameter("where"));
234         mergeData.put("order", req.getParameter("order"));
235         mergeData.put("offset", req.getParameter("offset"));
236         // this stuff is to be compatible with the other more advanced
237         // search method used for media and comments
238         mergeData.put("query_media_folder", req.getParameter("query_media_folder"));
239         mergeData.put("query_is_published", req.getParameter("query_is_published"));
240         mergeData.put("query_text", req.getParameter("query_text"));
241         mergeData.put("query_field", req.getParameter("query_field"));
242
243         deliver(req, res, mergeData, templateConfirmString);
244       }
245       else {
246         if (confirmParam != null && !confirmParam.equals("")) {
247           //theLog.printInfo("delete confirmed!");
248           mainModule.deleteById(idParam);
249           list(req, res); // back to list
250         }
251         else {
252           if (req.getParameter("where") != null)
253             list(req, res);
254           else
255             edit(req, res);
256         }
257       }
258     }
259     catch (Exception e) {
260       throw new ServletModuleException(e.getMessage());
261     }
262   }
263
264   /**
265    *  edit(req,res) - generische Editmethode. Wennn die Funktionalitaet
266    *  nicht reicht, muss sie in der abgeleiteten ServletModule-Klasse
267    *  ueberschreiben werden.
268    *
269    * @param req Http-Request, das vom Dispatcher durchgereicht wird
270    * @param res Http-Response, die vom Dispatcher durchgereicht wird
271    */
272   public void edit(HttpServletRequest req, HttpServletResponse res)
273       throws ServletModuleException {
274     try {
275       String idParam = req.getParameter("id");
276       deliver(req, res, mainModule.getById(idParam), templateObjektString);
277     }
278     catch (ModuleException e) {
279       throw new ServletModuleException(e.getMessage());
280     }
281   }
282
283   /**
284    *  update(req,res) - generische Updatemethode. Wennn die Funktionalitaet
285    *  nicht reicht, muss sie in der abgeleiteten ServletModule-Klasse
286    *  ueberschreiben werden.
287    *
288    * @param req Http-Request, das vom Dispatcher durchgereicht wird
289    * @param res Http-Response, die vom Dispatcher durchgereicht wird
290    */
291
292   public void update(HttpServletRequest req, HttpServletResponse res)
293       throws ServletModuleException {
294     try {
295       String idParam = req.getParameter("id");
296       HashMap withValues = getIntersectingValues(req, mainModule.getStorageObject());
297
298       String id = mainModule.set(withValues);
299       String whereParam = req.getParameter("where");
300       String orderParam = req.getParameter("order");
301
302       if ((whereParam != null && !whereParam.equals("")) || (orderParam != null && !orderParam.equals(""))) {
303         list(req, res);
304       }
305       else {
306         edit(req, res);
307       }
308     }
309     catch (Exception e) {
310       throw new ServletModuleException(e.getMessage());
311     }
312   }
313
314   /**
315    * deliver liefert das Template mit dem Filenamen templateFilename
316    * an den HttpServletResponse res aus, nachdem es mit den Daten aus
317    * TemplateModelRoot rtm gemischt wurde
318    *
319    * @param res Http-Response, die vom Dispatcher durchgereicht wird
320    * @param rtm beinahalten das freemarker.template.TempalteModelRoot mit den
321    *   Daten, die ins Template gemerged werden sollen.
322    * @param tmpl Name des Templates
323    * @exception ServletModuleException
324    */
325   public void deliver(HttpServletRequest req, HttpServletResponse res,
326                       TemplateModelRoot rtm, TemplateModelRoot popups,
327                       String templateFilename)
328       throws ServletModuleException {
329     if (rtm == null) rtm = new SimpleHash();
330     try {
331       PrintWriter out = res.getWriter();
332       HTMLTemplateProcessor.process(res, templateFilename, rtm, popups, out, getLocale(req));
333
334       // we default to admin bundles here, which is not exactly beautiful...
335       // but this whole producer stuff is going to be rewritten soon.
336       // ServletModuleOpenIndy overwrites deliver() to use open bundles
337       // (br1)
338       out.close();
339     }
340     catch (HTMLParseException e) {
341       throw new ServletModuleException(e.getMessage());
342     } catch (IOException e) {
343       throw new ServletModuleException(e.getMessage());
344     }
345   }
346
347
348   /**
349    * deliver liefert das Template mit dem Filenamen templateFilename
350    * an den HttpServletResponse res aus, nachdem es mit den Daten aus
351    * TemplateModelRoot rtm gemischt wurde
352    *
353    * @param res Http-Response, die vom Dispatcher durchgereicht wird
354    * @param rtm beinahalten das freemarker.template.TempalteModelRoot mit den
355    *   Daten, die ins Template gemerged werden sollen.
356    * @param tmpl Name des Templates
357    * @exception ServletModuleException
358    */
359   public void deliver(HttpServletRequest req, HttpServletResponse res,
360                       TemplateModelRoot rtm, String templateFilename)
361       throws ServletModuleException {
362     deliver(req, res, rtm, null, templateFilename);
363   }
364
365   /**
366    * deliver liefert das Template mit dem Filenamen templateFilename
367    * an den HttpServletResponse res aus, nachdem es mit den Daten aus
368    * TemplateModelRoot rtm gemischt wurde
369    *
370    * @param res Http-Response, die vom Dispatcher durchgereicht wird
371    * @param rtm beinahalten das freemarker.template.TempalteModelRoot mit den
372    *   Daten, die ins Template gemerged werden sollen.
373    * @param tmpl Name des Templates
374    * @exception ServletModuleException
375    */
376   public void deliver_compressed(HttpServletRequest req, HttpServletResponse res,
377                                  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.getMessage());
388     }
389     catch (IOException e) {
390       throw new ServletModuleException(e.getMessage());
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,
406                        TemplateModelRoot rtm, String templateFilename)
407       throws HTMLParseException {
408     HTMLTemplateProcessor.process(res, templateFilename, rtm, out, getLocale(req));
409   }
410
411   /**
412    *  Wenn die abgeleitete Klasse diese Methode ueberschreibt und einen String mit einem
413    *  Methodennamen zurueckliefert, dann wird diese Methode bei fehlender Angabe des
414    *  doParameters ausgefuehrt.
415    *
416    * @return Name der Default-Action
417    */
418   public String defaultAction() {
419     return defaultAction;
420   }
421
422   /**
423    *  Hier kann vor der Datenaufbereitung schon mal ein response geschickt
424    *  werden (um das subjektive Antwortverhalten bei langsamen Verbindungen
425    *  zu verbessern).
426    */
427   public void predeliver(HttpServletRequest req, HttpServletResponse res) {
428     ;
429   }
430
431   /**
432    * Holt die Felder aus der Metadatenfelderliste des StorageObjects, die
433    * im HttpRequest vorkommen und liefert sie als HashMap zurueck
434    *
435    * @return HashMap mit den Werten
436    */
437   public HashMap getIntersectingValues(HttpServletRequest req, StorageObject theStorage)
438       throws ServletModuleException {
439     ArrayList theFieldList;
440     try {
441       theFieldList = theStorage.getFields();
442     }
443     catch (StorageObjectException e) {
444       throw new ServletModuleException("ServletModule.getIntersectingValues: " + e.getMessage());
445     }
446
447     HashMap withValues = new HashMap();
448     String aField, aValue;
449
450     for (int i = 0; i < theFieldList.size(); i++) {
451       aField = (String) theFieldList.get(i);
452       aValue = req.getParameter(aField);
453       if (aValue != null) withValues.put(aField, aValue);
454     }
455     return withValues;
456   }
457
458 }