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:
0065: package com.jcorporate.expresso.core.dbobj;
0066:
0067: import EDU.oswego.cs.dl.util.concurrent.ConcurrentReaderHashMap;
0068: import com.jcorporate.expresso.core.ExpressoSchema;
0069: import com.jcorporate.expresso.core.controller.Transition;
0070: import com.jcorporate.expresso.core.dataobjects.DataException;
0071: import com.jcorporate.expresso.core.dataobjects.DataFieldMetaData;
0072: import com.jcorporate.expresso.core.dataobjects.jdbc.JDBCObjectMetaData;
0073: import com.jcorporate.expresso.core.db.DBException;
0074: import com.jcorporate.expresso.core.db.config.JDBCConfig;
0075: import com.jcorporate.expresso.core.i18n.Messages;
0076: import com.jcorporate.expresso.core.misc.ConfigManager;
0077: import com.jcorporate.expresso.core.misc.ConfigurationException;
0078: import com.jcorporate.expresso.core.misc.StringUtil;
0079: import com.jcorporate.expresso.core.security.filters.FilterManager;
0080: import org.apache.log4j.Logger;
0081: import org.apache.oro.text.regex.MalformedPatternException;
0082: import org.apache.oro.text.regex.Pattern;
0083: import org.apache.oro.text.regex.PatternCompiler;
0084: import org.apache.oro.text.regex.Perl5Compiler;
0085:
0086: import java.util.ArrayList;
0087: import java.util.Enumeration;
0088: import java.util.HashMap;
0089: import java.util.Hashtable;
0090: import java.util.Iterator;
0091: import java.util.Locale;
0092: import java.util.Map;
0093: import java.util.Set;
0094: import java.util.StringTokenizer;
0095: import java.util.Vector;
0096:
0097: /**
0098: * This object contains the "definition" of the DBObject, while the DBObject
0099: * itself contains only the data itself.
0100: * One DBObjectDef object is stored in a static HashMap in the DBObject class,
0101: * and is looked up and referenced for all definitions of the structure of the given object.
0102: * <p/>
0103: * since this class is not threadsafe for adding information, it is imperitive
0104: * that all information addition, typically done when the first instance
0105: * of a DBObject is instantiated, is done in a synchronized context.
0106: *
0107: * @author Michael Nash
0108: */
0109: public class DBObjectDef implements JDBCObjectMetaData {
0110:
0111: private static final String OBJECT_NAME_NOT_ASSIGNED = "NOT ASSIGNED";
0112:
0113: /* the log */
0114: transient private static Logger log = Logger
0115: .getLogger(DBObjectDef.class);
0116:
0117: /**
0118: * Perl5 Regular Expression Compiler. The patterns generated by this compiler
0119: * are mainly stored in the field mask table.
0120: */
0121: transient private static PatternCompiler patternCompiler = new Perl5Compiler();
0122:
0123: /**
0124: * An instance of the singleton FilterManager class.
0125: */
0126: transient private static FilterManager filterManager = FilterManager
0127: .getInstance();
0128:
0129: ////////////////////////////////////////////////////////////////////
0130: // instance members
0131: /////////////////////////////////////////////////////////////////////
0132:
0133: /**
0134: * A hashtable of all of the DBField objects in this DBObject
0135: */
0136: private Map allFields = new ConcurrentReaderHashMap();
0137:
0138: /**
0139: * Vector containing the field names in the order they were added
0140: */
0141: private ArrayList fieldNamesInOrder = new ArrayList();
0142: private Map allKeys = new ConcurrentReaderHashMap();
0143: private ArrayList keyList = new ArrayList();
0144: private String objectDescription = "";
0145:
0146: /**
0147: * Vector containing the field names in the order they were added for
0148: * INPUT and OUTPUT parameters for store procedure
0149: * author Yves Henri AMAIZO
0150: */
0151: private Map allInParameters = new ConcurrentReaderHashMap();
0152: private ArrayList inParamList = new ArrayList();
0153: private Map allOutParameters = new ConcurrentReaderHashMap();
0154: private ArrayList outParamList = new ArrayList();
0155:
0156: /**
0157: * The detailObjsLocal local and detailObjsForeign hashtables holds one or more references to other
0158: * dbobject classes (the class name is the key), with the value
0159: * stored being the names of the field(s) in this class (pipe-delimited)
0160: * that relate to the primary key in the other object
0161: */
0162: private Hashtable detailObjsLocal = new Hashtable();
0163: private Hashtable detailObjsForeign = new Hashtable();
0164:
0165: /**
0166: * A vector of "transition" objects that can be displayed as tabs
0167: * available when DBMaint displays a DBObject of this type
0168: */
0169: private ArrayList transitionTabs = new ArrayList();
0170:
0171: /**
0172: * The list of all indicies used by this DBObject.<br>
0173: * <i>Please Note:</i> If there is no index associated with a dbobject
0174: * then indexList WILL be null.
0175: */
0176: private ArrayList indexList = null;
0177:
0178: /**
0179: * Table name of the "primary" table that this DB object refers to
0180: */
0181: private String tableName = "";
0182:
0183: /**
0184: * Store Procedure name of the "primary" table that this DB object refers to
0185: */
0186: private String storeProcedureName = ("");
0187:
0188: private boolean returningValue = false;
0189:
0190: /**
0191: * Database schema name of the "primary" table that this DB object refers to
0192: */
0193: private String dbSchemaName = ("");
0194:
0195: /**
0196: * Database catalogue name of the "primary" table that this DB object refers to
0197: */
0198: private String dbCatalogName = ("");
0199:
0200: /**
0201: * A default characterset to filter on.
0202: */
0203: private String charSet = "ISO-8859-1";
0204: private String mObjectName = OBJECT_NAME_NOT_ASSIGNED;
0205:
0206: /**
0207: * Do we log changes to this object
0208: */
0209: private boolean loggingEnabled = false;
0210:
0211: /**
0212: * What schema does this DB object belong to?
0213: */
0214: private String mySchema = ExpressoSchema.class.getName();
0215:
0216: /**
0217: * When we do an update, do we check if any records
0218: * were updated & throw if there were none?
0219: */
0220: private boolean checkZeroUpdate = true;
0221:
0222: transient private int cacheSize = -2;
0223:
0224: /**
0225: * Default Constructor. This allows a DB object to be dynamically
0226: * instantiated (e.g. loaded
0227: * with Class.forName()) and does all of the required initializations.
0228: */
0229: public DBObjectDef() {
0230: } /* DBObjectDef() */
0231:
0232: /**
0233: * Add a field with more details: This version allows the user to specify a
0234: * precision, for fields that use both a size and precision.
0235: *
0236: * @param fieldName Name of the field
0237: * @param fieldType Type of the field - this is the internal Expresso type,
0238: * mapping in DBField to a specific database data type.
0239: * @param fieldSize Size of the field
0240: * @param fieldPrecision The precision of the field
0241: * @param allowNull Does this field allow nulls?
0242: * @param fieldDescription A longer description of this field
0243: * (user-understandable hopefully!)
0244: */
0245: synchronized public void addField(String fieldName,
0246: String fieldType, int fieldSize, int fieldPrecision,
0247: boolean allowNull, String fieldDescription)
0248: throws DBException {
0249: if (ConfigManager.isReservedWord(fieldName)) {
0250: throw new DBException(
0251: "You cannot have a field name of "
0252: + fieldName
0253: + ". It is a reserved word. Check "
0254: + "com.jcorporate.expresso.core.misc.ReservedWords for a full list"
0255: + " of reservered words");
0256: }
0257:
0258: if (!DBField.allDataTypes.contains(fieldType)) {
0259: throw new DBException(
0260: "You cannot have a field type of : "
0261: + fieldType
0262: + ". It is not a recognized Expresso datatype."
0263: + " See: com.jcorporate.expresso.core.dbobj.DBField for a list of all recognized datatypes");
0264: }
0265:
0266: allFields
0267: .put(fieldName, new DBField(fieldName, fieldType,
0268: fieldSize, fieldPrecision, allowNull,
0269: fieldDescription));
0270:
0271: /**
0272: * If we're dealing with integer datatypes, lets be helpful and make sure
0273: * that the field is a valid integer format. Add the mask automatically
0274: */
0275: if (fieldType.equalsIgnoreCase(DBField.INTEGER_TYPE)
0276: || fieldType.equalsIgnoreCase(DBField.INT_TYPE)) {
0277:
0278: setMask(fieldName, DBObject.INT_MASK);
0279: setAttribute(fieldName, DBObject.ATTRIBUTE_ERROR_MESSAGE,
0280: "You must enter a valid integer for field: "
0281: + fieldDescription);
0282: }
0283:
0284: fieldNamesInOrder.add(fieldName);
0285: } /* addField(String, String, int, int, boolean, String) */
0286:
0287: /**
0288: * Sets the default value for a particular field
0289: *
0290: * @param fieldName The name of the field to set
0291: * @param fieldValue the default value to use
0292: * @throws DBException upon error
0293: */
0294: synchronized public void setDefaultValue(String fieldName,
0295: String fieldValue) throws DBException {
0296: if (!isField(fieldName)) {
0297: throw new DBException("No such field as '" + fieldName
0298: + "' in db object '" + getName() + "'");
0299: }
0300:
0301: getFieldMetadata(fieldName).setDefaultValue(fieldValue);
0302: }
0303:
0304: /**
0305: * @return default value if found, or null
0306: */
0307: public String getDefaultValue(String fieldName) {
0308: return getFieldMetadata(fieldName).getDefaultValue();
0309: }
0310:
0311: /**
0312: * Specify a new "detail" db object, and the fields in this object
0313: * they specify the fields in the related object
0314: *
0315: * @param objName The class name of the related object. There is assumed to be
0316: * a one to one or one to many relationship from this object to the specified object
0317: * @param keyFieldsLocal A pipe-delimited list of field names in this object
0318: * @param keyFieldsForeign A pipe-delimieted list of field names in the other object
0319: */
0320: synchronized public void addDetail(String objName,
0321: String keyFieldsLocal, String keyFieldsForeign)
0322: throws DBException {
0323: detailObjsLocal.put(objName, keyFieldsLocal);
0324: detailObjsForeign.put(objName, keyFieldsForeign);
0325: }
0326:
0327: public Enumeration getDetails() {
0328: return detailObjsLocal.keys();
0329: }
0330:
0331: public String getDetailFieldsLocal(String detailName) {
0332: return (String) detailObjsLocal.get(detailName);
0333: }
0334:
0335: public String getDetailFieldsForeign(String detailName) {
0336: return (String) detailObjsForeign.get(detailName);
0337: }
0338:
0339: /**
0340: * Add a field with more details: This version of addfield supplies
0341: * the allowNull flags and a description of the field to be used
0342: * when reporting errors to the user. This method is only used by the class that
0343: * extends DB object, and typically only in the setupFields() method.
0344: *
0345: * @param fieldName Name of the field
0346: * @param fieldType Type of the field - this is the "internal" Expresso type,
0347: * and is mapped to a specific type for the database depending on the
0348: * mappings in the properties file (if any). The DBField object contains
0349: * the default mappings.
0350: * @param fieldSize Size of this field, if specified for this type of field. For
0351: * fields that do not use a size (such as "date"), specify 0 for the size.
0352: * @param allowNull Does this field allow nulls?
0353: * @param fieldDescription A longer description of this field
0354: * (user-understandable hopefully!)
0355: */
0356: synchronized public void addField(String fieldName,
0357: String fieldType, int fieldSize, boolean allowNull,
0358: String fieldDescription) throws DBException {
0359:
0360: // try {
0361: // fieldDescription = Messages.getString(this.getDefaulfieldDescription);
0362: // } catch (IllegalArgumentException e) {
0363: // //Do nothing here.
0364: // }
0365:
0366: addField(fieldName, fieldType, fieldSize, allowNull, null,
0367: fieldDescription);
0368: }
0369:
0370: /**
0371: * Add a field with more details: This version of addfield supplies
0372: * the allowNull flags and a description of the field to be used
0373: * when reporting errors to the user. This method is only used by the class that
0374: * extends DB object, and typically only in the setupFields() method.
0375: *
0376: * @param fieldName Name of the field
0377: * @param fieldType Type of the field - this is the "internal" Expresso type,
0378: * and is mapped to a specific type for the database depending on the
0379: * mappings in the properties file (if any). The DBField object contains
0380: * the default mappings.
0381: * @param fieldSize Size of this field, if specified for this type of field. For
0382: * fields that do not use a size (such as "date"), specify 0 for the size.
0383: * @param allowNull Does this field allow nulls?
0384: * @param descriptionKey Key into the local language files for this
0385: * field's description
0386: * @param fieldDescription A longer description of this field
0387: * (user-understandable hopefully!)
0388: */
0389: synchronized public void addField(String fieldName,
0390: String fieldType, int fieldSize, boolean allowNull,
0391: String descriptionKey, String fieldDescription)
0392: throws DBException {
0393: if (ConfigManager.isReservedWord(fieldName)) {
0394: throw new DBException(
0395: "You cannot have a field name of "
0396: + fieldName
0397: + ". It is a reserved word. Check "
0398: + "com.jcorporate.expresso.core.misc.ConfigManager for a full list"
0399: + " of reservered words");
0400: }
0401:
0402: allFields.put(fieldName, new DBField(fieldName, fieldType,
0403: fieldSize, 0, allowNull, fieldDescription));
0404: fieldNamesInOrder.add(fieldName);
0405:
0406: /**
0407: * If we're dealing with integer datatypes, lets be helpful and make sure
0408: * that the field is a valid integer format. Add the mask automatically
0409: */
0410: if (fieldType.equalsIgnoreCase(DBField.INTEGER_TYPE)
0411: || fieldType.equalsIgnoreCase(DBField.INT_TYPE)) {
0412:
0413: setMask(fieldName, DBObject.INT_MASK);
0414: setAttribute(fieldName, DBObject.ATTRIBUTE_ERROR_MESSAGE,
0415: "You must enter a valid integer for field: "
0416: + fieldDescription);
0417: }
0418:
0419: } /* addField(String, String, int, boolean, String) */
0420:
0421: /**
0422: * Returns whether the field allows null values or not.
0423: *
0424: * @param fieldName name of the field
0425: * @return true if the field allows null
0426: */
0427: public boolean allowsNull(String fieldName) throws DBException {
0428: DBField oneField = (DBField) allFields.get(fieldName);
0429:
0430: if (oneField == null) {
0431: throw new DBException("(" + mObjectName + ") Field "
0432: + fieldName
0433: + " is not defined as a field in this DBObject");
0434: }
0435: if (oneField.allowsNull()) {
0436: return true;
0437: }
0438:
0439: return false;
0440: } /* allowsNull(String) */
0441:
0442: /**
0443: * Sets the field's regular expression validation mask. It also precompiles
0444: * the regular expression when it is called.
0445: *
0446: * @param fieldName The field name to associate with this regular expression
0447: * @param newMask The actual regular expression.
0448: */
0449: synchronized public void setMask(String fieldName, String newMask)
0450: throws DBException {
0451: DBField oneField = (DBField) allFields.get(fieldName);
0452:
0453: if (oneField == null) {
0454: throw new DBException("(" + mObjectName + ") Field "
0455: + fieldName
0456: + " is not defined as a field in this DBObject");
0457: }
0458:
0459: StringUtil.assertNotBlank(newMask,
0460: "DBObject.setMask: newMask parameter was null for field: "
0461: + fieldName);
0462:
0463: try {
0464: Pattern p = patternCompiler.compile(newMask,
0465: Perl5Compiler.READ_ONLY_MASK);
0466: oneField.setMask(p);
0467: } catch (MalformedPatternException mpe) {
0468: throw new DBException("Error compiling mask for field: "
0469: + fieldName, mpe);
0470: }
0471: } /* allowsNull(String) */
0472:
0473: /**
0474: * Removes an attribute from the field.
0475: *
0476: * @param fieldName the name of the field to remove the attribute
0477: * @param attribName the attribute name to remove
0478: */
0479: public void removeAttribute(String fieldName, String attribName) {
0480: DBField oneField = (DBField) allFields.get(fieldName);
0481:
0482: if (oneField == null) {
0483: return;
0484: }
0485:
0486: oneField.removeAttribute(attribName);
0487: }
0488:
0489: /**
0490: * @param fieldName the name of the field to set the attribute for
0491: * @param attribName the name of the attribute to set
0492: * @param attribValue the attribute to set
0493: */
0494: synchronized public void setAttribute(String fieldName,
0495: String attribName, Object attribValue) throws DBException {
0496: DBField oneField = (DBField) allFields.get(fieldName);
0497:
0498: if (oneField == null) {
0499: throw new DBException("(" + getName() + ") Field "
0500: + fieldName
0501: + " is not defined as a field in this DBObject");
0502: }
0503:
0504: oneField.setAttribute(attribName, attribValue);
0505: } /* allowsNull(String) */
0506:
0507: /**
0508: * Gets an <code>Object</code> attribute from the field's metatdata
0509: *
0510: * @param fieldName the name of the field for the attribute
0511: * @param attribName the name of the attribute
0512: * @return java.lang.Object
0513: */
0514: public Object getAttribute(String fieldName, String attribName)
0515: throws DBException {
0516: DBField oneField = (DBField) allFields.get(fieldName);
0517:
0518: if (oneField == null) {
0519: throw new DBException("(" + getName() + ") Field "
0520: + fieldName
0521: + " is not defined as a field in this DBObject");
0522: }
0523:
0524: return oneField.getAttribute(attribName);
0525: } /* allowsNull(String) */
0526:
0527: public Iterator getAttributesIterator(String fieldName)
0528: throws DBException {
0529: DBField oneField = (DBField) allFields.get(fieldName);
0530:
0531: if (oneField == null) {
0532: throw new DBException("(" + getName() + ") Field "
0533: + fieldName
0534: + " is not defined as a field in this DBObject");
0535: }
0536:
0537: return oneField.getAttributesIterator();
0538: }
0539:
0540: /**
0541: * Add an index to the table.
0542: *
0543: * @param indexName the name to give the index in the table
0544: * @param fieldNames A comma delimited list of all fields in the index.
0545: * @param isUnique - True if this field is a unique index.
0546: * @throws IllegalArgumentException of fieldName is null or doesn't exist
0547: * or if indexName is null
0548: */
0549: synchronized public void addIndex(String indexName,
0550: String fieldNames, boolean isUnique)
0551: throws IllegalArgumentException {
0552:
0553: //
0554: // Begin Argument Validation
0555: //
0556: if (indexName == null) {
0557: throw new IllegalArgumentException(Messages.getString(
0558: getSchema(), "DBOBJ_Add_Index_IllegalArgument1"));
0559: }
0560: if (fieldNames == null) {
0561: throw new IllegalArgumentException(Messages.getString(
0562: getSchema(), "DBOBJ_Add_Index_IllegalArgument2"));
0563: }
0564:
0565: //
0566: //Iterate through all the field names and make sure that they exist
0567: //
0568: String tempString = null;
0569:
0570: //Check to make sure that these fields really do exist
0571: //in the table they're being called for.
0572: StringTokenizer stk = new StringTokenizer(fieldNames, ",");
0573:
0574: while (stk.hasMoreTokens()) {
0575: tempString = stk.nextToken();
0576:
0577: //
0578: //Will throw a DBException if the field doesn't exist.
0579: //
0580: this .getDBField(tempString);
0581: }
0582: //
0583: // End Argument Validation
0584: //
0585: if (indexList == null) {
0586: indexList = new ArrayList();
0587: }
0588: try {
0589: indexList.add(new DBIndex(indexName, getTargetTable(),
0590: fieldNames, isUnique));
0591: } catch (DBException e) {
0592: throw new IllegalArgumentException(e.getMessage());
0593: }
0594: } /* addIndex(String, String, boolean) */
0595:
0596: /**
0597: * Add a new field to the list of fields that are part of this
0598: * object's key. Called after all of the "addField" calls in the setupFields()
0599: * method to specify which fields make up the primary key of this object.
0600: *
0601: * @param keyFieldName The name of the field to add as part of the key
0602: * @throws DBException if the field name is not valid or the field
0603: * allows nulls
0604: */
0605: synchronized public void addKey(String keyFieldName)
0606: throws DBException {
0607: DBField oneField = (DBField) allFields.get(keyFieldName);
0608:
0609: if (oneField == null) {
0610: throw new DBException(
0611: "("
0612: + getName()
0613: + ") Field "
0614: + keyFieldName
0615: + " is not defined as a field in this DBObject - cannot add "
0616: + "to key");
0617: }
0618: if (oneField.allowsNull()) {
0619: throw new DBException("(" + getName() + ") Field "
0620: + keyFieldName
0621: + " allows null - not suitable for inclusion "
0622: + "in key");
0623: }
0624: if (oneField.isVirtual()) {
0625: throw new DBException("(" + getName() + ") Field "
0626: + keyFieldName
0627: + " is a virtual field - not suitable for "
0628: + "inclusion in key");
0629: }
0630:
0631: if (oneField.isLongObjectType()) {
0632: throw new DBException(
0633: "("
0634: + getName()
0635: + ") Field "
0636: + keyFieldName
0637: + " allows arbitrarily long length, either text or binary - not suitable for inclusion "
0638: + "in key");
0639: }
0640:
0641: oneField.setKey(true);
0642: allKeys.put(keyFieldName, oneField);
0643:
0644: /* We must keep keys in order, so we add to keyList as well */
0645: keyList.add(keyFieldName);
0646: } /* addKey(String) */
0647:
0648: /**
0649: * Add a new virtual field to the definition of this object.
0650: * A virtual field is just like a regular one, except it's
0651: * not stored in the target table
0652: * A normal call to getField or setField on a virtual field will throw
0653: * an exception - getField and setField should be extended to handle the virtual
0654: * fields for a particular object correctly.
0655: *
0656: * @param fieldName Name of the field
0657: * @param fieldType Database type of the field
0658: * @param fieldSize Size of the field in characters
0659: * @param fieldDescription A longer description of this field
0660: * (user-understandable hopefully!)
0661: */
0662: synchronized public void addVirtualField(String fieldName,
0663: String fieldType, int fieldSize, String fieldDescription)
0664: throws DBException {
0665: addVirtualField(fieldName, fieldType, fieldSize, null,
0666: fieldDescription);
0667: }
0668:
0669: /**
0670: * Add a new virtual field to the definition of this object.
0671: * A virtual field is just like a regular one, except it's
0672: * not stored in the target table
0673: * A normal call to getField or setField on a virtual field will throw
0674: * an exception - getField and setField should be extended to handle the virtual
0675: * fields for a particular object correctly.
0676: *
0677: * @param fieldName Name of the field
0678: * @param fieldType Database type of the field
0679: * @param fieldSize Size of the field in characters
0680: * @param descriptionKey Key into the local language files
0681: * for the description of this field.
0682: * @param fieldDescription A longer description of this field
0683: * (user-understandable hopefully!)
0684: */
0685: synchronized public void addVirtualField(String fieldName,
0686: String fieldType, int fieldSize, String descriptionKey,
0687: String fieldDescription) throws DBException {
0688: DBField newField = new DBField(fieldName, fieldType, fieldSize,
0689: 0, true, fieldDescription);
0690: newField.setVirtual(true);
0691: allFields.put(fieldName, newField);
0692: fieldNamesInOrder.add(fieldName);
0693: } /* addVirtualField(String, String, int, String) */
0694:
0695: /**
0696: * Add a field with more details: This version allows the user to specify a
0697: * precision, for fields that use both a size and precision.
0698: *
0699: * @param fieldName Name of the field
0700: * @param fieldType Type of the field - this is the internal Expresso type,
0701: * mapping in DBField to a specific database data type.
0702: * @param fieldSize Size of the field
0703: * @param fieldPrecision The precision of the field
0704: * @param allowNull Does this field allow nulls?
0705: * @param fieldDescription A longer description of this field
0706: * (user-understandable hopefully!)
0707: */
0708: synchronized public void addVirtualField(String fieldName,
0709: String fieldType, int fieldSize, int fieldPrecision,
0710: boolean allowNull, String fieldDescription)
0711: throws DBException {
0712: addVirtualField(fieldName, fieldType, fieldSize,
0713: fieldPrecision, allowNull, null, fieldDescription);
0714: } /* addVirtualField */
0715:
0716: /**
0717: * Add a field with more details: This version allows the user to specify a
0718: * precision, for fields that use both a size and precision.
0719: *
0720: * @param fieldName Name of the field
0721: * @param fieldType Type of the field - this is the internal Expresso type,
0722: * mapping in DBField to a specific database data type.
0723: * @param fieldSize Size of the field
0724: * @param fieldPrecision The precision of the field
0725: * @param allowNull Does this field allow nulls?
0726: * @param descriptionKey Key into the local langauge files
0727: * with a description of this field
0728: * @param fieldDescription A longer description of this field
0729: * (user-understandable hopefully!)
0730: */
0731: synchronized public void addVirtualField(String fieldName,
0732: String fieldType, int fieldSize, int fieldPrecision,
0733: boolean allowNull, String descriptionKey,
0734: String fieldDescription) throws DBException {
0735: DBField newField = new DBField(fieldName, fieldType, fieldSize,
0736: fieldPrecision, allowNull, fieldDescription);
0737: newField.setVirtual(true);
0738: allFields.put(fieldName, newField);
0739: fieldNamesInOrder.add(fieldName);
0740: } /* addField(String, String, int, int, boolean, String) */
0741:
0742: /**
0743: * Disable change logging of this object
0744: */
0745: public synchronized void disableLogging() {
0746: loggingEnabled = false;
0747: } /* disableLogging() */
0748:
0749: /**
0750: * Enable logging of changes to this object. Change logging writes an entry to
0751: * the ChangeLog object every time an add, update, or delete is made to this
0752: * object. It is used to track important tables, such as user information,
0753: * account information, etc.
0754: */
0755: public synchronized void enableLogging() {
0756: loggingEnabled = true;
0757: } /* enableLogging() */
0758:
0759: public boolean isLoggingEnabled() {
0760: return loggingEnabled;
0761: }
0762:
0763: /**
0764: * Return the "allFields" Hashtable, which contains all of the DBField objects
0765: * that make up this DB object.
0766: *
0767: * @return Hashtable
0768: * @deprecated use getAllFieldsMap instead
0769: */
0770: synchronized public Hashtable getAllFields() {
0771: return new Hashtable(allFields);
0772: } /* getAllFields() */
0773:
0774: /**
0775: * Check if a certain name is a field (of any kind) in this DBOBject
0776: * since SQL is case insensitive, ignore case of field name for match,
0777: * this method takes longer, so use isField if the field name is known precisely
0778: *
0779: * @param fieldName the name of the field to check
0780: * @return internal format for field name if matched, or null if no match
0781: */
0782: public String isFieldIgnoreCase(String fieldName) {
0783: // try efficient test first
0784: if (isField(fieldName)) {
0785: return fieldName;
0786: }
0787:
0788: // now iterate to ignore case
0789: String internalFieldName = null;
0790: for (Iterator i = getFieldListIterator(); i.hasNext();) {
0791: String oneFieldName = (String) i.next();
0792:
0793: if (oneFieldName.equalsIgnoreCase(fieldName)) {
0794: internalFieldName = oneFieldName;
0795: break;
0796: }
0797: } /* for each field */
0798:
0799: return internalFieldName;
0800: }
0801:
0802: /**
0803: * Check if a certain name is a field (of any kind) in this DBOBject
0804: *
0805: * @param fieldName the name of the field to check
0806: * @return true if the field name exists
0807: */
0808: public boolean isField(String fieldName) {
0809: return allFields.get(fieldName) != null;
0810: }
0811:
0812: /**
0813: * Return the "allFields" Hashtable, which contains all of the DBField objects
0814: * that make up this DB object.
0815: *
0816: * @return java.util.HashMap
0817: */
0818: public HashMap getAllFieldsMap() {
0819: return new HashMap(allFields);
0820: }
0821:
0822: public HashMap getAllDBFields() {
0823: return new HashMap(allFields);
0824: }
0825:
0826: /**
0827: * Way to get an interator into the allFields objects
0828: *
0829: * @return an Iterator into the allFields HashMap
0830: */
0831: public Iterator getAllFieldsIterator() {
0832: return allFields.values().iterator();
0833: }
0834:
0835: /**
0836: * Retrieve an interator of key fields
0837: *
0838: * @return Iterator of key fields. [MetaData]
0839: */
0840: public Iterator getKeyFieldListIterator() {
0841: return keyList.iterator();
0842: }
0843:
0844: /**
0845: * Return the "allKeys" hash, containing the DBField objects that make up
0846: * the primary key for this db object.
0847: *
0848: * @return java.util.Hashtable
0849: * @deprecated Use getAllKeysMap or getAllKeysIterator instead
0850: */
0851: public Hashtable getAllKeys() {
0852: return new Hashtable(allKeys);
0853: } /* getAllKeys() */
0854:
0855: /**
0856: * Return the "allKeys" hash, containing the DBField objects that make up
0857: * the primary key for this db object.
0858: *
0859: * @return java.util.HashMap
0860: */
0861: public HashMap getAllKeysMap() {
0862: return new HashMap(allKeys);
0863: } /* getAllKeysMap() */
0864:
0865: /**
0866: * <b> Non-threadsafe </b> way to get an interator into the allKeys data
0867: * structure
0868: *
0869: * @return java.util.Iterator of key fields (DBField)
0870: */
0871: public Iterator getAllKeysIterator() {
0872: return allKeys.values().iterator();
0873: } /* getAllKeysIterator() */
0874:
0875: /**
0876: * return the current object's character set
0877: *
0878: * @return java.lang.String
0879: */
0880: public String getCharset() {
0881: return charSet;
0882: } /* getCharset() */
0883:
0884: /**
0885: * Get the current Cache size of this object. or -2 if it hasn't been
0886: * defined yet.
0887: *
0888: * @return current cache size value.
0889: */
0890: public int getCacheSize() {
0891: return cacheSize;
0892: }
0893:
0894: /**
0895: * Sets the cache size for this DBObject
0896: *
0897: * @param newValue the new value. Must be >= -2
0898: * @throws IllegalArgumentException if newValue < -2
0899: */
0900: public void setCacheSize(int newValue) {
0901: if (newValue < -2) {
0902: throw new java.lang.IllegalArgumentException(
0903: this .getClass().getName()
0904: + ".setCacheSize(int). newValue must be greater than or equal to -2");
0905: }
0906:
0907: cacheSize = newValue;
0908: }
0909:
0910: /**
0911: * Set a characterset for a particular field.
0912: *
0913: * @param newCharSet The name of the characterset that you will filter against.
0914: * For Western-Latin character sets use "ISO-8859-1" as the parameter.
0915: * Currently, no other charactersets are implemented. <br>
0916: * @throws DBException upon error
0917: * @see com.jcorporate.expresso.core.security.filters.FilterManager
0918: * for more information on Filters and implementing Filters for your own
0919: * characterset.
0920: * <p/>
0921: * Sets the characterset expected for a this DB object. A Table's default
0922: * is "ISO-8859-1"
0923: * @see com.jcorporate.expresso.core.security.filters.Filter
0924: * @see com.jcorporate.expresso.core.security.filters.ISO_8859_1
0925: */
0926: synchronized public void setCharset(String newCharSet)
0927: throws DBException {
0928: charSet = newCharSet;
0929: } /* setCharset(String) */
0930:
0931: /**
0932: * Return a description of this database object. If no explicit description has
0933: * been set, return the class name.
0934: *
0935: * @return A string describing this database object
0936: */
0937: public String getDescription() {
0938: if (StringUtil.notNull(objectDescription).equals("")) {
0939: return getName();
0940: } else {
0941: return objectDescription;
0942: }
0943: } /* getDescription() */
0944:
0945: /**
0946: * Retrieve the table description in a localized way. If l == null, the
0947: * function uses the system locale to generate the value. If unable to
0948: * locate the key in the message bundle, the key becomes the return value.
0949: *
0950: * @param l the Locale to use for rendering the table description
0951: * @return java.lang.String
0952: */
0953: public String getDescription(Locale l) {
0954: String key = this .getDescription();
0955:
0956: if (key == null || key.length() == 0) {
0957: return "Unknown Table";
0958: }
0959:
0960: if (l == null) {
0961: l = Locale.getDefault();
0962: }
0963:
0964: String schema = this .getSchema();
0965: if (schema == null || schema.length() == 0) {
0966: schema = com.jcorporate.expresso.core.ExpressoSchema.class
0967: .getName();
0968: }
0969:
0970: String returnValue;
0971: try {
0972: returnValue = Messages.getString(schema, l, key);
0973: } catch (IllegalArgumentException ex) {
0974: returnValue = key;
0975: }
0976:
0977: return returnValue;
0978:
0979: }
0980:
0981: /**
0982: * Return the long description of a field, if available
0983: *
0984: * @param fieldName The name of the field
0985: * @return String: The long description of the field (user-readable)
0986: * @throws DBException If there is no such field
0987: */
0988: public String getDescription(String fieldName) throws DBException {
0989: DBField oneField = (DBField) allFields.get(fieldName);
0990:
0991: if (oneField == null) {
0992: throw new DBException("No such field '" + fieldName + "'"
0993: + " in object '" + mObjectName + "'");
0994: }
0995:
0996: return oneField.getDescription();
0997: } /* getDescription(String) */
0998:
0999: /**
1000: * Retrieve an i18n'ized description as per the locale defined for the
1001: * 'client'
1002: *
1003: * @param l the Locale to use. If null, will use the System default Locale
1004: * @param fieldName the name of the field to retrieve the i18n'ized description
1005: * for.
1006: * @return an i18n'ized string. K
1007: */
1008: public String getDescription(java.util.Locale l, String fieldName) {
1009: String key = null;
1010: try {
1011: key = this .getDescription(fieldName);
1012: } catch (DBException ex) {
1013: log.error("Error getting field: " + fieldName, ex);
1014: }
1015:
1016: if (key == null) {
1017: return "Unknown Field";
1018: }
1019:
1020: if (l == null) {
1021: l = Locale.getDefault();
1022: }
1023:
1024: String schema = this .getSchema();
1025: if (schema == null || schema.length() == 0) {
1026: schema = com.jcorporate.expresso.core.ExpressoSchema.class
1027: .getName();
1028: }
1029:
1030: String returnValue;
1031: try {
1032: returnValue = Messages.getString(schema, l, key);
1033: } catch (IllegalArgumentException ex) {
1034: returnValue = key;
1035: }
1036:
1037: return returnValue;
1038: }
1039:
1040: /**
1041: * Get the DBField object specified by the fieldname
1042: *
1043: * @param fieldName the name of the field to retrieve
1044: * @return <code>DBField</code> object
1045: */
1046: public DBField getDBField(String fieldName) {
1047: DBField oneField = (DBField) allFields.get(fieldName);
1048:
1049: if (oneField == null) {
1050: throw new IllegalArgumentException("No such field as '"
1051: + fieldName + "' in object '" + mObjectName + "'");
1052: }
1053:
1054: return oneField;
1055: } /* getDBField(String) */
1056:
1057: /**
1058: * Get a list of all of the fields in this object
1059: *
1060: * @return A Vector of all of the fieldNames in this object
1061: * @deprecated Use getFieldListArray or getFieldListIterator instead
1062: */
1063: synchronized public Enumeration getFieldList() {
1064: return new Vector(fieldNamesInOrder).elements();
1065: } /* getFieldList() */
1066:
1067: /**
1068: * Get a list of all of the fields in this object This is threadsafe in that
1069: * it makes a new copy of the fieldNamesInOrder ArrayList
1070: *
1071: * @return A Vector of all of the fieldNames in this object
1072: */
1073: synchronized public ArrayList getFieldListArray() {
1074: return (ArrayList) fieldNamesInOrder.clone();
1075: }
1076:
1077: /**
1078: * Get a list of all of the fields in this object This iterator is not thread
1079: * safe.
1080: *
1081: * @return An iterator of the fieldNamesInOrder array list
1082: */
1083: public Iterator getFieldListIterator() {
1084: return fieldNamesInOrder.iterator();
1085: }
1086:
1087: /**
1088: * Get a list of all of the names of the key fields in this object
1089: *
1090: * @return A Vector of all of the names of the key fields
1091: * @deprecated Use getKeyFieldArray instead
1092: */
1093: public Enumeration getKeyFieldList() {
1094: Vector newKeys = new Vector(keyList);
1095:
1096: return newKeys.elements();
1097: } /* getKeyFieldList() */
1098:
1099: /**
1100: * Get a list of all of the names of the key fields in this object
1101: *
1102: * @return An ArrayList of all of the names of the key fields
1103: */
1104: public ArrayList getKeyFieldListArray() {
1105: return keyList;
1106: }
1107:
1108: /**
1109: * Return the length of a field
1110: *
1111: * @param fieldName The name of the field
1112: * @return String: The length of the field
1113: * @throws DBException If there is no such field in this object
1114: */
1115: public String getLength(String fieldName) throws DBException {
1116: DBField oneField = getDBField(fieldName);
1117:
1118: return oneField.getLength();
1119: } /* getLength(String) */
1120:
1121: public int getLengthInt(String fieldName) throws DBException {
1122: return new Integer(getLength(fieldName)).intValue();
1123: }
1124:
1125: /**
1126: * @param fieldName The name of the field
1127: * @return integer for demcimal precision of the field
1128: */
1129: public int getPrecision(String fieldName) throws DBException {
1130: DBField oneField = getDBField(fieldName);
1131:
1132: return oneField.getPrecision();
1133: } /* getPrecision(String) */
1134:
1135: /**
1136: * Get a field's lookup object - this is the name of another database
1137: * object that can be used to look up valid values for this object. The lookup
1138: * object for a field is set in the db objects setupFields method, and is used
1139: * by the DBMaint servlet to provide automatic lookup links for fields.
1140: *
1141: * @param fieldName Field name to check
1142: * @return String specifying the className of the lookup object
1143: * @throws DBException If the specified field does not exist.
1144: */
1145: public String getLookupObject(String fieldName) throws DBException {
1146: DBField oneField = getDBField(fieldName);
1147:
1148: return oneField.getLookupObject();
1149: } /* getLookupObject(String) */
1150:
1151: /**
1152: * When you get a lookup object, to perform a complete mapping between the
1153: * two, you need to know what field name in the remote object maps to this
1154: * field.
1155: *
1156: * @param fieldName the name of the field to look up.
1157: * @return java.lang.String or null if there is no lookup field
1158: * @throws IllegalArgumentException if the field name does not exist
1159: */
1160: public String getLookupField(String fieldName) {
1161: DBField oneField = getDBField(fieldName);
1162: if (oneField == null) {
1163: throw new IllegalArgumentException(
1164: "No field metadata found for field name: "
1165: + fieldName);
1166: }
1167:
1168: return oneField.getLookupField();
1169: }
1170:
1171: /**
1172: * Get the name of this object
1173: *
1174: * @return String The database object name, or the table name if none
1175: * has been assigned
1176: */
1177: public String getName() {
1178: if (mObjectName.equals(OBJECT_NAME_NOT_ASSIGNED)
1179: || "".equals(mObjectName) || mObjectName == null) {
1180: return tableName;
1181: } else {
1182: return mObjectName;
1183: }
1184: } /* getName() */
1185:
1186: /**
1187: * Return the Table Name of the current database object. Keep in mind
1188: * that a database object could update or affect other tables as well.
1189: *
1190: * @return String: Table name of the target table of this database object
1191: * @throws DataException upon error
1192: */
1193: public String getTargetTable() throws DataException {
1194: if (tableName == null) {
1195: throw new DataException("No table name supplied");
1196: }
1197:
1198: return tableName;
1199: } /* getTargetTable() */
1200:
1201: /**
1202: * Return the Schema Name of the current database object.
1203: *
1204: * @return String: Schema name of the target table of this database object
1205: * <p/>
1206: * author Yves Henri AMAIZO <amy_amaizo@compuserve.com>
1207: */
1208: public String getTargetDbSchema() {
1209: return dbSchemaName;
1210: } /* getTargetDbSchema() */
1211:
1212: /**
1213: * Return the Schema Name of the current database object.
1214: *
1215: * @return String: Schema name of the target table of this database object
1216: * <p/>
1217: * author Yves Henri AMAIZO <amy_amaizo@compuserve.com>
1218: */
1219: public String getTargetDbCatalog() {
1220: return dbCatalogName;
1221: }
1222:
1223: /**
1224: * Return the type of a field - this method returns the internal Expresso type
1225: *
1226: * @param fieldName The name of the field
1227: * @return String: The type of the field
1228: * @throws DBException If there is no such field in this object
1229: */
1230: public String getType(String fieldName) throws DBException {
1231: DBField oneField = getDBField(fieldName);
1232:
1233: return oneField.getTypeString();
1234: } /* getType(String) */
1235:
1236: /**
1237: * Get an array of DBIndex objects for purpose of
1238: * creating them through the schema. Return type
1239: * should actually be DBIndex. <i>Please Note</i> This may cause an
1240: * exception to be thrown if indexList is null. Call hasIndex() first
1241: * before calling getIndexArray
1242: *
1243: * @return Object[]
1244: */
1245: synchronized public Object[] getIndexArray() {
1246: return this .indexList.toArray();
1247: }
1248:
1249: /**
1250: * Returns true if an Index exists for this array.
1251: *
1252: * @return true if it has an index
1253: */
1254: public boolean hasIndex() {
1255: if (this .indexList == null) {
1256: return false;
1257: } else {
1258: return true;
1259: }
1260: }
1261:
1262: /**
1263: * This method will return a boolean true if the field is defined in the DBOBject,
1264: * false otherwise.
1265: * Creation date: (8/8/00 11:04:32 AM)
1266: *
1267: * @param fieldName java.lang.String
1268: * @return boolean
1269: */
1270: public boolean hasField(String fieldName) {
1271: if (allFields.containsKey(fieldName)) {
1272: return true;
1273: }
1274:
1275: return false;
1276: } /* hasField(String) */
1277:
1278: public FilterManager getFilterManager() {
1279: return filterManager;
1280: }
1281:
1282: /**
1283: * Method called to determine if a particular field is multi-valued,
1284: * that is does it have a set of specific values and descriptions
1285: *
1286: * @param fieldName Name of the field
1287: * @return boolean True if the field is multi-valued, false if not
1288: * @throws DBException If there is no such field
1289: */
1290: synchronized public boolean isMultiValued(String fieldName)
1291: throws DBException {
1292: DBField oneField = getDBField(fieldName);
1293:
1294: return oneField.isMultiValued();
1295: } /* isMultiValued(String) */
1296:
1297: /**
1298: * Is a given field readOnly - these fields are not offered for entry
1299: * when a form is produced by the generic database maintenance servlet
1300: *
1301: * @param fieldName name of the field to check
1302: * @return true of the field is "read only", false if it is not
1303: * @throws DBException Ff there is no such field
1304: */
1305: public boolean isReadOnly(String fieldName) throws DBException {
1306: DBField oneField = getDBField(fieldName);
1307:
1308: if (oneField == null) {
1309: throw new DBException("No such field '" + fieldName + "'"
1310: + "' in object '" + mObjectName + "'");
1311: }
1312:
1313: return oneField.isReadOnly();
1314: } /* isReadOnly(String) */
1315:
1316: /**
1317: * Is a given field 'secret' - these fields are not shown
1318: * when a list is produced by the generic database maintenance servlet (DBMaint).
1319: * This means that only users with update permission to the record can see the
1320: * value of the specified field.
1321: *
1322: * @param fieldName The name of the field to check
1323: * @return True if the field is 'secret', false if it is not
1324: * @throws DBException If there is no such field.
1325: * @see #setSecret(String)
1326: */
1327: public boolean isSecret(String fieldName) throws DBException {
1328: DBField oneField = getDBField(fieldName);
1329:
1330: return oneField.isSecret();
1331: } /* isSecret(String) */
1332:
1333: /**
1334: * Is a given field virtual? A virtual field is not stored in the target table
1335: * for this object - it may be computed, or stored in another table.
1336: *
1337: * @param fieldName The name of the field to check
1338: * @return True of the field is virtual, false if it is not
1339: * @throws DBException If there is no such field
1340: * @see #addVirtualField(String, String, int, String)
1341: */
1342: public boolean isVirtual(String fieldName) throws DBException {
1343: DBField oneField = getDBField(fieldName);
1344:
1345: return oneField.isVirtual();
1346: } /* isVirtual(String) */
1347:
1348: /**
1349: * Turn on or off the facility to verify that when an update is made that at
1350: * least one record got updated. If this flag is on, and no records get updated,
1351: * the update() method throws an Exception. Note that for some databases, if the
1352: * existing record is not changed (e.g. it was already identical to what
1353: * was being updated) this counts "no update" (notably, mySQL does this).
1354: *
1355: * @param newFlag True to turn on checking, false to turn it off
1356: */
1357: synchronized public void setCheckZeroUpdate(boolean newFlag) {
1358: checkZeroUpdate = newFlag;
1359: } /* setCheckZeroUpdate(boolean) */
1360:
1361: public boolean checkZeroUpdate() {
1362: return checkZeroUpdate;
1363: }
1364:
1365: /**
1366: * Set the description of this object
1367: *
1368: * @param newDescription A description of this database object
1369: */
1370: synchronized public void setDescription(String newDescription) {
1371: objectDescription = newDescription;
1372: } /* setDescription(String) */
1373:
1374: /**
1375: * Set a field's lookup object - this is the name of another database
1376: * object that can be used to look up valid values for this object. This value
1377: * is used by the DBMaint servlet to provide automatic lookup ability for
1378: * related fields.
1379: *
1380: * @param fieldName The field name that this lookup is associated with
1381: * @param objectName The db object used to look up valid values for this field.
1382: */
1383: synchronized public void setLookupObject(String fieldName,
1384: String objectName) throws DBException {
1385: DBField oneField = getDBField(fieldName);
1386: oneField.setLookupObject(objectName);
1387: } /* setLookupObject(String, String) */
1388:
1389: /**
1390: * Set this field to be multi-valued - e.g. there is a specific list of
1391: * values that are valid for this field. There should be code in the
1392: * getValidValues method that returns the valid values for the specified
1393: * multi-valued field.
1394: *
1395: * @param fieldName The name of the field to specify as multi-valued
1396: * @throws DBException If the field name given is not valid, or is a virtual field
1397: */
1398: synchronized public void setMultiValued(String fieldName)
1399: throws DBException {
1400: DBField oneField = getDBField(fieldName);
1401:
1402: if (oneField.isVirtual()) {
1403: throw new DBException("(" + mObjectName + ") Field '"
1404: + fieldName
1405: + "' is a virtual field - not suitable for "
1406: + "setting as multi-valued");
1407: }
1408:
1409: oneField.setMultiValued(true);
1410: } /* setMultiValued(String) */
1411:
1412: /**
1413: * Set the name of this object - this name is used to identify the db object
1414: * with a more human-readable description
1415: *
1416: * @param theName New name for this object
1417: */
1418: synchronized public void setName(String theName) {
1419: mObjectName = theName;
1420: } /* setName(String) */
1421:
1422: /**
1423: * Set a field as read-only - these fields are not offered for update
1424: * when a form is produced by the generic database maintenance servlet
1425: * (DBMaint). It does not otherwise affect the use of the field.
1426: * <p>Typical uses are for serial-numbered fields and timestamps</p>
1427: *
1428: * @param fieldName The name of the field to be reserved as normally read-only.
1429: * @throws DBException If there is no such field.
1430: */
1431: synchronized public void setReadOnly(String fieldName)
1432: throws DBException {
1433: DBField oneField = getDBField(fieldName);
1434: oneField.setReadOnly();
1435: } /* setReadOnly(String) */
1436:
1437: /**
1438: * Set a field as 'secret' - these fields are not shown
1439: * when a list is produced by the generic database maintenance servlet. In
1440: * this way, only users with update permission to the object can view the
1441: * values of "secret" fields.
1442: *
1443: * @param fieldName The name of the field to set as 'secret'
1444: * @throws DBException if the field does not exist
1445: */
1446: synchronized public void setSecret(String fieldName)
1447: throws DBException {
1448: DBField oneField = getDBField(fieldName);
1449: oneField.setSecret();
1450: } /* setSecret(String) */
1451:
1452: /**
1453: * Set a filter for a particular field. Check the documentation at
1454: *
1455: * @param fieldName The name of the field to set a particular filter for.
1456: * @param filterMethod The name of the filter method to use when calling a filter.
1457: * Can be one of three values:<br> See @see
1458: * com.jcorporate.expresso.core.security.filters.FilterManager.filterString for
1459: * more information on this parameter.
1460: * @throws DBException if: fieldName doesn't exist, or filterType String
1461: * isn't a valid value.
1462: * @see com.jcorporate.expresso.core.security.filters.FilterManager
1463: * for more information on Filters and implementing Filters for your own
1464: * characterset.
1465: */
1466: synchronized public void setStringFilter(String fieldName,
1467: String filterMethod) throws DBException {
1468:
1469: //
1470: //Parameter Check
1471: //
1472: if (!(filterMethod.equalsIgnoreCase("standardFilter")
1473: || filterMethod.equalsIgnoreCase("stripFilter") || filterMethod
1474: .equalsIgnoreCase("rawFilter"))) {
1475: throw new DBException("Undefined Filter Method: "
1476: + filterMethod);
1477: }
1478:
1479: DBField oneField = getDBField(fieldName);
1480: oneField.setFilterMethod(filterMethod);
1481: } /* setStringFilter(String, String) */
1482:
1483: /**
1484: * Set the target table for this DBObject. Note that an object
1485: * can span tables by the use of virtual fields, but that this table
1486: * is the default table for the object.
1487: *
1488: * @param theTable Table for this object
1489: */
1490: synchronized public void setTargetTable(String theTable)
1491: throws DBException {
1492: if (theTable.length() > 18) {
1493: log.warn("Table name is over 18 characters");
1494: }
1495: if (ConfigManager.isReservedWord(theTable)) {
1496: throw new DBException(
1497: "You cannot have a table name of "
1498: + theTable
1499: + ". It is a database reserved word. Check "
1500: + "com.jcorporate.expresso.core.misc.ReservedWords for a full list"
1501: + " of reservered words");
1502: }
1503:
1504: tableName = theTable;
1505: } /* setTargetTable(String) */
1506:
1507: /**
1508: * Set the target database schema for this DBObject.
1509: *
1510: * @param theSchema database schema for this object
1511: * @throws DBException author Yves Henri AMAIZO <amy_amaizo@compuserve.com>
1512: */
1513: synchronized public void setTargetDbSchema(String theSchema)
1514: throws DBException {
1515: if (theSchema.length() > 18) {
1516: log.warn("Schema name is over 18 characters");
1517: }
1518: if (ConfigManager.isReservedWord(theSchema)) {
1519: throw new DBException(
1520: "You cannot have a Schema name of "
1521: + theSchema
1522: + ". It is a database reserved word. Check "
1523: + "com.jcorporate.expresso.core.misc.ReservedWords for a full list"
1524: + " of reservered words");
1525: }
1526:
1527: dbSchemaName = theSchema;
1528: } /* setTargetSchema(String) */
1529:
1530: /**
1531: * Set the target database schema for this DBObject.
1532: *
1533: * @param theCatalog database schema for this object
1534: * @throws DBException author Yves Henri AMAIZO <amy_amaizo@compuserve.com>
1535: */
1536: synchronized public void setTargetDbCatalog(String theCatalog)
1537: throws DBException {
1538: if (theCatalog.length() > 18) {
1539: log.warn("Schema name is over 18 characters");
1540: }
1541: if (ConfigManager.isReservedWord(theCatalog)) {
1542: throw new DBException(
1543: "You cannot have a Catalog name of "
1544: + theCatalog
1545: + ". It is a database reserved word. Check "
1546: + "com.jcorporate.expresso.core.misc.ReservedWords for a full list"
1547: + " of reservered words");
1548: }
1549:
1550: dbCatalogName = theCatalog;
1551: } /* setTargetDbCatalog(String) */
1552:
1553: /**
1554: * @param schemaName the name of the schema
1555: */
1556: synchronized public void setSchema(String schemaName) {
1557: StringUtil.assertNotBlank(mySchema,
1558: "Schema name may not be null or blank");
1559: mySchema = schemaName;
1560: } /* setSchema(String) */
1561:
1562: /**
1563: * @return the className of the schema associated with this DBObject
1564: */
1565: public String getSchema() {
1566: return mySchema;
1567: } /* getSchema() */
1568:
1569: /**
1570: * <p>This convenience method iterates through all the
1571: * fields belonging to this <code>DBObject</code>
1572: * returns an array of field names ( <code>String</code> ).</p>
1573: *
1574: * @return String array of all field names in this object.
1575: * <p/>
1576: * author Peter Pilgrim <peter.pilgrim@db.com>
1577: * @see #getFieldList()
1578: */
1579: public String[] getFields() {
1580: int N = fieldNamesInOrder.size();
1581: String[] arr = new String[N];
1582:
1583: for (int j = 0; j < N; ++j) {
1584: arr[j] = (String) fieldNamesInOrder.get(j);
1585: }
1586:
1587: return arr;
1588: } /* getFields() */
1589:
1590: /**
1591: * ??????
1592: *
1593: * @param t ???
1594: */
1595: synchronized public void addTransition(Transition t)
1596: throws DBException {
1597: transitionTabs.add(t);
1598: }
1599:
1600: /**
1601: * ????????????
1602: *
1603: * @return Iterator to the TransitionTabs
1604: */
1605: public Iterator getTransitionsIterator() throws DBException {
1606: return transitionTabs.iterator();
1607: }
1608:
1609: /**
1610: * Retrieve a set of detail objects.
1611: *
1612: * @return java.util.Set
1613: */
1614: public Set getDetailSet() {
1615: return detailObjsLocal.keySet();
1616: }
1617:
1618: /**
1619: * Returns whether the field allows null values or not.
1620: *
1621: * @param fieldName name of the field
1622: * @return true if the field allows null
1623: */
1624: public boolean isAllowsNull(String fieldName) throws DBException {
1625: return allowsNull(fieldName);
1626: }
1627:
1628: /**
1629: * Retrieve the metadata for the field.
1630: *
1631: * @param fieldName the name of the field to retrieve the metadata for.
1632: * @return DataFieldMetaData instance for the specified field name.
1633: */
1634: public DataFieldMetaData getFieldMetadata(String fieldName) {
1635: return (DataFieldMetaData) allFields.get(fieldName);
1636: }
1637:
1638: /**
1639: * Retrieve all the attributes so you can iterate through them.
1640: *
1641: * @param fieldName the name of the field to retrieve.
1642: * @return java.util.Set of all the attribute names for the given field.
1643: */
1644: public java.util.Set getAllAttributes(String fieldName) {
1645: DBField oneField = (DBField) allFields.get(fieldName);
1646:
1647: if (oneField == null) {
1648: throw new IllegalArgumentException("(" + getName()
1649: + ") Field " + fieldName
1650: + " is not defined as a field in this DBObject");
1651: }
1652:
1653: return oneField.getAllAttributes();
1654: }
1655:
1656: /**
1657: * Return the Store procedure Name of the current database object. Keep in mind
1658: * that a database object could update or affect other tables as well.
1659: *
1660: * @return String: Store procedure name of the target table of this database object
1661: * @throws DataException upon error
1662: * <p/>
1663: * author Yves Henri AMAIZO
1664: */
1665: public String getTargetStoreProcedure() throws DataException {
1666: if (storeProcedureName == null) {
1667: throw new DataException("No store procedure name supplied");
1668: }
1669:
1670: return storeProcedureName;
1671: } /* getTargetTable() */
1672:
1673: /**
1674: * Set the target store procedure for this DBObject.
1675: *
1676: * @param theStoreProcedure Store procedure for this object
1677: */
1678: synchronized public void setTargetStoreProcedure(
1679: String theStoreProcedure) throws DBException {
1680: if (theStoreProcedure.length() > 18) {
1681: log.warn("Strore procedure name is over 18 characters");
1682: }
1683: if (ConfigManager.isReservedWord(theStoreProcedure)) {
1684: throw new DBException(
1685: "You cannot have a store procedure name of "
1686: + theStoreProcedure
1687: + ". It is a database reserved word. Check "
1688: + "com.jcorporate.expresso.core.misc.ReservedWords for a full list"
1689: + " of reservered words");
1690: }
1691:
1692: storeProcedureName = theStoreProcedure;
1693: tableName = theStoreProcedure;
1694: } /* setTargetStoreProcedure(String) */
1695:
1696: /**
1697: * Add a new field to the list of fields that are part of this
1698: * object's list of input parameters. Called after all of the "addField" calls in the setupFields()
1699: * method to specify which fields make up the parameter fields of this object.
1700: *
1701: * @param inFieldName The name of the field to add as part of the input parameter
1702: * @throws DBException if the field name is not valid or the field
1703: * allows nulls
1704: */
1705: synchronized public void addInParam(String inFieldName)
1706: throws DBException {
1707: DBField oneField = (DBField) allFields.get(inFieldName);
1708:
1709: if (oneField == null) {
1710: throw new DBException(
1711: "("
1712: + getName()
1713: + ") Field "
1714: + inFieldName
1715: + " is not defined as a field in this DBObject - cannot add "
1716: + "to input list parameter");
1717: }
1718: if (oneField.allowsNull()) {
1719: throw new DBException("(" + getName() + ") Field "
1720: + inFieldName
1721: + " allows null - not suitable for inclusion "
1722: + "in key");
1723: }
1724: if (oneField.isVirtual()) {
1725: throw new DBException("(" + getName() + ") Field "
1726: + inFieldName
1727: + " is a virtual field - not suitable for "
1728: + "inclusion in input list parameter");
1729: }
1730:
1731: if (oneField.isLongObjectType()) {
1732: throw new DBException(
1733: "("
1734: + getName()
1735: + ") Field "
1736: + inFieldName
1737: + " allows arbitrarily long length, either text or binary - not suitable for inclusion "
1738: + "in the input list parameter");
1739: }
1740:
1741: allInParameters.put(inFieldName, oneField);
1742:
1743: /* We must keep keys in order, so we add to keyList as well */
1744: inParamList.add(inFieldName);
1745: } /* addInParam(String) */
1746:
1747: /**
1748: * Add a new field to the list of fields that are part of this
1749: * object's list of output parameter. Called after all of the "addField" calls in the setupFields()
1750: * method to specify which fields make up the parameter fields of this object.
1751: *
1752: * @param outFieldName The name of the field to add as part of the output parameter
1753: * @throws DBException if the field name is not valid or the field
1754: * allows nulls
1755: */
1756: synchronized public void addOutParam(String outFieldName)
1757: throws DBException {
1758: DBField oneField = (DBField) allFields.get(outFieldName);
1759:
1760: if (oneField == null) {
1761: throw new DBException(
1762: "("
1763: + getName()
1764: + ") Field "
1765: + outFieldName
1766: + " is not defined as a field in this DBObject - cannot add "
1767: + "to the output list parameter");
1768: }
1769: if (oneField.allowsNull()) {
1770: throw new DBException("(" + getName() + ") Field "
1771: + outFieldName
1772: + " allows null - not suitable for inclusion "
1773: + "in the output list parameter");
1774: }
1775: if (oneField.isVirtual()) {
1776: throw new DBException("(" + getName() + ") Field "
1777: + outFieldName
1778: + " is a virtual field - not suitable for "
1779: + "inclusion in the output list parameter");
1780: }
1781:
1782: if (oneField.isLongObjectType()) {
1783: throw new DBException(
1784: "("
1785: + getName()
1786: + ") Field "
1787: + outFieldName
1788: + " allows arbitrarily long length, either text or binary - not suitable for inclusion "
1789: + "in the output list parameter");
1790: }
1791:
1792: allOutParameters.put(outFieldName, oneField);
1793:
1794: /* We must keep keys in order, so we add to keyList as well */
1795: outParamList.add(outFieldName);
1796: } /* addOutParam(String) */
1797:
1798: public boolean isReturningValue() {
1799: return returningValue;
1800: }
1801:
1802: /**
1803: * @param value returning value to be set
1804: */
1805: public void setReturningValue(boolean value) {
1806: returningValue = value;
1807: }
1808:
1809: /**
1810: * Check if a certain name is a INPUT field parameter(of any kind) in this DBOBject
1811: *
1812: * @param fieldName the name of the field to check
1813: * @return true if the field name exists
1814: */
1815: public boolean isOutField(String fieldName) {
1816: return allOutParameters.get(fieldName) != null;
1817: }
1818:
1819: /**
1820: * Check if a certain name is a OUTPUT field parameter(of any kind) in this DBOBject
1821: *
1822: * @param fieldName the name of the field to check
1823: * @return true if the field name exists
1824: */
1825: public boolean isInField(String fieldName) {
1826: return allInParameters.get(fieldName) != null;
1827: }
1828:
1829: /**
1830: * Return the Table Name of the current database object. Keep in mind
1831: * that a database object could update or affect other tables as well.
1832: *
1833: * @return String: Table name of the target table of this database object
1834: * @throws DataException upon error
1835: * <p/>
1836: * author Yves Henri AMAIZO <amy_amaizo@compuserve.com>
1837: */
1838: public String getTargetSQLTable(String dataContext)
1839: throws DataException {
1840: String sqlTableName = getTargetTable();
1841: try {
1842: if (getTargetDbSchema() != null
1843: && !"".equals(getTargetDbSchema())) {
1844: sqlTableName = getTargetDbSchema() + "."
1845: + getTargetTable();
1846: } else {
1847: JDBCConfig myConfig = ConfigManager
1848: .getJdbcRequired(dataContext);
1849: if (myConfig.getDbSchema() != null
1850: && !"".equals(myConfig.getDbSchema())) {
1851: sqlTableName = myConfig.getDbSchema() + "."
1852: + getTargetTable();
1853: }
1854: }
1855: } catch (ConfigurationException ce) {
1856: throw new DataException(ce);
1857: }
1858: return sqlTableName;
1859: } /* getTargetSQLTable() */
1860:
1861: /**
1862: * Get a list of all of the names of the IN param fields in this object
1863: *
1864: * @return An ArrayList of all of the names of the IN param fields
1865: */
1866: public ArrayList getInParamListArray() {
1867: return inParamList;
1868: }
1869:
1870: /**
1871: * Get a list of all of the names of the OUT param fields in this object
1872: *
1873: * @return An ArrayList of all of the names of the OUT param fields
1874: */
1875: public ArrayList getOutParamListArray() {
1876: return outParamList;
1877: }
1878:
1879: /**
1880: * Retrieve an interator of IN param fields
1881: *
1882: * @return Iterator of IN param fields. [MetaData]
1883: */
1884: public Iterator getInParamFieldListIterator() {
1885: return inParamList.iterator();
1886: }
1887:
1888: /**
1889: * Retrieve an interator of IN param fields
1890: *
1891: * @return Iterator of IN param fields. [MetaData]
1892: */
1893: public Iterator getOutParamFieldListIterator() {
1894: return outParamList.iterator();
1895: }
1896:
1897: /**
1898: * This convenience method counts
1899: * <code>DBFields</code> belonging to this
1900: * <code>DBObject</code> that are set to <b>retrieve</b>.
1901: * author Yves Henri Amaizo <amy_amaizo@compuserve.com>
1902: *
1903: * @return int number of retrieve fields.
1904: */
1905: public synchronized int getOutParamFieldsCount() throws DBException {
1906: if (outParamList == null) {
1907: return 0;
1908: } else {
1909: return outParamList.size();
1910: }
1911: } /* getFieldsToRetrieveCount() */
1912:
1913: }
|