KickJava   Java API By Example, From Geeks To Geeks.

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


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.HashMap JavaDoc;
24 import java.util.Iterator JavaDoc;
25 import java.util.List JavaDoc;
26 import java.util.Map JavaDoc;
27
28 import org.apache.cayenne.CayenneRuntimeException;
29 import org.apache.cayenne.DataObject;
30 import org.apache.cayenne.DataRow;
31 import org.apache.cayenne.ObjectId;
32 import org.apache.cayenne.PersistenceState;
33 import org.apache.cayenne.Persistent;
34 import org.apache.cayenne.map.DbAttribute;
35 import org.apache.cayenne.map.DbEntity;
36 import org.apache.cayenne.map.EntityInheritanceTree;
37 import org.apache.cayenne.map.ObjEntity;
38 import org.apache.cayenne.reflect.ClassDescriptor;
39
40 /**
41  * DataRows-to-objects converter for a specific ObjEntity.
42  *
43  * @since 1.2
44  * @author Andrus Adamchik
45  */

46 class ObjectResolver {
47
48     DataContext context;
49     ClassDescriptor descriptor;
50     List JavaDoc primaryKey;
51
52     EntityInheritanceTree inheritanceTree;
53     boolean refreshObjects;
54     boolean resolveInheritance;
55     DataRowStore cache;
56
57     ObjectResolver(DataContext context, ClassDescriptor descriptor, boolean refresh,
58             boolean resolveInheritanceHierarchy) {
59         init(context, descriptor, refresh, resolveInheritanceHierarchy);
60     }
61
62     void init(
63             DataContext context,
64             ClassDescriptor descriptor,
65             boolean refresh,
66             boolean resolveInheritanceHierarchy) {
67         // sanity check
68
DbEntity dbEntity = descriptor.getEntity().getDbEntity();
69         if (dbEntity == null) {
70             throw new CayenneRuntimeException("ObjEntity '"
71                     + descriptor.getEntity().getName()
72                     + "' has no DbEntity.");
73         }
74
75         this.primaryKey = dbEntity.getPrimaryKey();
76         if (primaryKey.size() == 0) {
77             throw new CayenneRuntimeException("Won't be able to create ObjectId for '"
78                     + descriptor.getEntity().getName()
79                     + "'. Reason: DbEntity '"
80                     + dbEntity.getName()
81                     + "' has no Primary Key defined.");
82         }
83
84         this.context = context;
85         this.cache = context.getObjectStore().getDataRowCache();
86         this.refreshObjects = refresh;
87         this.descriptor = descriptor;
88         this.inheritanceTree = context.getEntityResolver().lookupInheritanceTree(
89                 descriptor.getEntity());
90         this.resolveInheritance = (inheritanceTree != null)
91                 ? resolveInheritanceHierarchy
92                 : false;
93     }
94
95     /**
96      * Properly synchronized version of 'objectsFromDataRows'.
97      */

98     List JavaDoc synchronizedObjectsFromDataRows(List JavaDoc rows) {
99         synchronized (context.getObjectStore()) {
100             return objectsFromDataRows(rows);
101         }
102     }
103
104     /**
105      * Converts rows to objects.
106      * <p>
107      * Synchronization note. This method requires EXTERNAL synchronization on ObjectStore
108      * and DataRowStore.
109      * </p>
110      */

111     List JavaDoc objectsFromDataRows(List JavaDoc rows) {
112         if (rows == null || rows.size() == 0) {
113             return new ArrayList JavaDoc(1);
114         }
115
116         List JavaDoc results = new ArrayList JavaDoc(rows.size());
117         Iterator JavaDoc it = rows.iterator();
118
119         while (it.hasNext()) {
120             results.add(objectFromDataRow((DataRow) it.next()));
121         }
122
123         // now deal with snapshots
124
cache.snapshotsUpdatedForObjects(results, rows, refreshObjects);
125
126         return results;
127     }
128
129     /**
130      * Processes a list of rows for a result set that has objects related to a set of
131      * parent objects via some relationship defined in PrefetchProcessorNode parameter.
132      * Relationships are linked in this method, assuming that parent PK columns are
133      * included in each row and are prefixed with DB relationship name.
134      * <p>
135      * Synchronization note. This method requires EXTERNAL synchronization on ObjectStore
136      * and DataRowStore.
137      * </p>
138      */

139     List JavaDoc relatedObjectsFromDataRows(List JavaDoc rows, PrefetchProcessorNode node) {
140         if (rows == null || rows.size() == 0) {
141             return new ArrayList JavaDoc(1);
142         }
143
144         ObjEntity sourceObjEntity = (ObjEntity) node
145                 .getIncoming()
146                 .getRelationship()
147                 .getSourceEntity();
148         String JavaDoc relatedIdPrefix = node
149                 .getIncoming()
150                 .getRelationship()
151                 .getReverseDbRelationshipPath()
152                 + ".";
153
154         List JavaDoc results = new ArrayList JavaDoc(rows.size());
155         Iterator JavaDoc it = rows.iterator();
156
157         while (it.hasNext()) {
158
159             DataRow row = (DataRow) it.next();
160             Persistent object = objectFromDataRow(row);
161             results.add(object);
162
163             // link with parent
164

165             // The algorithm below of building an ID doesn't take inheritance into
166
// account, so there maybe a miss...
167
ObjectId id = createObjectId(row, sourceObjEntity, relatedIdPrefix);
168             Persistent parentObject = (Persistent) context.getObjectStore().getNode(id);
169
170             // don't attach to hollow objects
171
if (parentObject != null
172                     && parentObject.getPersistenceState() != PersistenceState.HOLLOW) {
173                 node.linkToParent(object, parentObject);
174             }
175         }
176
177         // now deal with snapshots
178
cache.snapshotsUpdatedForObjects(results, rows, refreshObjects);
179
180         return results;
181     }
182
183     /**
184      * Processes a single row. This method does not synchronize on ObjectStore and doesn't
185      * send snapshot updates. These are responsibilities of the caller.
186      */

187     Persistent objectFromDataRow(DataRow row) {
188
189         // determine entity to use
190
ClassDescriptor classDescriptor;
191
192         if (resolveInheritance) {
193             ObjEntity objectEntity = inheritanceTree.entityMatchingRow(row);
194
195             // null probably means that inheritance qualifiers are messed up
196
classDescriptor = (objectEntity != null) ? context
197                     .getEntityResolver()
198                     .getClassDescriptor(objectEntity.getName()) : descriptor;
199         }
200         else {
201             classDescriptor = descriptor;
202         }
203
204         // not using DataRow.createObjectId for performance reasons - ObjectResolver has
205
// all needed metadata already cached.
206
ObjectId anId = createObjectId(row, classDescriptor.getEntity(), null);
207
208         // this will create a HOLLOW object if it is not registered yet
209
Persistent object = context.localObject(anId, null);
210
211         // deal with object state
212
int state = object.getPersistenceState();
213         switch (state) {
214             case PersistenceState.COMMITTED:
215             case PersistenceState.MODIFIED:
216             case PersistenceState.DELETED:
217                 // process the above only if refresh is requested...
218
if (refreshObjects) {
219                     DataRowUtils.mergeObjectWithSnapshot(
220                             context,
221                             classDescriptor,
222                             object,
223                             row);
224
225                     if (object instanceof DataObject) {
226                         ((DataObject) object).setSnapshotVersion(row.getVersion());
227                     }
228                 }
229                 break;
230             case PersistenceState.HOLLOW:
231                 if (!refreshObjects) {
232                     DataRow cachedRow = cache.getCachedSnapshot(anId);
233                     if (cachedRow != null) {
234                         row = cachedRow;
235                     }
236                 }
237                 DataRowUtils.mergeObjectWithSnapshot(
238                         context,
239                         classDescriptor,
240                         object,
241                         row);
242                 if (object instanceof DataObject) {
243                     ((DataObject) object).setSnapshotVersion(row.getVersion());
244                 }
245                 break;
246             default:
247                 break;
248         }
249
250         return object;
251     }
252
253     ObjEntity getEntity() {
254         return descriptor.getEntity();
255     }
256
257     ClassDescriptor getDescriptor() {
258         return descriptor;
259     }
260
261     ObjectId createObjectId(DataRow dataRow, ObjEntity objEntity, String JavaDoc namePrefix) {
262
263         List JavaDoc pk = objEntity == this.descriptor.getEntity() ? this.primaryKey : objEntity
264                 .getDbEntity()
265                 .getPrimaryKey();
266
267         boolean prefix = namePrefix != null && namePrefix.length() > 0;
268
269         // ... handle special case - PK.size == 1
270
// use some not-so-significant optimizations...
271

272         if (pk.size() == 1) {
273             DbAttribute attribute = (DbAttribute) pk.get(0);
274
275             String JavaDoc key = (prefix) ? namePrefix + attribute.getName() : attribute
276                     .getName();
277
278             Object JavaDoc val = dataRow.get(key);
279             if (val == null) {
280                 throw new CayenneRuntimeException("Null value for '"
281                         + key
282                         + "'. Snapshot: "
283                         + dataRow
284                         + ". Prefix: "
285                         + namePrefix);
286             }
287
288             // PUT without a prefix
289
return new ObjectId(objEntity.getName(), attribute.getName(), val);
290         }
291
292         // ... handle generic case - PK.size > 1
293

294         Map JavaDoc idMap = new HashMap JavaDoc(pk.size() * 2);
295         Iterator JavaDoc it = pk.iterator();
296         while (it.hasNext()) {
297             DbAttribute attribute = (DbAttribute) it.next();
298
299             String JavaDoc key = (prefix) ? namePrefix + attribute.getName() : attribute
300                     .getName();
301
302             Object JavaDoc val = dataRow.get(key);
303             if (val == null) {
304                 throw new CayenneRuntimeException("Null value for '"
305                         + key
306                         + "'. Snapshot: "
307                         + dataRow
308                         + ". Prefix: "
309                         + namePrefix);
310             }
311
312             // PUT without a prefix
313
idMap.put(attribute.getName(), val);
314         }
315
316         return new ObjectId(objEntity.getName(), idMap);
317     }
318 }
319
Popular Tags