0001: /* ====================================================================
0002: * The Jcorporate Apache Style Software License, Version 1.2 05-07-2002
0003: *
0004: * Copyright (c) 1995-2002 Jcorporate Ltd. All rights reserved.
0005: *
0006: * Redistribution and use in source and binary forms, with or without
0007: * modification, are permitted provided that the following conditions
0008: * are met:
0009: *
0010: * 1. Redistributions of source code must retain the above copyright
0011: * notice, this list of conditions and the following disclaimer.
0012: *
0013: * 2. Redistributions in binary form must reproduce the above copyright
0014: * notice, this list of conditions and the following disclaimer in
0015: * the documentation and/or other materials provided with the
0016: * distribution.
0017: *
0018: * 3. The end-user documentation included with the redistribution,
0019: * if any, must include the following acknowledgment:
0020: * "This product includes software developed by Jcorporate Ltd.
0021: * (http://www.jcorporate.com/)."
0022: * Alternately, this acknowledgment may appear in the software itself,
0023: * if and wherever such third-party acknowledgments normally appear.
0024: *
0025: * 4. "Jcorporate" and product names such as "Expresso" must
0026: * not be used to endorse or promote products derived from this
0027: * software without prior written permission. For written permission,
0028: * please contact info@jcorporate.com.
0029: *
0030: * 5. Products derived from this software may not be called "Expresso",
0031: * or other Jcorporate product names; nor may "Expresso" or other
0032: * Jcorporate product names appear in their name, without prior
0033: * written permission of Jcorporate Ltd.
0034: *
0035: * 6. No product derived from this software may compete in the same
0036: * market space, i.e. framework, without prior written permission
0037: * of Jcorporate Ltd. For written permission, please contact
0038: * partners@jcorporate.com.
0039: *
0040: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
0041: * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
0042: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
0043: * DISCLAIMED. IN NO EVENT SHALL JCORPORATE LTD OR ITS CONTRIBUTORS
0044: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
0045: * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
0046: * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
0047: * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
0048: * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
0049: * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
0050: * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
0051: * SUCH DAMAGE.
0052: * ====================================================================
0053: *
0054: * This software consists of voluntary contributions made by many
0055: * individuals on behalf of the Jcorporate Ltd. Contributions back
0056: * to the project(s) are encouraged when you make modifications.
0057: * Please send them to support@jcorporate.com. For more information
0058: * on Jcorporate Ltd. and its products, please see
0059: * <http://www.jcorporate.com/>.
0060: *
0061: * Portions of this software are based upon other open source
0062: * products and are subject to their respective licenses.
0063: */
0064: package com.jcorporate.expresso.services.controller.ui;
0065:
0066: import com.jcorporate.expresso.core.ExpressoSchema;
0067: import com.jcorporate.expresso.core.controller.Block;
0068: import com.jcorporate.expresso.core.controller.ControllerException;
0069: import com.jcorporate.expresso.core.controller.ControllerRequest;
0070: import com.jcorporate.expresso.core.controller.ControllerResponse;
0071: import com.jcorporate.expresso.core.controller.ErrorCollection;
0072: import com.jcorporate.expresso.core.controller.Input;
0073: import com.jcorporate.expresso.core.controller.Output;
0074: import com.jcorporate.expresso.core.dataobjects.DataException;
0075: import com.jcorporate.expresso.core.dataobjects.DataField;
0076: import com.jcorporate.expresso.core.dataobjects.DataFieldMetaData;
0077: import com.jcorporate.expresso.core.dataobjects.DataObject;
0078: import com.jcorporate.expresso.core.dataobjects.DataObjectMetaData;
0079: import com.jcorporate.expresso.core.dataobjects.NestableDataObject;
0080: import com.jcorporate.expresso.core.db.DBException;
0081: import com.jcorporate.expresso.core.dbobj.DBObject;
0082: import com.jcorporate.expresso.core.dbobj.SecuredDBObject;
0083: import com.jcorporate.expresso.core.dbobj.ValidValue;
0084: import com.jcorporate.expresso.core.misc.ConfigManager;
0085: import com.jcorporate.expresso.core.misc.DateTime;
0086: import com.jcorporate.expresso.core.misc.Format;
0087: import com.jcorporate.expresso.core.misc.StringUtil;
0088: import com.jcorporate.expresso.kernel.util.FastStringBuffer;
0089: import com.jcorporate.expresso.services.dbobj.MediaDBObject;
0090: import com.jcorporate.expresso.services.dbobj.MimeTypes;
0091: import org.apache.log4j.Logger;
0092:
0093: import java.text.DateFormat;
0094: import java.text.ParseException;
0095: import java.text.SimpleDateFormat;
0096: import java.util.Date;
0097: import java.util.HashMap;
0098: import java.util.Iterator;
0099: import java.util.Locale;
0100: import java.util.Map;
0101: import java.util.Vector;
0102:
0103: /**
0104: * Default implementation of the AutoController Element. Provides a default
0105: * unified method for rendering/parsing Inputs from DBObjects
0106: *
0107: * @author Michael Rimov, portions from Adam Rossi, Michael Nash, Shash
0108: * Chatterjee
0109: * @since Expresso 5.0
0110: */
0111: public class DefaultAutoElement implements AutoControllerElement {
0112: /**
0113: * singleton instance
0114: */
0115: protected static AutoControllerElement theDefault = null;
0116:
0117: /**
0118: *
0119: */
0120: public static final String CLASS_HANDLER_NAME = "AutoControllerElement";
0121:
0122: /**
0123: *
0124: */
0125: public static final String DEFAULT_CLASS_HANDLER = DefaultAutoElement.class
0126: .getName();
0127:
0128: /**
0129: *
0130: */
0131: public static final String DEFAULT_STYLE = "jc-formfield";
0132:
0133: /**
0134: *
0135: */
0136: public static final String REQUIRED_STYLE = "jc-required-field";
0137:
0138: /**
0139: *
0140: */
0141: public static final String ERROR_STYLE = "jc-error-field";
0142:
0143: /**
0144: *
0145: */
0146: protected static Logger log = Logger
0147: .getLogger(DefaultAutoElement.class);
0148:
0149: /**
0150: *
0151: */
0152: public static final String SESSION_KEY = "expresso.services.controller.ui.dbobjList";
0153: private static final String EXPRESSO_SCHEMA = ExpressoSchema.class
0154: .getName();
0155: public static final String DBOBJECT_LABEL = "dbobject";
0156: public static final String BLOCK_TITLE = "block-title";
0157:
0158: /**
0159: * The constructor here is protected. Use getAutoControllerElement()
0160: * instead to get the instance of this class.
0161: */
0162: protected DefaultAutoElement() {
0163: }
0164:
0165: /**
0166: * Constructor. Allows for a classHandler to be used from the
0167: * expresso-config.xml if you really need something completely different.
0168: *
0169: * @return an instantiated AutoControllerElement
0170: * @throws ControllerException upon error
0171: */
0172: public static synchronized AutoControllerElement getAutoControllerElement()
0173: throws ControllerException {
0174: if (theDefault == null) {
0175: String classHandler = ConfigManager
0176: .getClassHandler("AutoControllerElement");
0177:
0178: if (classHandler == null) {
0179: classHandler = DEFAULT_CLASS_HANDLER;
0180: }
0181:
0182: try {
0183: theDefault = (AutoControllerElement) Class.forName(
0184: classHandler).newInstance();
0185: } catch (Exception e) {
0186: log.error("Unable to instantiate controller renderer",
0187: e);
0188: throw new ControllerException(
0189: "Error instantiating controller renderer", e);
0190: }
0191: }
0192:
0193: return theDefault;
0194: }
0195:
0196: /**
0197: * Returns the style to be used if the Input field has an error with it.
0198: *
0199: * @return java.lang.String a Stylesheet class to render to
0200: */
0201: public String getErrorStyle() {
0202: return ERROR_STYLE;
0203: }
0204:
0205: /**
0206: * Returns the style to be used if the input has normal non-required
0207: * characteristics
0208: *
0209: * @return java.lang.String a Stylesheet class to render to
0210: */
0211: public String getNormalStyle() {
0212: return DEFAULT_STYLE;
0213: }
0214:
0215: /**
0216: * Returns the string to append to a field label if it is required.
0217: * Default is an ""
0218: *
0219: * @return java.lang.String a Stylesheet class to render to
0220: */
0221: public String getRequiredDecorator() {
0222: return "*";
0223: }
0224:
0225: /**
0226: * Returns the style to be used if the Input is required
0227: *
0228: * @return java.lang.String a Stylesheet class to render to
0229: */
0230: public String getRequiredStyle() {
0231: return REQUIRED_STYLE;
0232: }
0233:
0234: /**
0235: * Creates a DBObject Block that contains all the non-secret fields for the
0236: * DBObject. The Block will have a nested Output that matches DBObject's
0237: * description unless one is not supplied in which case the nested Output
0238: * will have the title "Untitled"
0239: *
0240: * @param response The ControllerResponse object
0241: * @param request The ControllerRequest Object
0242: * @param dbobj The dbObject to automatically render.
0243: * @return a rendered block
0244: * @throws ControllerException if there's an error rendering the DBObject
0245: */
0246: public Block createDBObjectBlock(ControllerRequest request,
0247: ControllerResponse response, DataObject dbobj)
0248: throws ControllerException {
0249: return createDBObjectBlock(request, response, dbobj
0250: .getMetaData().getDescription(request.getLocale()),
0251: dbobj);
0252: }
0253:
0254: /**
0255: * Creates a DBObject Block that contains all the non-secret fields for the
0256: * DBObject.
0257: *
0258: * @param response The ControllerResponse object
0259: * @param request The ControllerRequest Object
0260: * @param title The title to give this block. The system renders a nested
0261: * Output called "block-title" for the block that contains this
0262: * data.
0263: * @param dbobj The dbObject to automatically render.
0264: * @return a rendered Block object
0265: * @throws ControllerException if there's an error rendering the DBObject
0266: */
0267: public Block createDBObjectBlock(ControllerRequest request,
0268: ControllerResponse response, String title, DataObject dbobj)
0269: throws ControllerException {
0270: Block b = new Block(DBOBJECT_LABEL);
0271: b.add(new Output(BLOCK_TITLE, title));
0272:
0273: Map map = (Map) request.getSession().getAttribute(SESSION_KEY);
0274: DataObject dbobj2 = dbobj;
0275:
0276: if (map != null) {
0277: DBObject temp = (DBObject) map.get(dbobj.getClass()
0278: .getName());
0279:
0280: if (temp != null) {
0281: dbobj2 = temp;
0282: }
0283: }
0284:
0285: request.getSession().removeAttribute(SESSION_KEY);
0286:
0287: try {
0288: String oneFieldName = null;
0289: DataObjectMetaData objMetaData = dbobj2.getMetaData();
0290:
0291: for (Iterator e = objMetaData.getFieldListArray()
0292: .iterator(); e.hasNext();) {
0293: oneFieldName = (String) e.next();
0294:
0295: if (!objMetaData.isSecret(oneFieldName)) {
0296: Input i = renderDBObjectField(response, dbobj2,
0297: oneFieldName,
0298: dbobj2.getField(oneFieldName), false);
0299: if (i != null) {
0300: b.add(i);
0301: }
0302:
0303: // provide hook for subclass to reset value to what user typed in
0304: retrieveCachedValueInForm(response, oneFieldName, i);
0305: }
0306:
0307: }
0308: /* for each field */
0309:
0310: return b;
0311: } catch (DBException de) {
0312: throw new ControllerException(de);
0313: }
0314: }
0315:
0316: /**
0317: * Used to set values in created db objects to the values found (if any)
0318: * in the form cache. (the form cache is what people type into an HTML form,
0319: * and if there is an error, we cache those values in order to send back the
0320: * form (with error message) and have their typing preserved for the next try.)
0321: *
0322: * @param response ?
0323: * @param oneFieldName ?
0324: * @param i The Input to retrieve.
0325: * @see CacheAutoElement
0326: */
0327: protected void retrieveCachedValueInForm(
0328: ControllerResponse response, String oneFieldName, Input i)
0329: throws ControllerException {
0330: }
0331:
0332: /**
0333: * Convienence method if you only expect one DBObject to be returned from a
0334: * particular form.
0335: *
0336: * @param request The ControllerRequest object handed down by the framework
0337: * @param oneObject a single dbobject ro dumpt the parsed values into.
0338: * @param ec An instantiated ErrorCollection that is filled in with any
0339: * error
0340: * @return a filled out DBObject
0341: * @throws ControllerException if there's an error parsing the block or
0342: * communicating with the underlying DBObject
0343: */
0344: public DataObject parseBlock(ControllerRequest request,
0345: DataObject oneObject, ErrorCollection ec)
0346: throws ControllerException {
0347: DataObject[] objs = parseBlocks(request,
0348: new DataObject[] { oneObject }, ec);
0349:
0350: if ((objs == null) || (objs.length == 0)) {
0351: return null;
0352: } else {
0353: return objs[0];
0354: }
0355: }
0356:
0357: /**
0358: * Parses the appropriate DBObject from the block. Returns the fully
0359: * constructed DBOBject including any errors in the DBObject
0360: *
0361: * @param request The ControllerRequest object handed down by the framework
0362: * @param theObjects A pre-instantiated group of DBObjects in which you
0363: * expect to have the fields overwritten/filled. By using
0364: * instantiated DBObjects, you can pre-fill any potentially blank
0365: * fields and thus remove any Errors.
0366: * @param ec An instantiated ErrorCollection that is filled in with any
0367: * error
0368: * @return An array of parsed DBObjects
0369: * @throws ControllerException if there's an error parsing the block or
0370: * communicating with the underlying DBObject
0371: * @throws IllegalArgumentException if request, theObjects, or ec is null
0372: */
0373: public DataObject[] parseBlocks(ControllerRequest request,
0374: DataObject[] theObjects, ErrorCollection ec)
0375: throws ControllerException {
0376: if (request == null) {
0377: throw new IllegalArgumentException(
0378: "parseBlocks - request cannot be null");
0379: }
0380:
0381: if (ec == null) {
0382: throw new IllegalArgumentException(
0383: "parseBlocks - ec cannot be null");
0384: }
0385:
0386: if (theObjects == null) {
0387: throw new IllegalArgumentException(
0388: "parseBlocks - theObjects cannot be null");
0389: }
0390:
0391: String[] dbobjPrefixes = new String[theObjects.length];
0392:
0393: //First construct the DBObjects
0394: for (int i = 0; i < theObjects.length; i++) {
0395: dbobjPrefixes[i] = theObjects[i].getClass().getName() + ".";
0396: }
0397:
0398: for (int i = 0; i < theObjects.length; i++) {
0399: DataObject oneObject = theObjects[i];
0400:
0401: //
0402: //We have to guard against checkboxes because if they are left blank,
0403: //their value is simply not submitted.
0404: //
0405: try {
0406: for (Iterator it = oneObject.getMetaData()
0407: .getFieldListArray().iterator(); it.hasNext();) {
0408: String fieldName = (String) it.next();
0409: DataFieldMetaData metadata = oneObject
0410: .getFieldMetaData(fieldName);
0411:
0412: if (metadata.getAttribute("checkbox") != null) {
0413: DataField dataField = oneObject
0414: .getDataField(fieldName);
0415:
0416: if (dataField.getFieldMetaData()
0417: .isBooleanType()) {
0418: oneObject
0419: .set(fieldName, new Boolean(false));
0420: } else {
0421: oneObject.set(fieldName, "N");
0422: }
0423: }
0424: }
0425: } catch (DBException ex) {
0426: log.error("Error checking boolean fields", ex);
0427: }
0428: }
0429:
0430: //
0431: //Now iterate through all the parameters to find matching parameter
0432: //patterns and load them into the appropriate DBObject by calling
0433: //parseSingleInput for each matching paramter.
0434: //
0435: for (Iterator e = request.getParameters().keySet().iterator(); e
0436: .hasNext();) {
0437: String oneParameterName = (String) e.next();
0438:
0439: for (int i = 0; i < dbobjPrefixes.length; i++) {
0440: if (oneParameterName.startsWith(dbobjPrefixes[i])
0441: && (oneParameterName.length() > dbobjPrefixes[i]
0442: .length())) {
0443: String fieldName = oneParameterName
0444: .substring(dbobjPrefixes[i].length());
0445:
0446: // String oneParameter = request.getParameter(oneParameterName);
0447: parseSingleInput(request, theObjects[i], fieldName,
0448: oneParameterName, ec);
0449: }
0450: }
0451: }
0452:
0453: //
0454: //Ok, we successfully parsed things without bombing, now save that parsed
0455: //entity onto the Session so that we can grab it for rendering
0456: //
0457: Map dbobjList = (Map) request.getSession()
0458: .getPersistentAttribute(SESSION_KEY);
0459:
0460: if (dbobjList == null) {
0461: dbobjList = new HashMap(theObjects.length);
0462: }
0463:
0464: for (int i = 0; i < theObjects.length; i++) {
0465: //Now we make sure that there are no blank fields floating around
0466: //that are required.
0467: try {
0468: theObjects[i].setFieldsWithDefaults();
0469: } catch (DataException ex1) {
0470: ec.addError(ex1.getMessage());
0471: continue;
0472: }
0473:
0474: for (Iterator it = theObjects[i].getMetaData()
0475: .getFieldListArray().iterator(); it.hasNext();) {
0476: String fieldName = (String) it.next();
0477:
0478: try {
0479: String fieldValue = theObjects[i]
0480: .getField(fieldName);
0481:
0482: if ((fieldValue == null)
0483: || (fieldValue.length() == 0)) {
0484: theObjects[i].checkField(fieldName, fieldValue);
0485: }
0486: } catch (DBException dbe) {
0487: ec.addError(dbe.getMessage());
0488: }
0489: }
0490:
0491: dbobjList.put(theObjects[i].getClass().getName(),
0492: theObjects[i]);
0493: }
0494:
0495: //WE don't need session, just request scope.
0496: request.getSession().setAttribute(SESSION_KEY, dbobjList);
0497:
0498: return theObjects;
0499: }
0500:
0501: /**
0502: * Parses a dbobject
0503: *
0504: * @param request The ControllerRequest that contains all the parameters
0505: * for parsing.
0506: * @param oneObject The DBObject to populate.
0507: * @param ec An error Collection to send in for any parsing errors to be
0508: * saved to.
0509: * @param validate Set to true if you want the DBObject validated.
0510: * Sometimes, like for the DBMaint search form, this is not a
0511: * desired feature.
0512: * @return The parsed DBObject [Although oneObject gets populated since no
0513: * assignment takes place.] So you can ignore this return value
0514: * if you desire.
0515: * @throws IllegalArgumentException upon data exception.
0516: * @throws ControllerException upon controller-related error.
0517: */
0518: public DataObject parseDBObject(ControllerRequest request,
0519: DataObject oneObject, ErrorCollection ec, boolean validate)
0520: throws ControllerException {
0521: if (request == null) {
0522: throw new IllegalArgumentException(
0523: "parseBlocks - request cannot be null");
0524: }
0525:
0526: if (ec == null) {
0527: throw new IllegalArgumentException(
0528: "parseBlocks - ec cannot be null");
0529: }
0530:
0531: if (oneObject == null) {
0532: throw new IllegalArgumentException(
0533: "parseBlocks - theObjects cannot be null");
0534: }
0535:
0536: //
0537: //We have to guard against checkboxes because if they are left blank,
0538: //their value is simply not submitted.
0539: //
0540: try {
0541: for (Iterator it = oneObject.getMetaData()
0542: .getFieldListArray().iterator(); it.hasNext();) {
0543: String fieldName = (String) it.next();
0544: DataFieldMetaData metadata = oneObject
0545: .getFieldMetaData(fieldName);
0546:
0547: if (metadata.getAttribute("checkbox") != null) {
0548: DataField dataField = oneObject
0549: .getDataField(fieldName);
0550:
0551: if (dataField.getFieldMetaData().isBooleanType()) {
0552: oneObject.set(fieldName, new Boolean(false));
0553: } else {
0554: oneObject.set(fieldName, "N");
0555: }
0556: }
0557: }
0558: } catch (DBException ex) {
0559: log.error("Error checking boolean fields", ex);
0560: }
0561:
0562: //
0563: //Now iterate through all the parameters to find matching parameter
0564: //patterns and load them into the appropriate DBObject by calling
0565: //parseSingleInput for each matching paramter.
0566: //
0567: for (Iterator i = oneObject.getMetaData().getFieldListArray()
0568: .iterator(); i.hasNext();) {
0569: String oneFieldName = (String) i.next();
0570: String oneParameterValue = request
0571: .getParameter(oneFieldName);
0572:
0573: if (oneParameterValue != null) {
0574: parseSingleInput(request, oneObject, oneFieldName,
0575: null, ec);
0576: }
0577: }
0578:
0579: if (validate) {
0580: for (Iterator it = oneObject.getMetaData()
0581: .getFieldListArray().iterator(); it.hasNext();) {
0582: String fieldName = (String) it.next();
0583:
0584: try {
0585: String fieldValue = oneObject.getField(fieldName);
0586:
0587: if (((fieldValue == null) || (fieldValue.length() == 0))
0588: && !oneObject.getFieldMetaData(fieldName)
0589: .isReadOnly()) {
0590: oneObject.checkField(fieldName, fieldValue);
0591: }
0592: } catch (DBException dbe) {
0593: ec.addError(dbe.getMessage());
0594: }
0595: }
0596: }
0597:
0598: //
0599: //Ok, we successfully parsed things without bombing, now save that parsed
0600: //entity onto the Request so that we can grab it for rendering
0601: // NOTE: this is the REQUEST SCOPE, not session scope
0602: //
0603: Map dbobjList = (Map) request.getSession().getAttribute(
0604: SESSION_KEY);
0605:
0606: if (dbobjList == null) {
0607: dbobjList = new HashMap(1);
0608: }
0609:
0610: dbobjList.put(oneObject.getClass().getName(), oneObject);
0611:
0612: request.getSession().setAttribute(SESSION_KEY, dbobjList);
0613:
0614: return oneObject;
0615: }
0616:
0617: /**
0618: * Convienence method if you only expect one DBObject to be returned from a
0619: * particular form, and unlike the ParseBlock, there is no DBOBject name
0620: * prefix attached to the parameter names. This is similar to the
0621: * ControllerRequest validateDBObject functionality, but we're
0622: * consolodating things here.
0623: *
0624: * @param request The ControllerRequest object handed down by the framework
0625: * @param oneObject A DBObject to fill in.
0626: * @param ec An instantiated ErrorCollection that is filled in with any
0627: * error
0628: * @return a parsed DBObject
0629: * @throws ControllerException if there's an error parsing the block or
0630: * communicating with the underlying DBObject
0631: */
0632: public DataObject parseDBObject(ControllerRequest request,
0633: DataObject oneObject, ErrorCollection ec)
0634: throws ControllerException {
0635: return parseDBObject(request, oneObject, ec, true);
0636: }
0637:
0638: /**
0639: * Takes the Controller Request and appropriately parses a string for a
0640: * particular field. If the field is a Date, then it parses it as such,
0641: * if it is money, then it perses it as such. Etc.
0642: * <h4>
0643: * <p/>
0644: * <p/>
0645: * As of Expresso 5.1, the system properly parses multi-part request data.
0646: * If a parameter is a file parameter, then it sets the following field
0647: * attributes that can be retrieved by:<br/
0648: * ><code> DataObject.getFieldData(fieldName).getAttribute(attribName);
0649: * </code>
0650: * </p>
0651: * <p/>
0652: * <p/>
0653: * <p/>
0654: * <ul>
0655: * <li>
0656: * Attribute: fileName - The locally accessible file name to be used for
0657: * most likely saving to the database. Use <code>new
0658: * File(fileName)</code> to actually access the uploaded file
0659: * </li>
0660: * <li>
0661: * Attribute: origFileName - The original file name (without path) that was
0662: * uploaded to the server through the web browser. This will be different
0663: * from the attribute fileName since Expresso will rename the local file
0664: * name to prevent naming collisions
0665: * </li>
0666: * <li>
0667: * Attribute: MimeType - The system will make a guess as to the mime type
0668: * of the file that was uploaded based upon the file name.
0669: * </li>
0670: * </ul>
0671: * </p>
0672: * <p/>
0673: * <p/>
0674: * Finally, if the target dbobj is of type MediaDBObject the fields:
0675: * 'fieldName + "_mimeType"' and 'fieldName +
0676: * "_fileName"' will be set with the corresponding mimeType and
0677: * origFileName values
0678: * </p>
0679: *
0680: * @param request The ControllerRequest object
0681: * @param dbobj The DBObject for which we're going to put the field to
0682: * @param fieldName The name of the field to parse
0683: * @param parameterName The name of the http paramter to parse May be null
0684: * in which case, the funciton will by default use the fieldName as
0685: * the parameter name.
0686: * @param ec An instantiated ErrorCollection object that will be filled
0687: * with any parsing errors that may be encountered.
0688: * @return java.lang.String for the value.
0689: * @throws ControllerException upon parsing error
0690: * @since Expresso 5.0; Multipart Request Handling since Expresso 5.1
0691: */
0692: public String parseSingleInput(ControllerRequest request,
0693: DataObject dbobj, String fieldName, String parameterName,
0694: ErrorCollection ec) throws ControllerException {
0695: DataFieldMetaData metaData = dbobj.getFieldMetaData(fieldName);
0696: Locale currentLocale = request.getLocale();
0697:
0698: if (parameterName == null) {
0699: parameterName = fieldName;
0700: }
0701:
0702: String oneParameter = request.getParameter(parameterName);
0703:
0704: if (oneParameter == null) {
0705: ec.addError("Missing field: " + fieldName);
0706:
0707: return null;
0708: }
0709:
0710: //
0711: //Check for multipart request handling.
0712: //
0713: if (request.isFileParameter(fieldName)) {
0714: try {
0715: String fileName = request.getFileName(fieldName);
0716: String param = request.getParameter(fieldName);
0717: dbobj.getDataField(fieldName).setAttribute("fileName",
0718: fileName);
0719:
0720: String origFileName = null;
0721: String mimeType = null;
0722:
0723: if (param != null) {
0724: origFileName = getOriginalFileName(param);
0725: dbobj.getDataField(fieldName).setAttribute(
0726: "origFileName", origFileName);
0727: mimeType = MimeTypes.getMimeType(fileName,
0728: request.getDataContext()).getField(
0729: MimeTypes.FLD_MIMENUMBER);
0730:
0731: // mimeType = MimeTypes.getFileMap(request.getDataContext())
0732: // .getContentType(origFileName);
0733: dbobj.getDataField(fieldName).setAttribute(
0734: "mimeType", mimeType);
0735: }
0736:
0737: if (dbobj instanceof MediaDBObject) {
0738: MediaDBObject mediaObject = (MediaDBObject) dbobj;
0739: mediaObject.setField(fieldName + "_mimeType",
0740: mimeType);
0741: mediaObject.setField(fieldName + "_fileName",
0742: origFileName);
0743: }
0744:
0745: return param;
0746: } catch (DBException ex) {
0747: log.warn("Validation error for field:", ex);
0748: ec.addError(ex.getMessage());
0749:
0750: return null;
0751: }
0752: }
0753:
0754: if (!metaData.isVirtual() && !metaData.isBinaryObjectType()) {
0755: try {
0756: //
0757: //If we have date, or time let's try to parse it.
0758: //
0759: if (metaData.isDateOnlyType()) {
0760: try {
0761: DateFormat df = DateFormat.getDateInstance(
0762: DateFormat.SHORT, currentLocale);
0763: df.setLenient(true);
0764:
0765: Date dt = df.parse(oneParameter);
0766: dbobj.set(fieldName, DateTime.getDateForDB(dt,
0767: request.getDataContext()));
0768:
0769: // dbobj.setField(fieldName, DateTime.getDateForDB(dt,request.getDBName()));
0770: } catch (ParseException ex) {
0771: //We try to set the field anyway, since all those > 1988-10-1
0772: //type of queries need to be allowed through.
0773: dbobj.set(fieldName, oneParameter);
0774:
0775: // dbobj.setField(fieldName, oneParameter);
0776: }
0777: } else if (metaData.isTimeType()) {
0778: try {
0779: DateFormat df = DateFormat.getTimeInstance(
0780: DateFormat.SHORT, currentLocale);
0781: df.setLenient(true);
0782:
0783: Date dt = df.parse(oneParameter);
0784: dbobj.set(fieldName, DateTime.getTimeForDB(dt,
0785: request.getDataContext()));
0786:
0787: // dbobj.setField(fieldName, DateTime.getTimeForDB(dt,request.getDBName()));
0788: } catch (ParseException ex) {
0789: dbobj.set(fieldName, oneParameter);
0790:
0791: // dbobj.setField(fieldName, oneParameter);
0792: }
0793: } else if (metaData.isDateTimeType()) {
0794: try {
0795: DateFormat df = DateFormat.getDateTimeInstance(
0796: DateFormat.SHORT, DateFormat.SHORT,
0797: currentLocale);
0798: df.setLenient(true);
0799:
0800: Date dt = df.parse(oneParameter);
0801: dbobj.set(fieldName, DateTime.getDateTimeForDB(
0802: dt, request.getDataContext()));
0803:
0804: // dbobj.setField(fieldName, DateTime.getDateTimeForDB(dt,request.getDBName()));
0805: } catch (ParseException ex) {
0806: dbobj.set(fieldName, oneParameter);
0807: }
0808: } else if (metaData.isNumericType()) {
0809: /*
0810: Numeric fields are a bit special, because DBObject.getFieldInt()
0811: will return zero if the field is null, and will throw an exception
0812: for "". getFieldInt() javadoc tells people to check
0813: DBObject.isFieldNull() for a numeric field to know whether the zero
0814: is real or not.
0815:
0816: DBObject.isFieldNull() will NOT return true after the empty string
0817: is put into a field.
0818:
0819: */
0820:
0821: if (oneParameter != null
0822: && oneParameter.length() == 0) {
0823: dbobj.set(fieldName, null);
0824: } else {
0825: dbobj.set(fieldName, oneParameter);
0826: }
0827:
0828: } else {
0829: // String lookupObject = metaData.getLookupObject();
0830: // String lookupField = metaData.getLookupField();
0831:
0832: // if (lookupObject != null && lookupObject.length() > 0 && isMappable(lookupObject)) {
0833: // oneParameter = parseLookupValue(ec,dbobj,oneParameter,fieldName);
0834: // }
0835: dbobj.set(fieldName, oneParameter);
0836: }
0837: } catch (DBException de) {
0838: if (log.isInfoEnabled()) {
0839: log.info("Validation error for field:", de);
0840: }
0841:
0842: ec.addError(de.getMessage());
0843: }
0844: }
0845:
0846: return null;
0847: }
0848:
0849: /**
0850: * Renders a DBOBject Field as either an Input or an Output. For example,
0851: * if we're talking updating, then all key fields are outputs and not
0852: * inputs. This function auto-detects whether we are dealing with a add()
0853: * or update() situation by checking the DBObject's status. If it's NEW,
0854: * then we treat this as an add form, if it is
0855: *
0856: * @param response The ControllerResponse object
0857: * @param dbobj The parameter to render
0858: * @param fieldName The name of the field to render
0859: * @param cachedValue Any cached form value to put in the field.
0860: * @param readOnly - If set to true, then this is automatically a read-only
0861: * field... if set to false, this function might still render the
0862: * field as read-only if, for example, it's a key field.
0863: * @return a created Input
0864: * @throws ControllerException if there's an error creating the Input Field
0865: */
0866: public Input renderDBObjectField(ControllerResponse response,
0867: DataObject dbobj, String fieldName, String cachedValue,
0868: boolean readOnly) throws ControllerException {
0869: DataFieldMetaData metaData = dbobj.getFieldMetaData(fieldName);
0870: DataObjectMetaData objMetadata = dbobj.getMetaData();
0871:
0872: if (log.isDebugEnabled()) {
0873: FastStringBuffer logMsg = FastStringBuffer.getInstance();
0874: logMsg
0875: .append("entering renderDBObjectField. Parameters: \n\tdbobj=");
0876: logMsg.append(dbobj.getClass().getName());
0877: logMsg.append("\n\tfieldName=");
0878: logMsg.append(fieldName);
0879: logMsg.append("\n\tdefaultValue=");
0880: logMsg.append(cachedValue);
0881: logMsg.append("\n\treadOnly=");
0882: logMsg.append(readOnly);
0883: log.debug(logMsg.toString());
0884: logMsg.release();
0885: }
0886:
0887: try {
0888: StringUtil.assertNotBlank(fieldName,
0889: "Field Name must not be null");
0890:
0891: if (dbobj == null) {
0892: throw new DBException("Database object must be "
0893: + "initialized before calling autoField");
0894: }
0895:
0896: if (metaData.isVirtual()) {
0897: return null;
0898: }
0899:
0900: String oneFieldValue = dbobj.getField(fieldName);
0901:
0902: /// String oneFieldSize = Integer.toString(metaData.getLengthInt());
0903: if (oneFieldValue == null) {
0904: oneFieldValue = ("");
0905: }
0906:
0907: // if (oneFieldSize.equals("0")) {
0908: // oneFieldSize = ("30");
0909: // }
0910: int fieldSize = metaData.getLengthInt();
0911: fieldSize = fieldSize + 2;
0912:
0913: /* Make the longest display field size 60 characters */
0914: int displayFieldSize = fieldSize;
0915:
0916: //
0917: //Numeric fields are too small since integers which may, in text
0918: //take at least 6 characters are listed as only 2 byte in size via
0919: //the database information
0920: //
0921: if (displayFieldSize > 60) {
0922: displayFieldSize = 60;
0923: }
0924:
0925: //Since most numeric values of some sort have a specific
0926: //size we want the field. Then we check against the various
0927: //data types and set the field appropriately.
0928: if (displayFieldSize < 10) {
0929: if (metaData.isNumericType()) {
0930: displayFieldSize = 15;
0931: } else if (metaData.isDateTimeType()) {
0932: displayFieldSize = 30;
0933: } else if (metaData.isDateOnlyType()) {
0934: displayFieldSize = 15;
0935: } else if (metaData.isTimeType()) {
0936: displayFieldSize = 15;
0937: } else {
0938: displayFieldSize = 10;
0939: }
0940: }
0941:
0942: Input oneField = new Input(fieldName);
0943: oneField.setDisplayLength(displayFieldSize);
0944:
0945: if (fieldSize > displayFieldSize) {
0946: oneField.setMaxLength(fieldSize);
0947: } else {
0948: oneField.setMaxLength(displayFieldSize + 2);
0949: }
0950:
0951: if ((cachedValue != null) && (cachedValue.length() > 0)) {
0952: oneFieldValue = cachedValue;
0953: }
0954:
0955: // String lookupObject = metaData.getLookupObject();
0956: // String lookupField = metaData.getLookupField();
0957:
0958: //
0959: //If we have a lookup class and field, then we change the field value
0960: //to that returned by renderLookupValue
0961: //
0962: // if (lookupObject != null && lookupObject.length() > 0 && isMappable(lookupObject)
0963: // && cachedValue == null) {
0964: // oneFieldValue = renderLookupValue(dbobj,oneFieldValue
0965: // ,fieldName,oneField);
0966: // } else {
0967: oneField.setAttribute(Input.ATTRIBUTE_TYPE, metaData
0968: .getTypeString());
0969:
0970: // }
0971: Iterator dbAttribs = metaData.getAttributesIterator();
0972:
0973: if (dbAttribs != null) {
0974: String oneAttrib = null;
0975: Object oneAttribValue = null;
0976:
0977: while (dbAttribs.hasNext()) {
0978: oneAttrib = (String) dbAttribs.next();
0979: oneAttribValue = metaData.getAttribute(oneAttrib);
0980:
0981: if (oneAttribValue != null) {
0982: oneField.setAttribute(oneAttrib, oneAttribValue
0983: .toString());
0984: }
0985: }
0986: }
0987:
0988: // Get the localized description, including any date pattern
0989: {
0990: String description;
0991:
0992: // We could also convert request to HttpServletRequest and get locale from user pref.
0993: // I do not think it would be a problem, but I'm not sure this is not used in a
0994: // non-web environment.
0995: Locale locale = response.getLocale();
0996:
0997: //
0998: // Get the non-localized value to do our own message bundle lookup in order to cascade
0999: // the message bundle from the schema bundle if specified. Then lookup in the expresso
1000: // bundle. If this is not what is wanted, then a simple call could sufice as follows:
1001: //
1002: // description = objMetadata.getDescription(locale, fieldName);
1003: //
1004: // --- David Lloyd
1005: //
1006: Object[] args = {};
1007: String stringCode = objMetadata
1008: .getDescription(fieldName);
1009:
1010: try {
1011: description = com.jcorporate.expresso.core.i18n.Messages
1012: .getString(objMetadata.getSchema(), locale,
1013: stringCode, args);
1014: } catch (IllegalArgumentException iae) {
1015: if (log.isDebugEnabled()) {
1016: log.debug("DefaultAutoElement: Key ["
1017: + stringCode + "] not found in "
1018: + objMetadata.getSchema());
1019: }
1020:
1021: description = null;
1022:
1023: if (!objMetadata.getSchema()
1024: .equals(EXPRESSO_SCHEMA)) {
1025: try {
1026: description = com.jcorporate.expresso.core.i18n.Messages
1027: .getString(EXPRESSO_SCHEMA, locale,
1028: stringCode, args);
1029: } catch (IllegalArgumentException e) {
1030: description = null;
1031: }
1032: }
1033: }
1034:
1035: if ((description == null)
1036: || (description.length() == 0)) {
1037: description = stringCode;
1038: }
1039:
1040: //
1041: // END OF description lookup
1042: //
1043: if (metaData.isDateType() && !metaData.isReadOnly()) {
1044: // try to show 'A Date (MM/dd/yyyy)'
1045: String pattern = DateTime.getDateFormatString(
1046: metaData.isDateOnlyType(), locale);
1047:
1048: if (pattern.length() > 0) {
1049: pattern = " (" + pattern + ")";
1050: }
1051:
1052: oneField.setLabel(description + pattern);
1053: } else {
1054: oneField.setLabel(description);
1055: }
1056: }
1057:
1058: String dbobjStatus = dbobj.getStatus();
1059:
1060: /* If the field is explicitly set to read only, then only offer */
1061: /* input to it in search mode */
1062: /* Except virtual fields, which never get input... */
1063: /* And finally also when it isn't a new record and the field name */
1064: /* is a key field */
1065: if (metaData.isReadOnly()) {
1066: readOnly = true;
1067: } else if (metaData.isVirtual()) {
1068: readOnly = true;
1069: } else if (!dbobjStatus.equals(DBObject.STATUS_NEW)) {
1070: if (dbobj.getMetaData().getKeyFieldListArray()
1071: .contains(fieldName)) {
1072: //It's a key field, it should not be changeable.
1073: readOnly = true;
1074: }
1075: }
1076:
1077: /**
1078: * Don't display read only fields for a new object since they only
1079: * serve to add confusion and there is no value assigned to them
1080: * yet.
1081: */
1082: if (dbobjStatus.equals(DBObject.STATUS_NEW)) {
1083: if (metaData.isReadOnly()) {
1084: return null;
1085: }
1086: }
1087:
1088: String displayAttrib = (String) metaData
1089: .getAttribute("display");
1090:
1091: if (displayAttrib != null) {
1092: oneField.setAttribute("display", displayAttrib);
1093: }
1094:
1095: //Set the field value to the default value if a default value is
1096: //supplied and an existing field value does not.
1097: if ((cachedValue != null) && (cachedValue.length() > 0)) {
1098: if ((oneFieldValue == null)
1099: || (oneFieldValue.length() == 0)) {
1100: oneField.setDefaultValue(cachedValue);
1101: }
1102: }
1103:
1104: if (readOnly) {
1105: oneField = renderReadOnlyInput(response, oneField,
1106: dbobj, fieldName, oneFieldValue);
1107: } else { /* NOT readonly */
1108:
1109: String oneFieldSize = Integer
1110: .toString(displayFieldSize);
1111: oneField = renderReadWriteInput(response, oneField,
1112: dbobj, fieldName, oneFieldValue, oneFieldSize);
1113: }
1114: /* else not read-only */
1115:
1116: cachedValue = oneField.getDefaultValue();
1117:
1118: if (!StringUtil.notNull(cachedValue).equals("")) {
1119: oneField.setDefaultValue(cachedValue);
1120:
1121: if (log.isDebugEnabled()) {
1122: log.debug("Cached value for '" + fieldName
1123: + "' was '" + cachedValue + "'");
1124: }
1125: } else {
1126: /* If no cached value, see if the db object has a default */
1127: String defValue = dbobj.getMetaData().getDefaultValue(
1128: fieldName);
1129:
1130: if (defValue != null) {
1131: oneField.setDefaultValue(defValue);
1132: }
1133: }
1134:
1135: return oneField;
1136: } catch (DBException dbe) {
1137: throw new ControllerException("Error rendering input.", dbe);
1138: }
1139: }
1140:
1141: /**
1142: * Same as display value but for Date/DateTime types. Formats things
1143: * appropriate to the user's locale
1144: *
1145: * @param metaData the Data Field's metadata
1146: * @param dt The date value to format
1147: * @param l the User's Locale gathered from the ControllerResponse object
1148: * @return a properly formatted date
1149: */
1150: protected String displayValue(DataFieldMetaData metaData, Date dt,
1151: Locale l) {
1152: if (dt == null) {
1153: return "";
1154: }
1155:
1156: if (metaData.isDateOnlyType()) {
1157: DateFormat df = DateFormat.getDateInstance(
1158: DateFormat.SHORT, l);
1159: df = modifyDateFormat(df);
1160:
1161: return df.format(dt);
1162: } else if (metaData.isTimeType()) {
1163: DateFormat df = DateFormat.getTimeInstance(
1164: DateFormat.SHORT, l);
1165: df = modifyDateFormat(df);
1166:
1167: return df.format(dt);
1168: } else {
1169: DateFormat df = DateFormat.getDateTimeInstance(
1170: DateFormat.SHORT, DateFormat.SHORT, l);
1171: df = modifyDateFormat(df);
1172:
1173: return df.format(dt);
1174: }
1175: }
1176:
1177: /**
1178: * Format a value for display in the HTML being returned to the client
1179: *
1180: * @param metaData The Field Metadata
1181: * @param fieldValue The value of the field
1182: * @param fieldName the name of the field to render
1183: * @param l The Locale to display the value for.
1184: * @return String The formatted field
1185: * @throws ControllerException If the field format information could not be
1186: * determined
1187: */
1188: protected String displayValue(DataFieldMetaData metaData,
1189: String fieldValue, String fieldName, Locale l)
1190: throws ControllerException {
1191: try {
1192: if (metaData.getTypeString().equalsIgnoreCase("money")) {
1193: if (fieldValue.length() > 0) {
1194: return new Format("%-10.2f").form(new Double(
1195: fieldValue).doubleValue());
1196: }
1197: } else {
1198: return fieldValue;
1199: }
1200: } catch (NumberFormatException ne) {
1201: throw new ControllerException("Number for field not in a "
1202: + "valid numeric format:" + fieldValue + ":"
1203: + ne.getMessage());
1204: }
1205:
1206: return null;
1207: }
1208:
1209: /* displayValue(String, String) */
1210:
1211: /**
1212: * Modifies an already instantiated Input to be a finished read only
1213: * control.
1214: *
1215: * @param response The ControllerResponse object
1216: * @param oneField The input to flesh out.
1217: * @param dbobj The data source object
1218: * @param fieldName The field name in the dbobj to render.
1219: * @param oneFieldValue The value to add to the input control.
1220: * @return a read only input
1221: * @throws DBException if there's an error communicating with the DBObject
1222: * @throws ControllerException if there's an error building the Input
1223: * field.
1224: */
1225: protected Input renderReadOnlyInput(ControllerResponse response,
1226: Input oneField, DataObject dbobj, String fieldName,
1227: String oneFieldValue) throws DBException,
1228: ControllerException {
1229: DataFieldMetaData metaData = dbobj.getFieldMetaData(fieldName);
1230: DataObjectMetaData objMetaData = dbobj.getMetaData();
1231:
1232: oneField.setAttribute(Input.ATTRIBUTE_READONLY, "Y");
1233: oneField.setAttribute(Input.ATTRIBUTE_ORIGINAL_VALUE,
1234: oneFieldValue);
1235:
1236: if (metaData.isMultiValued()) {
1237: java.util.List values = dbobj.getValidValuesList(fieldName);
1238:
1239: if (values == null) {
1240: throw new DBException("Valid values for field "
1241: + fieldName + " from object "
1242: + objMetaData.getName() + " were null");
1243: }
1244:
1245: String fieldValue = null;
1246: ValidValue oneVV = null;
1247:
1248: for (Iterator e = values.iterator(); e.hasNext();) {
1249: oneVV = (ValidValue) e.next();
1250:
1251: if (oneVV.getValue().equals(oneFieldValue)) {
1252: fieldValue = oneVV.getDescription();
1253: }
1254: }
1255:
1256: if (fieldValue == null) {
1257: oneField.setDefaultValue(oneFieldValue);
1258: } else {
1259: oneField.setDefaultValue(fieldValue);
1260: }
1261: } else {
1262: if (metaData.isDateType()) {
1263: if ((oneFieldValue == null)
1264: || (oneFieldValue.length() == 0)) {
1265: oneField.setDefaultValue(displayValue(metaData,
1266: oneFieldValue, fieldName, response
1267: .getLocale()));
1268: } else {
1269: oneField.setDefaultValue(displayValue(metaData,
1270: dbobj.getField(fieldName), fieldName,
1271: response.getLocale()));
1272: }
1273: } else {
1274: oneField
1275: .setDefaultValue(displayValue(metaData,
1276: oneFieldValue, fieldName, response
1277: .getLocale()));
1278: }
1279: }
1280:
1281: return oneField;
1282: }
1283:
1284: /**
1285: * Modifies an already instantiated Input to be a finished Input control
1286: * specifically for a blob field. If the dbobject is a MediaObject, then
1287: * it adds the abilities to view the fields and creates an appropriate
1288: * icon.
1289: *
1290: * @param response The ControllerResponse object
1291: * @param oneField The input to flesh out.
1292: * @param dbobj The data source object
1293: * @param fieldName The field name in the dbobj to render.
1294: * @param oneFieldValue The value to add to the input control.
1295: * @param oneFieldSize The size of the Input control when finished.
1296: * @throws DBException if there's an error communicating with the DBObject
1297: * @throws ControllerException if there's an error building the Input
1298: * field.
1299: */
1300: protected void renderReadWriteBlob(ControllerResponse response,
1301: Input oneField, DataObject dbobj, String fieldName,
1302: String oneFieldValue, String oneFieldSize)
1303: throws DBException, ControllerException {
1304: oneField.setType("file");
1305: oneField.setDisplayLength(60);
1306:
1307: if (dbobj instanceof NestableDataObject) {
1308: String tempFieldName = fieldName;
1309: fieldName = ((NestableDataObject) dbobj)
1310: .getFieldFromNestedName(fieldName);
1311: dbobj = ((NestableDataObject) dbobj)
1312: .getNestedFromFieldName(tempFieldName);
1313: }
1314:
1315: if (dbobj instanceof MediaDBObject) {
1316: MediaDBObject media = (MediaDBObject) dbobj;
1317: String mimeNumber = media.getField(fieldName + "_mimeType");
1318:
1319: if (mimeNumber == null) {
1320: return;
1321: }
1322:
1323: MimeTypes mt = new MimeTypes(SecuredDBObject.SYSTEM_ACCOUNT);
1324: mt.setField(MimeTypes.FLD_MIMENUMBER, mimeNumber);
1325:
1326: if (mt.find()) {
1327: oneField.setAttribute("IconURL", mt.getIconURL());
1328: } else {
1329: log.error("Unable to find mime type for mime number: "
1330: + mimeNumber);
1331: }
1332:
1333: // Transition t = new Transition("view","View"
1334: // ,com.jcorporate.expresso.services.controller.DBMaint.class,
1335: // "ViewBlob");
1336: // t.addParam("fieldName", fieldName);
1337: // t.addParam("dbobj", ((Object)dbobj).getClass().getName());
1338: }
1339: }
1340:
1341: /**
1342: * Modifies an already instantiated Input to be a finished Input control
1343: *
1344: * @param response The ControllerResponse object
1345: * @param oneField The input to flesh out.
1346: * @param dbobj The data source object
1347: * @param fieldName The field name in the dbobj to render.
1348: * @param oneFieldValue The value to add to the input control.
1349: * @param oneFieldSize The size of the Input control when finished.
1350: * @return a rendered Read/Write Input
1351: * @throws DBException if there's an error communicating with the DBObject
1352: * @throws ControllerException if there's an error building the Input
1353: * field.
1354: */
1355: protected Input renderReadWriteInput(ControllerResponse response,
1356: Input oneField, DataObject dbobj, String fieldName,
1357: String oneFieldValue, String oneFieldSize)
1358: throws DBException, ControllerException {
1359: if (log.isDebugEnabled()) {
1360: log
1361: .debug("Entering DefaultAutoElement.renderReadWriteInput");
1362: }
1363:
1364: DataFieldMetaData metaData = dbobj.getFieldMetaData(fieldName);
1365: DataObjectMetaData dbobjMetaData = dbobj.getMetaData();
1366:
1367: DataField df = dbobj.getDataField(fieldName);
1368:
1369: //
1370: //Set the appropriate display style.
1371: //
1372: if (df.getAttribute(DBObject.ATTRIBUTE_ERROR) != null) {
1373: oneField.setAttribute(Input.ATTRIBUTE_CSS_STYLE,
1374: getErrorStyle());
1375: } else if (!metaData.allowsNull()) {
1376: oneField.setAttribute(Input.ATTRIBUTE_CSS_STYLE,
1377: getRequiredStyle());
1378: } else {
1379: oneField.setAttribute(Input.ATTRIBUTE_CSS_STYLE,
1380: getNormalStyle());
1381: }
1382:
1383: //
1384: //If it's a required field, decorate the label with a '*' or whatever
1385: //else is defined by the class.
1386: //
1387: if (!metaData.allowsNull()) {
1388: oneField.setLabel(oneField.getLabel()
1389: + getRequiredDecorator());
1390: }
1391:
1392: /* if the field is multi-valued, present a drop-down list */
1393: /* instead of just a text field */
1394: if (metaData.isMultiValued()) {
1395: oneField.setAttribute(Input.ATTRIBUTE_MULTIVALUED, "Y");
1396: oneField.setAttribute(Input.ATTRIBUTE_DROPDOWN, "Y");
1397: oneField.setType(Input.ATTRIBUTE_DROPDOWN);
1398:
1399: java.util.List values = dbobj.getValidValuesList(fieldName);
1400:
1401: //Hashtable values = dbobj.getValues(fieldName);
1402: if (values == null) {
1403: throw new DBException("Valid values for field "
1404: + fieldName + " from object "
1405: + dbobjMetaData.getName() + " were null");
1406: }
1407:
1408: oneField.setValidValues(new Vector(values));
1409: oneField.setDefaultValue(oneFieldValue);
1410: } else {
1411: //
1412: //If we have a blob, then it is a file to upload.
1413: //
1414: if (metaData.isBinaryObjectType()) {
1415: renderReadWriteBlob(response, oneField, dbobj,
1416: fieldName, oneFieldValue, oneFieldSize);
1417: }
1418:
1419: if (metaData.isDateType()) {
1420: oneField.setDisplayLength(10);
1421:
1422: // oneField.setMaxLength(10 + 2);
1423: if ((oneFieldValue == null)
1424: || (oneFieldValue.length() == 0)) {
1425: oneField.setDefaultValue(displayValue(metaData,
1426: oneFieldValue, fieldName, response
1427: .getLocale()));
1428: } else {
1429: oneField.setDefaultValue(displayValue(metaData,
1430: dbobj.getDataField(fieldName).asDate(),
1431: response.getLocale()));
1432: }
1433: } else {
1434: if (metaData.isCharacterLongObjectType()) {
1435: oneField.setDisplayLength(80);
1436: oneField.setLines(4);
1437: oneField.setMaxLength(4096);
1438: oneField.setType("text");
1439: } else {
1440: // oneField.setMaxLength(new Integer(oneFieldSize).intValue());
1441: }
1442:
1443: oneField
1444: .setDefaultValue(displayValue(metaData,
1445: oneFieldValue, fieldName, response
1446: .getLocale()));
1447: }
1448: }
1449:
1450: if (log.isDebugEnabled()) {
1451: if (oneField != null) {
1452: log
1453: .debug("Leaving DefaultAutoElement.renderReadWriteInput "
1454: + oneField.toString());
1455: } else {
1456: log
1457: .debug("Leaving DefaultAutoElement.renderReadWriteInput oneField=null");
1458: }
1459: }
1460:
1461: return oneField;
1462: }
1463:
1464: /**
1465: * For lookup objects that also define a lookup object AND lookup field,
1466: * then attempt to match the field key with the lookup field value
1467: *
1468: * @param className the DataObject to use as the metadata source
1469: *
1470: * @return String value of the lookup value.
1471: */
1472:
1473: // protected String renderLookupValue(DataObject object, String curValue,
1474: // String fieldName,Input i) throws DataException {
1475: // if (curValue == null || curValue.length() == 0) {
1476: // return "";
1477: // }
1478: //
1479: // DataFieldMetaData fieldMetadata = object.getFieldMetaData(fieldName);
1480: // String lookupObject = fieldMetadata.getLookupObject();
1481: //
1482: // Mappable mapObject = constructMappableObject(object,fieldName);
1483: // i.setDescription(mapObject.getMappedDescription());
1484: // return mapObject.getMappedValue(curValue);
1485: // }
1486: /**
1487: * Parses the lookup value. Adds to the ErrorCollection if referential
1488: * integrity cannot be established
1489: *
1490: * @param className the error collection to add errors to if any occur.
1491: *
1492: * @return the lookup value
1493: */
1494:
1495: // private String parseLookupValue(ErrorCollection ec,
1496: // DataObject object, String curValue,
1497: // String fieldName) throws DataException {
1498: // if (curValue== null || curValue.length() == 0) {
1499: // return null;
1500: // }
1501: //
1502: // DataFieldMetaData fieldMetadata = object.getFieldMetaData(fieldName);
1503: // String lookupObject = fieldMetadata.getLookupObject();
1504: //
1505: // Mappable mapObject = constructMappableObject(object,fieldName);
1506: // return mapObject.getKeyValue(curValue);
1507: //
1508: // }
1509: //
1510: /**
1511: * Checks to see if a lookup object is mappable.
1512: *
1513: * @param className the class name to test
1514: *
1515: * @return true if the class implements mappable, false otherwise.
1516: */
1517: // private boolean isMappable(String className)
1518: // {
1519: // try {
1520: // Object o = ClassLocator.loadClass(className).newInstance();
1521: //
1522: // if (o instanceof Mappable) {
1523: // return true;
1524: // } else {
1525: // return false;
1526: // }
1527: // } catch (InstantiationException ex) {
1528: // log.error("Error instantiating object " + className, ex);
1529: //
1530: // return false;
1531: // } catch (IllegalAccessException ex) {
1532: // log.error("Error instantiating object " + className, ex);
1533: //
1534: // return false;
1535: // } catch (ClassNotFoundException ex) {
1536: // log.error("Error instantiating object " + className, ex);
1537: //
1538: // return false;
1539: // }
1540: // }
1541: /**
1542: * Given a file pathname, tell us what the name without the path is.
1543: *
1544: * @param fileNameParam The file name of the file that was uploaded ot the
1545: * server.
1546: * @return a java.lang.String that contains the file name without any path
1547: * associated with it.
1548: */
1549: private String getOriginalFileName(String fileNameParam) {
1550: if (fileNameParam == null) {
1551: return null;
1552: }
1553:
1554: int lastSlash = fileNameParam.lastIndexOf("\\");
1555:
1556: if (lastSlash < 0) {
1557: lastSlash = fileNameParam.lastIndexOf("/");
1558:
1559: if (lastSlash < 0) {
1560: return fileNameParam;
1561: }
1562: }
1563:
1564: return fileNameParam.substring(lastSlash + 1);
1565: }
1566:
1567: /**
1568: * Constructs an object to perform the lookups based upon the lookup
1569: * object, and lookup definition names.
1570: *
1571: * @param sourceObject the object where we get the metadata, and source
1572: * data context
1573: * @param fieldName the name of the field to get the lookup object for
1574: *
1575: * @return an instantiated DataObject.
1576: *
1577: * @throws IllegalArgumentException
1578: */
1579: // private DataObject constructLookupObject(DataObject sourceObject,
1580: // String fieldName) throws DataException
1581: // {
1582: // DataFieldMetaData fieldMetadata = sourceObject.getFieldMetaData(fieldName);
1583: // String lookupObject = fieldMetadata.getLookupObject();
1584: // String definitionName = fieldMetadata.getLookupDefinition();
1585: //
1586: // if ((lookupObject == null) || (lookupObject.length() == 0)) {
1587: // throw new IllegalArgumentException(
1588: // "Was asked to construct lookup object that didn't exist for field: " +
1589: // fieldName);
1590: // }
1591: //
1592: // DataObject returnValue = null;
1593: // Class returnClass = null;
1594: //
1595: // try {
1596: // returnClass = ClassLocator.loadClass(lookupObject);
1597: // } catch (ClassNotFoundException ex) {
1598: // log.error("Class Not Found Exception", ex);
1599: // throw new IllegalArgumentException("Error finding lookup object: " +
1600: // lookupObject);
1601: // }
1602: //
1603: // returnValue = com.jcorporate.expresso.core.dataobjects.DataObjectFactory.createDataObject(returnClass,
1604: // sourceObject.getDataContext(), definitionName,
1605: // Securable.SYSTEM_ACCOUNT);
1606: //
1607: // try {
1608: // returnValue.clear();
1609: // } catch (DBException ex) {
1610: // throw new DataException("Error clearing new data object");
1611: // }
1612: //
1613: // return returnValue;
1614: // }
1615: /**
1616: * Constructs a properly instantiated mappable object
1617: *
1618: * @param sourceObject the dataobject where we get the lookup names, etc
1619: * @param fieldName the field name to get the lookup for
1620: *
1621: * @return a properly constructed Mappable object
1622: *
1623: * @throws IllegalArgumentException
1624: */
1625: // private Mappable constructMappableObject(DataObject sourceObject,
1626: // String fieldName) throws DataException
1627: // {
1628: // DataFieldMetaData fieldMetadata = sourceObject.getFieldMetaData(fieldName);
1629: // String lookupObject = fieldMetadata.getLookupObject();
1630: // String definitionName = fieldMetadata.getLookupDefinition();
1631: //
1632: // if ((lookupObject == null) || (lookupObject.length() == 0)) {
1633: // throw new IllegalArgumentException(
1634: // "Was asked to construct lookup object that didn't exist for field: " +
1635: // fieldName);
1636: // }
1637: //
1638: // Object returnValue = null;
1639: // Class returnClass = null;
1640: //
1641: // try {
1642: // returnClass = ClassLocator.loadClass(lookupObject);
1643: // } catch (ClassNotFoundException ex) {
1644: // log.error("Class Not Found Exception", ex);
1645: // throw new IllegalArgumentException("Error finding lookup object: " +
1646: // lookupObject);
1647: // }
1648: //
1649: // returnValue = com.jcorporate.expresso.core.dataobjects.DataObjectFactory.createObject(returnClass,
1650: // sourceObject.getDataContext(), definitionName,
1651: // Securable.SYSTEM_ACCOUNT);
1652: //
1653: // if (returnValue instanceof Mappable) {
1654: // return (Mappable) returnValue;
1655: // } else {
1656: // return null;
1657: // }
1658: // }
1659: /**
1660: * Gleaned from @link http://www.jguru.com/faq/view.jsp?EID=429821 to
1661: * make the SimpleDateFormat give us 4 year dates instead.
1662: *
1663: * @param df the DateFormat class
1664: * @return a proper DateFormat class to modify
1665: */
1666: private DateFormat modifyDateFormat(DateFormat df) {
1667: SimpleDateFormat sdf = null;
1668:
1669: try {
1670: sdf = (SimpleDateFormat) df;
1671: } catch (ClassCastException cce) {
1672: return df;
1673: }
1674:
1675: String sTemp = sdf.toPattern();
1676: int iLen = sTemp.length();
1677: int i = sTemp.lastIndexOf('y') + 1;
1678: sTemp = sTemp.substring(0, i) + "yy"
1679: + ((i < iLen) ? sTemp.substring(i, iLen) : "");
1680: sdf.applyPattern(sTemp);
1681:
1682: return sdf;
1683: }
1684: }
|