KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > genimen > djeneric > repository > DjSession


1 /*
2  * Copyright (c) 2001-2005 by Genimen BV (www.genimen.com) All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, is permitted provided that the following conditions are met: -
6  * Redistributions of source code must retain the above copyright notice, this
7  * list of conditions and the following disclaimer. - Redistributions in binary
8  * form must reproduce the above copyright notice, this list of conditions and
9  * the following disclaimer in the documentation and/or other materials
10  * provided with the distribution. - All advertising materials mentioning
11  * features or use of this software must display the following acknowledgment:
12  * "This product includes Djeneric." - Products derived from this software may
13  * not be called "Djeneric" nor may "Djeneric" appear in their names without
14  * prior written permission of Genimen BV. - Redistributions of any form
15  * whatsoever must retain the following acknowledgment: "This product includes
16  * Djeneric."
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS "AS IS"
19  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21  * ARE DISCLAIMED. IN NO EVENT SHALL GENIMEN BV, DJENERIC.ORG, OR CONTRIBUTORS
22  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28  * POSSIBILITY OF SUCH DAMAGE.
29  */

30 package com.genimen.djeneric.repository;
31
32 import java.util.HashMap JavaDoc;
33
34 import com.genimen.djeneric.language.Messages;
35 import com.genimen.djeneric.repository.exceptions.CatalogException;
36 import com.genimen.djeneric.repository.exceptions.DjenericException;
37 import com.genimen.djeneric.repository.exceptions.ObjectNotDefinedException;
38 import com.genimen.djeneric.repository.exceptions.RestrictionFailedException;
39 import com.genimen.djeneric.util.DjLogger;
40
41 /**
42  * A session holds the Unit Of Work and is the boundary for transactions.
43  * Beware: this class is not thread safe because concrete implementations
44  * may use database connections. This is especially true if you call the
45  * releaseDatasources() method since you might release a connection in the
46  * middle of commit processing in case of multi threading.
47  *
48  * @author Wido Riezebos @created 27 mei 2002
49  */

50 public abstract class DjSession
51 {
52   /**
53    * Applies all changes in the session to the database and performs a commit
54    *
55    * @exception DjenericException
56    */

57   public abstract void commit() throws DjenericException;
58
59   /**
60    * Closes (and thus invalidates) the session. No commit is performed so any uncommitted changes will be lost
61    */

62   public abstract void close();
63
64   /**
65    * Releases any associated connections (if any).
66    * You typically call this method in a web environment after you are done with your
67    * request processing (releasing expensive resources)
68    * Do not call this method if you have cursors open since they will become invalid.
69    * New datasources will be aquired automatically by the session (when needed) after which
70    * you should call this method again.
71    *
72    * This method has no effect on the state of objects in the session and thus can be called
73    * safely at any time as long as you are not using connections and cursors at the moment of
74    * the call.
75    *
76    */

77   public abstract void releaseDatasources();
78
79   /**
80    * Creates a new object of the type as defined by the given extent
81    */

82   public abstract DjObject createObject(DjExtent extent) throws DjenericException;
83
84   /**
85    * Returns the object of the given type with the specified (object) id.
86    *
87    * @param extent
88    * The extent to search for the specified object id
89    * @param id
90    * The object id
91    * @return The object
92    * @exception DjenericException
93    * If the object if not found a ObjectNotDefinedException is thrown
94    */

95   public abstract DjObject getObject(DjExtent extent, long id) throws DjenericException;
96
97   /**
98    * Returns all objects stored in the extent in a list
99    *
100    * @param extent
101    * The extent containing the objects to return
102    * @return The list of objects
103    * @exception DjenericException
104    */

105   public abstract DjList getObjects(DjExtent extent, boolean forceReloadFromDB) throws DjenericException;
106
107   /**
108    * Returns the list of objects that match the criteria as specified by the matcher (i.e. a QBE of OQL)
109    *
110    * @param matcher
111    * Specifies what objects to return
112    * @param forceReloadFromDB
113    * If true all objects that are present in the session (and might have been
114    * modified) will be reloaded from the database
115    * @return The list of objects
116    * @exception DjenericException
117    */

118   public abstract DjList getObjects(DjObjectMatcher matcher, boolean forceReloadFromDB) throws DjenericException;
119
120   /**
121    * Returns all objects stored in the extent in a cursor.
122    *
123    * @param extent
124    * The extent containing the objects to return
125    * @param forceReloadFromDB
126    * If true all objects that are present in the session (and might have been
127    * modified) will be reloaded from the database
128    * @return The list of objects
129    * @exception DjenericException
130    */

131   public abstract DjCursor getObjectsCursor(DjExtent ext, boolean forceReloadFromDB) throws DjenericException;
132
133   /**
134    * Returns a cursor for objects that match the criteria as specified by the matcher (i.e. a QBE of OQL)
135    *
136    * @param matcher
137    * Specifies what objects to return
138    * @param forceReloadFromDB
139    * If true all objects that are present in the session (and might have been
140    * modified) will be reloaded from the database
141    * @return The cursor
142    * @exception DjenericException
143    */

144   public abstract DjCursor getObjectsCursor(DjObjectMatcher matcher, boolean forceReloadFromDB)
145       throws DjenericException;
146
147   protected abstract void addValidMasterObjects(DjExtent masterExtent, long restrictingOid,
148                                                 String JavaDoc restrictingPropertyName, boolean forceReloadFromDB,
149                                                 DjList results) throws DjenericException;
150
151   /////////////////////////////////////////////////////////////////////
152

153   DjPersistenceManager _mgr;
154   HashMap JavaDoc _registeredValidValueLists = new HashMap JavaDoc();
155
156   boolean _invalid = false;
157   DjList _modifiedObjects = new DjList();
158   DjObjectCache _sessionCache = new DjObjectCache();
159   boolean _validateObjectsAfterLoading = true;
160
161   private boolean _commitAllowed = true;
162   private long _nextTransientObjectId;
163   private Boolean JavaDoc _canCreate = null;
164   private Boolean JavaDoc _canDelete = null;
165   private Boolean JavaDoc _canModify = null;
166   private Boolean JavaDoc _canQuery = null;
167
168   /**
169    * Constructor for the DjSession object
170    *
171    * @param mgr
172    * Description of the Parameter
173    */

174   protected DjSession(DjPersistenceManager mgr)
175   {
176     _mgr = mgr;
177     if (shouldTrace(DjPersistenceManager.TRACE_FLOW)) trace("Session created");
178   }
179
180   public boolean canCreate() throws DjenericException
181   {
182     if (_canCreate == null)
183     {
184       DjContext ctxt = getPersistenceManager().getCurrentContext();
185       DjUser user = getPersistenceManager().getCurrentUser();
186       _canCreate = new Boolean JavaDoc(user.canCreate(ctxt));
187     }
188     return _canCreate.booleanValue();
189   }
190
191   public boolean canDelete() throws DjenericException
192   {
193     if (_canDelete == null)
194     {
195       DjContext ctxt = getPersistenceManager().getCurrentContext();
196       DjUser user = getPersistenceManager().getCurrentUser();
197       _canDelete = new Boolean JavaDoc(user.canDelete(ctxt));
198     }
199     return _canDelete.booleanValue();
200   }
201
202   public boolean canModify() throws DjenericException
203   {
204     if (_canModify == null)
205     {
206       DjContext ctxt = getPersistenceManager().getCurrentContext();
207       DjUser user = getPersistenceManager().getCurrentUser();
208       _canModify = new Boolean JavaDoc(user.canModify(ctxt));
209     }
210     return _canModify.booleanValue();
211   }
212
213   public boolean canQuery() throws DjenericException
214   {
215     if (_canQuery == null)
216     {
217       DjContext ctxt = getPersistenceManager().getCurrentContext();
218       DjUser user = getPersistenceManager().getCurrentUser();
219       _canQuery = new Boolean JavaDoc(user.canQuery(ctxt));
220     }
221     return _canQuery.booleanValue();
222   }
223
224   /**
225    * Returns a Query by Example object for user with the specified extent
226    *
227    * @param extent
228    * The extent the QBE is for
229    * @return The QBE object
230    * @exception DjenericException
231    * Description of the Exception
232    */

233   public DjQueryByExample createQueryByExample(DjExtent extent) throws DjenericException
234   {
235     return new DjQueryByExample(this, extent);
236   }
237
238   /**
239    * Returns an OQL object that will handle the specified Java like where clause. Use || or && for logic and the normal
240    * operators like ==, >= etc. for comparison Further more is null and is not null is supported for comparing values
241    * with null Walking a path (concatenating properties) is supported and effectively will result in a join of undelying
242    * tables. Example of a where clause: editor.seq == 10 && application.name == "Main" || accept == "Y"
243    *
244    * @param extent
245    * The extent the OQL is for
246    * @param whereExpression
247    * The expression where you compare properties
248    * @return Description of the Return Value
249    * @exception DjenericException
250    * Description of the Exception
251    */

252   public DjOql createOql(DjExtent extent)
253   {
254     return new DjOql(extent);
255   }
256
257   /**
258    * Returns an OQL object that will handle the specified Java like where clause. Use || or && for logic and the normal
259    * operators like ==, >= etc. for comparison Further more is null and is not null is supported for comparing values
260    * with null Walking a path (concatenating properties) is supported and effectively will result in a join of undelying
261    * tables. Example of a where clause: editor.seq == 10 && application.name == "Main" || accept == "Y"
262    *
263    * @param extent
264    * The extent the OQL is for
265    * @param whereExpression
266    * The expression where you compare properties
267    * @return Description of the Return Value
268    * @exception DjenericException
269    * Description of the Exception
270    */

271   public DjOql createOql(DjExtent extent, String JavaDoc whereExpression)
272   {
273     return new DjOql(extent, whereExpression);
274   }
275
276   /**
277    * Creates a DjQueryByExample object that can be used to perform QBE like queries.
278    *
279    * @param objectType
280    * The type of objects the QBE should return
281    * @return The QBE object
282    * @exception DjenericException
283    */

284   public DjQueryByExample createQueryByExample(String JavaDoc objectType) throws DjenericException
285   {
286     return new DjQueryByExample(this, objectType);
287   }
288
289   /**
290    * Sets the commitAllowed of the DjSession. If commit is not allowed the session will be
291    * read-only for as far as the databse is concerned
292    *
293    * @param b
294    *
295    */

296   public void setCommitAllowed(boolean b)
297   {
298     _commitAllowed = b;
299   }
300
301   /**
302    * Returns true if the session can be committen to the database
303    */

304   public boolean isCommitAllowed()
305   {
306     return _commitAllowed;
307   }
308
309   /**
310    * When true all objects will be validated after loading them from the repository.
311    * When set to true ypu can be sure that when working woth objects all properties
312    * are set (if required) and contain valid values according to the domain definition.
313    * When set to false committing changes might fail because of invalid objects that
314    * might have been loaded into the session
315    */

316   public void setValidateObjectsAfterLoading(boolean b)
317   {
318     _validateObjectsAfterLoading = b;
319   }
320
321   /**
322    * Returns true when objects are to be validated after loading them into the session
323    */

324   public boolean shouldValidateObjectsAfterLoading()
325   {
326     return _validateObjectsAfterLoading;
327   }
328
329   /**
330    * Returns true if the session is valid (i.e. not closed) for normal use
331    */

332   public boolean isValid()
333   {
334     return !_invalid;
335   }
336
337   /**
338    * Can be used to invalidate a session so that no changes or transactions can occur
339    * in a session (anymore)
340    */

341   public void setValid(boolean b)
342   {
343     _invalid = !b;
344   }
345
346   /**
347    * Returns the list of objects that were modified since the last commit
348    *
349    * @return The list of objects that were modified
350    */

351   protected DjList getModifiedObjects()
352   {
353     return _modifiedObjects;
354   }
355
356   /**
357    * Returns the persistence manager that is associated with this session
358    *
359    * @return The persistenceManager value
360    */

361   public DjPersistenceManager getPersistenceManager()
362   {
363     return _mgr;
364   }
365
366   /**
367    * Writes a message to the trace log (e.g. console)
368    */

369   public void trace(String JavaDoc msg)
370   {
371     _mgr.trace(msg);
372   }
373
374   /**
375    * Determines wheter the given level is high enough to write trace messages (according
376    * to the trace level as set by the persistence manager
377    */

378   public boolean shouldTrace(int level)
379   {
380     return _mgr.shouldTrace(level);
381   }
382
383   /**
384    * Reset will remove any objects registered to this session.
385    * This effectively will undo any changes that have not been committed yet
386    * It will also make sure that objects retrieved from the session are 'fresh'
387    * in the sense that they will be fetched from the database now.
388    */

389   public void reset()
390   {
391     // release some memory now
392

393     _modifiedObjects.clear();
394     _sessionCache.clear();
395     if (shouldTrace(DjPersistenceManager.TRACE_INTERNAL)) trace("Session reset");
396   }
397
398   /**
399    * Places an object into the cache. You schould normally never have to use this method
400    */

401   public void cacheObject(DjObject po) throws DjenericException
402   {
403     if (_invalid) throw new DjenericException(Messages.getString("global.SessionClosed"));
404     _sessionCache.cache(po);
405   }
406
407   private void addToModifiedList(DjObject po) throws DjenericException
408   {
409     if (_invalid) throw new DjenericException(Messages.getString("global.SessionClosed"));
410     if (!_modifiedObjects.contains(po)) _modifiedObjects.add(po);
411     cacheObject(po);
412   }
413
414   private void removeFromModifiedList(DjObject po) throws DjenericException
415   {
416     _modifiedObjects.remove(po);
417     // Make sure it is found in the cache later on
418
cacheObject(po);
419   }
420
421   /**
422    * Removes an object from the modified objects list; this effectively excludes the object
423    * from the commit algorithm; unless it is part of a master-detail chain.
424    *
425    * @param po
426    * Description of the Parameter
427    * @exception DjenericException
428    * Description of the Exception
429    */

430   public void unregisterDjenericObject(DjObject po) throws DjenericException
431   {
432     if (_invalid) throw new DjenericException(Messages.getString("global.SessionClosed"));
433
434     removeFromModifiedList(po);
435     _sessionCache.remove(po);
436   }
437
438   /**
439    * Returns the objects of a given extent
440    *
441    * @param objectType
442    * The name of the object type
443    * @return The objects value
444    * @exception DjenericException
445    * Description of the Exception
446    */

447   public DjList getObjects(String JavaDoc extentName) throws DjenericException
448   {
449     return getObjects(_mgr.getExtent(extentName));
450   }
451
452   /**
453    * Returns the objects stored in a given extent
454    *
455    * @param extent
456    * Description of the Parameter
457    * @return The objects value
458    * @exception DjenericException
459    * Description of the Exception
460    */

461   public DjList getObjects(DjExtent extent) throws DjenericException
462   {
463     return getObjects(extent, false);
464   }
465
466   /**
467    * Returns the objects that match the criteria as specified by the matcher
468    *
469    * @param matcher
470    * The matcher to use
471    * @return The objects value
472    * @exception DjenericException
473    * Description of the Exception
474    */

475   public DjList getObjects(DjObjectMatcher matcher) throws DjenericException
476   {
477     return getObjects(matcher, false);
478   }
479
480   /**
481    * Returns the objectsCursor for all objects in a given extent
482    *
483    * @param ext
484    * Description of the Parameter
485    * @return The objectsCursor value
486    * @exception DjenericException
487    * Description of the Exception
488    */

489   public DjCursor getObjectsCursor(DjExtent ext) throws DjenericException
490   {
491     return getObjectsCursor(ext, false);
492   }
493
494   /**
495    * Returns a cursor for the objects that match the criteria as specified by the matcher
496    *
497    * @param matcher
498    * Description of the Parameter
499    * @return The objectsCursor value
500    * @exception DjenericException
501    * Description of the Exception
502    */

503   public DjCursor getObjectsCursor(DjObjectMatcher matcher) throws DjenericException
504   {
505     return getObjectsCursor(matcher, false);
506   }
507
508   protected DjDomainValue[] getValidValues(String JavaDoc listKey)
509   {
510     return (DjDomainValue[]) _registeredValidValueLists.get(listKey);
511   }
512
513   protected void registerValidValues(String JavaDoc listKey, DjDomainValue[] valids)
514   {
515     _registeredValidValueLists.put(listKey, valids);
516   }
517
518   /**
519    * Makes sure that any chached valid value lists are flushed
520    */

521   public void resetValidValueLists()
522   {
523     _registeredValidValueLists.clear();
524   }
525
526   /**
527    * Sets the detail flag for all objects in the session. The flag will be set to true
528    * for all objects that are detail in a master-detail relationship. Note that the master
529    * must be loaded in the session also otherwise the object will not be considered a detail.
530    *
531    * @exception DjenericException
532    */

533   protected void updateDetailFlags() throws DjenericException
534   {
535     for (int i = 0; i < getModifiedObjects().size(); i++)
536     {
537       DjObject po = getModifiedObjects().getDjenericObjectAt(i);
538       po.setIsDetail(false);
539       // will be set to true by the piece of code below if actually a master:
540
}
541
542     for (int i = 0; i < getModifiedObjects().size(); i++)
543     {
544       DjObject po = getModifiedObjects().getDjenericObjectAt(i);
545       po.updateDetailFlags();
546     }
547   }
548
549   protected void updateDetailOfnewMasterFlags() throws DjenericException
550   {
551     for (int i = 0; i < getModifiedObjects().size(); i++)
552     {
553       DjObject po = getModifiedObjects().getDjenericObjectAt(i);
554       po.setDetailOfNewMaster(false);
555       // will be set to true by the piece of code below if actually a master:
556
}
557
558     for (int i = 0; i < getModifiedObjects().size(); i++)
559     {
560       DjObject po = getModifiedObjects().getDjenericObjectAt(i);
561       po.updateDetailOfnewMasterFlags();
562     }
563   }
564
565   protected void addModifiedObjectsFromSession(DjExtent thisType, DjObjectMatcher matcher, DjList toThisList,
566                                                boolean deletedObjectsToo) throws DjenericException
567   {
568     for (int i = 0; i < getModifiedObjects().size(); i++)
569     {
570       DjObject po = getModifiedObjects().getDjenericObjectAt(i);
571
572       // Check the modified flag here; be thread safe(r)
573
if (po.getExtent() == thisType && po.isModified())
574       {
575         if (deletedObjectsToo || !po.isMarkedForDelete())
576         {
577           boolean canAdd = true;
578           if (matcher != null)
579           {
580             if (!matcher.match(po)) canAdd = false;
581           }
582           if (canAdd) toThisList.add(po);
583         }
584       }
585     }
586
587     DjExtent specs[] = thisType.getSpecializations();
588     for (int i = 0; i < specs.length; i++)
589     {
590       addModifiedObjectsFromSession(specs[i], matcher, toThisList, deletedObjectsToo);
591     }
592   }
593
594   protected void addNewObjectsFromSession(DjExtent extent, String JavaDoc restrictingPropertyName, long restrictingOid,
595                                           DjList toThisList) throws DjenericException
596   {
597     int propIdx = extent.getPropertyIndex(restrictingPropertyName);
598
599     for (int i = 0; i < getModifiedObjects().size(); i++)
600     {
601       DjObject po = getModifiedObjects().getDjenericObjectAt(i);
602       if (po.getExtent() == extent && po.isNew() && po.getLong(propIdx) == restrictingOid)
603       {
604         toThisList.add(po);
605       }
606     }
607     DjExtent specs[] = extent.getSpecializations();
608     for (int i = 0; i < specs.length; i++)
609     {
610       addNewObjectsFromSession(specs[i], restrictingPropertyName, restrictingOid, toThisList);
611     }
612   }
613
614   private void addDetailsFromSession(long masterObjectId, DjExtent detailExtent, int detailPropIdx, DjList toThisList,
615                                      boolean onlyNewObjects) throws DjenericException
616   {
617     for (int i = 0; i < getModifiedObjects().size(); i++)
618     {
619       DjObject po = getModifiedObjects().getDjenericObjectAt(i);
620       if (po.getExtent() == detailExtent && (!onlyNewObjects || !po.isNew())
621           && po.getLong(detailPropIdx) == masterObjectId && !po.isMarkedForDelete())
622       {
623         toThisList.add(po);
624       }
625     }
626     DjExtent specs[] = detailExtent.getSpecializations();
627     for (int i = 0; i < specs.length; i++)
628     {
629       addDetailsFromSession(masterObjectId, specs[i], detailPropIdx, toThisList, onlyNewObjects);
630     }
631   }
632
633   private void addDetailsFromSession(DjObject master, DjRelation rel, DjExtent specificType, DjList toThisList,
634                                      boolean newObjectsOnly) throws DjenericException
635   {
636     if (!specificType.isInstanceof(rel.getDetailExtent())) throw new DjenericException("Internal error: "
637                                                                                        + specificType.getName()
638                                                                                        + " is not a "
639                                                                                        + rel.getDetailExtent()
640                                                                                            .getName());
641     int detailPropIdx = specificType.getPropertyIndex(rel.getDetailProperty().getName());
642     long masterObjectId = master.getObjectId();
643
644     addDetailsFromSession(masterObjectId, specificType, detailPropIdx, toThisList, newObjectsOnly);
645   }
646
647   protected void addNewDetailsFromSession(DjObject master, DjRelation rel, DjExtent specificType, DjList toThisList)
648       throws DjenericException
649   {
650     addDetailsFromSession(master, rel, specificType, toThisList, true);
651   }
652
653   protected void addDetailsFromSession(DjObject master, DjRelation rel, DjExtent specificType, DjList toThisList)
654       throws DjenericException
655   {
656     addDetailsFromSession(master, rel, specificType, toThisList, false);
657   }
658
659   /**
660    * Returns true if there are changes that can be applied to the database
661    *
662    * @return Description of the Return Value
663    */

664   public boolean hasOutstandingChanges()
665   {
666     for (int i = 0; i < getModifiedObjects().size(); i++)
667     {
668       DjObject po = getModifiedObjects().getDjenericObjectAt(i);
669       if (po.isModified() || po.isMarkedForDelete()) return true;
670     }
671     return false;
672   }
673
674   /**
675    * Writes the changes to the database but does not commit them
676    *
677    * @exception DjenericException
678    * Description of the Exception
679    */

680
681   protected void postChanges() throws DjenericException
682   {
683     if (shouldTrace(DjPersistenceManager.TRACE_FLOW)) trace("Session post commenced");
684     if (!isValid()) throw new DjenericException(Messages.getString("global.SessionClosed"));
685     if (!isCommitAllowed()) throw new DjenericException(Messages.getString("global.CommitNotAllowed"));
686
687     // Objects ignore subsequent applies; but we need to tell the object the
688
// first apply is about to come:
689
for (int i = 0; i < getModifiedObjects().size(); i++)
690     {
691       DjObject po = getModifiedObjects().getDjenericObjectAt(i);
692       po.notifyStartTransaction();
693     }
694
695     // Now first insert all new objects in the proper order i.e. new objects at the top
696
// level of the hierarchy should be inserted first; followed by the level directly
697
// below until all new (master) have been inserted. If this is done proceed
698
// in the master detail order
699

700     boolean doneOne;
701     do
702     {
703       doneOne = false;
704       updateDetailOfnewMasterFlags();
705
706       for (int i = 0; i < getModifiedObjects().size(); i++)
707       {
708         DjObject po = getModifiedObjects().getDjenericObjectAt(i);
709         if (po.isNew() && !po.isDetailOfNewMaster() && !po.isHitDuringCurrentTransaction())
710         {
711           po.insert();
712           doneOne = true;
713           po.setHitDuringCurrentTransaction(true);
714         }
715       }
716     }
717     while (doneOne);
718
719     // Now proceed in the master detail order
720
updateDetailFlags();
721
722     for (int i = 0; i < getModifiedObjects().size(); i++)
723     {
724       DjObject po = getModifiedObjects().getDjenericObjectAt(i);
725       // Masters will coordinate detail applies..
726
// So do NOT apply details (could be too early!)
727
if (!po.isDetail()) po.applyUpdates();
728     }
729
730     for (int i = 0; i < getModifiedObjects().size(); i++)
731     {
732       DjObject po = getModifiedObjects().getDjenericObjectAt(i);
733       // Masters will coordinate detail applies..
734
// So do NOT apply details (could be too early!)
735
if (!po.isDetail()) po.applyDeletes();
736     }
737
738     // Now apply anything that is not hit by the previous run
739
// This could be objects that are marked as detail in a cycle
740
// i.e. there is no object that is not a detail in the cycle
741
// This will probably result in a database error later on
742
// except for objects that refer to themselves
743
for (int i = 0; i < getModifiedObjects().size(); i++)
744     {
745       DjObject po = getModifiedObjects().getDjenericObjectAt(i);
746       po.applyUpdates();
747     }
748     for (int i = 0; i < getModifiedObjects().size(); i++)
749     {
750       DjObject po = getModifiedObjects().getDjenericObjectAt(i);
751       po.applyDeletes();
752     }
753
754     if (shouldTrace(DjPersistenceManager.TRACE_FLOW)) trace("Session post completed");
755   }
756
757   /**
758    * Mark all objects that were hit during the apply/commit as successfully applied so
759    * they will not be applied again by a future apply/commit.
760    *
761    * @exception DjenericException
762    */

763   protected void notifyApplySuccesfull() throws DjenericException
764   {
765     // If we got here all is stored in the repository, mark the po's so a
766
// subsequent
767
// commit does not do the whole thing all over again
768
for (int i = 0; i < getModifiedObjects().size(); i++)
769     {
770       DjObject po = getModifiedObjects().getDjenericObjectAt(i);
771       // move the modified object to the cache; if it's not deleted that is
772
if (!po.isMarkedForDelete()) _sessionCache.cache(po);
773       if (!po.isDetail()) po.notifyApplySuccesfull();
774     }
775
776     // Reset the cache for valid value lists; the updates applied now could
777
// affect
778
// the lists previously loaded so: clear the cache
779

780     resetValidValueLists();
781
782     // Modified objects are moved to the cache; empty the modification list
783
// now:
784
getModifiedObjects().clear();
785     if (shouldTrace(DjPersistenceManager.TRACE_FLOW)) trace("Session applied");
786   }
787
788   /**
789    * Creates a new object in the given extent
790    *
791    * @param extentName specifies the name of the extent
792    * @return the new object
793    * @exception DjenericException
794    */

795   public DjObject createObject(String JavaDoc extentName) throws DjenericException
796   {
797     if (!isValid()) throw new DjenericException(Messages.getString("global.SessionClosed"));
798     if (shouldTrace(DjPersistenceManager.TRACE_FLOW)) trace("Create new " + extentName);
799     return createObject(getPersistenceManager().getExtent(extentName));
800   }
801
802   /**
803    * Returns the object with the provided object ID from the session's modified object list. This includes objects that
804    * are marked for delete!
805    *
806    * @param id
807    * Description of the Parameter
808    * @return The fromSession value
809    * @exception DjenericException
810    * Description of the Exception
811    */

812   protected DjObject getFromSession(long id) throws DjenericException
813   {
814     for (int i = 0; i < getModifiedObjects().size(); i++)
815     {
816       DjObject p = getModifiedObjects().getDjenericObjectAt(i);
817       if (p.getObjectId() == id)
818       {
819         if (shouldTrace(DjPersistenceManager.TRACE_FLOW)) trace("Retrieved " + p.toString()
820                                                                 + " from the modified objects list");
821         return p;
822       }
823     }
824     DjObject result = _sessionCache.lookup(id);
825     if (result != null)
826     {
827       if (shouldTrace(DjPersistenceManager.TRACE_INTERNAL)) trace("Retrieved " + result.toString() + " from the cache");
828     }
829     else
830     {
831       if (shouldTrace(DjPersistenceManager.TRACE_INTERNAL)) trace("Cache miss for object with id " + id);
832     }
833     return result;
834   }
835
836   DjList getValidMasterObjects(DjObject detail, DjExtent masterExtent, DjRestriction restriction,
837                                boolean forceReloadFromDB) throws DjenericException
838   {
839     if (!isValid()) throw new DjenericException(Messages.getString("global.SessionClosed"));
840
841     if (restriction == null) return getObjects(masterExtent);
842
843     DjList results = new DjList();
844     results.setStoredTypeName(masterExtent);
845     try
846     {
847       long restrictingOid = restriction.evaluate(detail);
848       String JavaDoc restrictingPropertyName = restriction.getTopLevelRestrictedProperty().getName();
849
850       // First add all master objects that are (new) in the session but not yet
851
// committed..
852
addNewObjectsFromSession(masterExtent, restrictingPropertyName, restrictingOid, results);
853       // Now the rest..
854
addValidMasterObjects(masterExtent, restrictingOid, restrictingPropertyName, forceReloadFromDB, results);
855     }
856     catch (RestrictionFailedException restrictFail)
857     { // If the evaluate fails the list of valid masters can not be determined
858
// at this time because one of the properties in the path(s) is null. In
859
// that
860
// case the only thing we can do is return an empty list: nothing is
861
// valid for
862
// certain at this time
863
}
864     return results;
865   }
866
867   protected void notifyModified(DjObject obj, boolean isModified)
868   {
869     try
870     {
871       if (isModified)
872       {
873         addToModifiedList(obj);
874         if (shouldTrace(DjPersistenceManager.TRACE_FLOW)) trace("Modified " + obj.getExtent().getObjectType() + "(id="
875                                                                 + obj.getObjectId() + ") " + obj.toString());
876       }
877       else removeFromModifiedList(obj);
878     }
879     catch (Exception JavaDoc x)
880     {
881       DjLogger.log(x);
882       // Ignore this; will fail if session closed which will fail later anyway
883
}
884   }
885
886   /**
887    * Returns the next objectid for objects that are marked transient i.e. will not participate
888    * in transactions with the database.
889    */

890   public synchronized long getNextTransientObjectId()
891   {
892     return _nextTransientObjectId--;
893   }
894
895   /**
896    * Returns the object that is uniquely identifed the the given UID
897    */

898   public DjObject getObject(DjUid uid) throws DjenericException
899   {
900     DjQueryByExample qbe = createQueryByExample(uid.getExtent());
901     String JavaDoc[] names = uid.getPropertyNames();
902     for (int i = 0; i < names.length; i++)
903     {
904       if (uid.isUidProperty(names[i])) qbe.set(names[i], getObject(uid.getUid(names[i])));
905       else qbe.setString(names[i], uid.getString(names[i]));
906     }
907     DjList lst = getObjects(qbe);
908     if (lst.size() == 0) throw new ObjectNotDefinedException(Messages.getString("DjPersistenceManager.ObjectNotFound",
909                                                                                 uid.getExtent().getNameSingular(), uid
910                                                                                     .getDescriptor()));
911     if (lst.size() != 1)
912     {
913       StringBuffer JavaDoc sb = new StringBuffer JavaDoc(100);
914       String JavaDoc[] props = uid.getPropertyNames();
915       for (int i = 0; i < props.length; i++)
916       {
917         if (i != 0) sb.append(", ");
918         sb.append(props[i]);
919       }
920       // Dump some extra diagnostic info: the objects found
921
System.err.println(uid);
922       for (int i = 0; i < lst.size(); i++)
923       {
924         System.err.println("id=" + lst.getDjenericObjectAt(i).getObjectId() + "; " + lst.getDjenericObjectAt(i));
925       }
926       throw new CatalogException(Messages.getString("DjPersistenceManager.MultipleHits", uid.getExtent()
927           .getNameSingular(), uid.getDescriptor(), sb.toString()));
928     }
929     return lst.getDjenericObjectAt(0);
930   }
931
932 }
Popular Tags