cleanup + misc. fixes
[mir.git] / source / mir / servlet / AdminServletModule.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 mir.entity.adapter.EntityAdapterEngine;
33 import mir.entity.adapter.EntityAdapterModel;
34 import mir.module.AbstractModule;
35 import mir.module.ModuleExc;
36 import mir.storage.Database;
37 import mir.util.HTTPRequestParser;
38 import mir.util.URLBuilder;
39 import mircoders.global.MirGlobal;
40 import mircoders.localizer.MirLocalizerExc;
41 import mircoders.servlet.ServletHelper;
42
43 import javax.servlet.http.HttpServletRequest;
44 import javax.servlet.http.HttpServletResponse;
45 import java.util.Collections;
46 import java.util.HashMap;
47 import java.util.HashSet;
48 import java.util.Iterator;
49 import java.util.List;
50 import java.util.Map;
51 import java.util.Set;
52 import java.io.IOException;
53
54 /**
55  *
56  */
57
58 public abstract class AdminServletModule extends ServletModule {
59   protected AbstractModule mainModule;
60   protected String definition;
61   private EntityAdapterModel model;
62
63   protected String listGenerator;
64   protected String editGenerator;
65   protected String deleteConfirmationGenerator;
66   protected int nrEntitiesPerListPage;
67
68   /** the list of parameters that need to be propagated in the list */
69   private Set propagatedParameters = new HashSet();
70
71   protected void addPropagatedParameter(String aParameter) {
72     propagatedParameters.add(aParameter);
73   }
74
75   protected AdminServletModule(){
76     addPropagatedParameter("searchfield");
77     addPropagatedParameter("searchtext");
78     addPropagatedParameter("searchispublished");
79     addPropagatedParameter("searchstatus");
80     addPropagatedParameter("searchorder");
81
82     definition = null;
83     try {
84       model = MirGlobal.localizer().dataModel().adapterModel();
85     }
86     catch (MirLocalizerExc e) {
87       getLogger().error("Can't create model: " + e.toString());
88
89       throw new ServletModuleFailure("Can't retrieve model", e);
90     }
91
92     listGenerator = getConfiguration().getString("ServletModule." + getName() + ".ListTemplate");
93     editGenerator = getConfiguration().getString("ServletModule." + getName() + ".EditTemplate");
94     deleteConfirmationGenerator = getConfiguration().getString("ServletModule." + getName() + ".DeleteConfirmationTemplate");
95     nrEntitiesPerListPage =
96         getConfiguration().getInt("ServletModule."+getName()+".ListSize",
97         getConfiguration().getInt("ServletModule.Default.ListSize", 20));
98
99   }
100
101   protected EntityAdapterModel getModel() {
102     return model;
103   }
104
105   protected void logAdminUsage(HttpServletRequest aRequest, String anObject, String aDescription) {
106     MirGlobal.logAdminUsage(ServletHelper.getUser(aRequest), getName() + ":" + anObject, aDescription);
107   }
108
109   /**
110    * Function to specify the default ordering for lists. May be overridden.
111    */
112   protected String getDefaultListOrdering() {
113
114     if (mainModule!=null && mainModule.getStorageObject()!=null &&
115         mainModule.getStorageObject().hasField("webdb_create")) {
116       return "webdb_create desc";
117     }
118     else {
119       return "id asc";
120     }
121   }
122
123   /**
124    * Generic list servlet method
125    */
126
127   public void list(HttpServletRequest aRequest, HttpServletResponse aResponse) throws ServletModuleExc {
128     HTTPRequestParser requestParser = new HTTPRequestParser(aRequest);
129
130     String where = requestParser.getParameter("where");
131     String order = requestParser.getParameterWithDefault("order", getDefaultListOrdering());
132     int offset = requestParser.getIntegerWithDefault("offset", 0);
133
134     returnList(aRequest, aResponse, where, order, offset);
135   }
136
137
138   public void returnList(HttpServletRequest aRequest, HttpServletResponse aResponse,
139                          String aWhereClause, String anOrderByClause, int anOffset) throws ServletModuleExc {
140     returnList(aRequest, aResponse, aWhereClause, anOrderByClause, anOffset, Collections.EMPTY_MAP);
141   }
142
143   public void returnList(HttpServletRequest aRequest, HttpServletResponse aResponse,
144                          String aWhereClause, String anOrderByClause, int anOffset,
145                          Map anOverridingRequestParameters) throws ServletModuleExc {
146     HTTPRequestParser requestParser = new HTTPRequestParser(aRequest, anOverridingRequestParameters);
147     URLBuilder urlBuilder = new URLBuilder();
148
149     try {
150       Map responseData = ServletHelper.makeGenerationData(aRequest, aResponse, getLocales(aRequest));
151
152       List list =
153          EntityAdapterEngine.retrieveAdapterList(model, definition, aWhereClause, anOrderByClause, nrEntitiesPerListPage, anOffset);
154
155       responseData.put("nexturl", null);
156       responseData.put("prevurl", null);
157       responseData.put("module", getName());
158
159       urlBuilder.setValue("module", getName());
160       urlBuilder.setValue("do", "list");
161       urlBuilder.setValue("where", aWhereClause);
162       urlBuilder.setValue("order", anOrderByClause);
163
164
165       urlBuilder.setValue("offset", anOffset);
166       responseData.put("offset" , Integer.toString(anOffset));
167       responseData.put("thisurl" , urlBuilder.getQuery());
168
169       propagateFields(requestParser, urlBuilder, responseData);
170
171       if (list.size()>=nrEntitiesPerListPage) {
172         urlBuilder.setValue("offset", anOffset + nrEntitiesPerListPage);
173         responseData.put("nexturl" , urlBuilder.getQuery());
174       }
175
176       if (anOffset>0) {
177         urlBuilder.setValue("offset", Math.max(anOffset - nrEntitiesPerListPage, 0));
178         responseData.put("prevurl" , urlBuilder.getQuery());
179       }
180
181       responseData.put("entities", list);
182       responseData.put("from" , Integer.toString(anOffset+1));
183       responseData.put("count", "?");
184       responseData.put("to", Integer.toString(anOffset+list.size()-1));
185
186       ServletHelper.generateResponse(aResponse.getWriter(), responseData, listGenerator);
187     }
188     catch (Throwable e) {
189       throw new ServletModuleFailure(e);
190     }
191   }
192
193   public void editObject(HttpServletRequest aRequest, HttpServletResponse aResponse, String anId) throws ServletModuleExc {
194     try {
195       editObject(aRequest, aResponse, model.makeEntityAdapter(definition, mainModule.getById(anId)), false, anId);
196     }
197     catch (Throwable t) {
198       throw new ServletModuleFailure(t);
199     }
200   }
201
202   public void editObject(HttpServletRequest aRequest, HttpServletResponse aResponse, Object anObject, boolean anIsNew, String anId) throws ServletModuleExc {
203     HTTPRequestParser requestParser = new HTTPRequestParser(aRequest);
204     URLBuilder urlBuilder = new URLBuilder();
205
206     try {
207       Map responseData = ServletHelper.makeGenerationData(aRequest, aResponse, getLocales(aRequest));
208
209       responseData.put("module", getName());
210       responseData.put("entity", anObject);
211       responseData.put("new", Boolean.valueOf(anIsNew));
212
213
214       urlBuilder.setValue("module", getName());
215       urlBuilder.setValue("returnurl", requestParser.getParameter("returnurl"));
216       if (anIsNew) {
217         urlBuilder.setValue("do", "add");
218       }
219       else {
220         urlBuilder.setValue("id", anId);
221         urlBuilder.setValue("do", "edit");
222       }
223       responseData.put("returnurl", requestParser.getParameter("returnurl"));
224       responseData.put("thisurl", urlBuilder.getQuery());
225
226       ServletHelper.generateResponse(aResponse.getWriter(), responseData, editGenerator);
227     }
228     catch (Throwable e) {
229       throw new ServletModuleFailure(e);
230     }
231   }
232
233   /**
234    * Generic add servlet method
235    */
236   public void add(HttpServletRequest aRequest, HttpServletResponse aResponse)
237       throws ServletModuleExc, ServletModuleUserExc, ServletModuleFailure  {
238
239     Map object = new HashMap();
240
241     Iterator i = mainModule.getStorageObject().getFieldNames().iterator();
242
243     while (i.hasNext()) {
244       object.put(i.next(), "");
245     }
246
247     initializeNewObject(object, aRequest, aResponse);
248
249     editObject(aRequest, aResponse, object, true, null);
250   }
251
252   protected void initializeNewObject(Map aNewObject, HttpServletRequest aRequest, HttpServletResponse aResponse) {
253   }
254
255   /**
256    * Generic edit servlet method
257    */
258   public void edit(HttpServletRequest aRequest, HttpServletResponse aResponse) throws ServletModuleExc, ServletModuleUserExc, ServletModuleFailure  {
259     edit(aRequest, aResponse, aRequest.getParameter("id"));
260   }
261
262   /**
263    */
264   public void edit(HttpServletRequest aRequest, HttpServletResponse aResponse, String anIdentifier)
265       throws ServletModuleExc, ServletModuleUserExc, ServletModuleFailure  {
266     try {
267       editObject(aRequest, aResponse, model.makeEntityAdapter(definition, mainModule.getById(anIdentifier)), false, anIdentifier);
268     }
269     catch (Throwable e) {
270       throw new ServletModuleFailure(e);
271     }
272   }
273
274   /**
275    * Generic update servlet method
276    */
277   public void update(HttpServletRequest aRequest, HttpServletResponse aResponse)
278       throws ServletModuleExc, ServletModuleUserExc, ServletModuleFailure  {
279     try {
280       HTTPRequestParser requestParser = new HTTPRequestParser(aRequest);
281
282       String id = aRequest.getParameter("id");
283       Map withValues = getIntersectingValues(aRequest, mainModule.getStorageObject());
284       mainModule.set(withValues);
285
286       logAdminUsage(aRequest, id, "object modified");
287
288       String returnUrl = requestParser.getParameter("returnurl");
289
290       if (returnUrl!=null) {
291         ServletHelper.redirect(aResponse, returnUrl);
292       }
293       else {
294         edit(aRequest, aResponse, id);
295       }
296     }
297     catch (Throwable e) {
298       throw new ServletModuleFailure(e);
299     }
300   }
301
302   /**
303    * Generic insert servlet method
304    */
305   public void insert(HttpServletRequest aRequest, HttpServletResponse aResponse)
306       throws ServletModuleExc, ServletModuleUserExc, ServletModuleFailure  {
307     try {
308       HTTPRequestParser requestParser = new HTTPRequestParser(aRequest);
309
310       Map object = getIntersectingValues(aRequest, mainModule.getStorageObject());
311
312       String id = processInstertedObject(object, aRequest, aResponse);
313
314       logAdminUsage(aRequest, id, "object inserted");
315
316       String returnUrl = requestParser.getParameter("returnurl");
317
318       if (returnUrl!=null) {
319         ServletHelper.redirect(aResponse, returnUrl);
320       }
321       else {
322         edit(aRequest, aResponse, id);
323       }
324     }
325     catch (Throwable e) {
326       throw new ServletModuleFailure(e);
327     }
328   }
329
330   /**
331    *
332    */
333   public String processInstertedObject(Map anObject, HttpServletRequest aRequest, HttpServletResponse aResponse) {
334     try {
335       return mainModule.add(anObject);
336     }
337     catch (ModuleExc t) {
338       throw new ServletModuleFailure(t);
339     }
340   }
341
342   /**
343    * Generic delete confirmation servlet method
344    */
345   public void confirmdelete(HttpServletRequest aRequest, HttpServletResponse aResponse) {
346     try {
347       String idParam = aRequest.getParameter("id");
348       String confirmParam = aRequest.getParameter("confirm");
349
350       if (confirmParam != null && !"".equals(confirmParam)) {
351         mainModule.deleteById(idParam);
352         logAdminUsage(aRequest, idParam, "object deleted");
353         ServletHelper.redirect(aResponse, aRequest.getParameter("okurl"));
354       }
355       else {
356         ServletHelper.redirect(aResponse, aRequest.getParameter("cancelurl"));
357       }
358     }
359     catch (Throwable t) {
360       throw new ServletModuleFailure(t);
361     }
362   }
363
364   /**
365    * Generic delete servlet method
366    */
367   public void delete(HttpServletRequest aRequest, HttpServletResponse aResponse)
368       throws ServletModuleExc, ServletModuleUserExc, ServletModuleFailure  {
369     String idParam = aRequest.getParameter("id");
370
371     if (idParam == null) {
372       throw new ServletModuleExc("Invalid call to delete: no id supplied");
373     }
374
375     Map responseData = ServletHelper.makeGenerationData(aRequest, aResponse, getLocales(aRequest));
376
377     responseData.put("module", getName());
378     responseData.put("id", idParam);
379     responseData.put("cancelurl", aRequest.getParameter("cancelurl"));
380     responseData.put("okurl", aRequest.getParameter("okurl"));
381
382     try {
383       ServletHelper.generateResponse(aResponse.getWriter(), responseData, deleteConfirmationGenerator);
384     }
385     catch (IOException e) {
386       throw new ServletModuleFailure(e);
387     }
388   }
389
390   /**
391    * Gets the fields from a httprequest and matches them with the metadata from
392    * the database object. Returns the keys that match, with their values.
393    *
394    * @return Map with the values
395    */
396   public Map getIntersectingValues(HttpServletRequest aRequest, Database aDatabase)
397       throws ServletModuleExc, ServletModuleFailure {
398
399     HTTPRequestParser parser = new HTTPRequestParser(aRequest);
400
401     List fields = aDatabase.getFieldNames();
402
403     Map result = new HashMap();
404     for (int i = 0; i < fields.size(); i++) {
405       String aField = (String) fields.get(i);
406
407       String aValue = parser.getParameter(aField);
408       if (aValue != null) {
409         result.put(aField, aValue);
410       }
411     }
412
413     return result;
414   }
415
416   private void propagateFields(HTTPRequestParser aRequest, URLBuilder aUrlBuilder, Map aResponseData) {
417     Iterator i = propagatedParameters.iterator();
418     while (i.hasNext()) {
419       String parameter = (String) i.next();
420       String value = aRequest.getParameter(parameter);
421       aUrlBuilder.setValue(parameter, value);
422       aResponseData.put(parameter, value);
423     }
424   }
425 }