KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > sun > jdo > spi > persistence > support > sqlstore > sql > UpdateObjectDescImpl


1 /*
2  * The contents of this file are subject to the terms
3  * of the Common Development and Distribution License
4  * (the License). You may not use this file except in
5  * compliance with the License.
6  *
7  * You can obtain a copy of the license at
8  * https://glassfish.dev.java.net/public/CDDLv1.0.html or
9  * glassfish/bootstrap/legal/CDDLv1.0.txt.
10  * See the License for the specific language governing
11  * permissions and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL
14  * Header Notice in each file and include the License file
15  * at glassfish/bootstrap/legal/CDDLv1.0.txt.
16  * If applicable, add the following below the CDDL Header,
17  * with the fields enclosed by brackets [] replaced by
18  * you own identifying information:
19  * "Portions Copyrighted [year] [name of copyright owner]"
20  *
21  * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
22  */

23
24 /*
25  * UpdateObjectDescImpl.java
26  *
27  * Created on March 3, 2000
28  *
29  */

30
31 package com.sun.jdo.spi.persistence.support.sqlstore.sql;
32
33 import com.sun.jdo.api.persistence.support.JDOFatalInternalException;
34 import com.sun.jdo.spi.persistence.support.sqlstore.*;
35 import com.sun.jdo.spi.persistence.support.sqlstore.model.ClassDesc;
36 import com.sun.jdo.spi.persistence.support.sqlstore.model.FieldDesc;
37 import com.sun.jdo.spi.persistence.support.sqlstore.model.ForeignFieldDesc;
38 import com.sun.jdo.spi.persistence.support.sqlstore.model.LocalFieldDesc;
39 import com.sun.jdo.spi.persistence.support.sqlstore.sql.concurrency.Concurrency;
40 import com.sun.jdo.spi.persistence.utility.I18NHelper;
41 import com.sun.jdo.spi.persistence.utility.logging.Logger;
42
43 import java.util.*;
44
45 /**
46  * Stores the update information for the associated state manager.
47  */

48 public class UpdateObjectDescImpl implements UpdateObjectDesc {
49
50     /** Array of Object. */
51     private List afterHiddenValues;
52
53     private SQLStateManager afterImage;
54
55     /** Array of Object. */
56     private List beforeHiddenValues;
57
58     private SQLStateManager beforeImage;
59
60     private Concurrency concurrency;
61
62     private Class JavaDoc pcClass;
63
64     private int updateAction;
65
66     /**
67      * Array of LocalFieldDesc.
68      * Fields contained in this array are written to the database.
69      */

70     private List updatedFields;
71
72     private Map updatedJoinTableRelationships;
73
74     /** Marker for fast relationship update check. */
75     private boolean relationshipChanged = false;
76
77     /** The logger. */
78     private static Logger logger = LogHelperSQLStore.getLogger();
79
80     /** I18N message handler. */
81     private final static ResourceBundle messages = I18NHelper.loadBundle(
82             "com.sun.jdo.spi.persistence.support.sqlstore.Bundle", // NOI18N
83
UpdateObjectDescImpl.class.getClassLoader());
84
85     public UpdateObjectDescImpl(Class JavaDoc pcClass) {
86         this.pcClass = pcClass;
87         updatedFields = new ArrayList();
88     }
89
90     public Class JavaDoc getPersistenceCapableClass() {
91         return pcClass;
92     }
93
94     public void reset() {
95         updatedFields.clear();
96
97         if (updatedJoinTableRelationships != null) {
98             updatedJoinTableRelationships.clear();
99         }
100
101         relationshipChanged = false;
102         concurrency = null;
103     }
104
105     public boolean hasUpdatedFields() {
106         return (updatedFields.size() > 0);
107     }
108
109     public Collection getUpdatedJoinTableFields() {
110         if (updatedJoinTableRelationships == null) {
111             return null;
112         }
113
114         return updatedJoinTableRelationships.keySet();
115     }
116
117     // RESOLVE: Should return _all_ join table descs, not separatly by field.
118
public Collection getUpdateJoinTableDescs(FieldDesc fieldDesc) {
119         HashMap updateJoinTableDescs = (HashMap) updatedJoinTableRelationships.get(fieldDesc);
120
121         if (updateJoinTableDescs != null) {
122             return updateJoinTableDescs.values();
123         }
124
125         return null;
126     }
127
128     public boolean hasUpdatedJoinTableRelationships() {
129         return (updatedJoinTableRelationships != null &&
130                 updatedJoinTableRelationships.size() > 0);
131     }
132
133     /**
134      * Returns <code>true</code> if any of the changed fields is byte[].
135      */

136     public boolean hasModifiedLobField() {
137
138         if (updatedFields != null) {
139             for (Iterator i = updatedFields.iterator(); i.hasNext(); ) {
140
141                 // The list updatedFields only contains LocalFieldDesc.
142
// Thus it's safe to cast to LocalFieldDesc below.
143
LocalFieldDesc field = (LocalFieldDesc)i.next();
144                 if (field.isMappedToLob()) {
145                     return true;
146                 }
147             }
148         }
149
150         return false;
151     }
152
153     /**
154      * Marks the relationship change property for this instance, if the
155      * updated field is a relationship field or a hidden field tracing a
156      * foreign key column in the database.
157      *
158      * @param fieldDesc Updated field.
159      */

160     public void markRelationshipChange(FieldDesc fieldDesc) {
161         if (fieldDesc.isRelationshipField() || fieldDesc.absoluteID < 0) {
162             if (logger.isLoggable(Logger.FINEST)) {
163                 logger.finest("sqlstore.sql.updateobjdescimpl.markrelationshipchange"); // NOI18N
164
}
165             // MARK THE RELATIONSHIP CHANGE for this instance.
166
relationshipChanged = true;
167         }
168     }
169
170     /**
171      * Returns <code>true</code>, if this state manager has a changed
172      * relationship field.
173      * @return True, if this state manager has a changed relationship field.
174      */

175     public boolean hasChangedRelationships() {
176         // If the relationship is set before the makePersistent call,
177
// this condition might be false for INSERTs.
178
if (relationshipChanged) {
179             return true;
180         }
181
182         // Check for updated join table relationships.
183
if (hasUpdatedJoinTableRelationships()) {
184             return true;
185         }
186
187         // Check for updated foreign key relationships.
188
if (updatedFields != null) {
189             for (Iterator iter = updatedFields.iterator(); iter.hasNext(); ) {
190                 LocalFieldDesc field = (LocalFieldDesc) iter.next();
191                 if (field.absoluteID < 0) {
192                     return true;
193                 }
194             }
195         }
196
197         return false;
198     }
199
200     /**
201      * Removes a previously scheduled jointable entry for relationship
202      * field <code>fieldDesc</code>. The <code>action</code>
203      * parameter specifies, if the entry to be removed is
204      * scheduled for creation or removal.
205      *
206      * @param fieldDesc Updated relationship field.
207      * @param foreignSM Associated state manager on the opposite side.
208      * @param action The action is either CREATE or REMOVE.
209      * @return True, if the specified jointable entry was found and removed, false otherwise.
210      * @see #recordUpdatedJoinTableRelationship
211      */

212     public boolean removeUpdatedJoinTableRelationship(ForeignFieldDesc fieldDesc,
213                                                       SQLStateManager foreignSM,
214                                                       int action) {
215         HashMap updateJoinTableDescs = null;
216
217         if ((updatedJoinTableRelationships == null) ||
218                 ((updateJoinTableDescs = (HashMap) updatedJoinTableRelationships.get(fieldDesc)) == null)) {
219             return false;
220         }
221
222         UpdateJoinTableDesc desc = (UpdateJoinTableDesc) updateJoinTableDescs.get(foreignSM);
223         if (desc != null && desc.getAction() == action) {
224             return (updateJoinTableDescs.remove(foreignSM) != null);
225         }
226
227         return false;
228     }
229
230     /**
231      * Schedules a jointable entry for relationship field
232      * <code>fieldDesc</code>. The scheduled jointable entry is
233      * uniquely identified by the relationship field and the two
234      * associated state managers. The <code>action</code> parameter
235      * specifies, if the jointable entry should be created or removed.
236      *
237      * @param fieldDesc Updated relationship field.
238      * @param parentSM State manager responsible for <code>fieldDesc</code>'s defining class.
239      * @param foreignSM State manager responsible for the other side.
240      * @param action The action is either CREATE or REMOVE.
241      * @see #removeUpdatedJoinTableRelationship
242      */

243     public void recordUpdatedJoinTableRelationship(ForeignFieldDesc fieldDesc,
244                                                    SQLStateManager parentSM,
245                                                    SQLStateManager foreignSM,
246                                                    int action) {
247         if (updatedJoinTableRelationships == null) {
248             updatedJoinTableRelationships = new HashMap();
249         }
250
251         HashMap updateJoinTableDescs = null;
252
253         if ((updateJoinTableDescs = (HashMap) updatedJoinTableRelationships.get(fieldDesc)) == null) {
254             updateJoinTableDescs = new HashMap();
255             updatedJoinTableRelationships.put(fieldDesc, updateJoinTableDescs);
256         }
257
258         UpdateJoinTableDesc desc = null;
259
260         if ((desc = (UpdateJoinTableDesc) updateJoinTableDescs.get(foreignSM)) == null) {
261             desc = new UpdateJoinTableDesc(parentSM, foreignSM, action);
262             updateJoinTableDescs.put(foreignSM, desc);
263         }
264     }
265
266     public void clearUpdatedJoinTableRelationships() {
267         updatedJoinTableRelationships = null;
268     }
269
270     public void recordUpdatedField(LocalFieldDesc fieldDesc) {
271         if (!updatedFields.contains(fieldDesc))
272             updatedFields.add(fieldDesc);
273     }
274
275     public List getUpdatedFields() {
276         return updatedFields;
277     }
278
279     public Object JavaDoc getAfterValue(FieldDesc f) {
280         if (afterImage == null) {
281             throw new JDOFatalInternalException(I18NHelper.getMessage(messages,
282                 "sqlstore.sql.updateobjdescimpl.afterimagenull")); //NOI18N
283
}
284
285         if (f.absoluteID < 0) {
286             return afterHiddenValues.get(-(f.absoluteID + 1));
287         } else {
288             return f.getValue(afterImage);
289         }
290     }
291
292     public Object JavaDoc getBeforeValue(FieldDesc f) {
293         if (beforeImage == null) {
294             throw new JDOFatalInternalException(I18NHelper.getMessage(messages,
295                 "sqlstore.sql.updateobjdescimpl.beforeimagenull")); //NOI18N
296
}
297
298         if (f.absoluteID < 0) {
299             return beforeHiddenValues.get(-(f.absoluteID + 1));
300         } else {
301             return f.getValue(beforeImage);
302         }
303     }
304
305     public int getUpdateAction() {
306         return updateAction;
307     }
308
309     public ClassDesc getConfig() {
310         return (ClassDesc) afterImage.getPersistenceConfig();
311     }
312
313     public SQLStateManager getAfterImage() {
314         return afterImage;
315     }
316
317     public boolean isBeforeImageRequired() {
318         return afterImage.isBeforeImageRequired();
319     }
320
321     public Concurrency getConcurrency() {
322         return concurrency;
323     }
324
325     public void setConcurrency(Concurrency concurrency) {
326         this.concurrency = concurrency;
327     }
328
329     /**
330      * We send the AfterImage for updates and inserts
331      * but for updates it will only hold values for updated attributes (unless
332      * the class is configured to send the whole AfterImage, also we'll let the
333      * concurrency interface affect the sent AfterImage (and the sent
334      * BeforeImage)). For deletes the AfterImage will be NIL, for inserts the
335      * BeforeImage will be NIL. For deletes the BeforeImage will contain values
336      * for all key attributes. Also for deletes and updates we'll send the
337      * HiddenValues array from the paladin (although we can set to NIL any
338      * values in the array not needed by this particular update).
339      *
340      * UpdatedAttributes will contain indexes into the PersistentDesc.Attributes
341      * array for new or updated values.
342      *
343      * Initially we'll probably just send the whole BeforeImage and AfterImage
344      * (except that we won't have an AfterImage for Deletes and we won't have
345      * a BeforeImage for updates).
346      */

347     public void setObjectInfo(StateManager biStateManager,
348                               StateManager aiStateManager,
349                               int action) {
350
351         this.beforeImage = (SQLStateManager) biStateManager;
352         this.afterImage = (SQLStateManager) aiStateManager;
353         ClassDesc config = (ClassDesc) afterImage.getPersistenceConfig();
354         updateAction = action;
355
356         this.afterHiddenValues = afterImage.hiddenValues;
357
358         if (beforeImage != null) {
359             this.beforeHiddenValues = beforeImage.hiddenValues;
360         }
361
362         // This pass through attributes we are only going to look at local attributes.
363
// These are attributes that are stored in this object and are not references
364
// to other persistent objects.
365

366         boolean debug = logger.isLoggable(Logger.FINER);
367
368         for (int i = 0; i < config.fields.size(); i++) {
369             FieldDesc f = (FieldDesc) config.fields.get(i);
370             LocalFieldDesc lf = null;
371             boolean updated = false;
372
373             if (f instanceof LocalFieldDesc) {
374                 lf = (LocalFieldDesc) f;
375             } else {
376                 continue;
377             }
378
379             if ((updateAction == LOG_DESTROY) ||
380                     ((lf.sqlProperties & FieldDesc.PROP_RECORD_ON_UPDATE) > 0)) {
381                 continue;
382             } else if (lf.absoluteID < 0) {
383                 if ((beforeImage == null) ||
384                         (beforeImage.getHiddenValue(lf.absoluteID) !=
385                         afterImage.getHiddenValue(lf.absoluteID))) {
386                     updated = true;
387                 }
388             } else if (lf.getType().isPrimitive() ||
389                     String JavaDoc.class == lf.getType() ||
390                     java.util.Date JavaDoc.class == lf.getType()) {
391                 Object JavaDoc afterVal = lf.getValue(afterImage);
392                 Object JavaDoc beforeVal = null;
393
394                 if (beforeImage != null) {
395                     beforeVal = lf.getValue(beforeImage);
396                 }
397
398                 if ((beforeVal != null) && (afterVal != null)) {
399                     if (!beforeVal.equals(afterVal)) {
400                         updated = true;
401                     }
402                 } else {
403                     updated = true;
404                 }
405             } else {
406                 // What else??
407
}
408
409             if (updated) {
410                 if (debug) {
411                     logger.finer("sqlstore.sql.updateobjdescimpl.updated", f.getName()); // NOI18N
412
}
413
414                 updatedFields.add(lf);
415             }
416         }
417
418         if (concurrency != null) {
419             concurrency.commit(this, beforeImage, afterImage, updateAction);
420         }
421     }
422
423     /**
424      * Triggers the version update if the associated state manager is
425      * registered for version consistency and database fields have been
426      * modified. The version is incremented, if
427      * <ul>
428      * <li>The associated instance is version consistent.</li>
429      * <li>The associated instance has updated database fields.</li>
430      * </ul>
431      * Note: The version is <b>not</b> incremented, if a relationship
432      * mapped to a join table was updated.
433      */

434     public void incrementVersion() {
435
436         if (afterImage.hasVersionConsistency()
437                 && updateAction == ActionDesc.LOG_UPDATE
438                 && hasUpdatedFields()) {
439
440             afterImage.incrementVersion();
441         }
442     }
443
444     /**
445      * Marks the associated state manager as failed.
446      */

447     public void setVerificationFailed() {
448         afterImage.setVerificationFailed();
449     }
450
451     public boolean hasVersionConsistency() {
452         return afterImage.hasVersionConsistency();
453     }
454 }
455
Popular Tags