0001: /*
0002: * Copyright (c) 2001 - 2005 ivata limited.
0003: * All rights reserved.
0004: * -----------------------------------------------------------------------------
0005: * ivata masks may be redistributed under the GNU General Public
0006: * License as published by the Free Software Foundation;
0007: * version 2 of the License.
0008: *
0009: * These programs are free software; you can redistribute them and/or
0010: * modify them under the terms of the GNU General Public License
0011: * as published by the Free Software Foundation; version 2 of the License.
0012: *
0013: * These programs are distributed in the hope that they will be useful,
0014: * but WITHOUT ANY WARRANTY; without even the implied warranty of
0015: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
0016: *
0017: * See the GNU General Public License in the file LICENSE.txt for more
0018: * details.
0019: *
0020: * If you would like a copy of the GNU General Public License write to
0021: *
0022: * Free Software Foundation, Inc.
0023: * 59 Temple Place - Suite 330
0024: * Boston, MA 02111-1307, USA.
0025: *
0026: *
0027: * To arrange commercial support and licensing, contact ivata at
0028: * http://www.ivata.com/contact.jsp
0029: * -----------------------------------------------------------------------------
0030: * $Log: MaskRequestProcessorImplementation.java,v $
0031: * Revision 1.13 2005/11/03 14:29:51 colinmacleod
0032: * Fixed spelling mistakes and removed duplicated logging statements.
0033: *
0034: * Revision 1.12 2005/10/17 18:23:53 colinmacleod
0035: * createActionForm now creates list forms too.
0036: * Added STOP_POPULATE_ATTRIBUTE flag to simplify chained action processing.
0037: *
0038: * Revision 1.11 2005/10/17 15:19:05 colinmacleod
0039: * Now ignores (doesn't set) empty password values.
0040: *
0041: * Revision 1.10 2005/10/14 14:09:17 colinmacleod
0042: * Added saveForm and getSavedForm methods to the implementation class.
0043: *
0044: * Revision 1.9 2005/10/12 18:36:58 colinmacleod
0045: * Standardized format of Logger declaration - to make it easier to find
0046: * instances which are not both static and final.
0047: *
0048: * Revision 1.8 2005/10/11 18:54:06 colinmacleod
0049: * Fixed some checkstyle and javadoc issues.
0050: *
0051: * Revision 1.7 2005/10/03 10:17:25 colinmacleod
0052: * Fixed some style and javadoc issues.
0053: *
0054: * Revision 1.6 2005/10/02 10:52:00 colinmacleod
0055: * Improved logging.
0056: * Added client session.
0057: *
0058: * Revision 1.5 2005/09/29 12:18:44 colinmacleod
0059: * Added session parameter to persistenceManager.openSession().
0060: *
0061: * Revision 1.4 2005/09/14 13:00:27 colinmacleod
0062: * Added work-around for lists which in
0063: * which indexed elements are set.
0064: *
0065: * Revision 1.3 2005/04/29 16:33:17 colinmacleod
0066: * Fixes for non-string types on dyna forms.
0067: *
0068: * Revision 1.2 2005/04/27 17:23:28 colinmacleod
0069: * Fixed bugs resulting from ivata masks changes
0070: * for ivata groupware v0.11.
0071: *
0072: * Revision 1.1 2005/04/11 12:21:15 colinmacleod
0073: * Changed MaskRequestProcessorImpl to
0074: * MaskRequestProcessorImplementation.
0075: * Improved tiles support.
0076: *
0077: * Revision 1.5 2005/03/10 10:44:35 colinmacleod
0078: * Fixed validation conversion of Struts classes to
0079: * ivata masks validation errors.
0080: *
0081: * Revision 1.4 2005/01/19 13:14:02 colinmacleod
0082: * Renamed CausedByException to SystemException.
0083: *
0084: * Revision 1.3 2005/01/07 08:08:24 colinmacleod
0085: * Moved up a version number.
0086: * Changed copyright notices to 2005.
0087: * Updated the documentation:
0088: * - started working on multiproject:site docu.
0089: * - changed the logo.
0090: * Added checkstyle and fixed LOADS of style issues.
0091: * Added separate thirdparty subproject.
0092: * Added struts (in web), util and webgui (in webtheme) from ivata op.
0093: *
0094: * Revision 1.2 2004/12/29 15:34:07 colinmacleod
0095: * Improved checking for non-ivata masks forms.
0096: *
0097: * Revision 1.1 2004/12/23 21:28:32 colinmacleod
0098: * Modifications to add ivata op compatibility.
0099: * -----------------------------------------------------------------------------
0100: */
0101: package com.ivata.mask.web.struts;
0102:
0103: import java.beans.PropertyDescriptor;
0104: import java.io.IOException;
0105: import java.io.StringReader;
0106: import java.lang.reflect.Constructor;
0107: import java.lang.reflect.InvocationTargetException;
0108: import java.util.Arrays;
0109: import java.util.Collection;
0110: import java.util.Enumeration;
0111: import java.util.List;
0112: import java.util.Map;
0113: import java.util.Vector;
0114:
0115: import javax.servlet.ServletContext;
0116: import javax.servlet.ServletException;
0117: import javax.servlet.http.HttpServletRequest;
0118: import javax.servlet.http.HttpServletResponse;
0119: import javax.servlet.http.HttpSession;
0120:
0121: import org.apache.commons.beanutils.DynaProperty;
0122: import org.apache.commons.beanutils.PropertyUtils;
0123: import org.apache.log4j.Logger;
0124: import org.apache.struts.Globals;
0125: import org.apache.struts.action.Action;
0126: import org.apache.struts.action.ActionForm;
0127: import org.apache.struts.action.ActionMapping;
0128: import org.apache.struts.action.ActionServlet;
0129: import org.apache.struts.action.DynaActionForm;
0130: import org.apache.struts.config.FormBeanConfig;
0131: import org.apache.struts.config.ModuleConfig;
0132: import org.apache.struts.taglib.html.Constants;
0133: import org.dom4j.Document;
0134: import org.dom4j.DocumentException;
0135: import org.dom4j.Element;
0136: import org.dom4j.Node;
0137: import org.dom4j.io.SAXReader;
0138: import org.sourceforge.clientsession.ClientSession;
0139: import org.sourceforge.clientsession.MarshallingException;
0140: import org.sourceforge.clientsession.SessionManager;
0141:
0142: import com.ivata.mask.Mask;
0143: import com.ivata.mask.MaskFactory;
0144: import com.ivata.mask.field.DefaultFieldValueConvertorFactory;
0145: import com.ivata.mask.field.Field;
0146: import com.ivata.mask.field.FieldValueConvertor;
0147: import com.ivata.mask.field.FieldValueConvertorConstants;
0148: import com.ivata.mask.field.FieldValueConvertorFactory;
0149: import com.ivata.mask.persistence.PersistenceManager;
0150: import com.ivata.mask.persistence.PersistenceSession;
0151: import com.ivata.mask.util.StringHandling;
0152: import com.ivata.mask.util.SystemException;
0153: import com.ivata.mask.validation.ValidationError;
0154: import com.ivata.mask.validation.ValidationErrors;
0155: import com.ivata.mask.valueobject.ValueObject;
0156: import com.ivata.mask.web.tag.html.ClientSessionConstants;
0157:
0158: /**
0159: * <p>
0160: * Mask request processor implementation - kept separate so we can share
0161: * functionality between the regular ({@link
0162: * com.ivata.mask.web.struts.MaskRequestProcessor}) and tiles (
0163: * {@link com.ivata.mask.web.struts.MaskTilesRequestProcessor}) versions.
0164: * </p>
0165: *
0166: * @since ivata masks 0.4 (2004-12-23)
0167: * @author Colin MacLeod
0168: * <a href='mailto:colin.macleod@ivata.com'>colin.macleod@ivata.com</a>
0169: * @version $Revision: 1.13 $
0170: */
0171: public class MaskRequestProcessorImplementation {
0172: /**
0173: * Logger for this class.
0174: */
0175: private static final Logger logger = Logger
0176: .getLogger(MaskRequestProcessorImplementation.class);
0177: /**
0178: * <p>
0179: * Used to generate convertors to convert property types from strings.
0180: * </p>
0181: */
0182: private FieldValueConvertorFactory fieldValueConvertorFactory;
0183: /**
0184: * <p>
0185: * This factory is needed to access the masks and groups of masks.
0186: * </p>
0187: */
0188: private MaskFactory maskFactory;
0189: /**
0190: * <p>
0191: * Used to locate the value objects by their shared base class.
0192: * </p>
0193: */
0194: private PersistenceManager persistenceManager;
0195: /**
0196: * <p>
0197: * <copyDoc>Refer to {@link MaskRequestProcessorImplementation()}.</copyDoc>
0198: * </p>
0199: */
0200: private SessionManager sessionManager;
0201:
0202: /**
0203: * <p>
0204: * Initializes the mask factory, the value object locator and the the
0205: * standard field value convertors.
0206: * </p>
0207: *
0208: * @param maskFactoryParam
0209: * needed to access the masks and groups of masks.
0210: * @param persistenceManagerParam
0211: * used to locate the value objects by their shared base class.
0212: * @param fieldValueConvertorFactoryParam Used to generate convertors, used
0213: * to set field values from string request parameters.
0214: * @param sessionManagerParam
0215: * This session manager is used to marshall and unmarshall client sessions.
0216: */
0217: public MaskRequestProcessorImplementation(
0218: final MaskFactory maskFactoryParam,
0219: final PersistenceManager persistenceManagerParam,
0220: final FieldValueConvertorFactory fieldValueConvertorFactoryParam,
0221: final SessionManager sessionManagerParam) {
0222: this .maskFactory = maskFactoryParam;
0223: this .persistenceManager = persistenceManagerParam;
0224: this .fieldValueConvertorFactory = fieldValueConvertorFactoryParam;
0225: this .sessionManager = sessionManagerParam;
0226: }
0227:
0228: /**
0229: * <p>
0230: * Override this method to define how to create actions in your environment.
0231: * This lets you use ivata masks with a standard framework.
0232: * </p>
0233: *
0234: * <p>
0235: * The default implementation looks for the action classes it knows about
0236: * and initializes them directly. This is a simple starting point; in real
0237: * life it is better to use a standard framework such as <a
0238: * href="http://picocontainer.org">picocontainer </a>.
0239: * </p>
0240: *
0241: *
0242: * @param className
0243: * full path and name of the action class to be created.
0244: * @param request request for which we are creating an action.
0245: * @param response response we are sending.
0246: * @param mapping <em>Struts</em> mapping.
0247: * @param servlet current servlet which is processing the action.
0248: * @param actionsParam Map of all existing system actions, keyed by class
0249: * name.
0250: * @return valid action for the path, or <code>null</code> if the action
0251: * can and should be created using the default <strong>Struts
0252: * </strong> framework.
0253: * @throws IOException if the action cannot be created.
0254: * @throws SystemException can be thrown by overridden methods, if the
0255: * action cannot be created.
0256: */
0257: protected Action createAction(final String className,
0258: final HttpServletRequest request,
0259: final HttpServletResponse response,
0260: final ActionMapping mapping, final ActionServlet servlet,
0261: final Map actionsParam) throws IOException, SystemException {
0262: if (logger.isDebugEnabled()) {
0263: logger.debug("createAction(String className = " + className
0264: + ", HttpServletRequest request = " + request
0265: + ", HttpServletResponse response = " + response
0266: + ", ActionMapping mapping = " + mapping
0267: + ", ActionServlet servlet = " + servlet
0268: + ") - start");
0269: }
0270:
0271: // if the class is not one of our ivata masks actions, get out...
0272: if (!className.startsWith("com.ivata.mask.web.struts")) {
0273: if (logger.isDebugEnabled()) {
0274: logger.debug("createAction - end - return value = "
0275: + null);
0276: }
0277: return null;
0278: }
0279: // if the class is one of our types, instantiate it accordingly
0280: Action action = null;
0281: MaskAuthenticator maskAuthenticator = new DefaultMaskAuthenticator();
0282: if (className.endsWith("FindAction")) {
0283: action = new FindAction(persistenceManager, maskFactory,
0284: maskAuthenticator);
0285: } else if (className.endsWith("InputMaskAction")) {
0286: action = new InputMaskAction(maskFactory,
0287: persistenceManager, maskAuthenticator);
0288: } else if (className.endsWith("ListAction")) {
0289: action = new ListAction(persistenceManager, maskFactory,
0290: maskAuthenticator);
0291: } else if (className.endsWith("NewAction")) {
0292: action = new NewAction(maskFactory, maskAuthenticator);
0293: } else {
0294: throw new IOException("Unknown action '" + className + "'");
0295: }
0296:
0297: if (logger.isDebugEnabled()) {
0298: logger.debug("createAction - end - return value = "
0299: + action);
0300: }
0301: return action;
0302: }
0303:
0304: /**
0305: * <p>
0306: * Override this method to define how to create action forms in your
0307: * environment. This lets you use ivata masks with a standard framework.
0308: * </p>
0309: *
0310: * <p>
0311: * The default implementation looks for the form classes it knows about and
0312: * initializes them directly. This is a simple starting point; in real life
0313: * it is better to use a standard framework such as <a
0314: * href="http://picocontainer.org">picocontainer </a>.
0315: * </p>
0316: *
0317: * @param formBeanConfig instance of <code>FormBeanConfig</code> defining
0318: * the form to be created.
0319: * @param request request for which we are creating an action.
0320: * @param response response we are sending.
0321: * @param mapping <em>Struts</em> mapping.
0322: * @return valid action for the path, or <code>null</code> if the form can
0323: * and should be created using the default <em>Struts</em> framework.
0324: * @throws SystemException if the form cannot be created for any reason.
0325: */
0326: protected ActionForm createActionForm(
0327: final FormBeanConfig formBeanConfig,
0328: final HttpServletRequest request,
0329: final HttpServletResponse response,
0330: final ActionMapping mapping) throws SystemException {
0331: if (logger.isDebugEnabled()) {
0332: logger
0333: .debug("createActionForm(FormBeanConfig formBeanConfig = "
0334: + formBeanConfig
0335: + ", HttpServletRequest request = "
0336: + request
0337: + ", HttpServletResponse response = "
0338: + response
0339: + ", ActionMapping mapping = "
0340: + mapping + ") - start");
0341: }
0342:
0343: String className = formBeanConfig.getType();
0344: // if the class is not one of our ivata masks actions, get out...
0345: if (!className.startsWith("com.ivata.mask.web.struts")) {
0346: if (logger.isDebugEnabled()) {
0347: logger.debug("createActionForm - end - return value = "
0348: + null);
0349: }
0350: return null;
0351: }
0352: ActionForm form = null;
0353:
0354: // this simple implementation looks for the two classes it knows about
0355: // - InputMaskForm, for input masks
0356: // - ListForm, for lists
0357: // if you are using a component framework such as Dependency Injection
0358: // (PicoContainer, Spring, et al), you want to override this method
0359: // to actually use your component interface to instantiate the form
0360: // instead. see PicoRequestProcessorImplementation in ivata groupware
0361: if ((InputMaskForm.class.getName().equals(className))
0362: || (ListForm.class.getName().equals(className))) {
0363: String baseClassName = request
0364: .getParameter("baseClass.name");
0365: if (baseClassName == null) {
0366: baseClassName = request.getParameter("baseClass");
0367: }
0368: if (baseClassName == null) {
0369: throw new NullPointerException(
0370: "ERROR in MaskRequestProcessor: "
0371: + "you must specify a request parameter called "
0372: + "'baseClass'.");
0373: }
0374: Class baseClass;
0375: try {
0376: baseClass = Class.forName(baseClassName);
0377: } catch (ClassNotFoundException e) {
0378: logger.error(
0379: "createActionForm - could not find class '"
0380: + baseClassName + "'", e);
0381: throw new RuntimeException(
0382: "ERROR in MaskRequestProcessor: no "
0383: + "class called '" + baseClassName
0384: + "'");
0385: }
0386:
0387: // if we were given a value object class to create specifically,
0388: // use that
0389: String valueObjectClassName = request
0390: .getParameter("valueObjectClass");
0391: if (valueObjectClassName == null) {
0392: valueObjectClassName = baseClassName;
0393: }
0394: String inputMask = request.getParameter("inputMask");
0395: if (inputMask == null) {
0396: inputMask = maskFactory.getDefaultInputMask();
0397: }
0398: Class valueObjectClass;
0399: try {
0400: valueObjectClass = Class.forName(valueObjectClassName);
0401: } catch (ClassNotFoundException e1) {
0402: logger.error(
0403: "createActionForm - error no class called '"
0404: + valueObjectClassName + "'.", e1);
0405: throw new SystemException(e1);
0406: }
0407: Mask mask = maskFactory
0408: .getMask(valueObjectClass, inputMask);
0409: // for lists, we'll just create an empty list
0410: if (ListForm.class.getName().equals(className)) {
0411: form = new ListForm(new Vector(), mask,
0412: valueObjectClass);
0413:
0414: // for input masks, we need to create a value object instance
0415: } else {
0416: ValueObject valueObject;
0417: String idString = request.getParameter("idString");
0418: if (idString != null) {
0419: PersistenceSession persistenceSession = persistenceManager
0420: .openSession(request.getSession());
0421: try {
0422: valueObject = persistenceManager
0423: .findByPrimaryKey(persistenceSession,
0424: baseClass, idString);
0425: } finally {
0426: persistenceSession.close();
0427: }
0428: if (valueObject == null) {
0429: throw new NullPointerException(
0430: "ERROR in MaskRequestProcessor: "
0431: + "no value object with id '"
0432: + idString + "' in class '"
0433: + baseClass + "'");
0434: }
0435: } else {
0436: try {
0437: valueObject = (ValueObject) valueObjectClass
0438: .newInstance();
0439: } catch (InstantiationException e) {
0440: logger.error(
0441: "createActionForm - could not instantiate "
0442: + valueObjectClass, e);
0443: throw new RuntimeException("ERROR ("
0444: + e.getClass().getName() + "): "
0445: + e.getMessage());
0446: } catch (IllegalAccessException e) {
0447: logger.error(
0448: "createActionForm - could not instantiate "
0449: + valueObjectClass, e);
0450: throw new RuntimeException("ERROR ("
0451: + e.getClass().getName() + "): "
0452: + e.getMessage());
0453: }
0454: }
0455: form = new InputMaskForm(valueObject, mask, baseClass);
0456: }
0457: }
0458:
0459: if (logger.isDebugEnabled()) {
0460: logger.debug("createActionForm - end - return value = "
0461: + form);
0462: }
0463: return form;
0464: }
0465:
0466: /**
0467: * Retrieve the client session from the request (if there), or create a new
0468: * client session.
0469: *
0470: * @param request Current servlet request we are processing.
0471: * @param servletContext Current servlet context of the servlet processing
0472: * this action.
0473: * @return Valid client session object.
0474: * @throws MarshallingException Thrown by the client session manager.
0475: */
0476: public ClientSession createClientSession(
0477: final HttpServletRequest request,
0478: final ServletContext servletContext)
0479: throws MarshallingException {
0480: if (logger.isDebugEnabled()) {
0481: logger
0482: .debug("createClientSession(HttpServletRequest request = "
0483: + request
0484: + ", ServletContext servletContext = "
0485: + servletContext + ") - start");
0486: }
0487:
0488: HttpSession session = request.getSession();
0489: ClientSession clientSession = (ClientSession) request
0490: .getAttribute(ClientSessionConstants.CLIENT_SESSION_NAME);
0491: if (clientSession != null) {
0492: // always try to keep the fallback version in the real session up to
0493: // date by setting it each time
0494: session.setAttribute(
0495: ClientSessionConstants.CLIENT_SESSION_NAME,
0496: clientSession);
0497:
0498: if (logger.isDebugEnabled()) {
0499: logger
0500: .debug("createClientSession - end - return value = "
0501: + clientSession);
0502: }
0503: return clientSession;
0504: }
0505: // we will have to unmarshall the client session from the request
0506: // parameter if this has not already been done in this request.
0507: String sessionString = request
0508: .getParameter(ClientSessionConstants.CLIENT_SESSION_NAME);
0509: if (!StringHandling.isNullOrEmpty(sessionString)) {
0510: clientSession = sessionManager.unmarshall(sessionString);
0511: } else {
0512: if (logger.isDebugEnabled()) {
0513: logger
0514: .debug("No client session string found in request "
0515: + "parameter. Resorting to session attribute.");
0516: }
0517: clientSession = (ClientSession) session
0518: .getAttribute(ClientSessionConstants.CLIENT_SESSION_NAME);
0519: if (clientSession == null) {
0520: logger.warn("No client session found at any scope. "
0521: + "Creating new one.");
0522: clientSession = sessionManager.createSession();
0523: }
0524: }
0525: request.setAttribute(
0526: ClientSessionConstants.CLIENT_SESSION_NAME,
0527: clientSession);
0528: session.setAttribute(
0529: ClientSessionConstants.CLIENT_SESSION_NAME,
0530: clientSession);
0531: servletContext.setAttribute(
0532: ClientSessionConstants.SESSION_MANAGER_NAME,
0533: sessionManager);
0534: if ("/shared/mask/find.action".equals(request.getServletPath())) {
0535: clientSession.put("maskForm", null);
0536: clientSession.put("InputMaskForm", null);
0537: }
0538:
0539: if (logger.isDebugEnabled()) {
0540: logger.debug("createClientSession - end - return value = "
0541: + clientSession);
0542: }
0543: return clientSession;
0544: }
0545:
0546: /**
0547: * Used to generate convertors to convert property types from strings.
0548: * @return Returns the FieldValueConvertor factory.
0549: */
0550: public FieldValueConvertorFactory getFieldValueConvertorFactory() {
0551: if (logger.isDebugEnabled()) {
0552: logger.debug("getFieldValueConvertorFactory() - start");
0553: }
0554:
0555: if (logger.isDebugEnabled()) {
0556: logger
0557: .debug("getFieldValueConvertorFactory - end - return value = "
0558: + fieldValueConvertorFactory);
0559: }
0560: return fieldValueConvertorFactory;
0561: }
0562:
0563: /**
0564: * Get the parameter value for a password field. A password field actually
0565: * returns 2 field values - one for the password and another to confirm
0566: * it against. This method checks the two value and reports any error.
0567: *
0568: * @param request Current servlet request we are processing
0569: * @param field Current field we are populating. Used in error reporting.
0570: * @param parameterName Name of the password parameter.
0571: * @param allErrors If the two passwords don't match, an error is added
0572: * here.
0573: * @return Value of the new password, or <code>null</code> if the password
0574: * should not be set.
0575: * @throws ServletException If two values are not found for this password
0576: * and confirm value.
0577: */
0578: private String getPasswordParameter(
0579: final HttpServletRequest request, final Field field,
0580: final String parameterName, final ValidationErrors allErrors)
0581: throws ServletException {
0582: if (logger.isDebugEnabled()) {
0583: logger
0584: .debug("getPasswordParameter(HttpServletRequest request = "
0585: + request
0586: + ", String parameterName = "
0587: + parameterName
0588: + ", ValidationErrors errors = "
0589: + allErrors + ") - start");
0590: }
0591:
0592: String[] values = request.getParameterValues(parameterName);
0593: assert (values != null);
0594: String value;
0595: if (values.length != 2) {
0596: throw new ServletException("Expected 2 values for "
0597: + "password field '" + parameterName
0598: + "'. Received " + values.length + ": " + values);
0599: }
0600: value = values[0];
0601: if (!value.equals(values[1])) {
0602: allErrors.add(new ValidationError(null, field,
0603: "errors.field.passwordConfirm", Arrays
0604: .asList(new Object[] {})));
0605:
0606: if (logger.isDebugEnabled()) {
0607: logger
0608: .debug("getPasswordParameter() - end - return value = "
0609: + null);
0610: }
0611: return null;
0612: }
0613: // consider empty as null - don't set null passwords
0614: if (value == "") {
0615: if (logger.isDebugEnabled()) {
0616: logger
0617: .debug("getPasswordParameter() - end - return value = "
0618: + null);
0619: }
0620: return null;
0621: }
0622:
0623: if (logger.isDebugEnabled()) {
0624: logger
0625: .debug("getPasswordParameter() - end - return value = "
0626: + value);
0627: }
0628: return value;
0629: }
0630:
0631: /**
0632: * Private helper to get the type of a form element, and handle any
0633: * exception.
0634: *
0635: * @param form Form for which to find the type of a property.
0636: * @param parameterName Name of the property in this form.
0637: * @return class of the property, or <code>null</code> if none can be
0638: * found.
0639: * @throws ServletException If there is a technical problem getting the
0640: * type.
0641: */
0642: private Class getPropertyType(final ActionForm form,
0643: final String parameterName) throws ServletException {
0644: if (logger.isDebugEnabled()) {
0645: logger.debug("getPropertyType(ActionForm form = " + form
0646: + ", String parameterName = " + parameterName
0647: + ") - start");
0648: }
0649:
0650: PropertyDescriptor descriptor;
0651: try {
0652: descriptor = PropertyUtils.getPropertyDescriptor(form,
0653: parameterName);
0654: } catch (IllegalAccessException e) {
0655: logger.error(
0656: "setNonFieldProperty - error getting property "
0657: + "descriptor" + parameterName, e);
0658: throw new ServletException(e);
0659: } catch (InvocationTargetException e) {
0660: logger.error(
0661: "setNonFieldProperty - error getting property "
0662: + "descriptor" + parameterName, e);
0663: throw new ServletException(e);
0664: } catch (NoSuchMethodException e) {
0665: logger.error(
0666: "setNonFieldProperty - error getting property "
0667: + "descriptor" + parameterName, e);
0668: // if there is no such method, we can ignore it
0669: descriptor = null;
0670: }
0671: Class type = null;
0672:
0673: if (descriptor != null) {
0674: type = descriptor.getPropertyType();
0675:
0676: // if this is a dyna form, it is still possible to get the type
0677: } else if (form instanceof DynaActionForm) {
0678: DynaActionForm dynaForm = (DynaActionForm) form;
0679: DynaProperty dynaProperty = dynaForm.getDynaClass()
0680: .getDynaProperty(parameterName);
0681: if (dynaProperty != null) {
0682: type = dynaProperty.getType();
0683: }
0684: }
0685:
0686: if (logger.isDebugEnabled()) {
0687: logger.debug("getPropertyType() - end - return value = "
0688: + type);
0689: }
0690: return type;
0691: }
0692:
0693: /**
0694: * Restore a form from the scope it was saved in.
0695: *
0696: * @param request Current servlet request we are processing.
0697: * @param mapping <em>Struts</em> mapping.
0698: * @return The saved form, or <code>null</code> if no saved form is
0699: * available.
0700: */
0701: public ActionForm getSavedForm(final HttpServletRequest request,
0702: final ActionMapping mapping) {
0703: if (logger.isDebugEnabled()) {
0704: logger.debug("getSavedForm(HttpServletRequest request = "
0705: + request + ", ActionMapping mapping = " + mapping
0706: + ") - start");
0707: }
0708:
0709: String scope = mapping.getScope();
0710: String attributeName = mapping.getAttribute();
0711: ActionForm form;
0712: if ("request".equals(scope)) {
0713: form = (ActionForm) request.getAttribute(attributeName);
0714: } else if ("clientSession".equals(scope)) {
0715: ClientSession clientSession = (ClientSession) request
0716: .getAttribute(ClientSessionConstants.CLIENT_SESSION_NAME);
0717: assert (clientSession != null);
0718: form = (ActionForm) clientSession.get(attributeName);
0719: // save the form in the request to make it work with traditional
0720: // tags which don't know about clientSession
0721: if (form != null) {
0722: request.setAttribute(attributeName, form);
0723: }
0724: } else {
0725: form = (ActionForm) request.getSession().getAttribute(
0726: mapping.getAttribute());
0727: }
0728: // don't return a mask form if the class has changed - we need a new
0729: // one in that case
0730: String requestBaseClass = request.getParameter("baseClass");
0731: if (requestBaseClass != null) {
0732: Class currentBaseClass = null;
0733: String currentId = null;
0734: if (form instanceof InputMaskForm) {
0735: InputMaskForm inputMaskForm = (InputMaskForm) form;
0736: currentBaseClass = inputMaskForm.getBaseClass();
0737: ValueObject valueObject = inputMaskForm
0738: .getValueObject();
0739: if (valueObject != null) {
0740: currentId = valueObject.getIdString();
0741: }
0742: } else if (form instanceof ListForm) {
0743: //ListForm listForm = (ListForm) form;
0744: //currentBaseClass = listForm.getBaseClass();
0745: // for now list forms refresh every time
0746: if (logger.isDebugEnabled()) {
0747: logger
0748: .debug("getSavedForm - refreshing list form - end -"
0749: + " return value = " + null);
0750: }
0751: return null;
0752: }
0753: if ((currentBaseClass != null)
0754: && (!requestBaseClass.equals(currentBaseClass
0755: .getName()))) {
0756: if (logger.isDebugEnabled()) {
0757: logger
0758: .debug("getSavedForm - base class changed from '"
0759: + currentBaseClass.getName()
0760: + "' to '"
0761: + requestBaseClass
0762: + "' - end - return value = "
0763: + null);
0764: }
0765: return null;
0766: }
0767: // see if the value object id has changed
0768: String requestId = request
0769: .getParameter("valueObject.idString");
0770: if ((requestId != null) && !requestId.equals(currentId)) {
0771: if (logger.isDebugEnabled()) {
0772: logger.debug("getSavedForm - id changed from '"
0773: + currentId + "' to '" + requestId
0774: + "' - end - return value = " + null);
0775: }
0776: return null;
0777: }
0778: }
0779: if (logger.isDebugEnabled()) {
0780: logger.debug("getSavedForm - using form from attribute"
0781: + " - end - return value = " + form);
0782: }
0783: return form;
0784: }
0785:
0786: /**
0787: * {@inheritDoc}
0788: *
0789: * @param servletParam {@inheritDoc}
0790: * @param moduleConfigParam {@inheritDoc}
0791: * @throws javax.servlet.ServletException {@inheritDoc}
0792: */
0793: public void init(final ActionServlet servletParam,
0794: final ModuleConfig moduleConfigParam)
0795: throws ServletException {
0796: if (logger.isDebugEnabled()) {
0797: logger.debug("init(ActionServlet servletParam = "
0798: + servletParam
0799: + ", ModuleConfig moduleConfigParam = "
0800: + moduleConfigParam + ") - start");
0801: }
0802:
0803: if (logger.isDebugEnabled()) {
0804: logger.debug("init(ActionServlet, ModuleConfig) - end");
0805: }
0806: }
0807:
0808: /**
0809: * <p>
0810: * Overridden to populate forms, and convert the string values of value
0811: * object properties into the correct form for their class.
0812: * </p>
0813: *
0814: * @param request {@inheritDoc}
0815: * @param response {@inheritDoc}
0816: * @param form {@inheritDoc}
0817: * @param mapping {@inheritDoc}
0818: * @exception ServletException {@inheritDoc}
0819: */
0820: protected void processPopulate(final HttpServletRequest request,
0821: final HttpServletResponse response, final ActionForm form,
0822: final ActionMapping mapping) throws ServletException {
0823: if (logger.isDebugEnabled()) {
0824: logger
0825: .debug("processPopulate(HttpServletRequest request = "
0826: + request
0827: + ", HttpServletResponse response = "
0828: + response
0829: + ", ActionForm form = "
0830: + form
0831: + ", ActionMapping mapping = "
0832: + mapping
0833: + ") - start");
0834: }
0835: // if we were told by the mask for not to populate this form, just
0836: // get out
0837: if ("true".equals(request
0838: .getAttribute(MaskAction.STOP_POPULATE_ATTRIBUTE))) {
0839: if (logger.isDebugEnabled()) {
0840: logger.debug("processPopulate - mask action finished "
0841: + "population - end");
0842: }
0843: return;
0844: }
0845:
0846: // if cancel was pressed, don't submit the form
0847: if ((request.getParameter(Constants.CANCEL_PROPERTY) != null)
0848: || (request.getParameter(Constants.CANCEL_PROPERTY_X) != null)) {
0849: request.setAttribute(Globals.CANCEL_KEY, Boolean.TRUE);
0850:
0851: if (logger.isDebugEnabled()) {
0852: logger.debug("processPopulate - end");
0853: }
0854:
0855: if (logger.isDebugEnabled()) {
0856: logger.debug("processPopulate() - end");
0857: }
0858: return;
0859: }
0860: form.reset(mapping, request);
0861: Enumeration parameterNames = request.getParameterNames();
0862: ValidationErrors allErrors = new ValidationErrors();
0863: while (parameterNames.hasMoreElements()) {
0864: String parameterName = (String) parameterNames
0865: .nextElement();
0866: // we're only interested in value object fields
0867: if (!parameterName
0868: .startsWith(FieldValueConvertorConstants.PARAMETER_NAME_PREFIX)) {
0869: setNonFieldProperty(form, parameterName, request);
0870: continue;
0871: }
0872: setFieldProperty(form, parameterName, request, allErrors);
0873: }
0874: if (!allErrors.isEmpty()) {
0875: request
0876: .setAttribute(
0877: FieldValueConvertorConstants.ERROR_REQUEST_ATTRIBUTE,
0878: allErrors);
0879: }
0880:
0881: if (logger.isDebugEnabled()) {
0882: logger.debug("processPopulate - end");
0883: }
0884: }
0885:
0886: /**
0887: * Save a form back to the appropriate scope, after it has been successfully
0888: * processed.
0889: *
0890: * @param request Current servlet request we are processing.
0891: * @param mapping <em>Struts</em> mapping.
0892: * @param form Form to be saved.
0893: */
0894: public void saveForm(final HttpServletRequest request,
0895: final ActionMapping mapping, final ActionForm form) {
0896: if (logger.isDebugEnabled()) {
0897: logger.debug("saveForm(HttpServletRequest request = "
0898: + request + ", ActionMapping mapping = " + mapping
0899: + ", ActionForm form = " + form + ") - start");
0900: }
0901:
0902: String scope = mapping.getScope();
0903: String attributeName = mapping.getAttribute();
0904: if ("request".equals(scope)) {
0905: request.setAttribute(attributeName, form);
0906: } else if ("clientSession".equals(scope)) {
0907: ClientSession clientSession = (ClientSession) request
0908: .getAttribute(ClientSessionConstants.CLIENT_SESSION_NAME);
0909: assert (clientSession != null);
0910: clientSession.put(attributeName, form);
0911: // save the form in the request to make it work with traditional
0912: // tags which don't know about clientSession
0913: if (form != null) {
0914: request.setAttribute(attributeName, form);
0915: }
0916: } else {
0917: request.getSession().setAttribute(attributeName, form);
0918: }
0919:
0920: if (logger.isDebugEnabled()) {
0921: logger.debug("saveForm() - end");
0922: }
0923: }
0924:
0925: /**
0926: * <p>
0927: * Set a target type of <code>Collection.</code>
0928: * </p>
0929: *
0930: * @param request <copyDoc>Refer to {@link #processPopulate}.</copyDoc>
0931: * @param parameterName name of the request parameter which evaluates to
0932: * a collection.
0933: * @param propertyType name of the concrete target class, a subclass of
0934: * <code>Collection</code>.
0935: * @param field field definition for the target.
0936: * @param valueObject value object which contains the collection as a
0937: * property.
0938: * @param allErrors used to store all errors encountered.
0939: * @throws ServletException if the collection cannot be set for any reason.
0940: */
0941: private void setCollection(final HttpServletRequest request,
0942: final String parameterName, final Class propertyType,
0943: final Field field, final ValueObject valueObject,
0944: final ValidationErrors allErrors) throws ServletException {
0945: if (logger.isDebugEnabled()) {
0946: logger.debug("setCollection(HttpServletRequest request = "
0947: + request + ", String parameterName = "
0948: + parameterName + ", Class propertyType = "
0949: + propertyType + ", Field field = " + field
0950: + ", ValueObject valueObject = " + valueObject
0951: + ", ValidationErrors allErrors = " + allErrors
0952: + ") - start");
0953: }
0954:
0955: Collection collection;
0956: try {
0957: collection = (Collection) PropertyUtils.getProperty(
0958: valueObject, field.getName());
0959: } catch (IllegalAccessException e) {
0960: logger.error(
0961: "setCollection - error getting property for field "
0962: + field, e);
0963: throw new ServletException(e);
0964: } catch (InvocationTargetException e) {
0965: logger.error(
0966: "setCollection - error getting property for field "
0967: + field, e);
0968: throw new ServletException(e);
0969: } catch (NoSuchMethodException e) {
0970: logger.error(
0971: "setCollection - error getting property for field "
0972: + field, e);
0973: throw new ServletException(e);
0974: }
0975: Class dOClass = field.getDOClass();
0976: if (dOClass == null) {
0977: throw new NullPointerException(
0978: "ERROR: for collection '"
0979: + field.getName()
0980: + "', you must specify a data object class (attribute 'class' "
0981: + "in the ivata masks config).");
0982: }
0983: collection.clear();
0984: // sublists are handled separately - they store values as XML
0985: if ("sublist".equals(field.getType())) {
0986: setSubList(request, parameterName, propertyType, dOClass,
0987: field, allErrors, collection);
0988: } else {
0989: // if it is not a sublist, it is a standard array of ids
0990: setValueObjectList(request, parameterName, dOClass,
0991: collection);
0992: }
0993:
0994: if (logger.isDebugEnabled()) {
0995: logger.debug("setCollection - end");
0996: }
0997: }
0998:
0999: /**
1000: * <p>
1001: * Use a value convertor to convert and set a single field value.
1002: * </p>
1003: *
1004: * @param value string equivalent of the field's value.
1005: * @param field field definition of the field to be set.
1006: * @param descriptor property descriptor for this field in the value object.
1007: * @param valueObject value object which contains the field as a
1008: * property.
1009: * @param allErrors stores all errors encountered processing the form.
1010: * @throws ServletException Not thrown by this class. Use in subclasses, if
1011: * you cannot set the field value for any reason.
1012: */
1013: private void setField(final String value, final Field field,
1014: final PropertyDescriptor descriptor,
1015: final ValueObject valueObject,
1016: final ValidationErrors allErrors) throws ServletException {
1017: if (logger.isDebugEnabled()) {
1018: logger.debug("setField(String value = " + value
1019: + ", Field field = " + field
1020: + ", PropertyDescriptor descriptor = " + descriptor
1021: + ", ValueObject valueObject = " + valueObject
1022: + ", ValidationErrors allErrors = " + allErrors
1023: + ") - start");
1024: }
1025:
1026: // convert from primitive types to their wrappers
1027: Class type = descriptor.getPropertyType();
1028: if (type.isPrimitive()) {
1029: try {
1030: type = DefaultFieldValueConvertorFactory
1031: .convertPrimitiveType(type);
1032: } catch (SystemException e) {
1033: logger.error(
1034: "setField - error converting primitive type "
1035: + type, e);
1036: throw new ServletException(e);
1037: }
1038: }
1039: FieldValueConvertor convertor;
1040: try {
1041: convertor = fieldValueConvertorFactory
1042: .getFieldValueConvertorForClass(type);
1043: } catch (SystemException e) {
1044: logger.error(
1045: "setField - error getting field value convertor for "
1046: + type, e);
1047: throw new ServletException(e);
1048: }
1049: ValidationErrors theseErrors = convertor.setStringValue(
1050: valueObject, field, value);
1051: if (!theseErrors.isEmpty()) {
1052: allErrors.addAll(theseErrors);
1053: }
1054:
1055: if (logger.isDebugEnabled()) {
1056: logger.debug("setField - end");
1057: }
1058: }
1059:
1060: /**
1061: * Set a property on a form which does represents an <strong>ivata
1062: * masks</strong> field.
1063: *
1064: * @param form form instance we are populating.
1065: * @param parameterName name of the parameter containing the field value.
1066: * @param request servlet request we are processing.
1067: * @param allErrors Any validation errors will be appended to this
1068: * collection.
1069: * @throws ServletException if the field value cannot be set.
1070: */
1071: private void setFieldProperty(final ActionForm form,
1072: final String parameterName,
1073: final HttpServletRequest request,
1074: final ValidationErrors allErrors) throws ServletException {
1075: if (logger.isDebugEnabled()) {
1076: logger.debug("setFieldProperty(ActionForm form = " + form
1077: + ", String parameterName = " + parameterName
1078: + ", HttpServletRequest request = " + request
1079: + ", ValidationErrors allErrors = " + allErrors
1080: + ") - start");
1081: }
1082:
1083: String fieldId = parameterName
1084: .substring(FieldValueConvertorConstants.PARAMETER_NAME_PREFIX
1085: .length());
1086: if (fieldId.length() == 0) {
1087: if (logger.isDebugEnabled()) {
1088: logger.debug("Empty field found for '" + parameterName
1089: + "' on form '" + form + "'");
1090: }
1091: return;
1092: }
1093: PropertyDescriptor descriptor;
1094: try {
1095: descriptor = PropertyUtils.getPropertyDescriptor(form,
1096: parameterName);
1097: } catch (IllegalAccessException e) {
1098: logger.error(
1099: "setFieldProperty - error getting property descriptor "
1100: + "for " + parameterName, e);
1101: throw new ServletException(e);
1102: } catch (InvocationTargetException e) {
1103: logger.error(
1104: "setFieldProperty - error getting property descriptor "
1105: + "for " + parameterName, e);
1106: throw new ServletException(e);
1107: } catch (IllegalArgumentException e) {
1108: logger.error(
1109: "setFieldProperty - error getting property descriptor "
1110: + "for " + parameterName, e);
1111: throw new ServletException(e);
1112: } catch (NoSuchMethodException e) {
1113: if (logger.isDebugEnabled()) {
1114: logger.debug(
1115: "setFieldProperty - no property descriptor "
1116: + "for " + parameterName, e);
1117: }
1118: descriptor = null;
1119: }
1120: if (descriptor == null) {
1121: if (logger.isDebugEnabled()) {
1122: logger.debug("Property descriptor is null for '"
1123: + parameterName + "' on form '" + form + "'");
1124: }
1125: return;
1126: }
1127: InputMaskForm inputMaskForm;
1128: Mask mask;
1129: ValueObject valueObject;
1130: if (form instanceof InputMaskForm) {
1131: inputMaskForm = (InputMaskForm) form;
1132: mask = inputMaskForm.getMask();
1133: valueObject = inputMaskForm.getValueObject();
1134: } else {
1135: if (logger.isDebugEnabled()) {
1136: logger.debug("setFieldProperty - end");
1137: }
1138:
1139: if (logger.isDebugEnabled()) {
1140: logger.debug("setFieldProperty() - end");
1141: }
1142: return;
1143: }
1144: Class propertyType = descriptor.getPropertyType();
1145:
1146: Field field = mask.getField(fieldId);
1147: if (field == null) {
1148: if (logger.isDebugEnabled()) {
1149: logger.debug("(Normally OK): no field found for '"
1150: + parameterName + "' on form '" + form + "'");
1151: }
1152: setNonFieldProperty(form, parameterName, request);
1153:
1154: if (logger.isDebugEnabled()) {
1155: logger.debug("setFieldProperty - end");
1156: }
1157:
1158: if (logger.isDebugEnabled()) {
1159: logger.debug("setFieldProperty() - end");
1160: }
1161: return;
1162: }
1163: // how we set the field value depends on the type of the field
1164: if (Collection.class.isAssignableFrom(propertyType)) {
1165: setCollection(request, parameterName, propertyType, field,
1166: valueObject, allErrors);
1167: // if it is a value object, assign it by id
1168: } else if (ValueObject.class.isAssignableFrom(propertyType)) {
1169: setValueObject(request, valueObject, field, propertyType,
1170: request.getParameter(parameterName));
1171: // otherwise use a specific convertor
1172: } else {
1173: // if this is a password, check the values match
1174: String value;
1175: if (Field.TYPE_PASSWORD.equals(field.getType())) {
1176: value = getPasswordParameter(request, field,
1177: parameterName, allErrors);
1178: if (value == null) {
1179: if (logger.isDebugEnabled()) {
1180: logger
1181: .debug("setFieldProperty() - getPasswordParameter"
1182: + " returned null - end");
1183: }
1184: return;
1185: }
1186: } else {
1187: value = request.getParameter(parameterName);
1188: }
1189: setField(value, field, descriptor, valueObject, allErrors);
1190: }
1191:
1192: if (logger.isDebugEnabled()) {
1193: logger.debug("setFieldProperty - end");
1194: }
1195: }
1196:
1197: /**
1198: * Set a property on a form which does not represent an <strong>ivata
1199: * masks</strong> field. This method uses {@link FieldValueConvertor}
1200: * instances to convert to and from strings.
1201: *
1202: * @param form form instance we are populating.
1203: * @param parameterName name of the parameter containing the field value.
1204: * @param request servlet request we are processing.
1205: * @throws ServletException if the field value cannot be set.
1206: */
1207: private void setNonFieldProperty(final ActionForm form,
1208: final String parameterName, final HttpServletRequest request)
1209: throws ServletException {
1210: if (logger.isDebugEnabled()) {
1211: logger.debug("setNonFieldProperty(ActionForm form = "
1212: + form + ", String parameterName = "
1213: + parameterName + ", HttpServletRequest request = "
1214: + request + ") - start");
1215: }
1216: Class type = getPropertyType(form, parameterName);
1217: // no descriptor? this could be some other kind of dyna form, in which
1218: // case, just try setting the string
1219: if (type == null) {
1220: if (logger.isDebugEnabled()) {
1221: logger
1222: .debug("setNonFieldProperty - (Normally OK): no field "
1223: + "found for '"
1224: + parameterName
1225: + "' on form '" + form + "'");
1226: }
1227: String value = request.getParameter(parameterName);
1228: try {
1229: PropertyUtils.setProperty(form, parameterName, value);
1230: } catch (IllegalArgumentException e) {
1231: logger.error(
1232: "setNonFieldProperty - error setting property '"
1233: + parameterName + "' to '" + value
1234: + "'.", e);
1235: throw e;
1236: } catch (IllegalAccessException e) {
1237: if (logger.isDebugEnabled()) {
1238: logger.debug("(Normally OK): "
1239: + e.getClass().getName()
1240: + " thrown setting property '"
1241: + parameterName + "' on form '" + form
1242: + "'", e);
1243: }
1244: } catch (InvocationTargetException e) {
1245: if (logger.isDebugEnabled()) {
1246: logger.debug("(Normally OK): "
1247: + e.getClass().getName()
1248: + " thrown setting property '"
1249: + parameterName + "' on form '" + form
1250: + "'", e);
1251: }
1252: } catch (NoSuchMethodException e) {
1253: if (logger.isDebugEnabled()) {
1254: logger.debug("(Normally OK): "
1255: + e.getClass().getName()
1256: + " thrown setting property '"
1257: + parameterName + "' on form '" + form
1258: + "'", e);
1259: }
1260: }
1261: if (logger.isDebugEnabled()) {
1262: logger.debug("setNonFieldProperty() - end");
1263: }
1264: return;
1265: }
1266: // if the type is list, but we have specified a single element of an
1267: // array, then assume string handling
1268: if (type.isAssignableFrom(List.class)
1269: && (parameterName.indexOf('[') != -1)) {
1270: type = String.class;
1271: }
1272:
1273: Object value;
1274: // if the descriptor is a string, then set it directly,
1275: // otherwise assume the type has a constructor with a string
1276: // as an argument - this works for things like Boolean, Integer
1277: if (type.isAssignableFrom(String.class)) {
1278: value = request.getParameter(parameterName);
1279: } else if (Object[].class.isAssignableFrom(type)) {
1280: value = request.getParameterValues(parameterName);
1281: } else if (type.isAssignableFrom(List.class)
1282: && (parameterName.indexOf('[') == -1)) {
1283: value = Arrays.asList(request
1284: .getParameterValues(parameterName));
1285: } else {
1286: // get a convertor for this type
1287: FieldValueConvertor convertor;
1288: try {
1289: convertor = fieldValueConvertorFactory
1290: .getFieldValueConvertorForClass(type);
1291: } catch (SystemException e2) {
1292: logger.error(
1293: "setNonFieldProperty - error getting field value "
1294: + "convertor for " + type, e2);
1295: throw new ServletException(e2);
1296: }
1297: if (convertor == null) {
1298: Constructor constructor;
1299: try {
1300: constructor = type
1301: .getConstructor(new Class[] { String.class });
1302: value = constructor
1303: .newInstance(new Object[] { request
1304: .getParameter(parameterName) });
1305: } catch (SecurityException e) {
1306: logger.error(
1307: "setNonFieldProperty - error constructing "
1308: + "new instance of " + type, e);
1309: throw new ServletException(e);
1310: } catch (NoSuchMethodException e) {
1311: logger.error(
1312: "setNonFieldProperty - error constructing "
1313: + "new instance of " + type, e);
1314: if (logger.isDebugEnabled()) {
1315: logger
1316: .debug("No constructor found of type '"
1317: + type.getName()
1318: + "' with a string constructor on form '"
1319: + form + "'");
1320: }
1321: return;
1322: } catch (IllegalArgumentException e) {
1323: logger.error(
1324: "setNonFieldProperty - error constructing "
1325: + "new instance of " + type, e);
1326: throw new ServletException(e);
1327: } catch (InstantiationException e) {
1328: logger.error(
1329: "setNonFieldProperty - error constructing "
1330: + "new instance of " + type, e);
1331: throw new ServletException(e);
1332: } catch (IllegalAccessException e) {
1333: logger.error(
1334: "setNonFieldProperty - error constructing "
1335: + "new instance of " + type, e);
1336: throw new ServletException(e);
1337: } catch (InvocationTargetException e) {
1338: logger.error(
1339: "setNonFieldProperty - error constructing "
1340: + "new instance of " + type, e);
1341: throw new ServletException(e);
1342: }
1343: } else {
1344: value = convertor.convertFromString(type, request
1345: .getParameter(parameterName));
1346: }
1347: }
1348: try {
1349: PropertyUtils.setProperty(form, parameterName, value);
1350: } catch (IllegalAccessException e1) {
1351: logger.error("setNonFieldProperty - error setting '"
1352: + parameterName + "' to '" + value + "'", e1);
1353: throw new ServletException(e1);
1354: } catch (InvocationTargetException e1) {
1355: logger.error("setNonFieldProperty - error setting '"
1356: + parameterName + "' to '" + value + "'", e1);
1357: throw new ServletException(e1);
1358: } catch (NoSuchMethodException e1) {
1359: // this is ok - it means there is no setter
1360: if (logger.isDebugEnabled()) {
1361: logger.debug("(Normally OK): no setter for property' "
1362: + parameterName + "'", e1);
1363: }
1364: }
1365:
1366: if (logger.isDebugEnabled()) {
1367: logger.debug("setNonFieldProperty - end");
1368: }
1369: }
1370:
1371: /**
1372: * <p>
1373: * Set all the elements of a value object sublist.
1374: * </p>
1375: *
1376: * @param requestParam <copyDoc>Refer to {@link #setCollection}.</copyDoc>
1377: * @param parameterNameParam
1378: * <copyDoc>Refer to {@link #setCollection}.</copyDoc>
1379: * @param propertyTypeParam
1380: * <copyDoc>Refer to {@link #setCollection}.</copyDoc>
1381: * @param dOClassParam
1382: * <copyDoc>Refer to {@link #setCollection}.</copyDoc>
1383: * @param fieldParam
1384: * <copyDoc>Refer to {@link #setCollection}.</copyDoc>
1385: * @param allErrorsParam
1386: * <copyDoc>Refer to {@link #setCollection}.</copyDoc>
1387: * @param collectionParam
1388: * <copyDoc>Refer to {@link #setCollection}.</copyDoc>
1389: * @throws ServletException
1390: * <copyDoc>Refer to {@link #setCollection}.</copyDoc>
1391: */
1392: private void setSubList(final HttpServletRequest requestParam,
1393: final String parameterNameParam,
1394: final Class propertyTypeParam, final Class dOClassParam,
1395: final Field fieldParam,
1396: final ValidationErrors allErrorsParam,
1397: final Collection collectionParam) throws ServletException {
1398: if (logger.isDebugEnabled()) {
1399: logger
1400: .debug("setSubList(HttpServletRequest requestParam = "
1401: + requestParam
1402: + ", String parameterNameParam = "
1403: + parameterNameParam
1404: + ", Class propertyTypeParam = "
1405: + propertyTypeParam
1406: + ", Class dOClassParam = "
1407: + dOClassParam
1408: + ", Field fieldParam = "
1409: + fieldParam
1410: + ", ValidationErrors allErrorsParam = "
1411: + allErrorsParam
1412: + ", Collection collectionParam = "
1413: + collectionParam + ") - start");
1414: }
1415:
1416: SAXReader reader = new SAXReader();
1417: Document document;
1418: try {
1419: document = reader.read(new StringReader(requestParam
1420: .getParameter(parameterNameParam)));
1421: } catch (DocumentException e1) {
1422: logger.error(
1423: "setSubList - error reading document from request "
1424: + "parameter '" + parameterNameParam + "'",
1425: e1);
1426: throw new ServletException(e1);
1427: }
1428: Element rootElement = document.getRootElement();
1429: // the root element should be 'sublist'
1430: if (!"sublist".equals(rootElement.getName())) {
1431: throw new ServletException(
1432: "Unexpected root element in sublist." + " Found '"
1433: + rootElement.getName()
1434: + "' , expected 'sublist'.");
1435: }
1436: // go thro' the value objects in the root
1437: for (int i = 0, rootSize = rootElement.nodeCount(); i < rootSize; ++i) {
1438: Node node = rootElement.node(i);
1439: // the root element should only contain value
1440: // objects...
1441: if (!((node instanceof Element) && "valueObject"
1442: .equals(((Element) node).getName()))) {
1443: throw new ServletException(
1444: "Unexpected value object element in sublist. Found '"
1445: + node.asXML()
1446: + "' , expected element called 'valueObject'.");
1447: }
1448: Element dOElement = (Element) node;
1449: String id = dOElement.attributeValue("id");
1450: String schema = dOElement.attributeValue("schema");
1451: // ignore extra value objects just there to give us the schema
1452: if ("true".equals(schema)) {
1453: continue;
1454: }
1455: // if the id is specified, get the value object
1456: // we're changing
1457: ValueObject subObject;
1458: if (!StringHandling.isNullOrEmpty(id)) {
1459: try {
1460: PersistenceSession persistenceSession = persistenceManager
1461: .openSession(requestParam.getSession());
1462: try {
1463: subObject = persistenceManager
1464: .findByPrimaryKey(persistenceSession,
1465: dOClassParam, id);
1466: } finally {
1467: persistenceSession.close();
1468: }
1469: } catch (SystemException e) {
1470: logger.error(
1471: "setSubList - error looking for value object of "
1472: + dOClassParam + ", id " + id, e);
1473: throw new ServletException(e);
1474: }
1475: } else {
1476: // ...otherwise, we're creating a new value object
1477: // TODO: assuming a default constructor exists
1478: // for the time being - might want to create
1479: // an overridable method here...
1480: try {
1481: subObject = (ValueObject) dOClassParam
1482: .getConstructor(null).newInstance(null);
1483: } catch (IllegalArgumentException e) {
1484: logger.error(
1485: "setSubList - error constructing new instance "
1486: + "of " + dOClassParam, e);
1487: throw new ServletException(e);
1488: } catch (SecurityException e) {
1489: logger.error(
1490: "setSubList - error constructing new instance "
1491: + "of " + dOClassParam, e);
1492: throw new ServletException(e);
1493: } catch (InstantiationException e) {
1494: logger.error(
1495: "setSubList - error constructing new instance "
1496: + "of " + dOClassParam, e);
1497: throw new ServletException(e);
1498: } catch (IllegalAccessException e) {
1499: logger.error(
1500: "setSubList - error constructing new instance "
1501: + "of " + dOClassParam, e);
1502: throw new ServletException(e);
1503: } catch (InvocationTargetException e) {
1504: logger.error(
1505: "setSubList - error constructing new instance "
1506: + "of " + dOClassParam, e);
1507: throw new ServletException(e);
1508: } catch (NoSuchMethodException e) {
1509: logger.error(
1510: "setSubList - error constructing new instance "
1511: + "of " + dOClassParam, e);
1512: throw new ServletException(e);
1513: }
1514: }
1515: Mask subMask = fieldParam.getValueObjectMask();
1516: // now go thro' all the fields in the value object
1517: for (int j = 0, dOSize = dOElement.nodeCount(); j < dOSize; ++j) {
1518: setSubListField(requestParam, subMask, subObject,
1519: dOElement.node(j), allErrorsParam);
1520: }
1521: // if the sub object has an id, then update it, otherwise add it
1522: try {
1523: PersistenceSession persistenceSession = persistenceManager
1524: .openSession(requestParam.getSession());
1525: try {
1526: if (StringHandling.isNullOrEmpty(id)) {
1527: subObject = persistenceManager.add(
1528: persistenceSession, subObject);
1529: } else {
1530: persistenceManager.amend(persistenceSession,
1531: subObject);
1532: }
1533: } finally {
1534: persistenceSession.close();
1535: }
1536: } catch (SystemException e) {
1537: logger.error("setSubList - error adding or amending "
1538: + subObject, e);
1539: throw new ServletException(e);
1540: }
1541: collectionParam.add(subObject);
1542: }
1543: if (logger.isDebugEnabled()) {
1544: logger.debug("setSubList - end");
1545: }
1546: }
1547:
1548: /**
1549: * Set the value of a single sublist field, from an XML node.
1550: *
1551: * @param requestParam Current servlet request we are processing.
1552: * @param subMask The Mask of fields for the sub-value object we are
1553: * populating.
1554: * @param subObject The value object we are populating.
1555: * @param node <em>dom4j</em> node containing field data.
1556: * @param allErrorsParam Will be used to append any validation errors to.
1557: * @throws ServletException If the sublist field cannot be set for any
1558: * reason.
1559: */
1560: private void setSubListField(final HttpServletRequest requestParam,
1561: final Mask subMask, final ValueObject subObject,
1562: final Node node, final ValidationErrors allErrorsParam)
1563: throws ServletException {
1564: if (logger.isDebugEnabled()) {
1565: logger
1566: .debug("setSubListField(HttpServletRequest requestParam = "
1567: + requestParam
1568: + ", Mask subMask = "
1569: + subMask
1570: + ", ValueObject subObject = "
1571: + subObject
1572: + ", Node node = "
1573: + node
1574: + ", ValidationErrors allErrorsParam = "
1575: + allErrorsParam + ") - start");
1576: }
1577:
1578: // the value object element should only contain
1579: // fields
1580: if (!((node instanceof Element) && "field"
1581: .equals(((Element) node).getName()))) {
1582: String xML = null;
1583: if (node != null) {
1584: xML = node.asXML();
1585: }
1586: throw new ServletException(
1587: "Unexpected field element in sublist. Found '"
1588: + xML
1589: + "' , expected element called 'field'.");
1590: }
1591: Element fieldElement = (Element) node;
1592: String subFieldId = fieldElement.attributeValue("id");
1593: Field subField = subMask.getField(subFieldId);
1594: PropertyDescriptor subDescriptor;
1595: try {
1596: subDescriptor = PropertyUtils.getPropertyDescriptor(
1597: subObject, subFieldId);
1598: } catch (IllegalAccessException e) {
1599: logger.error("setSubList - error getting descriptor for "
1600: + subObject + "." + subFieldId, e);
1601: throw new ServletException(e);
1602: } catch (InvocationTargetException e) {
1603: logger.error("setSubList - error getting descriptor for "
1604: + subObject + "." + subFieldId, e);
1605: throw new ServletException(e);
1606: } catch (NoSuchMethodException e) {
1607: logger.error("setSubList - error getting descriptor for "
1608: + subObject + "." + subFieldId, e);
1609: throw new ServletException(e);
1610: }
1611: Class subPropertyType = subDescriptor.getPropertyType();
1612: // if it is a value object, assign it by id
1613: if (ValueObject.class.isAssignableFrom(subPropertyType)) {
1614: setValueObject(requestParam, subObject, subField,
1615: subPropertyType, fieldElement.getText());
1616: // otherwise use a specific convertor
1617: } else {
1618: setField(fieldElement.getText(), subField, subDescriptor,
1619: subObject, allErrorsParam);
1620: }
1621:
1622: if (logger.isDebugEnabled()) {
1623: logger.debug("setSubListField() - end");
1624: }
1625: }
1626:
1627: /**
1628: * <p>
1629: * Set an individual value object.
1630: * </p>
1631: *
1632: * @param request Current request we are processing.
1633: * @param valueObject value object containing the value object to be set.
1634: * <b>Note</b> this is the container, not the 'property' value object.
1635: * @param field field definition of this value object.
1636: * @param propertyType class of value object.
1637: * @param id value object unique identifier.
1638: * @throws ServletException if the value object cannot be set for any
1639: * reason.
1640: */
1641: protected void setValueObject(final HttpServletRequest request,
1642: final ValueObject valueObject, final Field field,
1643: final Class propertyType, final String id)
1644: throws ServletException {
1645: if (logger.isDebugEnabled()) {
1646: logger.debug("setValueObject(HttpServletRequest request = "
1647: + request + ", ValueObject valueObject = "
1648: + valueObject + ", Field field = " + field
1649: + ", Class propertyType = " + propertyType
1650: + ", String id = " + id + ") - start");
1651: }
1652:
1653: ValueObject subObject;
1654: if (StringHandling.isNullOrEmpty(id)) {
1655: subObject = null;
1656: } else {
1657: try {
1658: PersistenceSession persistenceSession = persistenceManager
1659: .openSession(request.getSession());
1660: try {
1661: subObject = persistenceManager.findByPrimaryKey(
1662: persistenceSession, propertyType, id);
1663: } finally {
1664: persistenceSession.close();
1665: }
1666: if (subObject == null) {
1667: throw new NullPointerException(
1668: "ERROR: unable to locate sub-value object of class '"
1669: + propertyType + "', with id '"
1670: + id + "'");
1671: }
1672: } catch (SystemException e) {
1673: logger.error("setValueObject - error searching for "
1674: + propertyType + ", id " + id, e);
1675: throw new ServletException(e);
1676: }
1677: }
1678: try {
1679: PropertyUtils.setProperty(valueObject, field.getName(),
1680: subObject);
1681: } catch (IllegalAccessException e) {
1682: logger.error("setValueObject - error setting field "
1683: + field + " to " + subObject, e);
1684: throw new ServletException(e);
1685: } catch (InvocationTargetException e) {
1686: logger.error("setValueObject - error setting field "
1687: + field + " to " + subObject, e);
1688: throw new ServletException(e);
1689: } catch (NoSuchMethodException e) {
1690: logger.error("setValueObject - error setting field "
1691: + field + " to " + subObject, e);
1692: throw new ServletException(e);
1693: }
1694:
1695: if (logger.isDebugEnabled()) {
1696: logger.debug("setValueObject - end");
1697: }
1698: }
1699:
1700: /**
1701: * <p>
1702: * Set a list of value objects, identified by their id values.
1703: * </p>
1704: *
1705: * @param request current servlet request we are processing.
1706: * @param parameterName name of the request parameter which contains the
1707: * value object list details.
1708: * @param dOClass data object class of the value objects in the list.
1709: * @param collection collection to add the value objects to.
1710: * @throws ServletException if the value objects cannot be set for any
1711: * reason.
1712: */
1713: private void setValueObjectList(final HttpServletRequest request,
1714: final String parameterName, final Class dOClass,
1715: final Collection collection) throws ServletException {
1716: if (logger.isDebugEnabled()) {
1717: logger
1718: .debug("setValueObjectList(HttpServletRequest request = "
1719: + request
1720: + ", String parameterName = "
1721: + parameterName
1722: + ", Class dOClass = "
1723: + dOClass
1724: + ", Collection collection = "
1725: + collection + ") - start");
1726: }
1727:
1728: String[] ids = request.getParameterValues(parameterName);
1729: for (int i = 0; i < ids.length; i++) {
1730: if (StringHandling.isNullOrEmpty(ids[i])) {
1731: continue;
1732: }
1733: ValueObject subObject;
1734: try {
1735: PersistenceSession persistenceSession = persistenceManager
1736: .openSession(request.getSession());
1737: try {
1738: subObject = persistenceManager.findByPrimaryKey(
1739: persistenceSession, dOClass, ids[i]);
1740: } finally {
1741: persistenceSession.close();
1742: }
1743: } catch (SystemException e) {
1744: logger.error(
1745: "setValueObjectList - error searching for "
1746: + dOClass + ", id " + ids[i], e);
1747: throw new ServletException(e);
1748: }
1749: if (subObject == null) {
1750: throw new NullPointerException(
1751: "ERROR: unable to locate sub value object of class '"
1752: + dOClass + "', with id '" + ids[i]
1753: + "'");
1754: }
1755: collection.add(subObject);
1756: }
1757:
1758: if (logger.isDebugEnabled()) {
1759: logger.debug("setValueObjectList - end");
1760: }
1761: }
1762: }
|