KickJava   Java API By Example, From Geeks To Geeks.

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


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;
58
59 import java.util.ArrayList JavaDoc;
60 import java.util.Arrays JavaDoc;
61 import java.util.Collection JavaDoc;
62 import java.util.Collections JavaDoc;
63 import java.util.HashMap JavaDoc;
64 import java.util.HashSet JavaDoc;
65 import java.util.Iterator JavaDoc;
66 import java.util.List JavaDoc;
67 import java.util.Map JavaDoc;
68 import java.util.Set JavaDoc;
69
70 import org.apache.commons.collections.map.LinkedMap;
71 import org.apache.log4j.Level;
72 import org.objectstyle.cayenne.CayenneException;
73 import org.objectstyle.cayenne.CayenneRuntimeException;
74 import org.objectstyle.cayenne.DataObject;
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.map.DbAttribute;
79 import org.objectstyle.cayenne.map.DbEntity;
80 import org.objectstyle.cayenne.map.DbJoin;
81 import org.objectstyle.cayenne.map.DbRelationship;
82 import org.objectstyle.cayenne.map.EntitySorter;
83 import org.objectstyle.cayenne.map.ObjAttribute;
84 import org.objectstyle.cayenne.map.ObjEntity;
85 import org.objectstyle.cayenne.map.ObjRelationship;
86 import org.objectstyle.cayenne.query.DeleteBatchQuery;
87 import org.objectstyle.cayenne.query.InsertBatchQuery;
88 import org.objectstyle.cayenne.query.Query;
89 import org.objectstyle.cayenne.query.UpdateBatchQuery;
90
91 /**
92  * A stateful commit handler used by DataContext to perform commit operation.
93  * DataContextCommitAction resolves primary key dependencies, referential integrity
94  * dependencies (including multi-reflexive entities), generates primary keys, creates
95  * batches for massive data modifications, assigns operations to data nodes. It indirectly
96  * relies on graph algorithms provided by ASHWOOD library.
97  *
98  * @author Andriy Shapochka, Andrei Adamchik
99  * @since 1.2
100  */

101 // Renamed from ContextCommit in 1.1
102
class DataContextCommitAction {
103
104     private DataContext context;
105     private Level logLevel;
106     private Map JavaDoc newObjectsByObjEntity;
107     private Map JavaDoc objectsToDeleteByObjEntity;
108     private Map JavaDoc objectsToUpdateByObjEntity;
109     private List JavaDoc objEntitiesToInsert;
110     private List JavaDoc objEntitiesToDelete;
111     private List JavaDoc objEntitiesToUpdate;
112     private List JavaDoc nodeHelpers;
113     private List JavaDoc insObjects; //event support
114
private List JavaDoc delObjects; //event support
115
private List JavaDoc updObjects; //event support
116

117     DataContextCommitAction(DataContext contextToCommit) {
118         context = contextToCommit;
119     }
120
121     /**
122      * Commits changes in the enclosed DataContext.
123      */

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

510     private List JavaDoc qualifierAttributes(ObjEntity entity, boolean optimisticLocking) {
511         if (!optimisticLocking) {
512             return entity.getDbEntity().getPrimaryKey();
513         }
514
515         List JavaDoc attributes = new ArrayList JavaDoc(entity.getDbEntity().getPrimaryKey());
516
517         Iterator JavaDoc attributeIt = entity.getAttributes().iterator();
518         while (attributeIt.hasNext()) {
519             ObjAttribute attribute = (ObjAttribute) attributeIt.next();
520
521             if (attribute.isUsedForLocking()) {
522                 // only care about first step in a flattened attribute
523
DbAttribute dbAttribute = (DbAttribute) attribute
524                         .getDbPathIterator()
525                         .next();
526
527                 if (!attributes.contains(dbAttribute)) {
528                     attributes.add(dbAttribute);
529                 }
530             }
531         }
532
533         Iterator JavaDoc relationshipIt = entity.getRelationships().iterator();
534         while (relationshipIt.hasNext()) {
535             ObjRelationship relationship = (ObjRelationship) relationshipIt.next();
536
537             if (relationship.isUsedForLocking()) {
538                 // only care about the first DbRelationship
539
DbRelationship dbRelationship = (DbRelationship) relationship
540                         .getDbRelationships()
541                         .get(0);
542
543                 Iterator JavaDoc joinsIterator = dbRelationship.getJoins().iterator();
544                 while (joinsIterator.hasNext()) {
545                     DbJoin dbAttrPair = (DbJoin) joinsIterator.next();
546                     DbAttribute dbAttribute = dbAttrPair.getSource();
547                     if (!attributes.contains(dbAttribute)) {
548                         attributes.add(dbAttribute);
549                     }
550                 }
551             }
552         }
553
554         return attributes;
555     }
556
557     /**
558      * Creates a list of DbAttributes that are updated in a snapshot
559      *
560      * @param entity
561      * @return
562      */

563     private List JavaDoc updatedAttributes(DbEntity entity, Map JavaDoc updatedSnapshot) {
564         List JavaDoc attributes = new ArrayList JavaDoc(updatedSnapshot.size());
565         Map JavaDoc entityAttributes = entity.getAttributeMap();
566
567         Iterator JavaDoc it = updatedSnapshot.keySet().iterator();
568         while (it.hasNext()) {
569             Object JavaDoc name = it.next();
570             attributes.add(entityAttributes.get(name));
571         }
572
573         return attributes;
574     }
575
576     /**
577      * Appends values used for optimistic locking to a given snapshot.
578      */

579     private void appendOptimisticLockingAttributes(
580             Map JavaDoc qualifierSnapshot,
581             DataObject dataObject,
582             List JavaDoc qualifierAttributes) {
583
584         Map JavaDoc snapshot = null;
585
586         Iterator JavaDoc it = qualifierAttributes.iterator();
587         while (it.hasNext()) {
588             DbAttribute attribute = (DbAttribute) it.next();
589             String JavaDoc name = attribute.getName();
590             if (!qualifierSnapshot.containsKey(name)) {
591
592                 // get cached snapshot on demand ...
593
if (snapshot == null) {
594                     snapshot = dataObject
595                             .getDataContext()
596                             .getObjectStore()
597                             .getCachedSnapshot(dataObject.getObjectId());
598
599                     // sanity check...
600
if (snapshot == null) {
601                         throw new CayenneRuntimeException(
602                                 "Can't build qualifier for optimistic locking, "
603                                         + "no snapshot for id "
604                                         + dataObject.getObjectId());
605                     }
606                 }
607
608                 qualifierSnapshot.put(name, snapshot.get(name));
609             }
610         }
611     }
612
613     private void createPrimaryKeys() throws CayenneException {
614
615         DataDomain domain = context.getParentDataDomain();
616         PrimaryKeyHelper pkHelper = domain.getPrimaryKeyHelper();
617
618         Collections.sort(objEntitiesToInsert, pkHelper.getObjEntityComparator());
619         Iterator JavaDoc i = objEntitiesToInsert.iterator();
620         while (i.hasNext()) {
621             ObjEntity currentEntity = (ObjEntity) i.next();
622             List JavaDoc dataObjects = (List JavaDoc) newObjectsByObjEntity.get(currentEntity
623                     .getClassName());
624             pkHelper.createPermIdsForObjEntity(currentEntity, dataObjects);
625         }
626     }
627
628     /**
629      * Organizes committed objects by node, performs sorting operations.
630      */

631     private void categorizeObjects() throws CayenneException {
632         this.nodeHelpers = new ArrayList JavaDoc();
633
634         Iterator JavaDoc it = context.getObjectStore().getObjectIterator();
635         newObjectsByObjEntity = new HashMap JavaDoc();
636         objectsToDeleteByObjEntity = new HashMap JavaDoc();
637         objectsToUpdateByObjEntity = new HashMap JavaDoc();
638         objEntitiesToInsert = new ArrayList JavaDoc();
639         objEntitiesToDelete = new ArrayList JavaDoc();
640         objEntitiesToUpdate = new ArrayList JavaDoc();
641
642         while (it.hasNext()) {
643             DataObject nextObject = (DataObject) it.next();
644             int objectState = nextObject.getPersistenceState();
645             switch (objectState) {
646                 case PersistenceState.NEW:
647                     objectToInsert(nextObject);
648                     break;
649                 case PersistenceState.DELETED:
650                     objectToDelete(nextObject);
651                     break;
652                 case PersistenceState.MODIFIED:
653                     objectToUpdate(nextObject);
654                     break;
655             }
656         }
657     }
658
659     private void objectToInsert(DataObject o) throws CayenneException {
660         classifyByEntityAndNode(o,
661                 newObjectsByObjEntity,
662                 objEntitiesToInsert,
663                 DataNodeCommitAction.INSERT);
664     }
665
666     private void objectToDelete(DataObject o) throws CayenneException {
667         classifyByEntityAndNode(o,
668                 objectsToDeleteByObjEntity,
669                 objEntitiesToDelete,
670                 DataNodeCommitAction.DELETE);
671     }
672
673     private void objectToUpdate(DataObject o) throws CayenneException {
674         classifyByEntityAndNode(o,
675                 objectsToUpdateByObjEntity,
676                 objEntitiesToUpdate,
677                 DataNodeCommitAction.UPDATE);
678     }
679
680     private RuntimeException JavaDoc attemptToCommitReadOnlyEntity(
681             Class JavaDoc objectClass,
682             ObjEntity entity) {
683         String JavaDoc className = (objectClass != null) ? objectClass.getName() : "<null>";
684         StringBuffer JavaDoc message = new StringBuffer JavaDoc();
685         message
686                 .append("Class '")
687                 .append(className)
688                 .append("' maps to a read-only entity");
689
690         if (entity != null) {
691             message.append(" '").append(entity.getName()).append("'");
692         }
693
694         message.append(". Can't commit changes.");
695         return new CayenneRuntimeException(message.toString());
696     }
697
698     /**
699      * Performs classification of a DataObject for the DML operation. Throws
700      * CayenneRuntimeException if an object can't be classified.
701      */

702     private void classifyByEntityAndNode(
703             DataObject o,
704             Map JavaDoc objectsByObjEntity,
705             List JavaDoc objEntities,
706             int operationType) {
707
708         Class JavaDoc objEntityClass = o.getObjectId().getObjectClass();
709         ObjEntity entity = context.getEntityResolver().lookupObjEntity(objEntityClass);
710         Collection JavaDoc objectsForObjEntity = (Collection JavaDoc) objectsByObjEntity
711                 .get(objEntityClass.getName());
712         if (objectsForObjEntity == null) {
713             objEntities.add(entity);
714             DataNode responsibleNode = context.lookupDataNode(entity.getDataMap());
715
716             DataNodeCommitAction commitHelper = nodeHelper(responsibleNode);
717
718             commitHelper.addToEntityList(entity, operationType);
719             objectsForObjEntity = new ArrayList JavaDoc();
720             objectsByObjEntity.put(objEntityClass.getName(), objectsForObjEntity);
721         }
722         objectsForObjEntity.add(o);
723     }
724
725     private void categorizeFlattenedInsertsAndCreateBatches() {
726         Iterator JavaDoc i = context.getObjectStore().getFlattenedInserts().iterator();
727
728         while (i.hasNext()) {
729             FlattenedRelationshipUpdate info = (FlattenedRelationshipUpdate) i.next();
730
731             DataObject source = info.getSource();
732
733             // TODO: does it ever happen? How?
734
if (source.getPersistenceState() == PersistenceState.DELETED) {
735                 continue;
736             }
737
738             if (info.getDestination().getPersistenceState() == PersistenceState.DELETED) {
739                 continue;
740             }
741
742             DbEntity flattenedEntity = info.getJoinEntity();
743             DataNode responsibleNode = context.lookupDataNode(flattenedEntity
744                     .getDataMap());
745             DataNodeCommitAction commitHelper = nodeHelper(responsibleNode);
746             Map JavaDoc batchesByDbEntity = commitHelper.getFlattenedInsertQueries();
747
748             InsertBatchQuery relationInsertQuery = (InsertBatchQuery) batchesByDbEntity
749                     .get(flattenedEntity);
750
751             if (relationInsertQuery == null) {
752                 relationInsertQuery = new InsertBatchQuery(flattenedEntity, 50);
753                 relationInsertQuery.setLoggingLevel(logLevel);
754                 batchesByDbEntity.put(flattenedEntity, relationInsertQuery);
755             }
756
757             Map JavaDoc flattenedSnapshot = info.buildJoinSnapshotForInsert();
758             relationInsertQuery.add(flattenedSnapshot);
759         }
760     }
761
762     private void categorizeFlattenedDeletesAndCreateBatches() {
763         Iterator JavaDoc i = context.getObjectStore().getFlattenedDeletes().iterator();
764
765         while (i.hasNext()) {
766             FlattenedRelationshipUpdate info = (FlattenedRelationshipUpdate) i.next();
767
768             // TODO: does it ever happen?
769
Map JavaDoc sourceId = info.getSource().getObjectId().getIdSnapshot();
770
771             if (sourceId == null)
772                 continue;
773
774             Map JavaDoc dstId = info.getDestination().getObjectId().getIdSnapshot();
775             if (dstId == null)
776                 continue;
777
778             DbEntity flattenedEntity = info.getJoinEntity();
779
780             DataNode responsibleNode = context.lookupDataNode(flattenedEntity
781                     .getDataMap());
782             DataNodeCommitAction commitHelper = nodeHelper(responsibleNode);
783             Map JavaDoc batchesByDbEntity = commitHelper.getFlattenedDeleteQueries();
784
785             DeleteBatchQuery relationDeleteQuery = (DeleteBatchQuery) batchesByDbEntity
786                     .get(flattenedEntity);
787             if (relationDeleteQuery == null) {
788                 boolean optimisticLocking = false;
789                 relationDeleteQuery = new DeleteBatchQuery(flattenedEntity, 50);
790                 relationDeleteQuery.setUsingOptimisticLocking(optimisticLocking);
791                 relationDeleteQuery.setLoggingLevel(logLevel);
792                 batchesByDbEntity.put(flattenedEntity, relationDeleteQuery);
793             }
794
795             List JavaDoc flattenedSnapshots = info.buildJoinSnapshotsForDelete();
796             if (!flattenedSnapshots.isEmpty()) {
797                 Iterator JavaDoc snapsIt = flattenedSnapshots.iterator();
798                 while (snapsIt.hasNext()) {
799                     relationDeleteQuery.add((Map JavaDoc) snapsIt.next());
800                 }
801             }
802         }
803     }
804
805     private void prepareFlattenedQueries(
806             DataNodeCommitAction commitHelper,
807             Map JavaDoc flattenedBatches) {
808
809         for (Iterator JavaDoc i = flattenedBatches.values().iterator(); i.hasNext();) {
810             commitHelper.addToQueries((Query) i.next());
811         }
812     }
813
814     //
815
private void updateId(Map JavaDoc oldID, Map JavaDoc replacementID, Map JavaDoc updatedKeys) {
816         Iterator JavaDoc it = updatedKeys.entrySet().iterator();
817
818         while (it.hasNext()) {
819             Map.Entry JavaDoc entry = (Map.Entry JavaDoc) it.next();
820             Object JavaDoc key = entry.getKey();
821
822             if (oldID.containsKey(key) && !replacementID.containsKey(key)) {
823                 replacementID.put(key, entry.getValue());
824             }
825         }
826     }
827
828     private void groupObjEntitiesBySpannedDbEntities(
829             List JavaDoc dbEntities,
830             Map JavaDoc objEntitiesByDbEntity,
831             List JavaDoc objEntities) {
832
833         Iterator JavaDoc i = objEntities.iterator();
834         while (i.hasNext()) {
835             ObjEntity objEntity = (ObjEntity) i.next();
836             DbEntity dbEntity = objEntity.getDbEntity();
837
838             List JavaDoc objEntitiesForDbEntity = (List JavaDoc) objEntitiesByDbEntity.get(dbEntity);
839             if (objEntitiesForDbEntity == null) {
840                 objEntitiesForDbEntity = new ArrayList JavaDoc(1);
841                 dbEntities.add(dbEntity);
842                 objEntitiesByDbEntity.put(dbEntity, objEntitiesForDbEntity);
843             }
844             if (!objEntitiesForDbEntity.contains(objEntity))
845                 objEntitiesForDbEntity.add(objEntity);
846             for (Iterator JavaDoc j = objEntity.getAttributeMap().values().iterator(); j
847                     .hasNext();) {
848                 ObjAttribute objAttribute = (ObjAttribute) j.next();
849                 if (!objAttribute.isCompound())
850                     continue;
851                 dbEntity = (DbEntity) objAttribute.getDbAttribute().getEntity();
852                 objEntitiesForDbEntity = (List JavaDoc) objEntitiesByDbEntity.get(dbEntity);
853                 if (objEntitiesForDbEntity == null) {
854                     objEntitiesForDbEntity = new ArrayList JavaDoc(1);
855                     dbEntities.add(dbEntity);
856                     objEntitiesByDbEntity.put(dbEntity, objEntitiesForDbEntity);
857                 }
858                 if (!objEntitiesForDbEntity.contains(objEntity))
859                     objEntitiesForDbEntity.add(objEntity);
860             }
861         }
862     }
863
864     private DbRelationship findMasterToDependentDbRelationship(
865             DbEntity masterDbEntity,
866             DbEntity dependentDbEntity) {
867         if (masterDbEntity.equals(dependentDbEntity))
868             return null;
869         for (Iterator JavaDoc i = masterDbEntity.getRelationshipMap().values().iterator(); i
870                 .hasNext();) {
871             DbRelationship rel = (DbRelationship) i.next();
872             if (dependentDbEntity.equals(rel.getTargetEntity()) && rel.isToDependentPK())
873                 return rel;
874         }
875         return null;
876     }
877
878     /**
879      * Finds an existing helper for DataNode, creates a new one if no matching helper is
880      * found.
881      */

882     private DataNodeCommitAction nodeHelper(DataNode node) {
883
884         DataNodeCommitAction helper = null;
885         Iterator JavaDoc it = nodeHelpers.iterator();
886         while (it.hasNext()) {
887             DataNodeCommitAction itHelper = (DataNodeCommitAction) it.next();
888             if (itHelper.getNode() == node) {
889                 helper = itHelper;
890                 break;
891             }
892         }
893
894         if (helper == null) {
895             helper = new DataNodeCommitAction(node);
896             nodeHelpers.add(helper);
897         }
898
899         return helper;
900     }
901 }
Popular Tags