KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > dbforms > servlets > Controller


1 /*
2  * $Header: /cvsroot/jdbforms/dbforms/src/org/dbforms/servlets/Controller.java,v 1.38 2004/10/11 08:55:01 hkollmann Exp $
3  * $Revision: 1.38 $
4  * $Date: 2004/10/11 08:55:01 $
5  *
6  * DbForms - a Rapid Application Development Framework
7  * Copyright (C) 2001 Joachim Peer <joepeer@excite.com>
8  *
9  * This library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public
11  * License as published by the Free Software Foundation; either
12  * version 2.1 of the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17  * Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with this library; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22  */

23
24 package org.dbforms.servlets;
25
26 import org.apache.commons.logging.Log;
27 import org.apache.commons.logging.LogFactory;
28
29 import org.dbforms.config.DbFormsConfig;
30 import org.dbforms.config.DbFormsConfigRegistry;
31 import org.dbforms.config.MultipleValidationException;
32 import org.dbforms.config.Table;
33
34 import org.dbforms.event.DatabaseEvent;
35 import org.dbforms.event.EventEngine;
36 import org.dbforms.event.WebEvent;
37
38 import org.dbforms.util.MessageResources;
39 import org.dbforms.util.MultipartRequest;
40 import org.dbforms.util.ParseUtil;
41 import org.dbforms.util.SqlUtil;
42 import org.dbforms.util.Util;
43
44 import org.dbforms.validation.ValidatorConstants;
45
46 import java.io.IOException JavaDoc;
47 import java.io.PrintWriter JavaDoc;
48
49 import java.sql.Connection JavaDoc;
50 import java.sql.SQLException JavaDoc;
51
52 import java.util.Enumeration JavaDoc;
53 import java.util.Hashtable JavaDoc;
54 import java.util.Locale JavaDoc;
55 import java.util.Vector JavaDoc;
56
57 import javax.servlet.ServletException JavaDoc;
58 import javax.servlet.http.HttpServlet JavaDoc;
59 import javax.servlet.http.HttpServletRequest JavaDoc;
60 import javax.servlet.http.HttpServletResponse JavaDoc;
61 import javax.servlet.http.HttpSession JavaDoc;
62
63
64
65 /**
66  * This servlets is the Controller component in the Model-View-Controller -
67  * architecture used by the dbforms-framework. Every request goes through this
68  * component and its event dispatching facilities.
69  *
70  * @author Joe Peer
71  */

72 public class Controller extends HttpServlet JavaDoc {
73    /** logging category for this class */
74    private static Log logCat = LogFactory.getLog(Controller.class.getName());
75
76    /** 100KB default upload size */
77    private int maxUploadSize = 102400;
78
79    /**
80     * Process an HTTP "GET" request.
81     *
82     * @param request The servlet request we are processing
83     * @param response The servlet response we are creating
84     *
85     * @exception IOException if an input/output error occurs
86     * @exception ServletException if a servlet exception occurs
87     */

88    public void doGet(HttpServletRequest JavaDoc request,
89                      HttpServletResponse JavaDoc response)
90               throws IOException JavaDoc, ServletException JavaDoc {
91       process(request, response);
92    }
93
94
95    /**
96     * Process an HTTP "POST" request.
97     *
98     * @param request The servlet request we are processing
99     * @param response The servlet response we are creating
100     *
101     * @exception IOException if an input/output error occurs
102     * @exception ServletException if a servlet exception occurs
103     */

104    public void doPost(HttpServletRequest JavaDoc request,
105                       HttpServletResponse JavaDoc response)
106                throws IOException JavaDoc, ServletException JavaDoc {
107       process(request, response);
108    }
109
110
111    /**
112     * Initialize this servlet.
113     *
114     * @exception ServletException if the initialization fails
115     */

116    public void init() throws ServletException JavaDoc {
117       // if existing and valid, override default maxUploadSize, which determinates how
118
// big the http/multipart uploads may get
119
String JavaDoc maxUploadSizeStr = this.getServletConfig()
120                                     .getInitParameter("maxUploadSize");
121
122       if (maxUploadSizeStr != null) {
123          try {
124             this.maxUploadSize = Integer.parseInt(maxUploadSizeStr);
125          } catch (NumberFormatException JavaDoc nfe) {
126             logCat.error("maxUploadSize not a valid number => using default.");
127          }
128       }
129    }
130
131
132    /**
133     * Gets the connection object. Holds a list of all used connections. So they
134     * stay open between calls an can be reused
135     *
136     * @param request the request object
137     * @param tableId the table identifier
138     * @param connectionsTable the connections hash table
139     *
140     * @return The connection object
141     */

142    private Connection JavaDoc getConnection(DbFormsConfig config,
143                                     HttpServletRequest JavaDoc request,
144                                     int tableId,
145                                     Hashtable JavaDoc connectionsTable)
146                              throws SQLException JavaDoc {
147       String JavaDoc connectionName = null;
148       Connection JavaDoc con = null;
149
150       // get the connection name from the request;
151
if (tableId != -1) {
152          connectionName = ParseUtil.getParameter(request, "invname_" + tableId);
153       }
154
155       connectionName = Util.isNull(connectionName) ? "default"
156                                                    : connectionName;
157
158       if ((con = (Connection JavaDoc) connectionsTable.get(connectionName)) == null) {
159          con = config.getConnection(connectionName);
160          connectionsTable.put(connectionName, con);
161       }
162
163       return con;
164    }
165
166
167    /**
168     * In our development, we sometimes set the connection object to autoCommit
169     * = false in the interceptor (Pre... methods). This allows us to have
170     * dbForms do part of the required transaction (other parts are done via
171     * jdbc calls). If the database throws an exception, then we need to make
172     * sure that the connection is reinitialized (rollbacked) before it is sent
173     * back into the connection pool. Grunikiewicz.philip&at;hydro.qc.ca
174     * 2001-10-29
175     *
176     * @param con the connection object
177     */

178    private void cleanUpConnectionAfterException(Connection JavaDoc con) {
179       try {
180          // Do only if autoCommit is disabled
181
if ((con != null) && (!con.getAutoCommit())) {
182             con.rollback();
183             con.setAutoCommit(true);
184          }
185       } catch (java.sql.SQLException JavaDoc e) {
186          SqlUtil.logSqlException(e);
187       }
188    }
189
190
191    /**
192     * Close all the connections stored into the the connections HashTable.
193     *
194     * @param connectionsTable the connections HashTable
195     */

196    private void closeConnections(Hashtable JavaDoc connectionsTable) {
197       Enumeration JavaDoc cons = connectionsTable.keys();
198
199       while (cons.hasMoreElements()) {
200          String JavaDoc dbConnectionName = (String JavaDoc) cons.nextElement();
201          Connection JavaDoc con = (Connection JavaDoc) connectionsTable.get(dbConnectionName);
202
203          try {
204             // Do only if autoCommit is disabled
205
if ((con != null) && (!con.getAutoCommit())) {
206                con.commit();
207                con.setAutoCommit(true);
208             }
209          } catch (java.sql.SQLException JavaDoc e) {
210             SqlUtil.logSqlException(e);
211          }
212
213          SqlUtil.closeConnection(con);
214       }
215    }
216
217
218    /**
219     * Process the incoming requests.
220     *
221     * @param request the request object
222     * @param response the response object
223     *
224     * @throws IOException
225     * @throws ServletException
226     */

227    private void process(HttpServletRequest JavaDoc request,
228                         HttpServletResponse JavaDoc response)
229                  throws IOException JavaDoc, ServletException JavaDoc {
230       HttpSession JavaDoc session = request.getSession(true);
231       logCat.debug("session timeout: " + session.getMaxInactiveInterval());
232
233       // take Config-Object from application context - this object should have been
234
// initalized by Config-Servlet on Webapp/server-startup!
235
DbFormsConfig config = null;
236
237       try {
238          config = DbFormsConfigRegistry.instance()
239                                        .lookup();
240       } catch (Exception JavaDoc e) {
241          logCat.error(e);
242          throw new ServletException JavaDoc(e);
243       }
244
245       // create RFC-1867 data wrapper for the case the form was sent in multipart mode
246
// this is needed because common HttpServletRequestImpl - classes do not support it
247
// the whole application has to access Request via the "ParseUtil" class
248
// this is also true for jsp files written by the user
249
// #fixme taglib needed for convenient access to ParseUtil wrapper methods
250
Hashtable JavaDoc connections = new Hashtable JavaDoc();
251       String JavaDoc contentType = request.getContentType();
252
253       // Verify if Locale have been setted in session with "LOCALE_KEY"
254
// if not, take the request.getLocale() as default and put it in session
255
// Verify if Locale have been setted in session with "LOCALE_KEY"
256
// if not, take the request.getLocale() as default and put it in session
257
processLocale(request);
258
259       if ((contentType != null) && contentType.startsWith("multipart")) {
260          try {
261             MultipartRequest multipartRequest = new MultipartRequest(request,
262                                                                      maxUploadSize);
263             request.setAttribute("multipartRequest", multipartRequest);
264          } catch (IOException JavaDoc ioe) {
265             logCat.error("::process - check if uploaded file(s) exceeded allowed size",
266                          ioe);
267             sendErrorMessage("Check if uploaded file(s) exceeded allowed size.",
268                              response);
269
270             return;
271          }
272       }
273
274       Connection JavaDoc con = null;
275       WebEvent e = null;
276       Vector JavaDoc errors = new Vector JavaDoc();
277
278       try {
279          request.setAttribute("errors", errors);
280
281          EventEngine engine = new EventEngine(request, config);
282          e = engine.generatePrimaryEvent();
283
284          // send as info to dbForms (=> Taglib)
285
if (e != null) {
286             request.setAttribute("webEvent", e);
287          }
288
289          try {
290             con = getConnection(config, request,
291                                 ((e == null) || (e.getTable() == null)) ? (-1)
292                                                                         : e.getTable().getId(),
293                                 connections);
294
295             // primary event can be any kind of event (database, navigation...)
296
if (e instanceof DatabaseEvent) {
297                try {
298                   // if hidden formValidatorName exist and it's an Update or Insert event,
299
// doValidation with Commons-Validator
300
String JavaDoc formValidatorName = request.getParameter(ValidatorConstants.FORM_VALIDATOR_NAME
301                                                                   + "_"
302                                                                   + e.getTable().getId());
303
304                   if (formValidatorName != null) {
305                      ((DatabaseEvent) e).doValidation(formValidatorName,
306                                                       getServletContext());
307                   }
308
309                   ((DatabaseEvent) e).processEvent(con);
310                } catch (SQLException JavaDoc sqle) {
311                   logCat.error("::process - SQLException:", sqle);
312                   errors.addElement(sqle);
313                   cleanUpConnectionAfterException(con);
314                } catch (MultipleValidationException mve) {
315                   processMultipleValidationException(con, errors, mve);
316                }
317             }
318
319             //else
320
//{
321
// currently, we support db events ONLY
322
// but in future there may be events with processEvent() method which do not need a jdbc con!
323
// (you may think: "what about navigation events?" - well they are created by the
324
// controller but they get executed in the referncing "DbFormTag" at the jsp -- that's why we
325
// do not any further operations on them right here...we just put them into the request)
326
//}
327
// secondary Events are always database events
328
// (in fact, they all are SQL UPDATEs)
329
if (engine.getInvolvedTables() != null) {
330                processInvolvedTables(config, request, connections, e, errors,
331                                      engine);
332             }
333          } catch (SQLException JavaDoc exc) {
334             throw new ServletException JavaDoc(exc);
335          }
336       } finally {
337          // close all the connections stored into the connections hash table;
338
closeConnections(connections);
339
340          if (e != null) {
341             // PG - if form contained errors, use followupOnError (if available!)
342
String JavaDoc followUp = null;
343
344             if (errors.size() != 0) {
345                followUp = e.getFollowUpOnError();
346             }
347
348             if (Util.isNull(followUp)) {
349                followUp = e.getFollowUp();
350             }
351
352             logCat.info("*** e = " + e + "*** e.getFollowUp() = "
353                         + e.getFollowUp());
354
355             if (!Util.isNull(followUp)) {
356                request.getRequestDispatcher(followUp)
357                       .forward(request, response);
358             }
359          }
360       }
361    }
362
363
364    /**
365     * PRIVATE METHODS here
366     *
367     * @param request DOCUMENT ME!
368     * @param connections DOCUMENT ME!
369     * @param e DOCUMENT ME!
370     * @param errors DOCUMENT ME!
371     * @param engine DOCUMENT ME!
372     */

373    /**
374     * Process tables related to the main event table. <br>
375     * For every table related to the parent one, generate secundary (update)
376     * events for that table and execute them.
377     *
378     * @param request the request object
379     * @param connections the connections hashTable
380     * @param e the main webEvent object
381     * @param errors the errors vector
382     * @param engine the eventEngine reference
383     */

384    private void processInvolvedTables(DbFormsConfig config,
385                                       HttpServletRequest JavaDoc request,
386                                       Hashtable JavaDoc connections,
387                                       WebEvent e,
388                                       Vector JavaDoc errors,
389                                       EventEngine engine)
390                                throws SQLException JavaDoc {
391       Connection JavaDoc con;
392
393       // may be null if empty form!
394
Enumeration JavaDoc tableEnum = engine.getInvolvedTables()
395                                     .elements();
396
397       while (tableEnum.hasMoreElements()) {
398          Table t = (Table) tableEnum.nextElement();
399          Enumeration JavaDoc eventEnum = engine.generateSecundaryEvents(t, e);
400
401          // scan all the secundary events for the current secundary table;
402
while (eventEnum.hasMoreElements()) {
403             DatabaseEvent dbE = (DatabaseEvent) eventEnum.nextElement();
404
405             // 2003-02-03 HKK: do not do the work twice - without this every event
406
// would be generated for each table and event
407
if (t.getId() == dbE.getTable()
408                                       .getId()) {
409                con = getConnection(config, request, dbE.getTable().getId(),
410                                    connections);
411
412                // 2003-02-03 HKK: do not do the work twice!!!
413
String JavaDoc formValidatorName = request.getParameter(ValidatorConstants.FORM_VALIDATOR_NAME
414                                                                + "_"
415                                                                + dbE.getTable().getId());
416
417                try {
418                   // if hidden formValidatorName exist and it's an Update or Insert event,
419
// doValidation with Commons-Validator
420
if (formValidatorName != null) {
421                      dbE.doValidation(formValidatorName, getServletContext());
422                   }
423
424                   dbE.processEvent(con);
425                } catch (SQLException JavaDoc sqle2) {
426                   SqlUtil.logSqlException(sqle2,
427                                           "::process - exception while process secundary events");
428                   errors.addElement(sqle2);
429                   cleanUpConnectionAfterException(con);
430                } catch (MultipleValidationException mve) {
431                   processMultipleValidationException(con, errors, mve);
432                }
433             }
434          }
435       }
436    }
437
438
439    /**
440     * Set the default locale
441     *
442     * @param request the request object
443     */

444    private void processLocale(HttpServletRequest JavaDoc request) {
445       String JavaDoc lang = ParseUtil.getParameter(request, "lang");
446       String JavaDoc country = ParseUtil.getParameter(request, "country", "");
447       Locale JavaDoc locale = null;
448
449       if (!Util.isNull(lang)) {
450          locale = new Locale JavaDoc(lang, country);
451       } else if (MessageResources.getLocale(request) == null) {
452          MessageResources.setLocale(request, request.getLocale());
453       }
454
455       if (locale != null) {
456          MessageResources.setLocale(request, locale);
457       }
458    }
459
460
461    /**
462     * Process the input MultipleValidationException object.
463     *
464     * @param con the connection object to close
465     * @param errors the errors vector to fill
466     * @param mve the MultipleValidationException to process
467     */

468    private void processMultipleValidationException(Connection JavaDoc con,
469                                                    Vector JavaDoc errors,
470                                                    MultipleValidationException mve) {
471       java.util.Vector JavaDoc v = null;
472
473       logCat.error("::processMultipleValidationException - exception", mve);
474
475       if ((v = mve.getMessages()) != null) {
476          Enumeration JavaDoc e = v.elements();
477
478          while (e.hasMoreElements()) {
479             errors.addElement(e.nextElement());
480          }
481       }
482
483       cleanUpConnectionAfterException(con);
484    }
485
486
487    /**
488     * Send error messages to the servlet's output stream
489     *
490     * @param message the message to display
491     * @param response the response object
492     */

493    private void sendErrorMessage(String JavaDoc message,
494                                  HttpServletResponse JavaDoc response) {
495       try {
496          PrintWriter JavaDoc out = response.getWriter();
497
498          response.setContentType("text/html");
499          out.println("<html><body><h1>ERROR:</h1><p>");
500          out.println(message);
501          out.println("</p></body></html>");
502       } catch (IOException JavaDoc ioe) {
503          logCat.error("::sendErrorMessage - senderror message crashed", ioe);
504       }
505    }
506 }
507
Popular Tags