0001: package com.workingdogs.village;
0002:
0003: /*
0004: * Licensed to the Apache Software Foundation (ASF) under one
0005: * or more contributor license agreements. See the NOTICE file
0006: * distributed with this work for additional information
0007: * regarding copyright ownership. The ASF licenses this file
0008: * to you under the Apache License, Version 2.0 (the
0009: * "License"); you may not use this file except in compliance
0010: * with the License. You may obtain a copy of the License at
0011: *
0012: * http://www.apache.org/licenses/LICENSE-2.0
0013: *
0014: * Unless required by applicable law or agreed to in writing,
0015: * software distributed under the License is distributed on an
0016: * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
0017: * KIND, either express or implied. See the License for the
0018: * specific language governing permissions and limitations
0019: * under the License.
0020: */
0021:
0022: import java.io.ByteArrayOutputStream;
0023: import java.io.PrintWriter;
0024:
0025: import java.math.BigDecimal;
0026:
0027: import java.sql.Connection;
0028: import java.sql.PreparedStatement;
0029: import java.sql.ResultSet;
0030: import java.sql.SQLException;
0031:
0032: /**
0033: * A Record represents a row in the database. It contains a collection of <a href="Value.html">Values</A> which are the individual
0034: * contents of each column in the row.
0035: *
0036: * @author <a href="mailto:jon@latchkey.com">Jon S. Stevens</a>
0037: * @version $Revision: 568 $
0038: */
0039: public class Record {
0040: /** an array of Value objects, this is 1 based */
0041: private Value[] values;
0042:
0043: /** a 1 To 1 relationship between Values and whether they are clean or not */
0044: private boolean[] isClean;
0045:
0046: /** the parent DataSet for this Record */
0047: private DataSet parentDataSet;
0048:
0049: /** number of columns in this Record */
0050: private int numberOfColumns;
0051:
0052: /** this is the state of this record */
0053: private int saveType = 0;
0054:
0055: /** a saved copy of the schema for this Record */
0056: private Schema schema;
0057:
0058: /**
0059: * This isn't used and doesn't do anything.
0060: */
0061: public Record() {
0062: // don't do anything
0063: }
0064:
0065: /**
0066: * Creates a new Record and sets the parent dataset to the passed in value. This method also creates the Value objects which
0067: * are associated with this Record.
0068: *
0069: * @param ds TODO: DOCUMENT ME!
0070: *
0071: * @throws DataSetException TODO: DOCUMENT ME!
0072: * @throws SQLException TODO: DOCUMENT ME!
0073: */
0074: public Record(DataSet ds) throws DataSetException, SQLException {
0075: setParentDataSet(ds);
0076: initializeRecord();
0077: createValues(dataset().resultSet());
0078: }
0079:
0080: /**
0081: * This is a special case method for Record. This case is really only used when DataSet.addRecord() is called because we may
0082: * not have an existing ResultSet so there will not be any values in the Value objects that are created. Passing null to
0083: * createValues forces the Value object to be created, but no processing to be done within the Value object constructor.
0084: *
0085: * <P>
0086: * This method is a package method only because it is really not useful outside of the package.
0087: * </p>
0088: *
0089: * @param ds the dataset
0090: * @param addRecord whether or not this method is being called from DataSet.addRecord()
0091: *
0092: * @throws DataSetException TODO: DOCUMENT ME!
0093: * @throws SQLException TODO: DOCUMENT ME!
0094: */
0095: Record(DataSet ds, boolean addRecord) throws DataSetException,
0096: SQLException {
0097: setParentDataSet(ds);
0098: initializeRecord();
0099: createValues(null);
0100: }
0101:
0102: /**
0103: * Performs initialization for this Record.
0104: *
0105: * @throws DataSetException TODO: DOCUMENT ME!
0106: */
0107: private void initializeRecord() throws DataSetException {
0108: this .schema = dataset().schema();
0109: this .numberOfColumns = schema.numberOfColumns();
0110: this .values = new Value[size() + 1];
0111: this .isClean = new boolean[size() + 1];
0112: setSaveType(Enums.UNKNOWN);
0113:
0114: for (int i = 1; i <= size(); i++) {
0115: markValueClean(i);
0116: this .values[i] = null;
0117: }
0118: }
0119:
0120: /**
0121: * Creates the value objects for this Record. It is 1 based
0122: *
0123: * @param rs TODO: DOCUMENT ME!
0124: *
0125: * @exception DataSetException
0126: * @exception SQLException
0127: */
0128: private void createValues(ResultSet rs) throws DataSetException,
0129: SQLException {
0130: for (int i = 1; i <= size(); i++) {
0131: Value val = new Value(rs, i, schema().column(i).typeEnum());
0132: this .values[i] = val;
0133: }
0134: }
0135:
0136: /**
0137: * Saves the data in this Record to the database. Uses the parent dataset's connection.
0138: *
0139: * @return 1 if the save completed. 0 otherwise.
0140: *
0141: * @throws DataSetException TODO: DOCUMENT ME!
0142: * @throws SQLException TODO: DOCUMENT ME!
0143: */
0144: public int save() throws DataSetException, SQLException {
0145: return save(dataset().connection());
0146: }
0147:
0148: /**
0149: * Saves the data in this Record to the database. Uses the connection passed into it.
0150: *
0151: * @param connection TODO: DOCUMENT ME!
0152: *
0153: * @return 1 if the save completed. 0 otherwise.
0154: *
0155: * @throws DataSetException TODO: DOCUMENT ME!
0156: * @throws SQLException TODO: DOCUMENT ME!
0157: */
0158: public int save(Connection connection) throws DataSetException,
0159: SQLException {
0160: int returnValue = 0;
0161:
0162: if (dataset() instanceof QueryDataSet) {
0163: throw new DataSetException(
0164: "You cannot save a QueryDataSet. Please use a TableDataSet instead.");
0165: }
0166:
0167: if (!needsToBeSaved()) {
0168: return returnValue;
0169: }
0170:
0171: if (toBeSavedWithInsert()) {
0172: returnValue = saveWithInsert(connection);
0173: } else if (toBeSavedWithUpdate()) {
0174: returnValue = saveWithUpdate(connection);
0175: } else if (toBeSavedWithDelete()) {
0176: returnValue = saveWithDelete(connection);
0177: }
0178:
0179: return returnValue;
0180: }
0181:
0182: /**
0183: * Saves the data in this Record to the database with an DELETE statement
0184: *
0185: * @param connection TODO: DOCUMENT ME!
0186: *
0187: * @return SQL DELETE statement
0188: *
0189: * @throws DataSetException TODO: DOCUMENT ME!
0190: * @throws SQLException TODO: DOCUMENT ME!
0191: */
0192: private int saveWithDelete(Connection connection)
0193: throws DataSetException, SQLException {
0194: PreparedStatement stmt = null;
0195:
0196: try {
0197: stmt = connection.prepareStatement(getSaveString());
0198:
0199: int ps = 1;
0200:
0201: for (int i = 1; i <= dataset().keydef().size(); i++) {
0202: Value val = getValue(dataset().keydef().getAttrib(i));
0203:
0204: val.setPreparedStatementValue(stmt, ps++);
0205: }
0206:
0207: int ret = stmt.executeUpdate();
0208:
0209: // note that the actual deletion of the Record objects
0210: // from the TDS is now in the save() method of the TDS
0211: // instead of here. This fixes a bug where multiple
0212: // records would not be deleted properly because they
0213: // were being removed from here and the Records Vector
0214: // was getting out of sync with reality. So, just
0215: // mark them as needing to be removed here.
0216: setSaveType(Enums.ZOMBIE);
0217:
0218: if (ret > 1) {
0219: throw new SQLException("There were " + ret
0220: + " rows deleted with this records key value.");
0221: }
0222:
0223: return ret;
0224: } catch (SQLException e1) {
0225: throw e1;
0226: } finally {
0227: try {
0228: if (stmt != null) {
0229: stmt.close();
0230: }
0231: } catch (SQLException e2) {
0232: throw e2;
0233: }
0234: }
0235: }
0236:
0237: /**
0238: * Saves the data in this Record to the database with an UPDATE statement
0239: *
0240: * @param connection TODO: DOCUMENT ME!
0241: *
0242: * @return SQL UPDATE statement
0243: *
0244: * @throws DataSetException TODO: DOCUMENT ME!
0245: * @throws SQLException TODO: DOCUMENT ME!
0246: */
0247: private int saveWithUpdate(Connection connection)
0248: throws DataSetException, SQLException {
0249: PreparedStatement stmt = null;
0250:
0251: try {
0252: stmt = connection.prepareStatement(getSaveString());
0253:
0254: int ps = 1;
0255:
0256: for (int i = 1; i <= size(); i++) {
0257: Value val = getValue(i);
0258:
0259: if (!valueIsClean(i) && !schema().column(i).readOnly()) {
0260: val.setPreparedStatementValue(stmt, ps++);
0261: }
0262: }
0263:
0264: for (int i = 1; i <= dataset().keydef().size(); i++) {
0265: Value val = getValue(dataset().keydef().getAttrib(i));
0266:
0267: val.setPreparedStatementValue(stmt, ps++);
0268: }
0269:
0270: int ret = stmt.executeUpdate();
0271:
0272: if (((TableDataSet) dataset()).refreshOnSave()) {
0273: refresh(dataset().connection());
0274: } else {
0275: // Marks all of the values clean since they have now been saved
0276: markRecordClean();
0277: }
0278:
0279: setSaveType(Enums.AFTERUPDATE);
0280:
0281: if (ret > 1) {
0282: throw new SQLException("There were " + ret
0283: + " rows updated with this records key value.");
0284: }
0285:
0286: return ret;
0287: } catch (SQLException e1) {
0288: throw e1;
0289: } finally {
0290: try {
0291: if (stmt != null) {
0292: stmt.close();
0293: }
0294: } catch (SQLException e2) {
0295: throw e2;
0296: }
0297: }
0298: }
0299:
0300: /**
0301: * Saves the data in this Record to the database with an INSERT statement
0302: *
0303: * @param connection TODO: DOCUMENT ME!
0304: *
0305: * @return SQL INSERT statement
0306: *
0307: * @throws DataSetException TODO: DOCUMENT ME!
0308: * @throws SQLException TODO: DOCUMENT ME!
0309: */
0310: private int saveWithInsert(Connection connection)
0311: throws DataSetException, SQLException {
0312: PreparedStatement stmt = null;
0313:
0314: try {
0315: stmt = connection.prepareStatement(getSaveString());
0316:
0317: int ps = 1;
0318:
0319: for (int i = 1; i <= size(); i++) {
0320: Value val = getValue(i);
0321:
0322: if (!valueIsClean(i) && !schema().column(i).readOnly()) {
0323: val.setPreparedStatementValue(stmt, ps++);
0324: }
0325: }
0326:
0327: int ret = stmt.executeUpdate();
0328:
0329: if (((TableDataSet) dataset()).refreshOnSave()) {
0330: refresh(dataset().connection());
0331: } else {
0332: // Marks all of the values clean since they have now been saved
0333: markRecordClean();
0334: }
0335:
0336: setSaveType(Enums.AFTERINSERT);
0337:
0338: if (ret > 1) {
0339: throw new SQLException("There were " + ret
0340: + " rows inserted with this records key value.");
0341: }
0342:
0343: return ret;
0344: } catch (SQLException e1) {
0345: throw e1;
0346: } finally {
0347: try {
0348: if (stmt != null) {
0349: stmt.close();
0350: }
0351: } catch (SQLException e2) {
0352: throw e2;
0353: }
0354: }
0355: }
0356:
0357: /**
0358: * Builds the SQL UPDATE statement for this Record
0359: *
0360: * @return SQL UPDATE statement
0361: *
0362: * @throws DataSetException TODO: DOCUMENT ME!
0363: */
0364: private String getUpdateSaveString() throws DataSetException {
0365: KeyDef kd = dataset().keydef();
0366:
0367: if ((kd == null) || (kd.size() == 0)) {
0368: throw new DataSetException(
0369: "You must specify KeyDef attributes for this TableDataSet in order to create a Record for update.");
0370: } else if (recordIsClean()) {
0371: throw new DataSetException(
0372: "You must Record.setValue() on a column before doing an update.");
0373: }
0374:
0375: StringBuffer iss1 = new StringBuffer(256);
0376: StringBuffer iss2 = new StringBuffer(256);
0377: boolean comma = false;
0378:
0379: for (int i = 1; i <= size(); i++) {
0380: if (!valueIsClean(i) && !schema().column(i).readOnly()) {
0381: if (!comma) {
0382: iss1.append(schema().column(i).name());
0383: iss1.append(" = ?");
0384: comma = true;
0385: } else {
0386: iss1.append(", ");
0387: iss1.append(schema().column(i).name());
0388: iss1.append(" = ?");
0389: }
0390: }
0391: }
0392:
0393: comma = false;
0394:
0395: for (int i = 1; i <= kd.size(); i++) {
0396: String attrib = kd.getAttrib(i);
0397:
0398: if (!valueIsClean(schema().index(attrib))) {
0399: throw new DataSetException("The value for column '"
0400: + attrib
0401: + "' is a key value and cannot be updated.");
0402: }
0403:
0404: if (!comma) {
0405: iss2.append(attrib);
0406: iss2.append(" = ?");
0407: comma = true;
0408: } else {
0409: iss2.append(" AND ");
0410: iss2.append(attrib);
0411: iss2.append(" = ?");
0412: }
0413: }
0414:
0415: return "UPDATE " + schema().tableName() + " SET "
0416: + iss1.toString() + " WHERE " + iss2.toString();
0417: }
0418:
0419: /**
0420: * Builds the SQL DELETE statement for this Record
0421: *
0422: * @return SQL DELETE statement
0423: *
0424: * @throws DataSetException TODO: DOCUMENT ME!
0425: */
0426: private String getDeleteSaveString() throws DataSetException {
0427: KeyDef kd = dataset().keydef();
0428:
0429: if ((kd == null) || (kd.size() == 0)) {
0430: throw new DataSetException(
0431: "You must specify KeyDef attributes for this TableDataSet in order to delete a Record.");
0432: }
0433:
0434: StringBuffer iss1 = new StringBuffer(256);
0435:
0436: boolean comma = false;
0437:
0438: for (int i = 1; i <= kd.size(); i++) {
0439: if (!comma) {
0440: iss1.append(kd.getAttrib(i));
0441: iss1.append(" = ?");
0442: comma = true;
0443: } else {
0444: iss1.append(" AND ");
0445: iss1.append(kd.getAttrib(i));
0446: iss1.append(" = ? ");
0447: }
0448: }
0449:
0450: return "DELETE FROM " + schema().tableName() + " WHERE "
0451: + iss1.toString();
0452: }
0453:
0454: /**
0455: * Builds the SQL INSERT statement for this Record
0456: *
0457: * @return SQL INSERT statement
0458: *
0459: * @throws DataSetException TODO: DOCUMENT ME!
0460: */
0461: private String getInsertSaveString() throws DataSetException {
0462: StringBuffer iss1 = new StringBuffer(256);
0463: StringBuffer iss2 = new StringBuffer(256);
0464:
0465: boolean comma = false;
0466:
0467: for (int i = 1; i <= size(); i++) {
0468: if (!valueIsClean(i) && !schema().column(i).readOnly()) {
0469: if (!comma) {
0470: iss1.append(schema().column(i).name());
0471: iss2.append("?");
0472: comma = true;
0473: } else {
0474: iss1.append(", " + schema().column(i).name());
0475: iss2.append(", ?");
0476: }
0477: }
0478: }
0479:
0480: return "INSERT INTO " + schema().tableName() + " ( "
0481: + iss1.toString() + " ) VALUES ( " + iss2.toString()
0482: + " )";
0483: }
0484:
0485: /*
0486: * private Hashtable getAffectedColumns()
0487: * throws DataSetException
0488: * {
0489: * Hashtable affectedColumns = new Hashtable ( size() );
0490: * for ( int i = 1; i <= size(); i++ )
0491: * {
0492: * if ( valueIsClean(i) == false )
0493: * affectedColumns.put ( (Object) new Integer(i) , (Object) schema().getColumns()[i].name() );
0494: * }
0495: * return affectedColumns;
0496: * }
0497: */
0498:
0499: /**
0500: * Gets the appropriate SQL string for this record.
0501: *
0502: * @return SQL string
0503: *
0504: * @throws DataSetException TODO: DOCUMENT ME!
0505: */
0506: public String getSaveString() throws DataSetException {
0507: if (toBeSavedWithInsert()) {
0508: return getInsertSaveString();
0509: } else if (toBeSavedWithUpdate()) {
0510: return getUpdateSaveString();
0511: } else if (toBeSavedWithDelete()) {
0512: return getDeleteSaveString();
0513: } else {
0514: throw new DataSetException(
0515: "Not able to return save string: " + this .saveType);
0516: }
0517: }
0518:
0519: /**
0520: * gets the value at index i
0521: *
0522: * @param i TODO: DOCUMENT ME!
0523: *
0524: * @return the Value object at index i
0525: *
0526: * @throws DataSetException TODO: DOCUMENT ME!
0527: */
0528: public Value getValue(int i) throws DataSetException {
0529: if (i == 0) {
0530: throw new DataSetException("Values are 1 based!");
0531: } else if (i > size()) {
0532: throw new DataSetException("Only " + size()
0533: + " columns exist!");
0534: } else if (values[i] == null) {
0535: throw new DataSetException(
0536: "No values for the requested column!");
0537: }
0538:
0539: return values[i];
0540: }
0541:
0542: /**
0543: * TODO: DOCUMENT ME!
0544: *
0545: * @param columnName TODO: DOCUMENT ME!
0546: *
0547: * @return TODO: DOCUMENT ME!
0548: *
0549: * @throws DataSetException TODO: DOCUMENT ME!
0550: */
0551: public Value getValue(String columnName) throws DataSetException {
0552: return getValue(schema().index(columnName));
0553: }
0554:
0555: /**
0556: * the number of columns in this object
0557: *
0558: * @return the number of columns in this object
0559: */
0560: public int size() {
0561: return numberOfColumns;
0562: }
0563:
0564: /**
0565: * whether or not this Record is to be saved with an SQL insert statement
0566: *
0567: * @return true if saved with insert
0568: */
0569: public boolean toBeSavedWithInsert() {
0570: return (this .saveType == Enums.INSERT) ? true : false;
0571: }
0572:
0573: /**
0574: * whether or not this Record is to be saved with an SQL update statement
0575: *
0576: * @return true if saved with update
0577: */
0578: public boolean toBeSavedWithUpdate() {
0579: return (this .saveType == Enums.UPDATE) ? true : false;
0580: }
0581:
0582: /**
0583: * whether or not this Record is to be saved with an SQL delete statement
0584: *
0585: * @return true if saved with delete
0586: */
0587: public boolean toBeSavedWithDelete() {
0588: return (this .saveType == Enums.DELETE) ? true : false;
0589: }
0590:
0591: /**
0592: * Marks all the values in this record as clean.
0593: *
0594: * @throws DataSetException TODO: DOCUMENT ME!
0595: */
0596: public void markRecordClean() throws DataSetException {
0597: for (int i = 1; i <= size(); i++) {
0598: markValueClean(i);
0599: }
0600: }
0601:
0602: /**
0603: * Marks this record to be inserted when a save is executed.
0604: *
0605: * @throws DataSetException TODO: DOCUMENT ME!
0606: */
0607: public void markForInsert() throws DataSetException {
0608: if (dataset() instanceof QueryDataSet) {
0609: throw new DataSetException(
0610: "You cannot mark a record in a QueryDataSet for insert");
0611: }
0612:
0613: setSaveType(Enums.INSERT);
0614: }
0615:
0616: /**
0617: * Marks this record to be updated when a save is executed.
0618: *
0619: * @throws DataSetException TODO: DOCUMENT ME!
0620: */
0621: public void markForUpdate() throws DataSetException {
0622: if (dataset() instanceof QueryDataSet) {
0623: throw new DataSetException(
0624: "You cannot mark a record in a QueryDataSet for update");
0625: }
0626:
0627: setSaveType(Enums.UPDATE);
0628: }
0629:
0630: /**
0631: * Marks this record to be deleted when a save is executed.
0632: *
0633: * @return TODO: DOCUMENT ME!
0634: *
0635: * @throws DataSetException TODO: DOCUMENT ME!
0636: */
0637: public Record markToBeDeleted() throws DataSetException {
0638: if (dataset() instanceof QueryDataSet) {
0639: throw new DataSetException(
0640: "You cannot mark a record in a QueryDataSet for deletion");
0641: }
0642:
0643: setSaveType(Enums.DELETE);
0644:
0645: return this ;
0646: }
0647:
0648: /**
0649: * Unmarks a record that has been marked for deletion.
0650: *
0651: * <P>
0652: * WARNING: You must reset the save type before trying to save this record again.
0653: * </p>
0654: *
0655: * @return TODO: DOCUMENT ME!
0656: *
0657: * @throws DataSetException TODO: DOCUMENT ME!
0658: *
0659: * @see #markForUpdate()
0660: * @see #markForInsert()
0661: * @see #markToBeDeleted()
0662: */
0663: public Record unmarkToBeDeleted() throws DataSetException {
0664: if (this .saveType == Enums.ZOMBIE) {
0665: throw new DataSetException(
0666: "This record has already been deleted!");
0667: }
0668:
0669: setSaveType(Enums.UNKNOWN);
0670:
0671: return this ;
0672: }
0673:
0674: /**
0675: * marks a value at a given position as clean.
0676: *
0677: * @param pos TODO: DOCUMENT ME!
0678: *
0679: * @throws DataSetException TODO: DOCUMENT ME!
0680: */
0681: public void markValueClean(int pos) throws DataSetException {
0682: if (pos == 0) {
0683: throw new DataSetException(
0684: "Value position must be greater than 0.");
0685: } else if (pos > size()) {
0686: throw new DataSetException(
0687: "Value position is greater than number of values.");
0688: }
0689:
0690: this .isClean[pos] = true;
0691: }
0692:
0693: /**
0694: * marks a value with a given column name as clean.
0695: *
0696: * @param columnName TODO: DOCUMENT ME!
0697: *
0698: * @throws DataSetException TODO: DOCUMENT ME!
0699: */
0700: public void markValueClean(String columnName)
0701: throws DataSetException {
0702: markValueClean(schema().index(columnName));
0703: }
0704:
0705: /**
0706: * marks a value at a given position as dirty.
0707: *
0708: * @param pos TODO: DOCUMENT ME!
0709: *
0710: * @throws DataSetException TODO: DOCUMENT ME!
0711: */
0712: public void markValueDirty(int pos) throws DataSetException {
0713: if (pos == 0) {
0714: throw new DataSetException(
0715: "Value position must be greater than 0.");
0716: } else if (pos > size()) {
0717: throw new DataSetException(
0718: "Value position is greater than number of values.");
0719: }
0720:
0721: this .isClean[pos] = false;
0722: }
0723:
0724: /**
0725: * marks a value with a given column name as dirty.
0726: *
0727: * @param columnName TODO: DOCUMENT ME!
0728: *
0729: * @throws DataSetException TODO: DOCUMENT ME!
0730: */
0731: public void markValueDirty(String columnName)
0732: throws DataSetException {
0733: markValueDirty(schema().index(columnName));
0734: }
0735:
0736: /**
0737: * sets the internal save type as one of the defined privates (ie: ZOMBIE)
0738: *
0739: * @param type TODO: DOCUMENT ME!
0740: */
0741: void setSaveType(int type) {
0742: this .saveType = type;
0743: }
0744:
0745: /**
0746: * gets the internal save type as one of the defined privates (ie: ZOMBIE)
0747: *
0748: * @return TODO: DOCUMENT ME!
0749: */
0750: int getSaveType() {
0751: return this .saveType;
0752: }
0753:
0754: /**
0755: * sets the value at pos with a BigDecimal
0756: *
0757: * @param pos TODO: DOCUMENT ME!
0758: * @param value TODO: DOCUMENT ME!
0759: *
0760: * @return TODO: DOCUMENT ME!
0761: *
0762: * @throws DataSetException TODO: DOCUMENT ME!
0763: */
0764: public Record setValue(int pos, BigDecimal value)
0765: throws DataSetException {
0766: this .values[pos].setValue(value);
0767: markValueDirty(pos);
0768:
0769: return this ;
0770: }
0771:
0772: /**
0773: * sets the value at pos with a boolean
0774: *
0775: * @param pos TODO: DOCUMENT ME!
0776: * @param value TODO: DOCUMENT ME!
0777: *
0778: * @return TODO: DOCUMENT ME!
0779: *
0780: * @throws DataSetException TODO: DOCUMENT ME!
0781: */
0782: public Record setValue(int pos, boolean value)
0783: throws DataSetException {
0784: this .values[pos].setValue(new Boolean(value));
0785: markValueDirty(pos);
0786:
0787: return this ;
0788: }
0789:
0790: /**
0791: * sets the value at pos with a byte[]
0792: *
0793: * @param pos TODO: DOCUMENT ME!
0794: * @param value TODO: DOCUMENT ME!
0795: *
0796: * @return TODO: DOCUMENT ME!
0797: *
0798: * @throws DataSetException TODO: DOCUMENT ME!
0799: */
0800: public Record setValue(int pos, byte[] value)
0801: throws DataSetException {
0802: this .values[pos].setValue(value);
0803: markValueDirty(pos);
0804:
0805: return this ;
0806: }
0807:
0808: /**
0809: * sets the value at pos with a java.util.Date
0810: *
0811: * @param pos TODO: DOCUMENT ME!
0812: * @param value TODO: DOCUMENT ME!
0813: *
0814: * @return TODO: DOCUMENT ME!
0815: *
0816: * @throws DataSetException TODO: DOCUMENT ME!
0817: */
0818: public Record setValue(int pos, java.util.Date value)
0819: throws DataSetException {
0820: this .values[pos].setValue(value);
0821: markValueDirty(pos);
0822:
0823: return this ;
0824: }
0825:
0826: /**
0827: * sets the value at pos with a java.sql.Date
0828: *
0829: * @param pos TODO: DOCUMENT ME!
0830: * @param value TODO: DOCUMENT ME!
0831: *
0832: * @return TODO: DOCUMENT ME!
0833: *
0834: * @throws DataSetException TODO: DOCUMENT ME!
0835: */
0836: public Record setValue(int pos, java.sql.Date value)
0837: throws DataSetException {
0838: this .values[pos].setValue(value);
0839: markValueDirty(pos);
0840:
0841: return this ;
0842: }
0843:
0844: /**
0845: * sets the value at pos with a double
0846: *
0847: * @param pos TODO: DOCUMENT ME!
0848: * @param value TODO: DOCUMENT ME!
0849: *
0850: * @return TODO: DOCUMENT ME!
0851: *
0852: * @throws DataSetException TODO: DOCUMENT ME!
0853: */
0854: public Record setValue(int pos, double value)
0855: throws DataSetException {
0856: this .values[pos].setValue(new Double(value));
0857: markValueDirty(pos);
0858:
0859: return this ;
0860: }
0861:
0862: /**
0863: * sets the value at pos with a float
0864: *
0865: * @param pos TODO: DOCUMENT ME!
0866: * @param value TODO: DOCUMENT ME!
0867: *
0868: * @return TODO: DOCUMENT ME!
0869: *
0870: * @throws DataSetException TODO: DOCUMENT ME!
0871: */
0872: public Record setValue(int pos, float value)
0873: throws DataSetException {
0874: this .values[pos].setValue(new Float(value));
0875: markValueDirty(pos);
0876:
0877: return this ;
0878: }
0879:
0880: /**
0881: * sets the value at pos with a int
0882: *
0883: * @param pos TODO: DOCUMENT ME!
0884: * @param value TODO: DOCUMENT ME!
0885: *
0886: * @return TODO: DOCUMENT ME!
0887: *
0888: * @throws DataSetException TODO: DOCUMENT ME!
0889: */
0890: public Record setValue(int pos, int value) throws DataSetException {
0891: this .values[pos].setValue(new Integer(value));
0892: markValueDirty(pos);
0893:
0894: return this ;
0895: }
0896:
0897: /**
0898: * sets the value at pos with a long
0899: *
0900: * @param pos TODO: DOCUMENT ME!
0901: * @param value TODO: DOCUMENT ME!
0902: *
0903: * @return TODO: DOCUMENT ME!
0904: *
0905: * @throws DataSetException TODO: DOCUMENT ME!
0906: */
0907: public Record setValue(int pos, long value) throws DataSetException {
0908: this .values[pos].setValue(new Long(value));
0909: markValueDirty(pos);
0910:
0911: return this ;
0912: }
0913:
0914: /**
0915: * sets the value at pos with a String
0916: *
0917: * @param pos TODO: DOCUMENT ME!
0918: * @param value TODO: DOCUMENT ME!
0919: *
0920: * @return TODO: DOCUMENT ME!
0921: *
0922: * @throws DataSetException TODO: DOCUMENT ME!
0923: */
0924: public Record setValue(int pos, String value)
0925: throws DataSetException {
0926: this .values[pos].setValue(value);
0927: markValueDirty(pos);
0928:
0929: return this ;
0930: }
0931:
0932: /**
0933: * sets the value at pos with a java.sql.Time
0934: *
0935: * @param pos TODO: DOCUMENT ME!
0936: * @param value TODO: DOCUMENT ME!
0937: *
0938: * @return TODO: DOCUMENT ME!
0939: *
0940: * @throws DataSetException TODO: DOCUMENT ME!
0941: */
0942: public Record setValue(int pos, java.sql.Time value)
0943: throws DataSetException {
0944: this .values[pos].setValue(value);
0945: markValueDirty(pos);
0946:
0947: return this ;
0948: }
0949:
0950: /**
0951: * sets the value at pos with a java.sql.Timestamp
0952: *
0953: * @param pos TODO: DOCUMENT ME!
0954: * @param value TODO: DOCUMENT ME!
0955: *
0956: * @return TODO: DOCUMENT ME!
0957: *
0958: * @throws DataSetException TODO: DOCUMENT ME!
0959: */
0960: public Record setValue(int pos, java.sql.Timestamp value)
0961: throws DataSetException {
0962: this .values[pos].setValue(value);
0963: markValueDirty(pos);
0964:
0965: return this ;
0966: }
0967:
0968: /**
0969: * sets the value at pos with a Value
0970: *
0971: * @param pos TODO: DOCUMENT ME!
0972: * @param value TODO: DOCUMENT ME!
0973: *
0974: * @return TODO: DOCUMENT ME!
0975: *
0976: * @throws DataSetException TODO: DOCUMENT ME!
0977: */
0978: public Record setValue(int pos, Value value)
0979: throws DataSetException {
0980: this .values[pos].setValue(value.getValue());
0981: markValueDirty(pos);
0982:
0983: return this ;
0984: }
0985:
0986: /**
0987: * sets the value at column name with a BigDecimal
0988: *
0989: * @param columnName TODO: DOCUMENT ME!
0990: * @param value TODO: DOCUMENT ME!
0991: *
0992: * @return TODO: DOCUMENT ME!
0993: *
0994: * @throws DataSetException TODO: DOCUMENT ME!
0995: */
0996: public Record setValue(String columnName, BigDecimal value)
0997: throws DataSetException {
0998: setValue(schema().index(columnName), value);
0999:
1000: return this ;
1001: }
1002:
1003: /**
1004: * sets the value at column name with a boolean
1005: *
1006: * @param columnName TODO: DOCUMENT ME!
1007: * @param value TODO: DOCUMENT ME!
1008: *
1009: * @return TODO: DOCUMENT ME!
1010: *
1011: * @throws DataSetException TODO: DOCUMENT ME!
1012: */
1013: public Record setValue(String columnName, boolean value)
1014: throws DataSetException {
1015: setValue(schema().index(columnName), value);
1016:
1017: return this ;
1018: }
1019:
1020: /**
1021: * sets the value at column name with a byte[]
1022: *
1023: * @param columnName TODO: DOCUMENT ME!
1024: * @param value TODO: DOCUMENT ME!
1025: *
1026: * @return TODO: DOCUMENT ME!
1027: *
1028: * @throws DataSetException TODO: DOCUMENT ME!
1029: */
1030: public Record setValue(String columnName, byte[] value)
1031: throws DataSetException {
1032: setValue(schema().index(columnName), value);
1033:
1034: return this ;
1035: }
1036:
1037: /**
1038: * sets the value at column name with a java.util.Date
1039: *
1040: * @param columnName TODO: DOCUMENT ME!
1041: * @param value TODO: DOCUMENT ME!
1042: *
1043: * @return TODO: DOCUMENT ME!
1044: *
1045: * @throws DataSetException TODO: DOCUMENT ME!
1046: */
1047: public Record setValue(String columnName, java.util.Date value)
1048: throws DataSetException {
1049: setValue(schema().index(columnName), value);
1050:
1051: return this ;
1052: }
1053:
1054: /**
1055: * sets the value at column name with a java.sql.Date
1056: *
1057: * @param columnName TODO: DOCUMENT ME!
1058: * @param value TODO: DOCUMENT ME!
1059: *
1060: * @return TODO: DOCUMENT ME!
1061: *
1062: * @throws DataSetException TODO: DOCUMENT ME!
1063: */
1064: public Record setValue(String columnName, java.sql.Date value)
1065: throws DataSetException {
1066: setValue(schema().index(columnName), value);
1067:
1068: return this ;
1069: }
1070:
1071: /**
1072: * sets the value at column name with a double
1073: *
1074: * @param columnName TODO: DOCUMENT ME!
1075: * @param value TODO: DOCUMENT ME!
1076: *
1077: * @return TODO: DOCUMENT ME!
1078: *
1079: * @throws DataSetException TODO: DOCUMENT ME!
1080: */
1081: public Record setValue(String columnName, double value)
1082: throws DataSetException {
1083: setValue(schema().index(columnName), value);
1084:
1085: return this ;
1086: }
1087:
1088: /**
1089: * sets the value at column name with a float
1090: *
1091: * @param columnName TODO: DOCUMENT ME!
1092: * @param value TODO: DOCUMENT ME!
1093: *
1094: * @return TODO: DOCUMENT ME!
1095: *
1096: * @throws DataSetException TODO: DOCUMENT ME!
1097: */
1098: public Record setValue(String columnName, float value)
1099: throws DataSetException {
1100: setValue(schema().index(columnName), value);
1101:
1102: return this ;
1103: }
1104:
1105: /**
1106: * sets the value at column name with a int
1107: *
1108: * @param columnName TODO: DOCUMENT ME!
1109: * @param value TODO: DOCUMENT ME!
1110: *
1111: * @return TODO: DOCUMENT ME!
1112: *
1113: * @throws DataSetException TODO: DOCUMENT ME!
1114: */
1115: public Record setValue(String columnName, int value)
1116: throws DataSetException {
1117: setValue(schema().index(columnName), value);
1118:
1119: return this ;
1120: }
1121:
1122: /**
1123: * sets the value at column name with a long
1124: *
1125: * @param columnName TODO: DOCUMENT ME!
1126: * @param value TODO: DOCUMENT ME!
1127: *
1128: * @return TODO: DOCUMENT ME!
1129: *
1130: * @throws DataSetException TODO: DOCUMENT ME!
1131: */
1132: public Record setValue(String columnName, long value)
1133: throws DataSetException {
1134: setValue(schema().index(columnName), value);
1135:
1136: return this ;
1137: }
1138:
1139: /**
1140: * sets the value at column name with a String
1141: *
1142: * @param columnName TODO: DOCUMENT ME!
1143: * @param value TODO: DOCUMENT ME!
1144: *
1145: * @return TODO: DOCUMENT ME!
1146: *
1147: * @throws DataSetException TODO: DOCUMENT ME!
1148: */
1149: public Record setValue(String columnName, String value)
1150: throws DataSetException {
1151: setValue(schema().index(columnName), value);
1152:
1153: return this ;
1154: }
1155:
1156: /**
1157: * sets the value at column name with a java.sql.Time
1158: *
1159: * @param columnName TODO: DOCUMENT ME!
1160: * @param value TODO: DOCUMENT ME!
1161: *
1162: * @return TODO: DOCUMENT ME!
1163: *
1164: * @throws DataSetException TODO: DOCUMENT ME!
1165: */
1166: public Record setValue(String columnName, java.sql.Time value)
1167: throws DataSetException {
1168: setValue(schema().index(columnName), value);
1169:
1170: return this ;
1171: }
1172:
1173: /**
1174: * sets the value at column name with a java.sql.Timestamp
1175: *
1176: * @param columnName TODO: DOCUMENT ME!
1177: * @param value TODO: DOCUMENT ME!
1178: *
1179: * @return TODO: DOCUMENT ME!
1180: *
1181: * @throws DataSetException TODO: DOCUMENT ME!
1182: */
1183: public Record setValue(String columnName, java.sql.Timestamp value)
1184: throws DataSetException {
1185: setValue(schema().index(columnName), value);
1186:
1187: return this ;
1188: }
1189:
1190: /**
1191: * sets the value at column name with a Value
1192: *
1193: * @param columnName TODO: DOCUMENT ME!
1194: * @param value TODO: DOCUMENT ME!
1195: *
1196: * @return TODO: DOCUMENT ME!
1197: *
1198: * @throws DataSetException TODO: DOCUMENT ME!
1199: */
1200: public Record setValue(String columnName, Value value)
1201: throws DataSetException {
1202: setValue(schema().index(columnName), value);
1203:
1204: return this ;
1205: }
1206:
1207: /**
1208: * sets the value at pos with a NULL
1209: *
1210: * @param pos TODO: DOCUMENT ME!
1211: *
1212: * @return TODO: DOCUMENT ME!
1213: *
1214: * @throws DataSetException TODO: DOCUMENT ME!
1215: */
1216: public Record setValueNull(int pos) throws DataSetException {
1217: if (pos == 0) {
1218: throw new DataSetException(
1219: "Value position must be greater than 0.");
1220: } else if (pos > size()) {
1221: throw new DataSetException(
1222: "Value position is greater than number of values.");
1223: }
1224:
1225: this .values[pos].setValue(null);
1226: markValueDirty(pos);
1227:
1228: return this ;
1229: }
1230:
1231: /**
1232: * sets the value at column name with a NULL
1233: *
1234: * @param columnName TODO: DOCUMENT ME!
1235: *
1236: * @return TODO: DOCUMENT ME!
1237: *
1238: * @throws DataSetException TODO: DOCUMENT ME!
1239: */
1240: public Record setValueNull(String columnName)
1241: throws DataSetException {
1242: if ((columnName == null) || (columnName.length() == 0)) {
1243: throw new DataSetException(
1244: "You must specify a column name!");
1245: }
1246:
1247: setValueNull(schema().index(columnName));
1248:
1249: return this ;
1250: }
1251:
1252: /**
1253: * Determines if this record is a Zombie. A Zombie is a record that has been deleted from the database, but not yet removed
1254: * from the DataSet.
1255: *
1256: * @return a boolean
1257: */
1258: public boolean isAZombie() {
1259: return (this .saveType == Enums.ZOMBIE) ? true : false;
1260: }
1261:
1262: /**
1263: * If the record is not clean, needs to be saved with an Update, Delete or Insert, it returns true.
1264: *
1265: * @return boolean
1266: */
1267: public boolean needsToBeSaved() {
1268: return !isAZombie() || !recordIsClean()
1269: || toBeSavedWithUpdate() || toBeSavedWithDelete()
1270: || toBeSavedWithInsert();
1271: }
1272:
1273: /**
1274: * Determines whether or not a value stored in the record is clean.
1275: *
1276: * @param i TODO: DOCUMENT ME!
1277: *
1278: * @return true if clean
1279: */
1280: public boolean valueIsClean(int i) {
1281: return isClean[i];
1282: }
1283:
1284: /**
1285: * Determines whether or not a value stored in the record is clean.
1286: *
1287: * @param column TODO: DOCUMENT ME!
1288: *
1289: * @return true if clean
1290: *
1291: * @throws DataSetException TODO: DOCUMENT ME!
1292: */
1293: boolean valueIsClean(String column) throws DataSetException {
1294: return isClean[getValue(column).columnNumber()];
1295: }
1296:
1297: /**
1298: * Goes through all the values in the record to determine if it is clean or not.
1299: *
1300: * @return true if clean
1301: */
1302: public boolean recordIsClean() {
1303: for (int i = 1; i <= size(); i++) {
1304: if (!valueIsClean(i)) {
1305: return false;
1306: }
1307: }
1308:
1309: return true;
1310: }
1311:
1312: /**
1313: * This method refreshes this Record's Value's. It can only be performed on a Record that has not been modified and has been
1314: * created with a TableDataSet and corresponding KeyDef.
1315: *
1316: * @param connection
1317: *
1318: * @exception DataSetException
1319: * @exception SQLException
1320: */
1321: public void refresh(Connection connection) throws DataSetException,
1322: SQLException {
1323: if (toBeSavedWithDelete()) {
1324: return;
1325: } else if (toBeSavedWithInsert()) {
1326: throw new DataSetException(
1327: "There is no way to refresh a record which has been created with addRecord().");
1328: } else if (dataset() instanceof QueryDataSet) {
1329: throw new DataSetException(
1330: "You can only perform a refresh on Records created with a TableDataSet.");
1331: }
1332:
1333: PreparedStatement stmt = null;
1334:
1335: try {
1336: stmt = connection.prepareStatement(getRefreshQueryString());
1337:
1338: int ps = 1;
1339:
1340: for (int i = 1; i <= dataset().keydef().size(); i++) {
1341: Value val = getValue(dataset().keydef().getAttrib(i));
1342:
1343: if (val.isNull()) {
1344: throw new DataSetException(
1345: "You cannot execute an update with a null value for a KeyDef.");
1346: }
1347:
1348: val.setPreparedStatementValue(stmt, ps++);
1349: }
1350:
1351: ResultSet rs = stmt.executeQuery();
1352: rs.next();
1353:
1354: initializeRecord();
1355:
1356: createValues(rs);
1357: } catch (SQLException e1) {
1358: throw e1;
1359: } finally {
1360: try {
1361: if (stmt != null) {
1362: stmt.close();
1363: }
1364: } catch (SQLException e2) {
1365: throw e2;
1366: }
1367: }
1368: }
1369:
1370: /**
1371: * This builds the SELECT statement in order to refresh the contents of this Record. It depends on a valid KeyDef to exist and
1372: * it must have been created with a TableDataSet.
1373: *
1374: * @return the SELECT string
1375: *
1376: * @exception DataSetException
1377: */
1378: public String getRefreshQueryString() throws DataSetException {
1379: if ((dataset().keydef() == null)
1380: || (dataset().keydef().size() == 0)) {
1381: throw new DataSetException(
1382: "You can only perform a getRefreshQueryString on a TableDataSet that was created with a KeyDef.");
1383: } else if (dataset() instanceof QueryDataSet) {
1384: throw new DataSetException(
1385: "You can only perform a getRefreshQueryString on Records created with a TableDataSet.");
1386: }
1387:
1388: StringBuffer iss1 = new StringBuffer(256);
1389: StringBuffer iss2 = new StringBuffer(256);
1390: boolean comma = false;
1391:
1392: for (int i = 1; i <= size(); i++) {
1393: if (!comma) {
1394: iss1.append(schema().column(i).name());
1395: comma = true;
1396: } else {
1397: iss1.append(", ");
1398: iss1.append(schema().column(i).name());
1399: }
1400: }
1401:
1402: comma = false;
1403:
1404: for (int i = 1; i <= dataset().keydef().size(); i++) {
1405: String attrib = dataset().keydef().getAttrib(i);
1406:
1407: if (!valueIsClean(attrib)) {
1408: throw new DataSetException(
1409: "You cannot do a refresh from the database if the value "
1410: + "for a KeyDef column has been changed with a Record.setValue().");
1411: }
1412:
1413: if (!comma) {
1414: iss2.append(attrib);
1415: iss2.append(" = ?");
1416: comma = true;
1417: } else {
1418: iss2.append(" AND ");
1419: iss2.append(attrib);
1420: iss2.append(" = ?");
1421: }
1422: }
1423:
1424: return "SELECT " + iss1.toString() + " FROM "
1425: + schema().tableName() + " WHERE " + iss2.toString();
1426: }
1427:
1428: /**
1429: * TODO: DOCUMENT ME!
1430: *
1431: * @throws DataSetException TODO: DOCUMENT ME!
1432: */
1433: public void saveWithoutStatusUpdate() throws DataSetException {
1434: throw new DataSetException(
1435: "Record.saveWithoutStatusUpdate() is not yet implemented.");
1436: }
1437:
1438: /**
1439: * Gets the schema for the parent DataSet
1440: *
1441: * @return the schema for the parent DataSet
1442: *
1443: * @throws DataSetException TODO: DOCUMENT ME!
1444: */
1445: public Schema schema() throws DataSetException {
1446: if (dataset() != null) {
1447: return this .schema;
1448: } else {
1449: throw new DataSetException(
1450: "Internal Error: Record DataSet is null");
1451: }
1452: }
1453:
1454: /**
1455: * Gets the DataSet for this Record
1456: *
1457: * @return the DataSet for this Record
1458: */
1459: public DataSet dataset() {
1460: return this .parentDataSet;
1461: }
1462:
1463: /**
1464: * Sets the parent DataSet for this record.
1465: *
1466: * @param ds TODO: DOCUMENT ME!
1467: */
1468: void setParentDataSet(DataSet ds) {
1469: this .parentDataSet = ds;
1470: }
1471:
1472: /**
1473: * return the value of each column as a string. Not yet implemented!
1474: *
1475: * @param valueseparator
1476: * @param maxwidths
1477: *
1478: * @return the formatted string
1479: *
1480: * @exception DataSetException
1481: */
1482: public String asFormattedString(String valueseparator,
1483: int[] maxwidths) throws DataSetException {
1484: throw new DataSetException("Not yet implemented!");
1485: }
1486:
1487: /**
1488: * This returns a representation of this Record
1489: *
1490: * @return java.lang.String
1491: */
1492: public String toString() {
1493: try {
1494: ByteArrayOutputStream bout = new ByteArrayOutputStream();
1495: PrintWriter out = new PrintWriter(bout);
1496: out.print("{");
1497:
1498: for (int i = 1; i <= size(); i++) {
1499: out.print("'" + getValue(i).asString() + "'");
1500:
1501: if (i < size()) {
1502: out.print(',');
1503: }
1504: }
1505:
1506: out.print("}");
1507: out.flush();
1508:
1509: return bout.toString();
1510: } catch (DataSetException e) {
1511: return "";
1512: }
1513: }
1514: }
|