3eda4993e9292480d2ea7db80cb8eb296dea3c00
[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  any library licensed under the Apache Software License,
22  * The Sun (tm) Java Advanced Imaging library (JAI), The Sun JIMI library
23  * (or with modified versions of the above that use the same license as the above),
24  * and distribute linked combinations including the two.  You must obey the
25  * GNU General Public License in all respects for all of the code used other than
26  * the above mentioned libraries.  If you modify this file, you may extend this
27  * exception to your version of the file, but you are not obligated to do so.
28  * If you do not wish to do so, delete this exception statement from your version.
29  */
30 package mir.servlet;
31
32 import java.util.HashMap;
33 import java.util.Iterator;
34 import java.util.List;
35 import java.util.Locale;
36 import java.util.Map;
37
38 import javax.servlet.http.HttpServletRequest;
39 import javax.servlet.http.HttpServletResponse;
40 import javax.servlet.http.HttpSession;
41
42 import mir.config.MirPropertiesConfiguration;
43 import mir.config.MirPropertiesConfiguration.PropertiesConfigExc;
44 import mir.entity.adapter.EntityAdapterEngine;
45 import mir.entity.adapter.EntityAdapterModel;
46 import mir.log.LoggerWrapper;
47 import mir.module.AbstractModule;
48 import mir.storage.StorageObject;
49 import mir.util.HTTPRequestParser;
50 import mir.util.URLBuilder;
51 import mircoders.global.MirGlobal;
52 import mircoders.servlet.ServletHelper;
53
54 /**
55  *
56  * <p>Title: </p>
57  * <p>Description: </p>
58  * <p>Copyright: Copyright (c) 2003</p>
59  * <p>Company: </p>
60  * @author not attributable
61  * @version 1.0
62  */
63
64 public abstract class ServletModule {
65   public String defaultAction;
66   protected LoggerWrapper logger;
67   protected MirPropertiesConfiguration configuration;
68   protected Locale fallbackLocale;
69
70   protected AbstractModule mainModule;
71   protected String definition;
72   protected EntityAdapterModel model;
73
74   protected String listGenerator;
75   protected String editGenerator;
76   protected String deleteConfirmationGenerator;
77   protected int nrEntitiesPerListPage;
78
79
80   public ServletModule(){
81     definition = null;
82     model = null;
83
84     try {
85       configuration = MirPropertiesConfiguration.instance();
86     }
87     catch (PropertiesConfigExc e) {
88       throw new RuntimeException("Can't get configuration: " + e.getMessage());
89     }
90
91     listGenerator = configuration.getString("ServletModule."+getOperationModuleName()+".ListTemplate");
92     editGenerator = configuration.getString("ServletModule."+getOperationModuleName()+".EditTemplate");
93     deleteConfirmationGenerator = configuration.getString("ServletModule."+getOperationModuleName()+".DeleteConfirmationTemplate");
94     nrEntitiesPerListPage =
95         configuration.getInt("ServletModule."+getOperationModuleName()+".ListSize",
96         configuration.getInt("ServletModule.Default.ListSize", 20));
97
98     fallbackLocale = new Locale(configuration.getString("Mir.Admin.FallbackLanguage", "en"), "");
99   }
100
101
102   public void logAdminUsage(HttpServletRequest aRequest, String anObject, String aDescription) {
103     MirGlobal.logAdminUsage(ServletHelper.getUser(aRequest), getOperationModuleName() + ":" + anObject, aDescription);
104   }
105
106   /**
107    * Singleton instance retrievel method. MUST be overridden in subclasses.
108    *
109    * @return ServletModule the single instance of the servletmodule class
110    */
111   public static ServletModule getInstance() {
112     return null;
113   }
114
115   /**
116    * Get the module name
117    *
118    * @return
119    */
120   protected String getOperationModuleName() {
121     return getClass().getName().substring((new String("mircoders.servlet.ServletModule")).length());
122   }
123
124   /**
125    * get the locale either from the session or the accept-language header ot the request
126    * this supersedes getLanguage for the new i18n
127    */
128   public Locale getLocale(HttpServletRequest aRequest) {
129     Locale loc = null;
130     HttpSession session = aRequest.getSession(false);
131     if (session != null) {
132       // session can be null in case of logout
133       loc = (Locale) session.getAttribute("locale");
134     }
135     // if there is nothing in the session get it fron the accept-language
136     if (loc == null) {
137       loc = aRequest.getLocale();
138     }
139     return loc;
140   }
141
142   /**
143    * get the locale either from the session or the accept-language header ot the request
144    * this supersedes getLanguage for the new i18n
145    */
146   public Locale getFallbackLocale(HttpServletRequest aRequest) {
147     return fallbackLocale;
148   }
149
150   /**
151    * Function to specify the default ordering for lists. May be overridden.
152    *
153    *
154    * @return
155    */
156   public String getDefaultListOrdering() {
157
158     if (mainModule!=null && mainModule.getStorageObject()!=null){
159       if (mainModule.getStorageObject().getFields().contains("webdb_create"))
160         return "webdb_create desc";
161     }
162
163     return "id asc";
164   }
165
166   /**
167    *
168    * @param aResponse
169    * @param aQuery
170    * @throws ServletModuleExc
171    * @throws ServletModuleFailure
172    */
173   public void redirect(HttpServletResponse aResponse, String aQuery) throws ServletModuleExc, ServletModuleFailure {
174     try {
175       aResponse.sendRedirect(aResponse.encodeRedirectURL(MirPropertiesConfiguration.instance().getString("RootUri") + "/servlet/Mir?"+aQuery));
176     }
177     catch (Throwable t) {
178       throw new ServletModuleFailure("ServletModule.redirect: " +t.getMessage(), t);
179     }
180   }
181
182   /**
183    * Generic list method
184    *
185    * @param aRequest
186    * @param aResponse
187    * @throws ServletModuleExc
188    * @throws ServletModuleUserExc
189    * @throws ServletModuleFailure
190    */
191
192   public void list(HttpServletRequest aRequest, HttpServletResponse aResponse) throws ServletModuleExc
193   {
194     HTTPRequestParser requestParser = new HTTPRequestParser(aRequest);
195
196     String where = requestParser.getParameter("where");
197     String order = requestParser.getParameterWithDefault("order", getDefaultListOrdering());
198     int offset = requestParser.getIntegerWithDefault("offset", 0);
199
200     returnList(aRequest, aResponse, where, order, offset);
201   }
202
203
204   public void returnList(HttpServletRequest aRequest, HttpServletResponse aResponse,
205      String aWhereClause, String anOrderByClause, int anOffset) throws ServletModuleExc {
206
207     HTTPRequestParser requestParser = new HTTPRequestParser(aRequest);
208     URLBuilder urlBuilder = new URLBuilder();
209     int count;
210
211     try {
212       Map responseData = ServletHelper.makeGenerationData(aRequest, aResponse, new Locale[] { getLocale(aRequest), getFallbackLocale(aRequest)});
213
214       List list =
215          EntityAdapterEngine.retrieveAdapterList(model, definition, aWhereClause, anOrderByClause, nrEntitiesPerListPage, anOffset);
216
217       responseData.put("nexturl", null);
218       responseData.put("prevurl", null);
219       responseData.put("module", getOperationModuleName());
220
221       count=mainModule.getSize(aWhereClause);
222
223       urlBuilder.setValue("module", getOperationModuleName());
224       urlBuilder.setValue("do", "list");
225       urlBuilder.setValue("where", aWhereClause);
226       urlBuilder.setValue("order", anOrderByClause);
227
228       urlBuilder.setValue("searchfield", requestParser.getParameter("searchfield"));
229       urlBuilder.setValue("searchtext", requestParser.getParameter("searchtext"));
230       urlBuilder.setValue("searchispublished", requestParser.getParameter("searchispublished"));
231       urlBuilder.setValue("searchstatus", requestParser.getParameter("searchstatus"));
232       urlBuilder.setValue("searchorder", requestParser.getParameter("searchorder"));
233
234       responseData.put("searchfield", requestParser.getParameter("searchfield"));
235       responseData.put("searchtext", requestParser.getParameter("searchtext"));
236       responseData.put("searchispublished", requestParser.getParameter("searchispublished"));
237       responseData.put("searchstatus", requestParser.getParameter("searchstatus"));
238       responseData.put("searchorder", requestParser.getParameter("searchorder"));
239
240       urlBuilder.setValue("offset", anOffset);
241       responseData.put("offset" , new Integer(anOffset).toString());
242       responseData.put("thisurl" , urlBuilder.getQuery());
243
244       if (count>anOffset+nrEntitiesPerListPage) {
245         urlBuilder.setValue("offset", anOffset + nrEntitiesPerListPage);
246         responseData.put("nexturl" , urlBuilder.getQuery());
247       }
248
249       if (anOffset>0) {
250         urlBuilder.setValue("offset", Math.max(anOffset - nrEntitiesPerListPage, 0));
251         responseData.put("prevurl" , urlBuilder.getQuery());
252       }
253
254       responseData.put("entities", list);
255       responseData.put("from" , Integer.toString(anOffset+1));
256       responseData.put("count", Integer.toString(count));
257       responseData.put("to", Integer.toString(Math.min(anOffset+nrEntitiesPerListPage, count)));
258
259       ServletHelper.generateResponse(aResponse.getWriter(), responseData, listGenerator);
260     }
261     catch (Throwable e) {
262       throw new ServletModuleFailure(e);
263     }
264   }
265
266   public void editObject(HttpServletRequest aRequest, HttpServletResponse aResponse, String anId) throws ServletModuleExc {
267     try {
268       editObject(aRequest, aResponse, model.makeEntityAdapter(definition, mainModule.getById(anId)), false, anId);
269     }
270     catch (Throwable t) {
271       throw new ServletModuleFailure(t);
272     }
273   }
274
275   public void editObject(HttpServletRequest aRequest, HttpServletResponse aResponse, Object anObject, boolean anIsNew, String anId) throws ServletModuleExc {
276     HTTPRequestParser requestParser = new HTTPRequestParser(aRequest);
277     URLBuilder urlBuilder = new URLBuilder();
278     EntityAdapterModel model;
279
280     try {
281       Map responseData = ServletHelper.makeGenerationData(aRequest, aResponse, new Locale[] { getLocale(aRequest), getFallbackLocale(aRequest)});
282
283       responseData.put("module", getOperationModuleName());
284       responseData.put("entity", anObject);
285       responseData.put("new", new Boolean(anIsNew));
286
287
288       urlBuilder.setValue("module", getOperationModuleName());
289       urlBuilder.setValue("returnurl", requestParser.getParameter("returnurl"));
290       if (anIsNew)
291         urlBuilder.setValue("do", "add");
292       else {
293         urlBuilder.setValue("id", anId);
294         urlBuilder.setValue("do", "edit");
295       }
296       responseData.put("returnurl", requestParser.getParameter("returnurl"));
297       responseData.put("thisurl", urlBuilder.getQuery());
298
299       ServletHelper.generateResponse(aResponse.getWriter(), responseData, editGenerator);
300     }
301     catch (Throwable e) {
302       throw new ServletModuleFailure(e);
303     }
304   }
305
306
307   /**
308    * Generic add method
309    *
310    * @param aRequest
311    * @param aResponse
312    * @throws ServletModuleExc
313    * @throws ServletModuleUserExc
314    * @throws ServletModuleFailure
315    */
316   public void add(HttpServletRequest aRequest, HttpServletResponse aResponse)
317       throws ServletModuleExc, ServletModuleUserExc, ServletModuleFailure  {
318
319     Map object = new HashMap();
320
321     Iterator i = mainModule.getStorageObject().getFields().iterator();
322
323     while (i.hasNext())
324       object.put(i.next(), "");
325
326     initializeNewObject(object, aRequest, aResponse);
327
328     editObject(aRequest, aResponse, object, true, null);
329   }
330
331   protected void initializeNewObject(Map aNewObject, HttpServletRequest aRequest, HttpServletResponse aResponse) {
332   }
333
334   /**
335    * Method called when the user edits an object.
336    *
337    * @param aRequest
338    * @param aResponse
339    * @throws ServletModuleExc
340    * @throws ServletModuleUserExc
341    * @throws ServletModuleFailure
342    */
343   public void edit(HttpServletRequest aRequest, HttpServletResponse aResponse) throws ServletModuleExc, ServletModuleUserExc, ServletModuleFailure  {
344     edit(aRequest, aResponse, aRequest.getParameter("id"));
345   }
346
347   /**
348    * Generic edit method
349    *
350    * @param aRequest
351    * @param aResponse
352    * @param anIdentifier
353    * @throws ServletModuleExc
354    * @throws ServletModuleUserExc
355    * @throws ServletModuleFailure
356    */
357   public void edit(HttpServletRequest aRequest, HttpServletResponse aResponse, String anIdentifier)
358       throws ServletModuleExc, ServletModuleUserExc, ServletModuleFailure  {
359     try {
360       editObject(aRequest, aResponse, model.makeEntityAdapter(definition, mainModule.getById(anIdentifier)), false, anIdentifier);
361     }
362     catch (Throwable e) {
363       throw new ServletModuleFailure(e);
364     }
365   }
366
367   /**
368    * Generic update method
369    *
370    * @param aRequest
371    * @param aResponse
372    * @throws ServletModuleExc
373    * @throws ServletModuleUserExc
374    * @throws ServletModuleFailure
375    */
376   public void update(HttpServletRequest aRequest, HttpServletResponse aResponse)
377       throws ServletModuleExc, ServletModuleUserExc, ServletModuleFailure  {
378     try {
379       HTTPRequestParser requestParser = new HTTPRequestParser(aRequest);
380
381       String id = aRequest.getParameter("id");
382       Map withValues = getIntersectingValues(aRequest, mainModule.getStorageObject());
383       mainModule.set(withValues);
384
385       logAdminUsage(aRequest, id, "object modified");
386
387       String returnUrl = requestParser.getParameter("returnurl");
388
389       if (returnUrl!=null) {
390         redirect(aResponse, returnUrl);
391       }
392       else {
393         edit(aRequest, aResponse, id);
394       }
395     }
396     catch (Throwable e) {
397       throw new ServletModuleFailure(e);
398     }
399   }
400
401   /**
402    * Generic insert method
403    *
404    * @param aRequest
405    * @param aResponse
406    * @throws ServletModuleExc
407    * @throws ServletModuleUserExc
408    * @throws ServletModuleFailure
409    */
410   public void insert(HttpServletRequest aRequest, HttpServletResponse aResponse)
411       throws ServletModuleExc, ServletModuleUserExc, ServletModuleFailure  {
412     try {
413       HTTPRequestParser requestParser = new HTTPRequestParser(aRequest);
414
415       Map object = getIntersectingValues(aRequest, mainModule.getStorageObject());
416
417       String id = processInstertedObject(object, aRequest, aResponse);
418
419       logAdminUsage(aRequest, id, "object inserted");
420
421       String returnUrl = requestParser.getParameter("returnurl");
422
423       if (returnUrl!=null) {
424         redirect(aResponse, returnUrl);
425       }
426       else {
427         edit(aRequest, aResponse, id);
428       }
429     }
430     catch (Throwable e) {
431       throw new ServletModuleFailure(e);
432     }
433   }
434
435   public String processInstertedObject(Map anObject, HttpServletRequest aRequest, HttpServletResponse aResponse) {
436     try {
437       return mainModule.add(anObject);
438     }
439     catch (Throwable t) {
440       throw new ServletModuleFailure(t);
441     }
442   };
443
444   /**
445    *
446    * @param aRequest
447    * @param aResponse
448    */
449   public void confirmdelete(HttpServletRequest aRequest, HttpServletResponse aResponse) {
450     try {
451       String idParam = aRequest.getParameter("id");
452       String confirmParam = aRequest.getParameter("confirm");
453       String cancelParam = aRequest.getParameter("cancel");
454
455       if (confirmParam != null && !confirmParam.equals("")) {
456         mainModule.deleteById(idParam);
457         logAdminUsage(aRequest, idParam, "object deleted");
458         redirect(aResponse, aRequest.getParameter("okurl"));
459       }
460       else
461         redirect(aResponse, aRequest.getParameter("cancelurl"));
462     }
463     catch (Throwable t) {
464       throw new ServletModuleFailure(t);
465     }
466   }
467
468   /**
469    *
470    * @param aRequest
471    * @param aResponse
472    * @throws ServletModuleExc
473    * @throws ServletModuleUserExc
474    * @throws ServletModuleFailure
475    */
476   public void delete(HttpServletRequest aRequest, HttpServletResponse aResponse)
477       throws ServletModuleExc, ServletModuleUserExc, ServletModuleFailure  {
478     try {
479       String idParam = aRequest.getParameter("id");
480
481       if (idParam == null)
482         throw new ServletModuleExc("Invalid call to delete: no id supplied");
483
484       Map responseData = ServletHelper.makeGenerationData(aRequest, aResponse, new Locale[] { getLocale(aRequest), getFallbackLocale(aRequest)});
485
486       responseData.put("module", getOperationModuleName());
487       responseData.put("id", idParam);
488       responseData.put("cancelurl", aRequest.getParameter("cancelurl"));
489       responseData.put("okurl", aRequest.getParameter("okurl"));
490
491       ServletHelper.generateResponse(aResponse.getWriter(), responseData, deleteConfirmationGenerator);
492     }
493     catch (Throwable e) {
494       throw new ServletModuleFailure(e);
495     }
496   }
497
498   /**
499    *  Wenn die abgeleitete Klasse diese Methode ueberschreibt und einen String mit einem
500    *  Methodennamen zurueckliefert, dann wird diese Methode bei fehlender Angabe des
501    *  doParameters ausgefuehrt.
502    *
503    * @return Name der Default-Action
504    */
505   public String defaultAction() {
506     return defaultAction;
507   }
508
509   /**
510    * Gets the fields from a httprequest and matches them with the metadata from
511    * the storage object. Returns the keys that match, with their values.
512    *
513    * @return Map with the values
514    */
515   public Map getIntersectingValues(HttpServletRequest aRequest, StorageObject theStorage)
516       throws ServletModuleExc, ServletModuleFailure {
517
518     try {
519       HTTPRequestParser parser;
520       List theFieldList;
521
522       parser = new HTTPRequestParser(aRequest);
523
524       theFieldList = theStorage.getFields();
525
526       Map withValues = new HashMap();
527       String aField, aValue;
528
529       for (int i = 0; i < theFieldList.size(); i++) {
530         aField = (String) theFieldList.get(i);
531
532         aValue = parser.getParameter(aField);
533         if (aValue != null)
534           withValues.put(aField, aValue);
535       }
536       return withValues;
537     }
538     catch (Throwable e) {
539       e.printStackTrace(logger.asPrintWriter(LoggerWrapper.DEBUG_MESSAGE));
540
541       throw new ServletModuleFailure( "ServletModule.getIntersectingValues: " + e.getMessage(), e);
542     }
543   }
544 }