KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > cayenne > access > DataContextDeleteAction


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

19
20 package org.apache.cayenne.access;
21
22 import java.util.ArrayList JavaDoc;
23 import java.util.Collection JavaDoc;
24 import java.util.Collections JavaDoc;
25 import java.util.Iterator JavaDoc;
26 import java.util.List JavaDoc;
27
28 import org.apache.cayenne.CayenneRuntimeException;
29 import org.apache.cayenne.DeleteDenyException;
30 import org.apache.cayenne.PersistenceState;
31 import org.apache.cayenne.Persistent;
32 import org.apache.cayenne.map.DeleteRule;
33 import org.apache.cayenne.map.ObjRelationship;
34 import org.apache.cayenne.reflect.ArcProperty;
35 import org.apache.cayenne.reflect.AttributeProperty;
36 import org.apache.cayenne.reflect.ClassDescriptor;
37 import org.apache.cayenne.reflect.PropertyVisitor;
38 import org.apache.cayenne.reflect.ToManyProperty;
39 import org.apache.cayenne.reflect.ToOneProperty;
40
41 /**
42  * Helper class that implements DataObject deletion strategy.
43  *
44  * @since 1.2
45  * @author Andrus Adamchik
46  */

47 class DataContextDeleteAction {
48
49     DataContext dataContext;
50
51     DataContextDeleteAction(DataContext context) {
52         this.dataContext = context;
53     }
54
55     /**
56      * Deletes internal DataObject from its DataContext, processing delete rules.
57      */

58     boolean performDelete(Persistent object) throws DeleteDenyException {
59         int oldState = object.getPersistenceState();
60         if (oldState == PersistenceState.DELETED
61                 || oldState == PersistenceState.TRANSIENT) {
62
63             // Drop out... especially in case of DELETED we might be about to get
64
// into a horrible recursive loop due to CASCADE delete rules.
65
// Assume that everything must have been done correctly already
66
// and *don't* do it again
67
return false;
68         }
69
70         if (object.getObjectContext() == null) {
71             throw new CayenneRuntimeException(
72                     "Attempt to delete unregistered non-TRANSIENT object: " + object);
73         }
74
75         if (object.getObjectContext() != dataContext) {
76             throw new CayenneRuntimeException(
77                     "Attempt to delete object registered in a different DataContext. Object: "
78                             + object
79                             + ", data context: "
80                             + dataContext);
81         }
82
83         // must resolve HOLLOW objects before delete... needed
84
// to process relationships and optimistic locking...
85

86         dataContext.prepareForAccess(object, null, false);
87
88         if (oldState == PersistenceState.NEW) {
89             deleteNew(object, oldState);
90         }
91         else {
92             deletePersistent(object, oldState);
93         }
94
95         return true;
96     }
97
98     private void deletePersistent(Persistent object, int oldState)
99             throws DeleteDenyException {
100
101         object.setPersistenceState(PersistenceState.DELETED);
102         dataContext.getObjectStore().nodeRemoved(object.getObjectId());
103         processDeleteRules(object, oldState);
104     }
105
106     private void deleteNew(Persistent object, int oldState) throws DeleteDenyException {
107         object.setPersistenceState(PersistenceState.TRANSIENT);
108         processDeleteRules(object, oldState);
109
110         // if an object was NEW, we must throw it out of the ObjectStore
111

112         dataContext.getObjectStore().objectsUnregistered(
113                 Collections.singletonList(object));
114         object.setObjectContext(null);
115     }
116
117     private void processDeleteRules(final Persistent object, int oldState)
118             throws DeleteDenyException {
119
120         ClassDescriptor descriptor = dataContext.getEntityResolver().getClassDescriptor(
121                 object.getObjectId().getEntityName());
122
123         Iterator JavaDoc it = descriptor.getEntity().getRelationships().iterator();
124         while (it.hasNext()) {
125             ObjRelationship relationship = (ObjRelationship) it.next();
126
127             boolean processFlattened = relationship.isFlattened()
128                     && relationship.isToDependentEntity() && !relationship.isReadOnly();
129
130             // first check for no action... bail out if no flattened processing is needed
131
if (relationship.getDeleteRule() == DeleteRule.NO_ACTION && !processFlattened) {
132                 continue;
133             }
134
135             List JavaDoc relatedObjects = Collections.EMPTY_LIST;
136
137             ArcProperty property = (ArcProperty) descriptor.getProperty(relationship
138                     .getName());
139             Object JavaDoc related = property.readProperty(object);
140
141             if (relationship.isToMany()) {
142
143                 List JavaDoc toMany = (List JavaDoc) related;
144                 if (toMany.size() > 0) {
145                     // Get a copy of the list so that deleting objects doesn't
146
// result in concurrent modification exceptions
147
relatedObjects = new ArrayList JavaDoc(toMany);
148                 }
149             }
150             else {
151                 if (related != null) {
152                     relatedObjects = Collections.singletonList(related);
153                 }
154             }
155
156             // no related object, bail out
157
if (relatedObjects.size() == 0) {
158                 continue;
159             }
160
161             // process DENY rule first...
162
if (relationship.getDeleteRule() == DeleteRule.DENY) {
163                 object.setPersistenceState(oldState);
164
165                 String JavaDoc message = relatedObjects.size() == 1
166                         ? "1 related object"
167                         : relatedObjects.size() + " related objects";
168                 throw new DeleteDenyException(object, relationship.getName(), message);
169             }
170
171             // process flattened with dependent join tables...
172
// joins must be removed even if they are non-existent or ignored in the
173
// object graph
174
if (processFlattened) {
175                 ObjectStore objectStore = dataContext.getObjectStore();
176                 Iterator JavaDoc iterator = relatedObjects.iterator();
177                 while (iterator.hasNext()) {
178                     Persistent relatedObject = (Persistent) iterator.next();
179                     objectStore.arcDeleted(object.getObjectId(), relatedObject
180                             .getObjectId(), relationship.getName());
181                 }
182             }
183
184             // process remaining rules
185
switch (relationship.getDeleteRule()) {
186                 case DeleteRule.NO_ACTION:
187                     break;
188                 case DeleteRule.NULLIFY:
189                     ArcProperty reverseArc = property.getComplimentaryReverseArc();
190
191                     if (reverseArc == null) {
192                         // nothing we can do here
193
break;
194                     }
195
196                     final Collection JavaDoc finalRelatedObjects = relatedObjects;
197
198                     reverseArc.visit(new PropertyVisitor() {
199
200                         public boolean visitAttribute(AttributeProperty property) {
201                             return false;
202                         }
203
204                         public boolean visitToMany(ToManyProperty property) {
205                             Iterator JavaDoc iterator = finalRelatedObjects.iterator();
206                             while (iterator.hasNext()) {
207                                 Object JavaDoc relatedObject = iterator.next();
208                                 property.removeTarget(relatedObject, object, true);
209                             }
210
211                             return false;
212                         }
213
214                         public boolean visitToOne(ToOneProperty property) {
215                             // Inverse is to-one - find all related objects and
216
// nullify the reverse relationship
217
Iterator JavaDoc iterator = finalRelatedObjects.iterator();
218                             while (iterator.hasNext()) {
219                                 Object JavaDoc relatedObject = iterator.next();
220                                 property.setTarget(relatedObject, null, true);
221                             }
222                             return false;
223                         }
224                     });
225
226                     break;
227                 case DeleteRule.CASCADE:
228                     // Delete all related objects
229
Iterator JavaDoc iterator = relatedObjects.iterator();
230                     while (iterator.hasNext()) {
231                         Persistent relatedObject = (Persistent) iterator.next();
232                         new DataContextDeleteAction(this.dataContext)
233                                 .performDelete(relatedObject);
234                     }
235
236                     break;
237                 default:
238                     object.setPersistenceState(oldState);
239                     throw new CayenneRuntimeException("Invalid delete rule "
240                             + relationship.getDeleteRule());
241             }
242         }
243     }
244 }
245
Popular Tags