0001: /**
0002: * Copyright (C) 2006, 2007 David Bulmore, Software Sensation Inc.
0003: * All Rights Reserved.
0004: *
0005: * This file is part of JPersist.
0006: *
0007: * JPersist is free software; you can redistribute it and/or modify it under
0008: * the terms of the GNU General Public License (Version 2) as published by
0009: * the Free Software Foundation.
0010: *
0011: * JPersist is distributed in the hope that it will be useful, but WITHOUT
0012: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0013: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0014: * for more details.
0015: *
0016: * You should have received a copy of the GNU General Public License
0017: * along with JPersist; if not, write to the Free Software Foundation,
0018: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
0019: */package jpersist;
0020:
0021: import java.io.InputStream;
0022: import java.io.Reader;
0023: import java.math.BigDecimal;
0024: import java.net.URL;
0025: import java.sql.Array;
0026: import java.sql.Blob;
0027: import java.sql.CallableStatement;
0028: import java.sql.Clob;
0029: import java.sql.Connection;
0030: import java.sql.Date;
0031: import java.sql.PreparedStatement;
0032: import java.sql.Ref;
0033: import java.sql.ResultSet;
0034: import java.sql.SQLException;
0035: import java.sql.SQLWarning;
0036: import java.sql.Savepoint;
0037: import java.sql.Statement;
0038: import java.sql.Time;
0039: import java.sql.Timestamp;
0040: import java.util.Iterator;
0041: import java.util.Set;
0042: import java.util.Vector;
0043: import java.util.logging.Level;
0044: import java.util.logging.Logger;
0045: import jcommontk.utils.StringUtils;
0046: import jpersist.ObjectSupport.NullValue;
0047: import jpersist.interfaces.AsciiStream;
0048: import jpersist.interfaces.BinaryStream;
0049: import jpersist.interfaces.CharacterStream;
0050: import jpersist.interfaces.ColumnMapping;
0051: import jpersist.interfaces.TableMapping;
0052:
0053: /**
0054: * The center of JPersist, the Database class provides a seemless integration
0055: * of the JDBC classes Connection, Statement, and ResultSet, while also
0056: * providing object oriented database access.
0057: */
0058:
0059: @SuppressWarnings("unchecked")
0060: // working to complete a Java 1.5 version
0061: public final class Database {
0062: private static Logger logger = Logger.getLogger(Database.class
0063: .getName());
0064:
0065: private String catalogPattern, schemaPattern;
0066: private TableMapping tableMapper;
0067: private ColumnMapping columnMapper;
0068: private Vector resultsVector, queryQueueVector;
0069: private DatabaseManager databaseManager;
0070: private PreparedStatement statement;
0071: private Connection connection;
0072: private String databaseName;
0073: private boolean isClosed;
0074: private int fetchSize, maxRows, resultSetType,
0075: resultSetConcurrency;
0076:
0077: /* Non-public access ************************************************************/
0078:
0079: Database(DatabaseManager databaseManager) {
0080: this .databaseManager = databaseManager;
0081: }
0082:
0083: DatabaseManager getDatabaseManager() {
0084: return databaseManager;
0085: }
0086:
0087: void setDatabaseName(String databaseName) {
0088: this .databaseName = databaseName;
0089: }
0090:
0091: void initDatabase() {
0092: resultsVector = new Vector();
0093: queryQueueVector = new Vector();
0094: isClosed = false;
0095: fetchSize = maxRows = resultSetType = resultSetConcurrency = 0;
0096: }
0097:
0098: void setConnection(Connection connection) {
0099: this .connection = connection;
0100: }
0101:
0102: String getCatalogPattern() {
0103: return catalogPattern;
0104: }
0105:
0106: String getSchemaPattern() {
0107: return schemaPattern;
0108: }
0109:
0110: TableMapping getTableMapper() {
0111: return tableMapper;
0112: }
0113:
0114: ColumnMapping getColumnMapper() {
0115: return columnMapper;
0116: }
0117:
0118: /* End Non-public access ************************************************************/
0119:
0120: /**
0121: * Create a Database instance.
0122: *
0123: * @param databaseName the name of this database
0124: * @param connection a java.sql.Connection instance
0125: */
0126:
0127: public Database(String databaseName, Connection connection) {
0128: this .databaseName = databaseName;
0129: this .connection = connection;
0130: }
0131:
0132: /**
0133: * Returns the name of the current dtabase handler.
0134: *
0135: * @return a string representing the database handler name
0136: */
0137:
0138: public String getDatabaseName() {
0139: return databaseName;
0140: }
0141:
0142: /**
0143: * Returns the database connection.
0144: *
0145: * @return the JDBC connection instance
0146: *
0147: * @throws JPersistException
0148: */
0149:
0150: public Connection getConnection() throws JPersistException {
0151: if (isClosed)
0152: throw new JPersistException(
0153: JPersistException.DATABASE_CLOSED);
0154:
0155: return connection;
0156: }
0157:
0158: /**
0159: * Returns the database meta data associated with the current database.
0160: * The MetaData class can be used to access information about tables in
0161: * the database. It can also be used to add table and column mapping.
0162: *
0163: * @return an instance of MetaData
0164: *
0165: * @throws JPersistException
0166: */
0167:
0168: public MetaData getMetaData() throws JPersistException {
0169: try {
0170: return MetaData.getMetaData(connection);
0171: } catch (Exception e) {
0172: throw new JPersistException(e);
0173: }
0174: }
0175:
0176: /**
0177: * Sets limits on the meta data table information returned. Defining
0178: * catalogPattern and schemaPattern can help reduce the amount of time
0179: * spent loading table information. With some databases, it is absolutely
0180: * needed. This can also be set with databases.xml and/or DatabaseManager
0181: * constructors. Meta data limits will be reset (using the values in
0182: * DatabaseManager) with each call to DatabaseManager.getDatabase().
0183: *
0184: * @param catalogPattern the catalogPattern (can contain SQL wildcards)
0185: * @param schemaPattern the schemaPattern (can contain SQL wildcards)
0186: */
0187:
0188: public void setMetaDataLimits(String catalogPattern,
0189: String schemaPattern) {
0190: logger.fine("Limiting meta data with catalog = "
0191: + catalogPattern + ", schema = " + schemaPattern);
0192:
0193: this .catalogPattern = catalogPattern;
0194: this .schemaPattern = schemaPattern;
0195: }
0196:
0197: /**
0198: * This method can be used to add global table and column mappers.
0199: * Objects implementaing TableMapping and/or ColumnMapping override the global mappers.
0200: *
0201: * @param tableMapper an instance of TableMapping
0202: * @param columnMapper an instance of ColumnMapping
0203: */
0204: public void setGlobalMappers(TableMapping tableMapper,
0205: ColumnMapping columnMapper) {
0206: this .tableMapper = tableMapper;
0207: this .columnMapper = columnMapper;
0208: }
0209:
0210: /**
0211: * Closes the Database (returns pooled connections to the pool).
0212: *
0213: * @throws JPersistException
0214: */
0215:
0216: public void close() throws JPersistException {
0217: if (isClosed)
0218: throw new JPersistException(
0219: JPersistException.DATABASE_CLOSED);
0220:
0221: logger.finer("closing database");
0222:
0223: for (Iterator it = resultsVector.iterator(); it.hasNext();)
0224: ((Result) it.next()).close();
0225:
0226: if (databaseManager != null)
0227: databaseManager.releaseDatabase(this );
0228:
0229: isClosed = true;
0230: }
0231:
0232: /**
0233: * Closes the Database (simply calls close()), can be used in EL. For example:
0234: *
0235: * <pre>
0236: * ${db.close}
0237: * </pre>
0238: *
0239: * @throws JPersistException
0240: */
0241:
0242: public String getClose() throws JPersistException {
0243: close();
0244:
0245: return null;
0246: }
0247:
0248: /**
0249: * Closes the Database (simply calls close()), via a JavaBeans setter. For example:
0250: * <pre>
0251: * <jsp:useBean id="db" scope="request" class="jpersist.Database" />
0252: * <jsp:setProperty name="db" property="closed" value="true"/>
0253: * </pre>
0254: *
0255: * @throws JPersistException
0256: */
0257:
0258: public void setClosed(boolean true_only) throws JPersistException {
0259: close();
0260: }
0261:
0262: /**
0263: * Returns true if the database is closed, false otherwise.
0264: *
0265: * @return true or false
0266: */
0267:
0268: public boolean isClosed() {
0269: return isClosed;
0270: }
0271:
0272: /**
0273: * See same in java.sql.Statement
0274: *
0275: * @see java.sql.Statement
0276: */
0277:
0278: public void setFetchSize(int fetchSize) throws JPersistException {
0279: if (isClosed)
0280: throw new JPersistException(
0281: JPersistException.DATABASE_CLOSED);
0282:
0283: if (logger.isLoggable(Level.FINER))
0284: logger.finer("Setting fetch size to " + fetchSize);
0285:
0286: this .fetchSize = fetchSize;
0287: }
0288:
0289: /**
0290: * See same in java.sql.Statement
0291: *
0292: * @see java.sql.Statement
0293: */
0294:
0295: public void setMaxRows(int maximumResultRows)
0296: throws JPersistException {
0297: if (isClosed)
0298: throw new JPersistException(
0299: JPersistException.DATABASE_CLOSED);
0300:
0301: if (logger.isLoggable(Level.FINER))
0302: logger.finer("Setting maximum result rows to "
0303: + maximumResultRows);
0304:
0305: this .maxRows = maximumResultRows;
0306: }
0307:
0308: /**
0309: * Defaults to ResultSet.TYPE_SCROLL_INSENSITIVE.
0310: *
0311: * @see java.sql.Connection
0312: * @see java.sql.ResultSet
0313: *
0314: * @throws JPersistException
0315: */
0316:
0317: public void setResultSetType(int resultSetType)
0318: throws JPersistException {
0319: if (isClosed)
0320: throw new JPersistException(
0321: JPersistException.DATABASE_CLOSED);
0322:
0323: if (logger.isLoggable(Level.FINER))
0324: logger.finer("Setting result set type to " + resultSetType);
0325:
0326: this .resultSetType = resultSetType;
0327: }
0328:
0329: /**
0330: * Defaults to ResultSet.CONCUR_READ_ONLY.
0331: *
0332: * @see java.sql.Connection
0333: * @see java.sql.ResultSet
0334: *
0335: * @throws JPersistException
0336: */
0337:
0338: public void setResultSetConcurrency(int resultSetConcurrency)
0339: throws JPersistException {
0340: if (isClosed)
0341: throw new JPersistException(
0342: JPersistException.DATABASE_CLOSED);
0343:
0344: if (logger.isLoggable(Level.FINER))
0345: logger.finer("Setting result set concurrency to "
0346: + resultSetConcurrency);
0347:
0348: this .resultSetConcurrency = resultSetConcurrency;
0349: }
0350:
0351: /**
0352: * Creates a simple statement that can continue to be used with the database
0353: * handler (i.e. query results can be loaded into objects and so forth).
0354: *
0355: * @return a JDBC Statement instance
0356: *
0357: * @throws JPersistException
0358: */
0359:
0360: public Statement createStatement() throws JPersistException {
0361: if (isClosed)
0362: throw new JPersistException(
0363: JPersistException.DATABASE_CLOSED);
0364:
0365: try {
0366: if (logger.isLoggable(Level.FINER))
0367: logger.finer("Creating statement: resultSetType = "
0368: + resultSetType + ", resultSetConcurrency = "
0369: + resultSetConcurrency);
0370:
0371: Statement statement = connection.createStatement(
0372: resultSetType > 0 ? resultSetType
0373: : ResultSet.TYPE_SCROLL_INSENSITIVE,
0374: resultSetConcurrency > 0 ? resultSetConcurrency
0375: : ResultSet.CONCUR_READ_ONLY);
0376:
0377: if (fetchSize != 0)
0378: statement.setFetchSize(fetchSize);
0379:
0380: if (maxRows != 0)
0381: statement.setMaxRows(maxRows);
0382:
0383: return statement;
0384: } catch (Exception e) {
0385: throw new JPersistException(e);
0386: }
0387: }
0388:
0389: /**
0390: * Creates a prepared statement that can continue to be used with the database
0391: * handler (i.e. query results can be loaded into objects and so forth).
0392: *
0393: * @param sql the sql statement to be used (eg. "select * from tbl where id = ?")
0394: *
0395: * @return a JDBC PreparedStatement instance
0396: *
0397: * @throws JPersistException
0398: */
0399:
0400: public PreparedStatement createPreparedStatement(String sql)
0401: throws JPersistException {
0402: if (isClosed)
0403: throw new JPersistException(
0404: JPersistException.DATABASE_CLOSED);
0405:
0406: if (sql == null || sql.length() == 0)
0407: throw new JPersistException(
0408: JPersistException.SQL_STATEMENT_NULL);
0409:
0410: try {
0411: if (logger.isLoggable(Level.FINER))
0412: logger.finer("Creating prepared statement:\n"
0413: + "sql = " + sql + "\n" + "resultSetType = "
0414: + resultSetType + ", resultSetConcurrency = "
0415: + resultSetConcurrency);
0416:
0417: statement = connection.prepareStatement(sql,
0418: resultSetType > 0 ? resultSetType
0419: : ResultSet.TYPE_SCROLL_INSENSITIVE,
0420: resultSetConcurrency > 0 ? resultSetConcurrency
0421: : ResultSet.CONCUR_READ_ONLY);
0422:
0423: if (fetchSize != 0)
0424: statement.setFetchSize(fetchSize);
0425:
0426: if (maxRows != 0)
0427: statement.setMaxRows(maxRows);
0428:
0429: return (PreparedStatement) statement;
0430: } catch (Exception e) {
0431: throw new JPersistException(e);
0432: }
0433: }
0434:
0435: /**
0436: * Creates a callable statement that can be used to interact with PL/SQL, and can also continue to be
0437: * used with the database handler (i.e. query results can be loaded into objects and so forth).
0438: *
0439: * @param sql the sql statement to be used (eg. "{call getName(?, ?)}")
0440: *
0441: * @return a JDBC CallableStatement instance
0442: *
0443: * @throws JPersistException
0444: */
0445:
0446: public CallableStatement createCallableStatement(String sql)
0447: throws JPersistException {
0448: if (isClosed)
0449: throw new JPersistException(
0450: JPersistException.DATABASE_CLOSED);
0451:
0452: if (sql == null || sql.length() == 0)
0453: throw new JPersistException(
0454: JPersistException.SQL_STATEMENT_NULL);
0455:
0456: try {
0457: if (logger.isLoggable(Level.FINER))
0458: logger.finer("Creating callable statement:\n"
0459: + "sql = " + sql + "\n" + "resultSetType = "
0460: + resultSetType + ", resultSetConcurrency = "
0461: + resultSetConcurrency);
0462:
0463: statement = connection.prepareCall(sql,
0464: resultSetType > 0 ? resultSetType
0465: : ResultSet.TYPE_SCROLL_INSENSITIVE,
0466: resultSetConcurrency > 0 ? resultSetConcurrency
0467: : ResultSet.CONCUR_READ_ONLY);
0468:
0469: if (fetchSize != 0)
0470: statement.setFetchSize(fetchSize);
0471:
0472: if (maxRows != 0)
0473: statement.setMaxRows(maxRows);
0474:
0475: return (CallableStatement) statement;
0476: } catch (Exception e) {
0477: throw new JPersistException(e);
0478: }
0479: }
0480:
0481: /**
0482: * Builds a select query from the object and executes it. Any methods matching table columns will be returned,
0483: * and any values set will be used to build the where clause.
0484: *
0485: * @param object any Object (POJO, PersistentObject, etc.)
0486: *
0487: * @return a jpersist.Result instance
0488: *
0489: * @throws JPersistException
0490: */
0491:
0492: public <T> Result<T> queryObject(T object) throws JPersistException {
0493: return queryObject(object, null, null, (Object[]) null);
0494: }
0495:
0496: /**
0497: * Builds a select query from the object and executes it. Any methods matching table columns will be returned,
0498: * and any values set will be used to build the where clause.
0499: *
0500: * @param object any Object (POJO, PersistentObject, etc.)
0501: * @param nullValuesToInclude is a Set of set methods without the 'set', or table column names, to include in the where clause if null
0502: *
0503: * @return a jpersist.Result instance
0504: *
0505: * @throws JPersistException
0506: */
0507:
0508: public <T> Result<T> queryObject(T object,
0509: Set<String> nullValuesToInclude) throws JPersistException {
0510: return queryObject(object, nullValuesToInclude, null,
0511: (Object[]) null);
0512: }
0513:
0514: /**
0515: * Builds a select query from the object and executes it. Any methods matching table columns will be returned.
0516: * externalClauses can begin with a where clause or anything after the where clause.
0517: *
0518: * @param object any Object (POJO, PersistentObject, etc.)
0519: * @param externalClauses external clauses beginning with a where or after
0520: * @param externalClausesParameters the parameters to use with external clauses, can be null
0521: *
0522: * @return a jpersist.Result instance
0523: *
0524: * @throws JPersistException
0525: */
0526:
0527: public <T> Result<T> queryObject(T object, String externalClauses,
0528: Object... externalClausesParameters)
0529: throws JPersistException {
0530: return queryObject(object, null, externalClauses,
0531: externalClausesParameters);
0532: }
0533:
0534: /**
0535: * Builds a select query from the object and executes it. Any methods matching table columns will be returned.
0536: * externalClauses can begin with a where clause or anything after the where clause.
0537: *
0538: * @param object any Object (POJO, PersistentObject, etc.)
0539: * @param nullValuesToInclude is a Set of set methods without the 'set', or table column names, to include in the where clause if null
0540: * @param externalClauses external clauses beginning with a where or after
0541: * @param externalClausesParameters the parameters to use with external clauses, can be null
0542: *
0543: * @return a jpersist.Result instance
0544: *
0545: * @throws JPersistException
0546: */
0547:
0548: public <T> Result<T> queryObject(T object,
0549: Set<String> nullValuesToInclude, String externalClauses,
0550: Object... externalClausesParameters)
0551: throws JPersistException {
0552: if (isClosed)
0553: throw new JPersistException(
0554: JPersistException.DATABASE_CLOSED);
0555:
0556: try {
0557: Result result = ObjectSupport.queryObject(this , object
0558: .getClass(), object, nullValuesToInclude, false,
0559: externalClauses, externalClausesParameters);
0560:
0561: resultsVector.add(result);
0562:
0563: return result;
0564: } catch (Exception e) {
0565: throw new JPersistException(e);
0566: }
0567: }
0568:
0569: /**
0570: * Builds a select query from a class that matches up to a table. Any methods matching table
0571: * columns will be used to build the column list. externalClauses can begin with a where
0572: * clause or anything after the where clause.
0573: *
0574: * @param cs any class that matches up to a table
0575: *
0576: * @return a jpersist.Result instance
0577: *
0578: * @throws JPersistException
0579: */
0580:
0581: public <T> Result<T> queryObject(Class<T> cs)
0582: throws JPersistException {
0583: return queryObject(cs, null, (Object[]) null);
0584: }
0585:
0586: /**
0587: * Builds a select query from a class that matches up to a table. Any methods matching table
0588: * columns will be used to build the column list. externalClauses can begin with a where
0589: * clause or anything after the where clause.
0590: *
0591: * @param cs any class that matches up to a table
0592: * @param externalClauses external clauses beginning with a where or after
0593: * @param externalClausesParameters the parameters to use with external clauses, can be null
0594: *
0595: * @return a jpersist.Result instance
0596: *
0597: * @throws JPersistException
0598: */
0599: public <T> Result<T> queryObject(Class<T> cs,
0600: String externalClauses, Object... externalClausesParameters)
0601: throws JPersistException {
0602: if (isClosed)
0603: throw new JPersistException(
0604: JPersistException.DATABASE_CLOSED);
0605:
0606: try {
0607: Result result = ObjectSupport.queryObject(this , cs, null,
0608: null, false, externalClauses,
0609: externalClausesParameters);
0610:
0611: resultsVector.add(result);
0612:
0613: return result;
0614: } catch (Exception e) {
0615: throw new JPersistException(e);
0616: }
0617: }
0618:
0619: /**
0620: * Loads an objects associations.
0621: *
0622: * @param object the object whose associations are to be loaded
0623: *
0624: * @throws jpersist.JPersistException
0625: */
0626: public void loadAssociations(Object object)
0627: throws JPersistException {
0628: if (isClosed)
0629: throw new JPersistException(
0630: JPersistException.DATABASE_CLOSED);
0631:
0632: try {
0633: ObjectSupport.loadAssociations(this , object);
0634: } catch (Exception e) {
0635: throw new JPersistException(e);
0636: }
0637: }
0638:
0639: /**
0640: * Builds either an update or an insert depending on whether the object is persistent and was previously loaded, or not, respectively.
0641: *
0642: * @param object any Object (POJO, PersistentObject, etc.)
0643: *
0644: * @return number of rows updated
0645: *
0646: * @throws JPersistException
0647: */
0648:
0649: public int saveObject(Object object) throws JPersistException {
0650: return saveObject(object, null, null, (Object[]) null);
0651: }
0652:
0653: /**
0654: * Builds either an update or an insert depending on whether the object is persistent and was previously loaded, or not, respectively.
0655: *
0656: * @param object any Object (POJO, PersistentObject, etc.)
0657: * @param nullValuesToInclude is a Set of set methods without the 'set', or table column names, to include in the update
0658: *
0659: * @return number of rows updated
0660: *
0661: * @throws JPersistException
0662: */
0663:
0664: public int saveObject(Object object, Set<String> nullValuesToInclude)
0665: throws JPersistException {
0666: return saveObject(object, nullValuesToInclude, null,
0667: (Object[]) null);
0668: }
0669:
0670: /**
0671: * Builds either an update or an insert depending on whether the object is persistent and was previously loaded, or not, respectively.
0672: * externalClauses can begin with a where clause or anything after the where clause.
0673: *
0674: * @param object any Object (POJO, PersistentObject, etc.)
0675: * @param externalClauses external clauses beginning with a where or after
0676: * @param externalClausesParameters the parameters to use with external clauses, can be null
0677: *
0678: * @return number of rows updated
0679: *
0680: * @throws JPersistException
0681: */
0682:
0683: public int saveObject(Object object, String externalClauses,
0684: Object... externalClausesParameters)
0685: throws JPersistException {
0686: return saveObject(object, null, externalClauses,
0687: externalClausesParameters);
0688: }
0689:
0690: /**
0691: * Builds either an update or an insert depending on whether the object is persistent and was previously loaded, or not, respectively.
0692: * externalClauses can begin with a where clause or anything after the where clause.
0693: *
0694: * @param object any Object (POJO, PersistentObject, etc.)
0695: * @param nullValuesToInclude is a Set of set methods without the 'set', or table column names, to include in the update
0696: * @param externalClauses external clauses beginning with a where or after
0697: * @param externalClausesParameters the parameters to use with external clauses, can be null
0698: *
0699: * @return number of rows updated
0700: *
0701: * @throws JPersistException
0702: */
0703:
0704: public int saveObject(Object object,
0705: Set<String> nullValuesToInclude, String externalClauses,
0706: Object... externalClausesParameters)
0707: throws JPersistException {
0708: if (isClosed)
0709: throw new JPersistException(
0710: JPersistException.DATABASE_CLOSED);
0711:
0712: try {
0713: return ObjectSupport.objectTransaction(this , object,
0714: nullValuesToInclude, true, externalClauses,
0715: externalClausesParameters);
0716: } catch (Exception e) {
0717: throw new JPersistException(e);
0718: }
0719: }
0720:
0721: /**
0722: * Builds a delete statement from the object.
0723: *
0724: * @param object any Object (POJO, PersistentObject, etc.)
0725: *
0726: * @return number of rows deleted
0727: *
0728: * @throws JPersistException
0729: */
0730:
0731: public int deleteObject(Object object) throws JPersistException {
0732: return deleteObject(object, null, null, (Object[]) null);
0733: }
0734:
0735: /**
0736: * Builds a delete statement from the object.
0737: *
0738: * @param object any Object (POJO, PersistentObject, etc.)
0739: * @param nullValuesToInclude is a Set of set methods without the 'set', or table column names, to include in the where clause if null
0740: *
0741: * @return number of rows deleted
0742: *
0743: * @throws JPersistException
0744: */
0745:
0746: public int deleteObject(Object object,
0747: Set<String> nullValuesToInclude) throws JPersistException {
0748: return deleteObject(object, nullValuesToInclude, null,
0749: (Object[]) null);
0750: }
0751:
0752: /**
0753: * Builds a delete statement from the object. externalClauses can begin with a where clause or anything after
0754: * the where clause.
0755: *
0756: * @param object any Object (POJO, PersistentObject, etc.)
0757: * @param externalClauses external clauses beginning with a where or after
0758: * @param externalClausesParameters the parameters to use with external clauses, can be null
0759: *
0760: * @return number of rows deleted
0761: *
0762: * @throws JPersistException
0763: */
0764:
0765: public int deleteObject(Object object, String externalClauses,
0766: Object... externalClausesParameters)
0767: throws JPersistException {
0768: return deleteObject(object, null, externalClauses,
0769: externalClausesParameters);
0770: }
0771:
0772: /**
0773: * Builds a delete statement from the object. externalClauses can begin with a where clause or anything after
0774: * the where clause.
0775: *
0776: * @param object any Object (POJO, PersistentObject, etc.)
0777: * @param nullValuesToInclude is a Set of set methods without the 'set', or table column names, to include in the where clause if null
0778: * @param externalClauses external clauses beginning with a where or after
0779: * @param externalClausesParameters the parameters to use with external clauses, can be null
0780: *
0781: * @return number of rows deleted
0782: *
0783: * @throws JPersistException
0784: */
0785:
0786: public int deleteObject(Object object,
0787: Set<String> nullValuesToInclude, String externalClauses,
0788: Object... externalClausesParameters)
0789: throws JPersistException {
0790: if (isClosed)
0791: throw new JPersistException(
0792: JPersistException.DATABASE_CLOSED);
0793:
0794: try {
0795: return ObjectSupport.objectTransaction(this , object,
0796: nullValuesToInclude, false, externalClauses,
0797: externalClausesParameters);
0798: } catch (Exception e) {
0799: throw new JPersistException(e);
0800: }
0801: }
0802:
0803: /**
0804: * Executes a query from a previously created (and setup) prepared or callable statement.
0805: *
0806: * @return a jpersist.Result instance
0807: *
0808: * @throws JPersistException
0809: */
0810:
0811: public Result executeQuery() throws JPersistException {
0812: if (isClosed)
0813: throw new JPersistException(
0814: JPersistException.DATABASE_CLOSED);
0815:
0816: if (statement == null)
0817: throw new JPersistException(
0818: "Prepared or callable statement is null");
0819:
0820: try {
0821: Result result = new Result(this ,
0822: ((PreparedStatement) statement).executeQuery());
0823:
0824: resultsVector.add(result);
0825:
0826: return result;
0827: } catch (Exception e) {
0828: throw new JPersistException(e);
0829: }
0830: }
0831:
0832: /**
0833: * Executes a simple query.
0834: *
0835: * @param sql the SQL statement
0836: *
0837: * @return a jpersist.Result instance
0838: *
0839: * @throws JPersistException
0840: */
0841:
0842: public Result executeQuery(String sql) throws JPersistException {
0843: logger.fine(sql);
0844:
0845: if (sql == null || sql.length() == 0)
0846: throw new JPersistException(
0847: JPersistException.SQL_STATEMENT_NULL);
0848:
0849: try {
0850: Statement statement = createStatement();
0851: statement.executeQuery(sql);
0852:
0853: Result result = new Result(this , statement.getResultSet());
0854: resultsVector.add(result);
0855:
0856: return result;
0857: } catch (Exception e) {
0858: throw new JPersistException(e);
0859: }
0860: }
0861:
0862: /**
0863: * Executes a parameterized query. A paramterized query allows the use of '?' in
0864: * SQL statements.
0865: *
0866: * @param sql the SQL statement
0867: * @param parameters an array of objects used to set the parameters to the query
0868: *
0869: * @return a jpersist.Result instance
0870: *
0871: * @throws JPersistException
0872: */
0873:
0874: public Result parameterizedQuery(String sql, Object... parameters)
0875: throws JPersistException {
0876: if (logger.isLoggable(Level.FINE))
0877: logger.fine("sql = " + sql + "\nparameters[] = "
0878: + StringUtils.toString(parameters));
0879:
0880: try {
0881: Statement statement = createPreparedStatement(sql);
0882:
0883: setPreparedStatementObjects((PreparedStatement) statement,
0884: parameters);
0885:
0886: ((PreparedStatement) statement).execute();
0887:
0888: Result result = new Result(this , statement.getResultSet());
0889: resultsVector.add(result);
0890:
0891: return result;
0892: } catch (Exception e) {
0893: throw new JPersistException(e);
0894: }
0895: }
0896:
0897: /**
0898: * Executes a simple update.
0899: *
0900: * @param sql the SQL statement
0901: *
0902: * @throws JPersistException
0903: */
0904:
0905: public int executeUpdate(String sql) throws JPersistException {
0906: return executeUpdate(sql, (Vector) null);
0907: }
0908:
0909: /**
0910: * Executes a simple update.
0911: *
0912: * @param sql the SQL statement
0913: * @param keys is a Vector. If keys is non-null, then generated keys will be returned in
0914: * the keys vector. Vector can also define the key columns required
0915: * (depending on the database).
0916: *
0917: * @throws JPersistException
0918: */
0919:
0920: public int executeUpdate(String sql, Vector keys)
0921: throws JPersistException {
0922: if (isClosed)
0923: throw new JPersistException(
0924: JPersistException.DATABASE_CLOSED);
0925:
0926: if (logger.isLoggable(Level.FINE))
0927: logger.fine("sql = " + sql + "\nkeys = " + keys);
0928:
0929: try {
0930: Statement statement = null;
0931:
0932: try {
0933: int rval = 0;
0934:
0935: statement = getConnection().createStatement();
0936:
0937: if (keys != null && keys.size() > 0)
0938: statement.executeUpdate(sql, (String[]) keys
0939: .toArray(new String[keys.size()]));
0940: else if (keys != null)
0941: statement.executeUpdate(sql,
0942: Statement.RETURN_GENERATED_KEYS);
0943: else
0944: statement.executeUpdate(sql);
0945:
0946: if (keys != null) {
0947: ResultSet resultKeys = statement.getGeneratedKeys();
0948:
0949: keys.clear();
0950:
0951: while (resultKeys.next())
0952: keys
0953: .addElement(new Long(resultKeys
0954: .getLong(1)));
0955: }
0956:
0957: if (logger.isLoggable(Level.FINER))
0958: logger.finer("keys = " + keys + ", rows updated = "
0959: + rval);
0960:
0961: return rval;
0962: } finally {
0963: if (statement != null)
0964: statement.close();
0965: }
0966: } catch (Exception e) {
0967: throw new JPersistException(e);
0968: }
0969: }
0970:
0971: /**
0972: * Executes a parameterized update. A paramterized update allows the use of '?' in
0973: * SQL statements.
0974: *
0975: * @param sql the SQL statement
0976: * @param parameters an array of objects used to set the parameters to the update
0977: *
0978: * @throws JPersistException
0979: */
0980:
0981: public int parameterizedUpdate(String sql, Object... parameters)
0982: throws JPersistException {
0983: return parameterizedUpdate(sql, null, parameters);
0984: }
0985:
0986: /**
0987: * Executes a parameterized update. A paramterized update allows the use of '?' in
0988: * SQL statements.
0989: *
0990: * @param sql the SQL statement
0991: * @param keys is a Vector. If keys is non-null, then generated keys will be returned in
0992: * the keys vector. Vector can also define the key columns required
0993: * (depending on the database).
0994: * @param parameters an array of objects used to set the parameters to the update
0995: *
0996: * @throws JPersistException
0997: */
0998:
0999: public int parameterizedUpdate(String sql, Vector keys,
1000: Object... parameters) throws JPersistException {
1001: try {
1002: if (logger.isLoggable(Level.FINE))
1003: logger.fine("sql = " + sql + "\nparameters[] = "
1004: + StringUtils.toString(parameters)
1005: + ", keys = " + keys);
1006:
1007: if (isClosed)
1008: throw new JPersistException(
1009: JPersistException.DATABASE_CLOSED);
1010:
1011: int rval = 0;
1012: Statement statement = null;
1013:
1014: try {
1015: if (keys != null && keys.size() > 0)
1016: statement = getConnection().prepareStatement(
1017: sql,
1018: (String[]) keys.toArray(new String[keys
1019: .size()]));
1020: else if (keys != null)
1021: statement = getConnection().prepareStatement(sql,
1022: Statement.RETURN_GENERATED_KEYS);
1023: else
1024: statement = getConnection().prepareStatement(sql);
1025:
1026: setPreparedStatementObjects(
1027: (PreparedStatement) statement, parameters);
1028:
1029: rval = ((PreparedStatement) statement).executeUpdate();
1030:
1031: if (keys != null) {
1032: ResultSet generatedKeys = statement
1033: .getGeneratedKeys();
1034:
1035: keys.clear();
1036:
1037: while (generatedKeys.next())
1038: keys.add(generatedKeys.getObject(1));
1039: }
1040:
1041: if (logger.isLoggable(Level.FINER))
1042: logger.finer("keys = " + keys + ", rows updated = "
1043: + rval);
1044:
1045: return rval;
1046: } finally {
1047: if (statement != null)
1048: statement.close();
1049: }
1050: } catch (Exception e) {
1051: throw new JPersistException(e);
1052: }
1053: }
1054:
1055: /**
1056: * Adds a query to the query queue. The query queue is very
1057: * useful for building up several queries to be executed at a later
1058: * time (page rendering for example). Each call to nextQuery() executes
1059: * the queries in the query queue in the order they where added.
1060: *
1061: * @param sql simple query sql
1062: *
1063: * @throws JPersistException
1064: */
1065:
1066: public void queueQuery(String sql) throws JPersistException {
1067: logger.finer(sql);
1068:
1069: queryQueueVector.add(sql);
1070: }
1071:
1072: /**
1073: * Adds a parameterized query to the query queue. The query queue is very
1074: * useful for building up several queries to be executed at a later
1075: * time (page rendering for example). Each call to nextQuery() executes
1076: * the queries in the query queue in the order they where added.
1077: *
1078: * @param sql parameterized query sql
1079: * @param parameters an array of objects used to set the parameters to the query
1080: *
1081: * @throws JPersistException
1082: */
1083:
1084: public void queueParameterizedQuery(String sql,
1085: Object... parameters) throws JPersistException {
1086: if (isClosed)
1087: throw new JPersistException(
1088: JPersistException.DATABASE_CLOSED);
1089:
1090: if (logger.isLoggable(Level.FINER))
1091: logger.finer("sql = " + sql + "\nparameters[] = "
1092: + StringUtils.toString(parameters));
1093:
1094: Object[] obj = new Object[parameters.length + 1];
1095:
1096: obj[0] = sql;
1097:
1098: for (int i = 0; i < parameters.length; i++)
1099: obj[i + 1] = parameters[i];
1100: }
1101:
1102: /**
1103: * Simply calls nextQuery(). Usefull in environments where it is easier to call get methods.
1104: *
1105: * @return a jpersist.Result instance
1106: *
1107: * @throws JPersistException
1108: */
1109:
1110: public Result getNextQuery() throws JPersistException {
1111: return nextQuery();
1112: }
1113:
1114: /**
1115: * If a query exists in the query queue it is executed and a Result instance is
1116: * returned, otherwise null is returned. The query queue is very
1117: * useful for building up several queries to be executed at a later
1118: * time (page rendering for example). Each call to nextQuery() executes
1119: * the queries in the query queue in the order they where added.
1120: *
1121: * @return a jpersist.Result instance
1122: *
1123: * @throws JPersistException
1124: */
1125:
1126: public Result nextQuery() throws JPersistException {
1127: if (isClosed)
1128: throw new JPersistException(
1129: JPersistException.DATABASE_CLOSED);
1130:
1131: if (queryQueueVector.size() > 0) {
1132: Object obj = queryQueueVector.elementAt(0);
1133:
1134: queryQueueVector.removeElementAt(0);
1135:
1136: if (obj instanceof String)
1137: return executeQuery((String) obj);
1138: else {
1139: String sql = (String) ((Object[]) obj)[0];
1140: Object[] objs = new Object[((Object[]) obj).length - 1];
1141:
1142: for (int i = 0; i < objs.length; i++)
1143: objs[i] = ((Object[]) obj)[i + 1];
1144:
1145: return parameterizedQuery(sql, objs);
1146: }
1147: }
1148:
1149: return null;
1150: }
1151:
1152: /**
1153: * See same in java.sql.Connection
1154: *
1155: * @see java.sql.Connection
1156: */
1157:
1158: public void setAutoCommit(boolean autoCommit)
1159: throws JPersistException {
1160: if (isClosed)
1161: throw new JPersistException(
1162: JPersistException.DATABASE_CLOSED);
1163:
1164: if (logger.isLoggable(Level.FINE))
1165: logger.fine("Setting auto commit to " + autoCommit);
1166:
1167: try {
1168: getConnection().setAutoCommit(autoCommit);
1169: } catch (Exception e) {
1170: throw new JPersistException(e);
1171: }
1172: }
1173:
1174: /**
1175: * Starts a transaction by setting auto commit to false. endTransaction() should allways be called to reset the auto commit mode.
1176: */
1177:
1178: public void beginTransaction() throws JPersistException {
1179: if (logger.isLoggable(Level.FINE))
1180: logger.fine("Starting transaction");
1181:
1182: setAutoCommit(false);
1183: }
1184:
1185: /**
1186: * Ends a transaction by setting auto commit to true (also commits the transaction).
1187: * Should allways be called, even after commit or rollback.
1188: */
1189:
1190: public void endTransaction() throws JPersistException {
1191: if (logger.isLoggable(Level.FINE))
1192: logger.fine("End transaction");
1193:
1194: setAutoCommit(true);
1195: }
1196:
1197: /**
1198: * See same in java.sql.Connection
1199: *
1200: * @see java.sql.Connection
1201: */
1202:
1203: public boolean getAutoCommit() throws JPersistException {
1204: if (isClosed)
1205: throw new JPersistException(
1206: JPersistException.DATABASE_CLOSED);
1207:
1208: try {
1209: return getConnection().getAutoCommit();
1210: } catch (Exception e) {
1211: throw new JPersistException(e);
1212: }
1213: }
1214:
1215: /**
1216: * See same in java.sql.Connection
1217: *
1218: * @see java.sql.Connection
1219: */
1220:
1221: public void commit() throws JPersistException {
1222: if (isClosed)
1223: throw new JPersistException(
1224: JPersistException.DATABASE_CLOSED);
1225:
1226: if (logger.isLoggable(Level.FINE))
1227: logger.fine("Commiting transaction");
1228:
1229: try {
1230: getConnection().commit();
1231: } catch (Exception e) {
1232: throw new JPersistException(e);
1233: }
1234: }
1235:
1236: /**
1237: * See same in java.sql.Connection
1238: *
1239: * @see java.sql.Connection
1240: */
1241:
1242: public void rollback() throws JPersistException {
1243: if (isClosed)
1244: throw new JPersistException(
1245: JPersistException.DATABASE_CLOSED);
1246:
1247: if (logger.isLoggable(Level.FINE))
1248: logger.fine("Rolling back transaction");
1249:
1250: try {
1251: getConnection().rollback();
1252: } catch (Exception e) {
1253: throw new JPersistException(e);
1254: }
1255: }
1256:
1257: /**
1258: * See same in java.sql.Connection
1259: *
1260: * @see java.sql.Connection
1261: */
1262:
1263: public void rollback(Savepoint savepoint) throws JPersistException {
1264: if (isClosed)
1265: throw new JPersistException(
1266: JPersistException.DATABASE_CLOSED);
1267:
1268: if (logger.isLoggable(Level.FINE))
1269: logger.fine("Rolling back transaction");
1270:
1271: try {
1272: getConnection().rollback(savepoint);
1273: } catch (Exception e) {
1274: throw new JPersistException(e);
1275: }
1276: }
1277:
1278: /**
1279: * See same in java.sql.Connection
1280: *
1281: * @see java.sql.Connection
1282: */
1283:
1284: public Savepoint setSavepoint() throws JPersistException {
1285: if (isClosed)
1286: throw new JPersistException(
1287: JPersistException.DATABASE_CLOSED);
1288:
1289: if (logger.isLoggable(Level.FINE))
1290: logger.fine("Adding savepoint");
1291:
1292: try {
1293: return getConnection().setSavepoint();
1294: } catch (Exception e) {
1295: throw new JPersistException(e);
1296: }
1297: }
1298:
1299: /**
1300: * See same in java.sql.Connection
1301: *
1302: * @see java.sql.Connection
1303: */
1304:
1305: public Savepoint setSavepoint(String name) throws JPersistException {
1306: if (isClosed)
1307: throw new JPersistException(
1308: JPersistException.DATABASE_CLOSED);
1309:
1310: if (logger.isLoggable(Level.FINE))
1311: logger.fine("Adding savepoint named = " + name);
1312:
1313: try {
1314: return getConnection().setSavepoint(name);
1315: } catch (Exception e) {
1316: throw new JPersistException(e);
1317: }
1318: }
1319:
1320: /**
1321: * See same in java.sql.Connection
1322: *
1323: * @see java.sql.Connection
1324: */
1325:
1326: public void releaseSavepoint(Savepoint savepoint)
1327: throws JPersistException {
1328: if (isClosed)
1329: throw new JPersistException(
1330: JPersistException.DATABASE_CLOSED);
1331:
1332: if (logger.isLoggable(Level.FINE))
1333: logger.fine("Releasing savepoint");
1334:
1335: try {
1336: if (isClosed)
1337: throw new JPersistException(
1338: JPersistException.DATABASE_CLOSED);
1339:
1340: getConnection().releaseSavepoint(savepoint);
1341: } catch (Exception e) {
1342: throw new JPersistException(e);
1343: }
1344: }
1345:
1346: /**
1347: * See same in java.sql.Connection
1348: *
1349: * @see java.sql.Connection
1350: */
1351:
1352: public SQLWarning getWarnings() throws JPersistException {
1353: if (isClosed)
1354: throw new JPersistException(
1355: JPersistException.DATABASE_CLOSED);
1356:
1357: try {
1358: return getConnection().getWarnings();
1359: } catch (Exception e) {
1360: throw new JPersistException(e);
1361: }
1362: }
1363:
1364: /**
1365: * See same in java.sql.Connection
1366: *
1367: * @see java.sql.Connection
1368: */
1369:
1370: public void clearWarnings() throws JPersistException {
1371: if (isClosed)
1372: throw new JPersistException(
1373: JPersistException.DATABASE_CLOSED);
1374:
1375: try {
1376: getConnection().clearWarnings();
1377: } catch (Exception e) {
1378: throw new JPersistException(e);
1379: }
1380: }
1381:
1382: /**
1383: * Sets the prepared statement (using appropriate set methods) with objects from array.
1384: *
1385: * @param preparedStatement an instance of java.sql.PreparedStatement
1386: * @param objects an array of objects
1387: */
1388:
1389: public static void setPreparedStatementObjects(
1390: PreparedStatement preparedStatement, Object... objects)
1391: throws SQLException, JPersistException {
1392: for (int i = 0; i < objects.length; i++) {
1393: if (objects[i] instanceof NullValue)
1394: preparedStatement.setNull(i + 1,
1395: ((NullValue) objects[i]).getSqlType());
1396: else if (objects[i] instanceof Array)
1397: preparedStatement.setArray(i + 1, (Array) objects[i]);
1398: else if (objects[i] instanceof BigDecimal)
1399: preparedStatement.setBigDecimal(i + 1,
1400: (BigDecimal) objects[i]);
1401: else if (objects[i] instanceof Blob)
1402: preparedStatement.setBlob(i + 1, (Blob) objects[i]);
1403: else if (objects[i] instanceof Clob)
1404: preparedStatement.setClob(i + 1, (Clob) objects[i]);
1405: else if (objects[i] instanceof Date)
1406: preparedStatement.setDate(i + 1, (Date) objects[i]);
1407: else if (objects[i] instanceof InputStream) {
1408: throw new JPersistException(
1409: "Must use jpersist.interfaces.AsciiStream or jpersist.interfaces.BinaryStream instead of InputStream");
1410: } else if (objects[i] instanceof AsciiStream)
1411: preparedStatement.setAsciiStream(i + 1,
1412: ((AsciiStream) objects[i]).getInputStream(),
1413: ((AsciiStream) objects[i]).getLength());
1414: else if (objects[i] instanceof BinaryStream)
1415: preparedStatement.setBinaryStream(i + 1,
1416: ((BinaryStream) objects[i]).getInputStream(),
1417: ((BinaryStream) objects[i]).getLength());
1418: else if (objects[i] instanceof Reader) {
1419: throw new JPersistException(
1420: "Must use jpersist.interfaces.ReaderHandler instead of Reader");
1421: } else if (objects[i] instanceof CharacterStream)
1422: preparedStatement.setCharacterStream(i + 1,
1423: ((CharacterStream) objects[i]).getReader(),
1424: ((CharacterStream) objects[i]).getLength());
1425: else if (objects[i] instanceof Ref)
1426: preparedStatement.setRef(i + 1, (Ref) objects[i]);
1427: else if (objects[i] instanceof String)
1428: preparedStatement.setString(i + 1, (String) objects[i]);
1429: else if (objects[i] instanceof Time)
1430: preparedStatement.setTime(i + 1, (Time) objects[i]);
1431: else if (objects[i] instanceof Timestamp)
1432: preparedStatement.setTimestamp(i + 1,
1433: (Timestamp) objects[i]);
1434: else if (objects[i] instanceof URL)
1435: preparedStatement.setURL(i + 1, (URL) objects[i]);
1436: else
1437: preparedStatement.setObject(i + 1, objects[i]);
1438: }
1439: }
1440: }
|