All Downloads are FREE. Search and download functionalities are using the official Maven repository.

oracle.toplink.essentials.descriptors.FetchGroupManager Maven / Gradle / Ivy

There is a newer version: 2.1-60f
Show newest version
/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 * 
 * // Copyright (c) 1998, 2007, Oracle. All rights reserved.
 * 
 *
 * The contents of this file are subject to the terms of either the GNU
 * General Public License Version 2 only ("GPL") or the Common Development
 * and Distribution License("CDDL") (collectively, the "License").  You
 * may not use this file except in compliance with the License. You can obtain
 * a copy of the License at https://glassfish.dev.java.net/public/CDDL+GPL.html
 * or glassfish/bootstrap/legal/LICENSE.txt.  See the License for the specific
 * language governing permissions and limitations under the License.
 * 
 * When distributing the software, include this License Header Notice in each
 * file and include the License file at glassfish/bootstrap/legal/LICENSE.txt.
 * Sun designates this particular file as subject to the "Classpath" exception
 * as provided by Sun in the GPL Version 2 section of the License file that
 * accompanied this code.  If applicable, add the following below the License
 * Header, with the fields enclosed by brackets [] replaced by your own
 * identifying information: "Portions Copyrighted [year]
 * [name of copyright owner]"
 * 
 * Contributor(s):
 * 
 * If you wish your version of this file to be governed by only the CDDL or
 * only the GPL Version 2, indicate your decision by adding "[Contributor]
 * elects to include this software in this distribution under the [CDDL or GPL
 * Version 2] license."  If you don't indicate a single choice of license, a
 * recipient has the option to distribute your version of this file under
 * either the CDDL, the GPL Version 2 or to extend the choice of license to
 * its licensees as provided above.  However, if you add GPL Version 2 code
 * and therefore, elected the GPL Version 2 license, then the option applies
 * only if the new code is made subject to such option by the copyright
 * holder.
 */
package oracle.toplink.essentials.descriptors;

import java.util.*;
import oracle.toplink.essentials.exceptions.QueryException;
import oracle.toplink.essentials.internal.descriptors.ObjectBuilder;
import oracle.toplink.essentials.internal.descriptors.OptimisticLockingPolicy;
import oracle.toplink.essentials.internal.helper.DatabaseField;
import oracle.toplink.essentials.mappings.DatabaseMapping;
import oracle.toplink.essentials.descriptors.ClassDescriptor;
import oracle.toplink.essentials.internal.sessions.UnitOfWorkImpl;
import oracle.toplink.essentials.queryframework.FetchGroup;
import oracle.toplink.essentials.queryframework.FetchGroupTracker;
import oracle.toplink.essentials.queryframework.ObjectLevelReadQuery;

/**
 * 

Purpose: The fetch group manager controls the named fetch groups defined at * the descriptor level. TopLink supports multiple, overlapped fetch groups, optionally with * one of them as the default fetch group. * * The domain object must implement oracle.toplink.essentials.queryframework.FetchGroupTracker interface, * in order to make use of the fetch group performance enhancement feature. * * Please refer to FetchGroup class for the prons and cons of fetch group usage. * * @see oracle.toplink.essentials.queryframework.FetchGroup * @see oracle.toplink.essentials.queryframework.FetchGroupTracker * * @author King Wang * @since TopLink 10.1.3. */ public class FetchGroupManager { //The group map is keyed by the group name, valued by the fetch group object. private Map fetchGroups = null; //default fetch group private FetchGroup defaultFetchGroup; //ref to the descriptor private ClassDescriptor descriptor; /** * Constructor */ public FetchGroupManager() { } /** * Add a named fetch group to the descriptor */ public void addFetchGroup(FetchGroup group) { //create a new fetch group and put it in the group map. getFetchGroups().put(group.getName(), group); } /** * Return the fetch group map: keyed by the group name, valued by the fetch group object. */ public Map getFetchGroups() { if (fetchGroups == null) { //lazy initialized fetchGroups = new HashMap(2); } return fetchGroups; } /** * Return the descriptor-level default fetch group. * All read object and read all queries would use the default fetch group if no fetch group * is explicitly defined for the query, unless setShouldUseDefaultFetchGroup(false); is also * called on the query. * * Default fetch group should be used carefully. It would be beneficial if most of the system queries * are for the subset of the object, so un-needed attributes data would not have to be read, and the * users do not have to setup every query for the given fetch group, as default one is always used. * However, if queries on object are mostly use case specific and not systematic, using default fetch group * could cause undesirable extra round-trip and performance degradation. * * @see oracle.toplink.essentials.queryframework.ObjectLevelReadQuery#setShouldUseDefaultFetchGroup(boolean) */ public FetchGroup getDefaultFetchGroup() { return defaultFetchGroup; } /** * Return a pre-defined named fetch group. */ public FetchGroup getFetchGroup(String groupName) { return (FetchGroup)getFetchGroups().get(groupName); } /** * Set the descriptor-level default fetch group. * All read object and read all queries would use the default fetch group if no fetch group is * explicitly defined for the query, unless setShouldUseDefaultFetchGroup(false); * is also called on the query. * * Default fetch group should be used carefully. It would be beneficial if most of the system queries * are for the subset of the object, so un-needed attributes data would not have to be read, and the * users do not have to setup every query for the given fetch group, as default one is always used. * However, if queries on object are mostly use case specific and not systematic, using default fetch group * could cause undesirable extra round-trip and performance degradation. * * @see oracle.toplink.essentials.queryframework.ObjectLevelReadQuery#setShouldUseDefaultFetchGroup(boolean) */ public void setDefaultFetchGroup(FetchGroup newDefaultFetchGroup) { defaultFetchGroup = newDefaultFetchGroup; } /** * INTERNAL: * Return true if the object is partially fetched and cached. * It applies to the query with fetch group. */ public boolean isPartialObject(Object domainObject) { if (domainObject != null) { FetchGroup fetchGroupInCache = ((FetchGroupTracker)domainObject).getFetchGroup(); //if the fetch group reference is not null, it means the object is partial. return (fetchGroupInCache != null); } return false; } /** * INTERNAL: * Return if the cached object data is sufficiently valid against a fetch group */ public boolean isObjectValidForFetchGroup(Object object, FetchGroup fetchGroup) { FetchGroup groupInObject = ((FetchGroupTracker)object).getFetchGroup(); return (groupInObject == null) || groupInObject.isSupersetOf(fetchGroup); } /** * INTERNAL: * Return true if the cached object data should be written in clone. * It is used in Fetch Group case when filling in the clone from the cached object. */ public boolean shouldWriteInto(Object cachedObject, Object clone) { if (isPartialObject(clone)) { FetchGroup fetchGroupInSrc = ((FetchGroupTracker)cachedObject).getFetchGroup(); FetchGroup fetchGroupInTarg = ((FetchGroupTracker)clone).getFetchGroup(); //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, //or if refresh is required, should always write (either refresh or revert) data from the cache to the clones. return (!((fetchGroupInTarg == null) || fetchGroupInTarg.isSupersetOf(fetchGroupInSrc)) || ((FetchGroupTracker)cachedObject).shouldRefreshFetchGroup()); } return false; } /** * INTERNAL: * Write data of the partially fetched object into the working and backup clones */ public void writePartialIntoClones(Object partialObject, Object workingClone, UnitOfWorkImpl uow) { FetchGroup fetchGroupInClone = ((FetchGroupTracker)workingClone).getFetchGroup(); FetchGroup fetchGroupInObject = ((FetchGroupTracker)partialObject).getFetchGroup(); Object backupClone = uow.getBackupClone(workingClone); //if refresh is set, force to fill in fecth group data if (((FetchGroupTracker)partialObject).shouldRefreshFetchGroup()) { //refresh and fill in the fecth group data refreshFetchGroupIntoClones(partialObject, workingClone, backupClone, fetchGroupInObject, fetchGroupInClone, uow); } else {//no refresh is enforced //revert the unfetched attributes of the clones. revertDataIntoUnfetchedAttributesOfClones(partialObject, workingClone, backupClone, fetchGroupInObject, fetchGroupInClone, uow); } //update fecth group in clone as the union of two fetchGroupInObject = unionFetchGroups(fetchGroupInObject, fetchGroupInClone); //finally, update clone's fetch group reference setObjectFetchGroup(workingClone, fetchGroupInObject); setObjectFetchGroup(backupClone, fetchGroupInObject); } /** * Refresh the fetch group data into the working and backup clones. * This is called if refresh is enforced */ private void refreshFetchGroupIntoClones(Object cachedObject, Object workingClone, Object backupClone, FetchGroup fetchGroupInObject, FetchGroup fetchGroupInClone, UnitOfWorkImpl uow) { Vector mappings = descriptor.getMappings(); boolean isObjectPartial = (fetchGroupInObject != null); Set fetchedAttributes = isObjectPartial ? fetchGroupInObject.getAttributes() : null; for (int index = 0; index < mappings.size(); index++) { DatabaseMapping mapping = (DatabaseMapping)mappings.get(index); if ((!isObjectPartial) || ((fetchedAttributes != null) && fetchedAttributes.contains(mapping.getAttributeName()))) { //only fill in the unfetched attributes into clones mapping.buildClone(cachedObject, workingClone, uow); mapping.buildClone(workingClone, backupClone, uow); } } } /** * Revert the clones' unfetched attributes, and leave fetched ones intact. */ private void revertDataIntoUnfetchedAttributesOfClones(Object cachedObject, Object workingClone, Object backupClone, FetchGroup fetchGroupInObject, FetchGroup fetchGroupInClone, UnitOfWorkImpl uow) { //if(fetchGroupInClone == null || fetchGroupInClone.isSupersetOf(fetchGroupInObject)) { if (isObjectValidForFetchGroup(workingClone, fetchGroupInObject)) { //if working clone is fully fetched or it's fetch group is superset of that of the cached object //no reversion is needed, so simply return return; } Vector mappings = descriptor.getMappings(); //fetched attributes list in working clone Set fetchedAttributesClone = fetchGroupInClone.getAttributes(); for (int index = 0; index < mappings.size(); index++) { DatabaseMapping mapping = (DatabaseMapping)mappings.get(index); //only revert the attribute which is fetched by the cached object, but not fecthed by the clones. if (isAttributeFetched(cachedObject, mapping.getAttributeName()) && (!fetchedAttributesClone.contains(mapping.getAttributeName()))) { //only fill in the unfetched attributes into clones mapping.buildClone(cachedObject, workingClone, uow); mapping.buildClone(workingClone, backupClone, uow); } } } /** * INTERNAL: * Copy fetch group refrerence from the source object to the target */ public void copyFetchGroupInto(Object source, Object target) { if (isPartialObject(source)) { ((FetchGroupTracker)target).setFetchGroup(((FetchGroupTracker)source).getFetchGroup()); } } /** * INTERNAL: * Union the fetch group of the domain object with the new fetch group. */ public void unionFetchGroupIntoObject(Object source, FetchGroup newFetchGroup) { FetchGroupTracker tracker = (FetchGroupTracker)source; tracker.setFetchGroup(unionFetchGroups(tracker.getFetchGroup(), newFetchGroup)); } /** * INTERNAL: * Union two fetch groups. */ public FetchGroup unionFetchGroups(FetchGroup first, FetchGroup second) { if ((first == null) || (second == null)) { return null; } //return the superset if applied if (first.isSupersetOf(second)) { return first; } else if (second.isSupersetOf(first)) { return second; } //otherwise, union two fetch groups StringBuffer unionGroupName = new StringBuffer(first.getName()); unionGroupName.append("_"); unionGroupName.append(second.getName()); FetchGroup unionFetchGroup = new FetchGroup(unionGroupName.toString()); unionFetchGroup.addAttributes(first.getAttributes()); unionFetchGroup.addAttributes(second.getAttributes()); return unionFetchGroup; } /** * INTERNAL: * Reset object attributes to the default values. */ public void reset(Object source) { ((FetchGroupTracker)source).resetFetchGroup(); } /** * INTERNAL: * Reset object attributes to the default their values. */ public void setObjectFetchGroup(Object source, FetchGroup fetchGroup) { if (descriptor.getFetchGroupManager() != null) { ((FetchGroupTracker)source).setFetchGroup(fetchGroup); } } /** * INTERNAL: * Set if the tracked object is fetched from executing a query with or without refresh. */ public void setRefreshOnFetchGroupToObject(Object source, boolean shouldRefreshOnFetchgroup) { ((FetchGroupTracker)source).setShouldRefreshFetchGroup(shouldRefreshOnFetchgroup); } /** * Return true if the attribute of the object has already been fetched */ public boolean isAttributeFetched(Object object, String attributeName) { FetchGroup fetchgroup = ((FetchGroupTracker)object).getFetchGroup(); return (fetchgroup == null) || (fetchgroup.getAttributes().contains(attributeName)); } /** * INTERNAL: * Return the referenced descriptor. */ public ClassDescriptor getDescriptor() { return descriptor; } /** * INTERNAL: * Return the referenced descriptor. */ public ClassDescriptor getClassDescriptor() { return getDescriptor(); } /** * Set the referenced descriptor. */ public void setDescriptor(ClassDescriptor descriptor) { this.descriptor = descriptor; } /** * INTERNAL: * Prepare the query with the fetch group to add group attributes to the query * for partial reading. */ public void prepareQueryWithFetchGroup(ObjectLevelReadQuery query) { //initialize query's fetch group query.initializeFetchGroup(); if ((query.getFetchGroup() == null) || query.getFetchGroup().hasFetchGroupAttributeExpressions()) { //simply return if fetch group is not defined; or if defined, it has been prepared already. return; } else { if (query.isReportQuery()) { //fetch group does not work with report query throw QueryException.fetchGroupNotSupportOnReportQuery(); } if (query.hasPartialAttributeExpressions()) { //fetch group does not work with partial attribute reading throw QueryException.fetchGroupNotSupportOnPartialAttributeReading(); } } Set attributes = query.getFetchGroup().getAttributes(); ObjectBuilder builder = query.getDescriptor().getObjectBuilder(); //First add all primary key attributes into the fetch group Iterator pkMappingIter = builder.getPrimaryKeyMappings().iterator(); while (pkMappingIter.hasNext()) { DatabaseMapping pkMapping = (DatabaseMapping)pkMappingIter.next(); DatabaseField pkField = pkMapping.getField(); // Add pk attribute to the fetch group attributes list attributes.add(pkMapping.getAttributeName()); } //second, add version/optimistic locking object attributes into the fetch group if applied. OptimisticLockingPolicy lockingPolicy = getDescriptor().getOptimisticLockingPolicy(); if (query.shouldMaintainCache() && (lockingPolicy != null)) { lockingPolicy.prepareFetchGroupForReadQuery(query.getFetchGroup(), query); } //thrid, prepare all fetch group attributes Iterator attrIter = attributes.iterator(); while (attrIter.hasNext()) { String attrName = (String)attrIter.next(); DatabaseMapping mapping = builder.getMappingForAttributeName(attrName); if (mapping == null) { //the attribute name defined in the fetch group is not mapped throw QueryException.fetchGroupAttributeNotMapped(attrName); } //partially fetch each fetch group attribute if (mapping.isCollectionMapping()) { query.getFetchGroup().addFetchGroupAttribute(query.getExpressionBuilder().anyOf(attrName)); } else { query.getFetchGroup().addFetchGroupAttribute(query.getExpressionBuilder().get(attrName)); } } } /** * INTERNAL: * Clone the fetch group manager */ public Object clone() { Object object = null; try { object = super.clone(); } catch (Exception exception) { ; } return object; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy