001: package dinamica;
002:
003: import java.io.IOException;
004: import java.io.StringWriter;
005: import javax.servlet.*;
006: import javax.servlet.http.*;
007: import javax.sql.DataSource;
008: import java.sql.*;
009: import java.io.PrintWriter;
010: import electric.xml.*;
011: import java.util.*;
012: import java.util.regex.Pattern;
013:
014: /**
015: * Central controller to dispatch all requests
016: * recevied by a Web Application built with this framework.
017: * This class represents the Coordinator of all activities in
018: * the application, it is the base for the advanced MVC mechanism implemented
019: * by this framework. This servlet should be configured in WEB.XML to intercept
020: * requests targeting /trans/... URLs.<br>
021: * <br>
022: * The application template provided with the framework includes all
023: * the required configuration settings in WEB.XML, use that as a starting
024: * point for your own applications.
025: * <br>
026: * Please read the Howto documents and technical articles included with
027: * this framework in order to understand and master the inner working mechanisms
028: * of the framework and the role of this servlet in particular.
029: * <br>
030: * Creation date: 3/10/2003<br>
031: * Last Update: 3/10/2003<br>
032: * (c) 2003 Martin Cordova<br>
033: * This code is released under the LGPL license<br>
034: * @author Martin Cordova
035: */
036: public class Controller extends HttpServlet {
037:
038: /**
039: *
040: */
041: private static final long serialVersionUID = 1L;
042:
043: /**
044: * JNDI prefix (java:comp/env/ or "")
045: */
046: String _jndiPrefix = null;
047:
048: /**
049: * Servlet context
050: */
051: ServletContext _ctx = null;
052:
053: /**
054: * Default JDBC data source
055: */
056: DataSource _ds = null;
057:
058: /**
059: * trace log file for requests and JDBC
060: */
061: String _logFile = null;
062:
063: /**
064: * validation error action URI
065: */
066: String _validationErrorAction = null;
067:
068: /**
069: * default app-level request encoding
070: */
071: String _requestEncoding = null;
072:
073: /**
074: * default app-level file encoding
075: */
076: String _fileEncoding = null;
077:
078: /**
079: * Central point of control to intercept
080: * all transaction requests (the Controller in the MVC mechanism)
081: */
082: @SuppressWarnings("unchecked")
083: protected void service(HttpServletRequest req,
084: HttpServletResponse res) throws ServletException,
085: IOException {
086:
087: //PATCH 2005-09-14 reject all http methods except GET & POST
088: String method = req.getMethod().toUpperCase();
089: if (!method.equals("GET") && !method.equals("POST")) {
090: res.sendError(501, method + " not supported");
091: return;
092: }
093: //END PATCH
094:
095: /* MVC objects */
096: GenericTransaction t = null; //model
097: GenericOutput o = null; //view
098: Recordset inputValues = null; //request parameters to auto-validate
099:
100: /* transaction return code */
101: int returnCode = 0;
102:
103: /* for performance log */
104: long t1 = 0;
105: long t2 = 0;
106:
107: /* log flags */
108: boolean saveMvcLog = false;
109: boolean saveJdbcLog = false;
110:
111: /* activate log writers */
112: StringWriter logWriter = new StringWriter();
113: PrintWriter logPrinter = new PrintWriter(logWriter);
114:
115: Config config = null;
116:
117: try {
118:
119: /* get transaction path */
120: String path = getPath(req);
121: String configData = null;
122:
123: /* get config file */
124: try {
125: configData = StringUtil.getResource(_ctx, path
126: + "config.xml");
127: } catch (Throwable notFound) {
128: res.sendError(404);
129: return;
130: }
131:
132: configData = replaceMacros(req, configData); //replace macros like ${def:actionroot}
133:
134: /* create config object */
135: config = new Config(configData, path);
136:
137: /*
138: * set request encoding -if required- patch_20050214
139: * Action's config.xml is searched first, if no encoding
140: * directive is found at this level, then use app-wide
141: * encoding parameter -if defined-
142: */
143: if (config.requestEncoding != null) {
144: req.setCharacterEncoding(config.requestEncoding);
145: } else {
146: if (_requestEncoding != null)
147: req.setCharacterEncoding(_requestEncoding);
148: }
149:
150: /* set request values */
151: setRequestValues(req, config);
152:
153: /* set logs */
154: if (config.jdbcLog != null && config.jdbcLog.equals("true"))
155: saveJdbcLog = true;
156:
157: if (config.mvcLog.equals("true")) {
158: saveMvcLog = true;
159:
160: logPrinter.println("--REQUEST-START");
161: logPrinter.println("Request: " + path);
162: logPrinter.println("Summary: " + config.summary);
163: logPrinter
164: .println("Date: "
165: + new java.util.Date(System
166: .currentTimeMillis()));
167: logPrinter.println("Thread: "
168: + Thread.currentThread().getName());
169: ;
170: logPrinter.println("Session ID: "
171: + req.getSession(true).getId());
172:
173: }
174:
175: /* validate action if required */
176: if (config.transValidator != null
177: && config.transValidator.equals("true")) {
178: /* validation may require a database connection */
179: Connection con = null;
180: try {
181: /* get database connection from pool (default pool or transaction specific datasource) */
182: if (config.transDataSource != null)
183: con = Jndi.getDataSource(
184: _jndiPrefix + config.transDataSource)
185: .getConnection();
186: else
187: con = _ds.getConnection();
188:
189: /* inputs validation */
190: inputValues = validateInput(req, config, con,
191: saveJdbcLog, logPrinter);
192:
193: } catch (Throwable verror) {
194: throw verror;
195: } finally {
196: if (con != null)
197: con.close();
198: }
199: }
200:
201: //PATCH: 2006-06-29
202: //save request parameters into session?
203: if (config.validatorInSession != null
204: && config.validatorInSession.equals("true")) {
205: Iterator i = inputValues.getFields().values()
206: .iterator();
207: while (i.hasNext()) {
208: RecordsetField f = (RecordsetField) i.next();
209: if (!inputValues.isNull(f.getName()))
210: req.getSession(true).setAttribute(f.getName(),
211: inputValues.getString(f.getName()));
212: }
213: }
214:
215: t1 = System.currentTimeMillis();
216:
217: /* invoke transaction */
218: if (config.transClassName != null) {
219:
220: Connection con = null;
221:
222: try {
223:
224: /* get database connection from pool (default pool or transaction specific datasource) */
225: if (config.transDataSource != null)
226: con = Jndi.getDataSource(
227: _jndiPrefix + config.transDataSource)
228: .getConnection();
229: else
230: con = _ds.getConnection();
231:
232: /* load transaction class */
233: t = (GenericTransaction) getObject(config.transClassName);
234: t.init(_ctx, req, res);
235: t.setConfig(config);
236: t.setConnection(con);
237:
238: /* log jdbc performance? */
239: if (saveJdbcLog)
240: t.setLogWriter(logPrinter);
241:
242: /* requires transaction? */
243: if (config.transTransactions.equals("true"))
244: con.setAutoCommit(false);
245: else
246: con.setAutoCommit(true);
247:
248: /* wrapper API implemented? */
249: IServiceWrapper w = null;
250: if (t instanceof dinamica.IServiceWrapper) {
251: w = (IServiceWrapper) t;
252: w.beforeService(inputValues);
253: }
254:
255: /* execute service */
256: returnCode = t.service(inputValues);
257:
258: /* wrapper API? */
259: if (w != null)
260: w.afterService(inputValues);
261:
262: /* commit if transaction mode is ON */
263: if (!con.getAutoCommit())
264: con.commit();
265:
266: } catch (Throwable e) {
267: if (con != null && !con.getAutoCommit())
268: con.rollback();
269: throw e;
270: } finally {
271: if (con != null)
272: con.close();
273: }
274:
275: }
276:
277: t2 = System.currentTimeMillis();
278: if (saveMvcLog)
279: logPrinter.println("Transaction performance (ms): "
280: + (t2 - t1));
281:
282: /* check transaction exit code */
283: String forwardUri = config.getUriForExitCode(returnCode);
284: if (forwardUri != null) {
285: forward(forwardUri, req, res);
286: return;
287: }
288:
289: t1 = System.currentTimeMillis();
290:
291: /* invoke output */
292: if (config.outClassName != null) {
293: /* set http headers? */
294: if (config.headers.equals("true")) {
295: /* PATCH 2005-02-23 - encoding support */
296: String contentType = config.contentType;
297: if (contentType != null) {
298: if (config.contentType.startsWith("text")) {
299: if (contentType.indexOf("charset") < 0
300: && _fileEncoding != null)
301: contentType = contentType
302: + "; charset=" + _fileEncoding;
303: }
304: res.setContentType(contentType);
305: }
306: if (config.expiration != null) {
307: if (Integer.parseInt(config.expiration) == 0) {
308: res.setHeader("Cache-Control", "no-cache");
309: res.setHeader("Pragma", "no-cache");
310: } else
311: res.setHeader("Cache-Control", "max-age="
312: + config.expiration);
313: }
314: }
315:
316: /* load output class */
317: o = (GenericOutput) getObject(config.outClassName);
318: o.init(_ctx, req, res);
319: o.setConfig(config);
320:
321: /* is text based output? */
322: if (config.contentType != null
323: && config.contentType.startsWith("text")) {
324: /* load template */
325: String template = o.getResource(config.outTemplate);
326: TemplateEngine te = new TemplateEngine(_ctx, req,
327: template);
328:
329: /* use custom locale for this session? */
330: HttpSession s = req.getSession(true);
331: java.util.Locale l = (java.util.Locale) s
332: .getAttribute("dinamica.user.locale");
333: te.setLocale(l);
334:
335: /* PATCH 2005-02-23 - encoding support */
336: if (config.templateEncoding != null)
337: te.setEncoding(config.templateEncoding);
338: else
339: te.setEncoding(_fileEncoding);
340:
341: /* generate page using business object "t" */
342: o.print(te, t);
343:
344: /* process any includes and send page to response stream */
345: te.print(res);
346:
347: } else {
348: /* print binary output */
349: o.print(t);
350: }
351:
352: }
353:
354: t2 = System.currentTimeMillis();
355: if (saveMvcLog) {
356: logPrinter.println("Output performance (ms): "
357: + (t2 - t1));
358: }
359:
360: }
361:
362: /* request/form validation error */
363: catch (RequestValidationException vex) {
364: RequestDispatcher rd = _ctx
365: .getRequestDispatcher(_validationErrorAction);
366: req.setAttribute("dinamica.errors", vex.getErrors());
367: rd.forward(req, res);
368: }
369:
370: /* general application error */
371: catch (Throwable e) {
372:
373: //get stack trace
374: StringWriter s = new StringWriter();
375: PrintWriter err = new PrintWriter(s);
376: e.printStackTrace(err);
377:
378: /* set request attributes for the
379: generic error handler */
380: req.setAttribute("dinamica.error.description", e
381: .getMessage());
382: req.setAttribute("dinamica.error.url", req.getRequestURL()
383: .toString());
384: req.setAttribute("dinamica.error.stacktrace", s.toString());
385: req
386: .setAttribute("dinamica.error.user", req
387: .getRemoteUser());
388: req.setAttribute("dinamica.error.remote_addr", req
389: .getRemoteAddr());
390: req.setAttribute("dinamica.error.exception", e);
391:
392: //patch 2006-01-03 - use custom error handler if defined
393: if (config != null && config.onErrorAction != null) {
394: //remember to log exception info for this case
395: log(e.getMessage(), e);
396: _ctx.getRequestDispatcher(config.onErrorAction)
397: .forward(req, res);
398: } else {
399: //let the container's error handler do its job
400: throw new ServletException(e);
401: }
402: }
403:
404: finally {
405: /* save logs? */
406: if (saveJdbcLog || saveMvcLog)
407: saveLog(logWriter.toString());
408: }
409:
410: }
411:
412: /**
413: * Extract path begining with /trans/...
414: * @param uri
415: * @return req Servlet request object
416: */
417: String getPath(HttpServletRequest req) throws Throwable {
418:
419: String uri = null;
420:
421: /* is this an include? */
422: uri = (String) req
423: .getAttribute("javax.servlet.include.request_uri");
424:
425: if (uri == null)
426: uri = req.getRequestURI();
427:
428: /* get default mapping */
429: String find = getInitParameter("base-dir");
430:
431: /* find start of path */
432: int pos = uri.indexOf(find);
433: if (pos >= 0) {
434:
435: //PATCH 2005-08-30 required for ${def:actionroot} marker
436: String path = uri.substring(pos);
437: req.setAttribute("dinamica.action.path", path);
438: //END PATCH
439:
440: return "/WEB-INF" + path + "/";
441: } else {
442: throw new Throwable(
443: "Invalid base-dir parameter for this request ("
444: + uri
445: + ") - can't extract Transaction path from URI using this prefix: "
446: + find);
447: }
448:
449: }
450:
451: /**
452: * Controller initialization tasks.<br>
453: * Reads parameters jndi-prefix and def-datasource
454: * and creates a default datasource object with
455: * modular scope to be used by all threads from this servlet
456: */
457: public void init() throws ServletException {
458:
459: try {
460:
461: /* init tasks */
462: _ctx = getServletContext();
463:
464: /* get prefix for jndi lookups */
465: _jndiPrefix = _ctx.getInitParameter("jndi-prefix");
466: if (_jndiPrefix == null)
467: _jndiPrefix = "";
468:
469: /* get default datasource */
470: String dsName = _jndiPrefix
471: + _ctx.getInitParameter("def-datasource");
472: if (dsName == null || dsName.trim().equals(""))
473: throw new ServletException(
474: "Configuration problem detected in WEB.XML: def-datasource context parameter cannot be undefined!");
475:
476: _ds = Jndi.getDataSource(dsName);
477:
478: /* get logfile name */
479: _logFile = _ctx.getInitParameter("log-file");
480: if (_logFile == null || _logFile.trim().equals(""))
481: throw new ServletException(
482: "Configuration problem detected in WEB.XML: log-file context parameter cannot be undefined!");
483:
484: /* get custom validation action */
485: _validationErrorAction = _ctx
486: .getInitParameter("on-validation-error");
487: if (_validationErrorAction == null
488: || _validationErrorAction.trim().equals(""))
489: throw new ServletException(
490: "Configuration problem detected in WEB.XML: on-validation-error context parameter cannot be undefined!");
491:
492: /* get custom request encoding */
493: _requestEncoding = _ctx
494: .getInitParameter("request-encoding");
495: if (_requestEncoding != null
496: && _requestEncoding.trim().equals(""))
497: _requestEncoding = null;
498:
499: /* get custom template/response encoding */
500: _fileEncoding = _ctx.getInitParameter("file-encoding");
501: if (_fileEncoding != null
502: && _fileEncoding.trim().equals(""))
503: _fileEncoding = null;
504:
505: super .init();
506:
507: } catch (Throwable e) {
508: log("Controller servlet failed on init!");
509: throw new ServletException(e);
510: }
511:
512: }
513:
514: /**
515: * Save message to filesystem, using the context parameter
516: * log-file defined in web.xml and stored in modular variable _logFile
517: * @param message String to append to file
518: */
519: void saveLog(String message) {
520: StringUtil.saveMessage(_logFile, message);
521: }
522:
523: /**
524: * Auto-Validate request parameters for single value
525: * parameters - array parameters must be processed
526: * by the business logic using the Servlet Request object
527: * @param req Servlet Request
528: * @param config Configuration for the current Action
529: * @throws Throwable If any validation rule is violated
530: */
531: Recordset validateInput(HttpServletRequest req, Config config,
532: Connection conn, boolean jdbcLog, PrintWriter jdbcLogPrinter)
533: throws Throwable {
534:
535: /* to store validation error messages*/
536: RequestValidationException errors = new RequestValidationException();
537:
538: /* load default date format used to convert date strings to Date objects */
539: String dateFormat = _ctx.getInitParameter("def-input-date");
540:
541: /* recordset to hold request parameters and optional parameters defined in validator.xml */
542: Recordset inputs = new Recordset();
543:
544: /* load validator xml file */
545: String file = config.path + "validator.xml";
546: Document xml = new Document(StringUtil.getResource(_ctx, file));
547: Element root = xml.getRoot();
548:
549: /* read session id -2007-05-23- inputParams recordset can be saved in session */
550: String sessionID = root.getAttribute("id");
551: if (sessionID == null)
552: sessionID = "";
553:
554: /* read parameters pass 1 - create recordset structure */
555: Elements elements = root.getElements("parameter");
556: Element param;
557:
558: while (elements.hasMoreElements()) {
559:
560: /* validation attributes */
561: String type = null;
562: String id = null;
563: String label = null;
564: int sqlType = 0;
565: String required = null;
566:
567: param = elements.next();
568:
569: /* read attributes */
570: id = param.getAttributeValue("id");
571: if (id == null)
572: throw new Exception(
573: "Invalid Validator. Attribute [id] not found: "
574: + file);
575:
576: type = param.getAttributeValue("type");
577: if (type == null)
578: throw new Exception(
579: "Invalid Validator. Attribute [type] not found: "
580: + file);
581:
582: required = param.getAttributeValue("required");
583: if (required == null)
584: throw new Exception(
585: "Invalid Validator. Attribute [required] not found: "
586: + file);
587:
588: label = param.getAttributeValue("label");
589: if (label == null)
590: throw new Exception(
591: "Invalid Validator. Attribute [label] not found: "
592: + file);
593:
594: /* validate type attribute */
595: if (type.equals("varchar"))
596: sqlType = Types.VARCHAR;
597: else if (type.equals("integer"))
598: sqlType = Types.INTEGER;
599: else if (type.equals("double"))
600: sqlType = Types.DOUBLE;
601: else if (type.equals("date"))
602: sqlType = Types.DATE;
603: else
604: throw new Exception("Invalid validator data type ("
605: + type + ") in file: " + file);
606:
607: /* OK - append the field to the recordset */
608: inputs.append(id, sqlType);
609:
610: }
611:
612: /* add one record to hold the parameters values */
613: inputs.addNew();
614:
615: /* read parameters pass 2 - validate parameters */
616: elements = root.getElements("parameter");
617:
618: while (elements.hasMoreElements()) {
619:
620: /* validation attributes */
621: String type = null;
622: String value = null;
623: String id = null;
624: String label = null;
625: int sqlType = 0;
626: String required = "";
627: int maxLen = 0;
628: String maxLenAttr = "";
629: int minValue = 0;
630: int maxValue = 0;
631: String minValueAttr = "";
632: String maxValueAttr = "";
633: String regexp = null;
634: String regexpError = null;
635:
636: param = elements.next();
637:
638: /* read attributes */
639: id = param.getAttributeValue("id");
640: type = param.getAttributeValue("type");
641: required = param.getAttributeValue("required");
642: label = param.getAttributeValue("label");
643: maxLenAttr = param.getAttributeValue("maxlen");
644: minValueAttr = param.getAttributeValue("min");
645: maxValueAttr = param.getAttributeValue("max");
646: regexp = param.getAttributeValue("regexp");
647: regexpError = param.getAttributeValue("regexp-error-label");
648:
649: //patch 2007-07-16 - label in bold
650: label = "<b>" + label + "</b>";
651:
652: if (maxLenAttr != null)
653: maxLen = Integer.parseInt(maxLenAttr);
654: if (minValueAttr != null)
655: minValue = Integer.parseInt(minValueAttr);
656: if (maxValueAttr != null)
657: maxValue = Integer.parseInt(maxValueAttr);
658:
659: /* validate type attribute */
660: if (type.equals("varchar"))
661: sqlType = Types.VARCHAR;
662: else if (type.equals("integer"))
663: sqlType = Types.INTEGER;
664: else if (type.equals("double"))
665: sqlType = Types.DOUBLE;
666: else if (type.equals("date"))
667: sqlType = Types.DATE;
668:
669: /* get value if present in request */
670: String data[] = req.getParameterValues(id);
671: if (data != null && !data[0].trim().equals("")) {
672: /* only accept single value parameters - not arrays */
673: if (data.length == 1) {
674: /* OK - let's validate according to data type */
675: value = data[0].trim();
676:
677: /* check maxlen rule */
678: if (maxLen > 0) {
679: if (value.length() > maxLen)
680: errors.addMessage(id, label + ": "
681: + "${lbl:data_too_long}" + maxLen);
682: }
683:
684: /* check regular expression */
685: if (sqlType == Types.VARCHAR && regexp != null) {
686: boolean isMatch = Pattern
687: .matches(regexp, value);
688: if (!isMatch)
689: errors.addMessage(id, label + ": "
690: + regexpError);
691: }
692:
693: /* convert to datatype if valid */
694: switch (sqlType) {
695: case Types.DATE:
696: java.util.Date d = ValidatorUtil.testDate(
697: value, dateFormat);
698: if (d == null)
699: errors.addMessage(id, label + ": "
700: + "${lbl:invalid_date}");
701: else
702: inputs.setValue(id, d);
703:
704: break;
705:
706: case Types.DOUBLE:
707: Double dbl = ValidatorUtil.testDouble(value);
708: if (dbl == null)
709: errors.addMessage(id, label + ": "
710: + "${lbl:invalid_double}");
711: else
712: inputs.setValue(id, dbl);
713:
714: if (minValueAttr != null
715: && dbl != null
716: && dbl.doubleValue() < Double
717: .parseDouble(minValueAttr))
718: errors.addMessage(id, label + ": "
719: + "${lbl:min_value_violation}"
720: + minValue);
721: if (maxValueAttr != null
722: && dbl != null
723: && dbl.doubleValue() > Double
724: .parseDouble(maxValueAttr))
725: errors.addMessage(id, label + ": "
726: + "${lbl:max_value_violation}"
727: + maxValue);
728:
729: break;
730:
731: case Types.INTEGER:
732: Integer i = ValidatorUtil.testInteger(value);
733: if (i == null)
734: errors.addMessage(id, label + ": "
735: + "${lbl:invalid_integer}");
736: else
737: inputs.setValue(id, i);
738:
739: if (minValueAttr != null && i != null
740: && i.intValue() < minValue)
741: errors.addMessage(id, label + ": "
742: + "${lbl:min_value_violation}"
743: + minValue);
744: if (maxValueAttr != null && i != null
745: && i.intValue() > maxValue)
746: errors.addMessage(id, label + ": "
747: + "${lbl:max_value_violation}"
748: + maxValue);
749:
750: break;
751:
752: case Types.VARCHAR:
753: inputs.setValue(id, value);
754: break;
755:
756: }
757:
758: } else {
759: throw new Throwable(
760: "Invalid parameter. Generic validator can't process array parameters. Parameter ("
761: + id + ") in file: " + file);
762: }
763:
764: } else if (required.equals("true")) {
765: errors.addMessage(id, label + ": "
766: + "${lbl:parameter_required}");
767: }
768:
769: }
770:
771: /*
772: * now check if there are any custom validators defined
773: * this is only necessary if there are no previous errors
774: * because custom-validator require valid request parameters
775: */
776: if (errors.getErrors().getRecordCount() == 0) {
777: Elements valds = root.getElements("custom-validator");
778: while (valds.hasMoreElements()) {
779:
780: /* read validator configuration */
781: HashMap<String, String> a = new HashMap<String, String>(
782: 5);
783: Element validator = valds.next();
784: String className = validator
785: .getAttributeValue("classname");
786: String onErrorLabel = validator
787: .getAttributeValue("on-error-label");
788:
789: //patch 2008-01-31 - for ExtJS requested by M.Betti
790: String id = validator.getAttributeValue("id");
791: if (id == null)
792: id = "";
793: //end patch
794:
795: /* custom attributes */
796: Attributes attribs = validator.getAttributeObjects();
797: while (attribs.hasMoreElements()) {
798: Attribute ax = attribs.next();
799: a.put(ax.getName(), ax.getValue());
800: }
801:
802: /* load class and instantiate object */
803: AbstractValidator t = null;
804: t = (AbstractValidator) getObject(className);
805: t.init(_ctx, req, null);
806: t.setConfig(config);
807: t.setConnection(conn);
808:
809: /* log jdbc performance? */
810: if (jdbcLog)
811: t.setLogWriter(jdbcLogPrinter);
812:
813: /* call isValid method */
814: boolean b = t.isValid(req, inputs, a);
815:
816: /* on error add error message to list of errors */
817: if (!b) {
818: String err = t.getErrorMessage();
819: if (err == null)
820: err = onErrorLabel;
821: errors.addMessage(id, err);
822: }
823:
824: }
825: }
826:
827: if (errors.getErrors().getRecordCount() > 0) {
828: req.setAttribute("_request", inputs);
829: throw errors;
830: } else {
831: if (!sessionID.equals(""))
832: req.getSession().setAttribute(sessionID, inputs);
833: return inputs;
834: }
835:
836: }
837:
838: /**
839: * Forward request to another resource in the same context
840: * @param uri Absolute path to resource (a valid servlet mapping)
841: * @throws Throwable
842: */
843: void forward(String uri, HttpServletRequest req,
844: HttpServletResponse res) throws Throwable {
845: RequestDispatcher rd = _ctx.getRequestDispatcher(uri);
846: rd.forward(req, res);
847: }
848:
849: /**
850: * Set request attributes if defined in config.xml
851: * @param req
852: * @param config
853: * @throws Throwable
854: */
855: void setRequestValues(HttpServletRequest req, Config config)
856: throws Throwable {
857:
858: Document doc = config.getDocument();
859:
860: Elements e = doc.getRoot().getElements("set-request-attribute");
861: if (e != null) {
862: while (e.hasMoreElements()) {
863: Element r = e.next();
864: String id = r.getAttribute("id");
865: String value = r.getAttribute("value");
866: req.setAttribute(id, value);
867: }
868: }
869:
870: }
871:
872: /**
873: * PATCH 2005-01-24 - Loads class and returns new instance of this class.
874: * Solves sporadic Class not found exceptions when running with Resin 2.1.14 + IBM JDK 1.4.2.
875: * This method attempts to use context class loader, if fails it will use Class.forName().
876: * @param className Name of class to load - include full package name
877: * @return New instance of the class
878: * @throws Throwable (ClassNotFound exceptions)
879: */
880: Object getObject(String className) throws Throwable {
881:
882: ClassLoader loader = Thread.currentThread()
883: .getContextClassLoader();
884:
885: try {
886: return loader.loadClass(className).newInstance();
887: } catch (Throwable e) {
888: System.err.println("[classloader] " + loader.toString());
889: String date = StringUtil.formatDate(new java.util.Date(),
890: "dd-MM-yyyy HH:mm:ss");
891: System.err.println("[WARNING@" + date + "]: "
892: + e.getMessage());
893: System.err.println("[WARNING@" + date
894: + "]: Context class loader failed to load class ["
895: + className + "]. Using Class.forName()");
896: System.err.println("[classloader] "
897: + this .getClass().getClassLoader().toString());
898: return Class.forName(className).newInstance();
899: }
900:
901: }
902:
903: /**
904: * Replace markers like ${def:actionroot} in config.xml
905: * @param req Request object
906: * @param xmlData Body of config.xml
907: * @return Body of config.xml with all markers replaced by the corresponding values
908: * @throws Throwable
909: */
910: String replaceMacros(HttpServletRequest req, String xmlData)
911: throws Throwable {
912: //replace ${def:actionroot}
913: String actionPath = (String) req
914: .getAttribute("dinamica.action.path");
915: actionPath = actionPath.substring(0, actionPath
916: .lastIndexOf("/"));
917: xmlData = StringUtil.replace(xmlData, "${def:actionroot}",
918: actionPath);
919:
920: //return xml data
921: return xmlData;
922: }
923:
924: }
|