KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > oracle > toplink > essentials > descriptors > FetchGroupManager


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
5  * in compliance with the License.
6  *
7  * You can obtain a copy of the license at
8  * glassfish/bootstrap/legal/CDDLv1.0.txt or
9  * https://glassfish.dev.java.net/public/CDDLv1.0.html.
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 in each file and include the License file at
15  * glassfish/bootstrap/legal/CDDLv1.0.txt. If applicable,
16  * add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your
18  * own identifying information: Portions Copyright [yyyy]
19  * [name of copyright owner]
20  */

21 // Copyright (c) 1998, 2006, Oracle. All rights reserved.
22
package oracle.toplink.essentials.descriptors;
23
24 import java.util.*;
25 import oracle.toplink.essentials.exceptions.QueryException;
26 import oracle.toplink.essentials.internal.descriptors.ObjectBuilder;
27 import oracle.toplink.essentials.internal.descriptors.OptimisticLockingPolicy;
28 import oracle.toplink.essentials.internal.helper.DatabaseField;
29 import oracle.toplink.essentials.mappings.DatabaseMapping;
30 import oracle.toplink.essentials.descriptors.ClassDescriptor;
31 import oracle.toplink.essentials.internal.sessions.UnitOfWorkImpl;
32 import oracle.toplink.essentials.queryframework.FetchGroup;
33 import oracle.toplink.essentials.queryframework.FetchGroupTracker;
34 import oracle.toplink.essentials.queryframework.ObjectLevelReadQuery;
35
36 /**
37  * <p><b>Purpose</b>: The fetch group manager controls the named fetch groups defined at
38  * the descriptor level. TopLink supports multiple, overlapped fetch groups, optionally with
39  * one of them as the default fetch group.
40  *
41  * The domain object must implement oracle.toplink.essentials.queryframework.FetchGroupTracker interface,
42  * in order to make use of the fetch group performance enhancement feature.
43  *
44  * Please refer to FetchGroup class for the prons and cons of fetch group usage.
45  *
46  * @see oracle.toplink.essentials.queryframework.FetchGroup
47  * @see oracle.toplink.essentials.queryframework.FetchGroupTracker
48  *
49  * @author King Wang
50  * @since TopLink 10.1.3.
51  */

52 public class FetchGroupManager {
53     //The group map is keyed by the group name, valued by the fetch group object.
54
private Map fetchGroups = null;
55
56     //default fetch group
57
private FetchGroup defaultFetchGroup;
58
59     //ref to the descriptor
60
private ClassDescriptor descriptor;
61
62     /**
63      * Constructor
64      */

65     public FetchGroupManager() {
66     }
67
68     /**
69      * Add a named fetch group to the descriptor
70      */

71     public void addFetchGroup(FetchGroup group) {
72         //create a new fetch group and put it in the group map.
73
getFetchGroups().put(group.getName(), group);
74     }
75
76     /**
77      * Return the fetch group map: keyed by the group name, valued by the fetch group object.
78      */

79     public Map getFetchGroups() {
80         if (fetchGroups == null) {
81             //lazy initialized
82
fetchGroups = new HashMap(2);
83         }
84
85         return fetchGroups;
86     }
87
88     /**
89      * Return the descriptor-level default fetch group.
90      * All read object and read all queries would use the default fetch group if no fetch group
91      * is explicitly defined for the query, unless setShouldUseDefaultFetchGroup(false); is also
92      * called on the query.
93      *
94      * Default fetch group should be used carefully. It would be beneficial if most of the system queries
95      * are for the subset of the object, so un-needed attributes data would not have to be read, and the
96      * users do not have to setup every query for the given fetch group, as default one is always used.
97      * However, if queries on object are mostly use case specific and not systematic, using default fetch group
98      * could cause undesirable extra round-trip and performance degradation.
99      *
100      * @see oracle.toplink.essentials.queryframework.ObjectLevelReadQuery#setShouldUseDefaultFetchGroup(boolean)
101      */

102     public FetchGroup getDefaultFetchGroup() {
103         return defaultFetchGroup;
104     }
105
106     /**
107      * Return a pre-defined named fetch group.
108      */

109     public FetchGroup getFetchGroup(String JavaDoc groupName) {
110         return (FetchGroup)getFetchGroups().get(groupName);
111     }
112
113     /**
114      * Set the descriptor-level default fetch group.
115      * All read object and read all queries would use the default fetch group if no fetch group is
116      * explicitly defined for the query, unless setShouldUseDefaultFetchGroup(false);
117      * is also called on the query.
118      *
119      * Default fetch group should be used carefully. It would be beneficial if most of the system queries
120      * are for the subset of the object, so un-needed attributes data would not have to be read, and the
121      * users do not have to setup every query for the given fetch group, as default one is always used.
122      * However, if queries on object are mostly use case specific and not systematic, using default fetch group
123      * could cause undesirable extra round-trip and performance degradation.
124      *
125      * @see oracle.toplink.essentials.queryframework.ObjectLevelReadQuery#setShouldUseDefaultFetchGroup(boolean)
126      */

127     public void setDefaultFetchGroup(FetchGroup newDefaultFetchGroup) {
128         defaultFetchGroup = newDefaultFetchGroup;
129     }
130
131     /**
132      * INTERNAL:
133      * Return true if the object is partially fetched and cached.
134      * It applies to the query with fetch group.
135      */

136     public boolean isPartialObject(Object JavaDoc domainObject) {
137         if (domainObject != null) {
138             FetchGroup fetchGroupInCache = ((FetchGroupTracker)domainObject).getFetchGroup();
139
140             //if the fetch group reference is not null, it means the object is partial.
141
return (fetchGroupInCache != null);
142         }
143         return false;
144     }
145
146     /**
147      * INTERNAL:
148      * Return if the cached object data is sufficiently valid against a fetch group
149      */

150     public boolean isObjectValidForFetchGroup(Object JavaDoc object, FetchGroup fetchGroup) {
151         FetchGroup groupInObject = ((FetchGroupTracker)object).getFetchGroup();
152         return (groupInObject == null) || groupInObject.isSupersetOf(fetchGroup);
153     }
154
155     /**
156      * INTERNAL:
157      * Return true if the cached object data should be written in clone.
158      * It is used in Fetch Group case when filling in the clone from the cached object.
159      */

160     public boolean shouldWriteInto(Object JavaDoc cachedObject, Object JavaDoc clone) {
161         if (isPartialObject(clone)) {
162             FetchGroup fetchGroupInSrc = ((FetchGroupTracker)cachedObject).getFetchGroup();
163             FetchGroup fetchGroupInTarg = ((FetchGroupTracker)clone).getFetchGroup();
164
165             //if the target fetch group is not null (i.e. fully fetched object) or if partially fetched, it's not a superset of that of the source,
166
//or if refresh is required, should always write (either refresh or revert) data from the cache to the clones.
167
return (!((fetchGroupInTarg == null) || fetchGroupInTarg.isSupersetOf(fetchGroupInSrc)) || ((FetchGroupTracker)cachedObject).shouldRefreshFetchGroup());
168         }
169         return false;
170     }
171
172     /**
173     * INTERNAL:
174     * Write data of the partially fetched object into the working and backup clones
175     */

176     public void writePartialIntoClones(Object JavaDoc partialObject, Object JavaDoc workingClone, UnitOfWorkImpl uow) {
177         FetchGroup fetchGroupInClone = ((FetchGroupTracker)workingClone).getFetchGroup();
178         FetchGroup fetchGroupInObject = ((FetchGroupTracker)partialObject).getFetchGroup();
179         Object JavaDoc backupClone = uow.getBackupClone(workingClone);
180
181         //if refresh is set, force to fill in fecth group data
182
if (((FetchGroupTracker)partialObject).shouldRefreshFetchGroup()) {
183             //refresh and fill in the fecth group data
184
refreshFetchGroupIntoClones(partialObject, workingClone, backupClone, fetchGroupInObject, fetchGroupInClone, uow);
185         } else {//no refresh is enforced
186
//revert the unfetched attributes of the clones.
187
revertDataIntoUnfetchedAttributesOfClones(partialObject, workingClone, backupClone, fetchGroupInObject, fetchGroupInClone, uow);
188         }
189
190         //update fecth group in clone as the union of two
191
fetchGroupInObject = unionFetchGroups(fetchGroupInObject, fetchGroupInClone);
192         //finally, update clone's fetch group reference
193
setObjectFetchGroup(workingClone, fetchGroupInObject);
194         setObjectFetchGroup(backupClone, fetchGroupInObject);
195     }
196
197     /**
198      * Refresh the fetch group data into the working and backup clones.
199      * This is called if refresh is enforced
200      */

201     private void refreshFetchGroupIntoClones(Object JavaDoc cachedObject, Object JavaDoc workingClone, Object JavaDoc backupClone, FetchGroup fetchGroupInObject, FetchGroup fetchGroupInClone, UnitOfWorkImpl uow) {
202         Vector mappings = descriptor.getMappings();
203         boolean isObjectPartial = (fetchGroupInObject != null);
204         Set fetchedAttributes = isObjectPartial ? fetchGroupInObject.getAttributes() : null;
205         for (int index = 0; index < mappings.size(); index++) {
206             DatabaseMapping mapping = (DatabaseMapping)mappings.get(index);
207             if ((!isObjectPartial) || ((fetchedAttributes != null) && fetchedAttributes.contains(mapping.getAttributeName()))) {
208                 //only fill in the unfetched attributes into clones
209
mapping.buildClone(cachedObject, workingClone, uow, null);
210                 mapping.buildClone(workingClone, backupClone, uow, null);
211             }
212         }
213     }
214
215     /**
216      * Revert the clones' unfetched attributes, and leave fetched ones intact.
217      */

218     private void revertDataIntoUnfetchedAttributesOfClones(Object JavaDoc cachedObject, Object JavaDoc workingClone, Object JavaDoc backupClone, FetchGroup fetchGroupInObject, FetchGroup fetchGroupInClone, UnitOfWorkImpl uow) {
219         //if(fetchGroupInClone == null || fetchGroupInClone.isSupersetOf(fetchGroupInObject)) {
220
if (isObjectValidForFetchGroup(workingClone, fetchGroupInObject)) {
221             //if working clone is fully fetched or it's fetch group is superset of that of the cached object
222
//no reversion is needed, so simply return
223
return;
224         }
225         Vector mappings = descriptor.getMappings();
226
227         //fetched attributes list in working clone
228
Set fetchedAttributesClone = fetchGroupInClone.getAttributes();
229         for (int index = 0; index < mappings.size(); index++) {
230             DatabaseMapping mapping = (DatabaseMapping)mappings.get(index);
231
232             //only revert the attribute which is fetched by the cached object, but not fecthed by the clones.
233
if (isAttributeFetched(cachedObject, mapping.getAttributeName()) && (!fetchedAttributesClone.contains(mapping.getAttributeName()))) {
234                 //only fill in the unfetched attributes into clones
235
mapping.buildClone(cachedObject, workingClone, uow, null);
236                 mapping.buildClone(workingClone, backupClone, uow, null);
237             }
238         }
239     }
240
241     /**
242      * INTERNAL:
243      * Copy fetch group refrerence from the source object to the target
244      */

245     public void copyFetchGroupInto(Object JavaDoc source, Object JavaDoc target) {
246         if (isPartialObject(source)) {
247             ((FetchGroupTracker)target).setFetchGroup(((FetchGroupTracker)source).getFetchGroup());
248         }
249     }
250
251     /**
252      * INTERNAL:
253      * Union the fetch group of the domain object with the new fetch group.
254      */

255     public void unionFetchGroupIntoObject(Object JavaDoc source, FetchGroup newFetchGroup) {
256         FetchGroupTracker tracker = (FetchGroupTracker)source;
257         tracker.setFetchGroup(unionFetchGroups(tracker.getFetchGroup(), newFetchGroup));
258     }
259
260     /**
261      * INTERNAL:
262      * Union two fetch groups.
263      */

264     public FetchGroup unionFetchGroups(FetchGroup first, FetchGroup second) {
265         if ((first == null) || (second == null)) {
266             return null;
267         }
268
269         //return the superset if applied
270
if (first.isSupersetOf(second)) {
271             return first;
272         } else if (second.isSupersetOf(first)) {
273             return second;
274         }
275
276         //otherwise, union two fetch groups
277
StringBuffer JavaDoc unionGroupName = new StringBuffer JavaDoc(first.getName());
278         unionGroupName.append("_");
279         unionGroupName.append(second.getName());
280         FetchGroup unionFetchGroup = new FetchGroup(unionGroupName.toString());
281         unionFetchGroup.addAttributes(first.getAttributes());
282         unionFetchGroup.addAttributes(second.getAttributes());
283         return unionFetchGroup;
284     }
285
286     /**
287      * INTERNAL:
288      * Reset object attributes to the default values.
289      */

290     public void reset(Object JavaDoc source) {
291         ((FetchGroupTracker)source).resetFetchGroup();
292     }
293
294     /**
295      * INTERNAL:
296      * Reset object attributes to the default their values.
297      */

298     public void setObjectFetchGroup(Object JavaDoc source, FetchGroup fetchGroup) {
299         if (descriptor.getFetchGroupManager() != null) {
300             ((FetchGroupTracker)source).setFetchGroup(fetchGroup);
301         }
302     }
303
304     /**
305      * INTERNAL:
306      * Set if the tracked object is fetched from executing a query with or without refresh.
307      */

308     public void setRefreshOnFetchGroupToObject(Object JavaDoc source, boolean shouldRefreshOnFetchgroup) {
309         ((FetchGroupTracker)source).setShouldRefreshFetchGroup(shouldRefreshOnFetchgroup);
310     }
311
312     /**
313      * Return true if the attribute of the object has already been fetched
314      */

315     public boolean isAttributeFetched(Object JavaDoc object, String JavaDoc attributeName) {
316         FetchGroup fetchgroup = ((FetchGroupTracker)object).getFetchGroup();
317         return (fetchgroup == null) || (fetchgroup.getAttributes().contains(attributeName));
318     }
319
320     /**
321      * INTERNAL:
322      * Return the referenced descriptor.
323      */

324     public ClassDescriptor getDescriptor() {
325         return descriptor;
326     }
327
328     /**
329      * INTERNAL:
330      * Return the referenced descriptor.
331      */

332     public ClassDescriptor getClassDescriptor() {
333         return getDescriptor();
334     }
335
336     /**
337      * Set the referenced descriptor.
338      */

339     public void setDescriptor(ClassDescriptor descriptor) {
340         this.descriptor = descriptor;
341     }
342
343     /**
344      * INTERNAL:
345      * Prepare the query with the fetch group to add group attributes to the query
346      * for partial reading.
347      */

348     public void prepareQueryWithFetchGroup(ObjectLevelReadQuery query) {
349         //initialize query's fetch group
350
query.initializeFetchGroup();
351         if ((query.getFetchGroup() == null) || query.getFetchGroup().hasFetchGroupAttributeExpressions()) {
352             //simply return if fetch group is not defined; or if defined, it has been prepared already.
353
return;
354         } else {
355             if (query.isReportQuery()) {
356                 //fetch group does not work with report query
357
throw QueryException.fetchGroupNotSupportOnReportQuery();
358             }
359             if (query.hasPartialAttributeExpressions()) {
360                 //fetch group does not work with partial attribute reading
361
throw QueryException.fetchGroupNotSupportOnPartialAttributeReading();
362             }
363         }
364         Set attributes = query.getFetchGroup().getAttributes();
365         ObjectBuilder builder = query.getDescriptor().getObjectBuilder();
366
367         //First add all primary key attributes into the fetch group
368
Iterator pkMappingIter = builder.getPrimaryKeyMappings().iterator();
369
370         while (pkMappingIter.hasNext()) {
371             DatabaseMapping pkMapping = (DatabaseMapping)pkMappingIter.next();
372             DatabaseField pkField = pkMapping.getField();
373
374             // Add pk attribute to the fetch group attributes list
375
attributes.add(pkMapping.getAttributeName());
376         }
377
378         //second, add version/optimistic locking object attributes into the fetch group if applied.
379
OptimisticLockingPolicy lockingPolicy = getDescriptor().getOptimisticLockingPolicy();
380         if (query.shouldMaintainCache() && (lockingPolicy != null)) {
381             lockingPolicy.prepareFetchGroupForReadQuery(query.getFetchGroup(), query);
382         }
383
384         //thrid, prepare all fetch group attributes
385
Iterator attrIter = attributes.iterator();
386         while (attrIter.hasNext()) {
387             String JavaDoc attrName = (String JavaDoc)attrIter.next();
388             DatabaseMapping mapping = builder.getMappingForAttributeName(attrName);
389             if (mapping == null) {
390                 //the attribute name defined in the fetch group is not mapped
391
throw QueryException.fetchGroupAttributeNotMapped(attrName);
392             }
393
394             //partially fetch each fetch group attribute
395
if (mapping.isCollectionMapping()) {
396                 query.getFetchGroup().addFetchGroupAttribute(query.getExpressionBuilder().anyOf(attrName));
397             } else {
398                 query.getFetchGroup().addFetchGroupAttribute(query.getExpressionBuilder().get(attrName));
399             }
400         }
401     }
402
403     /**
404     * INTERNAL:
405     * Clone the fetch group manager
406     */

407     public Object JavaDoc clone() {
408         Object JavaDoc object = null;
409         try {
410             object = super.clone();
411         } catch (Exception JavaDoc exception) {
412             ;
413         }
414         return object;
415     }
416 }
417
Popular Tags