KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > objectstyle > cayenne > access > DataDomainCommitAction


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 package org.objectstyle.cayenne.access;
57
58 import java.util.ArrayList JavaDoc;
59 import java.util.Arrays JavaDoc;
60 import java.util.Collection JavaDoc;
61 import java.util.Collections JavaDoc;
62 import java.util.HashMap JavaDoc;
63 import java.util.HashSet JavaDoc;
64 import java.util.Iterator JavaDoc;
65 import java.util.List JavaDoc;
66 import java.util.Map JavaDoc;
67 import java.util.Set JavaDoc;
68
69 import org.apache.commons.collections.map.LinkedMap;
70 import org.objectstyle.cayenne.CayenneException;
71 import org.objectstyle.cayenne.CayenneRuntimeException;
72 import org.objectstyle.cayenne.DataObject;
73 import org.objectstyle.cayenne.ObjectContext;
74 import org.objectstyle.cayenne.ObjectId;
75 import org.objectstyle.cayenne.PersistenceState;
76 import org.objectstyle.cayenne.access.util.BatchQueryUtils;
77 import org.objectstyle.cayenne.access.util.PrimaryKeyHelper;
78 import org.objectstyle.cayenne.graph.GraphChangeHandler;
79 import org.objectstyle.cayenne.map.DbAttribute;
80 import org.objectstyle.cayenne.map.DbEntity;
81 import org.objectstyle.cayenne.map.DbJoin;
82 import org.objectstyle.cayenne.map.DbRelationship;
83 import org.objectstyle.cayenne.map.EntitySorter;
84 import org.objectstyle.cayenne.map.ObjAttribute;
85 import org.objectstyle.cayenne.map.ObjEntity;
86 import org.objectstyle.cayenne.map.ObjRelationship;
87 import org.objectstyle.cayenne.query.DeleteBatchQuery;
88 import org.objectstyle.cayenne.query.InsertBatchQuery;
89 import org.objectstyle.cayenne.query.Query;
90 import org.objectstyle.cayenne.query.UpdateBatchQuery;
91
92 /**
93  * A stateful commit operation invoked by DataDomain to commit changes in an
94  * ObjectContext.
95  *
96  * @since 1.2
97  * @author Andrus Adamchik
98  */

99
100 // Differences with DataContextCommitAction:
101
// * no synchronization on object store. Caller must do the right thing.
102
// * (!!!) no flattened relationships support, as it relied on the ObjectStore API... do
103
// something for ObjectContext (something smarter as it shouldn't care about "flattened"
104
// aspect)
105
// * DataDomain cache is used, so if a DataContext used a local cache, it can't use this
106
// action.
107
// * Currently doesn't support commit events
108
// * Doesn't change object store (there is no notion of ObjectStore anymore). Instead
109
// caller must do it.
110
// * There is no logging level overrides
111
class DataDomainCommitAction {
112
113     DataDomain domain;
114
115     Map JavaDoc newObjectsByObjEntity;
116     Map JavaDoc objectsToDeleteByObjEntity;
117     Map JavaDoc objectsToUpdateByObjEntity;
118     List JavaDoc objEntitiesToInsert;
119     List JavaDoc objEntitiesToDelete;
120     List JavaDoc objEntitiesToUpdate;
121     List JavaDoc nodeHelpers;
122
123     DataDomainCommitAction(DataDomain domain) {
124         this.domain = domain;
125     }
126
127     /**
128      * Commits changes in the enclosed DataContext.
129      */

130     void commit(ObjectContext context, GraphChangeHandler commitChangeCallback) {
131         synchronized (domain.getSharedSnapshotCache()) {
132             Collection JavaDoc uncommitted = context.uncommittedObjects();
133             categorizeObjects(uncommitted);
134             createPrimaryKeys();
135
136             for (Iterator JavaDoc i = nodeHelpers.iterator(); i.hasNext();) {
137                 DataNodeCommitAction nodeHelper = (DataNodeCommitAction) i.next();
138                 prepareInsertQueries(nodeHelper);
139                 prepareFlattenedQueries(nodeHelper, nodeHelper
140                         .getFlattenedInsertQueries());
141
142                 prepareUpdateQueries(nodeHelper);
143
144                 prepareFlattenedQueries(nodeHelper, nodeHelper
145                         .getFlattenedDeleteQueries());
146
147                 prepareDeleteQueries(nodeHelper);
148             }
149
150             OperationObserver observer = new DataDomainCommitObserver();
151             Transaction transaction = domain.createTransaction();
152
153             // TODO: should this line go inside try?
154
transaction.begin();
155
156             try {
157                 Iterator JavaDoc i = nodeHelpers.iterator();
158                 while (i.hasNext()) {
159                     DataNodeCommitAction nodeHelper = (DataNodeCommitAction) i.next();
160                     List JavaDoc queries = nodeHelper.getQueries();
161
162                     if (queries.size() > 0) {
163                         // note: observer throws on error
164
nodeHelper.getNode().performQueries(
165                                 queries,
166                                 observer,
167                                 transaction);
168                     }
169                 }
170
171                 // commit
172
transaction.commit();
173             }
174             catch (Throwable JavaDoc th) {
175                 try {
176                     // rollback
177
transaction.rollback();
178                 }
179                 catch (Throwable JavaDoc rollbackTh) {
180                     // ignoring...
181
}
182
183                 throw new CayenneRuntimeException("Transaction was rolledback.", th);
184             }
185
186             // notify callback of generated keys ...
187
if (commitChangeCallback != null) {
188                 Iterator JavaDoc it = uncommitted.iterator();
189                 while (it.hasNext()) {
190                     DataObject object = (DataObject) it.next();
191                     ObjectId id = object.getObjectId();
192                     if (id.isReplacementIdAttached()) {
193                         commitChangeCallback.nodeIdChanged(id, id.createReplacementId());
194                     }
195                 }
196             }
197         }
198     }
199
200     private void prepareInsertQueries(DataNodeCommitAction commitHelper) {
201
202         List JavaDoc entities = commitHelper.getObjEntitiesForInsert();
203         if (entities.isEmpty()) {
204             return;
205         }
206
207         boolean supportsGeneratedKeys = commitHelper
208                 .getNode()
209                 .getAdapter()
210                 .supportsGeneratedKeys();
211         List JavaDoc dbEntities = new ArrayList JavaDoc(entities.size());
212         Map JavaDoc objEntitiesByDbEntity = new HashMap JavaDoc(entities.size());
213         groupObjEntitiesBySpannedDbEntities(dbEntities, objEntitiesByDbEntity, entities);
214
215         EntitySorter sorter = commitHelper.getNode().getEntitySorter();
216         sorter.sortDbEntities(dbEntities, false);
217
218         Iterator JavaDoc i = dbEntities.iterator();
219         while (i.hasNext()) {
220             DbEntity dbEntity = (DbEntity) i.next();
221             List JavaDoc objEntitiesForDbEntity = (List JavaDoc) objEntitiesByDbEntity.get(dbEntity);
222
223             InsertBatchQuery batch = new InsertBatchQuery(dbEntity, 27);
224
225             for (Iterator JavaDoc j = objEntitiesForDbEntity.iterator(); j.hasNext();) {
226                 ObjEntity entity = (ObjEntity) j.next();
227                 boolean isMasterDbEntity = (entity.getDbEntity() == dbEntity);
228                 DbRelationship masterDependentDbRel = (isMasterDbEntity
229                         ? null
230                         : findMasterToDependentDbRelationship(
231                                 entity.getDbEntity(),
232                                 dbEntity));
233
234                 List JavaDoc objects = (List JavaDoc) newObjectsByObjEntity.get(entity.getClassName());
235
236                 // throw an exception - an attempt to modify read-only entity
237
if (entity.isReadOnly() && objects.size() > 0) {
238                     throw attemptToCommitReadOnlyEntity(objects.get(0).getClass(), entity);
239                 }
240
241                 if (isMasterDbEntity) {
242                     sorter.sortObjectsForEntity(entity, objects, false);
243                 }
244
245                 for (Iterator JavaDoc k = objects.iterator(); k.hasNext();) {
246                     DataObject o = (DataObject) k.next();
247                     Map JavaDoc snapshot = BatchQueryUtils.buildSnapshotForInsert(
248                             entity,
249                             o,
250                             masterDependentDbRel,
251                             supportsGeneratedKeys);
252                     batch.add(snapshot, o.getObjectId());
253                 }
254             }
255             commitHelper.getQueries().add(batch);
256         }
257     }
258
259     private void prepareDeleteQueries(DataNodeCommitAction commitHelper) {
260
261         List JavaDoc entities = commitHelper.getObjEntitiesForDelete();
262         if (entities.isEmpty()) {
263             return;
264         }
265
266         List JavaDoc dbEntities = new ArrayList JavaDoc(entities.size());
267         Map JavaDoc objEntitiesByDbEntity = new HashMap JavaDoc(entities.size());
268         groupObjEntitiesBySpannedDbEntities(dbEntities, objEntitiesByDbEntity, entities);
269
270         EntitySorter sorter = commitHelper.getNode().getEntitySorter();
271         sorter.sortDbEntities(dbEntities, true);
272
273         for (Iterator JavaDoc i = dbEntities.iterator(); i.hasNext();) {
274             DbEntity dbEntity = (DbEntity) i.next();
275             List JavaDoc objEntitiesForDbEntity = (List JavaDoc) objEntitiesByDbEntity.get(dbEntity);
276             Map JavaDoc batches = new LinkedMap();
277
278             for (Iterator JavaDoc j = objEntitiesForDbEntity.iterator(); j.hasNext();) {
279                 ObjEntity entity = (ObjEntity) j.next();
280
281                 // Per-objEntity optimistic locking conditional
282
boolean optimisticLocking = (ObjEntity.LOCK_TYPE_OPTIMISTIC == entity
283                         .getLockType());
284
285                 List JavaDoc qualifierAttributes = qualifierAttributes(entity, optimisticLocking);
286
287                 boolean isRootDbEntity = (entity.getDbEntity() == dbEntity);
288                 DbRelationship masterDependentDbRel = (isRootDbEntity
289                         ? null
290                         : findMasterToDependentDbRelationship(
291                                 entity.getDbEntity(),
292                                 dbEntity));
293
294                 List JavaDoc objects = (List JavaDoc) objectsToDeleteByObjEntity.get(entity
295                         .getClassName());
296
297                 // throw an exception - an attempt to delete read-only entity
298
if (entity.isReadOnly() && objects.size() > 0) {
299                     throw attemptToCommitReadOnlyEntity(objects.get(0).getClass(), entity);
300                 }
301
302                 if (isRootDbEntity) {
303                     sorter.sortObjectsForEntity(entity, objects, true);
304                 }
305
306                 for (Iterator JavaDoc k = objects.iterator(); k.hasNext();) {
307                     DataObject o = (DataObject) k.next();
308
309                     // build qualifier snapshot
310
Map JavaDoc idSnapshot = o.getObjectId().getIdSnapshot();
311
312                     if (idSnapshot == null || idSnapshot.isEmpty()) {
313                         // skip this one
314
continue;
315                     }
316
317                     if (!isRootDbEntity && masterDependentDbRel != null) {
318                         idSnapshot = masterDependentDbRel
319                                 .targetPkSnapshotWithSrcSnapshot(idSnapshot);
320                     }
321
322                     Map JavaDoc qualifierSnapshot = idSnapshot;
323                     if (optimisticLocking) {
324                         // clone snapshot and add extra keys...
325
qualifierSnapshot = new HashMap JavaDoc(qualifierSnapshot);
326                         appendOptimisticLockingAttributes(
327                                 qualifierSnapshot,
328                                 o,
329                                 qualifierAttributes);
330                     }
331
332                     // organize batches by the nulls in qualifier
333
Set JavaDoc nullQualifierNames = new HashSet JavaDoc();
334                     Iterator JavaDoc it = qualifierSnapshot.entrySet().iterator();
335                     while (it.hasNext()) {
336                         Map.Entry JavaDoc entry = (Map.Entry JavaDoc) it.next();
337                         if (entry.getValue() == null) {
338                             nullQualifierNames.add(entry.getKey());
339                         }
340                     }
341
342                     List JavaDoc batchKey = Arrays.asList(new Object JavaDoc[] {
343                         nullQualifierNames
344                     });
345
346                     DeleteBatchQuery batch = (DeleteBatchQuery) batches.get(batchKey);
347                     if (batch == null) {
348                         batch = new DeleteBatchQuery(
349                                 dbEntity,
350                                 qualifierAttributes,
351                                 nullQualifierNames,
352                                 27);
353
354                         batch.setUsingOptimisticLocking(optimisticLocking);
355                         batches.put(batchKey, batch);
356                     }
357
358                     batch.add(qualifierSnapshot);
359
360                 }
361             }
362             commitHelper.getQueries().addAll(batches.values());
363         }
364     }
365
366     private void prepareUpdateQueries(DataNodeCommitAction commitHelper) {
367         List JavaDoc entities = commitHelper.getObjEntitiesForUpdate();
368         if (entities.isEmpty()) {
369             return;
370         }
371
372         List JavaDoc dbEntities = new ArrayList JavaDoc(entities.size());
373         Map JavaDoc objEntitiesByDbEntity = new HashMap JavaDoc(entities.size());
374         groupObjEntitiesBySpannedDbEntities(dbEntities, objEntitiesByDbEntity, entities);
375
376         for (Iterator JavaDoc i = dbEntities.iterator(); i.hasNext();) {
377             DbEntity dbEntity = (DbEntity) i.next();
378             List JavaDoc objEntitiesForDbEntity = (List JavaDoc) objEntitiesByDbEntity.get(dbEntity);
379             Map JavaDoc batches = new LinkedMap();
380
381             for (Iterator JavaDoc j = objEntitiesForDbEntity.iterator(); j.hasNext();) {
382                 ObjEntity entity = (ObjEntity) j.next();
383
384                 // Per-objEntity optimistic locking conditional
385
boolean optimisticLocking = (ObjEntity.LOCK_TYPE_OPTIMISTIC == entity
386                         .getLockType());
387
388                 List JavaDoc qualifierAttributes = qualifierAttributes(entity, optimisticLocking);
389
390                 boolean isRootDbEntity = entity.getDbEntity() == dbEntity;
391
392                 DbRelationship masterDependentDbRel = (isRootDbEntity)
393                         ? null
394                         : findMasterToDependentDbRelationship(
395                                 entity.getDbEntity(),
396                                 dbEntity);
397                 List JavaDoc objects = (List JavaDoc) objectsToUpdateByObjEntity.get(entity
398                         .getClassName());
399
400                 for (Iterator JavaDoc k = objects.iterator(); k.hasNext();) {
401                     DataObject o = (DataObject) k.next();
402
403                     Map JavaDoc snapshot = BatchQueryUtils.buildSnapshotForUpdate(
404                             entity,
405                             o,
406                             masterDependentDbRel);
407
408                     // check whether MODIFIED object has real db-level
409
// modifications
410
if (snapshot.isEmpty()) {
411                         o.setPersistenceState(PersistenceState.COMMITTED);
412                         continue;
413                     }
414
415                     // after we filtered out "fake" modifications, check if an
416
// attempt is made to modify a read only entity
417
if (entity.isReadOnly()) {
418                         throw attemptToCommitReadOnlyEntity(o.getClass(), entity);
419                     }
420
421                     // build qualifier snapshot
422
Map JavaDoc idSnapshot = o.getObjectId().getIdSnapshot();
423
424                     if (!isRootDbEntity && masterDependentDbRel != null) {
425                         idSnapshot = masterDependentDbRel
426                                 .targetPkSnapshotWithSrcSnapshot(idSnapshot);
427                     }
428
429                     Map JavaDoc qualifierSnapshot = idSnapshot;
430                     if (optimisticLocking) {
431                         // clone snapshot and add extra keys...
432
qualifierSnapshot = new HashMap JavaDoc(qualifierSnapshot);
433                         appendOptimisticLockingAttributes(
434                                 qualifierSnapshot,
435                                 o,
436                                 qualifierAttributes);
437                     }
438
439                     // organize batches by the updated columns + nulls in qualifier
440
Set JavaDoc snapshotSet = snapshot.keySet();
441                     Set JavaDoc nullQualifierNames = new HashSet JavaDoc();
442                     Iterator JavaDoc it = qualifierSnapshot.entrySet().iterator();
443                     while (it.hasNext()) {
444                         Map.Entry JavaDoc entry = (Map.Entry JavaDoc) it.next();
445                         if (entry.getValue() == null) {
446                             nullQualifierNames.add(entry.getKey());
447                         }
448                     }
449
450                     List JavaDoc batchKey = Arrays.asList(new Object JavaDoc[] {
451                             snapshotSet, nullQualifierNames
452                     });
453
454                     UpdateBatchQuery batch = (UpdateBatchQuery) batches.get(batchKey);
455                     if (batch == null) {
456                         batch = new UpdateBatchQuery(
457                                 dbEntity,
458                                 qualifierAttributes,
459                                 updatedAttributes(dbEntity, snapshot),
460                                 nullQualifierNames,
461                                 10);
462
463                         batch.setUsingOptimisticLocking(optimisticLocking);
464                         batches.put(batchKey, batch);
465                     }
466
467                     batch.add(qualifierSnapshot, snapshot);
468
469                     if (isRootDbEntity) {
470                         updateId(
471                                 idSnapshot,
472                                 o.getObjectId().getReplacementIdMap(),
473                                 snapshot);
474                     }
475                 }
476             }
477             commitHelper.getQueries().addAll(batches.values());
478         }
479     }
480
481     /**
482      * Creates a list of DbAttributes that should be used in update WHERE clause.
483      */

484     private List JavaDoc qualifierAttributes(ObjEntity entity, boolean optimisticLocking) {
485         if (!optimisticLocking) {
486             return entity.getDbEntity().getPrimaryKey();
487         }
488
489         List JavaDoc attributes = new ArrayList JavaDoc(entity.getDbEntity().getPrimaryKey());
490
491         Iterator JavaDoc attributeIt = entity.getAttributes().iterator();
492         while (attributeIt.hasNext()) {
493             ObjAttribute attribute = (ObjAttribute) attributeIt.next();
494
495             if (attribute.isUsedForLocking()) {
496                 // only care about first step in a flattened attribute
497
DbAttribute dbAttribute = (DbAttribute) attribute
498                         .getDbPathIterator()
499                         .next();
500
501                 if (!attributes.contains(dbAttribute)) {
502                     attributes.add(dbAttribute);
503                 }
504             }
505         }
506
507         Iterator JavaDoc relationshipIt = entity.getRelationships().iterator();
508         while (relationshipIt.hasNext()) {
509             ObjRelationship relationship = (ObjRelationship) relationshipIt.next();
510
511             if (relationship.isUsedForLocking()) {
512                 // only care about the first DbRelationship
513
DbRelationship dbRelationship = (DbRelationship) relationship
514                         .getDbRelationships()
515                         .get(0);
516
517                 Iterator JavaDoc joinsIterator = dbRelationship.getJoins().iterator();
518                 while (joinsIterator.hasNext()) {
519                     DbJoin dbAttrPair = (DbJoin) joinsIterator.next();
520                     DbAttribute dbAttribute = dbAttrPair.getSource();
521                     if (!attributes.contains(dbAttribute)) {
522                         attributes.add(dbAttribute);
523                     }
524                 }
525             }
526         }
527
528         return attributes;
529     }
530
531     /**
532      * Creates a list of DbAttributes that are updated in a snapshot
533      *
534      * @param entity
535      * @return
536      */

537     private List JavaDoc updatedAttributes(DbEntity entity, Map JavaDoc updatedSnapshot) {
538         List JavaDoc attributes = new ArrayList JavaDoc(updatedSnapshot.size());
539         Map JavaDoc entityAttributes = entity.getAttributeMap();
540
541         Iterator JavaDoc it = updatedSnapshot.keySet().iterator();
542         while (it.hasNext()) {
543             Object JavaDoc name = it.next();
544             attributes.add(entityAttributes.get(name));
545         }
546
547         return attributes;
548     }
549
550     /**
551      * Appends values used for optimistic locking to a given snapshot.
552      */

553     private void appendOptimisticLockingAttributes(
554             Map JavaDoc qualifierSnapshot,
555             DataObject dataObject,
556             List JavaDoc qualifierAttributes) {
557
558         Map JavaDoc snapshot = null;
559
560         Iterator JavaDoc it = qualifierAttributes.iterator();
561         while (it.hasNext()) {
562             DbAttribute attribute = (DbAttribute) it.next();
563             String JavaDoc name = attribute.getName();
564             if (!qualifierSnapshot.containsKey(name)) {
565
566                 // get cached snapshot on demand ...
567
if (snapshot == null) {
568                     snapshot = dataObject
569                             .getDataContext()
570                             .getObjectStore()
571                             .getCachedSnapshot(dataObject.getObjectId());
572
573                     // sanity check...
574
if (snapshot == null) {
575                         throw new CayenneRuntimeException(
576                                 "Can't build qualifier for optimistic locking, "
577                                         + "no snapshot for id "
578                                         + dataObject.getObjectId());
579                     }
580                 }
581
582                 qualifierSnapshot.put(name, snapshot.get(name));
583             }
584         }
585     }
586
587     private void createPrimaryKeys() {
588
589         PrimaryKeyHelper pkHelper = domain.getPrimaryKeyHelper();
590
591         Collections.sort(objEntitiesToInsert, pkHelper.getObjEntityComparator());
592         Iterator JavaDoc i = objEntitiesToInsert.iterator();
593         while (i.hasNext()) {
594             ObjEntity currentEntity = (ObjEntity) i.next();
595             List JavaDoc dataObjects = (List JavaDoc) newObjectsByObjEntity.get(currentEntity
596                     .getClassName());
597
598             try {
599                 pkHelper.createPermIdsForObjEntity(currentEntity, dataObjects);
600             }
601             catch (CayenneException ex) {
602                 throw new CayenneRuntimeException(
603                         "Error creating primary key for entity " + currentEntity,
604                         ex);
605             }
606         }
607     }
608
609     /**
610      * Organizes committed objects by node, performs sorting operations.
611      */

612     private void categorizeObjects(Collection JavaDoc uncommittedObjects) {
613         this.nodeHelpers = new ArrayList JavaDoc();
614
615         newObjectsByObjEntity = new HashMap JavaDoc();
616         objectsToDeleteByObjEntity = new HashMap JavaDoc();
617         objectsToUpdateByObjEntity = new HashMap JavaDoc();
618         objEntitiesToInsert = new ArrayList JavaDoc();
619         objEntitiesToDelete = new ArrayList JavaDoc();
620         objEntitiesToUpdate = new ArrayList JavaDoc();
621
622         Iterator JavaDoc it = uncommittedObjects.iterator();
623         while (it.hasNext()) {
624             DataObject nextObject = (DataObject) it.next();
625             int objectState = nextObject.getPersistenceState();
626             switch (objectState) {
627                 case PersistenceState.NEW:
628                     objectToInsert(nextObject);
629                     break;
630                 case PersistenceState.DELETED:
631                     objectToDelete(nextObject);
632                     break;
633                 case PersistenceState.MODIFIED:
634                     objectToUpdate(nextObject);
635                     break;
636             }
637         }
638     }
639
640     private void objectToInsert(DataObject o) {
641         classifyByEntityAndNode(
642                 o,
643                 newObjectsByObjEntity,
644                 objEntitiesToInsert,
645                 DataNodeCommitAction.INSERT);
646     }
647
648     private void objectToDelete(DataObject o) {
649         classifyByEntityAndNode(
650                 o,
651                 objectsToDeleteByObjEntity,
652                 objEntitiesToDelete,
653                 DataNodeCommitAction.DELETE);
654     }
655
656     private void objectToUpdate(DataObject o) {
657         classifyByEntityAndNode(
658                 o,
659                 objectsToUpdateByObjEntity,
660                 objEntitiesToUpdate,
661                 DataNodeCommitAction.UPDATE);
662     }
663
664     private RuntimeException JavaDoc attemptToCommitReadOnlyEntity(
665             Class JavaDoc objectClass,
666             ObjEntity entity) {
667         String JavaDoc className = (objectClass != null) ? objectClass.getName() : "<null>";
668         StringBuffer JavaDoc message = new StringBuffer JavaDoc();
669         message
670                 .append("Class '")
671                 .append(className)
672                 .append("' maps to a read-only entity");
673
674         if (entity != null) {
675             message.append(" '").append(entity.getName()).append("'");
676         }
677
678         message.append(". Can't commit changes.");
679         return new CayenneRuntimeException(message.toString());
680     }
681
682     /**
683      * Performs classification of a DataObject for the DML operation. Throws
684      * CayenneRuntimeException if an object can't be classified.
685      */

686     private void classifyByEntityAndNode(
687             DataObject o,
688             Map JavaDoc objectsByObjEntity,
689             List JavaDoc objEntities,
690             int operationType) {
691
692         Class JavaDoc objEntityClass = o.getObjectId().getObjectClass();
693         ObjEntity entity = domain.getEntityResolver().lookupObjEntity(objEntityClass);
694         Collection JavaDoc objectsForObjEntity = (Collection JavaDoc) objectsByObjEntity
695                 .get(objEntityClass.getName());
696         if (objectsForObjEntity == null) {
697             objEntities.add(entity);
698             DataNode responsibleNode = domain.lookupDataNode(entity.getDataMap());
699
700             DataNodeCommitAction commitHelper = nodeHelper(responsibleNode);
701
702             commitHelper.addToEntityList(entity, operationType);
703             objectsForObjEntity = new ArrayList JavaDoc();
704             objectsByObjEntity.put(objEntityClass.getName(), objectsForObjEntity);
705         }
706         objectsForObjEntity.add(o);
707     }
708
709     private void prepareFlattenedQueries(
710             DataNodeCommitAction commitHelper,
711             Map JavaDoc flattenedBatches) {
712
713         for (Iterator JavaDoc i = flattenedBatches.values().iterator(); i.hasNext();) {
714             commitHelper.addToQueries((Query) i.next());
715         }
716     }
717
718     private void updateId(Map JavaDoc oldID, Map JavaDoc replacementID, Map JavaDoc updatedKeys) {
719         Iterator JavaDoc it = updatedKeys.entrySet().iterator();
720
721         while (it.hasNext()) {
722             Map.Entry JavaDoc entry = (Map.Entry JavaDoc) it.next();
723             Object JavaDoc key = entry.getKey();
724
725             if (oldID.containsKey(key) && !replacementID.containsKey(key)) {
726                 replacementID.put(key, entry.getValue());
727             }
728         }
729     }
730
731     private void groupObjEntitiesBySpannedDbEntities(
732             List JavaDoc dbEntities,
733             Map JavaDoc objEntitiesByDbEntity,
734             List JavaDoc objEntities) {
735
736         Iterator JavaDoc i = objEntities.iterator();
737         while (i.hasNext()) {
738             ObjEntity objEntity = (ObjEntity) i.next();
739             DbEntity dbEntity = objEntity.getDbEntity();
740
741             List JavaDoc objEntitiesForDbEntity = (List JavaDoc) objEntitiesByDbEntity.get(dbEntity);
742             if (objEntitiesForDbEntity == null) {
743                 objEntitiesForDbEntity = new ArrayList JavaDoc(1);
744                 dbEntities.add(dbEntity);
745                 objEntitiesByDbEntity.put(dbEntity, objEntitiesForDbEntity);
746             }
747             if (!objEntitiesForDbEntity.contains(objEntity))
748                 objEntitiesForDbEntity.add(objEntity);
749             for (Iterator JavaDoc j = objEntity.getAttributeMap().values().iterator(); j
750                     .hasNext();) {
751                 ObjAttribute objAttribute = (ObjAttribute) j.next();
752                 if (!objAttribute.isCompound())
753                     continue;
754                 dbEntity = (DbEntity) objAttribute.getDbAttribute().getEntity();
755                 objEntitiesForDbEntity = (List JavaDoc) objEntitiesByDbEntity.get(dbEntity);
756                 if (objEntitiesForDbEntity == null) {
757                     objEntitiesForDbEntity = new ArrayList JavaDoc(1);
758                     dbEntities.add(dbEntity);
759                     objEntitiesByDbEntity.put(dbEntity, objEntitiesForDbEntity);
760                 }
761                 if (!objEntitiesForDbEntity.contains(objEntity))
762                     objEntitiesForDbEntity.add(objEntity);
763             }
764         }
765     }
766
767     private DbRelationship findMasterToDependentDbRelationship(
768             DbEntity masterDbEntity,
769             DbEntity dependentDbEntity) {
770         if (masterDbEntity.equals(dependentDbEntity))
771             return null;
772         for (Iterator JavaDoc i = masterDbEntity.getRelationshipMap().values().iterator(); i
773                 .hasNext();) {
774             DbRelationship rel = (DbRelationship) i.next();
775             if (dependentDbEntity.equals(rel.getTargetEntity()) && rel.isToDependentPK())
776                 return rel;
777         }
778         return null;
779     }
780
781     /**
782      * Finds an existing helper for DataNode, creates a new one if no matching helper is
783      * found.
784      */

785     private DataNodeCommitAction nodeHelper(DataNode node) {
786
787         DataNodeCommitAction helper = null;
788         Iterator JavaDoc it = nodeHelpers.iterator();
789         while (it.hasNext()) {
790             DataNodeCommitAction itHelper = (DataNodeCommitAction) it.next();
791             if (itHelper.getNode() == node) {
792                 helper = itHelper;
793                 break;
794             }
795         }
796
797         if (helper == null) {
798             helper = new DataNodeCommitAction(node);
799             nodeHelpers.add(helper);
800         }
801
802         return helper;
803     }
804 }
805
Popular Tags