KickJava   Java API By Example, From Geeks To Geeks.

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


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.io.IOException JavaDoc;
60 import java.io.ObjectInputStream JavaDoc;
61 import java.io.ObjectOutputStream JavaDoc;
62 import java.io.Serializable JavaDoc;
63 import java.util.ArrayList JavaDoc;
64 import java.util.Collection JavaDoc;
65 import java.util.Collections JavaDoc;
66 import java.util.HashMap JavaDoc;
67 import java.util.Iterator JavaDoc;
68 import java.util.List JavaDoc;
69 import java.util.Map JavaDoc;
70
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.DataRow;
76 import org.objectstyle.cayenne.Fault;
77 import org.objectstyle.cayenne.ObjectId;
78 import org.objectstyle.cayenne.PersistenceState;
79 import org.objectstyle.cayenne.TempObjectId;
80 import org.objectstyle.cayenne.access.event.DataContextEvent;
81 import org.objectstyle.cayenne.access.util.IteratedSelectObserver;
82 import org.objectstyle.cayenne.access.util.PrefetchHelper;
83 import org.objectstyle.cayenne.access.util.QueryUtils;
84 import org.objectstyle.cayenne.conf.Configuration;
85 import org.objectstyle.cayenne.event.EventManager;
86 import org.objectstyle.cayenne.event.EventSubject;
87 import org.objectstyle.cayenne.map.DataMap;
88 import org.objectstyle.cayenne.map.DbJoin;
89 import org.objectstyle.cayenne.map.DbRelationship;
90 import org.objectstyle.cayenne.map.Entity;
91 import org.objectstyle.cayenne.map.EntityResolver;
92 import org.objectstyle.cayenne.map.ObjAttribute;
93 import org.objectstyle.cayenne.map.ObjEntity;
94 import org.objectstyle.cayenne.map.ObjRelationship;
95 import org.objectstyle.cayenne.query.GenericSelectQuery;
96 import org.objectstyle.cayenne.query.ParameterizedQuery;
97 import org.objectstyle.cayenne.query.Query;
98 import org.objectstyle.cayenne.query.SelectQuery;
99 import org.objectstyle.cayenne.util.Util;
100
101 /**
102  * Class that provides applications with access to Cayenne persistence features. In most
103  * cases this is the only access class directly used in the application.
104  * <p>
105  * Most common DataContext use pattern is to create one DataContext per session. "Session"
106  * may be a an HttpSesession in a web application, or any other similar concept in a
107  * multiuser application.
108  * </p>
109  * <p>
110  * DataObjects are registered with DataContext either implicitly when they are fetched via
111  * a query, or read via a relationship from another object, or explicitly via calling
112  * {@link #createAndRegisterNewObject(Class)}during new DataObject creation. DataContext
113  * tracks changes made to its DataObjects in memory, and flushes them to the database when
114  * {@link #commitChanges()}is called. Until DataContext is committed, changes made to its
115  * objects are not visible in other DataContexts.
116  * </p>
117  * <p>
118  * Each DataObject can belong only to a single DataContext. To create a replica of an
119  * object from a different DataContext in a local context, use
120  * {@link #localObjects(java.util.List)}method.
121  * <p>
122  * <i>For more information see <a HREF="../../../../../../userguide/index.html"
123  * target="_top">Cayenne User Guide. </a> </i>
124  * </p>
125  *
126  * @author Andrei Adamchik
127  */

128 public class DataContext implements QueryEngine, Serializable JavaDoc {
129
130     // noop delegate
131
private static final DataContextDelegate defaultDelegate = new DataContextDelegate() {
132
133         public GenericSelectQuery willPerformSelect(
134                 DataContext context,
135                 GenericSelectQuery query) {
136             return query;
137         }
138
139         public boolean shouldMergeChanges(DataObject object, DataRow snapshotInStore) {
140             return true;
141         }
142
143         public boolean shouldProcessDelete(DataObject object) {
144             return true;
145         }
146
147         public void finishedMergeChanges(DataObject object) {
148
149         }
150
151         public void finishedProcessDelete(DataObject object) {
152
153         }
154     };
155
156     // DataContext events
157
public static final EventSubject WILL_COMMIT = EventSubject.getSubject(
158             DataContext.class,
159             "DataContextWillCommit");
160     public static final EventSubject DID_COMMIT = EventSubject.getSubject(
161             DataContext.class,
162             "DataContextDidCommit");
163     public static final EventSubject DID_ROLLBACK = EventSubject.getSubject(
164             DataContext.class,
165             "DataContextDidRollback");
166     
167
168     
169     /**
170      * A holder of a DataContext bound to the current thread.
171      *
172      * @since 1.1
173      */

174     protected static final ThreadLocal JavaDoc threadDataContext = new ThreadLocal JavaDoc();
175
176     // event posting default for new DataContexts
177
private static boolean transactionEventsEnabledDefault;
178
179     // enable/disable event handling for individual instances
180
private boolean transactionEventsEnabled;
181
182     // Set of DataContextDelegates to be notified.
183
private DataContextDelegate delegate;
184
185     protected boolean usingSharedSnaphsotCache;
186     protected boolean validatingObjectsOnCommit;
187     protected ObjectStore objectStore;
188
189     protected transient QueryEngine parent;
190     
191     /**
192      * Stores user defined properties associated with this DataContext.
193      *
194      * @since 1.2
195      */

196     protected Map JavaDoc userProperties;
197
198     /**
199      * Stores the name of parent DataDomain. Used to defer initialization of the parent
200      * QueryEngine after deserialization. This helps avoid an issue with certain servlet
201      * engines (e.g. Tomcat) where HttpSessions with DataContext's are deserialized at
202      * startup before Cayenne stack is fully initialized.
203      */

204     protected transient String JavaDoc lazyInitParentDomainName;
205
206     /**
207      * A factory method of DataObjects. Uses Configuration ClassLoader to instantiate a
208      * new instance of DataObject of a given class.
209      */

210     private static final DataObject newDataObject(String JavaDoc className) throws Exception JavaDoc {
211         return (DataObject) Configuration
212                 .getResourceLoader()
213                 .loadClass(className)
214                 .newInstance();
215     }
216     
217     /**
218      * Returns the DataContext bound to the current thread.
219      *
220      * @since 1.1
221      * @return the DataContext associated with caller thread.
222      * @throws IllegalStateException if there is no DataContext bound to the current
223      * thread.
224      * @see org.objectstyle.cayenne.conf.WebApplicationContextProvider
225      */

226     public static DataContext getThreadDataContext() throws IllegalStateException JavaDoc {
227         DataContext dc = (DataContext) threadDataContext.get();
228         if (dc == null) {
229             throw new IllegalStateException JavaDoc("Current thread has no bound DataContext.");
230         }
231
232         return dc;
233     }
234     
235     /**
236      * Binds a DataContext to the current thread. DataContext can later be retrieved by
237      * users in the same thread by calling {@link DataContext#getThreadDataContext}. Using
238      * null parameter will unbind currently bound DataContext.
239      *
240      * @since 1.1
241      */

242     public static void bindThreadDataContext(DataContext context) {
243         threadDataContext.set(context);
244     }
245
246     /**
247      * Factory method that creates and returns a new instance of DataContext based on
248      * default domain. If more than one domain exists in the current configuration,
249      * {@link DataContext#createDataContext(String)} must be used instead. ObjectStore associated
250      * with created DataContext will have a cache stack configured using parent domain settings.
251      */

252     public static DataContext createDataContext() {
253         return Configuration.getSharedConfiguration().getDomain().createDataContext();
254     }
255
256     /**
257      * Factory method that creates and returns a new instance of DataContext based on
258      * default domain. If more than one domain exists in the current configuration,
259      * {@link DataContext#createDataContext(String, boolean)} must be used instead.
260      * ObjectStore associated with newly created DataContext will have a cache
261      * stack configured according to the specified policy, overriding a parent domain setting.
262      *
263      * @since 1.1
264      */

265     public static DataContext createDataContext(boolean useSharedCache) {
266         return Configuration.getSharedConfiguration().getDomain().createDataContext(
267                 useSharedCache);
268     }
269
270     /**
271      * Factory method that creates and returns a new instance of DataContext using named
272      * domain as its parent. If there is no domain matching the name argument, an
273      * exception is thrown.
274      */

275     public static DataContext createDataContext(String JavaDoc domainName) {
276         DataDomain domain = Configuration.getSharedConfiguration().getDomain(domainName);
277         if (domain == null) {
278             throw new IllegalArgumentException JavaDoc("Non-existent domain: " + domainName);
279         }
280         return domain.createDataContext();
281     }
282
283     /**
284      * Creates and returns new DataContext that will use a named DataDomain as its parent.
285      * ObjectStore associated with newly created DataContext will have a cache
286      * stack configured according to the specified policy, overriding a parent domain
287      * setting.
288      *
289      * @since 1.1
290      */

291     public static DataContext createDataContext(String JavaDoc domainName, boolean useSharedCache) {
292
293         DataDomain domain = Configuration.getSharedConfiguration().getDomain(domainName);
294         if (domain == null) {
295             throw new IllegalArgumentException JavaDoc("Non-existent domain: " + domainName);
296         }
297         return domain.createDataContext(useSharedCache);
298     }
299
300     /**
301      * Default constructor that creates a DataContext that has no association with a
302      * DataDomain.
303      */

304     public DataContext() {
305         this(null, null);
306     }
307
308     /**
309      * Creates a DataContext with parent QueryEngine and a DataRowStore that should be
310      * used by the ObjectStore.
311      *
312      * @since 1.1
313      * @param parent parent QueryEngine used to communicate with the data source.
314      * @param objectStore ObjectStore used by DataContext.
315      */

316     public DataContext(QueryEngine parent, ObjectStore objectStore) {
317         setParent(parent);
318
319         this.objectStore = objectStore;
320         this.setTransactionEventsEnabled(transactionEventsEnabledDefault);
321         this.usingSharedSnaphsotCache = getParentDataDomain() != null
322                 && objectStore.getDataRowCache() == getParentDataDomain()
323                         .getSharedSnapshotCache();
324     }
325
326     /**
327      * Initializes parent if deserialization left it uninitialized.
328      */

329     private final void awakeFromDeserialization() {
330         if (parent == null && lazyInitParentDomainName != null) {
331
332             DataDomain domain = Configuration.getSharedConfiguration().getDomain(
333                     lazyInitParentDomainName);
334
335             this.parent = domain;
336
337             if (isUsingSharedSnapshotCache() && domain != null) {
338                 this.objectStore.setDataRowCache(domain.getSharedSnapshotCache());
339             }
340         }
341     }
342     
343     /**
344      * Returns a map of user-defined properties associated with this DataContext.
345      *
346      * @since 1.2
347      */

348     protected Map JavaDoc getUserProperties() {
349         // do lazy init..
350
// as not all users will take advantage of properties, creating the
351
// map on demand to keep DataContext lean...
352
if (userProperties == null) {
353             userProperties = new HashMap JavaDoc();
354         }
355
356         return userProperties;
357     }
358     
359     /**
360      * Returns a user-defined property previously set via 'setUserProperty'. Note that it
361      * is a caller responsibility to synchronize access to properties.
362      *
363      * @since 1.2
364      */

365     public Object JavaDoc getUserProperty(String JavaDoc key) {
366         return getUserProperties().get(key);
367     }
368
369     /**
370      * Sets a user-defined property. Note that it is a caller responsibility to
371      * synchronize access to properties.
372      *
373      * @since 1.2
374      */

375     public void setUserProperty(String JavaDoc key, Object JavaDoc value) {
376         getUserProperties().put(key, value);
377     }
378     
379
380     /**
381      * Returns parent QueryEngine object. In most cases returned object is an instance of
382      * DataDomain.
383      */

384     public QueryEngine getParent() {
385         awakeFromDeserialization();
386         return parent;
387     }
388
389     /**
390      * <i>Note: currently nested DataContexts are not supported, so this method simply
391      * calls "getParent()". Using this method is preferrable to calling "getParent()"
392      * directly and casting it to DataDomain, since it more likely to be compatible with
393      * the future releases of Cayenne. </i>
394      *
395      * @return DataDomain that is a direct or indirect parent of this DataContext.
396      * @since 1.1
397      */

398     public DataDomain getParentDataDomain() {
399         return (DataDomain) getParent();
400     }
401
402     /**
403      * Sets direct parent of this DataContext.
404      */

405     public void setParent(QueryEngine parent) {
406         this.parent = parent;
407     }
408
409     /**
410      * Sets a DataContextDelegate for this context. Delegate is notified of certain events
411      * in the DataContext lifecycle and can customize DataContext behavior.
412      *
413      * @since 1.1
414      */

415     public void setDelegate(DataContextDelegate delegate) {
416         this.delegate = delegate;
417     }
418
419     /**
420      * Returns a delegate currently associated with this DataContext.
421      *
422      * @since 1.1
423      */

424     public DataContextDelegate getDelegate() {
425         return delegate;
426     }
427
428     /**
429      * @return a delegate instance if it is initialized, or a shared noop implementation
430      * the context has no delegate. Useful to prevent extra null checks and
431      * conditional logic in the code.
432      * @since 1.1
433      */

434     DataContextDelegate nonNullDelegate() {
435         return (delegate != null) ? delegate : DataContext.defaultDelegate;
436     }
437
438     /**
439      * Returns ObjectStore associated with this DataContext.
440      */

441     public ObjectStore getObjectStore() {
442         awakeFromDeserialization();
443         return objectStore;
444     }
445
446     /**
447      * Returns <code>true</code> if there are any modified, deleted or new objects
448      * registered with this DataContext, <code>false</code> otherwise.
449      */

450     public boolean hasChanges() {
451         return getObjectStore().hasChanges();
452     }
453
454     /**
455      * Returns a list of objects that are registered with this DataContext and have a
456      * state PersistenceState.NEW
457      */

458     public Collection JavaDoc newObjects() {
459         return getObjectStore().objectsInState(PersistenceState.NEW);
460     }
461
462     /**
463      * Returns a list of objects that are registered with this DataContext and have a
464      * state PersistenceState.DELETED
465      */

466     public Collection JavaDoc deletedObjects() {
467         return getObjectStore().objectsInState(PersistenceState.DELETED);
468     }
469
470     /**
471      * Returns a list of objects that are registered with this DataContext and have a
472      * state PersistenceState.MODIFIED
473      */

474     public Collection JavaDoc modifiedObjects() {
475         return getObjectStore().objectsInState(PersistenceState.MODIFIED);
476     }
477
478     /**
479      * Returns an object for a given ObjectId. If object is not registered with this
480      * context, a "hollow" object fault is created, registered, and returned to the
481      * caller.
482      */

483     public DataObject registeredObject(ObjectId oid) {
484         // must synchronize on ObjectStore since we must read and write atomically
485
synchronized (getObjectStore()) {
486             DataObject obj = objectStore.getObject(oid);
487             if (obj == null) {
488                 try {
489                     // TODO: shouldn't we replace this with oid.getObjectClass().newInstance()
490
obj = DataContext.newDataObject(oid.getObjectClass().getName());
491                 }
492                 catch (Exception JavaDoc ex) {
493                     String JavaDoc entity = (oid != null) ? getEntityResolver().lookupObjEntity(
494                             oid.getObjectClass()).getName() : null;
495                     throw new CayenneRuntimeException(
496                             "Error creating object for entity '" + entity + "'.",
497                             ex);
498                 }
499
500                 obj.setObjectId(oid);
501                 obj.setPersistenceState(PersistenceState.HOLLOW);
502                 obj.setDataContext(this);
503                 objectStore.addObject(obj);
504             }
505             return obj;
506         }
507     }
508
509     /**
510      * Creates or gets from cache a DataRow reflecting current object state.
511      *
512      * @since 1.1
513      */

514     public DataRow currentSnapshot(DataObject anObject) {
515         ObjEntity entity = getEntityResolver().lookupObjEntity(anObject);
516
517         // for a HOLLOW object return snapshot from cache
518
if (anObject.getPersistenceState() == PersistenceState.HOLLOW
519                 && anObject.getDataContext() != null) {
520
521             ObjectId id = anObject.getObjectId();
522             return getObjectStore().getSnapshot(id, this);
523         }
524
525         DataRow snapshot = new DataRow(10);
526
527         Iterator JavaDoc attributes = entity.getAttributeMap().entrySet().iterator();
528         while (attributes.hasNext()) {
529             Map.Entry JavaDoc entry = (Map.Entry JavaDoc) attributes.next();
530             String JavaDoc attrName = (String JavaDoc) entry.getKey();
531             ObjAttribute objAttr = (ObjAttribute) entry.getValue();
532
533             // processing compound attributes correctly
534
snapshot.put(objAttr.getDbAttributePath(), anObject
535                     .readPropertyDirectly(attrName));
536         }
537
538         Iterator JavaDoc relationships = entity.getRelationshipMap().entrySet().iterator();
539         while (relationships.hasNext()) {
540             Map.Entry JavaDoc entry = (Map.Entry JavaDoc) relationships.next();
541             ObjRelationship rel = (ObjRelationship) entry.getValue();
542
543             // if target doesn't propagates its key value, skip it
544
if (rel.isSourceIndependentFromTargetChange()) {
545                 continue;
546             }
547
548             Object JavaDoc targetObject = anObject.readPropertyDirectly(rel.getName());
549             if (targetObject == null) {
550                 continue;
551             }
552
553             // if target is Fault, get id attributes from stored snapshot
554
// to avoid unneeded fault triggering
555
if (targetObject instanceof Fault) {
556                 DataRow storedSnapshot = getObjectStore().getSnapshot(
557                         anObject.getObjectId(),
558                         this);
559                 if (storedSnapshot == null) {
560                     throw new CayenneRuntimeException(
561                             "No matching objects found for ObjectId "
562                                     + anObject.getObjectId()
563                                     + ". Object may have been deleted externally.");
564                 }
565
566                 DbRelationship dbRel = (DbRelationship) rel.getDbRelationships().get(0);
567                 Iterator JavaDoc joins = dbRel.getJoins().iterator();
568                 while (joins.hasNext()) {
569                     DbJoin join = (DbJoin) joins.next();
570                     String JavaDoc key = join.getSourceName();
571                     snapshot.put(key, storedSnapshot.get(key));
572                 }
573
574                 continue;
575             }
576
577             // target is resolved and we have an FK->PK to it,
578
// so extract it from target...
579
DataObject target = (DataObject) targetObject;
580             Map JavaDoc idParts = target.getObjectId().getIdSnapshot();
581
582             // this may happen in uncommitted objects
583
if (idParts.isEmpty()) {
584                 continue;
585             }
586
587             DbRelationship dbRel = (DbRelationship) rel.getDbRelationships().get(0);
588             Map JavaDoc fk = dbRel.srcFkSnapshotWithTargetSnapshot(idParts);
589             snapshot.putAll(fk);
590         }
591
592         // process object id map
593
// we should ignore any object id values if a corresponding attribute
594
// is a part of relationship "toMasterPK", since those values have been
595
// set above when db relationships where processed.
596
Map JavaDoc thisIdParts = anObject.getObjectId().getIdSnapshot();
597         if (thisIdParts != null) {
598             
599             // put only those that do not exist in the map
600
Iterator JavaDoc idIterator = thisIdParts.entrySet().iterator();
601             while (idIterator.hasNext()) {
602                 Map.Entry JavaDoc entry = (Map.Entry JavaDoc) idIterator.next();
603                 Object JavaDoc nextKey = entry.getKey();
604                 if (!snapshot.containsKey(nextKey)) {
605                     snapshot.put(nextKey, entry.getValue());
606                 }
607             }
608         }
609         
610         return snapshot;
611     }
612
613     /**
614      * Creates a list of DataObjects local to this DataContext from a list of DataObjects
615      * coming from a different DataContext. Note that all objects in the source list must
616      * be either in COMMITTED or in HOLLOW state.
617      *
618      * @since 1.0.3
619      */

620     public List JavaDoc localObjects(List JavaDoc objects) {
621         List JavaDoc localObjects = new ArrayList JavaDoc(objects.size());
622
623         Iterator JavaDoc it = objects.iterator();
624         while (it.hasNext()) {
625             DataObject object = (DataObject) it.next();
626
627             // sanity check
628
if (object.getPersistenceState() != PersistenceState.COMMITTED
629                     && object.getPersistenceState() != PersistenceState.HOLLOW) {
630                 throw new CayenneRuntimeException(
631                         "Only COMMITTED and HOLLOW objects can be transferred between contexts. "
632                                 + "Invalid object state '"
633                                 + PersistenceState.persistenceStateName(object
634                                         .getPersistenceState())
635                                 + "', ObjectId: "
636                                 + object.getObjectId());
637             }
638
639             DataObject localObject = (object.getDataContext() != this)
640                     ? registeredObject(object.getObjectId())
641                     : object;
642             localObjects.add(localObject);
643         }
644
645         return localObjects;
646     }
647
648     /**
649      * Converts a list of data rows to a list of DataObjects.
650      *
651      * @since 1.1
652      */

653     public List JavaDoc objectsFromDataRows(
654             ObjEntity entity,
655             List JavaDoc dataRows,
656             boolean refresh,
657             boolean resolveInheritanceHierarchy) {
658         
659         return new DataContextObjectFactory(this, refresh, resolveInheritanceHierarchy)
660                 .objectsFromDataRows(entity, dataRows);
661     }
662
663     /**
664      * Converts a list of DataRows to a List of DataObject registered with this
665      * DataContext. Internally calls
666      * {@link #objectsFromDataRows(ObjEntity,List,boolean,boolean)}.
667      *
668      * @since 1.1
669      * @see DataRow
670      * @see DataObject
671      */

672     public List JavaDoc objectsFromDataRows(
673             Class JavaDoc objectClass,
674             List JavaDoc dataRows,
675             boolean refresh,
676             boolean resolveInheritanceHierarchy) {
677         ObjEntity entity = this.getEntityResolver().lookupObjEntity(objectClass);
678         return objectsFromDataRows(entity, dataRows, refresh, resolveInheritanceHierarchy);
679     }
680
681     /**
682      * Creates a DataObject from DataRow. This is a convenience shortcut to
683      * {@link #objectsFromDataRows(Class,java.util.List,boolean,boolean)}.
684      *
685      * @see DataRow
686      * @see DataObject
687      */

688     public DataObject objectFromDataRow(
689             Class JavaDoc objectClass,
690             DataRow dataRow,
691             boolean refresh) {
692         List JavaDoc list = objectsFromDataRows(
693                 objectClass,
694                 Collections.singletonList(dataRow),
695                 refresh,
696                 true);
697         return (DataObject) list.get(0);
698     }
699
700
701     /**
702      * Instantiates new object and registers it with itself. Object class is determined
703      * from ObjEntity. Object class must have a default constructor.
704      * <p>
705      * <i>Note: preferred way to create new objects is via
706      * {@link #createAndRegisterNewObject(Class)}method. It works exactly the same way,
707      * but makes the application type-safe. </i>
708      * </p>
709      *
710      * @see #createAndRegisterNewObject(Class)
711      */

712     public DataObject createAndRegisterNewObject(String JavaDoc objEntityName) {
713         ObjEntity entity = this.getEntityResolver().getObjEntity(objEntityName);
714
715         if (entity == null) {
716             throw new IllegalArgumentException JavaDoc("Invalid entity name: " + objEntityName);
717         }
718
719         String JavaDoc objClassName = entity.getClassName();
720         DataObject dataObject = null;
721         try {
722             dataObject = DataContext.newDataObject(objClassName);
723         }
724         catch (Exception JavaDoc ex) {
725             throw new CayenneRuntimeException("Error instantiating object.", ex);
726         }
727
728         registerNewObjectWithEntity(dataObject, entity);
729         return dataObject;
730     }
731
732     /**
733      * Instantiates new object and registers it with itself. Object class must have a
734      * default constructor.
735      *
736      * @since 1.1
737      */

738     public DataObject createAndRegisterNewObject(Class JavaDoc objectClass) {
739         if (objectClass == null) {
740             throw new NullPointerException JavaDoc("DataObject class can't be null.");
741         }
742
743         ObjEntity entity = getEntityResolver().lookupObjEntity(objectClass);
744         if (entity == null) {
745             throw new IllegalArgumentException JavaDoc("Class is not mapped with Cayenne: "
746                     + objectClass.getName());
747         }
748
749         DataObject dataObject = null;
750         try {
751             dataObject = (DataObject) objectClass.newInstance();
752         }
753         catch (Exception JavaDoc ex) {
754             throw new CayenneRuntimeException("Error instantiating object.", ex);
755         }
756
757         registerNewObjectWithEntity(dataObject, entity);
758         return dataObject;
759     }
760
761
762     /**
763      * Registers a new object (that is not yet persistent) with itself.
764      *
765      * @param dataObject new object that we want to make persistent.
766      */

767     public void registerNewObject(DataObject dataObject) {
768         if (dataObject == null) {
769             throw new NullPointerException JavaDoc("Can't register null object.");
770         }
771
772         // sanity check - maybe already registered
773
if (dataObject.getObjectId() != null) {
774             if (dataObject.getDataContext() == this) {
775                 // already registered, just ignore
776
return;
777             }
778             else if (dataObject.getDataContext() != null) {
779                 throw new IllegalStateException JavaDoc(
780                         "DataObject is already registered with another DataContext. Try using 'localObjects()' instead.");
781             }
782         }
783
784         ObjEntity entity = getEntityResolver().lookupObjEntity(dataObject);
785         if (entity == null) {
786             throw new IllegalArgumentException JavaDoc(
787                     "Can't find ObjEntity for DataObject class: "
788                             + dataObject.getClass().getName()
789                             + ", class is likely not mapped.");
790         }
791
792         registerNewObjectWithEntity(dataObject, entity);
793     }
794
795     private void registerNewObjectWithEntity(DataObject dataObject, ObjEntity objEntity) {
796         // method is private ... assuming all sanity checks on the DataObject have been
797
// performed by the caller depending on the inocation context
798

799         if (dataObject.getObjectId() == null) {
800             dataObject.setObjectId(new TempObjectId(dataObject.getClass()));
801         }
802
803         // initialize to-many relationships with a fault
804
Iterator JavaDoc it = objEntity.getRelationships().iterator();
805         while (it.hasNext()) {
806             ObjRelationship rel = (ObjRelationship) it.next();
807             if (rel.isToMany()) {
808                 dataObject.writePropertyDirectly(rel.getName(), Fault.getToManyFault());
809             }
810         }
811
812         getObjectStore().addObject(dataObject);
813         dataObject.setDataContext(this);
814         dataObject.setPersistenceState(PersistenceState.NEW);
815     }
816
817     /**
818      * Unregisters a Collection of DataObjects from the DataContext and the underlying
819      * ObjectStore. This operation also unsets DataContext and ObjectId for each object
820      * and changes its state to TRANSIENT.
821      */

822     public void unregisterObjects(Collection JavaDoc dataObjects) {
823         getObjectStore().objectsUnregistered(dataObjects);
824     }
825
826     /**
827      * "Invalidates" a Collection of DataObject. This operation would remove each object's
828      * snapshot from cache and change object's state to HOLLOW. On the next access to this
829      * object, it will be refetched.
830      */

831     public void invalidateObjects(Collection JavaDoc dataObjects) {
832         getObjectStore().objectsInvalidated(dataObjects);
833     }
834
835     /**
836      * Schedules all objects in the collection for deletion on the next commit of this
837      * DataContext. Object's persistence state is changed to PersistenceState.DELETED;
838      * objects related to this object are processed according to delete rules, i.e.
839      * relationships can be unset ("nullify" rule), deletion operation is cascaded
840      * (cascade rule).
841      * <p>
842      * <i>"Nullify" delete rule side effect: </i> passing a collection representing
843      * to-many relationship with nullify delete rule may result in objects being removed
844      * from collection.
845      * </p>
846      *
847      * @since 1.2
848      */

849     public void deleteObjects(Collection JavaDoc objects) {
850         if (objects.isEmpty()) {
851             return;
852         }
853         
854         // clone object list... this maybe a relationship collection with nullify delete
855
// rule, so modifying
856
Iterator JavaDoc it = new ArrayList JavaDoc(objects).iterator();
857         while (it.hasNext()) {
858             DataObject object = (DataObject) it.next();
859             deleteObject(object);
860         }
861     }
862     
863     /**
864      * Schedules an object for deletion on the next commit of this DataContext. Object's
865      * persistence state is changed to PersistenceState.DELETED; objects related to this object
866      * are processed according to delete rules, i.e. relationships can be unset ("nullify" rule),
867      * deletion operation is cascaded (cascade rule).
868      *
869      * @param object data object that we want to delete.
870      * @throws DeleteDenyException if a DENY delete rule is applicable for object deletion.
871      * @throws NullPointerException if object is null.
872      */

873     public void deleteObject(DataObject object) throws DeleteDenyException {
874         new DataContextDeleteAction(this).performDelete(object);
875     }
876
877     /**
878      * Refetches object data for ObjectId. This method is used internally by Cayenne to
879      * resolve objects in state <code>PersistenceState.HOLLOW</code>. It can also be
880      * used to refresh certain objects.
881      *
882      * @throws CayenneRuntimeException if object id doesn't match any records, or if there
883      * is more than one object is fetched.
884      */

885     public DataObject refetchObject(ObjectId oid) {
886
887         if (oid == null) {
888             throw new NullPointerException JavaDoc("Null ObjectId");
889         }
890
891         if (oid.isTemporary()) {
892             throw new CayenneRuntimeException("Can't refetch ObjectId "
893                     + oid
894                     + ", as it is a temporary id.");
895         }
896
897         synchronized (getObjectStore()) {
898             DataObject object = objectStore.getObject(oid);
899
900             // clean up any cached data for this object
901
if (object != null) {
902                 this.invalidateObjects(Collections.singleton(object));
903             }
904         }
905
906         SelectQuery sel = QueryUtils.selectObjectForId(oid);
907         List JavaDoc results = this.performQuery(sel);
908
909         if (results.size() != 1) {
910             String JavaDoc msg = (results.size() == 0)
911                     ? "Refetch failure: no matching objects found for ObjectId " + oid
912                     : "Refetch failure: more than 1 object found for ObjectId "
913                             + oid
914                             + ". Fetch matched "
915                             + results.size()
916                             + " objects.";
917
918             throw new CayenneRuntimeException(msg);
919         }
920
921         return (DataObject) results.get(0);
922     }
923
924     /**
925      * Returns a DataNode that should hanlde queries for all DataMap components.
926      *
927      * @since 1.1
928      */

929     public DataNode lookupDataNode(DataMap dataMap) {
930         if (this.getParent() == null) {
931             throw new CayenneRuntimeException("Cannot use a DataContext without a parent");
932         }
933         return this.getParent().lookupDataNode(dataMap);
934     }
935
936     /**
937      * Reverts any changes that have occurred to objects registered with DataContext.
938      */

939     public void rollbackChanges() {
940         getObjectStore().objectsRolledBack();
941     }
942
943     /**
944      * Synchronizes object graph with the database. Executes needed insert, update and
945      * delete queries (generated internally).
946      */

947     public void commitChanges() throws CayenneRuntimeException {
948         commitChanges(null);
949     }
950
951     /**
952      * Synchronizes object graph with the database. Executes needed insert, update and
953      * delete queries (generated internally).
954      *
955      * @param logLevel if logLevel is higher or equals to the level set for QueryLogger,
956      * statements execution will be logged.
957      */

958     public void commitChanges(Level logLevel) throws CayenneRuntimeException {
959
960         if (this.getParent() == null) {
961             throw new CayenneRuntimeException("Cannot use a DataContext without a parent");
962         }
963
964         // prevent multiple commits occuring simulteneously
965
synchronized (getObjectStore()) {
966             // is there anything to do?
967
if (!this.hasChanges()) {
968                 return;
969             }
970
971             if (isValidatingObjectsOnCommit()) {
972                 getObjectStore().validateUncommittedObjects();
973             }
974
975             DataContextCommitAction worker = new DataContextCommitAction(this);
976
977             try {
978                 worker.commit(logLevel);
979             }
980             catch (CayenneException ex) {
981                 Throwable JavaDoc unwound = Util.unwindException(ex);
982
983                 if (unwound instanceof CayenneRuntimeException) {
984                     throw (CayenneRuntimeException) unwound;
985                 }
986                 else {
987                     throw new CayenneRuntimeException("Commit Exception", unwound);
988                 }
989             }
990         }
991     }
992
993     /**
994      * Performs a single database query that does not select rows. Returns an array of
995      * update counts.
996      *
997      * @since 1.1
998      */

999     public int[] performNonSelectingQuery(Query query) {
1000        QueryResult result = new QueryResult();
1001        performQueries(Collections.singletonList(query), result);
1002        List JavaDoc updateCounts = result.getUpdates(query);
1003
1004        if (updateCounts == null || updateCounts.isEmpty()) {
1005            return new int[0];
1006        }
1007
1008        int len = updateCounts.size();
1009        int[] counts = new int[len];
1010
1011        for (int i = 0; i < len; i++) {
1012            counts[i] = ((Number JavaDoc) updateCounts.get(i)).intValue();
1013        }
1014
1015        return counts;
1016    }
1017
1018    /**
1019     * Performs a named mapped query that does not select rows. Returns an array of update
1020     * counts.
1021     *
1022     * @since 1.1
1023     */

1024    public int[] performNonSelectingQuery(String JavaDoc queryName) {
1025        return performNonSelectingQuery(queryName, Collections.EMPTY_MAP);
1026    }
1027
1028    /**
1029     * Performs a named mapped non-selecting query using a map of parameters. Returns an
1030     * array of update counts.
1031     *
1032     * @since 1.1
1033     */

1034    public int[] performNonSelectingQuery(String JavaDoc queryName, Map JavaDoc parameters) {
1035        // find query...
1036
Query query = getEntityResolver().getQuery(queryName);
1037        if (query == null) {
1038            throw new CayenneRuntimeException("There is no saved query for name '"
1039                    + queryName
1040                    + "'.");
1041        }
1042
1043        if (parameters != null
1044                && !parameters.isEmpty()
1045                && query instanceof ParameterizedQuery) {
1046            query = ((ParameterizedQuery) query).createQuery(parameters);
1047        }
1048
1049        return performNonSelectingQuery(query);
1050    }
1051
1052    /**
1053     * Performs a single database select query returning result as a ResultIterator.
1054     * Returned ResultIterator will provide access to DataRows.
1055     */

1056    public ResultIterator performIteratedQuery(GenericSelectQuery query)
1057            throws CayenneException {
1058
1059        IteratedSelectObserver observer = new IteratedSelectObserver();
1060        observer.setLoggingLevel(query.getLoggingLevel());
1061        performQueries(Collections.singletonList(query), observer);
1062        return observer.getResultIterator();
1063    }
1064
1065    /**
1066     * Delegates queries execution to parent QueryEngine. If there are select queries that
1067     * require prefetching relationships, will create additional queries to perform
1068     * necessary prefetching.
1069     */

1070    public void performQueries(Collection JavaDoc queries, OperationObserver observer) {
1071        // note - use external transaction for iterated queries;
1072
// other types of transactions won't be safe in this case
1073
Transaction transaction = (observer.isIteratedResult())
1074                ? Transaction.externalTransaction(getParentDataDomain()
1075                        .getTransactionDelegate())
1076                : getParentDataDomain().createTransaction();
1077
1078        transaction.performQueries(this, queries, observer);
1079    }
1080
1081    /**
1082     * Delegates queries execution to parent QueryEngine.
1083     *
1084     * @since 1.1
1085     */

1086    public void performQueries(
1087            Collection JavaDoc queries,
1088            OperationObserver resultConsumer,
1089            Transaction transaction) {
1090
1091        if (this.getParent() == null) {
1092            throw new CayenneRuntimeException("Cannot use a DataContext without a parent");
1093        }
1094
1095        DataContextDelegate localDelegate = nonNullDelegate();
1096        List JavaDoc finalQueries = new ArrayList JavaDoc(queries.size());
1097
1098        Iterator JavaDoc it = queries.iterator();
1099        while (it.hasNext()) {
1100            Object JavaDoc query = it.next();
1101
1102            if (query instanceof GenericSelectQuery) {
1103                GenericSelectQuery genericSelect = (GenericSelectQuery) query;
1104
1105                // filter via a delegate
1106
GenericSelectQuery filteredSelect = localDelegate.willPerformSelect(
1107                        this,
1108                        genericSelect);
1109
1110                // suppressed by the delegate
1111
if (filteredSelect != null) {
1112                    finalQueries.add(filteredSelect);
1113                }
1114            }
1115            else {
1116                finalQueries.add(query);
1117            }
1118        }
1119
1120        this.getParent().performQueries(finalQueries, resultConsumer, transaction);
1121    }
1122
1123    /**
1124     * Performs prefetching. Prefetching would resolve a set of relationships for a list
1125     * of DataObjects in the most optimized way (preferrably in a single query per
1126     * relationship).
1127     * <p>
1128     * <i>WARNING: Currently supports only "one-step" to one relationships. This is an
1129     * arbitrary limitation and will be removed eventually. </i>
1130     * </p>
1131     */

1132    public void prefetchRelationships(SelectQuery query, List JavaDoc objects) {
1133        Collection JavaDoc prefetches = query.getPrefetches();
1134
1135        if (objects == null || objects.size() == 0 || prefetches.size() == 0) {
1136            return;
1137        }
1138
1139        ObjEntity entity = getEntityResolver().lookupObjEntity(query);
1140        Iterator JavaDoc prefetchesIt = prefetches.iterator();
1141        while (prefetchesIt.hasNext()) {
1142            String JavaDoc prefetchKey = (String JavaDoc) prefetchesIt.next();
1143            if (prefetchKey.indexOf(Entity.PATH_SEPARATOR) >= 0) {
1144                throw new CayenneRuntimeException("Only one-step relationships are "
1145                        + "supported at the moment, this will be fixed soon. "
1146                        + "Unsupported path : "
1147                        + prefetchKey);
1148            }
1149
1150            ObjRelationship relationship = (ObjRelationship) entity
1151                    .getRelationship(prefetchKey);
1152            if (relationship == null) {
1153                throw new CayenneRuntimeException("Invalid relationship: " + prefetchKey);
1154            }
1155
1156            if (relationship.isToMany()) {
1157                throw new CayenneRuntimeException(
1158                        "Only to-one relationships are supported at the moment. "
1159                                + "Can't prefetch to-many: "
1160                                + prefetchKey);
1161            }
1162
1163            PrefetchHelper.resolveToOneRelations(this, objects, prefetchKey);
1164        }
1165
1166    }
1167
1168    /**
1169     * Performs a single selecting query. If if query is a SelectQuery that require
1170     * prefetching relationships, will create additional queries to perform necessary
1171     * prefetching. Various query setting control the behavior of this method and the
1172     * results returned:
1173     * <ul>
1174     * <li>Query caching policy defines whether the results are retrieved from cache or
1175     * fetched from the database. Note that queries that use caching must have a name that
1176     * is used as a caching key.</li>
1177     * <li>Query refreshing policy controls whether to refresh existing data objects and
1178     * ignore any cached values.</li>
1179     * <li>Query data rows policy defines whether the result should be returned as
1180     * DataObjects or DataRows.</li>
1181     * </ul>
1182     *
1183     * @return A list of DataObjects or a DataRows, depending on the value returned by
1184     * {@link GenericSelectQuery#isFetchingDataRows()}.
1185     */

1186    public List JavaDoc performQuery(GenericSelectQuery query) {
1187        return new DataContextSelectAction(this).performQuery(query);
1188    }
1189
1190    /**
1191     * Returns a list of objects or DataRows for a named query stored in one of the
1192     * DataMaps. Internally Cayenne uses a caching policy defined in the named query. If
1193     * refresh flag is true, a refresh is forced no matter what the caching policy is.
1194     *
1195     * @param queryName a name of a GenericSelectQuery defined in one of the DataMaps. If
1196     * no such query is defined, this method will throw a
1197     * CayenneRuntimeException.
1198     * @param refresh A flag that determines whether refresh is required in case a query
1199     * uses caching.
1200     * @since 1.1
1201     */

1202    public List JavaDoc performQuery(String JavaDoc queryName, boolean refresh) {
1203        return performQuery(queryName, Collections.EMPTY_MAP, refresh);
1204    }
1205
1206    /**
1207     * Returns a list of objects or DataRows for a named query stored in one of the
1208     * DataMaps. Internally Cayenne uses a caching policy defined in the named query. If
1209     * refresh flag is true, a refresh is forced no matter what the caching policy is.
1210     *
1211     * @param queryName a name of a GenericSelectQuery defined in one of the DataMaps. If
1212     * no such query is defined, this method will throw a
1213     * CayenneRuntimeException.
1214     * @param parameters A map of parameters to use with stored query.
1215     * @param refresh A flag that determines whether refresh is required in case a query
1216     * uses caching.
1217     * @since 1.1
1218     */

1219    public List JavaDoc performQuery(String JavaDoc queryName, Map JavaDoc parameters, boolean refresh) {
1220        // find query...
1221
Query query = getEntityResolver().getQuery(queryName);
1222        if (query == null) {
1223            throw new CayenneRuntimeException("There is no saved query for name '"
1224                    + queryName
1225                    + "'.");
1226        }
1227
1228        // for SelectQuery we must always run parameter substitution as the query
1229
// in question might have unbound values in the qualifier... that's a bit
1230
// inefficient... any better ideas to determine whether we can skip parameter
1231
// processing?
1232

1233        // another side effect from NOT substituting parameters is that caching key of the
1234
// final query will be that of the original query... thus parameters vs. no
1235
// paramete will result in inconsistent caching behavior.
1236

1237        if (query instanceof SelectQuery) {
1238            SelectQuery select = (SelectQuery) query;
1239            if (select.getQualifier() != null) {
1240                query = select.createQuery(parameters != null
1241                        ? parameters
1242                        : Collections.EMPTY_MAP);
1243            }
1244        }
1245        else if (parameters != null
1246                && !parameters.isEmpty()
1247                && query instanceof ParameterizedQuery) {
1248            query = ((ParameterizedQuery) query).createQuery(parameters);
1249        }
1250
1251        if (!(query instanceof GenericSelectQuery)) {
1252            throw new CayenneRuntimeException("Query for name '"
1253                    + queryName
1254                    + "' is not a GenericSelectQuery: "
1255                    + query);
1256        }
1257
1258        return new DataContextSelectAction(this).performQuery((GenericSelectQuery) query, query
1259                .getName(), refresh);
1260    }
1261
1262
1263
1264    // serialization support
1265
private void writeObject(ObjectOutputStream JavaDoc out) throws IOException JavaDoc {
1266        out.defaultWriteObject();
1267
1268        // If the "parent" of this datacontext is a DataDomain, then just write the
1269
// name of it. Then when deserialization happens, we can get back the DataDomain
1270
// by name,
1271
// from the shared configuration (which will either load it if need be, or return
1272
// an existing one.
1273

1274        if (this.parent == null && this.lazyInitParentDomainName != null) {
1275            out.writeObject(lazyInitParentDomainName);
1276        }
1277        else if (this.parent instanceof DataDomain) {
1278            DataDomain domain = (DataDomain) this.parent;
1279            out.writeObject(domain.getName());
1280        }
1281        else {
1282            // Hope that whatever this.parent is, that it is Serializable
1283
out.writeObject(this.parent);
1284        }
1285
1286        // Serialize local snapshots cache
1287
if (!isUsingSharedSnapshotCache()) {
1288            out.writeObject(objectStore.getDataRowCache());
1289        }
1290    }
1291
1292    //serialization support
1293
private void readObject(ObjectInputStream JavaDoc in) throws IOException JavaDoc,
1294            ClassNotFoundException JavaDoc {
1295
1296        // 1. read non-transient properties
1297
in.defaultReadObject();
1298
1299        // 2. read parent or its name
1300
Object JavaDoc value = in.readObject();
1301        if (value instanceof QueryEngine) {
1302            // A real QueryEngine object - use it
1303
this.parent = (QueryEngine) value;
1304        }
1305        else if (value instanceof String JavaDoc) {
1306            // The name of a DataDomain - use it
1307
this.lazyInitParentDomainName = (String JavaDoc) value;
1308        }
1309        else {
1310            throw new CayenneRuntimeException(
1311                    "Parent attribute of DataContext was neither a QueryEngine nor "
1312                            + "the name of a valid DataDomain:"
1313                            + value);
1314        }
1315
1316        // 3. Deserialize local snapshots cache
1317
if (!isUsingSharedSnapshotCache()) {
1318            DataRowStore cache = (DataRowStore) in.readObject();
1319            objectStore.setDataRowCache(cache);
1320        }
1321
1322        // CayenneDataObjects have a transient datacontext
1323
// because at deserialize time the datacontext may need to be different
1324
// than the one at serialize time (for programmer defined reasons).
1325
// So, when a dataobject is resurrected because it's datacontext was
1326
// serialized, it will then set the objects datacontext to the correctone
1327
// If deserialized "otherwise", it will not have a datacontext (good)
1328

1329        synchronized (getObjectStore()) {
1330            Iterator JavaDoc it = objectStore.getObjectIterator();
1331            while (it.hasNext()) {
1332                DataObject object = (DataObject) it.next();
1333                object.setDataContext(this);
1334            }
1335        }
1336    }
1337
1338    /**
1339     * Returns EntityResolver object used to resolve and route queries.
1340     */

1341    public EntityResolver getEntityResolver() {
1342        if (this.getParent() == null) {
1343            throw new CayenneRuntimeException("Cannot use a DataContext without a parent");
1344        }
1345        return this.getParent().getEntityResolver();
1346    }
1347
1348    /**
1349     * Sets default for posting transaction events by new DataContexts.
1350     */

1351    public static void setTransactionEventsEnabledDefault(boolean flag) {
1352        transactionEventsEnabledDefault = flag;
1353    }
1354
1355    /**
1356     * Enables or disables posting of transaction events by this DataContext.
1357     */

1358    public void setTransactionEventsEnabled(boolean flag) {
1359        this.transactionEventsEnabled = flag;
1360    }
1361
1362    public boolean isTransactionEventsEnabled() {
1363        return this.transactionEventsEnabled;
1364    }
1365
1366    /**
1367     * Returns <code>true</code> if the ObjectStore uses shared cache of a parent
1368     * DataDomain.
1369     *
1370     * @since 1.1
1371     */

1372    public boolean isUsingSharedSnapshotCache() {
1373        return usingSharedSnaphsotCache;
1374    }
1375
1376    /**
1377     * Returns whether this DataContext performs object validation before commit is
1378     * executed.
1379     *
1380     * @since 1.1
1381     */

1382    public boolean isValidatingObjectsOnCommit() {
1383        return validatingObjectsOnCommit;
1384    }
1385
1386    /**
1387     * Sets the property defining whether this DataContext should perform object
1388     * validation before commit is executed.
1389     *
1390     * @since 1.1
1391     */

1392    public void setValidatingObjectsOnCommit(boolean flag) {
1393        this.validatingObjectsOnCommit = flag;
1394    }
1395
1396    public Collection JavaDoc getDataMaps() {
1397        return (parent != null) ? parent.getDataMaps() : Collections.EMPTY_LIST;
1398    }
1399
1400    void fireWillCommit() {
1401        // post event: WILL_COMMIT
1402
if (this.transactionEventsEnabled) {
1403            EventManager eventMgr = EventManager.getDefaultManager();
1404            DataContextEvent commitChangesEvent = new DataContextEvent(this);
1405            eventMgr.postEvent(commitChangesEvent, DataContext.WILL_COMMIT);
1406        }
1407    }
1408
1409    void fireTransactionRolledback() {
1410        // post event: DID_ROLLBACK
1411
if ((this.transactionEventsEnabled)) {
1412            EventManager eventMgr = EventManager.getDefaultManager();
1413            DataContextEvent commitChangesEvent = new DataContextEvent(this);
1414            eventMgr.postEvent(commitChangesEvent, DataContext.DID_ROLLBACK);
1415        }
1416    }
1417
1418    void fireTransactionCommitted() {
1419        // post event: DID_COMMIT
1420
if ((this.transactionEventsEnabled)) {
1421            EventManager eventMgr = EventManager.getDefaultManager();
1422            DataContextEvent commitChangesEvent = new DataContextEvent(this);
1423            eventMgr.postEvent(commitChangesEvent, DataContext.DID_COMMIT);
1424        }
1425    }
1426}
Popular Tags