alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

Glassfish example source code file (RetrieveDescImpl.java)

This example Glassfish source code file (RetrieveDescImpl.java) is included in the DevDaily.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Java - Glassfish tags/keywords

noi18n, noi18n, object, opinfo_field_disallowed, opinfo_no_operation, opinfo_val_disallowed, opinfo_val_disallowed, opinfo_val_required, opinfo_val_required, opt_count_pc, opt_projection, retrievedesc, retrievedescimpl, retrievedescimpl, util

The Glassfish RetrieveDescImpl.java source code

/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 *
 * Copyright (c) 1997-2010 Oracle and/or its affiliates. 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_1_1.html
 * or packager/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 packager/legal/LICENSE.txt.
 *
 * GPL Classpath Exception:
 * Oracle designates this particular file as subject to the "Classpath"
 * exception as provided by Oracle in the GPL Version 2 section of the License
 * file that accompanied this code.
 *
 * Modifications:
 * If applicable, add the following below the License Header, with the fields
 * enclosed by brackets [] replaced by your own identifying information:
 * "Portions Copyright [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.
 */

/*
 * RetrieveDescImpl.java
 *
 * Created on March 3, 2000
 *
 */

package com.sun.jdo.spi.persistence.support.sqlstore.sql;

import com.sun.jdo.api.persistence.support.JDOFatalInternalException;
import com.sun.jdo.spi.persistence.support.sqlstore.ActionDesc;
import com.sun.jdo.spi.persistence.support.sqlstore.RetrieveDesc;
import com.sun.jdo.spi.persistence.support.sqlstore.SQLStoreManager;
import com.sun.jdo.spi.persistence.support.sqlstore.model.ClassDesc;
import com.sun.jdo.spi.persistence.support.sqlstore.model.LocalFieldDesc;
import com.sun.jdo.spi.persistence.support.sqlstore.sql.concurrency.Concurrency;
import com.sun.jdo.spi.persistence.support.sqlstore.sql.constraint.Constraint;
import com.sun.jdo.spi.persistence.support.sqlstore.sql.constraint.ConstraintFieldName;
import com.sun.jdo.spi.persistence.support.sqlstore.sql.generator.SelectQueryPlan;
import com.sun.jdo.spi.persistence.utility.FieldTypeEnumeration;
import com.sun.jdo.spi.persistence.utility.ParameterInfo;
import org.glassfish.persistence.common.I18NHelper;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.ResourceBundle;

/**
 */
public class RetrieveDescImpl extends Object implements RetrieveDesc, Cloneable {

    private static final int OPINFO_FIELD_DISALLOWED =  0x01; // 1

    private static final int OPINFO_FIELD_REQUIRED =    0x02; // 2

    private static final int OPINFO_VAL_DISALLOWED =    0x04; // 4

    private static final int OPINFO_VAL_REQUIRED =      0x08; // 8

    private static final int OPINFO_VAL_IS_PCOUNT =     0x10; // 16

    private static final int OPINFO_ILLEGAL =           0x20; // 32

    private static final int OPINFO_NO_OPERATION =      0x40; // 64

    /** Indicates, that the query projects on this RD. */
    public static final int OPT_PROJECTION =    0x1; // 1

    /** Indicates, that a distinct query should be run. */
    public static final int OPT_DISTINCT =      0x2; // 2

    /** Indicates, that the selected rows should be locked for update. */
    public static final int OPT_FOR_UPDATE =    0x4; // 4

    /** Indicates, that an avg aggregate query should be run. */
    public static final int OPT_AVG =           0x08; // 8

    /** Indicates, that a min aggregate query should be run. */
    public static final int OPT_MIN =           0x10; // 16

    /** Indicates, that a max aggregate query should be run. */
    public static final int OPT_MAX =           0x20; // 32

    /** Indicates, that a sum aggregate query should be run. */
    public static final int OPT_SUM =           0x40; // 64

    /** Indicates, that a count aggregate query should be run. */
    public static final int OPT_COUNT =         0x80; // 128

    /** Special treatment for count on persistent capable objects. */
    public static final int OPT_COUNT_PC =      0x100; // 256

    /** Sum of all aggregate options. */
    public static final int OPT_AGGREGATE = OPT_AVG + OPT_MIN + OPT_MAX +
            OPT_SUM + OPT_COUNT + OPT_COUNT_PC;

    /** Sum of all aggregate options excluding count on persistent capable objects. */
    public static final int OPT_AGGREGATE_NON_COUNT_PC = OPT_AGGREGATE - OPT_COUNT_PC;

    /** Indicates, that fetch group fields should be added. */
    public static final int OPT_ADD_FETCHGROUPS = 0x200; // 512

    /**
     * Indicates, that only key fields should be added. When this option is set,
     * it modifies meaning of OPT_ADD_FETCHGROUPS. It is assumed that
     * only key fieldes from the fetch group will be added.
     */
    public static final int OPT_ADD_KEYS_ONLY = 0x400; // 1024

    /**
     * Indicates, that even if relationship fields are in DFG, they should not
     * be prefetched. The runtime will attempt to fetch relationhip fields only
     * when OPT_ADD_FETCH_GROUPS is set.
     * @see #OPT_ADD_FETCHGROUPS
     * @see #OPT_ADD_KEYS_ONLY
     */
    public static final int OPT_DISABLE_RELATIONSHIP_PREFETCH =    0x800; // 2048

    /** Indicates special treatment for version consistency verifications. */
    public static final int OPT_VERIFY =       0x1000; // 4024

    /** Array of ConstraintFieldName. */
    private ArrayList fields;

    /** The constraint stack */
    private Constraint constraint;

    /** Bitmask of options for this instance as specified by the OPT_* constants */
    private int options;

    /** Candidate class of this instance */
    private Class pcClass;

    /** Config for candidate class of this instance */
    private ClassDesc config;

    /** SelectQueryPlan for this instance */
    private SelectQueryPlan plan;

    /**
     * Discriminates different retrieve descriptors which use the same
     * navigational field.
     */
    private Object navigationalId;

    /** Result type for an aggregate query. */
    private int aggregateResultType = FieldTypeEnumeration.NOT_ENUMERATED;

    /**
     * I18N message handler
     */
    private final static ResourceBundle messages = I18NHelper.loadBundle(
            "com.sun.jdo.spi.persistence.support.sqlstore.Bundle", // NOI18N
            RetrieveDescImpl.class.getClassLoader());

    public RetrieveDescImpl(Class pcClass, ClassDesc config) {
        super();

        this.pcClass = pcClass;
        this.config = config;
        fields = new ArrayList();
        constraint = new Constraint();
    }

    /**
     * The addResult method is used to specify which fields should be
     * returned in a persistent object. If the field requested is a
     * reference to another persistent object then a RetrieveDesc may be
     * provided which describes which fields of the referenced object
     * should be returned and, optionally, constraints on it.
     * If the parameter <code>projection is true, the field
     * specified by <code>name should be projected.
     *
     * @param name The name of the field to return.
     * @param foreignConstraint
     * RetrieveDesc describing fields and constraints for a referenced object.
     * @param projection Specifies, if this is a projection.
     */
    public void addResult(String name,
                          RetrieveDesc foreignConstraint,
                          boolean projection) {
        ConstraintFieldName cfName = new ConstraintFieldName(name, foreignConstraint);

        if (projection) {
            if ((options & OPT_PROJECTION) > 0) {
                throw new JDOFatalInternalException(I18NHelper.getMessage(messages,
                        "sqlstore.retrievedesc.toomanyprojections")); // NOI18N
            }

            // For projections on foreign fields, mark the foreign constraint.
            // For local fields, set the property on the field constraint.
            if (foreignConstraint != null) {
                ((RetrieveDescImpl) foreignConstraint).options |= OPT_PROJECTION;
            } else {
                cfName.setProjection();

                // Set this property if you want to have DFG fields added for
                // projections on local fields.
                //      options = options | OPT_PROJECTION;
            }
        }
        fields.add(cfName);
    }

    /**
     * The addResult method can be used to specify <it>global
     * query attributes that don't end up in the where clause.
     * Aggregate functions and the distinct op code are examples for
     * those query options. The result type defines the object to be
     * returned by an aggregate query. In case of distinct the result
     * type should be FieldTypeEnumeration.NOT_ENUMERATED. The method
     * might be called twice, in case of a JDOQL query having both an
     * aggregate and distinct:
     * query.setResult("avg (distinct salary)");
     * ->
     * retrieveDesc.addResult(OP_AVG, FieldTypeEnumeration.DOUBLE);
     * retrieveDesc.addResult(OP_DISTINCT, FieldTypeEnumeration.NOT_ENUMERATED);
     * retrieveDesc.addResult("salary", null, true);
     *
     * @param opCode The operation code.
     * @param aggregateResultType The object type returned by aggregate queries.
     * @see com.sun.jdo.spi.persistence.utility.FieldTypeEnumeration
     */
    public void addResult(int opCode, int aggregateResultType) {
        switch (opCode) {
            case ActionDesc.OP_DISTINCT:
                options = options | OPT_DISTINCT;
                break;
            case ActionDesc.OP_AVG:
                options = options | OPT_AVG;
                break;
            case ActionDesc.OP_MIN:
                options = options | OPT_MIN;
                break;
            case ActionDesc.OP_MAX:
                options = options | OPT_MAX;
                break;
            case ActionDesc.OP_SUM:
                options = options | OPT_SUM;
                break;
            case ActionDesc.OP_COUNT:
                options = options | OPT_COUNT;
                break;
            case ActionDesc.OP_COUNT_PC:
                options = options | OPT_COUNT_PC;
                break;
            default:
                throw new JDOFatalInternalException(I18NHelper.getMessage(messages,
                        "core.constraint.illegalop", "" + opCode)); // NOI18N
        }

        if (aggregateResultType != FieldTypeEnumeration.NOT_ENUMERATED) {
            if (this.aggregateResultType == FieldTypeEnumeration.NOT_ENUMERATED) {
                this.aggregateResultType = aggregateResultType;
            } else {
                // aggregate result type has already been set
                throw new JDOFatalInternalException(I18NHelper.getMessage(messages,
                        "sqlstore.retrievedesc.toomanyresulttypes")); // NOI18N
            }
        }
    }

    /**
     * Add a field specified by <code>name to the list of fields to be prefetched.
     * @param name Name of the field to be prefetched.
     * @param foreignConstraint This parameter is null if the field is a local field.
     * If the field is a foreign field, this parameter should be not null and must refer
     * to an instance of RetrieveDesc correpsonding to the config of the foreign field.
     */
    public void addPrefetchedField(String name, RetrieveDesc foreignConstraint) {
        fields.add(new ConstraintFieldName(name, foreignConstraint, true));
    }

    /**
     * {@inheritDoc}
     */
    public void setPrefetchEnabled(boolean prefetchEnabled) {
        if (!prefetchEnabled) {
            options |= OPT_DISABLE_RELATIONSHIP_PREFETCH;
        } else {
            // options has the flag OPT_DISABLE_RELATIONSHIP_PREFETCH unset by default
        }
    }

    /**
     * <P>Adds a constraint on the foreign field specified by
     * <code>name. This method is used to specify a relationship
     * navigation on field <code>name to the class represented by
     * the retrieve descriptor <code>foreignConstraint.
     * If <code>name is null, an unrelated constraint is added.
     * A constraint is unrelated, if there is neither a foreign field
     * nor a local field connecting to the retrieve descriptor
     * <code>foreignConstraint.
     */
    public void addConstraint(String name,
                              RetrieveDesc foreignConstraint) {
        if (name == null) {
            constraint.addField(null, foreignConstraint);
        } else  {
            constraint.addForeignField(name, foreignConstraint);
        }
    }

    /**
     * <P>Adds a constraint on the relationship field specified by
     * <code>name.
     * This method is useful e.g. for comparisons of local fields with field of a related object:
     *   emp.addConstraint("lastName", ActionDesc.OP_EQ, mgr, lastName");
     * compares the employee's lastName field with the lastName field of the related manager.
     */
    public void addConstraint(String name, int operation,
                              RetrieveDesc foreignConstraint, String foreignName) {
        constraint.addField(foreignName, foreignConstraint);
        constraint.addField(name, null);
        constraint.addOperation(operation);
    }

    /**
     * The addConstraint method is used to limit the values of fields for
     * objects being selected.
     * addConstraint pushes the value, name, and operation onto the
     * Constraint stack.  The constraints are anded together by default.
     * Arbitrarily complex relationships on the Constraint stack are supported.
     * The Constraint stack can be manipulated directly if necessary.
     *
     * @param name
     * 	The name parameter specifies the field whose value
     * 	should be limited.
     * @param operation
     * 	The operation parameter specifies the relationship the field
     * 	should bear to the value.  Values for operation are defined in
     * 	the ActionDesc interface.
     * @param value
     * 	The value parameter usually specifies the value to which the
     * 	field should be limited, however it is sometimes used to
     * 	hold a parameter count as for the OP_IN operation.
     */
    public void addConstraint(String name,
                              int operation,
                              Object value) {
        int info = getOperationInfo(operation);

        if ((info & OPINFO_ILLEGAL) > 0) {
            throw new JDOFatalInternalException(I18NHelper.getMessage(messages,
                    "core.constraint.illegalop", "" + operation)); // NOI18N
        } else if ((info & OPINFO_FIELD_REQUIRED) > 0 && name == null) {
            throw new JDOFatalInternalException(I18NHelper.getMessage(messages,
                    "core.constraint.fieldrequired", "" + operation)); // NOI18N
        } else if ((info & OPINFO_FIELD_DISALLOWED) > 0 && name != null) {
            throw new JDOFatalInternalException(I18NHelper.getMessage(messages,
                    "core.constraint.fielddisallowed", "" + operation)); // NOI18N
        } else if ((info & OPINFO_VAL_REQUIRED) > 0 && value == null) {
            throw new JDOFatalInternalException(I18NHelper.getMessage(messages,
                    "core.constraint.valrequired", "" + operation)); // NOI18N
        } else if ((info & OPINFO_VAL_DISALLOWED) > 0 && value != null) {
            throw new JDOFatalInternalException(I18NHelper.getMessage(messages,
                    "core.constraint.valdisallowed", "" + operation)); // NOI18N
        }
        if ((info & OPINFO_VAL_IS_PCOUNT) > 0) {
            if (name != null) {
                constraint.addField(name, null);
            }
            addValueConstraint(name, value);
        } else {
            switch (operation) {
                case RetrieveDescImpl.OP_PARAMETER:
                    addParameterConstraint(value);
                    break;
                case ActionDesc.OP_IN:
                case ActionDesc.OP_NOTIN:
                    constraint.addConstraintFieldSubQuery(name,(ActionDesc) value);
                    break;
                default:
                    if (value != null) {
                        addValueConstraint(name, value);
                    }
                    if (name != null) {
                        constraint.addField(name, null);
                    }
                    break;
            }
        }
        if ((info & OPINFO_NO_OPERATION) == 0) {
            constraint.addOperation(operation);
        }
    }

    /**
     * Add Constraints corresponding to given <code>fields.
     * The constraints are added as Parameter Constraints.
     * index of the parameter starts at given <code>startIndex
     * @param fields fields for which constraints are to be added.
     * @param startIndex starting Index for the parameter.
     */
    public void addParameterConstraints(LocalFieldDesc[] fields, int startIndex) {
        for (int i = 0; i < fields.length; i++) {
            LocalFieldDesc field = fields[i];
            addParameterConstraint(field, i + startIndex);
        }
    }

    /**
     * Add ParameterConstraint corresponding to given <code>field
     * at given  <code>index.
     * @param field The field for which constraints are to be added.
     * @param index Index at which the ParameterConstraint is to be inserted.
     */
    public void addParameterConstraint(LocalFieldDesc field, int index) {
        // Generate parameter info for this parameter.
        String fieldName = field.getName();
        int type = field.getEnumType();

        addConstraint(null, ActionDesc.OP_PARAMETER,new ParameterInfo(index, type, fieldName));
        addConstraint(fieldName, ActionDesc.OP_FIELD, null);
        addConstraint(null, ActionDesc.OP_EQ, null);
    }

    /**
     * Adds information about <code>value on the constraint stack.
     * @param name Name of the field to which the specified value is bound.
     * The query compiler can detect the correct value for name only in
     * case of simple expressions in the filter. A simple expression is
     * <em>fieldName op value. If the compiler is not able to detect
     * correct value for name it will pass null.
     * @param value value to which the field's value is constrained.
     */
    private void addValueConstraint(String name, Object value) {
        constraint.addValue(value, getLocalFieldDesc(name));
    }

    /**
     * Adds information about parameter on the constraint stack.
     * @param value Instance of
     * <code>com.sun.jdo.spi.persistence.utility.ParameterInfo.
     * Contains index, type and name of the field to which
     * this parameter is bound. The field name is used when binding
     * the parameter to the sql statement.
     * name can be null for complex expressions in a filter as described in
     * addValueConstraint.
     *  @see #addValueConstraint
     */
    private void addParameterConstraint(Object value) {
        if (value instanceof ParameterInfo) {
            ParameterInfo parameterInfo = (ParameterInfo)value;
            constraint.addParamIndex(parameterInfo.getIndex(), parameterInfo.getType(),
                    getLocalFieldDesc(parameterInfo.getAssociatedField()));
        } else {
            throw new JDOFatalInternalException(I18NHelper.getMessage(messages,
                    "core.constraint.illegalParameterInfo")); // NOI18N
        }
    }

    /**
     * Returns the local field descriptor for the field <code>name.
     * Delegates to <code>ClassDesc#getLocalFieldDesc(String).
     *
     * @param name Field name.
     * @return null if the <code>name is null.
     * LocalFieldDesc for the field <code>name otherwise.
     */
    private LocalFieldDesc getLocalFieldDesc(String name) {
        return name == null ? null : config.getLocalFieldDesc(name);
    }

    /**
     * 	The getOperationInfo method returns information about the operation
     * 	requested.  The following constants define different properties of
     * 	an operation and can be or'd together:
     *   OPINFO_FIELD_DISALLOWED A field parameter cannot be specified
     *                           with this operation
     *   OPINFO_FIELD_REQUIRED   A field parameter must be specified
     *                           with this operation
     *   OPINFO_VAL_DISALLOWED	 A value parameter cannot be specified
     *                           with this operation
     *   OPINFO_VAL_REQUIRED     A value parameter must be specified
     *                           with this operation
     *   OPINFO_NULL             This operation is a "null" type operation
     *                           (i.e. "is null", or "is not null")
     *   OPINFO_ILLEGAL          This operation is illegal
     *   OPINFO_NO_OPERATION     This isn't an operation at all,
     *                           it is some other specifier.
     *   OPINFO_VAL_IS_PCOUNT    This operation has a value which is the
     *                           parameter count of following parameter
     *                           nodes
     *
     * @param operation
     *   The operation parameter specifies the operation for which
     *   information is desired.
    */
    private static int getOperationInfo(int operation) {
        int info;
        switch (operation) {
            case ActionDesc.OP_ABS:
                info = OPINFO_VAL_DISALLOWED;
                break;
            case ActionDesc.OP_ADD:
                info = 0;
                break;
            case ActionDesc.OP_AND:
                info = 0;
                break;
            case ActionDesc.OP_FIELD:
                info = OPINFO_FIELD_REQUIRED | OPINFO_VAL_DISALLOWED | OPINFO_NO_OPERATION;
                break;
            case ActionDesc.OP_BETWEEN:
                info = 0;
                break;
            case ActionDesc.OP_DIV:
                info = 0;
                break;
            case ActionDesc.OP_EQ:
                info = 0;
                break;
            case ActionDesc.OP_NE:
                info = 0;
                break;
            case ActionDesc.OP_EQUIJOIN:
                info = 0;
                break;
            case ActionDesc.OP_NOT:
                info = OPINFO_FIELD_DISALLOWED | OPINFO_VAL_DISALLOWED;
                break;
            case ActionDesc.OP_GE:
                info = 0;
                break;
            case ActionDesc.OP_GT:
                info = 0;
                break;
            case ActionDesc.OP_IN:
            case ActionDesc.OP_NOTIN:
                info = OPINFO_FIELD_REQUIRED | OPINFO_VAL_REQUIRED;
                break;
            case ActionDesc.OP_LE:
                info = 0;
                break;
            case ActionDesc.OP_LEFTJOIN:
                info = 0;
                break;
            case ActionDesc.OP_LENGTH:
                info = OPINFO_VAL_DISALLOWED;
                break;
            case ActionDesc.OP_LIKE:
                info = 0;
                break;
            case ActionDesc.OP_LIKE_ESCAPE:
                info = 0;
                break;
            case ActionDesc.OP_LT:
                info = 0;
                break;
            case ActionDesc.OP_LTRIM:
                info = OPINFO_VAL_DISALLOWED;
                break;
            case ActionDesc.OP_MUL:
                info = 0;
                break;
            case ActionDesc.OP_OR:
                info = 0;
                break;
            case ActionDesc.OP_ORDERBY:
                info = 0;
                break;
            case ActionDesc.OP_ORDERBY_DESC:
                info = 0;
                break;
            case ActionDesc.OP_PARAMETER_COUNT:
                info = OPINFO_FIELD_DISALLOWED | OPINFO_VAL_REQUIRED | OPINFO_VAL_IS_PCOUNT | OPINFO_NO_OPERATION;
                break;
            case ActionDesc.OP_RIGHTJOIN:
                info = 0;
                break;
            case ActionDesc.OP_RTRIM:
                info = OPINFO_VAL_DISALLOWED;
                break;
            case ActionDesc.OP_SQRT:
                info = OPINFO_VAL_DISALLOWED;
                break;
            case ActionDesc.OP_SUB:
                info = 0;
                break;
            case ActionDesc.OP_SUBSTRING:
                info = 0;
                break;
            case ActionDesc.OP_POSITION:
                info = 0;
                break;
            case ActionDesc.OP_POSITION_START:
                info = 0;
                break;
            case ActionDesc.OP_MAYBE_NULL:
                info = OPINFO_FIELD_REQUIRED;
                break;
            case ActionDesc.OP_CONCAT:
                info = 0;
                break;
            case ActionDesc.OP_VALUE:
                info = OPINFO_FIELD_DISALLOWED | OPINFO_VAL_REQUIRED | OPINFO_NO_OPERATION;
                break;
            case ActionDesc.OP_PARAMETER:
                info = OPINFO_FIELD_DISALLOWED | OPINFO_VAL_REQUIRED | OPINFO_NO_OPERATION;
                break;
            case OP_NULL:
            case OP_NOTNULL:
                info = 0;
                break;
            case ActionDesc.OP_MOD:
                info = 0;
                break;
            default:
                info = OPINFO_ILLEGAL;
                break;
        }
        return info;
    }

    /**
     * Builds the internal query plan and initializes the select statements.
     * Projections on collection fields will not be resolved until the actual
     * retrieval in {@link SQLStoreManager#retrieve(
     * com.sun.jdo.spi.persistence.support.sqlstore.PersistenceManager,
     *       RetrieveDesc, com.sun.jdo.spi.persistence.support.sqlstore.ValueFetcher)}.
     */
    public synchronized SelectQueryPlan buildQueryPlan(SQLStoreManager store,
                                                       Concurrency concurrency) {

        if (plan == null) {

            handleProjection();

            plan = SelectQueryPlan.newInstance(this, store, concurrency);

            plan.build();

            // Generate the text for the select statements.
            ArrayList statements = plan.getStatements();

            // Sanity check.
            if (statements.size() > 1) {
                throw new JDOFatalInternalException(I18NHelper.getMessage(messages,
                        "sqlstore.retrievedesc.stmntsnotjoined")); // NOI18N
            }
        }
        return plan;
    }

    /**
     * Sets the fetch group options for all retrieve descriptors in the
     * retrieve descriptor hierarchy. This is important for projection and
     * aggregate queries, as we don't want to select additional fields
     * from the data store. This is also important for queries where relationship
     * prefetch is involved, as we want to propagate user's choice to disable
     * relationship prefetch for a finder to all the retrieve descriptors in
     * the projection tree.
     * Also sets the projection on the candidate  class in case of queries without
     * user projection.
     */
    private void handleProjection() {
        // Prepare all the query options that need to be distributed to all the
        // RetrieveDescs involved in the projection tree.
        final int queryOptions = options & (OPT_AGGREGATE | OPT_DISABLE_RELATIONSHIP_PREFETCH);
        RetrieveDescImpl projectedDesc = distributeQueryOptions(
                queryOptions, aggregateResultType);

        if (projectedDesc == null) {
            // Set the default projection on the candidate retrieve descriptor.
            options |= OPT_PROJECTION;
            // Prepare fetch group options again after default projection has been set.
            setFetchGroupOptions(queryOptions);
        }
    }

    /**
     * Marks each descriptor with the options <code>queryOptions and
     * finds the projection in the retrieve descriptor hierarchy.
     * The query options have to be known for each descriptor, because we don't want to
     * generate outer joins for OPT_COUNT_PC and we want to propagate users
     * choice to disable prefetch for a finder to projected RetrieveDesc.
     * This method relies on the fact, that each query can have only
     * <b>one projection.
     *
     * @param queryOptions The options that need to be set on all
     *    retrieve descriptors. This helps identify aggregate queries, see
     *    {@link SelectQueryPlan#processJoins()}.
     *    This also helps propagate user's choice to disable prefetch to the
     *    projected RetrieveDesc, see
     *    {@link SelectQueryPlan#addFetchGroup(int, java.util.ArrayList, java.util.ArrayList)}.
     * @param aggregateResultType The aggregate result type has to
     *    be set on the projected retrieve descriptor.
     * @return The projected retrieve descriptor, or null there is
     *    no projection.
     */
    private RetrieveDescImpl distributeQueryOptions(int queryOptions,
                                                    int aggregateResultType) {
        RetrieveDescImpl projectedDesc = null;

        if ((options & OPT_PROJECTION) > 0) {
            // This is a foreign field projection.
            // Set the fetch group properties.
            setFetchGroupOptions(queryOptions);
            this.aggregateResultType = aggregateResultType;
            projectedDesc = this;
        }

        // Distribute the aggregate option to all retrieve descriptors.
        options |= queryOptions;

        // Loop through all dependent retrieve descriptors in the field list.
        for (int i = 0; i < fields.size(); i++) {
            ConstraintFieldName cfn = (ConstraintFieldName) fields.get(i);

            if (cfn.isProjection()) {
                // This is a local field projection.
                // No fetch groups are added.
                this.aggregateResultType = aggregateResultType;
                projectedDesc = this;
            } else if (cfn.desc != null) {
                projectedDesc = ((RetrieveDescImpl) cfn.desc).distributeQueryOptions(
                        queryOptions, aggregateResultType);
            }
        }

        return projectedDesc;
    }

    /**
     * Sets the fetch group policy for the projected retrieve descriptor.
     * The policy is based on the following rules:
     *
     * <ul>
     * <li>Fetchgroups are added for a projection w/o aggregates.
     * <li>Only keys are added for count(*) queries.
     * </ul>
     *
     * @param queryOptions The quey options that needs to be set for ********
     *    <code>queryOptions Aggregate queries impose
     *    special restrictions on which fields to be selected. All aggregate
     *    queries except count(*) operate on exactly one field. Count(*)
     *    queries operate on persistence capable objects.
     * @see SelectQueryPlan#processFetchGroups(ArrayList, ArrayList)
     */
    private void setFetchGroupOptions(int queryOptions) {

        if ((queryOptions & OPT_AGGREGATE_NON_COUNT_PC) == 0) {
            // Don't add fetch groups except for projections
            // w/o aggregates or counts on persistence capable objects.
            options |= OPT_ADD_FETCHGROUPS;

            if (queryOptions == OPT_COUNT_PC)  {
                options |= OPT_ADD_KEYS_ONLY;
            }
        }
    }

    /**
     * Sets a navigational id on the retrieve descriptor. This id
     * will be used to discriminate different retrieve descriptors which
     * use the same navigational field. If not set, the field name is used.
     *
     * @param navigationalId Tag to discriminate different retrieve
     * descriptors that use the same navigational field.
     */
    public void setNavigationalId(Object navigationalId) {
        this.navigationalId = navigationalId;
    }

    /**
     * Returns the navigational id of this retrieve descriptor. This id
     * will be used to discriminate different retrieve descriptors which
     * use the same navigational field. If not set, the field name is used.
     *
     * @return Tag to discriminate different retrieve descriptors that
     * use the same navigational field.
     */
    public Object getNavigationalId() {
        return navigationalId;
    }

    /**
     * Sets option <code>option. Only used to mark this
     * retrieve descriptor as internal. All valid options are defined
     * in this class.
     *
     * @param option Option being set.
     */
    public void setOption(int option) {
        this.options |= option;
    }

    /**
     * Returns the result type for aggregate queries.
     */
    public int getAggregateResultType() {
        return aggregateResultType;
    }

    /**
     * Returns the options of this retrieve descriptor.
     *
     * @return The options of this retrieve descriptor.
     */
    public int getOptions() {
        return options;
    }

    public SelectQueryPlan getPlan() {
        return plan;
    }

    public ClassDesc getConfig() {
        return config;
    }

    public void setPlan(SelectQueryPlan plan) {
        this.plan = plan;
    }

    public Class getPersistenceCapableClass() {
        return pcClass;
    }

    public Constraint getConstraint() {
        return constraint;
    }

    public Iterator getFields() {
        return fields.iterator();
    }

    public Object clone() {
        try {
            RetrieveDescImpl clone = (RetrieveDescImpl) super.clone();
            clone.fields = new ArrayList();
            clone.constraint = new Constraint();

            return clone;
        } catch (CloneNotSupportedException e) {
            //
            // shouldn't happen.
            //
            return null;
        }
    }

}

Other Glassfish examples (source code examples)

Here is a short list of links related to this Glassfish RetrieveDescImpl.java source code file:

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.