KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > objectstyle > cayenne > access > util > BatchQueryUtils


1 /* ====================================================================
2  *
3  * The ObjectStyle Group Software License, version 1.1
4  * ObjectStyle Group - http://objectstyle.org/
5  *
6  * Copyright (c) 2002-2005, Andrei (Andrus) Adamchik and individual authors
7  * of the software. All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  *
13  * 1. Redistributions of source code must retain the above copyright
14  * notice, this list of conditions and the following disclaimer.
15  *
16  * 2. Redistributions in binary form must reproduce the above copyright
17  * notice, this list of conditions and the following disclaimer in
18  * the documentation and/or other materials provided with the
19  * distribution.
20  *
21  * 3. The end-user documentation included with the redistribution, if any,
22  * must include the following acknowlegement:
23  * "This product includes software developed by independent contributors
24  * and hosted on ObjectStyle Group web site (http://objectstyle.org/)."
25  * Alternately, this acknowlegement may appear in the software itself,
26  * if and wherever such third-party acknowlegements normally appear.
27  *
28  * 4. The names "ObjectStyle Group" and "Cayenne" must not be used to endorse
29  * or promote products derived from this software without prior written
30  * permission. For written permission, email
31  * "andrus at objectstyle dot org".
32  *
33  * 5. Products derived from this software may not be called "ObjectStyle"
34  * or "Cayenne", nor may "ObjectStyle" or "Cayenne" appear in their
35  * names without prior written permission.
36  *
37  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
38  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
39  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
40  * DISCLAIMED. IN NO EVENT SHALL THE OBJECTSTYLE GROUP OR
41  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
42  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
43  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
44  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
45  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
46  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
47  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
48  * SUCH DAMAGE.
49  * ====================================================================
50  *
51  * This software consists of voluntary contributions made by many
52  * individuals and hosted on ObjectStyle Group web site. For more
53  * information on the ObjectStyle Group, please see
54  * <http://objectstyle.org/>.
55  */

56
57 package org.objectstyle.cayenne.access.util;
58
59 import java.sql.Types JavaDoc;
60 import java.util.Collections JavaDoc;
61 import java.util.HashMap JavaDoc;
62 import java.util.Iterator JavaDoc;
63 import java.util.List JavaDoc;
64 import java.util.Map JavaDoc;
65
66 import org.apache.commons.collections.Factory;
67 import org.objectstyle.cayenne.CayenneRuntimeException;
68 import org.objectstyle.cayenne.DataObject;
69 import org.objectstyle.cayenne.DataRow;
70 import org.objectstyle.cayenne.ObjectId;
71 import org.objectstyle.cayenne.access.DataContext;
72 import org.objectstyle.cayenne.map.DbAttribute;
73 import org.objectstyle.cayenne.map.DbJoin;
74 import org.objectstyle.cayenne.map.DbRelationship;
75 import org.objectstyle.cayenne.map.Entity;
76 import org.objectstyle.cayenne.map.ObjAttribute;
77 import org.objectstyle.cayenne.map.ObjEntity;
78 import org.objectstyle.cayenne.map.ObjRelationship;
79 import org.objectstyle.cayenne.query.BatchQuery;
80 import org.objectstyle.cayenne.query.InsertBatchQuery;
81 import org.objectstyle.cayenne.query.UpdateBatchQuery;
82 import org.objectstyle.cayenne.util.Util;
83
84 /**
85  * Collection of utility methods to work with BatchQueries.
86  *
87  * @author Andriy Shapochka
88  */

89 public class BatchQueryUtils {
90
91     private BatchQueryUtils() {
92     }
93
94     /**
95      * Utility method that returns <code>true</code> if the query will update at least
96      * one BLOB or CLOB DbAttribute.
97      */

98     public static boolean updatesLOBColumns(BatchQuery query) {
99         boolean isInsert = query instanceof InsertBatchQuery;
100         boolean isUpdate = query instanceof UpdateBatchQuery;
101
102         if (!isInsert && !isUpdate) {
103             return false;
104         }
105
106         List JavaDoc updatedAttributes = (isInsert)
107                 ? query.getDbAttributes()
108                 : ((UpdateBatchQuery) query).getUpdatedAttributes();
109
110         Iterator JavaDoc it = updatedAttributes.iterator();
111         while (it.hasNext()) {
112             int type = ((DbAttribute) it.next()).getType();
113             if (type == Types.CLOB || type == Types.BLOB) {
114                 return true;
115             }
116         }
117
118         return false;
119     }
120
121     public static Map JavaDoc buildSnapshotForUpdate(DataObject o) {
122         DataContext context = o.getDataContext();
123         Map JavaDoc committedSnapshot = context.getObjectStore().getSnapshot(
124                 o.getObjectId(),
125                 context);
126         Map JavaDoc currentSnapshot = o.getDataContext().currentSnapshot(o);
127         Map JavaDoc snapshot = null;
128
129         if (committedSnapshot == null || committedSnapshot.isEmpty()) {
130             snapshot = Collections.unmodifiableMap(currentSnapshot);
131             return snapshot;
132         }
133         else
134             snapshot = new HashMap JavaDoc(currentSnapshot.size());
135
136         Iterator JavaDoc it = currentSnapshot.entrySet().iterator();
137         while (it.hasNext()) {
138             Map.Entry JavaDoc entry = (Map.Entry JavaDoc) it.next();
139             String JavaDoc attrName = (String JavaDoc) entry.getKey();
140             Object JavaDoc newValue = entry.getValue();
141             // if snapshot exists, compare old values and new values,
142
// only add attribute to the update clause if the value has changed
143
Object JavaDoc oldValue = committedSnapshot.get(attrName);
144             if (!Util.nullSafeEquals(oldValue, newValue))
145                 snapshot.put(attrName, newValue);
146         }
147
148         // original snapshot can have extra keys that are missing in current snapshot
149
// process those
150
Iterator JavaDoc origit = committedSnapshot.entrySet().iterator();
151         while (origit.hasNext()) {
152             Map.Entry JavaDoc entry = (Map.Entry JavaDoc) origit.next();
153             String JavaDoc attrName = (String JavaDoc) entry.getKey();
154             Object JavaDoc oldValue = entry.getValue();
155             if (oldValue == null || currentSnapshot.containsKey(attrName))
156                 continue;
157             snapshot.put(attrName, null);
158         }
159
160         return Collections.unmodifiableMap(snapshot);
161     }
162
163     /**
164      * Creates a snapshot of inserted columns for a given object.
165      *
166      * @deprecated since 1.2
167      */

168     public static Map JavaDoc buildSnapshotForInsert(
169             ObjEntity entity,
170             DataObject o,
171             DbRelationship masterDependentRel) {
172         return buildSnapshotForInsert(entity, o, masterDependentRel, false);
173     }
174
175     /**
176      * Creates a snapshot of inserted columns for a given object. Supports deferring value
177      * resolution by setting adding factories to the snapshot instead of rela values if
178      * the value is not known yet.
179      *
180      * @since 1.2
181      */

182     public static Map JavaDoc buildSnapshotForInsert(
183             ObjEntity entity,
184             DataObject o,
185             DbRelationship masterDependentRel,
186             boolean supportsGeneratedKeys) {
187
188         boolean isMasterDbEntity = (masterDependentRel == null);
189         Map JavaDoc map = new HashMap JavaDoc();
190
191         // add object attributes
192
Map JavaDoc attrMap = entity.getAttributeMap();
193         Iterator JavaDoc attributes = attrMap.entrySet().iterator();
194         while (attributes.hasNext()) {
195             Map.Entry JavaDoc entry = (Map.Entry JavaDoc) attributes.next();
196             String JavaDoc attrName = (String JavaDoc) entry.getKey();
197             ObjAttribute objAttr = (ObjAttribute) entry.getValue();
198
199             if (isMasterDbEntity && !objAttr.isCompound()) {
200                 map.put(objAttr.getDbAttributePath(), o.readPropertyDirectly(attrName));
201             }
202             else if (!isMasterDbEntity && objAttr.isCompound()) {
203                 DbAttribute dbAttr = objAttr.getDbAttribute();
204                 if (dbAttr.getEntity() == masterDependentRel.getTargetEntity())
205                     map.put(dbAttr.getName(), o.readPropertyDirectly(attrName));
206             }
207         }
208
209         // infer keys from relationships
210
Map JavaDoc relMap = entity.getRelationshipMap();
211         Iterator JavaDoc relationships = relMap.entrySet().iterator();
212         while (relationships.hasNext()) {
213
214             Map.Entry JavaDoc entry = (Map.Entry JavaDoc) relationships.next();
215             String JavaDoc relName = (String JavaDoc) entry.getKey();
216             ObjRelationship rel = (ObjRelationship) entry.getValue();
217
218             if (rel.isSourceIndependentFromTargetChange()) {
219                 continue;
220             }
221
222             DataObject target = (DataObject) o.readPropertyDirectly(relName);
223             if (target == null) {
224                 continue;
225             }
226
227             Map JavaDoc targetKeyMap = target.getObjectId().getIdSnapshot();
228
229             // this may happen in uncommitted objects
230
if (targetKeyMap == null) {
231                 continue;
232             }
233
234             DbRelationship dbRel;
235             if (isMasterDbEntity) {
236                 dbRel = (DbRelationship) rel.getDbRelationships().get(0);
237             }
238             else {
239                 dbRel = (DbRelationship) rel.getDbRelationships().get(1);
240                 if (dbRel.getSourceEntity() != masterDependentRel.getTargetEntity()) {
241                     continue;
242                 }
243             }
244
245             // support deferred propagated values...
246
// stick a Factory in the snapshot if the value is not available yet.
247
Iterator JavaDoc joins = dbRel.getJoins().iterator();
248             while (joins.hasNext()) {
249                 DbJoin join = (DbJoin) joins.next();
250                 Object JavaDoc value = targetKeyMap.get(join.getTargetName());
251                 if (value == null) {
252                     if (supportsGeneratedKeys && join.getTarget().isGenerated()) {
253                         // setup a factory
254
value = new PropagatedValueFactory(target.getObjectId(), join
255                                 .getTargetName());
256                     }
257                     else {
258                         throw new CayenneRuntimeException(
259                                 "Some parts of FK are missing in snapshot, join: " + join);
260                     }
261                 }
262
263                 map.put(join.getSourceName(), value);
264             }
265         }
266
267         // process object id map
268
// we should ignore any object id values if a corresponding attribute
269
// is a part of relationship "toMasterPK", since those values have been
270
// set above when db relationships where processed.
271
Map JavaDoc thisIdParts = o.getObjectId().getIdSnapshot();
272         if (thisIdParts != null) {
273             if (!isMasterDbEntity) {
274                 thisIdParts = masterDependentRel
275                         .targetPkSnapshotWithSrcSnapshot(thisIdParts);
276             }
277             // put only thise that do not exist in the map
278
Iterator JavaDoc itm = thisIdParts.keySet().iterator();
279             while (itm.hasNext()) {
280                 Object JavaDoc nextKey = itm.next();
281                 if (!map.containsKey(nextKey))
282                     map.put(nextKey, thisIdParts.get(nextKey));
283             }
284         }
285         return map;
286     }
287
288     private static String JavaDoc getTargetDbAttributeName(
289             String JavaDoc srcDbAttributeName,
290             DbRelationship masterDependentRel) {
291         for (Iterator JavaDoc i = masterDependentRel.getJoins().iterator(); i.hasNext();) {
292             DbJoin join = (DbJoin) i.next();
293             if (srcDbAttributeName.equals(join.getSourceName()))
294                 return join.getTargetName();
295         }
296         return null;
297     }
298
299     /**
300      * Creates a snapshot of updated columns for a given object.
301      */

302     public static Map JavaDoc buildSnapshotForUpdate(
303             ObjEntity entity,
304             DataObject o,
305             DbRelationship masterDependentRel) {
306
307         boolean isRootDbEntity = (masterDependentRel == null);
308         DataContext context = o.getDataContext();
309         DataRow committedSnapshot = context.getObjectStore().getSnapshot(
310                 o.getObjectId(),
311                 context);
312         DataRow currentSnapshot = o.getDataContext().currentSnapshot(o);
313         Map JavaDoc snapshot = new HashMap JavaDoc(currentSnapshot.size());
314
315         // no committed snapshot (why?) - just use values from current snapshot
316
if (committedSnapshot == null || committedSnapshot.isEmpty()) {
317             Iterator JavaDoc i = currentSnapshot.entrySet().iterator();
318             while (i.hasNext()) {
319                 Map.Entry JavaDoc entry = (Map.Entry JavaDoc) i.next();
320                 String JavaDoc dbAttrPath = (String JavaDoc) entry.getKey();
321                 boolean compoundDbAttr = dbAttrPath.indexOf(Entity.PATH_SEPARATOR) > 0;
322                 Object JavaDoc newValue = entry.getValue();
323                 if (isRootDbEntity && !compoundDbAttr) {
324                     snapshot.put(dbAttrPath, newValue);
325                 }
326                 else if (!isRootDbEntity && compoundDbAttr) {
327                     Iterator JavaDoc pathIterator = entity.getDbEntity().resolvePathComponents(
328                             dbAttrPath);
329                     if (pathIterator.hasNext()
330                             && masterDependentRel.equals(pathIterator.next())) {
331                         DbAttribute dbAttr = (DbAttribute) pathIterator.next();
332                         snapshot.put(dbAttr.getName(), newValue);
333                     }
334                 }
335                 else if (!isRootDbEntity && !compoundDbAttr) {
336                     String JavaDoc pkAttrName = getTargetDbAttributeName(
337                             dbAttrPath,
338                             masterDependentRel);
339                     if (pkAttrName != null)
340                         snapshot.put(pkAttrName, newValue);
341                 }
342             }
343             return Collections.unmodifiableMap(snapshot);
344         }
345
346         Iterator JavaDoc it = currentSnapshot.entrySet().iterator();
347         while (it.hasNext()) {
348             Map.Entry JavaDoc entry = (Map.Entry JavaDoc) it.next();
349             String JavaDoc dbAttrPath = (String JavaDoc) entry.getKey();
350             boolean compoundDbAttr = dbAttrPath.indexOf(Entity.PATH_SEPARATOR) > 0;
351             Object JavaDoc newValue = entry.getValue();
352
353             // ... if not for flattened attributes, we could've used
354
// DataRow.createDiff()..
355

356             // if snapshot exists, compare old values and new values,
357
// only add attribute to the update clause if the value has changed
358
Object JavaDoc oldValue = committedSnapshot.get(dbAttrPath);
359             if (!Util.nullSafeEquals(oldValue, newValue)) {
360
361                 if (!isRootDbEntity) {
362                     if (compoundDbAttr) {
363                         Iterator JavaDoc pathIterator = entity
364                                 .getDbEntity()
365                                 .resolvePathComponents(dbAttrPath);
366                         if (pathIterator.hasNext()
367                                 && masterDependentRel.equals(pathIterator.next())) {
368                             DbAttribute dbAttr = (DbAttribute) pathIterator.next();
369                             snapshot.put(dbAttr.getName(), newValue);
370                         }
371                     }
372                     else {
373                         String JavaDoc pkAttrName = getTargetDbAttributeName(
374                                 dbAttrPath,
375                                 masterDependentRel);
376                         if (pkAttrName != null)
377                             snapshot.put(pkAttrName, newValue);
378                     }
379                 }
380                 else if (!compoundDbAttr) {
381                     snapshot.put(dbAttrPath, newValue);
382                 }
383             }
384         }
385
386         // original snapshot can have extra keys that are missing in current snapshot
387
// process those
388
Iterator JavaDoc origit = committedSnapshot.entrySet().iterator();
389         while (origit.hasNext()) {
390             Map.Entry JavaDoc entry = (Map.Entry JavaDoc) origit.next();
391             String JavaDoc dbAttrPath = (String JavaDoc) entry.getKey();
392             if (entry.getValue() == null || currentSnapshot.containsKey(dbAttrPath)) {
393                 continue;
394             }
395
396             boolean compoundDbAttr = dbAttrPath.indexOf(Entity.PATH_SEPARATOR) > 0;
397
398             if (isRootDbEntity && !compoundDbAttr) {
399                 snapshot.put(dbAttrPath, null);
400             }
401             else if (!isRootDbEntity && compoundDbAttr) {
402                 Iterator JavaDoc pathIterator = entity.getDbEntity().resolvePathComponents(
403                         dbAttrPath);
404                 if (pathIterator.hasNext()
405                         && masterDependentRel.equals(pathIterator.next())) {
406                     DbAttribute dbAttr = (DbAttribute) pathIterator.next();
407                     snapshot.put(dbAttr.getName(), null);
408                 }
409             }
410             else if (!isRootDbEntity && !compoundDbAttr) {
411                 String JavaDoc pkAttrName = getTargetDbAttributeName(
412                         dbAttrPath,
413                         masterDependentRel);
414                 if (pkAttrName != null)
415                     snapshot.put(pkAttrName, null);
416             }
417         }
418         return Collections.unmodifiableMap(snapshot);
419     }
420
421     final static class PropagatedValueFactory implements Factory {
422
423         ObjectId masterID;
424         String JavaDoc masterKey;
425
426         PropagatedValueFactory(ObjectId masterID, String JavaDoc masterKey) {
427             this.masterID = masterID;
428             this.masterKey = masterKey;
429         }
430
431         public Object JavaDoc create() {
432             if (!masterID.isReplacementIdAttached()) {
433                 throw new CayenneRuntimeException("Deferred propagated key ("
434                         + masterKey
435                         + ") wasn't generated for object with ID "
436                         + masterID);
437             }
438
439             Map JavaDoc replacementId = masterID.getReplacementIdMap();
440             Object JavaDoc value = replacementId.get(masterKey);
441             if (value == null) {
442                 throw new CayenneRuntimeException("Deferred propagated key ("
443                         + masterKey
444                         + ") wasn't generated for object with ID "
445                         + masterID);
446             }
447
448             return value;
449         }
450     }
451 }
Popular Tags