KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > ojb > odmg > ObjectEnvelope


1 package org.apache.ojb.odmg;
2
3 /* Copyright 2002-2005 The Apache Software Foundation
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */

17 /**
18  *
19  * @author <a HREF="mailto:thma@apache.org">Thomas Mahler</a>
20  * @author <a HREF="mailto:mattbaird@yahoo.com">Matthew Baird</a>
21  *
22  */

23
24 import java.util.HashMap JavaDoc;
25 import java.util.Iterator JavaDoc;
26 import java.util.Map JavaDoc;
27 import java.util.List JavaDoc;
28 import java.util.ArrayList JavaDoc;
29
30 import org.apache.commons.lang.builder.ToStringBuilder;
31 import org.apache.ojb.broker.Identity;
32 import org.apache.ojb.broker.PersistenceBroker;
33 import org.apache.ojb.broker.PersistenceBrokerException;
34 import org.apache.ojb.broker.OJBRuntimeException;
35 import org.apache.ojb.broker.PersistenceBrokerInternal;
36 import org.apache.ojb.broker.core.proxy.IndirectionHandler;
37 import org.apache.ojb.broker.core.proxy.ProxyHelper;
38 import org.apache.ojb.broker.metadata.ClassDescriptor;
39 import org.apache.ojb.broker.metadata.CollectionDescriptor;
40 import org.apache.ojb.broker.metadata.FieldDescriptor;
41 import org.apache.ojb.broker.metadata.ObjectReferenceDescriptor;
42 import org.apache.ojb.broker.util.BrokerHelper;
43 import org.apache.ojb.broker.util.ObjectModification;
44 import org.apache.ojb.broker.util.logging.Logger;
45 import org.apache.ojb.broker.util.logging.LoggerFactory;
46 import org.apache.ojb.odmg.states.ModificationState;
47 import org.apache.ojb.odmg.states.StateNewDirty;
48 import org.apache.ojb.odmg.states.StateOldClean;
49 import org.apache.ojb.odmg.states.StateOldDirty;
50 import org.apache.ojb.odmg.link.LinkEntry;
51 import org.apache.ojb.odmg.link.LinkEntryOneToOne;
52 import org.apache.ojb.odmg.link.LinkEntryOneToN;
53
54 /**
55  * ObjectEnvelope is used during ODMG transactions as a wrapper for a
56  * persistent objects declaration
57  *
58  */

59 public class ObjectEnvelope implements ObjectModification, Image.ImageListener
60 {
61     private Logger log = LoggerFactory.getLogger(ObjectEnvelope.class);
62
63     static final long serialVersionUID = -829177767933340522L;
64
65     static final int IS_MATERIALIZED_OBJECT = 11;
66     static final int IS_MATERIALIZED_PROXY = 13;
67     static final int IS_UNMATERIALIZED_PROXY = 17;
68
69     /**
70      * The objects modification state, e.g. Old and Clean
71      */

72     private ModificationState modificationState = null;
73     private Identity oid;
74     private Boolean JavaDoc hasChanged;
75     private boolean writeLocked;
76
77     /**
78      * myObj holds the object we are wrapping.
79      */

80     private Object JavaDoc myObj;
81
82     /**
83      * beforeImage holds a mapping between field
84      * names and values at the start of the transaction.
85      * currentImage holds the mapping at the
86      * end of the transaction.
87      */

88     private Map JavaDoc beforeImage;
89     private Map JavaDoc currentImage;
90     private ObjectEnvelopeTable buffer;
91     // list of all LinkEntry's
92
private List JavaDoc linkEntryList;
93
94     /**
95      * Create a wrapper by providing an Object.
96      */

97     public ObjectEnvelope(ObjectEnvelopeTable buffer, Identity oid, Object JavaDoc obj, boolean isNewObject)
98     {
99         this.linkEntryList = new ArrayList JavaDoc();
100         this.buffer = buffer;
101         this.oid = oid;
102         // TODO: do we really need to materialize??
103
myObj = ProxyHelper.getRealObject(obj);
104         prepareInitialState(isNewObject);
105         /*
106         TODO: is it possible to improve this? Take care that "new"
107         objects should support "persistence by reachability" too
108         (detection of new/persistent reference objects after maon object lock)
109         */

110         beforeImage = buildObjectImage(getBroker());
111     }
112
113     public PersistenceBrokerInternal getBroker()
114     {
115         return buffer.getTransaction().getBrokerInternal();
116     }
117
118     TransactionImpl getTx()
119     {
120         return buffer.getTransaction();
121     }
122
123     ObjectEnvelopeTable getEnvelopeTable()
124     {
125         return buffer;
126     }
127
128     public Map JavaDoc getBeforeImage()
129     {
130         if(beforeImage == null)
131         {
132             beforeImage = buildObjectImage(getBroker());
133         }
134         return beforeImage;
135     }
136
137     public Map JavaDoc getCurrentImage()
138     {
139         if(currentImage == null)
140         {
141             currentImage = buildObjectImage(getBroker());
142         }
143         return currentImage;
144     }
145
146     /**
147      * This method should be called before transaction ends
148      * to allow cleanup of used resources, e.g. remove proxy listener objects
149      * to avoid invoke of registered objects after tx end.
150      */

151     public void cleanup(boolean reuse, boolean wasInsert)
152     {
153         if(currentImage != null)
154         {
155             performImageCleanup(currentImage, reuse);
156         }
157         if(beforeImage != null)
158         {
159             // we always free all resources of the old image
160
performImageCleanup(beforeImage, false);
161         }
162         if(reuse)
163         {
164             refreshObjectImage(wasInsert);
165         }
166         else
167         {
168             myObj = null;
169         }
170     }
171
172     private void performImageCleanup(Map JavaDoc imageMap, boolean reuse)
173     {
174         Iterator JavaDoc iterator = imageMap.values().iterator();
175         while(iterator.hasNext())
176         {
177             Image base = (Image) iterator.next();
178             if(base != null) base.cleanup(reuse);
179         }
180     }
181
182     private void refreshObjectImage(boolean wasInsert)
183     {
184         try
185         {
186             // if an image already exists we
187
// replace the Identity too, maybe a temporary
188
// used PK value was replaced by the real one,
189
// see in docs SequenceManagerNativeImpl
190
if(getIdentity().isTransient())
191             {
192                 refreshIdentity();
193             }
194             if(currentImage != null)
195             {
196                 beforeImage = currentImage;
197             }
198             else
199             {
200                 if(beforeImage == null)
201                 {
202                     beforeImage = buildObjectImage(getBroker());
203                 }
204             }
205             currentImage = null;
206             hasChanged = null;
207             if(wasInsert)
208             {
209                 /*
210                 on insert we have to replace the PK fields and the version fields, because
211                 they populated after the object was written to DB, thus replace all field image values
212                 */

213                 refreshPKFields();
214             }
215             // TODO: How to handle version fields incremented by the DB?
216
// always refresh the version fields, because these fields will change when written to DB
217
refreshLockingFields();
218         }
219         catch(PersistenceBrokerException e)
220         {
221             beforeImage = null;
222             currentImage = null;
223             hasChanged = null;
224             log.error("Can't refresh object image for " + getIdentity(), e);
225             throw e;
226         }
227     }
228
229     private void refreshPKFields()
230     {
231         FieldDescriptor[] flds = getClassDescriptor().getPkFields();
232         for(int i = 0; i < flds.length; i++)
233         {
234             FieldDescriptor fld = flds[i];
235             addFieldImage(beforeImage, fld);
236         }
237     }
238
239     private void refreshLockingFields()
240     {
241         if(getClassDescriptor().isLocking())
242         {
243             FieldDescriptor[] flds = getClassDescriptor().getLockingFields();
244             for(int i = 0; i < flds.length; i++)
245             {
246                 FieldDescriptor fld = flds[i];
247                 addFieldImage(beforeImage, fld);
248             }
249         }
250     }
251
252     /**
253      * Replace the current with a new generated identity object and
254      * returns the old one.
255      */

256     public Identity refreshIdentity()
257     {
258         Identity oldOid = getIdentity();
259         this.oid = getBroker().serviceIdentity().buildIdentity(myObj);
260         return oldOid;
261     }
262
263     public Identity getIdentity()
264     {
265         if(oid == null)
266         {
267             oid = getBroker().serviceIdentity().buildIdentity(getObject());
268         }
269         return oid;
270     }
271
272     /**
273      * Returns the managed materialized object.
274      */

275     public Object JavaDoc getObject()
276     {
277         return myObj;
278     }
279
280     public Object JavaDoc getRealObject()
281     {
282         return ProxyHelper.getRealObject(getObject());
283     }
284
285     public void refreshObjectIfNeeded(Object JavaDoc obj)
286     {
287         if(this.myObj != obj)
288         {
289             this.myObj = obj;
290         }
291     }
292
293     /**
294      * We need to implement the Two-Phase Commit
295      * protocol.
296      *
297      * beginCommit is where we say if we can or cannot
298      * commit the transaction. At the begining however,
299      * we need to attain the after image so we can isolate
300      * everything.
301      *
302      * We should issue the call against the database
303      * at this point. If we get a SQL Exception, we
304      * should throw the org.odmg.TransactionAbortedException.
305      *
306      * We should also check to see if the object is
307      * TransactionAware. If so, we should give it a chance
308      * to kill the transaction before we toss it to the
309      * database.
310      */

311     public void beforeCommit()
312     {
313         if(myObj instanceof TransactionAware)
314         {
315             TransactionAware ta = (TransactionAware) myObj;
316             ta.beforeCommit();
317         }
318     }
319
320     /**
321      * Method declaration
322      */

323     public void afterCommit()
324     {
325         if(myObj instanceof TransactionAware)
326         {
327             TransactionAware ta = (TransactionAware) myObj;
328             ta.afterCommit();
329         }
330     }
331
332     /**
333      * Method declaration
334      */

335     public void beforeAbort()
336     {
337         if(myObj instanceof TransactionAware)
338         {
339             TransactionAware ta = (TransactionAware) myObj;
340             ta.beforeAbort();
341         }
342     }
343
344     /**
345      * Method declaration
346      */

347     public void afterAbort()
348     {
349         if(myObj instanceof TransactionAware)
350         {
351             TransactionAware ta = (TransactionAware) myObj;
352             ta.afterAbort();
353         }
354     }
355
356     /**
357      * buildObjectImage() will return the image of the Object.
358      */

359     private Map JavaDoc buildObjectImage(PersistenceBroker broker) throws PersistenceBrokerException
360     {
361         Map JavaDoc imageMap = new HashMap JavaDoc();
362         ClassDescriptor cld = broker.getClassDescriptor(getObject().getClass());
363         //System.out.println("++++ build image: " + getObject());
364
// register 1:1 references in image
365
buildImageForSingleReferences(imageMap, cld);
366         // put object values to image map
367
buildImageForFields(imageMap, cld);
368         // register 1:n and m:n references in image
369
buildImageForCollectionReferences(imageMap, cld);
370         return imageMap;
371     }
372
373     private void buildImageForSingleReferences(Map JavaDoc imageMap, ClassDescriptor cld)
374     {
375         // register all 1:1 references
376
Iterator JavaDoc iter = cld.getObjectReferenceDescriptors(true).iterator();
377         ObjectReferenceDescriptor rds;
378         while(iter.hasNext())
379         {
380             rds = (ObjectReferenceDescriptor) iter.next();
381             /*
382             arminw:
383             if a "super-reference" is matched (a 1:1 reference used to represent a super class)
384             we don't handle it, because this will be done by the PB-api and will never be change
385             */

386             if(!rds.isSuperReferenceDescriptor())
387             {
388                 Object JavaDoc referenceObject = rds.getPersistentField().get(myObj);
389
390                 IndirectionHandler handler = ProxyHelper.getIndirectionHandler(referenceObject);
391                 /*
392                 arminw:
393                 if object was serialized and anonymous FK are used in the main object, the FK
394                 values are null, we have to refresh (re-assign) these values before building field images.
395                 This will not touch the main object itself, because we only reassign anonymous FK fields.
396                 */

397                 if(handler == null && referenceObject != null
398                         && BrokerHelper.hasAnonymousKeyReference(rds.getClassDescriptor(), rds))
399                 {
400                     getBroker().serviceBrokerHelper().link(myObj, rds, false);
401                 }
402                 Image.SingleRef singleRef = new Image.SingleRef(this, rds, referenceObject);
403                 imageMap.put(rds, singleRef);
404             }
405         }
406     }
407
408     private void buildImageForFields(Map JavaDoc imageMap, ClassDescriptor cld)
409     {
410         // register all non reference fields of object (with inherited fields)
411
FieldDescriptor[] fieldDescs = cld.getFieldDescriptor(true);
412         for(int i = 0; i < fieldDescs.length; i++)
413         {
414             addFieldImage(imageMap, fieldDescs[i]);
415         }
416     }
417
418     private void addFieldImage(Map JavaDoc imageMap, FieldDescriptor fld)
419     {
420         // register copies of all field values
421
Object JavaDoc value = fld.getPersistentField().get(myObj);
422         // get the real sql type value
423
value = fld.getFieldConversion().javaToSql(value);
424         // make copy of the sql type value
425
value = fld.getJdbcType().getFieldType().copy(value);
426         // buffer in image the field name and the sql type value
427
// wrapped by a helper class
428
imageMap.put(fld.getPersistentField().getName(), new Image.Field(fld.getJdbcType().getFieldType(), value));
429     }
430
431     private void buildImageForCollectionReferences(Map JavaDoc imageMap, ClassDescriptor cld)
432     {
433         // register the 1:n and m:n references
434
Iterator JavaDoc collections = cld.getCollectionDescriptors(true).iterator();
435         CollectionDescriptor cds;
436         while(collections.hasNext())
437         {
438             cds = (CollectionDescriptor) collections.next();
439             Object JavaDoc collectionOrArray = cds.getPersistentField().get(myObj);
440             Image.MultipleRef colRef = new Image.MultipleRef(this, cds, collectionOrArray);
441             imageMap.put(cds, colRef);
442         }
443     }
444
445     /**
446      * Returns the Modification-state.
447      * @return org.apache.ojb.server.states.ModificationState
448      */

449     public ModificationState getModificationState()
450     {
451         return modificationState;
452     }
453
454     /**
455      * Returns true if the underlying Object needs an INSERT statement, else returns false.
456      */

457     public boolean needsInsert()
458     {
459         return this.getModificationState().needsInsert();
460     }
461
462     /**
463      * Returns true if the underlying Object needs an UPDATE statement, else returns false.
464      */

465     public boolean needsUpdate()
466     {
467         return this.getModificationState().needsUpdate();
468     }
469
470     /**
471      * Returns true if the underlying Object needs an UPDATE statement, else returns false.
472      */

473     public boolean needsDelete()
474     {
475         return this.getModificationState().needsDelete();
476     }
477
478     /**
479      * Sets the initial MoificationState of the wrapped object myObj. The initial state will be StateNewDirty if myObj
480      * is not persisten already. The state will be set to StateOldClean if the object is already persistent.
481      */

482     private void prepareInitialState(boolean isNewObject)
483     {
484         // determine appropriate modification state
485
ModificationState initialState;
486         if(isNewObject)
487         {
488             // if object is not already persistent it must be marked as new
489
// it must be marked as dirty because it must be stored even if it will not modified during tx
490
initialState = StateNewDirty.getInstance();
491         }
492         else if(isDeleted(oid))
493         {
494             // if object is already persistent it will be marked as old.
495
// it is marked as dirty as it has been deleted during tx and now it is inserted again,
496
// possibly with new field values.
497
initialState = StateOldDirty.getInstance();
498         }
499         else
500         {
501             // if object is already persistent it will be marked as old.
502
// it is marked as clean as it has not been modified during tx already
503
initialState = StateOldClean.getInstance();
504         }
505         // remember it:
506
modificationState = initialState;
507     }
508
509     /**
510      * Checks if the object with the given identity has been deleted
511      * within the transaction.
512      * @param id The identity
513      * @return true if the object has been deleted
514      * @throws PersistenceBrokerException
515      */

516     public boolean isDeleted(Identity id)
517     {
518         ObjectEnvelope envelope = buffer.getByIdentity(id);
519
520         return (envelope != null && envelope.needsDelete());
521     }
522
523     /**
524      * set the Modification state to a new value. Used during state transitions.
525      * @param newModificationState org.apache.ojb.server.states.ModificationState
526      */

527     public void setModificationState(ModificationState newModificationState)
528     {
529         if(newModificationState != modificationState)
530         {
531             if(log.isDebugEnabled())
532             {
533                 log.debug("object state transition for object " + this.oid + " ("
534                         + modificationState + " --> " + newModificationState + ")");
535 // try{throw new Exception();}catch(Exception e)
536
// {
537
// e.printStackTrace();
538
// }
539
}
540             modificationState = newModificationState;
541         }
542     }
543
544     /**
545      * returns a String representation.
546      * @return java.lang.String
547      */

548     public String JavaDoc toString()
549     {
550         ToStringBuilder buf = new ToStringBuilder(this);
551         buf.append("Identity", oid)
552             .append("ModificationState", modificationState.toString());
553         return buf.toString();
554     }
555
556     /**
557      * For internal use only! Only call immediately before commit to guarantee
558      * that all changes can be detected (because this method cache the detected "change state"
559      * thus on eager call changes could be ignored). Checks whether object and internal clone
560      * differ and returns <em>true</em> if so, returns <em>false</em> else.
561      *
562      * @return boolean The result.
563      */

564     public boolean hasChanged(PersistenceBroker broker)
565     {
566         if(hasChanged == null)
567         {
568             Map JavaDoc current = null;
569             try
570             {
571                 current = getCurrentImage();
572             }
573             catch(Exception JavaDoc e)
574             {
575                 log.warn("Could not verify object changes, mark dirty: " + getIdentity(), e);
576             }
577             if(beforeImage != null && current != null)
578             {
579                 Iterator JavaDoc it = beforeImage.entrySet().iterator();
580                 hasChanged = Boolean.FALSE;
581                 while(it.hasNext())
582                 {
583                     Map.Entry JavaDoc entry = (Map.Entry JavaDoc) it.next();
584                     Image imageBefore = (Image) entry.getValue();
585                     Image imageCurrent = (Image) current.get(entry.getKey());
586                     if(imageBefore.modified(imageCurrent))
587                     {
588                         hasChanged = Boolean.TRUE;
589                         break;
590                     }
591                 }
592             }
593             else
594             {
595                 hasChanged = Boolean.TRUE;
596             }
597             if(log.isDebugEnabled())
598             {
599                 log.debug("State detection for " + getIdentity() + " --> object "
600                         + (hasChanged.booleanValue() ? "has changed" : "unchanged"));
601             }
602         }
603         return hasChanged.booleanValue();
604     }
605
606     /**
607      * Mark new or deleted reference elements
608      * @param broker
609      */

610     void markReferenceElements(PersistenceBroker broker)
611     {
612         // these cases will be handled by ObjectEnvelopeTable#cascadingDependents()
613
// if(getModificationState().needsInsert() || getModificationState().needsDelete()) return;
614

615         Map JavaDoc oldImage = getBeforeImage();
616         Map JavaDoc newImage = getCurrentImage();
617
618         Iterator JavaDoc iter = newImage.entrySet().iterator();
619         while (iter.hasNext())
620         {
621             Map.Entry JavaDoc entry = (Map.Entry JavaDoc) iter.next();
622             Object JavaDoc key = entry.getKey();
623             // we only interested in references
624
if(key instanceof ObjectReferenceDescriptor)
625             {
626                 Image oldRefImage = (Image) oldImage.get(key);
627                 Image newRefImage = (Image) entry.getValue();
628                 newRefImage.performReferenceDetection(oldRefImage);
629             }
630         }
631     }
632
633     public void doUpdate()
634     {
635         if(log.isDebugEnabled()) log.debug("Start UPDATE action for " + getIdentity());
636         performLinkEntries();
637         getBroker().store(getObject(), getIdentity(), getClassDescriptor(), false, true);
638     }
639
640     public void doInsert()
641     {
642         if(log.isDebugEnabled()) log.debug("Start INSERT action for " + getIdentity());
643         performLinkEntries();
644         getBroker().store(getObject(), getIdentity(), getClassDescriptor(), true, true);
645         Identity oldOid = refreshIdentity();
646         buffer.replaceRegisteredIdentity(getIdentity(), oldOid);
647     }
648
649     public void doDelete()
650     {
651         if(log.isDebugEnabled()) log.debug("Start DELETE action for " + getIdentity());
652         getBroker().delete(getObject(), true);
653     }
654
655     public void doEvictFromCache()
656     {
657         if(log.isDebugEnabled()) log.debug("Remove from cache " + getIdentity());
658         getBroker().removeFromCache(getIdentity());
659     }
660
661     public boolean isWriteLocked()
662     {
663         return writeLocked;
664     }
665
666     public void setWriteLocked(boolean writeLocked)
667     {
668         this.writeLocked = writeLocked;
669     }
670
671     ClassDescriptor getClassDescriptor()
672     {
673         return getBroker().getClassDescriptor(ProxyHelper.getRealClass(getObject()));
674     }
675
676     void addLinkOneToOne(ObjectReferenceDescriptor ord, boolean unlink)
677     {
678         LinkEntry entry = new LinkEntryOneToOne(ord, getObject(), unlink);
679         linkEntryList.add(entry);
680     }
681
682     void addLinkOneToN(CollectionDescriptor col, Object JavaDoc source, boolean unlink)
683     {
684         if(col.isMtoNRelation()) throw new OJBRuntimeException("Expected an 1:n relation, but specified a m:n");
685         LinkEntry entry = new LinkEntryOneToN(source, col, getObject(), unlink);
686         linkEntryList.add(entry);
687     }
688
689     private void performLinkEntries()
690     {
691         PersistenceBroker broker = getBroker();
692         for(int i = 0; i < linkEntryList.size(); i++)
693         {
694             LinkEntry linkEntry = (LinkEntry) linkEntryList.get(i);
695             linkEntry.execute(broker);
696         }
697     }
698
699     public void addedOneToOne(ObjectReferenceDescriptor ord, Object JavaDoc refObjOrProxy, Identity oid)
700     {
701         // the main objects needs link/unlink of the FK to 1:1 reference,
702
// so mark this dirty
703
setModificationState(getModificationState().markDirty());
704         // if the object is already registered, OJB knows about
705
// else lock and register object, get read lock, because we
706
// don't know if the object is new or moved from an existing other object
707
ObjectEnvelope oe = buffer.getByIdentity(oid);
708         if(oe == null)
709         {
710             RuntimeObject rt = new RuntimeObject(refObjOrProxy, getTx());
711             // we don't use cascade locking, because new reference object
712
// will be detected by ObjectEnvelopeTable#cascadeMarkedForInsert()
713
getTx().lockAndRegister(rt, TransactionExt.READ, false, getTx().getRegistrationList());
714         }
715         // in any case we need to link the main object
716
addLinkOneToOne(ord, false);
717     }
718
719     public void deletedOneToOne(ObjectReferenceDescriptor ord, Object JavaDoc refObjOrProxy, Identity oid, boolean needsUnlink)
720     {
721         // the main objects needs link/unlink of the FK to 1:1 reference,
722
// so mark this dirty
723
setModificationState(getModificationState().markDirty());
724         ObjectEnvelope oldRefMod = buffer.getByIdentity(oid);
725         // only delete when the reference wasn't assigned with another object
726
if(!buffer.isNewAssociatedObject(oid))
727         {
728             // if cascading delete is enabled, remove the 1:1 reference
729
// because it was removed from the main object
730
if(buffer.getTransaction().cascadeDeleteFor(ord))
731             {
732                 oldRefMod.setModificationState(oldRefMod.getModificationState().markDelete());
733             }
734             // unlink the main object
735
if(needsUnlink) addLinkOneToOne(ord, true);
736         }
737     }
738
739     public void addedXToN(CollectionDescriptor cod, Object JavaDoc refObjOrProxy, Identity oid)
740     {
741         ObjectEnvelope mod = buffer.getByIdentity(oid);
742         // if the object isn't registered already, it can be 'new' or already 'persistent'
743
if(mod == null)
744         {
745             boolean isNew = getTx().isTransient(null, refObjOrProxy, oid);
746             mod = buffer.get(oid, refObjOrProxy, isNew);
747         }
748         // if the object was deleted in an previous action, mark as new
749
// to avoid deletion, else mark object as dirty to assign the FK of
750
// the main object
751
if(mod.needsDelete())
752         {
753             mod.setModificationState(mod.getModificationState().markNew());
754         }
755         else
756         {
757             /*
758             arminw: if the reference is a m:n relation and the object state is
759             old clean, no need to update the reference.
760             */

761             if(!(cod.isMtoNRelation() && mod.getModificationState().equals(StateOldClean.getInstance())))
762             {
763                 mod.setModificationState(mod.getModificationState().markDirty());
764             }
765         }
766         // buffer this object as "new" in a list to prevent deletion
767
// when object was moved from one collection to another
768
buffer.addNewAssociatedIdentity(oid);
769         // new referenced object found, so register all m:n relation for "linking"
770
if(cod.isMtoNRelation())
771         {
772             buffer.addM2NLinkEntry(cod, getObject(), refObjOrProxy);
773         }
774         else
775         {
776             // we have to link the new object
777
mod.addLinkOneToN(cod, getObject(), false);
778         }
779         if(mod.needsInsert())
780         {
781             buffer.addForInsertDependent(mod);
782         }
783     }
784
785     public void deletedXToN(CollectionDescriptor cod, Object JavaDoc refObjOrProxy, Identity oid)
786     {
787         ObjectEnvelope mod = buffer.getByIdentity(oid);
788         // if this object is associated with another object it's
789
// not allowed to remove it, thus nothing will change
790
if(!buffer.isNewAssociatedObject(oid))
791         {
792             if(mod != null)
793             {
794                 boolean cascade = buffer.getTransaction().cascadeDeleteFor(cod);
795                 if(cascade)
796                 {
797                     mod.setModificationState(mod.getModificationState().markDelete());
798                     buffer.addForDeletionDependent(mod);
799                 }
800                 if(cod.isMtoNRelation())
801                 {
802                     buffer.addM2NUnlinkEntry(cod, getObject(), refObjOrProxy);
803                 }
804                 else
805                 {
806                     // when cascade 'true' we remove all dependent objects, so no need
807
// to unlink, else we have to unlink all referenced objects of this
808
// object
809
if(!cascade)
810                     {
811                         mod.setModificationState(mod.getModificationState().markDirty());
812                         mod.addLinkOneToN(cod, getObject(), true);
813                     }
814                 }
815             }
816             else
817             {
818                 throw new Image.ImageException("Unexpected behaviour, unregistered object to delete: "
819                         + oid + ", main object is " + getIdentity()+ ", envelope object is " + this.toString());
820             }
821         }
822     }
823 }
Popular Tags