001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * // Copyright (c) 1998, 2007, Oracle. All rights reserved.
005: *
006: *
007: * The contents of this file are subject to the terms of either the GNU
008: * General Public License Version 2 only ("GPL") or the Common Development
009: * and Distribution License("CDDL") (collectively, the "License"). You
010: * may not use this file except in compliance with the License. You can obtain
011: * a copy of the License at https://glassfish.dev.java.net/public/CDDL+GPL.html
012: * or glassfish/bootstrap/legal/LICENSE.txt. See the License for the specific
013: * language governing permissions and limitations under the License.
014: *
015: * When distributing the software, include this License Header Notice in each
016: * file and include the License file at glassfish/bootstrap/legal/LICENSE.txt.
017: * Sun designates this particular file as subject to the "Classpath" exception
018: * as provided by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the License
020: * Header, with the fields enclosed by brackets [] replaced by your own
021: * identifying information: "Portions Copyrighted [year]
022: * [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * If you wish your version of this file to be governed by only the CDDL or
027: * only the GPL Version 2, indicate your decision by adding "[Contributor]
028: * elects to include this software in this distribution under the [CDDL or GPL
029: * Version 2] license." If you don't indicate a single choice of license, a
030: * recipient has the option to distribute your version of this file under
031: * either the CDDL, the GPL Version 2 or to extend the choice of license to
032: * its licensees as provided above. However, if you add GPL Version 2 code
033: * and therefore, elected the GPL Version 2 license, then the option applies
034: * only if the new code is made subject to such option by the copyright
035: * holder.
036: */
037: package oracle.toplink.essentials.queryframework;
038:
039: import java.util.*;
040: import oracle.toplink.essentials.internal.helper.*;
041: import oracle.toplink.essentials.internal.sessions.*;
042: import oracle.toplink.essentials.exceptions.*;
043: import oracle.toplink.essentials.internal.sessions.AbstractRecord;
044: import oracle.toplink.essentials.internal.sessions.UnitOfWorkImpl;
045: import oracle.toplink.essentials.internal.sessions.AbstractSession;
046: import oracle.toplink.essentials.descriptors.ClassDescriptor;
047:
048: /**
049: * <p><b>Purpose</b>:
050: * Abstract class for all object modify queries.
051: *
052: * <p><b>Responsibilities</b>:
053: * <ul>
054: * <li> Stores & retrieves the object to modify.
055: * <li> Stores & retrieves the primary key of the objects.
056: * </ul>
057: *
058: * @author Yvon Lavoie
059: * @since TOPLink/Java 1.0
060: */
061: public abstract class ObjectLevelModifyQuery extends ModifyQuery {
062:
063: /* Primary key of the object to be modified. */
064: protected Vector primaryKey;
065:
066: /* The object being modified. */
067: protected Object object;
068:
069: /* A changeSet representing the object being modified */
070: protected ObjectChangeSet objectChangeSet;
071:
072: /* The clone of the object being modified from unit of work. */
073: protected Object backupClone;
074:
075: /**
076: * PUBLIC:
077: * Initialize the state of the query.
078: */
079: public ObjectLevelModifyQuery() {
080: this .cascadePolicy = CascadePrivateParts;
081: }
082:
083: /**
084: * INTERNAL:
085: * Ensure that the descriptor has been set.
086: */
087: public void checkDescriptor(AbstractSession session)
088: throws QueryException {
089: if (getDescriptor() == null) {
090: if (getObject() == null) {
091: throw QueryException.objectToModifyNotSpecified(this );
092: }
093:
094: //Bug#3947714 Pass the object instead of class in case object is proxy
095: ClassDescriptor referenceDescriptor = session
096: .getDescriptor(getObject());
097: if (referenceDescriptor == null) {
098: throw QueryException.descriptorIsMissing(getObject()
099: .getClass(), this );
100: }
101: setDescriptor(referenceDescriptor);
102: }
103: }
104:
105: /**
106: * INTERNAL:
107: * All have done is move code from UnitOfWork.internalExecuteQuery
108: */
109: public Object executeInUnitOfWork(UnitOfWorkImpl unitOfWork,
110: AbstractRecord translationRow) throws DatabaseException {
111: if (unitOfWork.isAfterWriteChangesButBeforeCommit()) {
112: throw ValidationException
113: .illegalOperationForUnitOfWorkLifecycle(unitOfWork
114: .getLifecycle(),
115: "executeQuery(ObjectLevelModifyQuery)");
116: }
117: return executeInUnitOfWorkObjectLevelModifyQuery(unitOfWork,
118: translationRow);
119: }
120:
121: /**
122: * INTERNAL:
123: * This code was moved from UnitOfWork.internalExecuteQuery
124: * @param unitOfWork
125: * @param translationRow
126: * @return
127: * @throws oracle.toplink.essentials.exceptions.DatabaseException
128: * @throws oracle.toplink.essentials.exceptions.OptimisticLockException
129: */
130: protected Object executeInUnitOfWorkObjectLevelModifyQuery(
131: UnitOfWorkImpl unitOfWork, AbstractRecord translationRow)
132: throws DatabaseException, OptimisticLockException {
133: if (!unitOfWork.getCommitManager().isActive()) {
134: throw QueryException.invalidQuery(this );
135: }
136:
137: if ((getObject() != null)
138: && (unitOfWork.isClassReadOnly(getObject().getClass()))) {
139: return getObject();
140: }
141:
142: // CR#3216 - Apply check to ObjectLevelModifyQuery not just WriteObjectQuery
143: if (unitOfWork.shouldPerformNoValidation()
144: && unitOfWork.getUnregisteredExistingObjects()
145: .containsKey(getObject())) {
146: //if the object is an unregistered existing object then skip it. This
147: // Will only be in the collection if validation is turned off
148: return null;
149: }
150:
151: return super .executeInUnitOfWork(unitOfWork, translationRow);
152: }
153:
154: /**
155: * INTERNAL:
156: * Return the backup clone of the object from the unit of work.
157: */
158: public Object getBackupClone() {
159: // PERF: A backup clone is only required for the old commit,
160: // So avoid its creation for normal commit.
161: if ((backupClone == null) && getSession().isUnitOfWork()) {
162: setBackupClone(((UnitOfWorkImpl) getSession())
163: .getBackupCloneForCommit(getObject()));
164: }
165: return backupClone;
166: }
167:
168: /**
169: * PUBLIC:
170: * Return the object required for modification.
171: */
172: public Object getObject() {
173: return object;
174: }
175:
176: /**
177: * PUBLIC:
178: * Return the ObjectChangeSet representing the object being changed
179: */
180: public ObjectChangeSet getObjectChangeSet() {
181: return this .objectChangeSet;
182: }
183:
184: /**
185: * INTERNAL:
186: * Get the primary key for the query
187: */
188: public Vector getPrimaryKey() {
189: return primaryKey;
190: }
191:
192: /**
193: * Return the domain class associated with this query.
194: */
195: public Class getReferenceClass() {
196: return getObject().getClass();
197: }
198:
199: /**
200: * INTERNAL:
201: * Return the reference class for a query
202: * Note: Although the API is designed to avoid classpath dependancies for the MW, since the object
203: * is specified at runtime, this will not be an issue.
204: */
205: public String getReferenceClassName() {
206: return getReferenceClass().getName();
207: }
208:
209: /**
210: * PUBLIC:
211: * Return if this is an object level modify query.
212: */
213: public boolean isObjectLevelModifyQuery() {
214: return true;
215: }
216:
217: /**
218: * INTERNAL:
219: * Prepare the receiver for execution in a session.
220: * In particular check that the tables on the descriptor are set.
221: */
222: protected void prepare() throws QueryException {
223: checkDescriptor(getSession());
224:
225: if (getObject() != null) {// Prepare can be called without the object set yet.
226: setObject(getDescriptor().getObjectBuilder().unwrapObject(
227: getObject(), getSession()));
228: }
229:
230: if (getDescriptor().isAggregateDescriptor()) {
231: throw QueryException
232: .aggregateObjectCannotBeDeletedOrWritten(
233: getDescriptor(), this );
234: }
235:
236: super .prepare();
237: }
238:
239: /**
240: * INTERNAL:
241: * Prepare the receiver for execution in a session.
242: * In particular check that the tables on the descriptor are set.
243: */
244: public void prepareForExecution() throws QueryException {
245: super .prepareForExecution();
246:
247: if (getObject() == null) {
248: throw QueryException.objectToModifyNotSpecified(this );
249: }
250:
251: setObject(getDescriptor().getObjectBuilder().unwrapObject(
252: getObject(), getSession()));
253:
254: if (getPrimaryKey() == null) {
255: if (getObjectChangeSet() != null) {
256: setPrimaryKey(getObjectChangeSet().getPrimaryKeys());
257: } else {
258: setPrimaryKey(getSession().keyFromObject(getObject()));
259: }
260: }
261: }
262:
263: /**
264: * INTERNAL:
265: * Set the backup clone of the object from the unit of work.
266: */
267: public void setBackupClone(Object backupClone) {
268: this .backupClone = backupClone;
269: }
270:
271: /**
272: * PUBLIC (REQUIRED):
273: * Set the object required for modification.
274: */
275: public void setObject(Object object) {
276: this .object = object;
277: }
278:
279: /**
280: * INTERNAL:
281: * Set the ObjectChangeSet representing the object to be written
282: */
283: public void setObjectChangeSet(ObjectChangeSet changeSet) {
284: this .objectChangeSet = changeSet;
285: }
286:
287: /**
288: * INTERNAL:
289: * Set the primary key for the query.
290: */
291: public void setPrimaryKey(Vector primaryKey) {
292: this .primaryKey = primaryKey;
293: }
294:
295: public String toString() {
296: return Helper.getShortClassName(getClass()) + "("
297: + String.valueOf(getObject()) + ")";
298: }
299: }
|