KickJava   Java API By Example, From Geeks To Geeks.

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


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.HashMap JavaDoc;
25 import java.util.Iterator JavaDoc;
26 import java.util.List JavaDoc;
27 import java.util.Map JavaDoc;
28
29 import org.apache.commons.collections.Factory;
30 import org.apache.cayenne.CayenneRuntimeException;
31 import org.apache.cayenne.DataObject;
32 import org.apache.cayenne.DataRow;
33 import org.apache.cayenne.ObjectId;
34 import org.apache.cayenne.Persistent;
35 import org.apache.cayenne.graph.CompoundDiff;
36 import org.apache.cayenne.graph.NodeIdChangeOperation;
37 import org.apache.cayenne.map.DbEntity;
38 import org.apache.cayenne.map.ObjAttribute;
39 import org.apache.cayenne.map.ObjEntity;
40 import org.apache.cayenne.reflect.AttributeProperty;
41 import org.apache.cayenne.reflect.ClassDescriptor;
42
43 /**
44  * A superclass of batch query wrappers.
45  *
46  * @since 1.2
47  * @author Andrus Adamchik
48  */

49 abstract class DataDomainSyncBucket {
50
51     final Map JavaDoc objectsByDescriptor;
52     final DataDomainFlushAction parent;
53
54     List JavaDoc dbEntities;
55     Map JavaDoc descriptorsByDbEntity;
56
57     DataDomainSyncBucket(DataDomainFlushAction parent) {
58         this.objectsByDescriptor = new HashMap JavaDoc();
59         this.parent = parent;
60     }
61
62     boolean isEmpty() {
63         return objectsByDescriptor.isEmpty();
64     }
65
66     abstract void appendQueriesInternal(Collection JavaDoc queries);
67
68     /**
69      * Appends all queries originated in the bucket to provided collection.
70      */

71     void appendQueries(Collection JavaDoc queries) {
72
73         if (!objectsByDescriptor.isEmpty()) {
74             groupObjEntitiesBySpannedDbEntities();
75             appendQueriesInternal(queries);
76         }
77     }
78
79     void checkReadOnly(ObjEntity entity) throws CayenneRuntimeException {
80
81         if (entity.isReadOnly()) {
82
83             StringBuffer JavaDoc message = new StringBuffer JavaDoc();
84             message
85                     .append("Attempt to modify object(s) mapped to a read-only entity: ")
86                     .append(entity.getName());
87
88             if (entity != null) {
89                 message.append(" '").append(entity.getName()).append("'");
90             }
91
92             message.append(". Can't commit changes.");
93             throw new CayenneRuntimeException(message.toString());
94         }
95     }
96
97     private void groupObjEntitiesBySpannedDbEntities() {
98
99         dbEntities = new ArrayList JavaDoc(objectsByDescriptor.size());
100         descriptorsByDbEntity = new HashMap JavaDoc(objectsByDescriptor.size() * 2);
101
102         Iterator JavaDoc i = objectsByDescriptor.keySet().iterator();
103         while (i.hasNext()) {
104             ClassDescriptor descriptor = (ClassDescriptor) i.next();
105             DbEntity dbEntity = descriptor.getEntity().getDbEntity();
106
107             List JavaDoc objEntitiesForDbEntity = (List JavaDoc) descriptorsByDbEntity.get(dbEntity);
108             if (objEntitiesForDbEntity == null) {
109                 objEntitiesForDbEntity = new ArrayList JavaDoc(1);
110                 dbEntities.add(dbEntity);
111                 descriptorsByDbEntity.put(dbEntity, objEntitiesForDbEntity);
112             }
113
114             if (!objEntitiesForDbEntity.contains(descriptor)) {
115                 objEntitiesForDbEntity.add(descriptor);
116             }
117
118             // Note that this logic won't allow flattened attributes to span multiple
119
// databases...
120
Iterator JavaDoc j = descriptor.getEntity().getAttributeMap().values().iterator();
121             while (j.hasNext()) {
122                 Object JavaDoc next = j.next();
123
124                 // TODO: andrus, 2/10/2007 - handle embedded
125
if (!(next instanceof ObjAttribute)) {
126                     continue;
127                 }
128
129                 ObjAttribute objAttribute = (ObjAttribute) next;
130                 if (!objAttribute.isCompound()) {
131                     continue;
132                 }
133
134                 dbEntity = (DbEntity) objAttribute.getDbAttribute().getEntity();
135                 objEntitiesForDbEntity = (List JavaDoc) descriptorsByDbEntity.get(dbEntity);
136
137                 if (objEntitiesForDbEntity == null) {
138                     objEntitiesForDbEntity = new ArrayList JavaDoc(1);
139                     dbEntities.add(dbEntity);
140                     descriptorsByDbEntity.put(dbEntity, objEntitiesForDbEntity);
141                 }
142
143                 if (!objEntitiesForDbEntity.contains(descriptor)) {
144                     objEntitiesForDbEntity.add(descriptor);
145                 }
146             }
147         }
148     }
149
150     void addDirtyObject(Object JavaDoc object, ClassDescriptor descriptor) {
151
152         Collection JavaDoc objects = (Collection JavaDoc) objectsByDescriptor.get(descriptor);
153         if (objects == null) {
154
155             objects = new ArrayList JavaDoc();
156             objectsByDescriptor.put(descriptor, objects);
157         }
158
159         objects.add(object);
160     }
161
162     void postprocess() {
163
164         if (!objectsByDescriptor.isEmpty()) {
165
166             CompoundDiff result = parent.getResultDiff();
167             Map JavaDoc modifiedSnapshots = parent.getResultModifiedSnapshots();
168             Collection JavaDoc deletedIds = parent.getResultDeletedIds();
169
170             Iterator JavaDoc it = objectsByDescriptor.entrySet().iterator();
171             while (it.hasNext()) {
172
173                 Map.Entry JavaDoc entry = (Map.Entry JavaDoc) it.next();
174                 ClassDescriptor descriptor = (ClassDescriptor) entry.getKey();
175
176                 Iterator JavaDoc objects = ((Collection JavaDoc) entry.getValue()).iterator();
177                 while (objects.hasNext()) {
178                     Persistent object = (Persistent) objects.next();
179                     ObjectId id = object.getObjectId();
180
181                     ObjectId finalId;
182
183                     // record id change and update attributes for generated ids
184
if (id.isReplacementIdAttached()) {
185
186                         Map JavaDoc replacement = id.getReplacementIdMap();
187                         Iterator JavaDoc idProperties = descriptor.getIdProperties();
188                         while (idProperties.hasNext()) {
189                             AttributeProperty property = (AttributeProperty) idProperties
190                                     .next();
191                             Object JavaDoc value = replacement.get(property
192                                     .getAttribute()
193                                     .getDbAttributeName());
194
195                             // TODO: andrus, 11/28/2006: this operation may be redundant
196
// if the id wasn't generated. We may need to optimize it...
197
if (value != null) {
198                                 property.writePropertyDirectly(object, null, value);
199                             }
200                         }
201
202                         ObjectId replacementId = id.createReplacementId();
203
204                         result.add(new NodeIdChangeOperation(id, replacementId));
205
206                         // classify replaced permanent ids as "deleted", as
207
// DataRowCache has no notion of replaced id...
208
if (!id.isTemporary()) {
209                             deletedIds.add(id);
210                         }
211
212                         finalId = replacementId;
213                     }
214                     else if (id.isTemporary()) {
215                         throw new CayenneRuntimeException(
216                                 "Temporary ID hasn't been replaced on commit: " + object);
217                     }
218                     else {
219                         finalId = id;
220
221                     }
222
223                     // do not take the snapshot until generated columns are processed (see
224
// code above)
225
DataRow dataRow = parent.getContext().currentSnapshot(object);
226
227                     if (object instanceof DataObject) {
228                         DataObject dataObject = (DataObject) object;
229                         dataRow.setReplacesVersion(dataObject.getSnapshotVersion());
230                         dataObject.setSnapshotVersion(dataRow.getVersion());
231                     }
232
233                     modifiedSnapshots.put(finalId, dataRow);
234                 }
235             }
236         }
237     }
238
239     // a factory for extracting PKs generated on commit.
240
final static class PropagatedValueFactory implements Factory {
241
242         ObjectId masterID;
243         String JavaDoc masterKey;
244
245         PropagatedValueFactory(ObjectId masterID, String JavaDoc masterKey) {
246             this.masterID = masterID;
247             this.masterKey = masterKey;
248         }
249
250         public Object JavaDoc create() {
251             Object JavaDoc value = masterID.getIdSnapshot().get(masterKey);
252             if (value == null) {
253                 throw new CayenneRuntimeException("Can't extract a master key. "
254                         + "Missing key ("
255                         + masterKey
256                         + "), master ID ("
257                         + masterID
258                         + ")");
259             }
260
261             return value;
262         }
263     }
264 }
265
Popular Tags