0001: /*
0002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
0003: *
0004: * // Copyright (c) 1998, 2007, Oracle. All rights reserved.
0005: *
0006: *
0007: * The contents of this file are subject to the terms of either the GNU
0008: * General Public License Version 2 only ("GPL") or the Common Development
0009: * and Distribution License("CDDL") (collectively, the "License"). You
0010: * may not use this file except in compliance with the License. You can obtain
0011: * a copy of the License at https://glassfish.dev.java.net/public/CDDL+GPL.html
0012: * or glassfish/bootstrap/legal/LICENSE.txt. See the License for the specific
0013: * language governing permissions and limitations under the License.
0014: *
0015: * When distributing the software, include this License Header Notice in each
0016: * file and include the License file at glassfish/bootstrap/legal/LICENSE.txt.
0017: * Sun designates this particular file as subject to the "Classpath" exception
0018: * as provided by Sun in the GPL Version 2 section of the License file that
0019: * accompanied this code. If applicable, add the following below the License
0020: * Header, with the fields enclosed by brackets [] replaced by your own
0021: * identifying information: "Portions Copyrighted [year]
0022: * [name of copyright owner]"
0023: *
0024: * Contributor(s):
0025: *
0026: * If you wish your version of this file to be governed by only the CDDL or
0027: * only the GPL Version 2, indicate your decision by adding "[Contributor]
0028: * elects to include this software in this distribution under the [CDDL or GPL
0029: * Version 2] license." If you don't indicate a single choice of license, a
0030: * recipient has the option to distribute your version of this file under
0031: * either the CDDL, the GPL Version 2 or to extend the choice of license to
0032: * its licensees as provided above. However, if you add GPL Version 2 code
0033: * and therefore, elected the GPL Version 2 license, then the option applies
0034: * only if the new code is made subject to such option by the copyright
0035: * holder.
0036: */
0037: package oracle.toplink.essentials.internal.queryframework;
0038:
0039: import java.util.*;
0040: import java.io.*;
0041: import oracle.toplink.essentials.internal.descriptors.OptimisticLockingPolicy;
0042: import oracle.toplink.essentials.descriptors.VersionLockingPolicy;
0043: import oracle.toplink.essentials.descriptors.DescriptorEvent;
0044: import oracle.toplink.essentials.descriptors.DescriptorEventManager;
0045: import oracle.toplink.essentials.descriptors.DescriptorQueryManager;
0046: import oracle.toplink.essentials.internal.helper.*;
0047: import oracle.toplink.essentials.internal.databaseaccess.*;
0048: import oracle.toplink.essentials.internal.sessions.*;
0049: import oracle.toplink.essentials.sessions.DatabaseRecord;
0050: import oracle.toplink.essentials.internal.identitymaps.CacheKey;
0051: import oracle.toplink.essentials.expressions.*;
0052: import oracle.toplink.essentials.queryframework.*;
0053: import oracle.toplink.essentials.exceptions.*;
0054: import oracle.toplink.essentials.mappings.*;
0055: import oracle.toplink.essentials.logging.SessionLog;
0056: import oracle.toplink.essentials.internal.sessions.AbstractRecord;
0057: import oracle.toplink.essentials.internal.sessions.UnitOfWorkImpl;
0058: import oracle.toplink.essentials.internal.sessions.AbstractSession;
0059: import oracle.toplink.essentials.descriptors.ClassDescriptor;
0060:
0061: /**
0062: * <p><b>Purpose</b>:
0063: * Abstract class for all database query mechanism objects.
0064: * DatabaseQueryMechanism is actually a helper class and currently is required
0065: * for all types of queries. Most of the work performed by the query framework is
0066: * performed in the query mechanism. The query mechanism contains the internal
0067: * knowledge necessary to perform the specific database operation.
0068: * <p>
0069: * <p><b>Responsibilities</b>:
0070: * Provide a common protocol for query mechanism objects.
0071: * Provides all of the database specific work for the assigned query.
0072: *
0073: * @author Yvon Lavoie
0074: * @since TOPLink/Java 1.0
0075: */
0076: public abstract class DatabaseQueryMechanism implements Cloneable,
0077: Serializable {
0078:
0079: /** The database query that uses this mechanism. */
0080: protected DatabaseQuery query;
0081:
0082: /**
0083: * Initialize the state of the query.
0084: */
0085: public DatabaseQueryMechanism() {
0086: }
0087:
0088: /**
0089: * Initialize the state of the query
0090: * @param query - owner of mechanism
0091: */
0092: public DatabaseQueryMechanism(DatabaseQuery query) {
0093: this .query = query;
0094: }
0095:
0096: /**
0097: * Remove the query object from the identity map.
0098: */
0099: protected void addObjectDeletedDuringCommit() {
0100: WriteObjectQuery writeQuery = getWriteObjectQuery();
0101: Object object = writeQuery.getObject();
0102:
0103: // CR3510313, avoid removing aggregate collections from cache (maintain cache is false).
0104: if (writeQuery.shouldMaintainCache()) {
0105: if (getSession().isUnitOfWork()) {
0106: ((UnitOfWorkImpl) getSession())
0107: .addObjectDeletedDuringCommit(object,
0108: getDescriptor());
0109: } else {
0110: getSession().getIdentityMapAccessorInstance()
0111: .removeFromIdentityMap(
0112: writeQuery.getPrimaryKey(),
0113: getDescriptor().getJavaClass(),
0114: getDescriptor());
0115: }
0116: }
0117: }
0118:
0119: /**
0120: * Add the initial write lock value to the row for insert.
0121: */
0122: protected void addWriteLockFieldForInsert() {
0123: if (getDescriptor().usesOptimisticLocking()) {
0124: getDescriptor().getOptimisticLockingPolicy()
0125: .setupWriteFieldsForInsert(getWriteObjectQuery());
0126: }
0127: }
0128:
0129: /**
0130: * Internal:
0131: * In the case of EJBQL, an expression needs to be generated. Build the required expression.
0132: */
0133: public void buildSelectionCriteria(AbstractSession session) {
0134: // Default is do nothing
0135: }
0136:
0137: /**
0138: * Perform a cache lookup for the query.
0139: * If the translation row contains all the primary key fields,
0140: * then a cache check will be performed.
0141: * If the object is found in the cache, return it;
0142: * otherwise return null.
0143: */
0144: public Object checkCacheForObject(AbstractRecord translationRow,
0145: AbstractSession session) {
0146: // Null check added for CR#4295 - TW
0147: if ((translationRow == null) || (translationRow.isEmpty())) {
0148: return null;
0149: }
0150:
0151: List keyFields = getDescriptor().getPrimaryKeyFields();
0152: Vector primaryKey = new Vector(keyFields.size());
0153:
0154: for (int index = 0; index < keyFields.size(); index++) {
0155: Object value = translationRow.get((DatabaseField) keyFields
0156: .get(index));
0157: if (value == null) {
0158: return null;
0159: } else {
0160: primaryKey.add(value);
0161: }
0162: }
0163: return session.getIdentityMapAccessorInstance()
0164: .getFromIdentityMapWithDeferredLock(primaryKey,
0165: getReadObjectQuery().getReferenceClass(),
0166: false, getDescriptor());
0167: }
0168:
0169: /**
0170: * Clone the mechanism
0171: */
0172: protected Object clone() {
0173: try {
0174: return super .clone();
0175: } catch (CloneNotSupportedException e) {
0176: throw new InternalError();
0177: }
0178: }
0179:
0180: /**
0181: * Clone the mechanism for the specified query clone.
0182: */
0183: public DatabaseQueryMechanism clone(DatabaseQuery queryClone) {
0184: DatabaseQueryMechanism clone = (DatabaseQueryMechanism) clone();
0185: clone.setQuery(queryClone);
0186: return clone;
0187: }
0188:
0189: /**
0190: * Read all rows from the database using a cursored stream.
0191: * @exception DatabaseException - an error has occurred on the database
0192: */
0193: public abstract DatabaseCall cursorSelectAllRows()
0194: throws DatabaseException;
0195:
0196: /**
0197: * Delete a collection of objects
0198: * This should be overriden by subclasses.
0199: * @exception DatabaseException - an error has occurred on the database
0200: */
0201: public boolean isEJBQLCallQueryMechanism() {
0202: return false;
0203: }
0204:
0205: /**
0206: * Build the objects for the rows, and answer them
0207: * @exception DatabaseException - an error has occurred on the database
0208: */
0209: public Object buildObjectsFromRows(Vector rows)
0210: throws DatabaseException {
0211: Object result = ((ReadAllQuery) getQuery())
0212: .getContainerPolicy().containerInstance(rows.size());
0213: return getDescriptor().getObjectBuilder().buildObjectsInto(
0214: (ReadAllQuery) getQuery(), rows, result);
0215: };
0216:
0217: public abstract Integer deleteAll() throws DatabaseException;
0218:
0219: /**
0220: * Delete an object
0221: * This should be overriden by subclasses.
0222: * @exception DatabaseException
0223: * @return the row count.
0224: */
0225: public abstract Integer deleteObject() throws DatabaseException;
0226:
0227: /**
0228: * Delete an object from the database.
0229: */
0230: public void deleteObjectForWrite() {
0231: WriteObjectQuery writeQuery = getWriteObjectQuery();
0232: Object object = writeQuery.getObject();
0233: DescriptorQueryManager queryManager = getDescriptor()
0234: .getQueryManager();
0235:
0236: // check for user-defined query
0237: if ((!writeQuery.isUserDefined())// this is not a user-defined query
0238: && queryManager.hasDeleteQuery()// there is a user-defined query
0239: && isExpressionQueryMechanism()) {// this is not a hand-coded call (custom SQL etc.)
0240: performUserDefinedDelete();
0241: return;
0242: }
0243:
0244: CommitManager commitManager = getSession().getCommitManager();
0245:
0246: // This must be done after the custom query check, otherwise it will be done twice.
0247: commitManager.markPreModifyCommitInProgress(object);
0248:
0249: if (writeQuery.getObjectChangeSet() == null) {
0250: // PERF: Avoid events if no listeners.
0251: if (getDescriptor().getEventManager()
0252: .hasAnyEventListeners()) {
0253: // only throw the events if there is no changeset otherwise the event will be thrown twice
0254: // once by the calculate changes code and here
0255: getDescriptor().getEventManager().executeEvent(
0256: new DescriptorEvent(
0257: DescriptorEventManager.PreDeleteEvent,
0258: writeQuery));
0259: }
0260: }
0261:
0262: // check whether deep shallow modify is turned on
0263: if (writeQuery.shouldCascadeParts()) {
0264: queryManager.preDelete(writeQuery);
0265: }
0266:
0267: // In a unit of work/writeObjects the preDelete may cause a shallow update of this object,
0268: // in this case the following second write must do the real delete.
0269: if (!commitManager.isShallowCommitted(object)
0270: && !writeQuery.shouldCascadeParts()) {
0271: updateForeignKeyFieldBeforeDelete();
0272: } else {
0273: // CR#2660080 missing aboutToDelete event.
0274: // PERF: Avoid events if no listeners.
0275: if (getDescriptor().getEventManager()
0276: .hasAnyEventListeners()) {
0277: DescriptorEvent event = new DescriptorEvent(
0278: DescriptorEventManager.AboutToDeleteEvent,
0279: writeQuery);
0280: event.setRecord(getModifyRow());
0281: getDescriptor().getEventManager().executeEvent(event);
0282: }
0283:
0284: int rowCount = deleteObject().intValue();
0285:
0286: if (rowCount < 1) {
0287: getSession().getEventManager().noRowsModified(
0288: writeQuery, object);
0289: }
0290:
0291: if (getDescriptor().usesOptimisticLocking()) {
0292: getDescriptor().getOptimisticLockingPolicy()
0293: .validateDelete(rowCount, object, writeQuery);
0294: }
0295:
0296: // remember that the object was deleted
0297: addObjectDeletedDuringCommit();
0298: }
0299:
0300: commitManager.markPostModifyCommitInProgress(object);
0301:
0302: // Verify if deep shallow modify is turned on.
0303: if (writeQuery.shouldCascadeParts()) {
0304: queryManager.postDelete(writeQuery);
0305: }
0306:
0307: // PERF: Avoid events if no listeners.
0308: if (getDescriptor().getEventManager().hasAnyEventListeners()) {
0309: getDescriptor().getEventManager().executeEvent(
0310: new DescriptorEvent(
0311: DescriptorEventManager.PostDeleteEvent,
0312: writeQuery));
0313: }
0314: }
0315:
0316: /**
0317: * Execute a non selecting SQL call
0318: * This should be overriden by subclasses.
0319: * @exception DatabaseException
0320: * @return the row count.
0321: */
0322: public abstract Integer executeNoSelect() throws DatabaseException;
0323:
0324: /**
0325: * Execute a select SQL call and return the rows.
0326: * This should be overriden by subclasses.
0327: * @exception DatabaseException
0328: */
0329: public abstract Vector executeSelect() throws DatabaseException;
0330:
0331: /**
0332: * Check whether the object already exists on the database; then
0333: * perform an insert, update or delete, as appropriate.
0334: * This method was moved here, from WriteObjectQuery.execute(),
0335: * so we can hide the source.
0336: * Return the object being written.
0337: */
0338: public Object executeWrite() throws DatabaseException,
0339: OptimisticLockException {
0340: WriteObjectQuery writeQuery = getWriteObjectQuery();
0341: Object object = writeQuery.getObject();
0342: CommitManager commitManager = getSession().getCommitManager();
0343:
0344: // if the object has already been committed, no work is required
0345: if (commitManager.isCommitCompleted(object)
0346: || commitManager.isCommitInPostModify(object)) {
0347: return object;
0348: }
0349:
0350: // check whether the object is already being committed -
0351: // if it is, then a shallow write must be executed
0352: if (commitManager.isCommitInPreModify(object)) {
0353: writeQuery.executeShallowWrite();
0354: return object;
0355: }
0356:
0357: try {
0358: getSession().beginTransaction();
0359:
0360: if (writeQuery.getObjectChangeSet() == null) {
0361: // PERF: Avoid events if no listeners.
0362: if (getDescriptor().getEventManager()
0363: .hasAnyEventListeners()) {
0364: // only throw the events if there is no changeset otherwise the event will be thrown twice
0365: // once by the calculate changes code and here
0366: getDescriptor()
0367: .getEventManager()
0368: .executeEvent(
0369: new DescriptorEvent(
0370: DescriptorEventManager.PreWriteEvent,
0371: writeQuery));
0372: }
0373: }
0374: writeQuery.executeCommit();
0375:
0376: // PERF: Avoid events if no listeners.
0377: if (getDescriptor().getEventManager()
0378: .hasAnyEventListeners()) {
0379: getDescriptor().getEventManager().executeEvent(
0380: new DescriptorEvent(
0381: DescriptorEventManager.PostWriteEvent,
0382: writeQuery));
0383: }
0384:
0385: getSession().commitTransaction();
0386:
0387: // notify the commit manager of the completion to the commit
0388: commitManager.markCommitCompleted(object);
0389:
0390: return object;
0391:
0392: } catch (RuntimeException exception) {
0393: getSession().rollbackTransaction();
0394: commitManager.markCommitCompleted(object);
0395: throw exception;
0396: }
0397: }
0398:
0399: /**
0400: * Check whether the object already exists on the database; then
0401: * perform an insert or update, as appropriate.
0402: * This method was moved here, from WriteObjectQuery.execute(),
0403: * so we can hide the source.
0404: * Return the object being written.
0405: */
0406: public Object executeWriteWithChangeSet() throws DatabaseException,
0407: OptimisticLockException {
0408: WriteObjectQuery writeQuery = getWriteObjectQuery();
0409: ObjectChangeSet objectChangeSet = writeQuery
0410: .getObjectChangeSet();
0411: CommitManager commitManager = getSession().getCommitManager();
0412:
0413: //if there are no changes then there is no work required
0414: // Check for forcedUpdate Version and Optimistic read lock (hasForcedChanges() set in ObjectChangePolicy)
0415: if (!objectChangeSet.hasChanges()
0416: && !objectChangeSet.hasForcedChanges()) {
0417: commitManager.markCommitCompleted(objectChangeSet);
0418: commitManager.markCommitCompleted(writeQuery.getObject());
0419: return writeQuery.getObject();
0420: }
0421: // if the object has already been committed, no work is required
0422: if (commitManager.isCommitCompleted(objectChangeSet)
0423: || commitManager.isCommitInPostModify(objectChangeSet)) {
0424: return writeQuery.getObject();
0425: }
0426:
0427: // if the object has already been committed, no work is required
0428: // need to check for the object to ensure insert wasn't completed already.
0429: if (commitManager.isCommitCompleted(writeQuery.getObject())
0430: || commitManager.isCommitInPostModify(writeQuery
0431: .getObject())) {
0432: return writeQuery.getObject();
0433: }
0434: try {
0435: getSession().beginTransaction();
0436:
0437: writeQuery.executeCommitWithChangeSet();
0438:
0439: // PERF: Avoid events if no listeners.
0440: if (getDescriptor().getEventManager()
0441: .hasAnyEventListeners()) {
0442: getDescriptor().getEventManager().executeEvent(
0443: new DescriptorEvent(
0444: DescriptorEventManager.PostWriteEvent,
0445: writeQuery));
0446: }
0447:
0448: getSession().commitTransaction();
0449:
0450: // notify the commit manager of the completion to the commit
0451: commitManager.markCommitCompleted(objectChangeSet);
0452: commitManager.markCommitCompleted(writeQuery.getObject());
0453:
0454: return writeQuery.getObject();
0455:
0456: } catch (RuntimeException exception) {
0457: getSession().rollbackTransaction();
0458: commitManager.markCommitCompleted(objectChangeSet);
0459: commitManager.markCommitCompleted(writeQuery.getObject());
0460: throw exception;
0461: }
0462: }
0463:
0464: /**
0465: * Convenience method
0466: */
0467: protected ClassDescriptor getDescriptor() {
0468: return getQuery().getDescriptor();
0469: }
0470:
0471: /**
0472: * Convenience method
0473: */
0474: public AbstractRecord getModifyRow() {
0475: if (getQuery().isModifyQuery()) {
0476: return ((ModifyQuery) getQuery()).getModifyRow();
0477: } else {
0478: return null;
0479: }
0480: }
0481:
0482: /**
0483: * Return the query that uses the mechanism.
0484: */
0485: public DatabaseQuery getQuery() {
0486: return query;
0487: }
0488:
0489: /**
0490: * Convenience method
0491: */
0492: protected ReadObjectQuery getReadObjectQuery() {
0493: return (ReadObjectQuery) getQuery();
0494: }
0495:
0496: /**
0497: * Return the selection criteria for the mechanism.
0498: * By default this is null. This method exists because both statement and expression
0499: * mechanisms use an expression and some code in the mappings depends on returning this.
0500: */
0501: public Expression getSelectionCriteria() {
0502: return null;
0503: }
0504:
0505: /**
0506: * Convenience method
0507: */
0508: protected AbstractSession getSession() {
0509: return getQuery().getSession();
0510: }
0511:
0512: /**
0513: * Convenience method
0514: */
0515: protected AbstractRecord getTranslationRow() {
0516: return getQuery().getTranslationRow();
0517: }
0518:
0519: /**
0520: * Convenience method
0521: */
0522: protected WriteObjectQuery getWriteObjectQuery() {
0523: return (WriteObjectQuery) getQuery();
0524: }
0525:
0526: /**
0527: * Insert an object.
0528: */
0529: public abstract void insertObject() throws DatabaseException;
0530:
0531: /**
0532: * Insert an object and provide the opportunity to reprepare prior to the insert.
0533: * This will be overridden
0534: * CR#3237
0535: */
0536: public void insertObject(boolean reprepare) {
0537: insertObject();
0538: }
0539:
0540: /**
0541: * Insert an object in the database.
0542: */
0543: public void insertObjectForWrite() {
0544: WriteObjectQuery writeQuery = getWriteObjectQuery();
0545: Object object = writeQuery.getObject();
0546: DescriptorQueryManager queryManager = getDescriptor()
0547: .getQueryManager();
0548:
0549: // check for user-defined query
0550: if ((!writeQuery.isUserDefined())// this is not a user-defined query
0551: && queryManager.hasInsertQuery()// there is a user-defined query
0552: && isExpressionQueryMechanism()) {// this is not a hand-coded call (custom SQL etc.)
0553: performUserDefinedInsert();
0554: return;
0555: }
0556:
0557: CommitManager commitManager = getSession().getCommitManager();
0558:
0559: // This must be done after the custom query check, otherwise it will be done twice.
0560: commitManager.markPreModifyCommitInProgress(object);
0561:
0562: if (writeQuery.getObjectChangeSet() == null) {
0563: // PERF: Avoid events if no listeners.
0564: if (getDescriptor().getEventManager()
0565: .hasAnyEventListeners()) {
0566: // only throw the events if there is no changeset otherwise the event will be thrown twice
0567: // once by the calculate changes code and here
0568: getDescriptor().getEventManager().executeEvent(
0569: new DescriptorEvent(
0570: DescriptorEventManager.PreInsertEvent,
0571: writeQuery));
0572: }
0573: }
0574:
0575: // check whether deep shallow modify is turned on
0576: if (writeQuery.shouldCascadeParts()) {
0577: queryManager.preInsert(writeQuery);
0578: }
0579:
0580: // In a unit of work/writeObjects the preInsert may have caused a shallow insert of this object,
0581: // in this case this second write must do an update.
0582: if (commitManager.isShallowCommitted(object)) {
0583: updateForeignKeyFieldAfterInsert();
0584: } else {
0585: AbstractRecord modifyRow = writeQuery.getModifyRow();
0586: if (modifyRow == null) {// Maybe have been passed in as in aggregate collection.
0587: if (writeQuery.shouldCascadeParts()) {
0588: writeQuery.setModifyRow(getDescriptor()
0589: .getObjectBuilder().buildRow(object,
0590: getSession()));
0591: } else {
0592: writeQuery.setModifyRow(getDescriptor()
0593: .getObjectBuilder()
0594: .buildRowForShallowInsert(object,
0595: getSession()));
0596: }
0597: } else {
0598: if (writeQuery.shouldCascadeParts()) {
0599: writeQuery.setModifyRow(getDescriptor()
0600: .getObjectBuilder().buildRow(modifyRow,
0601: object, getSession()));
0602: } else {
0603: writeQuery.setModifyRow(getDescriptor()
0604: .getObjectBuilder()
0605: .buildRowForShallowInsert(modifyRow,
0606: object, getSession()));
0607: }
0608: }
0609:
0610: // the modify row and the translation row are the same for insert
0611: writeQuery.setTranslationRow(getModifyRow());
0612: if (!writeQuery.getDescriptor()
0613: .isAggregateCollectionDescriptor()) {// Should/cannot be recomputed in aggregate collection.
0614: writeQuery.setPrimaryKey(getDescriptor()
0615: .getObjectBuilder()
0616: .extractPrimaryKeyFromObject(object,
0617: getSession()));
0618: }
0619: addWriteLockFieldForInsert();
0620:
0621: // CR#3237
0622: // Store the size of the modify row so we can determine if the user has added to the row in the insert.
0623: int modifyRowSize = getModifyRow().size();
0624:
0625: // PERF: Avoid events if no listeners.
0626: if (getDescriptor().getEventManager()
0627: .hasAnyEventListeners()) {
0628: DescriptorEvent event = new DescriptorEvent(
0629: DescriptorEventManager.AboutToInsertEvent,
0630: writeQuery);
0631: event.setRecord(getModifyRow());
0632: getDescriptor().getEventManager().executeEvent(event);
0633: }
0634:
0635: // CR#3237
0636: // Call insert with a boolean that tells it to reprepare if the user has altered the modify row.
0637: insertObject(modifyRowSize != getModifyRow().size());
0638:
0639: // register the object before post insert to resolve possible cycles
0640: registerObjectInIdentityMap();
0641: if (writeQuery.getObjectChangeSet() != null) {
0642: //make sure that we put this new changeset in the changes list of the
0643: //uow changeset for serialization, or customer usage.
0644: ((UnitOfWorkChangeSet) writeQuery.getObjectChangeSet()
0645: .getUOWChangeSet()).putNewObjectInChangesList(
0646: writeQuery.getObjectChangeSet(), getSession());
0647: }
0648: }
0649:
0650: commitManager.markPostModifyCommitInProgress(object);
0651: // Verify if deep shallow modify is turned on.
0652: if (writeQuery.shouldCascadeParts()) {
0653: queryManager.postInsert(writeQuery);
0654: }
0655:
0656: // PERF: Avoid events if no listeners.
0657: if (getDescriptor().getEventManager().hasAnyEventListeners()) {
0658: getDescriptor().getEventManager().executeEvent(
0659: new DescriptorEvent(
0660: DescriptorEventManager.PostInsertEvent,
0661: writeQuery));
0662: }
0663: }
0664:
0665: /**
0666: * Insert an object in the database.
0667: */
0668: public void insertObjectForWriteWithChangeSet() {
0669: WriteObjectQuery writeQuery = getWriteObjectQuery();
0670: ObjectChangeSet objectChangeSet = writeQuery
0671: .getObjectChangeSet();
0672: DescriptorQueryManager queryManager = getDescriptor()
0673: .getQueryManager();
0674: CommitManager commitManager = getSession().getCommitManager();
0675:
0676: // check for user-defined query
0677: if ((!writeQuery.isUserDefined())// this is not a user-defined query
0678: && queryManager.hasInsertQuery()// there is a user-defined query
0679: && isExpressionQueryMechanism()) {// this is not a hand-coded call (custom SQL etc.)
0680: //must mark the changeSet here because the userDefined Insert will not use the changesets
0681: commitManager
0682: .markPreModifyCommitInProgress(objectChangeSet);
0683: performUserDefinedInsert();
0684: return;
0685: }
0686:
0687: // This must be done after the custom query check, otherwise it will be done twice.
0688: commitManager.markPreModifyCommitInProgress(objectChangeSet);
0689: commitManager.markPreModifyCommitInProgress(writeQuery
0690: .getObject());
0691:
0692: // check whether deep shallow modify is turned on
0693: if (writeQuery.shouldCascadeParts()) {
0694: queryManager.preInsert(writeQuery);
0695: }
0696:
0697: // In a unit of work/writeObjects the preInsert may have caused a shallow insert of this object,
0698: // in this case this second write must do an update.
0699: if (commitManager.isShallowCommitted(objectChangeSet)) {
0700: updateForeignKeyFieldAfterInsert();
0701: } else {
0702: AbstractRecord modifyRow = writeQuery.getModifyRow();
0703: if (modifyRow == null) {// Maybe have been passed in as in aggregate collection.
0704: if (writeQuery.shouldCascadeParts()) {
0705: writeQuery.setModifyRow(getDescriptor()
0706: .getObjectBuilder().buildRowWithChangeSet(
0707: objectChangeSet, getSession()));
0708: } else {
0709: writeQuery.setModifyRow(getDescriptor()
0710: .getObjectBuilder()
0711: .buildRowForShallowInsertWithChangeSet(
0712: objectChangeSet, getSession()));
0713: }
0714: } else {
0715: if (writeQuery.shouldCascadeParts()) {
0716: writeQuery.setModifyRow(getDescriptor()
0717: .getObjectBuilder().buildRowWithChangeSet(
0718: modifyRow, objectChangeSet,
0719: getSession()));
0720: } else {
0721: writeQuery.setModifyRow(getDescriptor()
0722: .getObjectBuilder()
0723: .buildRowForShallowInsertWithChangeSet(
0724: modifyRow, objectChangeSet,
0725: getSession()));
0726: }
0727: }
0728:
0729: // the modify row and the translation row are the same for insert
0730: writeQuery.setTranslationRow(getModifyRow());
0731: if (!writeQuery.getDescriptor()
0732: .isAggregateCollectionDescriptor()) {// Should/cannot be recomputed in aggregate collection.
0733: writeQuery.setPrimaryKey(objectChangeSet
0734: .getPrimaryKeys());
0735: }
0736: addWriteLockFieldForInsert();
0737:
0738: // PERF: Avoid events if no listeners.
0739: if (getDescriptor().getEventManager()
0740: .hasAnyEventListeners()) {
0741: DescriptorEvent event = new DescriptorEvent(
0742: DescriptorEventManager.AboutToInsertEvent,
0743: writeQuery);
0744: event.setRecord(getModifyRow());
0745: getDescriptor().getEventManager().executeEvent(event);
0746: }
0747:
0748: insertObject();
0749:
0750: // register the object before post insert to resolve possible cycles
0751: registerObjectInIdentityMap();
0752: if (objectChangeSet != null) {
0753: //make sure that we put this new changeset in the changes list of the
0754: //uow changeset for serialization, or customer usage.
0755: ((UnitOfWorkChangeSet) objectChangeSet
0756: .getUOWChangeSet()).putNewObjectInChangesList(
0757: objectChangeSet, getSession());
0758: }
0759: }
0760:
0761: commitManager.markPostModifyCommitInProgress(objectChangeSet);
0762: commitManager.markPostModifyCommitInProgress(writeQuery
0763: .getObject());
0764: // Verify if deep shallow modify is turned on.
0765: if (writeQuery.shouldCascadeParts()) {
0766: queryManager.postInsert(writeQuery);
0767: }
0768:
0769: // PERF: Avoid events if no listeners.
0770: if (getDescriptor().getEventManager().hasAnyEventListeners()) {
0771: getDescriptor().getEventManager().executeEvent(
0772: new DescriptorEvent(
0773: DescriptorEventManager.PostInsertEvent,
0774: writeQuery));
0775: }
0776: }
0777:
0778: /**
0779: * Return true if this is a call query mechanism
0780: */
0781: public boolean isCallQueryMechanism() {
0782: return false;
0783: }
0784:
0785: /**
0786: * Return true if this is an expression query mechanism
0787: */
0788: public boolean isExpressionQueryMechanism() {
0789: return false;
0790: }
0791:
0792: /**
0793: * Return true if this is a query by example mechanism
0794: */
0795: public boolean isQueryByExampleMechanism() {
0796: return false;
0797: }
0798:
0799: /**
0800: * Return true if this is a statement query mechanism
0801: */
0802: public boolean isStatementQueryMechanism() {
0803: return false;
0804: }
0805:
0806: /**
0807: * Delete the object using the user defined query.
0808: * This ensures that the query is cloned and prepared correctly.
0809: */
0810: protected void performUserDefinedDelete() {
0811: performUserDefinedWrite(getDescriptor().getQueryManager()
0812: .getDeleteQuery());
0813: }
0814:
0815: /**
0816: * Insert the object using the user defined query.
0817: * This ensures that the query is cloned and prepared correctly.
0818: */
0819: protected void performUserDefinedInsert() {
0820: performUserDefinedWrite(getDescriptor().getQueryManager()
0821: .getInsertQuery());
0822: }
0823:
0824: /**
0825: * Update the object using the user defined query.
0826: * This ensures that the query is cloned and prepared correctly.
0827: */
0828: protected void performUserDefinedUpdate() {
0829: performUserDefinedWrite(getDescriptor().getQueryManager()
0830: .getUpdateQuery());
0831: }
0832:
0833: /**
0834: * Write the object using the specified user-defined query.
0835: * This ensures that the query is cloned and prepared correctly.
0836: */
0837: protected void performUserDefinedWrite(
0838: WriteObjectQuery userDefinedWriteQuery) {
0839: userDefinedWriteQuery.checkPrepare(getSession(),
0840: getTranslationRow());
0841:
0842: Object object = getWriteObjectQuery().getObject();
0843: WriteObjectQuery writeQuery = (WriteObjectQuery) userDefinedWriteQuery
0844: .clone();
0845: writeQuery.setObject(object);
0846: writeQuery.setObjectChangeSet(getWriteObjectQuery()
0847: .getObjectChangeSet());
0848: writeQuery.setCascadePolicy(getQuery().getCascadePolicy());
0849: writeQuery.setShouldMaintainCache(getQuery()
0850: .shouldMaintainCache());
0851: writeQuery.setTranslationRow(getTranslationRow());
0852: writeQuery.setModifyRow(getModifyRow());
0853: writeQuery.setPrimaryKey(getWriteObjectQuery().getPrimaryKey());
0854: writeQuery.setSession(getSession());
0855: writeQuery.prepareForExecution();
0856:
0857: // HACK: If there is a changeset, the change set method must be used,
0858: // however it is currently broken for inserts, so until this is fixed,
0859: // only using correct commit for updates.
0860: if (getWriteObjectQuery().isUpdateObjectQuery()
0861: && (getWriteObjectQuery().getObjectChangeSet() != null)) {
0862: writeQuery.executeCommitWithChangeSet();
0863: } else {
0864: writeQuery.executeCommit();
0865: }
0866: }
0867:
0868: /**
0869: * This is different from 'prepareForExecution()'
0870: * in that this is called on the original query,
0871: * and the other is called on the clone of the query.
0872: * This query is copied for concurrency so this prepare can only setup things that
0873: * will apply to any future execution of this query.
0874: */
0875: public void prepare() throws QueryException {
0876: // the default is to do nothing
0877: }
0878:
0879: /**
0880: * Pre-pare for a cursored execute.
0881: * This is sent to the original query before cloning.
0882: */
0883: public abstract void prepareCursorSelectAllRows()
0884: throws QueryException;
0885:
0886: /**
0887: * Prepare for a delete all.
0888: * This is sent to the original query before cloning.
0889: */
0890: public abstract void prepareDeleteAll() throws QueryException;
0891:
0892: /**
0893: * Prepare for a delete.
0894: * This is sent to the original query before cloning.
0895: */
0896: public abstract void prepareDeleteObject() throws QueryException;
0897:
0898: /**
0899: * Pre-pare for a select execute.
0900: * This is sent to the original query before cloning.
0901: */
0902: public abstract void prepareDoesExist(DatabaseField field)
0903: throws QueryException;
0904:
0905: /**
0906: * Prepare for a raw (non-object), non-selecting call.
0907: * This is sent to the original query before cloning.
0908: */
0909: public abstract void prepareExecuteNoSelect() throws QueryException;
0910:
0911: /**
0912: * Prepare for a raw (non-object) select call.
0913: * This is sent to the original query before cloning.
0914: */
0915: public abstract void prepareExecuteSelect() throws QueryException;
0916:
0917: /**
0918: * All the query mechanism related things are initialized here.
0919: * This method is called on the *clone* of the query with
0920: * every execution.
0921: */
0922: public void prepareForExecution() throws QueryException {
0923: // the default is to do nothing
0924: }
0925:
0926: /**
0927: * Prepare for an insert.
0928: * This is sent to the original query before cloning.
0929: */
0930: public abstract void prepareInsertObject() throws QueryException;
0931:
0932: /**
0933: * Pre-pare for a select execute.
0934: * This is sent to the original query before cloning.
0935: */
0936: public abstract void prepareReportQuerySelectAllRows()
0937: throws QueryException;
0938:
0939: /**
0940: * Pre-pare a report query for a sub-select.
0941: */
0942: public abstract void prepareReportQuerySubSelect()
0943: throws QueryException;
0944:
0945: /**
0946: * Prepare for a select returning (possibly) multiple rows.
0947: * This is sent to the original query before cloning.
0948: */
0949: public abstract void prepareSelectAllRows() throws QueryException;
0950:
0951: /**
0952: * Prepare for a select returning a single row.
0953: * This is sent to the original query before cloning.
0954: */
0955: public abstract void prepareSelectOneRow() throws QueryException;
0956:
0957: /**
0958: * Prepare for an update.
0959: * This is sent to the original query before cloning.
0960: */
0961: public abstract void prepareUpdateObject() throws QueryException;
0962:
0963: /**
0964: * Prepare for an update all.
0965: * This is sent to the original query before cloning.
0966: */
0967: public abstract void prepareUpdateAll() throws QueryException;
0968:
0969: /**
0970: * Store the query object in the identity map.
0971: */
0972: protected void registerObjectInIdentityMap() {
0973: WriteObjectQuery writeQuery = getWriteObjectQuery();
0974: Object object = writeQuery.getObject();
0975:
0976: if (writeQuery.shouldMaintainCache()) {
0977: if (getDescriptor().usesOptimisticLocking()) {
0978: Object optimisticLockValue = getDescriptor()
0979: .getOptimisticLockingPolicy()
0980: .getValueToPutInCache(
0981: writeQuery.getModifyRow(), getSession());
0982: getSession().getIdentityMapAccessorInstance()
0983: .putInIdentityMap(object,
0984: writeQuery.getPrimaryKey(),
0985: optimisticLockValue,
0986: System.currentTimeMillis(),
0987: getDescriptor());
0988: } else {
0989: getSession().getIdentityMapAccessorInstance()
0990: .putInIdentityMap(object,
0991: writeQuery.getPrimaryKey(), null,
0992: System.currentTimeMillis(),
0993: getDescriptor());
0994: }
0995: }
0996: }
0997:
0998: /**
0999: * INTERNAL:
1000: * Read all rows from the database.
1001: */
1002: public abstract Vector selectAllReportQueryRows()
1003: throws DatabaseException;
1004:
1005: /**
1006: * Read and return rows from the database.
1007: */
1008: public abstract Vector selectAllRows() throws DatabaseException;
1009:
1010: /**
1011: * Read and return a row from the database.
1012: */
1013: public abstract AbstractRecord selectOneRow()
1014: throws DatabaseException;
1015:
1016: /**
1017: * Read and return a row from the database for an existence check.
1018: */
1019: public abstract AbstractRecord selectRowForDoesExist(
1020: DatabaseField field) throws DatabaseException;
1021:
1022: /**
1023: * Set the query that uses this mechanism.
1024: */
1025: public void setQuery(DatabaseQuery query) {
1026: this .query = query;
1027: }
1028:
1029: /**
1030: * INTERNAL:
1031: * Shallow delete the specified object.
1032: */
1033: public void shallowDeleteObjectForWrite(Object object,
1034: WriteObjectQuery writeQuery, CommitManager commitManager)
1035: throws DatabaseException, OptimisticLockException {
1036: // a shallow delete must be performed
1037: writeQuery.dontCascadeParts();
1038: deleteObjectForWrite();
1039: // mark this object as shallow committed so that the delete will be executed
1040: commitManager.markShallowCommit(object);
1041: }
1042:
1043: /**
1044: * INTERNAL:
1045: * Shallow insert the specified object.
1046: */
1047: public void shallowInsertObjectForWrite(Object object,
1048: WriteObjectQuery writeQuery, CommitManager commitManager)
1049: throws DatabaseException, OptimisticLockException {
1050: // a shallow insert must be performed
1051: writeQuery.dontCascadeParts();
1052: insertObjectForWrite();
1053: // mark this object as shallow committed so that the insert will do an update
1054: commitManager.markShallowCommit(object);
1055: }
1056:
1057: /**
1058: * Update the foreign key fields when resolving a bi-directonal reference in a UOW.
1059: * This must always be dynamic as it is called within an insert query and is really part of the insert
1060: * and does not fire update events or worry about locking.
1061: */
1062: protected void updateForeignKeyFieldAfterInsert() {
1063: WriteObjectQuery writeQuery = getWriteObjectQuery();
1064: Object object = writeQuery.getObject();
1065:
1066: writeQuery.setPrimaryKey(getDescriptor().getObjectBuilder()
1067: .extractPrimaryKeyFromObject(object, getSession()));
1068: // reset the translation row because the insert has occurred and the id has
1069: // been assigned to the object, but not the row
1070: writeQuery.setTranslationRow(getDescriptor().getObjectBuilder()
1071: .buildRowForTranslation(object, getSession()));
1072:
1073: writeQuery.setModifyRow(getDescriptor().getObjectBuilder()
1074: .buildRowForUpdate(writeQuery));
1075:
1076: updateForeignKeyFieldShallow(writeQuery);
1077: }
1078:
1079: /**
1080: * Null out the foreign key fields when resolving a bi-directonal reference in a UOW.
1081: * This must always be dynamic as it is called within a delete query and is really part of the delete
1082: * and does not fire update events or worry about locking.
1083: */
1084: protected void updateForeignKeyFieldBeforeDelete() {
1085: WriteObjectQuery writeQuery = getWriteObjectQuery();
1086: Object object = writeQuery.getObject();
1087:
1088: writeQuery.setPrimaryKey(getDescriptor().getObjectBuilder()
1089: .extractPrimaryKeyFromObject(object, getSession()));
1090: // set the translation row
1091: writeQuery.setTranslationRow(getDescriptor().getObjectBuilder()
1092: .buildRowForTranslation(object, getSession()));
1093: // build a query to null out the foreign keys
1094: writeQuery.setModifyRow(getDescriptor().getObjectBuilder()
1095: .buildRowForShallowDelete(object, getSession()));
1096:
1097: updateForeignKeyFieldShallow(writeQuery);
1098: }
1099:
1100: /**
1101: * Issue update SQL statement
1102: */
1103: public abstract Integer updateAll() throws DatabaseException;
1104:
1105: /**
1106: * Update an object.
1107: * Return the row count.
1108: */
1109: public abstract Integer updateObject() throws DatabaseException;
1110:
1111: /**
1112: * Update the foreign key fields when resolving a bi-directonal reference in a UOW.
1113: * This must always be dynamic as it is called within an insert query and is really part of the insert
1114: * and does not fire update events or worry about locking.
1115: */
1116: protected abstract void updateForeignKeyFieldShallow(
1117: WriteObjectQuery writeQuery);
1118:
1119: protected void updateObjectAndRowWithReturnRow(
1120: Collection returnFields, boolean isFirstCallForInsert) {
1121: WriteObjectQuery writeQuery = getWriteObjectQuery();
1122: AbstractRecord outputRow = (AbstractRecord) writeQuery
1123: .getProperties().get("output");
1124: if ((outputRow == null) || outputRow.isEmpty()) {
1125: return;
1126: }
1127: AbstractRecord row = new DatabaseRecord();
1128: for (Iterator iterator = returnFields.iterator(); iterator
1129: .hasNext();) {
1130: DatabaseField field = (DatabaseField) iterator.next();
1131: if (outputRow.containsKey(field)) {
1132: row.put(field, outputRow.get(field));
1133: }
1134: }
1135: if (row.isEmpty()) {
1136: return;
1137: }
1138:
1139: Object object = writeQuery.getObject();
1140:
1141: getDescriptor().getObjectBuilder().assignReturnRow(object,
1142: getSession(), row);
1143:
1144: Vector primaryKeys = null;
1145: if (isFirstCallForInsert) {
1146: AbstractRecord pkToModify = new DatabaseRecord();
1147: List primaryKeyFields = getDescriptor()
1148: .getPrimaryKeyFields();
1149: for (int i = 0; i < primaryKeyFields.size(); i++) {
1150: DatabaseField field = (DatabaseField) primaryKeyFields
1151: .get(i);
1152: if (row.containsKey(field)) {
1153: pkToModify.put(field, row.get(field));
1154: }
1155: }
1156: if (!pkToModify.isEmpty()) {
1157: primaryKeys = getDescriptor().getObjectBuilder()
1158: .extractPrimaryKeyFromObject(object,
1159: getSession());
1160: writeQuery.setPrimaryKey(primaryKeys);
1161: // Now I need to update the row
1162: getModifyRow().putAll(pkToModify);
1163: getDescriptor()
1164: .getObjectBuilder()
1165: .addPrimaryKeyForNonDefaultTable(getModifyRow());
1166: }
1167: }
1168:
1169: // update the changeSet if there is one
1170: if (getSession().isUnitOfWork()) {
1171: ObjectChangeSet objectChangeSet = writeQuery
1172: .getObjectChangeSet();
1173: if ((objectChangeSet == null)
1174: && (((UnitOfWorkImpl) getSession())
1175: .getUnitOfWorkChangeSet() != null)) {
1176: objectChangeSet = (ObjectChangeSet) ((UnitOfWorkImpl) getSession())
1177: .getUnitOfWorkChangeSet()
1178: .getObjectChangeSetForClone(object);
1179: }
1180: if (objectChangeSet != null) {
1181: updateChangeSet(getDescriptor(), objectChangeSet, row,
1182: object);
1183: if (primaryKeys != null) {
1184: objectChangeSet.setCacheKey(new CacheKey(
1185: primaryKeys));
1186: }
1187: }
1188: }
1189: }
1190:
1191: /**
1192: * Update the change set with all of the field values in the row.
1193: * This handle writable and read-only mappings, direct and nested aggregates.
1194: * It is used from ReturningPolicy and VersionLockingPolicy.
1195: */
1196: public void updateChangeSet(ClassDescriptor desc,
1197: ObjectChangeSet objectChangeSet, AbstractRecord row,
1198: Object object) {
1199: HashSet handledMappings = new HashSet(row.size());
1200: for (int i = 0; i < row.size(); i++) {
1201: DatabaseField field = (DatabaseField) row.getFields()
1202: .elementAt(i);
1203: Object value = row.getValues().elementAt(i);
1204: updateChangeSet(desc, objectChangeSet, field, object,
1205: handledMappings);
1206: }
1207: }
1208:
1209: protected void updateChangeSet(ClassDescriptor desc,
1210: ObjectChangeSet objectChangeSet, DatabaseField field,
1211: Object object) {
1212: updateChangeSet(desc, objectChangeSet, field, object, null);
1213: }
1214:
1215: protected void updateChangeSet(ClassDescriptor desc,
1216: ObjectChangeSet objectChangeSet, DatabaseField field,
1217: Object object, Collection handledMappings) {
1218: DatabaseMapping mapping;
1219: Vector mappingVector = desc.getObjectBuilder()
1220: .getReadOnlyMappingsForField(field);
1221: if (mappingVector != null) {
1222: for (int j = 0; j < mappingVector.size(); j++) {
1223: mapping = (DatabaseMapping) mappingVector.elementAt(j);
1224: updateChangeSet(mapping, objectChangeSet, field,
1225: object, handledMappings);
1226: }
1227: }
1228: mapping = desc.getObjectBuilder().getMappingForField(field);
1229: if (mapping != null) {
1230: updateChangeSet(mapping, objectChangeSet, field, object,
1231: handledMappings);
1232: }
1233: }
1234:
1235: protected void updateChangeSet(DatabaseMapping mapping,
1236: ObjectChangeSet objectChangeSet, DatabaseField field,
1237: Object object, Collection handledMappings) {
1238: if ((handledMappings != null)
1239: && handledMappings.contains(mapping)) {
1240: return;
1241: }
1242: if (mapping.isAggregateObjectMapping()) {
1243: Object aggregate = mapping
1244: .getAttributeValueFromObject(object);
1245: AggregateChangeRecord record = (AggregateChangeRecord) objectChangeSet
1246: .getChangesForAttributeNamed(mapping
1247: .getAttributeName());
1248: if (aggregate != null) {
1249: if (record == null) {
1250: record = new AggregateChangeRecord(objectChangeSet);
1251: record.setAttribute(mapping.getAttributeName());
1252: record.setMapping(mapping);
1253: objectChangeSet.addChange(record);
1254: }
1255: ObjectChangeSet aggregateChangeSet = (oracle.toplink.essentials.internal.sessions.ObjectChangeSet) record
1256: .getChangedObject();
1257: ClassDescriptor aggregateDescriptor = ((AggregateObjectMapping) mapping)
1258: .getReferenceDescriptor();
1259: if (aggregateChangeSet == null) {
1260: aggregateChangeSet = aggregateDescriptor
1261: .getObjectBuilder()
1262: .createObjectChangeSet(
1263: aggregate,
1264: (oracle.toplink.essentials.internal.sessions.UnitOfWorkChangeSet) ((UnitOfWorkImpl) getSession())
1265: .getUnitOfWorkChangeSet(),
1266: getSession());
1267: record.setChangedObject(aggregateChangeSet);
1268: }
1269: updateChangeSet(aggregateDescriptor,
1270: aggregateChangeSet, field, aggregate,
1271: handledMappings);
1272: } else {
1273: if (record != null) {
1274: record.setChangedObject(null);
1275: }
1276: }
1277: } else if (mapping.isDirectToFieldMapping()) {
1278: Object attributeValue = mapping
1279: .getAttributeValueFromObject(object);
1280: objectChangeSet.updateChangeRecordForAttribute(mapping,
1281: attributeValue);
1282: } else {
1283: getSession().log(SessionLog.FINEST, SessionLog.QUERY,
1284: "field_for_unsupported_mapping_returned", field,
1285: getDescriptor());
1286: }
1287: }
1288:
1289: /**
1290: * Update the object's primary key by fetching a new sequence number from the accessor.
1291: */
1292: protected void updateObjectAndRowWithSequenceNumber()
1293: throws DatabaseException {
1294: WriteObjectQuery writeQuery = getWriteObjectQuery();
1295: Object object = writeQuery.getObject();
1296:
1297: Object sequenceValue = getDescriptor().getObjectBuilder()
1298: .assignSequenceNumber(object, getSession());
1299: if (sequenceValue == null) {
1300: return;
1301: }
1302: Vector primaryKeys = getDescriptor().getObjectBuilder()
1303: .extractPrimaryKeyFromObject(object, getSession());
1304: writeQuery.setPrimaryKey(primaryKeys);
1305: DatabaseField sequenceNumberField = getDescriptor()
1306: .getSequenceNumberField();
1307:
1308: // Now I need to update the row
1309: getModifyRow().put(sequenceNumberField, sequenceValue);
1310: getDescriptor().getObjectBuilder()
1311: .addPrimaryKeyForNonDefaultTable(getModifyRow());
1312: // update the changeSet if there is one
1313: if (getSession().isUnitOfWork()) {
1314: ObjectChangeSet objectChangeSet = writeQuery
1315: .getObjectChangeSet();
1316: if ((objectChangeSet == null)
1317: && (((UnitOfWorkImpl) getSession())
1318: .getUnitOfWorkChangeSet() != null)) {
1319: objectChangeSet = (ObjectChangeSet) ((UnitOfWorkImpl) getSession())
1320: .getUnitOfWorkChangeSet()
1321: .getObjectChangeSetForClone(object);
1322: }
1323: if (objectChangeSet != null) {
1324: updateChangeSet(getDescriptor(), objectChangeSet,
1325: sequenceNumberField, object);
1326: objectChangeSet.setCacheKey(new CacheKey(primaryKeys));
1327: }
1328: }
1329: }
1330:
1331: /**
1332: * Update the object
1333: */
1334: public void updateObjectForWrite() {
1335: WriteObjectQuery writeQuery = getWriteObjectQuery();
1336: Object object = writeQuery.getObject();
1337: DescriptorQueryManager queryManager = getDescriptor()
1338: .getQueryManager();
1339:
1340: // check for user-defined query
1341: if ((!writeQuery.isUserDefined())// this is not a user-defined query
1342: && queryManager.hasUpdateQuery()// there is a user-defined query
1343: && isExpressionQueryMechanism()) {// this is not a hand-coded call (custom SQL etc.)
1344: performUserDefinedUpdate();
1345: return;
1346: }
1347:
1348: // This must be done after the custom query check, otherwise it will be done twice.
1349: getSession().getCommitManager().markPreModifyCommitInProgress(
1350: object);
1351:
1352: if (writeQuery.getObjectChangeSet() == null) {
1353: // PERF: Avoid events if no listeners.
1354: if (getDescriptor().getEventManager()
1355: .hasAnyEventListeners()) {
1356: // only throw the events if there is no changeset otherwise the event will be thrown twice
1357: // once by the calculate changes code and here
1358: getDescriptor().getEventManager().executeEvent(
1359: new DescriptorEvent(
1360: DescriptorEventManager.PreUpdateEvent,
1361: writeQuery));
1362: }
1363: }
1364:
1365: // Verify if deep shallow modify is turned on
1366: if (writeQuery.shouldCascadeParts()) {
1367: queryManager.preUpdate(writeQuery);
1368: }
1369:
1370: // The row must not be built until after preUpdate in case the object reference has changed.
1371: // For a user defined update in the uow to row must be built twice to check if any update is required.
1372: if ((writeQuery.isUserDefined() || writeQuery.isCallQuery())
1373: && (!getSession().isUnitOfWork())) {
1374: writeQuery.setModifyRow(getDescriptor().getObjectBuilder()
1375: .buildRow(object, getSession()));
1376: } else {
1377: writeQuery.setModifyRow(getDescriptor().getObjectBuilder()
1378: .buildRowForUpdate(writeQuery));
1379: }
1380:
1381: if (!getModifyRow().isEmpty()) {
1382: // If user defined the entire row is required. Must not be built until change is known.
1383: if ((writeQuery.isUserDefined() || writeQuery.isCallQuery())
1384: && getSession().isUnitOfWork()) {
1385: writeQuery.setModifyRow(getDescriptor()
1386: .getObjectBuilder().buildRow(object,
1387: getSession()));
1388: }
1389:
1390: // Update the write lock field if required
1391: if (getDescriptor().usesOptimisticLocking()) {
1392: OptimisticLockingPolicy policy = getDescriptor()
1393: .getOptimisticLockingPolicy();
1394: policy.addLockValuesToTranslationRow(writeQuery);
1395:
1396: // update the row with newer lock value
1397: policy.updateRowAndObjectForUpdate(writeQuery, object);
1398: }
1399:
1400: // PERF: Avoid events if no listeners.
1401: if (getDescriptor().getEventManager()
1402: .hasAnyEventListeners()) {
1403: DescriptorEvent event = new DescriptorEvent(
1404: DescriptorEventManager.AboutToUpdateEvent,
1405: writeQuery);
1406: event.setRecord(getModifyRow());
1407: getDescriptor().getEventManager().executeEvent(event);
1408: }
1409:
1410: int rowCount = updateObject().intValue();
1411:
1412: if (rowCount < 1) {
1413: getSession().getEventManager().noRowsModified(
1414: writeQuery, object);
1415: }
1416: if (getDescriptor().usesOptimisticLocking()) {
1417: getDescriptor().getOptimisticLockingPolicy()
1418: .validateUpdate(rowCount, object, writeQuery);
1419: }
1420: }
1421:
1422: getSession().getCommitManager().markPostModifyCommitInProgress(
1423: object);
1424:
1425: // Verify if deep shallow modify is turned on
1426: if (writeQuery.shouldCascadeParts()) {
1427: queryManager.postUpdate(writeQuery);
1428: }
1429:
1430: // PERF: Avoid events if no listeners.
1431: if (getDescriptor().getEventManager().hasAnyEventListeners()) {
1432: getDescriptor().getEventManager().executeEvent(
1433: new DescriptorEvent(
1434: DescriptorEventManager.PostUpdateEvent,
1435: writeQuery));
1436: }
1437: }
1438:
1439: /**
1440: * Update the object
1441: */
1442: public void updateObjectForWriteWithChangeSet() {
1443: WriteObjectQuery writeQuery = getWriteObjectQuery();
1444: Object object = writeQuery.getObject();
1445: DescriptorQueryManager queryManager = getDescriptor()
1446: .getQueryManager();
1447:
1448: // check for user-defined query
1449: if ((!writeQuery.isUserDefined())// this is not a user-defined query
1450: && queryManager.hasUpdateQuery()// there is a user-defined query
1451: && isExpressionQueryMechanism()) {// this is not a hand-coded call (custom SQL etc.)
1452: // THis must be done here because the userdefined updatedoes not use a changeset so it will noe be set otherwise
1453: getSession().getCommitManager()
1454: .markPreModifyCommitInProgress(
1455: writeQuery.getObjectChangeSet());
1456: performUserDefinedUpdate();
1457: return;
1458: }
1459:
1460: // This must be done after the custom query check, otherwise it will be done twice.
1461: getSession().getCommitManager().markPreModifyCommitInProgress(
1462: object);
1463: // This must be done after the custom query check, otherwise it will be done twice.
1464: getSession().getCommitManager().markPreModifyCommitInProgress(
1465: writeQuery.getObjectChangeSet());
1466:
1467: if (writeQuery.getObjectChangeSet().hasChanges()) {
1468: // PERF: Avoid events if no listeners.
1469: if (getDescriptor().getEventManager()
1470: .hasAnyEventListeners()) {
1471: DescriptorEvent event = new DescriptorEvent(
1472: DescriptorEventManager.PreUpdateWithChangesEvent,
1473: writeQuery);
1474: getDescriptor().getEventManager().executeEvent(event);
1475:
1476: // PreUpdateWithChangesEvent listeners may have altered the object - should recalculate the change set.
1477: UnitOfWorkChangeSet uowChangeSet = (oracle.toplink.essentials.internal.sessions.UnitOfWorkChangeSet) ((UnitOfWorkImpl) writeQuery
1478: .getSession()).getUnitOfWorkChangeSet();
1479: // writeQuery.getObjectChangeSet() is mapped to object in uowChangeSet.
1480: // It is first cleared then re-populated by calculateChanges method.
1481: writeQuery.getObjectChangeSet().clear();
1482: if (writeQuery.getDescriptor().getObjectChangePolicy()
1483: .calculateChanges(
1484: object,
1485: ((UnitOfWorkImpl) event.getSession())
1486: .getBackupClone(object),
1487: uowChangeSet, writeQuery.getSession(),
1488: writeQuery.getDescriptor(), false) == null) {
1489: // calculateChanges returns null in case the changeSet doesn't have changes.
1490: // It should be removed from the list of ObjectChangeSets that have changes in uowChangeSet.
1491: uowChangeSet.getAllChangeSets().remove(
1492: writeQuery.getObjectChangeSet());
1493: }
1494: }
1495: }
1496:
1497: // Verify if deep shallow modify is turned on
1498: if (writeQuery.shouldCascadeParts()) {
1499: queryManager.preUpdate(writeQuery);
1500: }
1501:
1502: // The row must not be built until after preUpdate in case the object reference has changed.
1503: // For a user defined update in the uow to row must be built twice to check if any update is required.
1504: writeQuery.setModifyRow(getDescriptor().getObjectBuilder()
1505: .buildRowForUpdateWithChangeSet(writeQuery));
1506:
1507: Boolean shouldModifyVersionField = writeQuery
1508: .getObjectChangeSet().shouldModifyVersionField();
1509:
1510: if (!getModifyRow().isEmpty()
1511: || (shouldModifyVersionField != null)
1512: || writeQuery.getObjectChangeSet()
1513: .hasCmpPolicyForcedUpdate()) {
1514: // If user defined the entire row is required. Must not be built until change is known.
1515: if (writeQuery.isUserDefined() || writeQuery.isCallQuery()) {
1516: writeQuery.setModifyRow(getDescriptor()
1517: .getObjectBuilder().buildRow(object,
1518: getSession()));
1519: }
1520:
1521: // Update the write lock field if required
1522: if (getDescriptor().usesOptimisticLocking()) {
1523: OptimisticLockingPolicy policy = getDescriptor()
1524: .getOptimisticLockingPolicy();
1525: policy.addLockValuesToTranslationRow(writeQuery);
1526:
1527: if (!getModifyRow().isEmpty()
1528: || (shouldModifyVersionField.booleanValue() && policy instanceof VersionLockingPolicy)) {
1529: // update the row with newer lock value
1530: policy.updateRowAndObjectForUpdate(writeQuery,
1531: object);
1532: } else if (!shouldModifyVersionField.booleanValue()
1533: && policy instanceof VersionLockingPolicy) {
1534: ((VersionLockingPolicy) policy)
1535: .writeLockValueIntoRow(writeQuery, object);
1536: }
1537: }
1538:
1539: // PERF: Avoid events if no listeners.
1540: if (getDescriptor().getEventManager()
1541: .hasAnyEventListeners()) {
1542: DescriptorEvent event = new DescriptorEvent(
1543: DescriptorEventManager.AboutToUpdateEvent,
1544: writeQuery);
1545: event.setRecord(getModifyRow());
1546: getDescriptor().getEventManager().executeEvent(event);
1547: }
1548:
1549: int rowCount = updateObject().intValue();
1550:
1551: if (rowCount < 1) {
1552: getSession().getEventManager().noRowsModified(
1553: writeQuery, object);
1554: }
1555: if (getDescriptor().usesOptimisticLocking()) {
1556: getDescriptor().getOptimisticLockingPolicy()
1557: .validateUpdate(rowCount, object, writeQuery);
1558: }
1559: }
1560:
1561: getSession().getCommitManager().markPostModifyCommitInProgress(
1562: object);
1563: getSession().getCommitManager().markPostModifyCommitInProgress(
1564: writeQuery.getObjectChangeSet());
1565:
1566: // Verify if deep shallow modify is turned on
1567: if (writeQuery.shouldCascadeParts()) {
1568: queryManager.postUpdate(writeQuery);
1569: }
1570:
1571: // PERF: Avoid events if no listeners.
1572: if (getDescriptor().getEventManager().hasAnyEventListeners()) {
1573: getDescriptor().getEventManager().executeEvent(
1574: new DescriptorEvent(
1575: DescriptorEventManager.PostUpdateEvent,
1576: writeQuery));
1577: }
1578: }
1579: }
|