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.Vector;
040: import oracle.toplink.essentials.exceptions.*;
041: import oracle.toplink.essentials.expressions.*;
042: import oracle.toplink.essentials.internal.queryframework.DatabaseQueryMechanism;
043: import oracle.toplink.essentials.internal.queryframework.ExpressionQueryMechanism;
044: import oracle.toplink.essentials.internal.sessions.AbstractRecord;
045: import oracle.toplink.essentials.internal.sessions.UnitOfWorkImpl;
046: import oracle.toplink.essentials.internal.sessions.AbstractSession;
047:
048: /**
049: * PUBLIC:
050: * Query used to perform a bulk delete using TopLink's expression framework.
051: *
052: * @author Andrei Ilitchev
053: * @date August 18, 2005
054: */
055: public abstract class ModifyAllQuery extends ModifyQuery {
056:
057: /** Cache usage flags */
058: public static final int NO_CACHE = 0;
059: public static final int INVALIDATE_CACHE = 1;
060:
061: private int m_cacheUsage = INVALIDATE_CACHE;
062:
063: protected Class referenceClass;
064: protected String referenceClassName;
065:
066: /** Number of modified objects */
067: protected transient Integer result;
068:
069: /** Indicates whether execution should be deferred in UOW */
070: private boolean shouldDeferExecutionInUOW;
071:
072: /** Provide a default builder so that it's easier to be consistent */
073: protected ExpressionBuilder defaultBuilder;
074:
075: /** Indicates whether the query was prepared so that it will execute using temp storage */
076: protected boolean isPreparedUsingTempStorage;
077:
078: /**
079: * PUBLIC:
080: */
081: public ModifyAllQuery() {
082: super ();
083: shouldDeferExecutionInUOW = true;
084: }
085:
086: /**
087: * PUBLIC:
088: * Create a new update all query for the class specified.
089: */
090: public ModifyAllQuery(Class referenceClass) {
091: this ();
092: setReferenceClass(referenceClass);
093: }
094:
095: /**
096: * PUBLIC:
097: * Create a new update all query for the class and the selection criteria
098: * specified.
099: */
100: public ModifyAllQuery(Class referenceClass,
101: Expression selectionCriteria) {
102: this ();
103: setReferenceClass(referenceClass);
104: setSelectionCriteria(selectionCriteria);
105: }
106:
107: /**
108: * PUBLIC:
109: * Return true if this is a modify query.
110: */
111: public boolean isModifyQuery() {
112: return true;
113: }
114:
115: /**
116: * INTERNAL:
117: */
118: public void setIsPreparedUsingTempStorage(
119: boolean isPreparedUsingTempStorage) {
120: this .isPreparedUsingTempStorage = isPreparedUsingTempStorage;
121: }
122:
123: /**
124: * INTERNAL:
125: */
126: public boolean isPreparedUsingTempStorage() {
127: return isPreparedUsingTempStorage;
128: }
129:
130: /**
131: * INTERNAL
132: * Used to give the subclasses oportunity to copy aspects of the cloned query
133: * to the original query. The clones of all the ModifyAllQueries will be added to modifyAllQueries for validation.
134: */
135: protected void clonedQueryExecutionComplete(DatabaseQuery query,
136: AbstractSession session) {
137: super .clonedQueryExecutionComplete(query, session);
138:
139: if (session.isUnitOfWork()) {
140: ((UnitOfWorkImpl) session).storeModifyAllQuery(query);
141: }
142: }
143:
144: /**
145: * INTERNAL:
146: * Override query execution where Session is a UnitOfWork.
147: * <p>
148: * If there are objects in the cache return the results of the cache lookup.
149: *
150: * @param unitOfWork - the session in which the receiver will be executed.
151: * @param translationRow - the arguments
152: * @exception DatabaseException - an error has occurred on the database.
153: * @exception OptimisticLockException - an error has occurred using the optimistic lock feature.
154: * @return An object, the result of executing the query.
155: */
156: public Object executeInUnitOfWork(UnitOfWorkImpl unitOfWork,
157: AbstractRecord translationRow) throws DatabaseException,
158: OptimisticLockException {
159: if (unitOfWork.isNestedUnitOfWork()) {
160: throw ValidationException
161: .nestedUOWNotSupportedForModifyAllQuery();
162: }
163:
164: //Bug4607551 For UpdateAllQuery, if deferred, add the original query with a translation row to the deferredUpdateAllQueries for execution.
165: //No action for non-deferred. Later on the clones of all the UpdateAllQuery's will be added to modifyAllQueries for validation.
166: if (shouldDeferExecutionInUOW()) {
167: unitOfWork
168: .storeDeferredModifyAllQuery(this , translationRow);
169: result = null;
170: } else {
171: if (!unitOfWork.isInTransaction()) {
172: unitOfWork.beginEarlyTransaction();
173: }
174: unitOfWork.setWasNonObjectLevelModifyQueryExecuted(true);
175: result = (Integer) super .executeInUnitOfWork(unitOfWork,
176: translationRow);
177: }
178: return result;
179: }
180:
181: /**
182: * PUBLIC:
183: * Return the cache usage for this query.
184: */
185: public int getCacheUsage() {
186: return m_cacheUsage;
187: }
188:
189: /**
190: * PUBLIC:
191: * Get the expression builder which should be used for this query.
192: * This expression builder should be used to build all expressions used by this query.
193: */
194: public ExpressionBuilder getExpressionBuilder() {
195: if (defaultBuilder == null) {
196: initializeDefaultBuilder();
197: }
198:
199: return defaultBuilder;
200: }
201:
202: /**
203: * INTERNAL
204: * Sets the default expression builder for this query.
205: */
206: public void setExpressionBuilder(ExpressionBuilder builder) {
207: this .defaultBuilder = builder;
208: }
209:
210: /**
211: * INTERNAL:
212: * Return the name of the reference class of the query.
213: * Used by the Mappign Workbench to avoid classpath dependancies
214: */
215: public String getReferenceClassName() {
216: if ((referenceClassName == null) && (referenceClass != null)) {
217: referenceClassName = referenceClass.getName();
218: }
219: return referenceClassName;
220: }
221:
222: /**
223: * PUBLIC:
224: * Return the reference class for this query.
225: */
226: public Class getReferenceClass() {
227: return referenceClass;
228: }
229:
230: /**
231: * INTERNAL:
232: * Invalid the cache, that is, those objects in the cache that were affected
233: * by the query.
234: */
235: protected void invalidateCache() {
236: oracle.toplink.essentials.sessions.IdentityMapAccessor identityMapAccessor = getSession()
237: .getIdentityMapAccessor();
238: if (getSelectionCriteria() == null) {
239: // Invalidate the whole class since the user did not specify a where clause
240: if (getDescriptor().isChildDescriptor()) {
241: Vector collectionToInvalidate = identityMapAccessor
242: .getAllFromIdentityMap(null,
243: getReferenceClass(),
244: getTranslationRow(), null);
245: identityMapAccessor
246: .invalidateObjects(collectionToInvalidate);
247: } else {
248: // if it's either a root class or there is no inheritance just clear the identity map
249: identityMapAccessor
250: .invalidateClass(getReferenceClass());
251: }
252: } else {
253: // Invalidate only those objects in the cache that match the selection criteria
254: //Bug:4293920, expression parameters were not passed in
255: boolean noObjectsModifiedInDb = result != null
256: && result.intValue() == 0;
257: try {
258: InMemoryQueryIndirectionPolicy policy = new InMemoryQueryIndirectionPolicy();
259: if (noObjectsModifiedInDb) {
260: policy
261: .ignoreIndirectionExceptionReturnNotConformed();
262: } else {
263: policy.ignoreIndirectionExceptionReturnConformed();
264: }
265: Vector collectionToInvalidate = identityMapAccessor
266: .getAllFromIdentityMap(getSelectionCriteria(),
267: getReferenceClass(),
268: getTranslationRow(), policy);
269: identityMapAccessor
270: .invalidateObjects(collectionToInvalidate);
271: } catch (QueryException ex) {
272: if (ex.getErrorCode() == QueryException.CANNOT_CONFORM_EXPRESSION) {
273: // If no objects changed in the db - don't invalidate, ignore.
274: if (!noObjectsModifiedInDb) {
275: // Invalidate the whole class since the expression can't be selected in memory
276: identityMapAccessor
277: .invalidateClass(getReferenceClass());
278: }
279: } else {
280: throw ex;
281: }
282: }
283: }
284: }
285:
286: /**
287: * INTERNAL:
288: * After execution we need to merge the changes into the shared cache
289: */
290: public void mergeChangesIntoSharedCache() {
291: if (shouldInvalidateCache()) {
292: invalidateCache();
293: }
294: }
295:
296: /**
297: * PUBLIC:
298: * Set the level of cache support for this query, either NONE or INVALIDATE.
299: */
300: public void setCacheUsage(int cacheUsage) {
301: m_cacheUsage = cacheUsage;
302: }
303:
304: /**
305: * PUBLIC:
306: * Set the reference class this query.
307: */
308: public void setReferenceClass(Class referenceClass) {
309: if (this .referenceClass != referenceClass) {
310: setIsPrepared(false);
311: }
312: this .referenceClass = referenceClass;
313: }
314:
315: /**
316: * INTERNAL:
317: * Set the class name of the reference class of this query.
318: * Used by the Mapping Workbench to avoid classpath dependancies.
319: */
320: public void setReferenceClassName(String className) {
321: referenceClassName = className;
322: }
323:
324: /**
325: * PUBLIC:
326: * Set a flag indicating whether execution should be deferred in UOW until commit.
327: */
328: public void setShouldDeferExecutionInUOW(
329: boolean shouldDeferExecutionInUOW) {
330: this .shouldDeferExecutionInUOW = shouldDeferExecutionInUOW;
331: }
332:
333: /**
334: * PUBLIC:
335: * Indicates whether execution should be deferred in UOW until commit.
336: */
337: public boolean shouldDeferExecutionInUOW() {
338: return shouldDeferExecutionInUOW;
339: }
340:
341: /**
342: * INTERNAL:
343: */
344: protected boolean shouldInvalidateCache() {
345: return m_cacheUsage == INVALIDATE_CACHE;
346: }
347:
348: /**
349: * INTERNAL:
350: * Initialize the expression builder which should be used for this query. If
351: * there is a where clause, use its expression builder, otherwise
352: * generate one and cache it. This helps avoid unnecessary rebuilds.
353: */
354: protected void initializeDefaultBuilder() {
355: initializeQuerySpecificDefaultBuilder();
356: if (defaultBuilder == null) {
357: defaultBuilder = new ExpressionBuilder();
358: }
359: }
360:
361: /**
362: * INTERNAL:
363: * Initialize the expression builder which should be used for this query. If
364: * there is a where clause, use its expression builder.
365: * If after this method defaultBuilder is still null,
366: * then initializeDefaultBuilder method will generate and cache it.
367: */
368: protected void initializeQuerySpecificDefaultBuilder() {
369: DatabaseQueryMechanism mech = getQueryMechanism();
370: if (mech.isExpressionQueryMechanism()
371: && ((ExpressionQueryMechanism) mech)
372: .getExpressionBuilder() != null) {
373: this .defaultBuilder = ((ExpressionQueryMechanism) mech)
374: .getExpressionBuilder();
375: }
376: }
377: }
|