001: /*
002: * Copyright (c) 2001 - 2005 ivata limited.
003: * All rights reserved.
004: * -----------------------------------------------------------------------------
005: * ivata masks may be redistributed under the GNU General Public
006: * License as published by the Free Software Foundation;
007: * version 2 of the License.
008: *
009: * These programs are free software; you can redistribute them and/or
010: * modify them under the terms of the GNU General Public License
011: * as published by the Free Software Foundation; version 2 of the License.
012: *
013: * These programs are distributed in the hope that they will be useful,
014: * but WITHOUT ANY WARRANTY; without even the implied warranty of
015: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
016: *
017: * See the GNU General Public License in the file LICENSE.txt for more
018: * details.
019: *
020: * If you would like a copy of the GNU General Public License write to
021: *
022: * Free Software Foundation, Inc.
023: * 59 Temple Place - Suite 330
024: * Boston, MA 02111-1307, USA.
025: *
026: *
027: * To arrange commercial support and licensing, contact ivata at
028: * http://www.ivata.com/contact.jsp
029: * -----------------------------------------------------------------------------
030: * $Log: MaskRequestProcessor.java,v $
031: * Revision 1.16 2005/10/14 14:09:17 colinmacleod
032: * Added saveForm and getSavedForm methods to the implementation class.
033: *
034: * Revision 1.15 2005/10/11 18:54:06 colinmacleod
035: * Fixed some checkstyle and javadoc issues.
036: *
037: * Revision 1.14 2005/10/03 10:17:25 colinmacleod
038: * Fixed some style and javadoc issues.
039: *
040: * Revision 1.13 2005/10/02 10:52:00 colinmacleod
041: * Improved logging.
042: * Added client session.
043: *
044: * Revision 1.12 2005/04/27 17:23:27 colinmacleod
045: * Fixed bugs resulting from ivata masks changes
046: * for ivata groupware v0.11.
047: *
048: * Revision 1.11 2005/04/22 09:46:36 colinmacleod
049: * processActionCreate no longer final.
050: *
051: * Revision 1.10 2005/04/11 12:21:15 colinmacleod
052: * Changed MaskRequestProcessorImpl to
053: * MaskRequestProcessorImplementation.
054: * Improved tiles support.
055: *
056: * Revision 1.9 2005/04/09 18:04:19 colinmacleod
057: * Changed copyright text to GPL v2 explicitly.
058: *
059: * Revision 1.8 2005/01/19 13:14:02 colinmacleod
060: * Renamed CausedByException to SystemException.
061: *
062: * Revision 1.7 2005/01/07 08:08:24 colinmacleod
063: * Moved up a version number.
064: * Changed copyright notices to 2005.
065: * Updated the documentation:
066: * - started working on multiproject:site docu.
067: * - changed the logo.
068: * Added checkstyle and fixed LOADS of style issues.
069: * Added separate thirdparty subproject.
070: * Added struts (in web), util and webgui (in webtheme) from ivata op.
071: *
072: * Revision 1.6 2004/12/29 15:34:07 colinmacleod
073: * Improved checking for non-ivata masks forms.
074: *
075: * Revision 1.5 2004/12/23 21:28:32 colinmacleod
076: * Modifications to add ivata op compatibility.
077: *
078: * Revision 1.4 2004/11/12 15:10:42 colinmacleod
079: * Moved persistence classes from ivata op as a replacement for
080: * ValueObjectLocator.
081: *
082: * Revision 1.3 2004/11/11 13:49:47 colinmacleod
083: * Added log4j logging.
084: *
085: * Revision 1.2 2004/05/18 22:22:15 colinmacleod
086: * Added check not to populate if cancel was pressed.
087: *
088: * Revision 1.1.1.1 2004/05/16 20:40:33 colinmacleod
089: * Ready for 0.1 release
090: * -----------------------------------------------------------------------------
091: */
092: package com.ivata.mask.web.struts;
093:
094: import java.io.IOException;
095:
096: import javax.servlet.ServletException;
097: import javax.servlet.http.HttpServletRequest;
098: import javax.servlet.http.HttpServletResponse;
099:
100: import org.apache.log4j.Logger;
101: import org.apache.struts.action.Action;
102: import org.apache.struts.action.ActionForm;
103: import org.apache.struts.action.ActionMapping;
104: import org.apache.struts.action.ActionServlet;
105: import org.apache.struts.action.RequestProcessor;
106: import org.apache.struts.config.FormBeanConfig;
107: import org.apache.struts.config.ModuleConfig;
108: import org.apache.struts.util.RequestUtils;
109: import org.sourceforge.clientsession.MarshallingException;
110:
111: import com.ivata.mask.MaskFactory;
112: import com.ivata.mask.persistence.PersistenceManager;
113: import com.ivata.mask.util.SystemException;
114:
115: /**
116: * <p>
117: * Extend from this class if you _don't_ want to use <strong>Struts Tiles
118: * </strong>.
119: * </p>
120: *
121: * @since ivata masks 0.3 (2004-05-11)
122: * @author Colin MacLeod
123: * <a href='mailto:colin.macleod@ivata.com'>colin.macleod@ivata.com</a>
124: * @version $Revision: 1.16 $
125: */
126: public class MaskRequestProcessor extends RequestProcessor {
127: /**
128: * Logger for this class.
129: */
130: private static final Logger logger = Logger
131: .getLogger(MaskRequestProcessor.class);
132:
133: /**
134: * <p>
135: * This does all the hard work. :-)
136: * </p>
137: */
138: private MaskRequestProcessorImplementation implementation;
139:
140: /**
141: * <p>
142: * Initializes the mask factory, the value object locator and the the
143: * standard field value converters.
144: * </p>
145: *
146: * @param maskFactory
147: * needed to access the masks and groups of masks.
148: * @param persistenceManager
149: * used to locate the value objects by their shared base class.
150: */
151: public MaskRequestProcessor(final MaskFactory maskFactory,
152: final PersistenceManager persistenceManager) {
153: }
154:
155: /**
156: * <p>
157: * Override this method to define how to create actions in your environment.
158: * This lets you use ivata masks with a standard framework.
159: * </p>
160: *
161: * <p>
162: * The default implementation looks for the action classes it knows about
163: * and initializes them directly. This is a simple starting point; in real
164: * life it is better to use a standard framework such as <a
165: * href="http://picocontainer.org">picocontainer </a>.
166: * </p>
167: *
168: *
169: * @param className
170: * full path and name of the action class to be created.
171: * @param request
172: * request for which we are creating an action.
173: * @param response
174: * response we are sending.
175: * @param mapping
176: * <strong>Struts </strong> mapping.
177: * @return valid action for the path, or <code>null</code> if the action
178: * can and should be created using the default <strong>Struts
179: * </strong> framework.
180: * @throws IOException
181: * if the action cannot be created.
182: */
183: protected Action createAction(final String className,
184: final HttpServletRequest request,
185: final HttpServletResponse response,
186: final ActionMapping mapping) throws IOException {
187: if (logger.isDebugEnabled()) {
188: logger.debug("createAction(String className = " + className
189: + ", HttpServletRequest request = " + request
190: + ", HttpServletResponse response = " + response
191: + ", ActionMapping mapping = " + mapping
192: + ") - start");
193: }
194:
195: assert (implementation != null);
196: try {
197: Action instance = implementation.createAction(className,
198: request, response, mapping, servlet, actions);
199: if (instance != null) {
200: instance.setServlet(servlet);
201: }
202:
203: if (logger.isDebugEnabled()) {
204: logger.debug("createAction() - end - return value = "
205: + instance);
206: }
207: return instance;
208: } catch (SystemException e) {
209: logger
210: .error("createAction - error creating the action.",
211: e);
212: response.sendError(
213: HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
214: getInternal().getMessage("actionCreate",
215: mapping.getPath()));
216:
217: if (logger.isDebugEnabled()) {
218: logger.debug("createAction() - end - return value = "
219: + null);
220: }
221: return null;
222: }
223:
224: }
225:
226: /**
227: * <p>
228: * Override this method to define how to create action forms in your
229: * environment. This lets you use ivata masks with a standard framework.
230: * </p>
231: *
232: * <p>
233: * The default implementation looks for the form classes it knows about and
234: * initializes them directly. This is a simple starting point; in real life
235: * it is better to use a standard framework such as <a
236: * href="http://picocontainer.org">picocontainer </a>.
237: * </p>
238: *
239: * @param formBeanConfig
240: * instance of <code>FormBeanConfig</code> defining the form to
241: * be created.
242: * @param request
243: * request for which we are creating an action.
244: * @param response
245: * response we are sending.
246: * @param mapping
247: * <strong>Struts </strong> mapping.
248: * @return valid action for the path, or <code>null</code> if the form can
249: * and should be created using the default <strong>Struts </strong>
250: * framework.
251: * @throws SystemException
252: * if the form cannot be created for any reason.
253: */
254: protected ActionForm createActionForm(
255: final FormBeanConfig formBeanConfig,
256: final HttpServletRequest request,
257: final HttpServletResponse response,
258: final ActionMapping mapping) throws SystemException {
259: if (logger.isDebugEnabled()) {
260: logger
261: .debug("createActionForm(FormBeanConfig formBeanConfig = "
262: + formBeanConfig
263: + ", HttpServletRequest request = "
264: + request
265: + ", HttpServletResponse response = "
266: + response
267: + ", ActionMapping mapping = "
268: + mapping + ") - start");
269: }
270:
271: assert (implementation != null);
272: // if the form should be dynamic, we need the servlet to create it
273: if (formBeanConfig.getDynamic()) {
274: ActionForm returnActionForm = RequestUtils
275: .createActionForm(formBeanConfig, servlet);
276: if (logger.isDebugEnabled()) {
277: logger
278: .debug("createActionForm() - end - return value = "
279: + returnActionForm);
280: }
281: return returnActionForm;
282: }
283: ActionForm form = implementation.createActionForm(
284: formBeanConfig, request, response, mapping);
285: if (form != null) {
286: form.setServlet(servlet);
287: }
288:
289: if (logger.isDebugEnabled()) {
290: logger.debug("createActionForm() - end - return value = "
291: + form);
292: }
293: return form;
294: }
295:
296: /**
297: * Get the actual mask request processor which does all the hard work. The
298: * functionality for this class is split off into this processor, so we
299: * can extend both the <em>Tiles</em> and standard versions of
300: * <em>Struts</em> processor classes with the same functional extensions.
301: *
302: * @return mask processor implementation.
303: */
304: protected MaskRequestProcessorImplementation getImplementation() {
305: if (logger.isDebugEnabled()) {
306: logger.debug("getImplementation() - start");
307: }
308:
309: assert (implementation != null);
310:
311: if (logger.isDebugEnabled()) {
312: logger.debug("getImplementation() - end - return value = "
313: + implementation);
314: }
315: return implementation;
316: }
317:
318: /**
319: * {@inheritDoc}
320: *
321: * @param servletParam {@inheritDoc}
322: * @param moduleConfigParam {@inheritDoc}
323: * @throws javax.servlet.ServletException {@inheritDoc}
324: */
325: public void init(final ActionServlet servletParam,
326: final ModuleConfig moduleConfigParam)
327: throws ServletException {
328: if (logger.isDebugEnabled()) {
329: logger.debug("init(ActionServlet servletParam = "
330: + servletParam
331: + ", ModuleConfig moduleConfigParam = "
332: + moduleConfigParam + ") - start");
333: }
334:
335: super .init(servletParam, moduleConfigParam);
336: assert (implementation != null);
337: implementation.init(servletParam, moduleConfigParam);
338:
339: if (logger.isDebugEnabled()) {
340: logger.debug("init() - end");
341: }
342: }
343:
344: /**
345: * <p>
346: * Overridden to create actions, since our actions have custom constructor
347: * parameters. <b>Don't try to override this method: </b> override {@link
348: * #createAction createAction} instead.
349: * </p>
350: *
351: * @param request {@inheritDoc}
352: * @param response {@inheritDoc}
353: * @param mapping {@inheritDoc}
354: * @return valid action for the path.
355: * @throws IOException {@inheritDoc}
356: */
357: protected Action processActionCreate(
358: final HttpServletRequest request,
359: final HttpServletResponse response,
360: final ActionMapping mapping) throws IOException {
361: if (logger.isDebugEnabled()) {
362: logger
363: .debug("processActionCreate(HttpServletRequest request = "
364: + request
365: + ", HttpServletResponse response = "
366: + response
367: + ", ActionMapping mapping = "
368: + mapping + ") - start");
369: }
370:
371: // see if there is already an instance of this class to use
372: String className = mapping.getType();
373: Action action = (Action) actions.get(className);
374: if (action != null) {
375: if (logger.isDebugEnabled()) {
376: logger
377: .debug("processActionCreate() - end - return value = "
378: + action);
379: }
380: return action;
381: }
382: action = createAction(className, request, response, mapping);
383: if (action != null) {
384: if (logger.isDebugEnabled()) {
385: logger
386: .debug("processActionCreate() - end - return value = "
387: + action);
388: }
389: return action;
390: }
391: Action returnAction = super .processActionCreate(request,
392: response, mapping);
393: if (logger.isDebugEnabled()) {
394: logger
395: .debug("processActionCreate() - end - return value = "
396: + returnAction);
397: }
398: return returnAction;
399: }
400:
401: /**
402: * <p>
403: * Overridden to create forms, since our forms have custom constructor
404: * parameters. <b>Don't try to override this method: </b> override {@link
405: * #createActionForm createActionForm} instead.
406: * </p>
407: *
408: * @param request {@inheritDoc}
409: * @param response {@inheritDoc}
410: * @param mapping {@inheritDoc}
411: * @return {@inheritDoc}
412: */
413: protected final ActionForm processActionForm(
414: final HttpServletRequest request,
415: final HttpServletResponse response,
416: final ActionMapping mapping) {
417: if (logger.isDebugEnabled()) {
418: logger
419: .debug("processActionForm(HttpServletRequest request = "
420: + request
421: + ", HttpServletResponse response = "
422: + response
423: + ", ActionMapping mapping = "
424: + mapping + ") - start");
425: }
426:
427: try {
428: implementation.createClientSession(request, servlet
429: .getServletContext());
430: } catch (MarshallingException e) {
431: logger.error(
432: "processActionForm - error creating the client "
433: + "session.", e);
434: throw new RuntimeException(e);
435: }
436: String name = mapping.getAttribute();
437: FormBeanConfig config = moduleConfig.findFormBeanConfig(name);
438: if (config == null) {
439: if (logger.isDebugEnabled()) {
440: logger
441: .debug("processActionForm() - end - return value = "
442: + null);
443: }
444: return null;
445: }
446: ActionForm form = implementation.getSavedForm(request, mapping);
447: if (form != null) {
448: if (logger.isDebugEnabled()) {
449: logger
450: .debug("processActionForm() - end - return value = "
451: + form);
452: }
453: return form;
454: }
455: try {
456: form = createActionForm(config, request, response, mapping);
457: } catch (SystemException e) {
458: logger
459: .error(
460: "processActionForm - error creating the action form.",
461: e);
462: throw new RuntimeException(e);
463: }
464: if (form == null) {
465: form = super .processActionForm(request, response, mapping);
466: }
467: if (form != null) {
468: implementation.saveForm(request, mapping, form);
469: }
470:
471: if (logger.isDebugEnabled()) {
472: logger.debug("processActionForm() - end - return value = "
473: + form);
474: }
475: return form;
476: }
477:
478: /**
479: * <p>
480: * Overridden to populate forms, and convert the string values of value
481: * object properties into the correct form for their class.
482: * </p>
483: *
484: * @param request {@inheritDoc}
485: * @param response {@inheritDoc}
486: * @param form {@inheritDoc}
487: * @param mapping {@inheritDoc}
488: * @exception ServletException {@inheritDoc}
489: */
490: protected void processPopulate(final HttpServletRequest request,
491: final HttpServletResponse response, final ActionForm form,
492: final ActionMapping mapping) throws ServletException {
493: if (logger.isDebugEnabled()) {
494: logger
495: .debug("processPopulate(HttpServletRequest request = "
496: + request
497: + ", HttpServletResponse response = "
498: + response
499: + ", ActionForm form = "
500: + form
501: + ", ActionMapping mapping = "
502: + mapping
503: + ") - start");
504: }
505:
506: // can't populate if there's nothing there :-)
507: if (form == null) {
508: if (logger.isDebugEnabled()) {
509: logger.debug("processPopulate() - end");
510: }
511: return;
512: }
513: assert (implementation != null);
514: implementation
515: .processPopulate(request, response, form, mapping);
516: //super.processPopulate(request, response, form, mapping);
517: if (form != null) {
518: form.setServlet(servlet);
519: }
520:
521: if (logger.isDebugEnabled()) {
522: logger.debug("processPopulate() - end");
523: }
524: }
525:
526: /**
527: * <copyDoc>Refer to {@link #getImplementation}.</copyDoc>
528: * @param implementationParam
529: * <copyDoc>Refer to {@link #getImplementation}.</copyDoc>
530: */
531: protected void setImplementation(
532: final MaskRequestProcessorImplementation implementationParam) {
533: if (logger.isDebugEnabled()) {
534: logger.debug("Setting implementation. Before '"
535: + implementation + "', after '"
536: + implementationParam + "'");
537: }
538: implementation = implementationParam;
539:
540: if (logger.isDebugEnabled()) {
541: logger.debug("setImplementation() - end");
542: }
543: }
544: }
|