FileDocCategorySizeDatePackage
JoinedAttributeManager.javaAPI DocGlassfish v2 API29199Thu Jun 28 08:09:52 BST 2007oracle.toplink.essentials.internal.queryframework

JoinedAttributeManager

public class JoinedAttributeManager extends Object implements Cloneable

Purpose: A common class to be used by ObjectLevelReadQueries and ReportItems. This Class will be used to store Joined Attribute Expressions. It will also store the indexes for object construction.

author
Gordon Yorke
since
EJB3.0 RI

Fields Summary
protected ArrayList
joinedAttributeExpressions_
Stores the joined attributes added through the query
protected ArrayList
joinedMappingExpressions_
Stores the joined attributes as specified in the descriptor
protected ArrayList
joinedAttributes_
PERF: Cache the local joined attribute names.
protected boolean
isToManyJoin
Used to determine if -m joining has been used.
protected boolean
hasOuterJoinedAttribute
PERF: Used to avoid null checks for inner attribute joining.
protected transient HashMap
joinedMappingIndexes_
Used internally for joining.
protected transient HashMap
joinedMappingQueries_
Used internally for joining.
protected List
dataResults
Stored all row results to -m joining.
protected ClassDescriptor
descriptor
Stores the descriptor that these joins apply on
protected ExpressionBuilder
baseExpressionBuilder
Stores the base builder for resolving joined attributes by name
protected ObjectBuildingQuery
baseQuery
Stores the baseQuery
protected int
parentResultIndex
Stores the result index of the parent, used for oneToMany joins
Constructors Summary
public JoinedAttributeManager()

    
     
    
public JoinedAttributeManager(ClassDescriptor descriptor, ExpressionBuilder baseBuilder, ObjectBuildingQuery baseQuery)

        this.descriptor = descriptor;
        this.baseQuery = baseQuery;
        this.baseExpressionBuilder = baseBuilder;
        this.parentResultIndex = 0;
    
Methods Summary
public voidaddJoinedAttribute(java.lang.String attributeExpression)
INTERNAL:

        this.getJoinedAttributes().add(attributeExpression);
    
public voidaddJoinedAttributeExpression(oracle.toplink.essentials.expressions.Expression attributeExpression)
INTERNAL:

        getJoinedAttributeExpressions().add(attributeExpression);
    
public voidaddJoinedMapping(java.lang.String attributeName)
INTERNAL: Add an attribute represented by the given attribute name to the list of joins for this query. Note: Mapping level joins are represented separately from query level joins

        addJoinedMappingExpression(this.baseExpressionBuilder.get(attributeName));
    
public voidaddJoinedMappingExpression(oracle.toplink.essentials.expressions.Expression mappingExpression)
INTERNAL: Add an attribute represented by the given attribute name to the list of joins for this query. Note: Mapping level joins are represented separately from query level joins

        getJoinedMappingExpressions().add(mappingExpression);
    
public java.lang.Objectclone()
INTERNAL: Clones the Joined Attribute Manager. Generally called from Query.clone()

        JoinedAttributeManager joinManager = new JoinedAttributeManager();
        joinManager.baseExpressionBuilder = this.baseExpressionBuilder;
        joinManager.baseQuery = this.baseQuery;
        joinManager.descriptor = this.descriptor;
        if (this.joinedAttributeExpressions_ != null){
            joinManager.joinedAttributeExpressions_ = (ArrayList)this.joinedAttributeExpressions_.clone();
        }
        if (this.joinedMappingExpressions_ != null){
            joinManager.joinedMappingExpressions_ = (ArrayList)this.joinedMappingExpressions_.clone();
        }
        if (this.joinedAttributes_ != null){
            joinManager.joinedAttributes_ = (ArrayList)this.joinedAttributes_.clone();
        }
        if (this.joinedMappingIndexes_ != null){
            joinManager.joinedMappingIndexes_ = (HashMap)this.joinedMappingIndexes_.clone();
        }
        if (this.joinedMappingQueries_ != null){
            joinManager.joinedMappingQueries_ = (HashMap)this.joinedMappingQueries_.clone();
        }
        joinManager.isToManyJoin = this.isToManyJoin;
        joinManager.hasOuterJoinedAttribute = this.hasOuterJoinedAttribute;
        return joinManager;
        
    
protected intcomputeIndexesForJoinedExpressions(java.util.List joinedExpressions, int currentIndex, oracle.toplink.essentials.internal.sessions.AbstractSession session)
INTERNAL: This method is used when computing the indexes for joined mappings. It iterates through a list of join expressions and adds an index that represents where the fields represented by that expression will appear in the row returned by a read query.

see
#computeJoiningMappingIndexes(boolean, AbstractSession)

        for (int index = 0; index < joinedExpressions.size(); index++) {
            ObjectExpression objectExpression = (ObjectExpression)joinedExpressions.get(index);

            // Ignore nested
            if ((objectExpression.getBaseExpression() == objectExpression.getBuilder()) && objectExpression.getMapping() != null && objectExpression.getMapping().isForeignReferenceMapping()) {
                getJoinedMappingIndexes_().put(objectExpression.getMapping(), new Integer(currentIndex));
            }
            ClassDescriptor descriptor = objectExpression.getMapping().getReferenceDescriptor();
            int nFields;
            if(objectExpression.isQueryKeyExpression() && ((QueryKeyExpression)objectExpression).isUsingOuterJoinForMultitableInheritance()) {
                nFields = descriptor.getAllFields().size();
            } else {
                nFields = descriptor.getFields().size();
            }
            currentIndex = currentIndex + nFields;
        }
        return currentIndex;
    
public intcomputeJoiningMappingIndexes(boolean includeAllSubclassFields, oracle.toplink.essentials.internal.sessions.AbstractSession session, int offset)
INTERNAL: For joining the resulting rows include the field/values for many objects. As some of the objects may have the same field names, these row partitions need to be calculated. The indexes are stored in the query and used later when building the objects.

        if (!hasJoinedExpressions()) {
            return offset;
        }
        setJoinedMappingIndexes_(new HashMap(getJoinedAttributeExpressions().size() + getJoinedMappingExpressions().size()));
        int fieldIndex = 0;
        if (includeAllSubclassFields) {
            fieldIndex = getDescriptor().getAllFields().size();
        } else {
            fieldIndex = getDescriptor().getFields().size();
        }
        fieldIndex += offset;
        fieldIndex = computeIndexesForJoinedExpressions(getJoinedAttributeExpressions(), fieldIndex, session);
        computeIndexesForJoinedExpressions(getJoinedMappingExpressions(), fieldIndex, session);
        return fieldIndex;
    
public voidcomputeJoiningMappingQueries(oracle.toplink.essentials.internal.sessions.AbstractSession session)
INTERNAL: Used to optimize joining by pre-computing the nested join queries for the mappings.

        if (hasJoinedExpressions()) {
            this.joinedAttributes_ = new ArrayList(getJoinedAttributeExpressions().size() + getJoinedMappingExpressions().size());
            setJoinedMappingQueries_(new HashMap(getJoinedAttributeExpressions().size() + getJoinedMappingExpressions().size()));
            computeNestedQueriesForJoinedExpressions(getJoinedAttributeExpressions(), session, (ObjectLevelReadQuery)this.baseQuery);
            computeNestedQueriesForJoinedExpressions(getJoinedMappingExpressions(), session, (ObjectLevelReadQuery)this.baseQuery);
        }
    
protected voidcomputeNestedQueriesForJoinedExpressions(java.util.List joinedExpressions, oracle.toplink.essentials.internal.sessions.AbstractSession session, oracle.toplink.essentials.queryframework.ObjectLevelReadQuery readQuery)
INTERNAL: This method is used when computing the nested queries for joined mappings. It recurses computing the nested mapping queries and their join indexes.

        for (int index = 0; index < joinedExpressions.size(); index++) {
            ObjectExpression objectExpression = (ObjectExpression)joinedExpressions.get(index);
            
            // Expression may not have been initialized.
            objectExpression.getBuilder().setSession(session.getRootSession(null));
            if (objectExpression.getBuilder().getQueryClass() == null){
                objectExpression.getBuilder().setQueryClass(descriptor.getJavaClass());
            }
            
            // PERF: Cache join attribute names.
            ObjectExpression baseExpression = objectExpression;
            while (!baseExpression.getBaseExpression().isExpressionBuilder()) {
                baseExpression = (ObjectExpression)((QueryKeyExpression)baseExpression).getBaseExpression();
            }
            this.addJoinedAttribute(baseExpression.getName());
            
            // Ignore nested
            if ((objectExpression.getBaseExpression() == objectExpression.getBuilder()) && objectExpression.getMapping().isForeignReferenceMapping()) {
                ForeignReferenceMapping mapping = (ForeignReferenceMapping)objectExpression.getMapping();

                // A nested query must be built to pass to the descriptor that looks like the real query execution would.
                ObjectLevelReadQuery nestedQuery = mapping.prepareNestedJoins(this, session);

                // Register the nested query to be used by the mapping for all the objects.
                getJoinedMappingQueries_().put(mapping, nestedQuery);
            }
        }
    
public oracle.toplink.essentials.expressions.ExpressionBuildergetBaseExpressionBuilder()
INTERNAL: Returns the base expression builder for this query.

        return this.baseExpressionBuilder;
    
public oracle.toplink.essentials.queryframework.ObjectBuildingQuerygetBaseQuery()
INTERNAL: Returns the base query.

        return this.baseQuery;
    
public java.util.ListgetDataResults_()
INTERNAL: Return all of the rows fetched by the query, used for 1-m joining.

        return dataResults;
    
public oracle.toplink.essentials.descriptors.ClassDescriptorgetDescriptor()
INTERNAL:

        return this.descriptor;
    
public java.util.ListgetJoinedAttributeExpressions()
INTERNAL: Return the attributes that must be joined.

        if (this.joinedAttributeExpressions_ == null){
            this.joinedAttributeExpressions_ = new ArrayList();
        }
        return joinedAttributeExpressions_;
    
public java.util.ListgetJoinedAttributes()
INTERNAL: Return the attributes that must be joined.

        if (this.joinedAttributes_ == null){
            this.joinedAttributes_ = new ArrayList();
        }
        return this.joinedAttributes_;
    
public java.util.ListgetJoinedMappingExpressions()
INTERNAL: Get the list of expressions that represent elements that are joined because of their mapping for this query.

        if (this.joinedMappingExpressions_ == null){
            this.joinedMappingExpressions_ = new ArrayList();
        }
        return joinedMappingExpressions_;
    
public java.util.MapgetJoinedMappingIndexes_()
INTERNAL: Return the joined mapping indexes, used to compute mapping row partitions.

        return joinedMappingIndexes_;
    
public java.util.MapgetJoinedMappingQueries_()
INTERNAL: Return the joined mapping queries, used optimize joining, only compute the nested queries once.

        return joinedMappingQueries_;
    
public intgetParentResultIndex()

        return parentResultIndex;
    
public booleanhasJoinedAttributeExpressions()
INTERNAL: Return the attributes that must be joined.

        return this.joinedAttributeExpressions_ != null && !this.joinedAttributeExpressions_.isEmpty();
    
public booleanhasJoinedAttributes()
INTERNAL: Return if any attributes are joined. This is a convience method that is only valid after prepare.

        return this.joinedAttributes_ != null && !this.joinedAttributes_.isEmpty();
    
public booleanhasJoinedExpressions()
INTERNAL: THis methos checks bot attribute expressions and mapping expressions and determines if there are any joins to be made

        return hasJoinedAttributeExpressions() || hasJoinedMappingExpressions();
    
public booleanhasJoinedMappingExpressions()
INTERNAL: Return the attributes that must be joined.

        return this.joinedMappingExpressions_ != null && !this.joinedMappingExpressions_.isEmpty();
    
public booleanhasOuterJoinedAttributeQuery()
INTERNAL: PERF: Return if the query uses any outer attribute joins, used to avoid null checks in building objects.

        return this.hasOuterJoinedAttribute;
    
protected booleanisAttributeExpressionJoined(java.lang.String attributeName)
INTERNAL: Return if the attribute is specified for joining.

        return isAttributeNameInJoinedExpressionList(attributeName, getJoinedAttributeExpressions());
    
public booleanisAttributeJoined(oracle.toplink.essentials.descriptors.ClassDescriptor mappingDescriptor, java.lang.String attributeName)
INTERNAL: Return if the attribute is specified for joining.

        // Since aggregates share the same query as their parent, must avoid the aggregate thinking
        // the parents mappings is for it, (queries only share if the aggregate was not joined).
        if (mappingDescriptor.isAggregateDescriptor() && (mappingDescriptor != getDescriptor())) {
            return false;
        }
        if (this.hasJoinedAttributes()) {
            return this.joinedAttributes_.contains(attributeName);
        }
        return isAttributeExpressionJoined(attributeName) || isAttributeMappingJoined(attributeName);
    
protected booleanisAttributeMappingJoined(java.lang.String attributeName)
INTERNAL: Return whether the given attribute is joined as a result of a join on a mapping

        return isAttributeNameInJoinedExpressionList(attributeName, getJoinedMappingExpressions());
    
protected booleanisAttributeNameInJoinedExpressionList(java.lang.String attributeName, java.util.List joinedExpressionList)
Iterate through a list of expressions searching for the given attribute name. Return true if it is found, false otherwise.

        for (Iterator joinEnum = joinedExpressionList.iterator(); joinEnum.hasNext();) {
            QueryKeyExpression expression = (QueryKeyExpression)joinEnum.next();
            while (!expression.getBaseExpression().isExpressionBuilder()) {
                expression = (QueryKeyExpression)expression.getBaseExpression();
            }
            if (expression.getName().equals(attributeName)) {
                return true;
            }
        }
        return false;
    
public booleanisToManyJoin()
INTERNAL: Return if the query uses any -m joins, and thus return duplicate/multiple rows.

        return this.isToManyJoin;
    
protected voidprepareJoinExpression(oracle.toplink.essentials.expressions.Expression expression, oracle.toplink.essentials.internal.sessions.AbstractSession session)
Validate and prepare the join expression.

        // Must be query key expression.
        if (!expression.isQueryKeyExpression()) {
            throw QueryException.mappingForExpressionDoesNotSupportJoining(expression);
        }
        QueryKeyExpression objectExpression = (QueryKeyExpression)expression;

        // Expression may not have been initialized.
        objectExpression.getBuilder().setSession(session.getRootSession(null));
        if (objectExpression.getBuilder().getQueryClass() == null){
            objectExpression.getBuilder().setQueryClass(descriptor.getJavaClass());
        }
        // Can only join relationships.
        if ((objectExpression.getMapping() == null) || (!objectExpression.getMapping().isJoiningSupported())) {
            throw QueryException.mappingForExpressionDoesNotSupportJoining(objectExpression);
        }

        // Search if any of the expression traverse a 1-m.
        ObjectExpression baseExpression = objectExpression;
        while (!baseExpression.isExpressionBuilder()) {
            if (((QueryKeyExpression)baseExpression).shouldQueryToManyRelationship()) {
                setIsToManyJoinQuery(true);
            }
            if (((QueryKeyExpression)baseExpression).shouldUseOuterJoin()) {
                setIsOuterJoinedAttributeQuery(true);
            }
            baseExpression = (ObjectExpression)((QueryKeyExpression)baseExpression).getBaseExpression();
        }
    
public voidprepareJoinExpressions(oracle.toplink.essentials.internal.sessions.AbstractSession session)
INTERNAL: Validate and prepare join expressions.

        // The prepareJoinExpression check for outer-joins to set this to true.
        setIsOuterJoinedAttributeQuery(false);
        for (int index = 0; index < getJoinedAttributeExpressions().size(); index++) {
            Expression expression = (Expression)getJoinedAttributeExpressions().get(index);
            if(expression.isObjectExpression()) {
                ((ObjectExpression)expression).setShouldUseOuterJoinForMultitableInheritance(true);
            }
            prepareJoinExpression(expression, session);
        }
        for (int index = 0; index < getJoinedMappingExpressions().size(); index++) {
            Expression expression = (Expression)getJoinedMappingExpressions().get(index);
            if(expression.isObjectExpression()) {
                ((ObjectExpression)expression).setShouldUseOuterJoinForMultitableInheritance(true);
            }
            prepareJoinExpression(expression, session);
        }
        computeJoiningMappingQueries(session);
    
public voidprocessJoinedMappings()
INTERNAL: This method collects the Joined Mappings from the descriptor and initializes them

        ObjectBuilder objectBuilder = getDescriptor().getObjectBuilder();
        if (objectBuilder.hasJoinedAttributes()) {
            Vector mappingJoinedAttributes = objectBuilder.getJoinedAttributes();
            if (!hasJoinedExpressions()) {
                for (int i = 0; i < mappingJoinedAttributes.size(); i++) {
                    addJoinedMapping((String)mappingJoinedAttributes.get(i));
                }
            } else {
                for (int i = 0; i < mappingJoinedAttributes.size(); i++) {
                    String attribute = (String)mappingJoinedAttributes.get(i);
                    if (!isAttributeExpressionJoined(attribute)) {
                        addJoinedMapping(attribute);
                    }
                }
            }
        }
    
public voidreset()
INTERNAL: Reset the JoinedAttributeManager. This will be called when the Query is re-prepared

        this.joinedMappingExpressions_ = null;
        this.joinedAttributes_ = null;
        this.isToManyJoin = false;
        this.hasOuterJoinedAttribute = true;
        this.joinedMappingIndexes_ = null;
        this.joinedMappingQueries_ = null;
        this.dataResults = null;
    
protected voidsetBaseExpressionBuilder(oracle.toplink.essentials.expressions.ExpressionBuilder builder)
INTERNAL: This method is called from within this package, it is used when initializing a ReportItem

        this.baseExpressionBuilder = builder;
    
public voidsetBaseQuery(oracle.toplink.essentials.queryframework.ObjectLevelReadQuery query)
INTERNAL: This method is called from within this package it is used when initializing a report Item

        this.baseQuery = query;
    
public voidsetDataResults(java.util.List dataResults, oracle.toplink.essentials.internal.sessions.AbstractSession session)
INTERNAL: Set all of the rows fetched by the query, used for 1-m joining.

        this.dataResults = dataResults;
        if(getJoinedMappingQueries_() != null &&  !getJoinedMappingQueries_().isEmpty() && dataResults != null && !dataResults.isEmpty()) {
            Iterator  it =  getJoinedMappingQueries_().entrySet().iterator();
            while(it.hasNext()) {
                Map.Entry entry = (Map.Entry)it.next();
                ObjectLevelReadQuery nestedQuery = (ObjectLevelReadQuery)entry.getValue();
                if(nestedQuery.getJoinedAttributeManager().isToManyJoin()) {
                    ForeignReferenceMapping frMapping = (ForeignReferenceMapping)entry.getKey();
                    Object indexObject = getJoinedMappingIndexes_().get(entry.getKey());
                    List nestedDataResults = new ArrayList(dataResults.size());
                    for(int i=0; i < dataResults.size(); i++) {
                        AbstractRecord row = (AbstractRecord)dataResults.get(i);                        
                        nestedDataResults.add(frMapping.trimRowForJoin(row, indexObject, session));
                    }
                    nestedQuery.getJoinedAttributeManager().setDataResults(nestedDataResults, session);
                }
            }
         }
    
public voidsetDescriptor(oracle.toplink.essentials.descriptors.ClassDescriptor descriptor)
INTERNAL: Called to set the descriptor on a Join Managerwith in a ReportItem, durring initialization, and durring DatabaseQuery.checkDescriptor

        this.descriptor = descriptor;
    
protected voidsetIsOuterJoinedAttributeQuery(boolean isOuterJoinedAttribute)
INTERNAL: PERF: Set if the query uses any outer attribute joins, used to avoid null checks in building objects.

        this.hasOuterJoinedAttribute = isOuterJoinedAttribute;
    
protected voidsetIsToManyJoinQuery(boolean isToManyJoin)
INTERNAL: Set if the query uses any -m joins, and thus return duplicate/multiple rows.

        this.isToManyJoin = isToManyJoin;
    
public voidsetJoinedAttributeExpressions_(java.util.List joinedExpressions)
INTERNAL: Set the list of expressions that represent elements that are joined because of their mapping for this query.

        this.joinedAttributeExpressions_ = new ArrayList(joinedExpressions);
    
public voidsetJoinedMappingExpressions_(java.util.List joinedMappingExpressions)
INTERNAL: Set the list of expressions that represent elements that are joined because of their mapping for this query.

        this.joinedMappingExpressions_ = new ArrayList(joinedMappingExpressions);
    
public voidsetJoinedMappingIndexes_(java.util.HashMap joinedMappingIndexes)
INTERNAL: Set the joined mapping indexes, used to compute mapping row partitions.

        this.joinedMappingIndexes_ = joinedMappingIndexes;
    
protected voidsetJoinedMappingQueries_(java.util.HashMap joinedMappingQueries)
INTERNAL: Set the joined mapping queries, used optimize joining, only compute the nested queries once.

        this.joinedMappingQueries_ = joinedMappingQueries;
    
public voidsetParentResultIndex(int parentsResultIndex)

        this.parentResultIndex = parentsResultIndex;
    
public oracle.toplink.essentials.internal.expressions.ForUpdateOfClausesetupLockingClauseForJoinedExpressions(oracle.toplink.essentials.internal.expressions.ForUpdateOfClause lockingClause, oracle.toplink.essentials.internal.sessions.AbstractSession session)
INTERNAL: Used for joining in conjunction with pessimistic locking Iterate through a list of joined expressions and ensure expression is set on the locking clause for each expression that represents a pessimisically locked descriptor.

        if (hasJoinedAttributeExpressions()){
            setupLockingClauseForJoinedExpressions(getJoinedAttributeExpressions(), session);
        }
        if (hasJoinedMappingExpressions()){
            setupLockingClauseForJoinedExpressions(getJoinedMappingExpressions(), session);
        }
        return lockingClause;
    
private voidsetupLockingClauseForJoinedExpressions(java.util.List joinedExpressions, oracle.toplink.essentials.internal.sessions.AbstractSession session)
INTERNAL: Used for joining in conjunction with pessimistic locking Iterate through a list of joined expressions and ensure expression is set on the locking clause for each expression that represents a pessimisically locked descriptor.

        // Must iterate over all of the joined attributes, just check
        // if any of them have pessimistic locking defined on the descriptor.
        for (Iterator e = joinedExpressions.iterator(); e.hasNext();) {
            Expression expression = (Expression)e.next();

            // Expression has not yet been validated.
            if (expression.isObjectExpression()) {
                ObjectExpression joinedAttribute = (ObjectExpression)expression;

                // Expression may not have been initialized.
                joinedAttribute.getBuilder().setSession(session.getRootSession(null));
                if (joinedAttribute.getBuilder().getQueryClass() == null){
                    joinedAttribute.getBuilder().setQueryClass(descriptor.getJavaClass());
                }
                
                ClassDescriptor nestedDescriptor = null;// joinedAttribute.getDescriptor();

                // expression may not be valid, no descriptor, validation occurs later.
                if (nestedDescriptor == null) {
                    return;
                }
            }
        }
        return;