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