0001: /*
0002: Copyright (C) 2003 Know Gate S.L. All rights reserved.
0003: C/Oña, 107 1º2 28050 Madrid (Spain)
0004:
0005: Redistribution and use in source and binary forms, with or without
0006: modification, are permitted provided that the following conditions
0007: are met:
0008:
0009: 1. Redistributions of source code must retain the above copyright
0010: notice, this list of conditions and the following disclaimer.
0011:
0012: 2. The end-user documentation included with the redistribution,
0013: if any, must include the following acknowledgment:
0014: "This product includes software parts from hipergate
0015: (http://www.hipergate.org/)."
0016: Alternately, this acknowledgment may appear in the software itself,
0017: if and wherever such third-party acknowledgments normally appear.
0018:
0019: 3. The name hipergate must not be used to endorse or promote products
0020: derived from this software without prior written permission.
0021: Products derived from this software may not be called hipergate,
0022: nor may hipergate appear in their name, without prior written
0023: permission.
0024:
0025: This library is distributed in the hope that it will be useful,
0026: but WITHOUT ANY WARRANTY; without even the implied warranty of
0027: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
0028:
0029: You should have received a copy of hipergate License with this code;
0030: if not, visit http://www.hipergate.org or mail to info@hipergate.org
0031: */
0032:
0033: package com.knowgate.dataobjs;
0034:
0035: import java.io.IOException;
0036: import java.io.FileNotFoundException;
0037: import java.io.File;
0038:
0039: import java.sql.SQLException;
0040: import java.sql.CallableStatement;
0041: import java.sql.PreparedStatement;
0042: import java.sql.ResultSet;
0043: import java.sql.Time;
0044: import java.sql.Timestamp;
0045:
0046: import java.lang.ClassNotFoundException;
0047: import java.lang.IllegalAccessException;
0048: import java.lang.InstantiationException;
0049:
0050: import java.util.Date;
0051: import java.util.Map;
0052: import java.util.Collection;
0053: import java.util.HashMap;
0054: import java.util.Iterator;
0055: import java.util.LinkedList;
0056: import java.util.ListIterator;
0057: import java.util.Set;
0058: import java.util.Properties;
0059:
0060: import java.math.BigDecimal;
0061:
0062: import java.text.ParseException;
0063: import java.text.SimpleDateFormat;
0064: import java.text.DecimalFormat;
0065:
0066: import org.xml.sax.SAXException;
0067: import org.xml.sax.SAXNotRecognizedException;
0068: import org.xml.sax.SAXNotSupportedException;
0069: import org.xml.sax.SAXParseException;
0070:
0071: import com.knowgate.debug.*;
0072: import com.knowgate.jdc.*;
0073: import com.knowgate.math.Money;
0074: import com.knowgate.misc.Gadgets;
0075:
0076: /**
0077: * <p>Core class for persisting Java objects as registers in a RDMS.<p>
0078: * <p>Althought not an abstract class, DBPersist is mainly designed to be inherited
0079: * by a child class implementing specific behavior for reading a writting a Java
0080: * object from and to a relational database.</p>
0081: * <p>DBPersist mantains an internal collection of values each one mapped to a database field.</p>
0082: * This mapping is done automatically by DBPersist reading the target table metadata definition
0083: * and preparing the proper internal value set.</p>
0084: * <p>This object keeps the internal value set in memory as long as it is not garbage collected,
0085: * but it does not mantaing any session information nor transaction management with the database.
0086: * It is the programmer's responsability to pass an open database connection on each method call
0087: * and to commit or rollback transaction involving the usage of a DBPersist object.
0088: * @author Sergio Montoro Ten
0089: * @version 3.0
0090: */
0091:
0092: public class DBPersist implements Map {
0093:
0094: /**
0095: * Create instance for reading and writing register from a table
0096: * @param sTable Database table name for storing objects.
0097: * @param sAuditClass Name of child Java class inheriting from DBPersist.
0098: * @throws IllegalStateException
0099: */
0100:
0101: public DBPersist(String sTableName, String sAuditClass)
0102: throws IllegalStateException {
0103:
0104: sTable = sTableName;
0105:
0106: sAuditCls = sAuditClass;
0107: sAuditUsr = "";
0108: sTransactId = "";
0109: bAllCaps = bHasLongVarBinaryData = false;
0110: AllVals = new HashMap();
0111: }
0112:
0113: /**
0114: * Create instance for reading and writing register from a table
0115: * @param sTable Database table name for storing objects.
0116: * @param sAuditClass Name of child Java class inheriting from DBPersist.
0117: * @param bAllValuesUpperCase Convert all put string values to uppercase
0118: * @throws IllegalStateException
0119: * @since 3.0
0120: */
0121:
0122: public DBPersist(String sTableName, String sAuditClass,
0123: boolean bAllValuesUpperCase) throws IllegalStateException {
0124:
0125: sTable = sTableName;
0126:
0127: sAuditCls = sAuditClass;
0128: sAuditUsr = "";
0129: sTransactId = "";
0130: bAllCaps = bAllValuesUpperCase;
0131: bHasLongVarBinaryData = false;
0132: AllVals = new HashMap();
0133: }
0134:
0135: /**
0136: * Automatically convert put string values to uppercase
0137: * @param bAllValuesUpperCase boolean
0138: * @since 3.0
0139: */
0140: public void allcaps(boolean bAllValuesUpperCase) {
0141: bAllCaps = bAllValuesUpperCase;
0142: }
0143:
0144: /**
0145: * Get allcaps state
0146: * @return boolean
0147: * @since 3.0
0148: */
0149: public boolean allcaps() {
0150: return bAllCaps;
0151: }
0152:
0153: /**
0154: * Set user id for automatic operation auditing.
0155: */
0156: public void setAuditUser(String sAuditUser) {
0157: sAuditUsr = sAuditUser;
0158: }
0159:
0160: /**
0161: * Set transaction id for automatic operation auditing.
0162: */
0163:
0164: public void setAuditTransact(String sAuditTransact) {
0165: sTransactId = sAuditTransact;
0166: }
0167:
0168: /**
0169: * Returns whether or not this DBPersist contains no field values
0170: * @return boolean
0171: */
0172: public boolean isEmpty() {
0173: return AllVals.isEmpty();
0174: }
0175:
0176: /**
0177: * Actual number of field values on this DBPersist
0178: * @return int
0179: */
0180: public int size() {
0181: return AllVals.size();
0182: }
0183:
0184: /**
0185: * <p>Clears internal values.</p>
0186: * <p>No register is deleted at the database.</p>
0187: */
0188: public void clear() {
0189: AllVals.clear();
0190: }
0191:
0192: /**
0193: * <p>Copy another DBPersist into this instance</p>
0194: * Table and audit class values are replaced with to ones from source object
0195: * @param oSource Source Object
0196: * @since 2.2
0197: */
0198: public void clone(DBPersist oSource) {
0199: sTable = oSource.getTableName();
0200: sAuditCls = oSource.getAuditClassName();
0201: AllVals = new HashMap(oSource.AllVals);
0202: }
0203:
0204: /**
0205: * Returns true if any of this DBPersist fields has the specified value.
0206: * @param oKey Object whose presence in this map is to be tested
0207: * @return boolean
0208: * @since 2.2
0209: */
0210: public boolean containsValue(Object oKey) {
0211: return AllVals.containsValue(oKey);
0212: }
0213:
0214: /**
0215: * Returns true if this DBPersist contains a field for the given name
0216: * @param oKey Field Name
0217: * @return boolean
0218: * @throws NullPointerException If oKey is <b>null</b>
0219: * @since 2.2
0220: */
0221: public boolean containsKey(Object oKey) throws NullPointerException {
0222: if (oKey == null)
0223: throw new NullPointerException(
0224: "DBPersist.containsKey() field name cannot be null");
0225: return AllVals.containsKey(oKey);
0226: }
0227:
0228: /**
0229: * <p>Get value for a field name</p>
0230: * @param sKey String Field Name
0231: * @return Field value. If field is <b>null</b> or DBPersist has not been loaded,
0232: * or no field with given name exists at table, get() returns <b>null</b>.
0233: */
0234:
0235: public Object get(String sKey) {
0236: return AllVals.get(sKey);
0237: }
0238:
0239: /**
0240: * Get dt_created column of register corresponding to this DBPersist instace
0241: * @param oConn JDCConnection
0242: * @return Date or <b>null</b> if no data is found
0243: * @throws SQLException If table for this DBPersist does not have a column named dt_created
0244: */
0245: public Date getCreationDate(JDCConnection oConn)
0246: throws SQLException {
0247: Date oDt;
0248: ResultSet oRSet = null;
0249: PreparedStatement oStmt = null;
0250: DBTable oTbl = getTable(oConn);
0251: LinkedList oList = oTbl.getPrimaryKey();
0252: ListIterator oIter;
0253: String sSQL = "SELECT " + DB.dt_created + " FROM "
0254: + oTbl.getName() + " WHERE 1=1";
0255: oIter = oList.listIterator();
0256: while (oIter.hasNext())
0257: sSQL += " AND " + oIter.next() + "=?";
0258: try {
0259: oStmt = oConn.prepareStatement(sSQL,
0260: ResultSet.TYPE_FORWARD_ONLY,
0261: ResultSet.CONCUR_READ_ONLY);
0262: int p = 0;
0263: oIter = oList.listIterator();
0264: while (oIter.hasNext())
0265: oStmt.setObject(++p, get(oIter.next()));
0266: oRSet = oStmt.executeQuery();
0267: if (oRSet.next())
0268: oDt = oRSet.getDate(1);
0269: else
0270: oDt = null;
0271: oRSet.close();
0272: oRSet = null;
0273: oStmt.close();
0274: oStmt = null;
0275: } catch (Exception xcpt) {
0276: if (null != oRSet) {
0277: try {
0278: oRSet.close();
0279: } catch (Exception ignore) { /* ignore */
0280: }
0281: }
0282: if (null != oStmt) {
0283: try {
0284: oStmt.close();
0285: } catch (Exception ignore) { /* ignore */
0286: }
0287: }
0288: throw new SQLException("DBPersist.getCreationDate() "
0289: + xcpt.getClass().getName() + " "
0290: + xcpt.getMessage());
0291: }
0292: return oDt;
0293: } // getCreationDate
0294:
0295: /**
0296: * <p>Get value for a field name</p>
0297: * @param sKey String Field Name
0298: * @return Field value. If field is <b>null</b> or DBPersist has not been loaded,
0299: * or no field with given name exists at table, get() returns <b>null</b>.
0300: * @throws NullPointerException If oKey is <b>null</b>
0301: * @since 2.2
0302: */
0303:
0304: public Object get(Object oKey) throws NullPointerException {
0305: if (oKey == null)
0306: throw new NullPointerException(
0307: "DBPersist.get() field name cannot be null");
0308: return AllVals.get(oKey);
0309: }
0310:
0311: /**
0312: * <p>Get value for a DECIMAL or NUMERIC field<p>
0313: * @param sKey Field Name
0314: * @return Field value or <b>null</b>.
0315: * @throws java.lang.ClassCastException
0316: * @throws java.lang.NumberFormatException
0317: */
0318:
0319: public BigDecimal getDecimal(String sKey)
0320: throws ClassCastException, NumberFormatException {
0321:
0322: Object oDec = AllVals.get(sKey);
0323:
0324: if (oDec == null)
0325: return null;
0326: else {
0327: if (oDec.getClass().getName().equalsIgnoreCase(
0328: "java.lang.String"))
0329: return new BigDecimal((String) oDec);
0330: else
0331: return (BigDecimal) oDec;
0332: }
0333: } // getDecimal
0334:
0335: /**
0336: * <p>Get decimal formated as a String using the given pattern and the symbols for the default locale</p>
0337: * @param sKey Field Name
0338: * @param sPattern A non-localized pattern string, for example: "#0.00"
0339: * @return String decimal value formated according to sPatern or <b>null</b>
0340: * @throws ClassCastException
0341: * @throws NumberFormatException
0342: * @throws NullPointerException if sPattern is <b>null</b>
0343: * @throws IllegalArgumentException if sPattern is invalid
0344: */
0345: public String getDecimalFormated(String sKey, String sPattern)
0346: throws ClassCastException, NumberFormatException,
0347: NullPointerException, IllegalArgumentException {
0348:
0349: BigDecimal oDec = getDecimal(sKey);
0350:
0351: if (oDec == null)
0352: return null;
0353: else {
0354: return new DecimalFormat(sPattern).format(oDec
0355: .doubleValue());
0356: }
0357: } // getDecimalFormated
0358:
0359: /**
0360: * <p>Get double formated as a String using the given pattern and the symbols for the default locale</p>
0361: * @param sKey Field Name
0362: * @param sPattern A non-localized pattern string, for example: "#0.00"
0363: * @return String decimal value formated according to sPatern or <b>null</b>
0364: * @throws ClassCastException
0365: * @throws NumberFormatException
0366: * @throws NullPointerException
0367: * @throws IllegalArgumentException
0368: */
0369: public String getDoubleFormated(String sKey, String sPattern)
0370: throws ClassCastException, NumberFormatException,
0371: NullPointerException, IllegalArgumentException {
0372: if (isNull(sKey))
0373: return null;
0374: else
0375: return new DecimalFormat(sPattern).format(getDouble(sKey));
0376: }
0377:
0378: /**
0379: * <p>Get float formated as a String using the given pattern and the symbols for the default locale</p>
0380: * @param sKey Field Name
0381: * @param sPattern A non-localized pattern string, for example: "#0.00"
0382: * @return String decimal value formated according to sPatern or <b>null</b>
0383: * @throws ClassCastException
0384: * @throws NumberFormatException
0385: * @throws NullPointerException
0386: * @throws IllegalArgumentException
0387: */
0388: public String getFloatFormated(String sKey, String sPattern)
0389: throws ClassCastException, NumberFormatException,
0390: NullPointerException, IllegalArgumentException {
0391: if (isNull(sKey))
0392: return null;
0393: else
0394: return new DecimalFormat(sPattern).format(getFloat(sKey));
0395: }
0396:
0397: /**
0398: * <p>Get value of a VARCHAR field that holds a money+currency amount<p>
0399: * Money values are stored with its currency sign embedded inside,
0400: * like "26.32 USD" or "$48.3" or "35.44 €"
0401: * @param sKey Field Name
0402: * @return com.knowgate.math.Money
0403: * @throws NumberFormatException
0404: * @since 3.0
0405: */
0406: public Money getMoney(String sKey) throws NumberFormatException {
0407: Object oVal = AllVals.get(sKey);
0408: if (null != oVal)
0409: if (oVal.toString().length() > 0)
0410: return Money.parse(oVal.toString());
0411: else
0412: return null;
0413: else
0414: return null;
0415: } // getMoney
0416:
0417: /**
0418: * <p>Get value for a CHAR, VARCHAR or LONGVARCHAR field<p>
0419: * @param sKey Field Name
0420: * @return Field value or <b>null</b>.
0421: * @throws NullPointerException if field is <b>null</b> or no field with
0422: * such name was found at internal value collection.
0423: */
0424: public String getString(String sKey) throws NullPointerException {
0425: return AllVals.get(sKey).toString();
0426: }
0427:
0428: /**
0429: * <p>Get value for a CHAR, VARCHAR or LONGVARCHAR field replacing <b>null</b>
0430: * with a default value.<p>
0431: * @param sKey Field Name
0432: * @param sDefault Value to be returned if field is null. sDefault may itself
0433: * be <b>null</b>, provinding a null safe version of getString() method.
0434: * @return Field value or default value.
0435: */
0436:
0437: public String getStringNull(String sKey, String sDefault) {
0438: Object oVal;
0439: if (AllVals.containsKey(sKey)) {
0440: oVal = AllVals.get(sKey);
0441: if (null == oVal)
0442: return sDefault;
0443: else
0444: return oVal.toString();
0445: } else
0446: return sDefault;
0447: }
0448:
0449: /**
0450: * <p>Get value for SQL92 TIME field</p>
0451: * @param sKey Field Name
0452: * @return java.sql.Time
0453: * @since 3.0
0454: */
0455: public Time getTimeOfDay(String sKey) {
0456: Object oTm = AllVals.get(sKey);
0457: if (null != oTm)
0458: return (Time) oTm;
0459: else
0460: return null;
0461: } // getTimeOfDay
0462:
0463: /**
0464: * <p>Get value for a SMALLINT field<p>
0465: * @param sKey Field Name
0466: * @return Field value.
0467: * @throws NullPointerException if field is <b>null</b> or no field with
0468: * such name was found at internal value collection.
0469: */
0470:
0471: public short getShort(String sKey)
0472: throws java.lang.NullPointerException {
0473: Object oVal = AllVals.get(sKey);
0474:
0475: if (oVal == null)
0476: throw new NullPointerException(sKey + " is null");
0477:
0478: return Short.parseShort(oVal.toString());
0479: }
0480:
0481: /**
0482: * <p>Get value for a DOUBLE or NUMBER([1..28],m) field<p>
0483: * @param sKey Field Name
0484: * @return Field value.
0485: * @throws NullPointerException if field is <b>null</b> or no field with
0486: * such name was found at internal value collection.
0487: * @throws NumberFormatException
0488: */
0489:
0490: public double getDouble(String sKey) throws NullPointerException,
0491: NumberFormatException {
0492: Object oVal = AllVals.get(sKey);
0493: Class oCls;
0494: double dRetVal;
0495:
0496: if (oVal == null)
0497: throw new NullPointerException(sKey + " is null");
0498:
0499: oCls = oVal.getClass();
0500:
0501: try {
0502: if (oCls.equals(Short.TYPE))
0503: dRetVal = (double) ((Short) oVal).shortValue();
0504: else if (oCls.equals(Integer.TYPE))
0505: dRetVal = (double) ((Integer) oVal).intValue();
0506: else if (oCls.equals(Class.forName("java.math.BigDecimal")))
0507: dRetVal = ((java.math.BigDecimal) oVal).doubleValue();
0508: else if (oCls.equals(Float.TYPE))
0509: dRetVal = ((Float) oVal).floatValue();
0510: else if (oCls.equals(Double.TYPE))
0511: dRetVal = ((Double) oVal).doubleValue();
0512: else
0513: dRetVal = new Double(oVal.toString()).floatValue();
0514: } catch (ClassNotFoundException cnfe) { /* never thrown */
0515: dRetVal = 0d;
0516: }
0517:
0518: return dRetVal;
0519: } // getDouble
0520:
0521: /**
0522: * <p>Get value for a FLOAT or NUMBER([1..28],m) field<p>
0523: * @param sKey Field Name
0524: * @return Field value.
0525: * @throws NullPointerException if field is <b>null</b> or no field with
0526: * such name was found at internal value collection.
0527: * @throws NumberFormatException
0528: */
0529:
0530: public float getFloat(String sKey) throws NullPointerException,
0531: NumberFormatException {
0532: Object oVal = AllVals.get(sKey);
0533: Class oCls;
0534: float fRetVal;
0535:
0536: if (oVal == null)
0537: throw new NullPointerException(sKey + " is null");
0538:
0539: oCls = oVal.getClass();
0540:
0541: try {
0542: if (oCls.equals(Short.TYPE))
0543: fRetVal = (float) ((Short) oVal).shortValue();
0544: else if (oCls.equals(Integer.TYPE))
0545: fRetVal = (float) ((Integer) oVal).intValue();
0546: else if (oCls.equals(Class.forName("java.math.BigDecimal")))
0547: fRetVal = ((java.math.BigDecimal) oVal).floatValue();
0548: else if (oCls.equals(Float.TYPE))
0549: fRetVal = ((Float) oVal).floatValue();
0550: else if (oCls.equals(Double.TYPE))
0551: fRetVal = ((Double) oVal).floatValue();
0552: else
0553: fRetVal = new Float(oVal.toString()).floatValue();
0554: } catch (ClassNotFoundException cnfe) { /* never thrown */
0555: fRetVal = 0f;
0556: }
0557:
0558: return fRetVal;
0559:
0560: } // getFloat
0561:
0562: /**
0563: * <p>Get value for a INTEGER or NUMBER([1..11]) field<p>
0564: * @param sKey Field Name
0565: * @return Field value.
0566: * @throws NullPointerException if field is <b>null</b> or no field with
0567: * such name was found at internal value collection.
0568: * @throws NumberFormatException
0569: */
0570:
0571: public int getInt(String sKey) throws NullPointerException,
0572: NumberFormatException {
0573: int iRetVal;
0574: Object oInt = AllVals.get(sKey);
0575:
0576: if (Integer.TYPE.equals(oInt.getClass()))
0577: iRetVal = ((Integer) (oInt)).intValue();
0578: else
0579: iRetVal = Integer.parseInt(oInt.toString());
0580:
0581: return iRetVal;
0582: } // getInt
0583:
0584: /**
0585: * <p>Get value for a INTEGER or NUMBER([1..11]) field<p>
0586: * @param sKey Field Name
0587: * @return Field value or <b>null</b>.
0588: * @throws NumberFormatException
0589: */
0590:
0591: public Integer getInteger(String sKey) throws NumberFormatException {
0592: Object oInt = AllVals.get(sKey);
0593:
0594: if (null != oInt)
0595: if (Integer.TYPE.equals(oInt.getClass()))
0596: return (Integer) oInt;
0597: else
0598: return new Integer(oInt.toString());
0599: else
0600: return null;
0601: } // getInteger
0602:
0603: /**
0604: * <p>Get value for a DATETIME field<p>
0605: * @param sKey Field Name
0606: * @return Date value or <b>null</b>.
0607: * @throws ClassCastException if sKey field is not of type DATETIME
0608: */
0609:
0610: public java.util.Date getDate(String sKey)
0611: throws ClassCastException {
0612: Object oDt = AllVals.get(sKey);
0613: java.util.Date dDt = null;
0614: if (null != oDt) {
0615: if (oDt.getClass().equals(ClassUtilDate))
0616: dDt = (java.util.Date) oDt;
0617: else if (oDt.getClass().equals(ClassTimestamp))
0618: dDt = new java.util.Date(((java.sql.Timestamp) oDt)
0619: .getTime());
0620: else if (oDt.getClass().equals(ClassSQLDate))
0621: dDt = new java.util.Date(((java.sql.Date) oDt)
0622: .getYear(), ((java.sql.Date) oDt).getMonth(),
0623: ((java.sql.Date) oDt).getDate());
0624: else if (oDt.getClass().equals(ClassLangString)) {
0625: try {
0626: dDt = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")
0627: .parse((String) oDt);
0628: } catch (java.text.ParseException pe) {
0629: throw new ClassCastException("Cannot parse Date "
0630: + oDt);
0631: }
0632: }
0633: }
0634: return dDt;
0635: } // getDate
0636:
0637: /**
0638: * <p>Get DATE formated as ccyy-MM-dd<p>
0639: * @param sKey Field Name
0640: * @throws ClassCastException if sKey field is not of type DATE
0641: * @return String value for Date or <b>null</b>.
0642: */
0643:
0644: public String getDateShort(String sKey) throws ClassCastException {
0645: java.util.Date dDt = getDate(sKey);
0646: if (null != dDt) {
0647: int y = dDt.getYear() + 1900, m = dDt.getMonth() + 1, d = dDt
0648: .getDate();
0649: return String.valueOf(y) + "-" + (m < 10 ? "0" : "")
0650: + String.valueOf(m) + "-" + (d < 10 ? "0" : "")
0651: + String.valueOf(d);
0652: } else
0653: return null;
0654: } // getDateShort
0655:
0656: /**
0657: * <p>Get value for a DATE, DATETIME or TIMESTAMP field formated a String<p>
0658: * @param sKey Field Name
0659: * @param sFormat Date Format (like "yyyy-MM-dd HH:mm:ss")
0660: * @return Formated date or <b>null</b>.
0661: * @throws ClassCastException if sKey field is not of type DATE, DATETIME or TIMESTAMP
0662: * @see java.text.SimpleDateFormat
0663: */
0664:
0665: public String getDateFormated(String sKey, String sFormat)
0666: throws ClassCastException {
0667: java.util.Date oDt = getDate(sKey);
0668: SimpleDateFormat oSimpleDate;
0669:
0670: if (null != oDt) {
0671: oSimpleDate = new SimpleDateFormat(sFormat);
0672: return oSimpleDate.format(oDt);
0673: } else
0674: return null;
0675: } // getDateFormated()
0676:
0677: /**
0678: * <p>Get value for a DATE, DATETIME or TIMESTAMP field formated a yyyy-MM-dd hh:mm:ss<p>
0679: * @param sKey String Field Name
0680: * @return String Formated date or <b>null</b>.
0681: * @throws ClassCastException if sKey field is not of type DATE
0682: * @since 3.0
0683: */
0684: public String getDateTime(String sKey) {
0685: return getDateFormated(sKey, "yyyy-MM-dd hh:mm:ss");
0686: } // getDateTime
0687:
0688: /**
0689: * <p>Get value for a DATE, DATETIME or TIMESTAMP field formated a yyyy-MM-dd HH:mm:ss<p>
0690: * @param sKey String Field Name
0691: * @return String Formated date or <b>null</b>.
0692: * @throws ClassCastException if sKey field is not of type DATE, DATETIME or TIMESTAMP
0693: * @since 3.0
0694: */
0695: public String getDateTime24(String sKey) {
0696: return getDateFormated(sKey, "yyyy-MM-dd HH:mm:ss");
0697: } // getDateTime24()
0698:
0699: /**
0700: * <p>Get value for a DATE field<p>
0701: * @param sKey Field Name
0702: * @return java.sql.Date
0703: * @throws ClassCastException if sKey field is not of type DATE, DATETIME or TIMESTAMP
0704: * @since 3.0
0705: */
0706: public java.sql.Date getSQLDate(String sKey)
0707: throws ClassCastException {
0708: java.sql.Date oRetVal;
0709: Object oObj = AllVals.get(sKey);
0710:
0711: if (oObj == null) {
0712: oRetVal = null;
0713: } else {
0714: String sCls = oObj.getClass().getName();
0715: if (sCls.equals("java.sql.Date"))
0716: oRetVal = (java.sql.Date) oObj;
0717: else if (sCls.equals("java.util.Date"))
0718: oRetVal = new java.sql.Date(((java.util.Date) oObj)
0719: .getTime());
0720: else if (sCls.equals("java.sql.Timestamp"))
0721: oRetVal = new java.sql.Date(((java.sql.Timestamp) oObj)
0722: .getTime());
0723: else
0724: throw new ClassCastException(
0725: "DBPersist.getSQLDate() Cannot cast " + sCls
0726: + " to java.sql.Date");
0727: }
0728: return oRetVal;
0729: } // getSQLDate
0730:
0731: /**
0732: * <p>Get value for a TIME field<p>
0733: * @param sKey Field Name
0734: * @return java.sql.Time
0735: * @throws ClassCastException
0736: * @since 3.0
0737: */
0738: public Time getSQLTime(String sKey) throws ClassCastException {
0739: java.sql.Time oRetVal;
0740: Object oObj = AllVals.get(sKey);
0741:
0742: if (oObj == null) {
0743: oRetVal = null;
0744: } else {
0745: String sCls = oObj.getClass().getName();
0746: if (sCls.equals("java.sql.Time"))
0747: oRetVal = (java.sql.Time) oObj;
0748: else if (sCls.equals("java.util.Date"))
0749: oRetVal = new java.sql.Time(((java.util.Date) oObj)
0750: .getTime());
0751: else if (sCls.equals("java.sql.Timestamp"))
0752: oRetVal = new java.sql.Time(((java.sql.Timestamp) oObj)
0753: .getTime());
0754: else
0755: throw new ClassCastException(
0756: "DBPersist.getSQLTime() Cannot cast " + sCls
0757: + " to java.sql.Time");
0758: }
0759: return oRetVal;
0760: } // getSQLTime
0761:
0762: /**
0763: * <p>Get time part of date as a String</p>
0764: * @param sKey Field Name
0765: * @return String HH24:MI:SS or <b>null</b>
0766: * @throws ClassCastException if sKey field is not of type DATE
0767: */
0768: public String getTime(String sKey) throws ClassCastException {
0769: Object oObj = AllVals.get(sKey);
0770:
0771: if (oObj != null) {
0772: java.util.Date oDt = (java.util.Date) oObj;
0773: return (oDt.getHours() < 10 ? "0" : "")
0774: + String.valueOf(oDt.getHours()) + ":"
0775: + (oDt.getMinutes() < 10 ? "0" : "")
0776: + String.valueOf(oDt.getMinutes())
0777: + (oDt.getSeconds() < 10 ? "0" : "") + ":"
0778: + String.valueOf(oDt.getSeconds());
0779: } else {
0780: return null;
0781: }
0782: } // getTime
0783:
0784: /**
0785: * <p>Get a part of an interval value</p>
0786: * This function only works for PostgreSQL
0787: * @param sKey String String Field Name
0788: * @param sPart String Currently, only "days" is allowed as interval part
0789: * @return int Number of days in the given interval
0790: * @throws NullPointerException if interval is <b>null</b>
0791: * @throws IllegalArgumentException is sPart is not "days"
0792: * @throws NumberFormatException if interval has no days
0793: * @since 3.0
0794: */
0795: public int getIntervalPart(String sKey, String sPart)
0796: throws NullPointerException, NumberFormatException,
0797: IllegalArgumentException {
0798: if (sPart == null)
0799: throw new IllegalArgumentException(
0800: "DBPersist.getIntervalPart() interval part to get cannot be null");
0801: if (!sPart.equalsIgnoreCase("days"))
0802: throw new IllegalArgumentException(
0803: "DBPersist.getIntervalPart() interval part to get must be 'days'");
0804: Object oObj = AllVals.get(sKey);
0805: if (oObj == null)
0806: throw new NullPointerException(
0807: "DBPersist.getIntervalPart() value of interval is null");
0808: String sTI = oObj.toString().toLowerCase();
0809: int iMons = sTI.indexOf("mons") < 0 ? 0
0810: : sTI.indexOf("mons") + 4;
0811: int iDays = sTI.indexOf("days");
0812: if (iDays < 0)
0813: return 0;
0814: return Integer.parseInt(Gadgets.removeChars(sTI.substring(
0815: iMons, iDays), " "));
0816: } // getIntervalPart
0817:
0818: /**
0819: * <p>Get value for a DATETIME or TIMESTAMP field<p>
0820: * @param sKey Field Name
0821: * @return Field value or <b>null</b>.
0822: */
0823:
0824: public Timestamp getTimestamp(String sKey) {
0825: Object oDt = AllVals.get(sKey);
0826:
0827: if (null != oDt)
0828: return new Timestamp(((java.util.Date) oDt).getTime());
0829: else
0830: return null;
0831: } // getTimestamp
0832:
0833: /**
0834: * @return Field Names Set
0835: * @deprecated Use keySet() instead
0836: */
0837: public Set getItems() {
0838: return AllVals.keySet();
0839: }
0840:
0841: /**
0842: * @return Field Names Set
0843: * @since 2.2
0844: */
0845: public Set keySet() {
0846: return AllVals.keySet();
0847: }
0848:
0849: /**
0850: * @return Values Map
0851: */
0852: public HashMap getItemMap() {
0853: return AllVals;
0854: }
0855:
0856: /**
0857: * @return Values Collection
0858: * @since 2.2
0859: */
0860: public Collection values() {
0861: return AllVals.values();
0862: }
0863:
0864: /**
0865: * @return Field Values Set
0866: * @since 2.2
0867: */
0868: public Set entrySet() {
0869: return AllVals.entrySet();
0870: }
0871:
0872: /**
0873: * @return Iterator for values stored in-memory at this DBPersist.
0874: */
0875:
0876: public Iterator iterator() {
0877: return AllVals.values().iterator();
0878: }
0879:
0880: /**
0881: * Get audit class name
0882: * @return Name of base table for this DBPersist
0883: */
0884:
0885: public String getAuditClassName() {
0886: return sAuditCls;
0887: }
0888:
0889: /**
0890: * Get base table name
0891: * @return Name of base table for this DBPersist
0892: */
0893:
0894: public String getTableName() {
0895: return sTable;
0896: }
0897:
0898: /**
0899: * @return {@link DBTable} object where data is stored
0900: * or <b>null</b> if the table does not exist at the database.
0901: * @deprecated Use {@link #getTable(JDCConnection) getTable(JDCConnection)} instead
0902: */
0903:
0904: public DBTable getTable() {
0905: if (null == oTable) {
0906: oTable = DBBind.getTable(sTable);
0907: }
0908: return oTable;
0909: } // getTable()
0910:
0911: /**
0912: * Get DBTable object witch holds this DBPersist registers.
0913: * @param oConn JDBC Database Connection
0914: * @return {@link DBTable} object where data is stored
0915: * or <b>null</b> if the table does not exist at the database.
0916: * @throws IllegalStateException DBPersist uses the internal static table map
0917: * from DBBind. The internal DBBind table map is loaded upon first call to
0918: * a DBBind constructor. Thus, if a DBPersist object is instantiated before
0919: * instantiating any DBBind object, the internal table map will not be
0920: * preloaded and an IllegalStateException will be raised.
0921: * @since 2.0
0922: */
0923: public DBTable getTable(JDCConnection oConn) throws SQLException,
0924: IllegalStateException {
0925:
0926: if (null == oTable) {
0927: JDCConnectionPool oPool = oConn.getPool();
0928:
0929: if (null == oPool) {
0930: if (oConn.getDataBaseProduct() == JDCConnection.DBMS_POSTGRESQL)
0931: oTable = new DBTable(oConn.getCatalog(), null,
0932: sTable, 1);
0933: else
0934: oTable = new DBTable(oConn.getCatalog(), oConn
0935: .getSchemaName(), sTable, 1);
0936:
0937: oTable.readColumns(oConn, oConn.getMetaData());
0938: } else {
0939: DBBind oBind = (DBBind) oPool.getDatabaseBinding();
0940:
0941: if (null == oBind)
0942: throw new IllegalStateException(
0943: "Connection Pool for " + sAuditCls
0944: + " is not binded to the database.");
0945: else
0946: oTable = oBind.getDBTable(sTable);
0947: }
0948: }
0949: return oTable;
0950: }
0951:
0952: /**
0953: * Test is a readed field was null.
0954: * @param sKey Field Name
0955: * @return <b>true</b> if readed field was null or if no field with given name
0956: * was found at internal collection.
0957: */
0958:
0959: public boolean isNull(String sKey) {
0960: boolean bIsNull = !AllVals.containsKey(sKey);
0961: if (!bIsNull)
0962: bIsNull = AllVals.get(sKey) == null;
0963: return bIsNull;
0964: }
0965:
0966: /**
0967: * <p>Load the internal value set from a register at a database table</p>
0968: * @param oConn Database Connection
0969: * @param PKVals Primary key values in order of appearance
0970: * @return <b>true</b> if a register was found, <b>false</b> if no register was
0971: * found with such primary key.
0972: * @throws SQLException
0973: */
0974:
0975: public boolean load(JDCConnection oConn, Object[] PKVals)
0976: throws SQLException {
0977: if (oTable == null) {
0978: oTable = getTable(oConn);
0979: if (null == oTable)
0980: throw new SQLException("Table not found " + sTable,
0981: "42S02", 42002);
0982: return oTable.loadRegister(oConn, PKVals, AllVals);
0983: } else
0984: return oTable.loadRegister(oConn, PKVals, AllVals);
0985: }
0986:
0987: /**
0988: * <p>Load the internal value set from a register at a database table</p>
0989: * @param oConn JDCConnection
0990: * @param sKey String Primary key value
0991: * @return <b>true</b> if a register was found, <b>false</b> if no register was
0992: * found with such primary key.
0993: * @throws SQLException
0994: * @since 3.0
0995: */
0996: public boolean load(JDCConnection oConn, String sKey)
0997: throws SQLException {
0998: if (oTable == null) {
0999: oTable = getTable(oConn);
1000: if (null == oTable)
1001: throw new SQLException("Table not found " + sTable,
1002: "42S02", 42002);
1003: return oTable.loadRegister(oConn, new Object[] { sKey },
1004: AllVals);
1005: } else
1006: return oTable.loadRegister(oConn, new Object[] { sKey },
1007: AllVals);
1008: }
1009:
1010: /**
1011: * <p>Set value at internal collection</p>
1012: * If allcaps is set tu <b>true</b> then sVal is converted to uppercase
1013: * @param sKey Field Name
1014: * @param sVal Field Value
1015: * @throws NullPointerException If sKey is <b>null</b>
1016: */
1017:
1018: public void put(String sKey, String sVal)
1019: throws NullPointerException {
1020: if (sKey == null)
1021: throw new NullPointerException(
1022: "DBPersist.put(String,String) field name cannot be null");
1023: if (null == sVal)
1024: AllVals.put(sKey, null);
1025: else if (bAllCaps)
1026: AllVals.put(sKey, sVal.toUpperCase());
1027: else
1028: AllVals.put(sKey, sVal);
1029: }
1030:
1031: /**
1032: * <p>Set value at internal collection</p>
1033: * @param sKey Field Name
1034: * @param oObj Field Value
1035: * @throws NullPointerException If sKey is <b>null</b>
1036: */
1037:
1038: public void put(String sKey, Object oObj)
1039: throws NullPointerException {
1040: if (sKey == null)
1041: throw new NullPointerException(
1042: "DBPersist.put(String,Object) field name cannot be null");
1043: AllVals.put(sKey, oObj);
1044: }
1045:
1046: /**
1047: * <p>Set value at internal collection</p>
1048: * If internal collection previously contained a mapping for this key, the old value is replaced.
1049: * @param sKey Field Name
1050: * @param oObj Field Value
1051: * @return previous value associated with specified key, or null if there was no mapping for key
1052: * @throws NullPointerException If sKey is <b>null</b>
1053: * @since 2.2
1054: */
1055:
1056: public Object put(Object sKey, Object oObj)
1057: throws NullPointerException {
1058: Object oPrevious;
1059: if (sKey == null)
1060: throw new NullPointerException(
1061: "DBPersist.put(Object,Object) field name cannot be null");
1062: if (AllVals.containsKey(sKey)) {
1063: oPrevious = AllVals.get(sKey);
1064: AllVals.remove(sKey);
1065: } else {
1066: oPrevious = null;
1067: }
1068: AllVals.put(sKey, oObj);
1069: return oPrevious;
1070: }
1071:
1072: /**
1073: * <p>Set value at internal collection</p>
1074: * @param sKey Field Name
1075: * @param iVal Field Value
1076: */
1077:
1078: public void put(String sKey, int iVal) {
1079: AllVals.put(sKey, new Integer(iVal));
1080: }
1081:
1082: /**
1083: * <p>Set value at internal collection</p>
1084: * @param sKey Field Name
1085: * @param iVal Field Value
1086: */
1087:
1088: public void put(String sKey, short iVal) {
1089: AllVals.put(sKey, new Short(iVal));
1090: }
1091:
1092: /**
1093: * <p>Set value at internal collection</p>
1094: * @param sKey Field Name
1095: * @param dtVal Field Value
1096: */
1097:
1098: public void put(String sKey, Date dtVal) {
1099: AllVals.put(sKey, dtVal);
1100: }
1101:
1102: /**
1103: * <p>Set value at internal collection</p>
1104: * @param sKey Field Name
1105: * @param tmVal Field Value
1106: * @since 3.0
1107: */
1108:
1109: public void put(String sKey, Time tmVal) {
1110: AllVals.put(sKey, tmVal);
1111: }
1112:
1113: /**
1114: * Put Date value using specified format
1115: * @param sKey String Field Name
1116: * @param sDate String Field Value as String
1117: * @param oPattern SimpleDateFormat Date format to be used
1118: * @since 3.0
1119: */
1120: public void put(String sKey, String sDate, SimpleDateFormat oPattern)
1121: throws ParseException {
1122: AllVals.put(sKey, oPattern.parse(sDate));
1123: }
1124:
1125: /**
1126: * <p>Put double value at internal collection</p>
1127: * @param sKey Field Name
1128: * @param dVal Field Value
1129: */
1130:
1131: public void put(String sKey, double dVal) {
1132: AllVals.put(sKey, new Double(dVal));
1133: }
1134:
1135: /**
1136: * <p>Put BigDecimal value at internal collection</p>
1137: * @param sKey Field Name
1138: * @param oDecVal Field Value
1139: */
1140:
1141: public void put(String sKey, BigDecimal oDecVal) {
1142: AllVals.put(sKey, oDecVal);
1143: }
1144:
1145: /**
1146: * Parse BigDecimal value and put it at internal collection
1147: * @param sKey String Field Name
1148: * @param sDecVal Field Name as String
1149: * @param oPattern DecimalFormat
1150: * @throws ParseException
1151: * @since 3.0
1152: */
1153: public void put(String sKey, String sDecVal, DecimalFormat oPattern)
1154: throws ParseException {
1155: AllVals.put(sKey, oPattern.parse(sDecVal));
1156: }
1157:
1158: /**
1159: * <p>Set value at internal collection</p>
1160: * @param sKey Field Name
1161: * @param fVal Field Value
1162: */
1163:
1164: public void put(String sKey, float fVal) {
1165: AllVals.put(sKey, new Float(fVal));
1166: }
1167:
1168: /**
1169: * <p>Set value at internal collection</p>
1170: * @param sKey Field Name
1171: * @param mVal Field Value
1172: * @since 3.0
1173: */
1174:
1175: public void put(String sKey, Money mVal) {
1176: if (null == mVal)
1177: AllVals.put(sKey, null);
1178: else
1179: AllVals.put(sKey, mVal.toString());
1180: }
1181:
1182: /**
1183: * <p>Set reference to a binary file for a long field</p>
1184: * @param sKey Field Name
1185: * @param oFile File Object
1186: * @throws FileNotFoundException
1187: */
1188:
1189: public void put(String sKey, File oFile)
1190: throws FileNotFoundException {
1191: if (!bHasLongVarBinaryData)
1192: LongVarBinaryValsLen = new HashMap();
1193:
1194: LongVarBinaryValsLen.put(sKey, new Long(oFile.length()));
1195:
1196: AllVals.put(sKey, oFile);
1197:
1198: bHasLongVarBinaryData = true;
1199: } // put
1200:
1201: /**
1202: * <p>Set reference to a byte array for a long field</p>
1203: * <p>Use this method only for binding LONGVARBINARY or BLOB fields</p>
1204: * @param sKey Field Name
1205: * @param aBytes byte array
1206: */
1207:
1208: public void put(String sKey, byte[] aBytes) {
1209: if (!bHasLongVarBinaryData)
1210: LongVarBinaryValsLen = new HashMap();
1211:
1212: LongVarBinaryValsLen.put(sKey, new Long(aBytes.length));
1213:
1214: AllVals.put(sKey, aBytes);
1215:
1216: bHasLongVarBinaryData = true;
1217: } // put
1218:
1219: /**
1220: * <p>Set reference to a character array for a long field</p>
1221: * <p>Use this method only for binding LONGVARCHAR or CLOB fields</p>
1222: * @param sKey Field Name
1223: * @param aChars char array
1224: */
1225:
1226: public void put(String sKey, char[] aChars) {
1227: if (!bHasLongVarBinaryData)
1228: LongVarBinaryValsLen = new HashMap();
1229:
1230: LongVarBinaryValsLen.put(sKey, new Long(aChars.length));
1231:
1232: AllVals.put(sKey, aChars);
1233:
1234: bHasLongVarBinaryData = true;
1235: } // put
1236:
1237: /**
1238: * <p>Set value at internal collection</p>
1239: * @param sKey Field Name
1240: * @param sData Field Value as a String. If iSQLType is BLOB or LONGVARBINARY
1241: * then sData is interpreted as a full file path uri.
1242: * @param iSQLType SQL Type for field
1243: * @throws NullPointerException If sKey is <b>null</b>
1244: * @throws IllegalArgumentException If SQL Type is not recognized.
1245: * Recognized types are { CHAR, VARCHAR, LONGVARCHAR, CLOB, INTEGER, SMALLINT,
1246: * DATE, TIMESTAMP, DOUBLE, FLOAT, REAL, DECIMAL, NUMERIC, BLOB, LONGVARBINARY }
1247: */
1248:
1249: public void put(String sKey, String sData, int iSQLType)
1250: throws FileNotFoundException, IllegalArgumentException,
1251: NullPointerException {
1252: int iDecDot;
1253:
1254: if (sKey == null)
1255: throw new NullPointerException(
1256: "DBPersist.put(String,String,int) field name cannot be null");
1257:
1258: switch (iSQLType) {
1259: case java.sql.Types.VARCHAR:
1260: case java.sql.Types.LONGVARCHAR:
1261: case java.sql.Types.CHAR:
1262: case java.sql.Types.CLOB:
1263: if (null == sData)
1264: AllVals.put(sKey, null);
1265: else if (bAllCaps)
1266: AllVals.put(sKey, sData.toUpperCase());
1267: else
1268: AllVals.put(sKey, sData);
1269: break;
1270: case java.sql.Types.INTEGER:
1271: AllVals.put(sKey, new Integer(sData));
1272: break;
1273: case java.sql.Types.SMALLINT:
1274: AllVals.put(sKey, new Short(sData));
1275: break;
1276: case java.sql.Types.DATE:
1277: if (null != sData)
1278: AllVals.put(sKey, java.sql.Date.valueOf(sData));
1279: else
1280: AllVals.put(sKey, null);
1281: break;
1282: case java.sql.Types.TIME:
1283: if (null != sData)
1284: AllVals.put(sKey, java.sql.Time.valueOf(sData));
1285: else
1286: AllVals.put(sKey, null);
1287: break;
1288: case java.sql.Types.TIMESTAMP:
1289: if (null != sData)
1290: AllVals.put(sKey, new java.sql.Timestamp(java.util.Date
1291: .parse(sData)));
1292: else
1293: AllVals.put(sKey, null);
1294: break;
1295: case java.sql.Types.DOUBLE:
1296: case java.sql.Types.FLOAT:
1297: AllVals.put(sKey, new Double(sData));
1298: break;
1299: case java.sql.Types.REAL:
1300: AllVals.put(sKey, new Float(sData));
1301: break;
1302: case java.sql.Types.DECIMAL:
1303: case java.sql.Types.NUMERIC:
1304: iDecDot = sData.indexOf(".");
1305: if (iDecDot < 0)
1306: iDecDot = sData.indexOf(",");
1307: if (iDecDot < 0)
1308: AllVals.put(sKey, new BigDecimal(sData));
1309: else
1310: AllVals
1311: .put(sKey, BigDecimal.valueOf(
1312: Long.parseLong(sData.substring(0,
1313: iDecDot)),
1314: Integer.parseInt(sData
1315: .substring(iDecDot + 1))));
1316: break;
1317: case java.sql.Types.LONGVARBINARY:
1318: case java.sql.Types.BLOB:
1319: if (!bHasLongVarBinaryData)
1320: LongVarBinaryValsLen = new HashMap();
1321:
1322: File oFile = new File(sData);
1323: if (oFile.exists()) {
1324: LongVarBinaryValsLen
1325: .put(sKey, new Long(oFile.length()));
1326: AllVals.put(sKey, oFile);
1327: }
1328: bHasLongVarBinaryData = true;
1329: break;
1330: case 1111: // PostgreSQL interval
1331: if (DebugFile.trace)
1332: DebugFile.writeln("Binding interval " + sData);
1333: try {
1334: Class cPGIntval = Class
1335: .forName("org.postgresql.util.PGInterval");
1336: java.lang.reflect.Constructor cNewPGInt = null;
1337: Object oPGIntval;
1338: try {
1339: cNewPGInt = cPGIntval
1340: .getConstructor(new Class[] { String.class });
1341: } catch (NoSuchMethodException neverthrown) {
1342: }
1343: try {
1344: oPGIntval = cNewPGInt
1345: .newInstance(new Object[] { sData });
1346: AllVals.put(sKey, oPGIntval);
1347: } catch (InstantiationException neverthrown) {
1348: } catch (IllegalAccessException neverthrown) {
1349: } catch (java.lang.reflect.InvocationTargetException neverthrown) {
1350: }
1351: } catch (ClassNotFoundException cnfe) {
1352: throw new IllegalArgumentException(
1353: "ClassNotFoundException org.postgresql.util.PGInterval");
1354: }
1355: if (DebugFile.trace)
1356: DebugFile.writeln("Interval successfully binded");
1357: break;
1358: } // end switch
1359: } // put
1360:
1361: /**
1362: * <p>Load values from a Properties object</p>
1363: */
1364:
1365: public void putAll(Properties oPropsCollection)
1366: throws FileNotFoundException {
1367: Iterator oIter = this .getTable().getColumns().iterator();
1368: DBColumn oDBCol;
1369: String sColName;
1370: String sPropValue;
1371:
1372: while (oIter.hasNext()) {
1373: oDBCol = (DBColumn) oIter.next();
1374: sColName = oDBCol.getName();
1375: sPropValue = oPropsCollection.getProperty(sColName);
1376:
1377: if (null != sPropValue) {
1378: if (sPropValue.trim().length() > 0) {
1379: switch (oDBCol.getSqlType()) {
1380: case java.sql.Types.INTEGER:
1381: replace(sColName, new Integer(sPropValue));
1382: break;
1383: case java.sql.Types.SMALLINT:
1384: replace(sColName, new Short(sPropValue));
1385: break;
1386: case java.sql.Types.DOUBLE:
1387: case java.sql.Types.REAL:
1388: replace(sColName, new Double(sPropValue));
1389: break;
1390: case java.sql.Types.FLOAT:
1391: replace(sColName, new Float(sPropValue));
1392: break;
1393: case java.sql.Types.NUMERIC:
1394: case java.sql.Types.DECIMAL:
1395: replace(sColName, new java.math.BigDecimal(
1396: sPropValue));
1397: break;
1398: default:
1399: put(sColName, sPropValue, oDBCol.getSqlType());
1400: } // end switch
1401: } // fi (s!="")
1402: else if (!isNull(sColName))
1403: replace(sColName, null);
1404: } // fi (s!=null)
1405: } // wend
1406: } // putAll()
1407:
1408: /**
1409: * <p>Put values from a Map into this DBPersist instance</p>
1410: * allcaps has no effect on input data when calling this method
1411: * @param oMap
1412: * @since 2.2
1413: */
1414: public void putAll(Map oMap) {
1415: Iterator oIter = oMap.keySet().iterator();
1416: while (oIter.hasNext()) {
1417: String sKey = oIter.next().toString();
1418: AllVals.put(sKey, oMap.get(sKey));
1419: } // wend
1420: } // putAll
1421:
1422: /**
1423: * <p>Remove a value from internal collection</p>
1424: * @param sKey Field Name
1425: */
1426:
1427: public void remove(String sKey) {
1428: if (AllVals.containsKey(sKey))
1429: AllVals.remove(sKey);
1430: }
1431:
1432: /**
1433: * <p>Remove a value from internal collection</p>
1434: * @param oKey Field Name
1435: * @return Object previos value associated with given field name
1436: * @since 2.2
1437: */
1438:
1439: public Object remove(Object oKey) {
1440: Object oPrevious;
1441: if (AllVals.containsKey(oKey)) {
1442: oPrevious = AllVals.get(oKey);
1443: AllVals.remove(oKey);
1444: } else {
1445: oPrevious = null;
1446: }
1447: return oPrevious;
1448: }
1449:
1450: /**
1451: * <p>Replace a value from internal collection</p>
1452: * @param sKey Field Name
1453: * @param oObj New Value
1454: */
1455: public void replace(String sKey, Object oObj) {
1456: remove(sKey);
1457:
1458: AllVals.put(sKey, oObj);
1459: }
1460:
1461: /**
1462: * <p>Replace a value from internal collection</p>
1463: * @param sKey Field Name
1464: * @param iVal New int value
1465: */
1466:
1467: public void replace(String sKey, int iVal) {
1468: Integer oObj = new Integer(iVal);
1469:
1470: remove(sKey);
1471:
1472: AllVals.put(sKey, oObj);
1473: }
1474:
1475: /**
1476: * <p>Replace a value from internal collection</p>
1477: * @param sKey Field Name
1478: * @param iVal New short value
1479: */
1480:
1481: public void replace(String sKey, short iVal) {
1482: Short oObj = new Short(iVal);
1483:
1484: remove(sKey);
1485:
1486: AllVals.put(sKey, oObj);
1487: }
1488:
1489: /**
1490: * <p>Replace a value from internal collection</p>
1491: * @param sKey Field Name
1492: * @param iVal New float value
1493: */
1494:
1495: public void replace(String sKey, float fVal) {
1496: Float oObj = new Float(fVal);
1497:
1498: remove(sKey);
1499:
1500: AllVals.put(sKey, oObj);
1501: }
1502:
1503: /**
1504: * Convert value kept with given key to lowercase
1505: * @param sKey String
1506: * @since 3.0
1507: */
1508:
1509: public void toLowerCase(String sKey) {
1510: if (!isNull(sKey))
1511: replace(sKey, getString(sKey).toLowerCase());
1512: }
1513:
1514: /**
1515: * Convert value kept with given key to uppercase
1516: * @param sKey String
1517: * @since 3.0
1518: */
1519:
1520: public void toUpperCase(String sKey) {
1521: if (!isNull(sKey))
1522: replace(sKey, getString(sKey).toUpperCase());
1523: }
1524:
1525: /**
1526: * <p>Store a register at database representing this instance of DBPersist</p>
1527: * <p><b>Insertions and updates</b> : The store method automatically manages
1528: * register insertions and updates. If the stored object already exists at
1529: * database then it is updated, if it does not exists then it is inserted.
1530: * A primary key violation error is never thrown so ther is no need to call
1531: * delete() method before re-writing an existing object.</p>
1532: * <p><b>NULL fields</b> : All values not set calling put() methods for DBPersist
1533: * will be assumed to be NULL. If a not nullable field is not set then an
1534: * SQLException will be raised.<br>
1535: * On storing an already existing object all values will we overwrited,
1536: * so is a DBPersist is not fully loaded before storing it, values not set
1537: * by calling put() methods that already were present at database will be lost.</p>
1538: * @param oConn Database Connection
1539: * @return boolean <b>true</b> if register was stored for the first time,
1540: * <b>false</b> if register already existed.
1541: * @throws SQLException
1542: */
1543:
1544: public boolean store(JDCConnection oConn) throws SQLException {
1545: boolean bRetVal;
1546:
1547: if (bHasLongVarBinaryData) {
1548: try {
1549: if (oTable == null) {
1550: oTable = getTable(oConn);
1551: if (null == oTable)
1552: throw new SQLException("Table not found "
1553: + sTable, "42S02", 42002);
1554: bRetVal = oTable.storeRegisterLong(oConn, AllVals,
1555: LongVarBinaryValsLen);
1556: } else
1557: bRetVal = oTable.storeRegisterLong(oConn, AllVals,
1558: LongVarBinaryValsLen);
1559: } catch (IOException ioe) {
1560: throw new SQLException(ioe.getMessage(), "40001", 40001);
1561: } finally {
1562: LongVarBinaryValsLen.clear();
1563: bHasLongVarBinaryData = false;
1564: }
1565: } else if (oTable == null) {
1566: oTable = getTable(oConn);
1567: if (null == oTable)
1568: throw new SQLException("Table not found " + sTable,
1569: "42S02", 42002);
1570: bRetVal = oTable.storeRegister(oConn, AllVals);
1571: } else
1572: bRetVal = oTable.storeRegister(oConn, AllVals);
1573:
1574: return bRetVal;
1575: } // store()
1576:
1577: /**
1578: * <p>Delete a register from database</p>
1579: * <p>The deleted register will be the one matching this DBPersist primary key,
1580: * as set at constructor or load() method.</p>
1581: * @param oConn Database connection
1582: * @return <b>true</b> if register was successfully erased, <b>false</b> if not.
1583: * @throws SQLException
1584: */
1585:
1586: public boolean delete(JDCConnection oConn) throws SQLException {
1587: boolean bRetVal;
1588:
1589: if (null == oTable) {
1590: oTable = getTable(oConn);
1591: if (null == oTable)
1592: throw new SQLException("Table not found " + sTable,
1593: "42S02", 42002);
1594: bRetVal = oTable.deleteRegister(oConn, AllVals);
1595: } else
1596: bRetVal = oTable.deleteRegister(oConn, AllVals);
1597:
1598: return bRetVal;
1599: } // delete()
1600:
1601: /**
1602: * <p>Find out whether or not a particular register exists at database</p>
1603: * @param oConn database connection
1604: * @return <b>true</b> if a register exists a DBPersist base table witch
1605: * primary key coincides with the one set in memory for the DBPersist.
1606: * @throws SQLException
1607: */
1608:
1609: public boolean exists(JDCConnection oConn) throws SQLException {
1610: if (null == oTable) {
1611: oTable = getTable(oConn);
1612: if (null == oTable)
1613: throw new SQLException("Table not found " + sTable,
1614: "42S02", 42002);
1615: return oTable.existsRegister(oConn, AllVals);
1616: } else
1617: return oTable.existsRegister(oConn, AllVals);
1618: }
1619:
1620: /**
1621: * <p>Get an XML dump for the DBPersist values</p>
1622: * @param sIdent Number of blank spaces for left padding at every line.
1623: * @param sDelim Line delimiter (usually "\n" or "\r\n")
1624: * @param oAttrs Map of values to be added as attributes of the toplevel node
1625: * @return XML String
1626: * @throws IllegalStateException If XML method is invoked before DBPersist object is loaded
1627: * @since 3.0
1628: */
1629:
1630: protected String toXML(String sIdent, String sDelim, HashMap oAttrs)
1631:
1632: throws IllegalStateException {
1633:
1634: if (null == oTable)
1635: throw new IllegalStateException(
1636: "DBPersist.toXML() method invoked before load() method was called");
1637:
1638: StringBuffer oBF = new StringBuffer(80 * oTable.columnCount());
1639: ListIterator oIT = oTable.getColumns().listIterator();
1640: DBColumn oColumn;
1641: Object oColValue;
1642: String sColName;
1643: String sStartElement = sIdent + sIdent + "<";
1644: String sEndElement = ">" + sDelim;
1645: Class oColClass, ClassString = null, ClassDate = null;
1646: SimpleDateFormat oXMLDate = new SimpleDateFormat(
1647: "yyyy-MM-dd'T'hh:mm:ss");
1648:
1649: try {
1650: ClassString = Class.forName("java.lang.String");
1651: ClassDate = Class.forName("java.util.Date");
1652: } catch (ClassNotFoundException ignore) {
1653: }
1654:
1655: if (null == oAttrs) {
1656: oBF.append(sIdent + "<" + sAuditCls + ">" + sDelim);
1657: } else {
1658: oBF.append(sIdent + "<" + sAuditCls);
1659: Iterator oNames = oAttrs.keySet().iterator();
1660: while (oNames.hasNext()) {
1661: Object oName = oNames.next();
1662: oBF.append(" " + oName + "=\"" + oAttrs.get(oName)
1663: + "\"");
1664: } // wend
1665: oBF.append(">" + sDelim);
1666: } // fi
1667:
1668: while (oIT.hasNext()) {
1669: oColumn = (DBColumn) oIT.next();
1670: sColName = oColumn.getName();
1671: oColValue = AllVals.get(sColName);
1672:
1673: oBF.append(sStartElement);
1674: oBF.append(sColName);
1675: oBF.append(">");
1676: if (null != oColValue) {
1677: oColClass = oColValue.getClass();
1678: if (oColClass.equals(ClassString))
1679: oBF.append("<![CDATA[" + oColValue + "]]>");
1680: else if (oColClass.equals(ClassDate))
1681: oBF.append(oXMLDate
1682: .format((java.util.Date) oColValue));
1683: else
1684: oBF.append(oColValue);
1685: }
1686: oBF.append("</");
1687: oBF.append(sColName);
1688: oBF.append(sEndElement);
1689: } // wend
1690:
1691: oBF.append(sIdent + "</" + sAuditCls + ">");
1692:
1693: return oBF.toString();
1694: } // toXML
1695:
1696: /**
1697: * <p>Get an XML dump for the DBPersist values</p>
1698: * @param sIdent Number of blank spaces for left padding at every line.
1699: * @param sDelim Line delimiter (usually "\n" or "\r\n")
1700: * @return XML String
1701: @ @throws IllegalStateException If XML method is invoked before DBPersist object is loaded
1702: */
1703:
1704: public String toXML(String sIdent, String sDelim)
1705: throws IllegalStateException {
1706: return toXML(sIdent, sDelim, null);
1707: }
1708:
1709: /**
1710: * <p>Get an XML dump for the DBPersist values.</p>
1711: * <p>Lines are delimited by a single Line Feed CHR(10) '\n' character.</p>
1712: * @param sIdent Number of blank spaces for left padding at every line.
1713: * @return XML String
1714: */
1715:
1716: public String toXML(String sIdent) {
1717: return toXML(sIdent, "\n", null);
1718: }
1719:
1720: /**
1721: * <p>Get an XML dump for the DBPersist values.</p>
1722: * <p>No left padding is placed to the left of each line.</p>
1723: * <p>Lines are delimited by a single Line Feed CHR(10) '\n' character.</p>
1724: * @return XML String
1725: */
1726:
1727: public String toXML() {
1728: return toXML("", "\n", null);
1729: }
1730:
1731: /**
1732: * <p>Load an XML String into DBPersist internal collection.</p>
1733: * <p>Each tag <field>...</field> found will be stored as a DBPersist value.</p>
1734: * <p>Example of input file:<br>
1735: * <?xml version="1.0" encoding="ISO-8859-1"?><br>
1736: * <ACLUser><br>
1737: * <gu_user>32f4f56fda343a5898c15a021203dd82</gu_user><br>
1738: * <id_domain>1026</id_domain><br>
1739: * <nm_user>The 7th Guest</nm_user><br>
1740: * <tx_pwd>123456</tx_pwd><br>
1741: * <tx_main_email>guest7@domain.com</tx_main_email><br>
1742: * <tx_alt_email>admin@hipergate.com</tx_alt_email><br>
1743: * <dt_last_updated>Fri, 29 Aug 2003 13:30:00 GMT+0130</dt_last_updated><br>
1744: * <tx_comments><![CDATA[Sôme ñasti & ïnternational chars stuff]]></tx_comments><br>
1745: * </ACLUser></p>
1746: * @param sXMLFilePath XML Path to XML file to parse
1747: * @throws SAXException
1748: * @throws SAXNotRecognizedException
1749: * @throws SAXNotSupportedException
1750: * @throws SAXParseException
1751: * @throws IOException
1752: * @throws ClassNotFoundException
1753: * @throws IllegalAccessException
1754: * @throws InstantiationException
1755: */
1756:
1757: public void parseXML(String sXMLFilePath) throws SAXException,
1758: SAXNotRecognizedException, SAXNotSupportedException,
1759: SAXParseException, IOException, ClassNotFoundException,
1760: IllegalAccessException, InstantiationException {
1761: DBSaxHandler oHandler = new DBSaxHandler(this );
1762: oHandler.parse(sXMLFilePath);
1763: }
1764:
1765: /**
1766: * Compares two objects and returns a Map of their differences
1767: * @param oOldInstance DBPersist
1768: * @return HashMap
1769: */
1770: protected HashMap changelog(DBPersist oOldInstance) {
1771: Object oKey, oOld, oNew;
1772: HashMap oLog = new HashMap(size() * 2);
1773:
1774: // Iterate throught this instance and see what keys are different at oOldInstance
1775: Iterator oKeys = keySet().iterator();
1776: while (oKeys.hasNext()) {
1777: oKey = oKeys.next();
1778: oNew = get(oKey);
1779: oOld = oOldInstance.get(oKey);
1780: if (null != oNew) {
1781: if (!oNew.equals(oOld))
1782: oLog.put(oKey, oOld);
1783: } else if (oOld != null) {
1784: oLog.put(oKey, oOld);
1785: }
1786: } // wend
1787:
1788: // Iterate throught oOldInstance and see what keys are different at this instance
1789: oKeys = oOldInstance.keySet().iterator();
1790: while (oKeys.hasNext()) {
1791: oKey = oKeys.next();
1792: if (!containsKey(oKey)) {
1793: oOld = oOldInstance.get(oKey);
1794: oLog.put(oKey, oOld);
1795: }
1796: } // wend
1797: return oLog;
1798: } // changelog
1799:
1800: /**
1801: * <p>Internal method for being called by inherited classes</p>
1802: * <p>Searches an object instance GUID from its unique name</p>
1803: * @param oConn Database Connection
1804: * @param iDomainId Domain Identifier
1805: * @param sInstanceNm Instance Name
1806: * @param sStoredProc Stored Procedure or PL/pgSQL Function Name
1807: * @return Global Unique Identifier of instance been searched or <n>null</n>
1808: * if no instance was found with such name.
1809: * @throws SQLException
1810: */
1811:
1812: protected static String getUIdFromName(JDCConnection oConn,
1813: Integer iDomainId, String sInstanceNm, String sStoredProc)
1814: throws SQLException {
1815: CallableStatement oCall;
1816: PreparedStatement oStmt;
1817: ResultSet oRSet;
1818:
1819: String sInstanceId;
1820:
1821: if (null == iDomainId) {
1822: if (JDCConnection.DBMS_POSTGRESQL == oConn
1823: .getDataBaseProduct()) {
1824: if (DebugFile.trace)
1825: DebugFile
1826: .writeln("Connection.prepareStatement(SELECT "
1827: + sStoredProc
1828: + "('"
1829: + sInstanceNm
1830: + "')");
1831:
1832: oStmt = oConn.prepareStatement("SELECT " + sStoredProc
1833: + "(?)", ResultSet.TYPE_FORWARD_ONLY,
1834: ResultSet.CONCUR_READ_ONLY);
1835: oStmt.setString(1, sInstanceNm);
1836: oRSet = oStmt.executeQuery();
1837: if (oRSet.next())
1838: sInstanceId = oRSet.getString(1);
1839: else
1840: sInstanceId = null;
1841: oRSet.close();
1842: oStmt.close();
1843: } else {
1844: if (DebugFile.trace)
1845: DebugFile.writeln("Connection.prepareCall({ call "
1846: + sStoredProc + " ('" + sInstanceNm
1847: + "',?)})");
1848:
1849: oCall = oConn.prepareCall("{ call " + sStoredProc
1850: + " (?,?)}");
1851: try {
1852: oCall.setQueryTimeout(15);
1853: } catch (SQLException sqle) {
1854: }
1855:
1856: oCall.setString(1, sInstanceNm);
1857: oCall.registerOutParameter(2, java.sql.Types.CHAR);
1858:
1859: oCall.execute();
1860:
1861: sInstanceId = oCall.getString(2);
1862:
1863: if (JDCConnection.DBMS_ORACLE == oConn
1864: .getDataBaseProduct()
1865: && null != sInstanceId)
1866: sInstanceId = sInstanceId.trim();
1867:
1868: oCall.close();
1869: oCall = null;
1870: }
1871: } else {
1872: if (JDCConnection.DBMS_POSTGRESQL == oConn
1873: .getDataBaseProduct()) {
1874: if (DebugFile.trace)
1875: DebugFile
1876: .writeln("Connection.prepareStatement(SELECT "
1877: + sStoredProc
1878: + "("
1879: + iDomainId.toString()
1880: + ",'"
1881: + sInstanceNm + "')");
1882:
1883: oStmt = oConn.prepareStatement("SELECT " + sStoredProc
1884: + "(?,?)", ResultSet.TYPE_FORWARD_ONLY,
1885: ResultSet.CONCUR_READ_ONLY);
1886: oStmt.setInt(1, iDomainId.intValue());
1887: oStmt.setString(2, sInstanceNm);
1888: oRSet = oStmt.executeQuery();
1889: if (oRSet.next())
1890: sInstanceId = oRSet.getString(1);
1891: else
1892: sInstanceId = null;
1893: oRSet.close();
1894: oStmt.close();
1895: } else {
1896: if (DebugFile.trace)
1897: DebugFile.writeln("Connection.prepareCall({ call "
1898: + sStoredProc + " (" + iDomainId.toString()
1899: + ",'" + sInstanceNm + "',?)})");
1900:
1901: oCall = oConn.prepareCall("{ call " + sStoredProc
1902: + " (?,?,?) }");
1903: try {
1904: oCall.setQueryTimeout(15);
1905: } catch (SQLException sqle) {
1906: }
1907:
1908: oCall.setInt(1, iDomainId.intValue());
1909: oCall.setString(2, sInstanceNm);
1910: oCall.registerOutParameter(3, java.sql.Types.CHAR);
1911:
1912: oCall.execute();
1913:
1914: sInstanceId = oCall.getString(3);
1915:
1916: if (null != sInstanceId)
1917: sInstanceId = sInstanceId.trim();
1918:
1919: oCall.close();
1920: oCall = null;
1921: }
1922: }
1923:
1924: return sInstanceId;
1925: } // getUIdFromName
1926:
1927: private static Class getClassForName(String sClassName) {
1928: Class oRetVal;
1929: try {
1930: oRetVal = Class.forName(sClassName);
1931: } catch (ClassNotFoundException cnfe) {
1932: oRetVal = null;
1933: }
1934: return oRetVal;
1935: } // getClassForName
1936:
1937: protected HashMap AllVals;
1938: protected String sAuditCls;
1939: protected String sAuditUsr;
1940: protected String sTransactId;
1941: private boolean bAllCaps;
1942: private boolean bHasLongVarBinaryData;
1943: private HashMap LongVarBinaryValsLen;
1944: private DBTable oTable;
1945: private String sTable;
1946:
1947: // ----------------------------------------------------------
1948:
1949: private static Class ClassLangString = getClassForName("java.lang.String");
1950: private static Class ClassUtilDate = getClassForName("java.util.Date");
1951: private static Class ClassSQLDate = getClassForName("java.sql.Date");
1952: private static Class ClassSQLTime = getClassForName("java.sql.Time");
1953: private static Class ClassTimestamp = getClassForName("java.sql.Timestamp");
1954:
1955: } //DBPersist
|