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.core.controller;
0065:
0066: import com.jcorporate.expresso.core.controller.session.SimplePersistentSession;
0067: import com.jcorporate.expresso.core.dataobjects.DataObjectMetaData;
0068: import com.jcorporate.expresso.core.dataobjects.jdbc.JDBCObjectMetaData;
0069: import com.jcorporate.expresso.core.db.DBException;
0070: import com.jcorporate.expresso.core.dbobj.DBField;
0071: import com.jcorporate.expresso.core.dbobj.DBObject;
0072: import com.jcorporate.expresso.core.i18n.Messages;
0073: import com.jcorporate.expresso.core.misc.StringUtil;
0074: import com.jcorporate.expresso.kernel.util.ClassLocator;
0075: import com.jcorporate.expresso.kernel.util.FastStringBuffer;
0076: import org.apache.log4j.Logger;
0077: import org.apache.struts.Globals;
0078: import org.apache.struts.action.ActionError;
0079: import org.w3c.dom.NamedNodeMap;
0080: import org.w3c.dom.Node;
0081: import org.w3c.dom.NodeList;
0082:
0083: import javax.servlet.http.HttpServletRequest;
0084: import java.io.Serializable;
0085: import java.util.Enumeration;
0086: import java.util.HashMap;
0087: import java.util.Hashtable;
0088: import java.util.Iterator;
0089: import java.util.Locale;
0090: import java.util.Map;
0091: import java.util.Stack;
0092: import java.util.Vector;
0093:
0094: /**
0095: * A ControllerResponse object contains the vector of Inputs, Outputs and
0096: * Transitions that results from a call to "newState(String)" for a particular
0097: * controller.
0098: * <p>Once a state has been processed, the ControllerResponse object is usually
0099: * saved in the Servlet Request Context where it can be retrieved by JSP tags
0100: * by querying the request context for an object named "controllerResponse"
0101: * </p>
0102: */
0103: public class ControllerResponse implements Serializable {
0104: /**
0105: * The log4j logger.
0106: */
0107: private static final transient Logger log = Logger
0108: .getLogger(ControllerResponse.class);
0109:
0110: /**
0111: * The ControllerRequest object set for this response
0112: */
0113: protected ControllerRequest myRequest = null;
0114:
0115: /**
0116: * Object for setting the Locale object
0117: */
0118: protected Locale responseLocale = null;
0119:
0120: /**
0121: * A name to value map of blocks
0122: */
0123: protected HashMap blockCache = null;
0124:
0125: /**
0126: * The name to value map for inputs
0127: */
0128: protected HashMap inputCache = null;
0129:
0130: /**
0131: * A name to value map for outputs
0132: */
0133: protected HashMap outputCache = null;
0134:
0135: /**
0136: * A name to value map for Transitions
0137: */
0138: protected HashMap transitionCache = null;
0139:
0140: /**
0141: * The current state
0142: */
0143: protected State currentState = null;
0144:
0145: /**
0146: * The classname of this controller
0147: */
0148: protected String myControllerClass = null;
0149:
0150: /**
0151: * The data context for this controller response
0152: */
0153: protected String dataContext = "default";
0154:
0155: /**
0156: * The request path
0157: */
0158: protected String myRequestPath = null;
0159:
0160: /**
0161: * The requested state name
0162: */
0163: protected String requestedState = null;
0164:
0165: /**
0166: * The resulting style code
0167: */
0168: protected String style = null;
0169:
0170: /**
0171: * The title of the ControllerResponse
0172: */
0173: protected String title = null;
0174:
0175: /**
0176: * A list of all blocks in the order they were added to the response
0177: */
0178: protected Vector blockCacheOrdered = null;
0179:
0180: /**
0181: * A list of all inputs as added to the response
0182: */
0183: protected Vector inputCacheOrdered = null;
0184:
0185: /**
0186: * A list of all outputs in the order they were added to the response
0187: */
0188: protected Vector outputCacheOrdered = null;
0189:
0190: /**
0191: * A list of all transitions in the order they were added to the response
0192: */
0193: protected Vector transitionCacheOrdered = null;
0194:
0195: /**
0196: * NOTE: Any Controller that must access the HttpServletResponse object
0197: * available from the ControllerRequest object and handle making it's own
0198: * response to the client (e.g. a custom mime type, multimedia stream,
0199: * etc), should call setCustomResponse(true) to tell the caller that it
0200: * should not try to format the Outputs, Inputs, and Transitions from this
0201: * controller call. Use only when absolutely required!
0202: */
0203: protected boolean customResponse = false;
0204:
0205: /**
0206: * Provides a hierarchy of schemas to check for messages bundles. The top
0207: * of the stack is the lowest on the heirarchy and should be checked first
0208: * for Messages, etc... then proceed on down the stack.
0209: */
0210: private java.util.Stack schemaStack;
0211:
0212: /**
0213: * Default constructor for the controller response
0214: */
0215: public ControllerResponse() {
0216: super ();
0217: }
0218:
0219: /**
0220: * Set the named attribute of this Controller to the given value
0221: *
0222: * @param attrib The name of an "attribtue" for this ControllerElement item
0223: * @param val The value for this attribute
0224: * @throws ControllerException upon error
0225: */
0226: public void setAttribute(String attrib, String val)
0227: throws ControllerException {
0228: getRequest().setAttrib(attrib, val);
0229: }
0230:
0231: /* setAttributes(String, String) */
0232:
0233: /**
0234: * Retrieve an attribute as specified from the request
0235: *
0236: * @param attrib The name of an "attribute" for this ControllerElement item
0237: * @return the attribute value (may be null)
0238: * @throws ControllerException upon error
0239: */
0240: public String getAttribute(String attrib)
0241: throws ControllerException {
0242: return (String) getRequest().getAttrib(attrib);
0243: }
0244:
0245: /* setAttributes(String, String) */
0246:
0247: /**
0248: * Set the attribute Map
0249: *
0250: * @param attributes the supplied attribute values
0251: * @throws ControllerException upon error
0252: */
0253: public void setAttributes(Map attributes)
0254: throws ControllerException {
0255: getRequest().setAttributes(attributes);
0256: }
0257:
0258: /* setAttributes(Map) */
0259:
0260: /**
0261: * Get the attribute Map
0262: *
0263: * @return an java.util.Map of Strings
0264: * @throws ControllerException upon error
0265: */
0266: public Map getAttributes() throws ControllerException {
0267: return getRequest().getAttributes();
0268: }
0269:
0270: /* getAttributes() */
0271:
0272: /**
0273: * Get a specific block.
0274: *
0275: * @param blockName the name of the Block
0276: * @return Block instance or null if no block found.
0277: * @throws ControllerException upon error
0278: */
0279: public Block getBlock(String blockName) throws ControllerException {
0280: validState();
0281:
0282: if (blockCache != null) {
0283: return (Block) blockCache.get(blockName);
0284: }
0285:
0286: return null;
0287: }
0288:
0289: /* getBlock(String) */
0290:
0291: /**
0292: * Return the vector of Blocks for this controller state to the client
0293: *
0294: * @return Vector of Block objects
0295: */
0296: public final Vector getBlocks() {
0297: validState();
0298:
0299: if (blockCacheOrdered != null) {
0300: return blockCacheOrdered;
0301: }
0302:
0303: return null;
0304: }
0305:
0306: /* getBlocks() */
0307:
0308: /**
0309: * Set public so that test classes can get into it.
0310: *
0311: * @param newClass the new controller class name
0312: */
0313: public void setControllerClass(String newClass) {
0314: myControllerClass = newClass;
0315: }
0316:
0317: /**
0318: * Retrieve the controller class name
0319: *
0320: * @return java.lang.String, the name of the controller class
0321: */
0322: public String getControllerClass() {
0323: return myControllerClass;
0324: }
0325:
0326: /**
0327: * Return the current State object, based on the state we last transitioned
0328: * into
0329: *
0330: * @return java.lang.String the current state
0331: */
0332: public State getCurrentState() {
0333: return currentState;
0334: }
0335:
0336: /**
0337: * Return a specific Input item.
0338: *
0339: * @param inputName the name of the input to retrieve
0340: * @return Input
0341: */
0342: public final Input getInput(String inputName) {
0343: validState();
0344:
0345: if (inputCache != null) {
0346: return (Input) inputCache.get(inputName);
0347: }
0348:
0349: return null;
0350: }
0351:
0352: /* getInput(String) */
0353:
0354: /**
0355: * Return the vector of input items for this controller state to the
0356: * client.
0357: *
0358: * @return java.util.Vector of Input objects
0359: */
0360: public final Vector getInputs() {
0361: validState();
0362:
0363: if (inputCacheOrdered != null) {
0364: return inputCacheOrdered;
0365: }
0366:
0367: return new Vector();
0368: }
0369:
0370: /* getInptus() */
0371:
0372: /**
0373: * If absolutely necessary the Controller can access the ServletResponse
0374: * object directly from the ServletControllerRequest object, if the
0375: * controller is running in a servlet environment. For example, if a
0376: * custom mime-type must be set, a multimedia data stream returned, or
0377: * other special processing. If this is done, the method below should be
0378: * called so that the "container" that called this Controller knows that
0379: * the response object has been manipulated, and that it should not
0380: * perform the normal processing of Inputs, Outputs and Transitions.
0381: *
0382: * @param newCustom set to true if you don't want Struts to render the
0383: * response through JSP
0384: */
0385: public void setCustomResponse(boolean newCustom) {
0386: customResponse = newCustom;
0387: }
0388:
0389: /**
0390: * Did this Controller call directly manipulate the ServletResponse and
0391: * handle it's own output to the client? (This is NOT recommended)
0392: *
0393: * @return true if the controller IS sending a custom response
0394: */
0395: public boolean isCustomResponse() {
0396: return customResponse;
0397: }
0398:
0399: /**
0400: * Set the db name of this ControllerResponse
0401: *
0402: * @param newDBName the new database name
0403: * @throws ControllerException upon error
0404: */
0405: public synchronized void setDBName(String newDBName)
0406: throws ControllerException {
0407: this .dataContext = newDBName;
0408: }
0409:
0410: /**
0411: * Get the database from the request, if there is a request available
0412: *
0413: * @return the database context that the system is set for.
0414: * @throws ControllerException upon error
0415: */
0416: public String getDBName() throws ControllerException {
0417: return getDataContext();
0418: } /* getDBName() */
0419:
0420: /**
0421: * Get the database from the request, if there is a request available
0422: *
0423: * @return the database context that the system is set for.
0424: * @throws ControllerException upon error
0425: */
0426: public String getDataContext() throws ControllerException {
0427: if (dataContext != null) {
0428: return dataContext;
0429: }
0430:
0431: return "default";
0432: }
0433:
0434: /**
0435: * Automatically find all input fields and put them in the formCache.
0436: * Creation date: (7/19/00 7:22:11 PM) author: Adam Rossi,
0437: * PlatinumSolutions
0438: *
0439: * @throws ControllerException upon error
0440: */
0441: public void setFormCache() throws ControllerException {
0442: getDefaultForm().saveForm(getRequest());
0443: }
0444:
0445: /* setFormCache() */
0446:
0447: /**
0448: * Save a name/value pair to the formCache. Creation date: (7/20/00 1:14:14
0449: * PM)
0450: *
0451: * @param fieldName java.lang.String
0452: * @param fieldValue java.lang.String
0453: * @throws ControllerException upon error
0454: */
0455: public void setFormCache(String fieldName, String fieldValue)
0456: throws ControllerException {
0457: getDefaultForm().setField(fieldName, fieldValue);
0458: }
0459:
0460: /* setFormCache(String, String) */
0461:
0462: /**
0463: * Get the entire formResponseCache Hashtable Creation date: (7/19/00
0464: * 7:18:51 PM) author: Adam Rossi, PlatinumSolutions
0465: *
0466: * @return Hashtable of ControllerElements
0467: * @throws ControllerException upon error
0468: */
0469: public Hashtable getFormCache() throws ControllerException {
0470: return getDefaultForm().getFields();
0471: }
0472:
0473: /* getFormCache() */
0474:
0475: /**
0476: * Fetch the requested field from the response cache. Return an empty
0477: * string if not found. Creation date: (7/19/00 7:18:51 PM) author: Adam
0478: * Rossi, PlatinumSolutions
0479: *
0480: * @param fieldName java.lang.String
0481: * @return java.lang.String
0482: * @throws ControllerException upon error
0483: */
0484: public String getFormCache(String fieldName)
0485: throws ControllerException {
0486: return StringUtil.notNull(getDefaultForm().getField(fieldName));
0487: }
0488:
0489: /* getFormCache(String) */
0490:
0491: /**
0492: * Allows the generic setting of form attributes.
0493: *
0494: * @param fieldName the name of the field attribute to set
0495: * @param fieldAttribute the attribute to set it to
0496: * @throws ControllerException if the fieldName is blank or null
0497: */
0498: public void setFormCacheAttribute(String fieldName,
0499: Object fieldAttribute) throws ControllerException {
0500: getDefaultForm().setAttribute(fieldName, fieldAttribute);
0501: }
0502:
0503: /**
0504: * Gets the saved cache attribute.
0505: *
0506: * @param fieldName the name of the field to retrieve
0507: * @return Object the cache attribute
0508: * @throws ControllerException if the fieldName specified is blank or null.
0509: */
0510: public Object getFormCacheAttribute(String fieldName)
0511: throws ControllerException {
0512: return getDefaultForm().getAttribute(fieldName);
0513: }
0514:
0515: /**
0516: * Retrieve the Locale for the request
0517: *
0518: * @return Locale object or default locale if noen was set
0519: * @throws ControllerException upon error
0520: */
0521: public Locale getLocale() throws ControllerException {
0522: if (responseLocale == null) {
0523: return Locale.getDefault();
0524: }
0525:
0526: return responseLocale;
0527: }
0528:
0529: /**
0530: * Retrieve the Inputs as a map so that JSTL can cope with navigating the
0531: * ControllerResponse through a named fashion
0532: *
0533: * @return java.util.Map
0534: * @throws ControllerException upon error
0535: */
0536: public Map getNamedInputs() throws ControllerException {
0537: validState();
0538:
0539: return inputCache;
0540: }
0541:
0542: /**
0543: * Get a specific output item.
0544: *
0545: * @param outputName the name of the output to retrieve
0546: * @return <code>Output</code>
0547: * @throws ControllerException upon error
0548: */
0549: public Output getOutput(String outputName)
0550: throws ControllerException {
0551: validState();
0552:
0553: if (outputCache != null) {
0554: return (Output) outputCache.get(outputName);
0555: }
0556:
0557: return null;
0558: }
0559:
0560: /* getOutput(String) */
0561:
0562: /**
0563: * Get the contents of a particular Output item.
0564: *
0565: * @param outputName the name of the output to retrieve
0566: * @return java.lang.String the content of the named output
0567: * @throws ControllerException If there is no such output
0568: */
0569: public String getOutputContent(String outputName)
0570: throws ControllerException {
0571: validState();
0572:
0573: Output o = getOutput(outputName);
0574:
0575: if (o == null) {
0576: return ("No Such Output named '" + outputName + "'");
0577: }
0578:
0579: return o.getContent();
0580: }
0581:
0582: /* getOutputContent(String) */
0583:
0584: /**
0585: * Get the named output, but throw if it's not found.
0586: *
0587: * @param outputName the name of the output to retrieve
0588: * @return Output object
0589: * @throws ControllerException if the output cannot be found
0590: */
0591: public Output getOutputRequired(String outputName)
0592: throws ControllerException {
0593: Output o = getOutput(outputName);
0594:
0595: if (o == null) {
0596: throw new ControllerException("There is no output named '"
0597: + outputName + "'");
0598: }
0599:
0600: return o;
0601: }
0602:
0603: /* getOutputRequired(String) */
0604:
0605: /**
0606: * The client calls this method for each state to determine what output to
0607: * show to the user.
0608: *
0609: * @return Vector of Output objects
0610: */
0611: public final Vector getOutputs() {
0612: validState();
0613:
0614: if (outputCacheOrdered != null) {
0615: return outputCacheOrdered;
0616: }
0617:
0618: return new Vector();
0619: }
0620:
0621: /* getOutputs() */
0622:
0623: /**
0624: * Retrieve the error collection for this response
0625: *
0626: * @return ErrorCollection (may be null)
0627: * @throws ControllerException upon error reading from the session
0628: */
0629: public ErrorCollection getErrors() throws ControllerException {
0630: ErrorCollection errs = (ErrorCollection) getRequest()
0631: .getSession().getAttribute(Globals.ERROR_KEY);
0632:
0633: return errs;
0634: }
0635:
0636: /**
0637: * Retrieve the parameter
0638: *
0639: * @param paramName the name of the parameter to retrieve
0640: * @return java.lang.String or null if the parameter doesn't exist
0641: * @throws ControllerException upon error
0642: */
0643: public String getParameter(String paramName)
0644: throws ControllerException {
0645: return getRequest().getParameter(paramName);
0646: }
0647:
0648: /**
0649: * Set the controller request - this is done as part of the processing of
0650: * the controller so that the response has access to all of the request
0651: * fields
0652: *
0653: * @param newRequest the new controller request.
0654: * @throws ControllerException upon error
0655: */
0656: public void setRequest(ControllerRequest newRequest)
0657: throws ControllerException {
0658: if (newRequest == null) {
0659: throw new ControllerException(
0660: "You cannot set a null Controller Request here");
0661: }
0662:
0663: myRequest = newRequest;
0664: requestedState = StringUtil.notNull(myRequest
0665: .getParameter(Controller.STATE_PARAM_KEY));
0666: this .dataContext = newRequest.getDataContext();
0667: this .responseLocale = newRequest.getLocale();
0668: }
0669:
0670: /**
0671: * Retrieve the ControllerRequest associated with this object
0672: *
0673: * @return <code>ControllerRequest</code> object
0674: * @throws IllegalArgumentException if the setRequest() object has not
0675: * been set yet.
0676: */
0677: public ControllerRequest getRequest() {
0678: if (myRequest == null) {
0679: throw new IllegalStateException(
0680: "ControllerResponse.setRequest() must be set before calling getRequest()");
0681: }
0682: return myRequest;
0683: }
0684:
0685: /**
0686: * Sets the request path
0687: *
0688: * @param newPath the URL path without the .do at the end of it.
0689: */
0690: public synchronized void setRequestPath(String newPath) {
0691: myRequestPath = newPath + ".do";
0692: }
0693:
0694: /**
0695: * Returns the request path set earlier. (Note we moved the +".do" to
0696: * setRequestPath because we set less often than we get, so we do less
0697: * string allocations)
0698: *
0699: * @return java.lang.String
0700: */
0701: public String getRequestPath() {
0702: return myRequestPath;
0703: }
0704:
0705: /**
0706: * Retrieve the requested state
0707: *
0708: * @return state name requested
0709: */
0710: public String getRequestedState() {
0711: return requestedState;
0712: }
0713:
0714: /**
0715: * Get the name of the schema object that this Controller belongs to
0716: *
0717: * @return java.lang.String, the Schema classname associated with this
0718: * ControllerResponse.
0719: */
0720: public String getSchema() {
0721: if ((schemaStack == null) || schemaStack.isEmpty()) {
0722: return "com.jcorporate.expresso.core.ExpressoSchema";
0723: } else {
0724: return (String) schemaStack.peek();
0725: }
0726: }
0727:
0728: /* getSchema() */
0729:
0730: /**
0731: * Sets the schema stack for message bundle retrieval
0732: *
0733: * @param schemaStack the Stack to use.
0734: */
0735: public void setSchemaStack(java.util.Stack schemaStack) {
0736: this .schemaStack = schemaStack;
0737: }
0738:
0739: /**
0740: * Retrieve the schema stack. Walk up the schema stack to check a
0741: * hierarchy of MessagesBundles for a possible message
0742: *
0743: * @return java.util.Stack
0744: */
0745: public java.util.Stack getSchemaStack() {
0746: if (schemaStack == null) {
0747: schemaStack = new Stack();
0748: }
0749:
0750: if (schemaStack.isEmpty()) {
0751: schemaStack
0752: .push(com.jcorporate.expresso.core.ExpressoSchema.class
0753: .getName());
0754: }
0755:
0756: return schemaStack;
0757: }
0758:
0759: /**
0760: * retrieve an appropriate localized string from the
0761: * correct Schema object. This version of the call is overridden with more
0762: * sophisticated versions in DBController (which knows the username)
0763: *
0764: * @param stringCode the String code to retrieve
0765: * @param args the formatting arguments
0766: * @return translated string or stringCode if not found
0767: * @throws ControllerException upon error
0768: */
0769: public String getString(String stringCode, Object[] args)
0770: throws ControllerException {
0771: StringUtil.assertNotBlank(stringCode,
0772: "You must specify a string key");
0773:
0774: if (myRequest == null) {
0775: log
0776: .error("No request object was established for this controller response, "
0777: + " for controller class '"
0778: + StringUtil.notNull(myControllerClass)
0779: + "'");
0780:
0781: return null;
0782: }
0783:
0784: Stack s = this .getSchemaStack();
0785: try {
0786: return Messages.getString(s, this .responseLocale,
0787: stringCode, args);
0788: } catch (IllegalArgumentException ex) {
0789: throw new IllegalArgumentException(
0790: "Unable to locate string " + stringCode
0791: + " for any schema");
0792: }
0793: }
0794:
0795: /**
0796: * Convenience version of the above with no arguments.
0797: *
0798: * @param stringCode the string code to retrieve
0799: * @return java.lang.String
0800: * @throws ControllerException upon error
0801: */
0802: public String getString(String stringCode)
0803: throws ControllerException {
0804: Object[] args = {};
0805:
0806: return getString(stringCode, args);
0807: }
0808:
0809: /* getString(String) */
0810:
0811: /**
0812: * Convenience method of getString(String,Object[]) where first (and only) param of args will be string1
0813: *
0814: * @param stringCode the string code to retrieve
0815: * @param string1 a single parameter for message format (the first argument to replace)
0816: * @return translated string or stringCode if not found
0817: * @throws ControllerException upon error
0818: */
0819: public String getString(String stringCode, String string1)
0820: throws ControllerException {
0821: Object[] args = { string1 };
0822:
0823: return getString(stringCode, args);
0824: }
0825:
0826: /**
0827: * Convenience method to retrieve the string with two formatting parameters
0828: *
0829: * @param stringCode the string code to retrieve
0830: * @param string1 formatting parameter one
0831: * @param string2 formatting parameter two
0832: * @return java.lang.String
0833: * @throws ControllerException upon error
0834: */
0835: public String getString(String stringCode, String string1,
0836: String string2) throws ControllerException {
0837: Object[] args = { string1, string2 };
0838:
0839: return getString(stringCode, args);
0840: }
0841:
0842: /**
0843: * Retrieve a localized string with 3 formatting parameters
0844: *
0845: * @param stringCode the string code to retrieve
0846: * @param string1 formatting parameter one
0847: * @param string2 formatting parameter two
0848: * @param string3 formatting parameter number three
0849: * @return java.lang.String
0850: * @throws ControllerException upon error
0851: */
0852: public String getString(String stringCode, String string1,
0853: String string2, String string3) throws ControllerException {
0854: Object[] args = { string1, string2, string3 };
0855:
0856: return getString(stringCode, args);
0857: }
0858:
0859: /**
0860: * Retrieve a localized string with 4 formatting parameters
0861: *
0862: * @param stringCode the string code to retrieve
0863: * @param string1 formatting parameter one
0864: * @param string2 formatting parameter two
0865: * @param string3 formatting parameter number three
0866: * @param string4 formatting parameter number four
0867: * @return java.lang.String
0868: * @throws ControllerException upon error
0869: */
0870: public String getString(String stringCode, String string1,
0871: String string2, String string3, String string4)
0872: throws ControllerException {
0873: Object[] args = { string1, string2, string3, string4 };
0874:
0875: return getString(stringCode, args);
0876: }
0877:
0878: /**
0879: * Use setStyle to specify a different Struts ActionForward to send the
0880: * rendering to rather then the default one.
0881: *
0882: * @param newStyle the new style string. Must be in one of the
0883: * struts-config.xml files.
0884: */
0885: public void setStyle(String newStyle) {
0886: style = newStyle;
0887: }
0888:
0889: /**
0890: * Retrieve the style that the controller response is set to
0891: *
0892: * @return java.lang.String
0893: */
0894: public String getStyle() {
0895: return style;
0896: }
0897:
0898: /**
0899: * Sets the title of the controller
0900: *
0901: * @param newTitle the new title for the controller
0902: */
0903: public void setTitle(String newTitle) {
0904: title = newTitle;
0905: }
0906:
0907: /**
0908: * Assemble a ControllerResponse from an xml document (may be document
0909: * fragment).
0910: *
0911: * @param n a DOM node to assemble the response from.
0912: * @return an instantiated ControllerResponse object
0913: * @throws ControllerException upon error
0914: */
0915: public static ControllerResponse fromXML(Node n)
0916: throws ControllerException {
0917: //If we're at the root node, then it'll be doc instead of input.
0918: if (n.getNodeName().equals("#document")) {
0919: return fromXML(n.getChildNodes().item(0));
0920: }
0921:
0922: if (!n.getNodeName().equals("controller-response")) {
0923: throw new ControllerException("Failed To Get DOM Node of "
0924: + " type 'controller-response' Got "
0925: + n.getNodeName() + " instead.");
0926: }
0927:
0928: ControllerResponse cr = new ControllerResponse();
0929:
0930: //
0931: //Since we technically need a controller request to be able to deal with
0932: //error collection. Then we need to create a dummy session for such
0933: //usage.
0934: //
0935: SimplePersistentSession session = new SimplePersistentSession();
0936: ControllerRequest request = new ControllerRequest();
0937: request.setUid(3);
0938: request.setSession(session);
0939: cr.setRequest(request);
0940:
0941: //
0942: // Load The Controller Response Attributes
0943: //
0944: NamedNodeMap attributes = n.getAttributes();
0945: Node oneAttribute = attributes.getNamedItem("name");
0946:
0947: if (oneAttribute != null) {
0948: cr.setControllerClass(oneAttribute.getNodeValue());
0949: }
0950:
0951: oneAttribute = attributes.getNamedItem("title");
0952:
0953: if (oneAttribute != null) {
0954: cr.setTitle(oneAttribute.getNodeValue());
0955: }
0956:
0957: oneAttribute = attributes.getNamedItem("requestedState");
0958:
0959: if (oneAttribute != null) {
0960: cr.requestedState = oneAttribute.getNodeValue();
0961: }
0962:
0963: oneAttribute = attributes.getNamedItem("style");
0964:
0965: if (oneAttribute != null) {
0966: cr.setStyle(oneAttribute.getNodeValue());
0967: }
0968:
0969: try {
0970: NodeList children = n.getChildNodes();
0971:
0972: for (int index = 0; index < children.getLength(); index++) {
0973: Node oneChild = children.item(index);
0974: String nodeName = oneChild.getNodeName();
0975:
0976: if (nodeName != null) {
0977: if (nodeName.equals("block")) {
0978: Block b = (Block) Block.fromXML(oneChild);
0979:
0980: if (b != null) {
0981: cr.addBlock(b);
0982: }
0983: } else if (nodeName.equals("input")) {
0984: Input i = (Input) Input.fromXML(oneChild);
0985:
0986: if (i != null) {
0987: cr.addInput(i);
0988: }
0989: } else if (nodeName.equals("output")) {
0990: Output o = (Output) Output.fromXML(oneChild);
0991:
0992: if (o != null) {
0993: cr.addOutput(o);
0994: }
0995: } else if (nodeName.equals("transition")) {
0996: Transition t = (Transition) Transition
0997: .fromXML(oneChild);
0998:
0999: if (t != null) {
1000: cr.addTransition(t);
1001: }
1002: }
1003: }
1004:
1005: /* if nodeName != null */
1006: }
1007:
1008: /* For each child node */
1009: } catch (ClassCastException cce) {
1010: cce.printStackTrace();
1011: throw new ControllerException("Error Loading Subobjects "
1012: + "for ControllerResponse: " + cce.getMessage());
1013: }
1014:
1015: return cr;
1016: }
1017:
1018: /**
1019: * get title
1020: * title and name are synonymous--easier for JSTL
1021: *
1022: * @return java.lang.String The Title of the controller
1023: */
1024: public String getName() {
1025: return getTitle();
1026: }
1027:
1028: /**
1029: * get title
1030: * title and name are synonymous--easier for JSTL
1031: *
1032: * @return java.lang.String The Title of the controller
1033: */
1034: public String getTitle() {
1035: try {
1036: String temp = getString(title);
1037:
1038: if (temp == null) {
1039: temp = title;
1040: }
1041:
1042: return temp;
1043: } catch (Exception e) {
1044: return title;
1045: }
1046: }
1047:
1048: /**
1049: * Get a specific transition item.
1050: *
1051: * @param transitionName the name of the transition
1052: * @return Transition named in parameter
1053: * @throws ControllerException upon error
1054: */
1055: public Transition getTransition(String transitionName)
1056: throws ControllerException {
1057: validState();
1058:
1059: if (transitionCache != null) {
1060: return (Transition) transitionCache.get(transitionName);
1061: }
1062:
1063: return null;
1064: }
1065:
1066: /* getTransition(String) */
1067:
1068: /**
1069: * The getTransitions method is called by the client to this controller in
1070: * order to determine what the possible next states are from the current
1071: * state. The controller uses the contents of the current state (e.g.
1072: * parameters) to determine where it is possible for this user to go next.
1073: *
1074: * @return A Vector of Transition objects representing the transitions that
1075: * can be taken by the user at this point to select new states
1076: */
1077: public final Vector getTransitions() {
1078: validState();
1079:
1080: if (transitionCacheOrdered != null) {
1081: return transitionCacheOrdered;
1082: }
1083:
1084: return null;
1085: }
1086:
1087: /* getTransitions() */
1088:
1089: /**
1090: * Retrieve the Blocks as a map so that JSTL can cope with navigating the
1091: * ControllerResponse through a named fashion
1092: *
1093: * @return java.util.Map
1094: * @throws ControllerException upon error
1095: */
1096: public Map getNamedBlocks() throws ControllerException {
1097: validState();
1098:
1099: return blockCache;
1100: }
1101:
1102: /**
1103: * Retrieve the Outputs as a map so that JSTL can cope with navigating the
1104: * ControllerResponse through a named fashion
1105: *
1106: * @return java.util.Map
1107: * @throws ControllerException upon error
1108: */
1109: public Map getNamedOutputs() throws ControllerException {
1110: validState();
1111:
1112: return outputCache;
1113: }
1114:
1115: /**
1116: * Retrieve the Transitions as a map so that JSTL can cope with navigating
1117: * the ControllerResponse through a named fashion
1118: *
1119: * @return java.util.Map
1120: * @throws ControllerException upon error
1121: */
1122: public Map getNamedTransitions() throws ControllerException {
1123: validState();
1124:
1125: return transitionCache;
1126: }
1127:
1128: /**
1129: * Set the user string value
1130: *
1131: * @param newUser the new user.
1132: * @throws ControllerException upon error
1133: */
1134: public synchronized void setUser(String newUser)
1135: throws ControllerException {
1136: getRequest().setUser(newUser);
1137: }
1138:
1139: /**
1140: * Get the database from the request, if there is a request available
1141: *
1142: * @return the User as specified by the request.
1143: * @throws ControllerException upon error
1144: */
1145: public String getUser() throws ControllerException {
1146: return getRequest().getUser();
1147: }
1148:
1149: /* getUser() */
1150:
1151: /**
1152: * Convenience method to allow us to add any ControllerElement to this
1153: * controllers inputs, outputs or transitions
1154: *
1155: * @param t the new ControllerElement
1156: * @throws ControllerException upon error [Such as if the ControllerElement
1157: * is an unrecognized type]
1158: */
1159: public void add(ControllerElement t) throws ControllerException {
1160: if (t instanceof Input) {
1161: addInput((Input) t);
1162: } else if (t instanceof Output) {
1163: addOutput((Output) t);
1164: } else if (t instanceof Transition) {
1165: addTransition((Transition) t);
1166: } else if (t instanceof Block) {
1167: addBlock((Block) t);
1168: } else {
1169: throw new ControllerException("Element " + t.getName()
1170: + " is not a Block, Input, Output or Transition");
1171: }
1172: }
1173:
1174: /* add(ControllerElement) */
1175:
1176: /**
1177: * addAutoInput is a convenience method that creates a new Input object
1178: * based on the specified field parameters and adds the input object to
1179: * this controller object. Creation date: (7/20/00 3:43:14 PM)
1180: *
1181: * @param fieldName java.lang.String
1182: * @param friendlyName the friendly name
1183: * @param defaultValue java.lang.String
1184: * @param displayLength the length of the display
1185: * @param maxLength the maximum length of the input
1186: * @param validValues a Vector of valid value objects for dropdowns
1187: * @throws ControllerException upon error
1188: */
1189: public void addAutoInput(String fieldName, String friendlyName,
1190: String defaultValue, int displayLength, int maxLength,
1191: Vector validValues) throws ControllerException {
1192: addAutoInput(fieldName, friendlyName, defaultValue,
1193: displayLength, maxLength, validValues, "text");
1194: }
1195:
1196: /* addAutoInput(STring, String, String, int, int, Vector) */
1197:
1198: /**
1199: * addAutoInput is a convenience method that creates a new Input object
1200: * based on the specified field parameters and adds the input object to
1201: * this controller object. Creation date: (7/20/00 3:43:14 PM) author:
1202: * Shash Chatterjee
1203: *
1204: * @param fieldName java.lang.String
1205: * @param dbobj com.jcorporate.expresso.core.dbobj.DBObject
1206: * @param defaultValue java.lang.String
1207: * @throws ControllerException upon error
1208: */
1209: public void addAutoInput(String fieldName, DBObject dbobj,
1210: String defaultValue) throws ControllerException {
1211: int displayLength = 0;
1212: int maxLength = 0;
1213: String friendlyName = null;
1214: Vector validValues = null;
1215: JDBCObjectMetaData metadata = dbobj.getJDBCMetaData();
1216:
1217: try {
1218: if (!metadata.isField(fieldName)) {
1219: throw new ControllerException(
1220: "The field name specified is not valid for this DBObject.");
1221: }
1222:
1223: friendlyName = metadata.getDescription(fieldName);
1224: maxLength = Integer.parseInt(metadata.getLength(fieldName));
1225: displayLength = maxLength;
1226:
1227: if (displayLength > 40) {
1228: displayLength = 40;
1229: }
1230:
1231: if (metadata.isMultiValued(fieldName)) {
1232: validValues = dbobj.getValidValues(fieldName);
1233: }
1234:
1235: if (defaultValue == null) {
1236: defaultValue = dbobj.getField(fieldName);
1237: }
1238:
1239: addAutoInput(fieldName, friendlyName, defaultValue,
1240: displayLength, maxLength, validValues, metadata
1241: .getType(fieldName));
1242: } catch (DBException dbe) {
1243: throw new ControllerException(
1244: "There was a problem accessing the "
1245: + "DBObject for autoInput generation", dbe);
1246: }
1247: }
1248:
1249: /* addAutoInput(String, DBObject, String) */
1250:
1251: /**
1252: * addAutoInput is a convenience method that creates a new Input object
1253: * based on the specified field parameters and adds the input object to
1254: * this controller object. Creation date: (7/20/00 3:43:14 PM) author:
1255: * Adam Rossi, PlatinumSolutions
1256: *
1257: * @param fieldName java.lang.String
1258: * @param dbClassName java.lang.String
1259: * @param defaultValue java.lang.String
1260: * @throws ControllerException upon error
1261: */
1262: public void addAutoInput(String fieldName, String dbClassName,
1263: String defaultValue) throws ControllerException {
1264: DBObject dbobj = null;
1265: int displayLength = 0;
1266: int maxLength = 0;
1267: String friendlyName = null;
1268: Vector validValues = null;
1269:
1270: try {
1271: try {
1272: Class clazz = ClassLocator.loadClass(dbClassName);
1273: dbobj = (DBObject) clazz.newInstance();
1274: } catch (Exception e) {
1275: throw new ControllerException(
1276: "The dbClass specified could not be loaded.");
1277: }
1278:
1279: DataObjectMetaData metadata = dbobj.getMetaData();
1280:
1281: if (!metadata.isField(fieldName)) {
1282: throw new ControllerException(
1283: "The field name specified is not valid for this DBObject.");
1284: }
1285:
1286: friendlyName = metadata.getDescription(fieldName);
1287: maxLength = Integer.parseInt(metadata.getLength(fieldName));
1288: displayLength = maxLength;
1289:
1290: if (displayLength > 40) {
1291: displayLength = 40;
1292: }
1293:
1294: if (metadata.isMultiValued(fieldName)) {
1295: validValues = dbobj.getValidValues(fieldName);
1296: }
1297:
1298: if (defaultValue == null) {
1299: defaultValue = dbobj.getField(fieldName);
1300: }
1301:
1302: addAutoInput(fieldName, friendlyName, defaultValue,
1303: displayLength, maxLength, validValues, metadata
1304: .getType(fieldName));
1305: } catch (DBException dbe) {
1306: throw new ControllerException(
1307: "There was a problem accessing the "
1308: + "DBObject for autoInput generation", dbe);
1309: }
1310: }
1311:
1312: /* addAutoInput(String, String, String) */
1313:
1314: /**
1315: * Convenience method to add an input for every non-secret field in a db
1316: * object to the current response, using the default values and valid
1317: * values provided by the db object itself
1318: *
1319: * @param myDBObj the dbobject to render to the controller response
1320: * @throws ControllerException upon error
1321: */
1322: public void addAutoInput(DBObject myDBObj)
1323: throws ControllerException {
1324: try {
1325: String oneFieldName = null;
1326: DataObjectMetaData metadata = myDBObj.getMetaData();
1327: String className = myDBObj.getClass().getName();
1328:
1329: for (Iterator e = metadata.getFieldListArray().iterator(); e
1330: .hasNext();) {
1331: oneFieldName = (String) e.next();
1332:
1333: if (!metadata.isSecret(oneFieldName)) {
1334: addAutoInput(oneFieldName, metadata
1335: .getDescription(oneFieldName), className,
1336: myDBObj.getField(oneFieldName));
1337: }
1338: }
1339:
1340: /* for each field */
1341: } catch (DBException de) {
1342: throw new ControllerException(de);
1343: }
1344: }
1345:
1346: /* addAutoInput(DBOBject) */
1347:
1348: /**
1349: * addAutoInput is a convenience method that creates a new Input object
1350: * based on the specified field parameters and adds the input object to
1351: * this controller object. Creation date: (7/20/00 3:43:14 PM) author:
1352: * Adam Rossi, PlatinumSolutions
1353: *
1354: * @param fieldName java.lang.String
1355: * @param friendlyName the description of the Input to set.
1356: * @param dbClassName java.lang.String
1357: * @param defaultValue java.lang.String
1358: * @throws ControllerException upon error
1359: */
1360: public void addAutoInput(String fieldName, String friendlyName,
1361: String dbClassName, String defaultValue)
1362: throws ControllerException {
1363: DBObject dbobj = null;
1364: int displayLength = 0;
1365: int maxLength = 0;
1366: Vector validValues = null;
1367:
1368: try {
1369: try {
1370: Class clazz = ClassLocator.loadClass(dbClassName);
1371: dbobj = (DBObject) clazz.newInstance();
1372: } catch (Exception e) {
1373: throw new ControllerException(
1374: "The dbClass specified could not be loaded.");
1375: }
1376:
1377: DataObjectMetaData metadata = dbobj.getMetaData();
1378:
1379: if (!metadata.isField(fieldName)) {
1380: throw new ControllerException(
1381: "The field name specified is not valid for this DBObject.");
1382: }
1383:
1384: maxLength = Integer.parseInt(metadata.getLength(fieldName));
1385: displayLength = maxLength;
1386:
1387: if (displayLength > 40) {
1388: displayLength = 40;
1389: }
1390:
1391: if (metadata.isMultiValued(fieldName)) {
1392: validValues = dbobj.getValidValues(fieldName);
1393: }
1394:
1395: if (defaultValue == null) {
1396: defaultValue = dbobj.getField(fieldName);
1397: }
1398:
1399: this .addAutoInput(fieldName, friendlyName, defaultValue,
1400: displayLength, maxLength, validValues, metadata
1401: .getType(fieldName));
1402: } catch (DBException dbe) {
1403: throw new ControllerException(
1404: "There was a problem accessing the "
1405: + "DBObject for autoInput generation: "
1406: + dbe.getMessage());
1407: }
1408: }
1409:
1410: /* addAuotoInput(String, String, String, String) */
1411:
1412: /**
1413: * addAutoInput is a convenience method that creates a new Input object
1414: * based on the specified field parameters and adds the input object to
1415: * this controller object. Creation date: (7/20/00 3:43:14 PM)
1416: *
1417: * @param fieldName java.lang.String
1418: * @param friendlyName the description of the input
1419: * @param defaultValue java.lang.String
1420: * @param displayLength display size of the Input
1421: * @param maxLength the maximum input length
1422: * @param validValues valid value Vector if needed for dropdown boxes
1423: * @param fieldType the type of the field such as "datetime", "varchar",
1424: * etc
1425: * @throws ControllerException upon error
1426: */
1427: public void addAutoInput(String fieldName, String friendlyName,
1428: String defaultValue, int displayLength, int maxLength,
1429: Vector validValues, String fieldType)
1430: throws ControllerException {
1431: Input oneInput = new Input();
1432:
1433: if ((displayLength == 0) || (maxLength == 0)) {
1434: if (fieldType.equalsIgnoreCase(DBField.DATETIME_TYPE)) {
1435: displayLength = maxLength = 19;
1436: }
1437: }
1438:
1439: oneInput.setName(fieldName);
1440: oneInput.setLabel(friendlyName);
1441: oneInput.setDisplayLength(displayLength);
1442: oneInput.setDefaultValue(StringUtil.notNull(defaultValue));
1443: oneInput.setMaxLength(maxLength);
1444:
1445: //Here we do a little more intelligent probing to determine the input
1446: //type.
1447: //Normally, we use a TEXTAREA only for text fields. However, if the
1448: //VARCHAR area is bigger than 150, we will use a textarea for that as well.
1449: boolean expandToTextArea = false;
1450:
1451: if (fieldType.equalsIgnoreCase(DBField.VARCHAR_TYPE)) {
1452: if (displayLength > 150) {
1453: expandToTextArea = true;
1454: }
1455: }
1456:
1457: if (validValues != null) {
1458: oneInput.setValidValues(validValues);
1459: oneInput.setType("LISTBOX");
1460: } else {
1461: if (fieldType.equalsIgnoreCase("text") || expandToTextArea) {
1462: oneInput.setType("TEXTAREA");
1463: } else if (fieldType.equalsIgnoreCase(DBField.VARCHAR_TYPE)) {
1464: oneInput.setType("TEXTFIELD");
1465: } else if (fieldType.equalsIgnoreCase("date")) {
1466: oneInput.setType("TEXTFIELD");
1467: oneInput.setDisplayLength(10);
1468: oneInput.setMaxLength(10);
1469: } else if (fieldType.equalsIgnoreCase("time")) {
1470: oneInput.setType("TEXTFIELD");
1471: oneInput.setDisplayLength(10);
1472: oneInput.setMaxLength(10);
1473: } else if (fieldType
1474: .equalsIgnoreCase(DBField.DATETIME_TYPE)) {
1475: oneInput.setType("TEXTFIELD");
1476: oneInput.setDisplayLength(21);
1477: oneInput.setMaxLength(21);
1478: } else {
1479: oneInput.setType("TEXTFIELD");
1480: }
1481: }
1482:
1483: addInput(oneInput);
1484: }
1485:
1486: /* addAutoInput(String, String, String, int, int, Vector) */
1487:
1488: /**
1489: * addAutoInputRenameField is a convenience method that creates a new Input
1490: * object based on the specified field parameters and adds the input
1491: * object to this controller object. This variation on addAutoInput allows
1492: * a user to force a field to be renamed in the INPUT object. This is
1493: * important when you have two DBOBjects with the same field name
1494: * rendering on the same page, and you still want to use AddAutoInput.
1495: * Creation date: 1/17/2002
1496: *
1497: * @param fieldName java.lang.String
1498: * @param renameFieldTo the field to rename to
1499: * @param dbobj com.jcorporate.expresso.core.dbobj.DBObject
1500: * @param defaultValue java.lang.String
1501: * @throws ControllerException upon error
1502: */
1503: public void addAutoInputRenameField(String fieldName,
1504: String renameFieldTo, DBObject dbobj, String defaultValue)
1505: throws ControllerException {
1506: //NOTE: I cut and pasted this method, and I have to do that.
1507: //All of the AddAuto* methods need to be rewritten, this is
1508: //getting out of hand. - Adam
1509: int displayLength = 0;
1510: int maxLength = 0;
1511: String friendlyName = null;
1512: Vector validValues = null;
1513: JDBCObjectMetaData metadata = dbobj.getJDBCMetaData();
1514:
1515: try {
1516: if (!metadata.isField(fieldName)) {
1517: throw new ControllerException(
1518: "The field name specified is not valid for this DBObject.");
1519: }
1520:
1521: friendlyName = metadata.getDescription(fieldName);
1522: maxLength = Integer.parseInt(metadata.getLength(fieldName));
1523: displayLength = maxLength;
1524:
1525: if (displayLength > 40) {
1526: displayLength = 40;
1527: }
1528:
1529: if (metadata.isMultiValued(fieldName)) {
1530: validValues = dbobj.getValidValues(fieldName);
1531: }
1532:
1533: if (defaultValue == null) {
1534: defaultValue = dbobj.getField(fieldName);
1535: }
1536:
1537: addAutoInput(renameFieldTo, friendlyName, defaultValue,
1538: displayLength, maxLength, validValues, metadata
1539: .getType(fieldName));
1540: } catch (DBException dbe) {
1541: throw new ControllerException(
1542: "There was a problem accessing the "
1543: + "DBObject for autoInput generation", dbe);
1544: }
1545: }
1546:
1547: /* addAutoInputRenameField(String, DBObject, String) */
1548:
1549: /**
1550: * Adds a Block to the response that will be formatted by the controller
1551: * handler
1552: *
1553: * @param newBlock the block instance to add
1554: * @throws ControllerException upon error
1555: */
1556: public void addBlock(Block newBlock) throws ControllerException {
1557: if (blockCache == null) {
1558: blockCache = new HashMap();
1559: }
1560:
1561: if (StringUtil.notNull(newBlock.getName()).equals("")) {
1562: int nextNum = blockCache.size() + 1;
1563: newBlock.setName("" + nextNum);
1564: }
1565:
1566: newBlock.setControllerResponse(this );
1567:
1568: synchronized (blockCache) {
1569: blockCache.put(newBlock.getName(), newBlock);
1570: }
1571:
1572: if (blockCacheOrdered == null) {
1573: blockCacheOrdered = new Vector();
1574: }
1575:
1576: blockCacheOrdered.addElement(newBlock);
1577: }
1578:
1579: /* addBlock(Block) */
1580:
1581: /**
1582: * @param errorMessage
1583: */
1584: public void addError(String errorMessage)
1585: throws ControllerException {
1586: ErrorCollection errs = getErrors();
1587:
1588: if (errs == null) {
1589: errs = new ErrorCollection();
1590: }
1591:
1592: errs.addError(errorMessage);
1593: saveErrors(errs);
1594: }
1595:
1596: /**
1597: * add an error code, and an associated arg for translating that error code
1598: *
1599: * @param errorMessage key to error msg found in message bundle
1600: * @param arg a replacement value to use in ${} replacement template
1601: * @see com.jcorporate.expresso.core.i18n.MessageBundle#getString(java.lang.String, java.lang.Object[])
1602: */
1603: public void addError(String errorMessage, Object arg)
1604: throws ControllerException {
1605: ErrorCollection errs = getErrors();
1606:
1607: if (errs == null) {
1608: errs = new ErrorCollection();
1609: }
1610:
1611: errs.addError(errorMessage, arg);
1612: saveErrors(errs);
1613: }
1614:
1615: /**
1616: * add an error code, and associated args for translating that error code
1617: *
1618: * @param errorMessage key to error msg found in message bundle
1619: * @param args an array of replacement value to use in ${} replacement templates
1620: * @see com.jcorporate.expresso.core.i18n.MessageBundle#getString(java.lang.String, java.lang.Object[])
1621: */
1622: public void addError(String errorMessage, Object[] args)
1623: throws ControllerException {
1624: ErrorCollection errs = getErrors();
1625:
1626: if (errs == null) {
1627: errs = new ErrorCollection();
1628: }
1629:
1630: errs.addError(errorMessage, args);
1631: saveErrors(errs);
1632: }
1633:
1634: /**
1635: * @param propName
1636: * @param errorMessage
1637: * @deprecated 7/04 v5.5 expresso uses only one property name, the default; use addError(String errmsg) instead
1638: */
1639: public void addError(String propName, String errorMessage)
1640: throws ControllerException {
1641: ErrorCollection errs = getErrors();
1642:
1643: if (errs == null) {
1644: errs = new ErrorCollection();
1645: }
1646:
1647: errs.addError(propName, errorMessage);
1648: saveErrors(errs);
1649: }
1650:
1651: /**
1652: * Add an Input to the ControllerResponse
1653: *
1654: * @param newInput the Input to add to the ControllerResponse
1655: * @throws ControllerException upon error
1656: */
1657: public void addInput(Input newInput) throws ControllerException {
1658: if (inputCache == null) {
1659: inputCache = new HashMap();
1660: }
1661:
1662: newInput.setControllerResponse(this );
1663:
1664: if (StringUtil.notNull(newInput.getName()).equals("")) {
1665: int nextNum = inputCache.size() + 1;
1666: newInput.setName("i" + nextNum);
1667: }
1668:
1669: synchronized (inputCache) {
1670: inputCache.put(newInput.getName(), newInput);
1671: }
1672:
1673: if (inputCacheOrdered == null) {
1674: inputCacheOrdered = new Vector();
1675: }
1676:
1677: inputCacheOrdered.addElement(newInput);
1678: }
1679:
1680: /* addInput(Input) */
1681:
1682: /**
1683: * Add an Output to the controller response object
1684: *
1685: * @param newOutput the new output to add
1686: * @throws ControllerException upon error
1687: */
1688: public void addOutput(Output newOutput) throws ControllerException {
1689: if (outputCache == null) {
1690: outputCache = new HashMap();
1691: }
1692:
1693: newOutput.setControllerResponse(this );
1694:
1695: if (StringUtil.notNull(newOutput.getName()).equals("")) {
1696: int nextNum = outputCache.size() + 1;
1697: newOutput.setName("o" + nextNum);
1698: }
1699:
1700: synchronized (outputCache) {
1701: outputCache.put(newOutput.getName(), newOutput);
1702: }
1703:
1704: if (outputCacheOrdered == null) {
1705: outputCacheOrdered = new Vector();
1706: }
1707:
1708: outputCacheOrdered.addElement(newOutput);
1709: }
1710:
1711: /* addOutput(Output) */
1712:
1713: /**
1714: * Add a Transition to this ControllerResponse
1715: *
1716: * @param newTransition the new Transition to add
1717: * @throws ControllerException upon error
1718: */
1719: public void addTransition(Transition newTransition)
1720: throws ControllerException {
1721: if (transitionCache == null) {
1722: transitionCache = new HashMap();
1723: }
1724:
1725: if (StringUtil.notNull(newTransition.getName()).equals("")) {
1726: /* Assign it a name */
1727: int nextNum = transitionCache.size() + 1;
1728: newTransition.setName("t" + nextNum);
1729: }
1730:
1731: synchronized (transitionCache) {
1732: transitionCache.put(newTransition.getName(), newTransition);
1733: }
1734:
1735: newTransition.setControllerResponse(this );
1736:
1737: if (transitionCacheOrdered == null) {
1738: transitionCacheOrdered = new Vector();
1739: }
1740:
1741: transitionCacheOrdered.addElement(newTransition);
1742: }
1743:
1744: /* addTransition(Transition) */
1745:
1746: /**
1747: * AutoValidate is a quick way to validate the fields of a specified dbobj.
1748: * Creation date: (7/19/00 6:06:21 PM)
1749: *
1750: * @param checkClassName the class name to validate
1751: * @param errorCollection where Errors are saved to
1752: * @throws ValidationException The exception description.
1753: * @throws ControllerException upon error
1754: */
1755: public void autoValidate(String checkClassName,
1756: ErrorCollection errorCollection)
1757: throws ValidationException, ControllerException {
1758: String paramName = null;
1759: ValidationItem vi = null;
1760: StringUtil.assertNotBlank(checkClassName,
1761: "The checkClassName cannot be null");
1762:
1763: ValidationSet validSet = new ValidationSet();
1764:
1765: for (Enumeration e = getRequest().getParameters().keys(); e
1766: .hasMoreElements();) {
1767: paramName = (String) e.nextElement();
1768: vi = new ValidationItem(paramName, false, checkClassName);
1769: validSet.setValidationItem(vi);
1770: }
1771:
1772: validate(validSet, errorCollection);
1773: }
1774:
1775: /* autoValidate(String, ErrorCollection) */
1776:
1777: /**
1778: * AutoValidate is a quick way to validate the fields of a specified dbobj.
1779: * This method has not been tested and may not be correct. This methods
1780: * takes an optional requiredFields vector, which just tells the
1781: * validation routine which inputs are required. Creation date: (7/19/00
1782: * 6:06:21 PM)
1783: *
1784: * @param checkClassName the class name to cehck
1785: * @param errorCollection the error collection to save errors to
1786: * @param requiredFields the field anmes that are required
1787: * @throws ValidationException The exception description.
1788: * @throws ControllerException upon error
1789: */
1790: public void autoValidate(String checkClassName,
1791: ErrorCollection errorCollection, Vector requiredFields)
1792: throws ValidationException, ControllerException {
1793: if (requiredFields == null) {
1794: requiredFields = new Vector();
1795: }
1796:
1797: String fieldName = null;
1798: ValidationItem vi = null;
1799:
1800: if ((checkClassName == null) || "".equals(checkClassName)) {
1801: throw new ValidationException(
1802: "The checkClassName cannot be null");
1803: }
1804:
1805: ValidationSet validSet = new ValidationSet();
1806: DBObject dbobj = null;
1807:
1808: try {
1809: Class clazz = ClassLocator.loadClass(checkClassName);
1810: dbobj = (DBObject) clazz.newInstance();
1811: } catch (Exception e) {
1812: throw new ControllerException(
1813: "The dbClass specified could not be loaded.");
1814: }
1815:
1816: DataObjectMetaData metadata = dbobj.getMetaData();
1817: Iterator it = null;
1818:
1819: it = metadata.getFieldListArray().iterator();
1820:
1821: boolean requireField = false;
1822:
1823: while (it.hasNext()) {
1824: fieldName = (String) it.next();
1825:
1826: if (requiredFields.contains(fieldName)) {
1827: requireField = true;
1828: } else {
1829: requireField = false;
1830: }
1831:
1832: vi = new ValidationItem(fieldName, requireField,
1833: checkClassName);
1834: validSet.setValidationItem(vi);
1835: }
1836:
1837: validate(validSet, errorCollection);
1838: }
1839:
1840: /* autoValidate(String, ErrorCollection, Vector) */
1841:
1842: /**
1843: * Clear the Attribute values
1844: */
1845: public void clearAttributes() {
1846: myRequest.setAttributes(null);
1847: }
1848:
1849: /* clearAttributes() */
1850: /**
1851: *
1852: */
1853: public void clearBlockCache() {
1854: blockCache = null;
1855: }
1856:
1857: /* clearBlockCache() */
1858:
1859: /**
1860: * Completely clear the internal formResponseCache Creation date: (7/19/00
1861: * 6:53:58 PM) author: Adam Rossi, PlatinumSolutions
1862: *
1863: * @throws ControllerException upon error
1864: */
1865: public void clearFormCache() throws ControllerException {
1866: getDefaultForm().clear();
1867: }
1868:
1869: /* clearFormCache() */
1870:
1871: /**
1872: * Clear the input cache
1873: */
1874: public void clearInputCache() {
1875: inputCache = null;
1876: }
1877:
1878: /* clearInputCache() */
1879:
1880: /**
1881: * Clear the output cache
1882: */
1883: public void clearOutputCache() {
1884: outputCache = null;
1885: }
1886:
1887: /* clearOutputCache() */
1888: /**
1889: *
1890: */
1891: public void clearTransitionCache() {
1892: transitionCache = null;
1893: }
1894:
1895: /* clearTransitionCache() */
1896:
1897: /**
1898: * determine whether response has errors
1899: *
1900: * @return true if response has errors
1901: * @throws ControllerException if there is a problem
1902: */
1903: public boolean hasErrors() throws ControllerException {
1904: ErrorCollection errs = getErrors();
1905:
1906: if (errs == null) {
1907: return false;
1908: }
1909:
1910: if (errs.getErrorCount() > 0) {
1911: return true;
1912: }
1913:
1914: return false;
1915: }
1916:
1917: /**
1918: * determine whether response has errors of the particular label
1919: *
1920: * @return true if response has errors of the particular label
1921: * @throws ControllerException if there is a problem
1922: */
1923: public boolean hasErrors(String label) throws ControllerException {
1924: ErrorCollection errs = getErrors();
1925:
1926: if (errs == null) {
1927: return false;
1928: }
1929:
1930: if (errs.getErrors(label).hasNext()) {
1931: return true;
1932: }
1933:
1934: return false;
1935: }
1936:
1937: /**
1938: * Restore the controller form
1939: */
1940: public void restoreForm() throws ControllerException {
1941: getDefaultForm().restoreForm(getRequest());
1942: }
1943:
1944: /**
1945: * This method saves an ErrorCollection object to the request attributes
1946: * collection. The ErrorCollection is saved with the
1947: * ErrorCollection.ERRORCOLLECTIONKEY key. To retrieve the ErrorCollection
1948: * in a JSP or servlet: ErrorCollection errors =
1949: * (ErrorCollection)pageContext.getValue(
1950: * ErrorCollection.ERRORCOLLECTIONKEY, PageContext.REQUEST_SCOPE); Note:
1951: * This method does not need to be updated to GenericSession...it is
1952: * saving to the pageContext, not the session. Creation date: (7/19/00
1953: * 7:25:05 PM) author: Adam Rossi, PlatinumSolutions
1954: *
1955: * @param errorCollection java.jcorporate.expresso.core.controller.ErrorCollection
1956: * @throws ControllerException upon error
1957: */
1958: public void saveErrors(ErrorCollection errorCollection)
1959: throws ControllerException {
1960: ControllerRequest req = getRequest();
1961: HttpServletRequest hreq = null;
1962:
1963: if (req instanceof ServletControllerRequest) {
1964: ServletControllerRequest sreq = (ServletControllerRequest) req;
1965: hreq = (HttpServletRequest) sreq.getServletRequest();
1966: }
1967:
1968: // Remove any errorCollection attribute if none are required
1969: if ((errorCollection == null)
1970: || (errorCollection.getErrorCount() == 0)) {
1971: req.getSession().setAttribute(Globals.ERROR_KEY, null);
1972:
1973: if (hreq != null) {
1974: hreq.setAttribute(Globals.ERROR_KEY, null);
1975: }
1976:
1977: return;
1978: }
1979:
1980: // Save the errorCollection
1981: req.getSession().setAttribute(Globals.ERROR_KEY,
1982: errorCollection);
1983:
1984: if (hreq != null) {
1985: hreq.setAttribute(Globals.ERROR_KEY, errorCollection);
1986: }
1987: }
1988:
1989: /* saveErrors(ErrorCollection) */
1990:
1991: /**
1992: * Convert the controller response to an xml document fragment.
1993: *
1994: * @return an xml document
1995: * @throws ControllerException upon error
1996: */
1997: public synchronized String toXML() throws ControllerException {
1998: FastStringBuffer returnBuffer = FastStringBuffer.getInstance();
1999: String returnValue = null;
2000:
2001: try {
2002: returnBuffer.append("<controller-response name=\""
2003: + myControllerClass + "\"");
2004:
2005: if (title != null) {
2006: returnBuffer.append(" title=\"" + title + "\"");
2007: }
2008:
2009: if (requestedState != null) {
2010: returnBuffer.append(" requestedState=\""
2011: + requestedState + "\"");
2012: }
2013:
2014: if (style != null) {
2015: returnBuffer.append(" style=\"" + style + "\"");
2016: }
2017:
2018: returnBuffer.append(">\n");
2019:
2020: ErrorCollection ec = getErrors();
2021:
2022: if ((ec != null) && (ec.getErrorCount() > 0)) {
2023: returnBuffer.append("<errors>");
2024:
2025: for (Iterator i = ec.getErrors(); i.hasNext();) {
2026: ActionError oneError = (ActionError) i.next();
2027: returnBuffer.append("<error-message>");
2028: returnBuffer.append(oneError.getKey());
2029: returnBuffer.append("</error-message>");
2030: }
2031:
2032: returnBuffer.append("</errors>");
2033: }
2034:
2035: Vector blockList = getBlocks();
2036: Block oneBlock = null;
2037:
2038: if (blockList != null) {
2039: /* for each block */
2040: for (Enumeration bl = blockList.elements(); bl
2041: .hasMoreElements();) {
2042: oneBlock = (Block) bl.nextElement();
2043: returnBuffer = oneBlock.toXML(returnBuffer);
2044: }
2045:
2046: /* each block */
2047: }
2048:
2049: Vector outputs = getOutputs();
2050:
2051: if (outputs != null) {
2052: for (Enumeration eo = outputs.elements(); eo
2053: .hasMoreElements();) {
2054: returnBuffer = ((ControllerElement) eo
2055: .nextElement()).toXML(returnBuffer);
2056: }
2057: }
2058:
2059: Vector inputs = getInputs();
2060:
2061: if (inputs != null) {
2062: for (Enumeration ei = inputs.elements(); ei
2063: .hasMoreElements();) {
2064: returnBuffer = ((ControllerElement) ei
2065: .nextElement()).toXML(returnBuffer);
2066: }
2067: }
2068:
2069: Vector transitions = getTransitions();
2070:
2071: if (transitions != null) {
2072: for (Enumeration et = transitions.elements(); et
2073: .hasMoreElements();) {
2074: returnBuffer = ((ControllerElement) et
2075: .nextElement()).toXML(returnBuffer);
2076: }
2077: }
2078:
2079: returnBuffer.append("</controller-response>");
2080: returnValue = returnBuffer.toString();
2081: } finally {
2082: returnBuffer.release();
2083: returnBuffer = null;
2084: }
2085:
2086: return returnValue;
2087: }
2088:
2089: /**
2090: * The validate method is a quick and easy way to test user input. We are
2091: * trying to ensure that required fields are completed, and that the input
2092: * is correct based on the corresponding dbobj.checkField() method.
2093: * Creation date: (7/19/00 3:49:16 PM)
2094: *
2095: * @param validSet com.jcorporate.expresso.core.controller.ValidationSet
2096: * @param errorCollection com.jcorporate.expresso.core.controller.ErrorCollection
2097: * @throws ValidationException upon error
2098: * @deprecated See ControllerRequest.validateDBObject instead....
2099: */
2100: public void validate(ValidationSet validSet,
2101: ErrorCollection errorCollection) throws ValidationException {
2102: Vector validationVector = validSet.getValidationItems();
2103: ValidationItem vi = null;
2104: Hashtable checkClassCache = new Hashtable();
2105: String fieldValue = null;
2106: String fieldName = null;
2107: String friendlyFieldName = null;
2108: String checkClassName = null;
2109: String dbFieldName = null;
2110: DBObject dbobject = null;
2111: boolean oneErrorFlag = false;
2112: boolean isDBField = false;
2113:
2114: /* Here we validate 2 things:
2115: 1. If the field is required, but there is no value, we add an error
2116: 2. If the field is there, we check to see if the checkField() method of the
2117: corresponding dbobject passes the input
2118: */
2119: try {
2120: for (int i = 0; i < validationVector.size(); i++) {
2121: vi = (ValidationItem) validationVector.elementAt(i);
2122: vi.checkThisItem();
2123: fieldName = StringUtil.notNull(vi.getFieldName());
2124: fieldValue = this .getFormCache(fieldName);
2125: friendlyFieldName = StringUtil.notNull(vi
2126: .getFriendlyFieldName());
2127: checkClassName = StringUtil.notNull(vi
2128: .getCheckClassName());
2129: dbFieldName = StringUtil.notNull(vi.getDbFieldName());
2130:
2131: // The dbFieldName is optional. If it is blank, we assume the
2132: // fieldName is the same as the dbFieldName
2133: if (dbFieldName.equals("")) {
2134: dbFieldName = fieldName;
2135: }
2136:
2137: oneErrorFlag = false;
2138:
2139: // We first make sure that we have a cached copy of the checker
2140: // DBObject class, if one is specified in the ValidationItem
2141: if (!checkClassName.equals("")) {
2142: if (!checkClassCache.contains(checkClassName)) {
2143: //instantiate a new DBObject
2144: Class clazz = ClassLocator
2145: .loadClass(checkClassName);
2146: dbobject = (DBObject) clazz.newInstance();
2147: checkClassCache.put(checkClassName, dbobject);
2148:
2149: DataObjectMetaData metadata = dbobject
2150: .getMetaData();
2151: isDBField = metadata.isField(dbFieldName);
2152:
2153: if (isDBField) {
2154: // If the ValidationItem object was not given a friendly
2155: // name, we use the field Description from the DBObject
2156: if ("".equals(friendlyFieldName)) {
2157: friendlyFieldName = metadata
2158: .getDescription(dbFieldName);
2159: }
2160: }
2161: }
2162: }
2163:
2164: // End object cache check
2165: // Now we check to see if the field is required but not there
2166: if (vi.isRequired() && "".equals(fieldValue)) {
2167: oneErrorFlag = true;
2168:
2169: if (!"".equals(friendlyFieldName)) {
2170: errorCollection
2171: .addError("The "
2172: + friendlyFieldName
2173: + " field is required. Please complete this field.");
2174: }
2175: }
2176:
2177: // end required check
2178: // Now we check to see if the DBOBject accepts the input
2179: if ((!oneErrorFlag) && (isDBField)) {
2180: // Check to see if the field passes the dbobject validation
2181: if (checkClassCache.containsKey(checkClassName)) {
2182: dbobject = (DBObject) checkClassCache
2183: .get(checkClassName);
2184:
2185: try {
2186: dbobject
2187: .checkField(dbFieldName, fieldValue);
2188: } catch (DBException dbe) {
2189: oneErrorFlag = true;
2190:
2191: if (!"".equals(friendlyFieldName)) {
2192: errorCollection
2193: .addError("There was a problem "
2194: + "with your input for the "
2195: + friendlyFieldName
2196: + " field: "
2197: + dbe.getMessage());
2198: }
2199: }
2200: }
2201: }
2202: }
2203: } catch (Exception e) {
2204: e.printStackTrace();
2205: throw new ValidationException("Unable to validate '"
2206: + checkClassName + "'", e);
2207: }
2208: }
2209:
2210: /* validate(ValidationSet, ErrorCollection) */
2211:
2212: /**
2213: * Retrieve the DefaultForm object
2214: *
2215: * @return DefaultForm
2216: * @throws ControllerException upon error
2217: */
2218: protected DefaultForm getDefaultForm() throws ControllerException {
2219: String formKey = getRequest().getFormAttribute();
2220:
2221: if (StringUtil.notNull(formKey).equals("")) {
2222: throw new ControllerException(
2223: "No ActionForm has been specified for this Controller mapping,"
2224: + " unable to utilize form cache. Please set an action form in struts-config.xml or similar files"
2225: + " by setting name=\"default\" in the Action mapping. (i.e., use the default expresso formbean)");
2226: }
2227:
2228: DefaultForm myForm = (DefaultForm) getRequest().getSession()
2229: .getAttribute(formKey);
2230:
2231: if (myForm == null) {
2232: myForm = (DefaultForm) getRequest().getSession()
2233: .getPersistentAttribute(formKey);
2234: }
2235:
2236: if (myForm == null) {
2237: throw new ControllerException(
2238: "No ActionForm found for key '" + formKey
2239: + "' in request or session scope.");
2240: }
2241:
2242: return myForm;
2243: }
2244:
2245: /**
2246: * Tell this Controller object what Schema it belongs to. This is used when
2247: * the Controller tries to use it's "getString(String, Object[])" method
2248: * to prepare internationalized messages - it passes the call along to the
2249: * appropriate schema which knows how to locate the proper message file.
2250: *
2251: * @param schemaClass the schema class name to associate with this
2252: * controllerresposne
2253: */
2254: protected void setSchema(String schemaClass) {
2255: StringUtil.assertNotBlank(schemaClass,
2256: "Must specify a non-blank schema");
2257:
2258: if (schemaStack == null) {
2259: schemaStack = new Stack();
2260: }
2261:
2262: schemaStack.push(schemaClass);
2263: }
2264:
2265: /* setSchema(String) */
2266:
2267: /**
2268: * Check to see if we are currently in a valid state
2269: *
2270: * @return true if the state name is valid
2271: */
2272: protected boolean validState() {
2273: if (getCurrentState() == null) {
2274: return false;
2275: }
2276:
2277: return true;
2278: }
2279:
2280: /**
2281: * Set the current State object
2282: *
2283: * @param newState the new current state
2284: */
2285: void setCurrentState(State newState) {
2286: currentState = newState;
2287: }
2288:
2289: /**
2290: * Useful for JSTL iteration of all items in response.
2291: *
2292: * @return a Map of all nested elements keyed by controllerElement name.
2293: */
2294: public Map getNestedMap() throws ControllerException {
2295: HashMap mappedNested = new HashMap();
2296:
2297: Map map = this .getNamedBlocks();
2298: if (map != null) {
2299: mappedNested.putAll(map);
2300: }
2301:
2302: map = this .getNamedInputs();
2303: if (map != null) {
2304: mappedNested.putAll(map);
2305: }
2306:
2307: map = this .getNamedOutputs();
2308: if (map != null) {
2309: mappedNested.putAll(map);
2310: }
2311:
2312: map = this .getNamedTransitions();
2313: if (map != null) {
2314: mappedNested.putAll(map);
2315: }
2316:
2317: return mappedNested;
2318: }
2319:
2320: /**
2321: * return raw key, without running through msg bundle string translation--useful for when 'cloning' in Transition
2322: */
2323: public String getTitleKey() {
2324: return title;
2325: }
2326:
2327: }
|