Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: er/extensions/ERXDefaultEditingContextDelegate.java


1   /*
2    * Copyright (C) NetStruxr, Inc. All rights reserved.
3    *
4    * This software is published under the terms of the NetStruxr
5    * Public Software License version 0.5, a copy of which has been
6    * included with this distribution in the LICENSE.NPL file.  */
7   package er.extensions;
8   
9   import com.webobjects.foundation.*;
10  import com.webobjects.eocontrol.*;
11  import com.webobjects.eoaccess.*;
12  import com.webobjects.appserver.*;
13  import java.util.*;
14  
15  /**
16   * Default editing context delegate. This delegate
17   * augments the regular transaction process by adding
18   * the calling of willInsert, willUpdate or willDelete
19   * on enterprise objects that are of type ERXGenericRecord
20   * after saveChanges is called on the editing context, but
21   * before validateForSave is called on the object. These
22   * methods can give the object a last chance to modify itself
23   * before validation occurs. The second enhancement is a built
24   * in flushing of caches on subclasses of ERXGenericRecords
25   * when objects have changes merged in or are invalidated.
26   * Being able to maintain caches on enterprise objects that
27   * are flushed when the underlying values change can be very
28   * handy.
29   */
30  public class ERXDefaultEditingContextDelegate extends ERXEditingContextDelegate {
31  
32      /** logging support */
33      public static final ERXLogger log = ERXLogger.getERXLogger(ERXDefaultEditingContextDelegate.class);
34      /** logging support for modified objects */
35      public static final ERXLogger logMod = ERXLogger.getERXLogger("er.transaction.delegate.EREditingContextDelegate.modifedObjects");
36  
37      /**
38       * flag that can tell if the editing context is in
39       * the middle of a will save changes call.
40       */
41      // FIXME inherently single threaded
42      private boolean _isInWillSaveChanges=false;
43      /**
44       * Can tell if the delegate is in the middle of a
45       * call to will save changes.
46       * @return if the delegate is already processing
47       *     a request at the time when another request
48       *    comes in.
49       */
50      public boolean isInWillSaveChanges() { return _isInWillSaveChanges; }
51      
52      /**
53       * Enumerates through all of the objects that have been
54       * changed, inserted and deleted calling the appropriate
55       * will* method, willInsert, etc. on each of the objects
56       * if they are of type ERXGenericRecord. Note that this
57       * method is called before validateForSave is called on
58       * any of the objects.
59       * @param ec editing context that is about to be saved.
60       */
61      public void editingContextWillSaveChanges(EOEditingContext ec) throws Throwable {
62          try {
63              if (log.isDebugEnabled()) log.debug("EditingContextWillSaveChanges: start calling will*");            
64              _isInWillSaveChanges=true;                      
65              if (ec != null && ec.hasChanges()) {
66                  NSNotificationCenter.defaultCenter().postNotification(ERXExtensions.objectsWillChangeInEditingContext, ec);
67                  // Changed objects
68                  if (ec.updatedObjects()!=null && ec.updatedObjects().count()>0) {
69                      for (Enumeration e = ec.updatedObjects().objectEnumerator(); e.hasMoreElements();) {
70                          EOEnterpriseObject eo = (EOEnterpriseObject)e.nextElement();
71                          if (eo instanceof ERXGenericRecord)
72                              ((ERXGenericRecord)eo).willUpdate();
73                      }
74                  }
75                  // Deleted objects
76                  if (ec.deletedObjects()!=null && ec.deletedObjects().count()>0) {
77                      for (Enumeration e = ec.deletedObjects().objectEnumerator(); e.hasMoreElements();) {
78                          EOEnterpriseObject eo = (EOEnterpriseObject)e.nextElement();
79                          if (eo instanceof ERXGenericRecord)
80                              ((ERXGenericRecord)eo).willDelete();
81                      }                    
82                  }
83                  // Inserted objects
84                  if (ec.insertedObjects()!=null && ec.insertedObjects().count()>0) {
85                      for (Enumeration e = ec.insertedObjects().objectEnumerator(); e.hasMoreElements();) {
86                          EOEnterpriseObject eo = (EOEnterpriseObject)e.nextElement();
87                          if (eo instanceof ERXGenericRecord && !ec.deletedObjects().containsObject(eo))
88                              ((ERXGenericRecord)eo).willInsert();
89                      }
90                  }                
91                  if (log.isDebugEnabled()) log.debug("EditingContextWillSaveChanges: done calling will*");
92                  if (logMod.isDebugEnabled()) {
93                      if (ec.updatedObjects()!=null) logMod.debug("** Updated Objects "+ec.updatedObjects().count()+" - "+ec.updatedObjects());
94                      if (ec.insertedObjects()!=null) logMod.debug("** Inserted Objects "+ec.insertedObjects().count()+" - "+ec.insertedObjects());
95                      if (ec.deletedObjects()!=null) logMod.debug("** Deleted Objects "+ec.deletedObjects().count()+" - "+ec.deletedObjects());
96                  }
97              }
98          } catch (Throwable e) {
99              if (log.isDebugEnabled()) // i want this stack trace shown in one of the two categories, but not both
100                 log.debug("Stack Trace:\n" + ERXUtilities.stackTrace(e));
101             else if (logMod.isDebugEnabled())
102                 logMod.debug("Stack Trace:\n" + ERXUtilities.stackTrace(e));
103             try {
104                 StringBuffer buffer = new StringBuffer();
105                 buffer.append("The following exception has occurred with ec: " + ec + "\n" + ERXUtilities.stackTrace(e) + "\n");
106                 if (ec.updatedObjects()!=null) {
107                     buffer.append("** Updated Objects "+ec.updatedObjects().count());
108                     for (Enumeration en = ec.updatedObjects().objectEnumerator(); en.hasMoreElements();) {
109                         buffer.append('\n');
110                         buffer.append(toDebugString((EOEnterpriseObject)en.nextElement()));
111                     }
112                 }
113                 if (ec.insertedObjects()!=null) {
114                     buffer.append("\n** Inserted Objects "+ec.insertedObjects().count());
115                     for (Enumeration en = ec.insertedObjects().objectEnumerator(); en.hasMoreElements();) {
116                         buffer.append('\n');
117                         buffer.append(toDebugString((EOEnterpriseObject)en.nextElement()));
118                     }
119                 }
120                 if (ec.deletedObjects()!=null) {
121                     buffer.append("\n** Deleted Objects "+ec.deletedObjects().count());
122                     for (Enumeration en = ec.deletedObjects().objectEnumerator(); en.hasMoreElements();) {
123                         buffer.append('\n');
124                         buffer.append(toDebugString((EOEnterpriseObject)en.nextElement()));
125                     }
126                 }
127                 logMod.error(buffer);
128             } catch (Throwable e2) {
129                 log.error("Caught "+e2+" trying to print editing context state");
130             } finally {
131                 _isInWillSaveChanges=false;                
132             }
133             throw e;
134         } finally {
135             _isInWillSaveChanges=false;
136         }
137     }
138 
139     /**
140      * Returns a string of a verbose look a the given
141      * enterprise object. Also includes the primary key.
142      * @param eo enterprise object to create the debug string
143      *     for.
144      * @return verbose description of the object.
145      */
146     // MOVEME: If this is usedful then it might be worth putting in EOGenericRecordClazz or ERXEOFUtilities
147     private static String toDebugString(EOEnterpriseObject eo) {
148         String result=null;
149         if (eo!=null) {
150             if (eo instanceof ERXGenericRecord) {
151                 ERXGenericRecord rec = (ERXGenericRecord)eo;
152                 result="PKey: " + rec.primaryKey() + " - " + rec.toLongString();
153             } else {
154                 result="Pkey: "+EOUtilities.primaryKeyForObject(eo.editingContext(),eo)+" - "+eo;
155             }
156         }
157         return result;
158     }
159     /**
160      * When invalidating an object their local
161      * cache is flushed by calling the method: <code>
162      * flushCaches</code> on the enterprise object if
163      * it is an instance of ERXGenericRecord.
164      * @param anEditingContext current editing context
165      * @param anObject enterprise object to be invlidated
166      * @param anEOGlobalID global id to be invalidated
167      * @return true
168      */
169     public boolean editingContextShouldInvalidateObject(EOEditingContext anEOEditingContext,
170                                                         EOEnterpriseObject anObject,
171                                                         EOGlobalID anEOGlobalID) {
172         if (anObject instanceof ERXGenericRecord) {
173             ((ERXGenericRecord)anObject).flushCaches();
174         }
175         return true;
176     }
177 
178     /**
179      * When merging changes into an object their local
180      * cache is flushed by calling the method: <code>
181      * flushCaches</code> on the enterprise object if
182      * it is an instance of ERXGenericRecord.
183      * @param anEditingContext current editing context
184      * @param object enterprise object to have changes
185      *    merged into it.
186      * @return true
187      */
188     public boolean editingContextShouldMergeChangesForObject(EOEditingContext anEditingContext,
189                                                              EOEnterpriseObject object) {
190         if (object instanceof ERXGenericRecord) {
191             ((ERXGenericRecord)object).flushCaches();
192         }
193         return true;
194     }
195 }