1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
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.servlets.base.AbstractServletBase;
30
31 import org.dbforms.config.DbFormsConfig;
32 import org.dbforms.config.DbFormsConfigRegistry;
33 import org.dbforms.config.MultipleValidationException;
34 import org.dbforms.config.Table;
35
36 import org.dbforms.event.AbstractDatabaseEvent;
37 import org.dbforms.event.EventEngine;
38 import org.dbforms.event.AbstractWebEvent;
39
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;
47
48 import java.sql.Connection;
49 import java.sql.SQLException;
50
51 import java.util.Enumeration;
52 import java.util.Hashtable;
53 import java.util.Vector;
54
55 import javax.servlet.ServletException;
56 import javax.servlet.http.HttpServletRequest;
57 import javax.servlet.http.HttpServletResponse;
58 import javax.servlet.http.HttpSession;
59
60
61
62 /***
63 * This servlets is the Controller component in the Model-View-Controller -
64 * architecture used by the dbforms-framework. Every request goes through this
65 * component and its event dispatching facilities.
66 *
67 * @author Joe Peer
68 */
69 public class Controller extends AbstractServletBase {
70
71 /*** logging category for this class */
72 private static Log logCat = LogFactory.getLog(Controller.class.getName());
73
74
75 /***
76 * Initialize this servlet.
77 *
78 * @exception ServletException if the initialization fails
79 */
80 public void init() throws ServletException {
81 super.init();
82 }
83
84
85 /***
86 * Gets the connection object. Holds a list of all used connections. So they
87 * stay open between calls an can be reused
88 *
89 * @param request the request object
90 * @param tableId the table identifier
91 * @param connectionsTable the connections hash table
92 *
93 * @return The connection object
94 */
95 private Connection getConnection(DbFormsConfig config,
96 HttpServletRequest request,
97 int tableId,
98 Hashtable connectionsTable)
99 throws SQLException {
100 String connectionName = null;
101 Connection con = null;
102
103
104 if (tableId != -1) {
105 connectionName = ParseUtil.getParameter(request, "invname_" + tableId);
106 }
107
108 connectionName = Util.isNull(connectionName) ? "default"
109 : connectionName;
110
111 if ((con = (Connection) connectionsTable.get(connectionName)) == null) {
112 con = config.getConnection(connectionName);
113 connectionsTable.put(connectionName, con);
114 }
115
116 return con;
117 }
118
119
120 /***
121 * In our development, we sometimes set the connection object to autoCommit
122 * = false in the interceptor (Pre... methods). This allows us to have
123 * dbForms do part of the required transaction (other parts are done via
124 * jdbc calls). If the database throws an exception, then we need to make
125 * sure that the connection is reinitialized (rollbacked) before it is sent
126 * back into the connection pool. Grunikiewicz.philip&at;hydro.qc.ca
127 * 2001-10-29
128 *
129 * @param con the connection object
130 */
131 private void cleanUpConnectionAfterException(Connection con) {
132 try {
133
134 if ((con != null) && (!con.getAutoCommit())) {
135 con.rollback();
136 con.setAutoCommit(true);
137 }
138 } catch (java.sql.SQLException e) {
139 SqlUtil.logSqlException(e);
140 }
141 }
142
143
144 /***
145 * Close all the connections stored into the the connections HashTable.
146 *
147 * @param connectionsTable the connections HashTable
148 */
149 private void closeConnections(Hashtable connectionsTable) {
150 Enumeration cons = connectionsTable.keys();
151
152 while (cons.hasMoreElements()) {
153 String dbConnectionName = (String) cons.nextElement();
154 Connection con = (Connection) connectionsTable.get(dbConnectionName);
155
156 try {
157
158 if ((con != null) && (!con.getAutoCommit())) {
159 con.commit();
160 con.setAutoCommit(true);
161 }
162 } catch (java.sql.SQLException e) {
163 SqlUtil.logSqlException(e);
164 }
165
166 SqlUtil.closeConnection(con);
167 }
168 }
169
170
171 /***
172 * Process the incoming requests.
173 *
174 * @param request the request object
175 * @param response the response object
176 *
177 * @throws IOException
178 * @throws ServletException
179 */
180 protected void process(HttpServletRequest request,
181 HttpServletResponse response)
182 throws IOException, ServletException {
183
184 HttpSession session = request.getSession(true);
185 logCat.debug("session timeout: " + session.getMaxInactiveInterval());
186
187
188
189
190 DbFormsConfig config = null;
191
192 try {
193 config = DbFormsConfigRegistry.instance()
194 .lookup();
195 } catch (Exception e) {
196 logCat.error(e);
197 throw new ServletException(e);
198 }
199
200
201 Hashtable connections = new Hashtable();
202 Connection con = null;
203 AbstractWebEvent e = null;
204 Vector errors = new Vector();
205
206 try {
207 request.setAttribute("errors", errors);
208
209 EventEngine engine = new EventEngine(request, config);
210 e = engine.generatePrimaryEvent();
211
212
213 if (e != null) {
214 request.setAttribute("webEvent", e);
215 }
216
217 try {
218 con = getConnection(config, request,
219 ((e == null) || (e.getTable() == null)) ? (-1)
220 : e.getTable().getId(),
221 connections);
222
223
224 if (e instanceof AbstractDatabaseEvent) {
225 try {
226
227
228 String formValidatorName = request.getParameter(ValidatorConstants.FORM_VALIDATOR_NAME
229 + "_"
230 + e.getTable().getId());
231
232 if (formValidatorName != null) {
233 ((AbstractDatabaseEvent) e).doValidation(formValidatorName,
234 getServletContext());
235 }
236
237 ((AbstractDatabaseEvent) e).processEvent(con);
238 } catch (SQLException sqle) {
239 logCat.error("::process - SQLException:", sqle);
240 errors.addElement(sqle);
241 cleanUpConnectionAfterException(con);
242 } catch (MultipleValidationException mve) {
243 processMultipleValidationException(con, errors, mve);
244 }
245 }
246
247
248
249
250
251
252
253
254
255
256
257 if (engine.getInvolvedTables() != null) {
258 processInvolvedTables(config, request, connections, e, errors,
259 engine);
260 }
261 } catch (SQLException exc) {
262 throw new ServletException(exc);
263 }
264 } finally {
265
266 closeConnections(connections);
267
268 if (e != null) {
269
270 String followUp = null;
271
272 if (errors.size() != 0) {
273 followUp = e.getFollowUpOnError();
274 }
275
276 if (Util.isNull(followUp)) {
277 followUp = e.getFollowUp();
278 }
279
280 logCat.info("*** e = " + e + "*** e.getFollowUp() = "
281 + e.getFollowUp());
282
283 if (!Util.isNull(followUp)) {
284 request.getRequestDispatcher(followUp)
285 .forward(request, response);
286 }
287 }
288 }
289 }
290
291
292 /***
293 * PRIVATE METHODS here
294 *
295 * @param request DOCUMENT ME!
296 * @param connections DOCUMENT ME!
297 * @param e DOCUMENT ME!
298 * @param errors DOCUMENT ME!
299 * @param engine DOCUMENT ME!
300 */
301 /***
302 * Process tables related to the main event table. <br>
303 * For every table related to the parent one, generate secundary (update)
304 * events for that table and execute them.
305 *
306 * @param request the request object
307 * @param connections the connections hashTable
308 * @param e the main webEvent object
309 * @param errors the errors vector
310 * @param engine the eventEngine reference
311 */
312 private void processInvolvedTables(DbFormsConfig config,
313 HttpServletRequest request,
314 Hashtable connections,
315 AbstractWebEvent e,
316 Vector errors,
317 EventEngine engine)
318 throws SQLException {
319 Connection con;
320
321
322 Enumeration tableEnum = engine.getInvolvedTables()
323 .elements();
324
325 while (tableEnum.hasMoreElements()) {
326 Table t = (Table) tableEnum.nextElement();
327 Enumeration eventEnum = engine.generateSecundaryEvents(t, e);
328
329
330 while (eventEnum.hasMoreElements()) {
331 AbstractDatabaseEvent dbE = (AbstractDatabaseEvent) eventEnum.nextElement();
332
333
334
335 if (t.getId() == dbE.getTable()
336 .getId()) {
337 con = getConnection(config, request, dbE.getTable().getId(),
338 connections);
339
340
341 String formValidatorName = request.getParameter(ValidatorConstants.FORM_VALIDATOR_NAME
342 + "_"
343 + dbE.getTable().getId());
344
345 try {
346
347
348 if (formValidatorName != null) {
349 dbE.doValidation(formValidatorName, getServletContext());
350 }
351
352 dbE.processEvent(con);
353 } catch (SQLException sqle2) {
354 SqlUtil.logSqlException(sqle2,
355 "::process - exception while process secundary events");
356 errors.addElement(sqle2);
357 cleanUpConnectionAfterException(con);
358 } catch (MultipleValidationException mve) {
359 processMultipleValidationException(con, errors, mve);
360 }
361 }
362 }
363 }
364 }
365
366
367
368
369 /***
370 * Process the input MultipleValidationException object.
371 *
372 * @param con the connection object to close
373 * @param errors the errors vector to fill
374 * @param mve the MultipleValidationException to process
375 */
376 private void processMultipleValidationException(Connection con,
377 Vector errors,
378 MultipleValidationException mve) {
379 java.util.Vector v = null;
380
381 logCat.error("::processMultipleValidationException - exception", mve);
382
383 if ((v = mve.getMessages()) != null) {
384 Enumeration e = v.elements();
385
386 while (e.hasMoreElements()) {
387 errors.addElement(e.nextElement());
388 }
389 }
390
391 cleanUpConnectionAfterException(con);
392 }
393
394
395 }