FileDocCategorySizeDatePackage
EJBQueryImpl.javaAPI DocGlassfish v2 API30424Thu Jun 21 16:40:32 BST 2007oracle.toplink.essentials.internal.ejb.cmp3.base

EJBQueryImpl

public abstract class EJBQueryImpl extends Object
Concrete EJB 3.0 query class To do: Internationalize exceptions Change TopLink exceptions to exception types used by the spec Named Parameters Report Query firstResultIndex set in query framework temporal type parameters Change single result to use ReadObjectQuery

Fields Summary
protected DatabaseQuery
databaseQuery
protected EntityManagerImpl
entityManager
protected String
queryName
protected Map
parameters
protected int
firstResultIndex
protected int
maxResults
protected int
maxRows
Constructors Summary
protected EJBQueryImpl(EntityManagerImpl entityManager)
Base constructor for EJBQueryImpl. Initializes basic variables.

 // -1 indicates undefined

            
            

                 
       
        parameters = new HashMap();
        this.entityManager = entityManager;
    
public EJBQueryImpl(DatabaseQuery query, EntityManagerImpl entityManager)
Create an EJBQueryImpl with a TopLink query.

param
query

        this(entityManager);
        this.databaseQuery = query;
    
public EJBQueryImpl(String ejbql, EntityManagerImpl entityManager)
Build an EJBQueryImpl based on the given ejbql string

param
ejbql
param
entityManager

        this(ejbql, entityManager, false);
    
public EJBQueryImpl(String queryDescription, EntityManagerImpl entityManager, boolean isNamedQuery)
Create an EJBQueryImpl with either a query name or an ejbql string

param
queryDescription
param
entityManager
param
isNamedQuery determines whether to treat the query description as ejbql or a query name

        this(entityManager);
        if (isNamedQuery) {
            this.queryName = queryDescription;
        } else {
            if (databaseQuery == null) {
                databaseQuery = buildEJBQLDatabaseQuery(queryDescription, getActiveSession());
            }
        }
    
Methods Summary
protected static voidapplyHints(java.util.HashMap hints, oracle.toplink.essentials.queryframework.DatabaseQuery query)
Set implementation-specific hints.

param
hints a list of hints to be applied to the query
param
query the query to apply the hints to

        QueryHintsHandler.apply(hints, query);
    
public static oracle.toplink.essentials.queryframework.DatabaseQuerybuildEJBQLDatabaseQuery(java.lang.String ejbql, oracle.toplink.essentials.sessions.Session session, java.util.HashMap hints)
Build a DatabaseQuery from an EJBQL string.

param
ejbql
param
session the session to get the descriptors for this query for.
param
hints a list of hints to be applied to the query
return
a DatabaseQuery representing the given ejbql

        return buildEJBQLDatabaseQuery(null, ejbql, null, session, hints, null);
    
public static oracle.toplink.essentials.queryframework.DatabaseQuerybuildEJBQLDatabaseQuery(java.lang.String ejbql, oracle.toplink.essentials.sessions.Session session, java.util.HashMap hints, java.lang.ClassLoader classLoader)
Build a DatabaseQuery from an EJBQL string.

param
ejbql
param
session the session to get the descriptors for this query for.
param
hints a list of hints to be applied to the query
param
classLoader the class loader to build the query with
return
a DatabaseQuery representing the given ejbql

        return buildEJBQLDatabaseQuery(null, ejbql, null, session, hints, classLoader);
    
public static oracle.toplink.essentials.queryframework.DatabaseQuerybuildEJBQLDatabaseQuery(java.lang.String ejbql, java.lang.Boolean flushOnExecute, oracle.toplink.essentials.sessions.Session session)
Build a DatabaseQuery from an EJBQL string.

param
ejbql
parem
flushOnExecute
param
session the session to get the descriptors for this query for.
return
a DatabaseQuery representing the given ejbql

        return buildEJBQLDatabaseQuery(null, ejbql, flushOnExecute, session, null, null);
    
public static oracle.toplink.essentials.queryframework.DatabaseQuerybuildEJBQLDatabaseQuery(java.lang.String ejbql, java.lang.Boolean flushOnExecute, oracle.toplink.essentials.sessions.Session session, java.lang.ClassLoader classLoader)
Build a DatabaseQuery from an EJBQL string.

param
ejbql
parem
flushOnExecute
param
session the session to get the descriptors for this query for.
return
a DatabaseQuery representing the given ejbql

        return buildEJBQLDatabaseQuery(null, ejbql, flushOnExecute, session, null, classLoader);
    
public static oracle.toplink.essentials.queryframework.DatabaseQuerybuildEJBQLDatabaseQuery(java.lang.String queryName, java.lang.String ejbql, java.lang.Boolean flushOnExecute, oracle.toplink.essentials.sessions.Session session, java.util.HashMap hints, java.lang.ClassLoader classLoader)
Build a DatabaseQuery from an EJBQL string.

param
ejbql
parem
flushOnExecute
param
session the session to get the descriptors for this query for.
param
hints a list of hints to be applied to the query
return
a DatabaseQuery representing the given ejbql

        DatabaseQuery databaseQuery = null;
        EJBQLParseTree parseTree = EJBQLParser.buildParseTree(queryName, ejbql);
        parseTree.setClassLoader(classLoader);
        databaseQuery = parseTree.createDatabaseQuery();
        databaseQuery.setEJBQLString(ejbql);
        parseTree.populateQuery(databaseQuery, (oracle.toplink.essentials.internal.sessions.AbstractSession)session);
        //Bug#4646580  Add arguments to query
        parseTree.addParametersToQuery(databaseQuery);
        ((EJBQLCallQueryMechanism)databaseQuery.getQueryMechanism()).getEJBQLCall().setIsParsed(true);
        databaseQuery.setFlushOnExecute(flushOnExecute);

        //GF#1324 toplink.refresh query hint does not cascade
        //cascade by mapping as default for read query
        if(databaseQuery.isReadQuery ()) {
            databaseQuery.cascadeByMapping();
        }
        
        // apply any query hints
        applyHints(hints, databaseQuery);
        
        return databaseQuery;
    
public static oracle.toplink.essentials.queryframework.DatabaseQuerybuildEJBQLDatabaseQuery(java.lang.String ejbql, oracle.toplink.essentials.sessions.Session session)
Build a DatabaseQuery from an EJBQL string.

param
ejbql
param
session the session to get the descriptors for this query for.
return
a DatabaseQuery representing the given ejbql

        return buildEJBQLDatabaseQuery(ejbql, null, session);
    
public static oracle.toplink.essentials.queryframework.DatabaseQuerybuildSQLDatabaseQuery(java.lang.Class resultClass, java.lang.String sqlString)
Build a ReadAllQuery from a class and sql string.

param
resultClass
param
flushOnExecute
param
sqlString
return

        return buildSQLDatabaseQuery(resultClass, sqlString, null);
    
public static oracle.toplink.essentials.queryframework.DatabaseQuerybuildSQLDatabaseQuery(java.lang.Class resultClass, java.lang.String sqlString, java.util.HashMap hints)
Build a ReadAllQuery from a class and sql string.

param
resultClass
param
flushOnExecute
param
sqlString
param
hints a list of hints to be applied to the query
return

        ReadAllQuery query = new ReadAllQuery(resultClass);
        query.setSQLString(sqlString);
        query.setIsUserDefined(true);
        
        // apply any query hints
        applyHints(hints, query);

        return query;
    
public static oracle.toplink.essentials.queryframework.DatabaseQuerybuildSQLDatabaseQuery(java.lang.String sqlResultSetMappingName, java.lang.String sqlString)
Build a ResultSetMappingQuery from a sql result set mapping name and sql string.

param
sqlResultSetMappingName
param
flushOnExecute
param
sqlString
return

        return buildSQLDatabaseQuery(sqlResultSetMappingName, sqlString, null);
    
public static oracle.toplink.essentials.queryframework.DatabaseQuerybuildSQLDatabaseQuery(java.lang.String sqlResultSetMappingName, java.lang.String sqlString, java.util.HashMap hints)
Build a ResultSetMappingQuery from a sql result set mapping name and sql string.

param
sqlResultSetMappingName
param
flushOnExecute
param
sqlString
param
hints a list of hints to be applied to the query
return

        ResultSetMappingQuery query = new ResultSetMappingQuery();
        query.setSQLResultSetMappingName(sqlResultSetMappingName);
        query.setSQLString(sqlString);
        query.setIsUserDefined(true);
        
        // apply any query hints
        applyHints(hints, query);

        return query;
    
public static oracle.toplink.essentials.queryframework.DatabaseQuerybuildSQLDatabaseQuery(java.lang.String sqlString, java.lang.Boolean flushOnExecute)
Build a DataReadQuery from a sql string.

        return buildSQLDatabaseQuery(sqlString, new HashMap());
    
public static oracle.toplink.essentials.queryframework.DatabaseQuerybuildSQLDatabaseQuery(java.lang.String sqlString, java.util.HashMap hints)
Build a DataReadQuery from a sql string.

        DataReadQuery query = new DataReadQuery();
        query.setUseAbstractRecord(false);
        query.setSQLString(sqlString);
        query.setIsUserDefined(true);

        // apply any query hints
        applyHints(hints, query);
        
        return query;
    
protected java.lang.ObjectexecuteReadQuery()
Execute a ReadQuery by assigning the stored parameter values and running it in the database

return
the results of the query execution

        Vector parameterValues = processParameters();
        //TODO: the following performFlush() call is a temporary workaround for bug 4752493:
        // CTS: INMEMORY QUERYING IN EJBQUERY BROKEN DUE TO CHANGE TO USE REPORTQUERY.
        // Ideally we should only flush in case the selectionExpression can't be conformed in memory.
        // There are two alternative ways to implement that:
        // 1. Try running the query with conformInUOW flag first - if it fails with 
        //    QueryException.cannotConformExpression then flush and run the query again -
        //    now without conforming.
        // 2. Implement a new isComformable method on Expression which would determine whether the expression
        //    could be conformed in memory, flush only in case it returns false.
        //    Note that doesConform method currently implemented on Expression
        //    requires object(s) to be confirmed as parameter(s).
        //    The new isComformable method should not take any objects as parameters,
        //    it should return false if there could be such an object that
        //    passed to doesConform causes it to throw QueryException.cannotConformExpression -
        //    and true otherwise.
        boolean shouldResetConformResultsInUnitOfWork = false;
        if(isFlushModeAUTO()) {
            performPreQueryFlush();
            if(getDatabaseQuery().isObjectLevelReadQuery()) {
                if(((ObjectLevelReadQuery)getDatabaseQuery()).shouldConformResultsInUnitOfWork()) {
                    ((ObjectLevelReadQuery)getDatabaseQuery()).setCacheUsage(ObjectLevelReadQuery.UseDescriptorSetting);
                    shouldResetConformResultsInUnitOfWork = true;
                }
            }
        }
        try {
            // in case it's a user-defined query
            if(getDatabaseQuery().isUserDefined()) {
                // and there is an active transaction
                if(this.entityManager.checkForTransaction(false) != null) {
                    // verify whether uow has begun early transaction
                    if(!((oracle.toplink.essentials.internal.sessions.UnitOfWorkImpl)getActiveSession()).wasTransactionBegunPrematurely()) {
                        // uow begins early transaction in case it hasn't already begun.
                        ((oracle.toplink.essentials.internal.sessions.UnitOfWorkImpl)getActiveSession()).beginEarlyTransaction();
                    }
                }
            }
            return getActiveSession().executeQuery(getDatabaseQuery(), parameterValues);
        } finally {
            if(shouldResetConformResultsInUnitOfWork) {
                ((ObjectLevelReadQuery)getDatabaseQuery()).conformResultsInUnitOfWork();
            }
        }
    
public intexecuteUpdate()
Execute an update or delete statement.

return
the number of entities updated or deleted

        try {
            //bug51411440: need to throw IllegalStateException if query executed on closed em
            entityManager.verifyOpen();
            setAsSQLModifyQuery();
            //bug:4294241, only allow modify queries - UpdateAllQuery prefered
            if ( !(getDatabaseQuery() instanceof ModifyQuery) ){
                throw new IllegalStateException(ExceptionLocalization.buildMessage("incorrect_query_for_execute_update"));
            }
            
            // need to throw TransactionRequiredException if there is no active transaction
            entityManager.checkForTransaction(true);
            
            //fix for bug:4288845, did not add the parameters to the query
            Vector parameterValues = processParameters();
            if(isFlushModeAUTO()) {
                performPreQueryFlush();
            }
            Integer changedRows = (Integer)((Session)getActiveSession()).executeQuery(databaseQuery, parameterValues);
            return changedRows.intValue();
        } catch (RuntimeException e) {
            setRollbackOnly();
            throw e;
        }
    
protected oracle.toplink.essentials.sessions.SessiongetActiveSession()

        return entityManager.getActiveSession();
    
public oracle.toplink.essentials.queryframework.DatabaseQuerygetDatabaseQuery()
Return the cached database query for this EJBQueryImpl. If the query is a named query and it has not yet been looked up, the query will be looked up and stored as the cached query.

        if ((queryName != null) && (databaseQuery == null)) {
            // need error checking and appropriate exception for non-existing query
            databaseQuery = getActiveSession().getQuery(queryName);
            if (databaseQuery != null) {
                if (!databaseQuery.isPrepared()){
                    //prepare the query before cloning, this ensures we do not have to continually prepare on each usage
                    databaseQuery.prepareCall(getActiveSession(), new DatabaseRecord());
                }
                //Bug5040609  Make a clone of the original DatabaseQuery for this EJBQuery
                databaseQuery = (DatabaseQuery)databaseQuery.clone();
            } else {
                throw new IllegalArgumentException(ExceptionLocalization.buildMessage("unable_to_find_named_query", new Object[] {queryName}));
            }
            
        }
        return databaseQuery;
    
public java.util.CollectiongetResultCollection()
Non-standard method to return results of a ReadQuery that has a containerPoliry that returns objects as a collection rather than a List

return
Collection of results

        //bug51411440: need to throw IllegalStateException if query executed on closed em
        entityManager.verifyOpen();
        setAsSQLReadQuery();
        propagateResultProperties();
        //bug:4297903, check container policy class and throw exception if its not the right type 
        if (getDatabaseQuery() instanceof ReadAllQuery){
          Class containerClass = ((ReadAllQuery)getDatabaseQuery()).getContainerPolicy().getContainerClass();
          if (! Helper.classImplementsInterface(containerClass, ClassConstants.Collection_Class)){
            throw QueryException.invalidContainerClass( containerClass, ClassConstants.Collection_Class );
          }
        } else if (getDatabaseQuery() instanceof ReadObjectQuery){
            //bug:4300879, no support for ReadObjectQuery if a collection is required
            throw QueryException.incorrectQueryObjectFound( getDatabaseQuery(), ReadAllQuery.class );
        } else if (!(getDatabaseQuery() instanceof ReadQuery)){
            throw new IllegalStateException(ExceptionLocalization.buildMessage("incorrect_query_for_get_result_collection"));
        }
        Object result = executeReadQuery();
        return (Collection)result;
    
public java.util.ListgetResultList()
Execute the query and return the query results as a List.

return
a list of the results

        try {
            //bug51411440: need to throw IllegalStateException if query executed on closed em
            entityManager.verifyOpen();
            setAsSQLReadQuery();
            propagateResultProperties();
            //bug:4297903, check container policy class and throw exception if its not the right type 
            if (getDatabaseQuery() instanceof ReadAllQuery){
              Class containerClass = ((ReadAllQuery)getDatabaseQuery()).getContainerPolicy().getContainerClass();
              if (! Helper.classImplementsInterface(containerClass, ClassConstants.List_Class)){
                throw QueryException.invalidContainerClass( containerClass, ClassConstants.List_Class );
              }
            } else if (getDatabaseQuery() instanceof ReadObjectQuery){
                //bug:4300879, handle ReadObjectQuery returning null
                throw QueryException.incorrectQueryObjectFound( getDatabaseQuery(), ReadAllQuery.class );
            } else if (!(getDatabaseQuery() instanceof ReadQuery)){
                throw new IllegalStateException(ExceptionLocalization.buildMessage("incorrect_query_for_get_result_list"));
            }
            Object result = executeReadQuery();
            return (List)result;
        } catch (RuntimeException e) {
            setRollbackOnly();
            throw e;
        }
    
public java.lang.ObjectgetSingleResult()
Execute a query that returns a single result.

return
the result
throws
EntityNotFoundException if there is no result
throws
NonUniqueResultException if more than one result

        boolean rollbackOnException = true;
        try {
            //bug51411440: need to throw IllegalStateException if query executed on closed em
            entityManager.verifyOpen();
            setAsSQLReadQuery();
            propagateResultProperties();
            //bug:4301674, requires lists to be returned from ReadAllQuery objects
            if (getDatabaseQuery() instanceof ReadAllQuery){
              Class containerClass = ((ReadAllQuery)getDatabaseQuery()).getContainerPolicy().getContainerClass();
              if (! Helper.classImplementsInterface(containerClass, ClassConstants.List_Class)){
                throw QueryException.invalidContainerClass( containerClass, ClassConstants.List_Class );
              }
            } else if (!(getDatabaseQuery() instanceof ReadQuery)){
                throw new IllegalStateException(ExceptionLocalization.buildMessage("incorrect_query_for_get_single_result"));
            }
            Object result = executeReadQuery();
            if (result instanceof List){
                List results = (List)result;
                if (results.isEmpty()) {
                    rollbackOnException = false;
                    throwNoResultException(ExceptionLocalization.buildMessage("no_entities_retrieved_for_get_single_result", (Object[])null));                
                } else if (results.size() > 1) {
                    rollbackOnException = false;
                    throwNonUniqueResultException(ExceptionLocalization.buildMessage("too_many_results_for_get_single_result", (Object[])null));
                }
                return results.get(0);
            }else{
                if (result == null) {
                    rollbackOnException = false;
                    throwNoResultException(ExceptionLocalization.buildMessage("no_entities_retrieved_for_get_single_result", (Object[])null));
                }
                return result;
            }
        } catch (RuntimeException e) {
            if(rollbackOnException) {
                setRollbackOnly();
            }
            throw e;
        }
    
protected booleanisFlushModeAUTO()
Spec. 3.5.2: "FlushMode.AUTO is set on the Query object, or if the flush mode setting for the persistence context is AUTO (the default) and a flush mode setting has not been specified for the Query object, the persistence provider is responsible for ensuring that all updates to the state of all entities in the persistence context which could potentially affect the result of the query are visible to the processing of the query."

        if(getDatabaseQuery().getFlushOnExecute() != null) {
            return getDatabaseQuery().getFlushOnExecute().booleanValue();
        } else {
            return entityManager.isFlushModeAUTO();
        }
    
protected booleanisValidActualParameter(java.lang.Object value, java.lang.Object parameterType)

        if (value == null) {
            return true;
        } else {
            return BasicTypeHelperImpl.getInstance().isAssignableFrom(parameterType, value.getClass());
        }
    
protected voidperformPreQueryFlush()

        if (this.entityManager.shouldFlushBeforeQuery()){
            this.entityManager.flush();
        }
    
protected java.util.VectorprocessParameters()
Internal method to add the parameters values to the query prior to execution. Returns a list of parameter values in the order the parameters are defined for the databaseQuery.

        if (databaseQuery == null) {
            getDatabaseQuery();
        }
        List arguments = databaseQuery.getArguments();
        if (arguments.isEmpty()) {
            Iterator params = parameters.keySet().iterator();
            while (params.hasNext()) {
                databaseQuery.addArgument((String)params.next());
            }
            arguments = databaseQuery.getArguments();
        }
        // now create parameterValues in the same order as the argument list
        Vector parameterValues = new Vector(arguments.size());
        for (Iterator i = arguments.iterator(); i.hasNext();) {
            String name = (String)i.next();
            if (parameters.containsKey(name)) {
                parameterValues.add(parameters.get(name));
            } else {
                // Error: missing actual parameter value
                throw new IllegalStateException(ExceptionLocalization.buildMessage("missing_parameter_value", new Object[]{name}));
            }
        }
        return parameterValues;
    
protected voidpropagateResultProperties()

        DatabaseQuery databaseQuery = getDatabaseQuery();
        if (databaseQuery.isReadQuery()) {
            ReadQuery readQuery = (ReadQuery)databaseQuery;
            if (maxResults >= 0) {
                maxRows = maxResults + ((firstResultIndex >= 0) ? firstResultIndex : 0);
                readQuery.setMaxRows(maxRows);
                maxResults = -1;
            }
            if (firstResultIndex > -1) {
                readQuery.setFirstResult(firstResultIndex);
                firstResultIndex = -1;
            }
        }
    
protected voidsetAsSQLModifyQuery()
Internal method to change the wrapped query to a DataModifyQuery if neccessary

        if (getDatabaseQuery().isDataReadQuery()){
            DataModifyQuery query = new DataModifyQuery();
            query.setSQLString(databaseQuery.getSQLString());
            query.setIsUserDefined(databaseQuery.isUserDefined());
            query.setFlushOnExecute(databaseQuery.getFlushOnExecute());
            databaseQuery = query;
        }
    
protected voidsetAsSQLReadQuery()
Internal method to change the wrapped query to a DataReadQuery if neccessary

        if(getDatabaseQuery().isDataModifyQuery()){
            DataReadQuery query = new DataReadQuery();
            query.setUseAbstractRecord(false);
            query.setSQLString(databaseQuery.getSQLString());
            query.setIsUserDefined(databaseQuery.isUserDefined());
            query.setFlushOnExecute(databaseQuery.getFlushOnExecute());
            databaseQuery = query;
        }
    
public voidsetDatabaseQuery(oracle.toplink.essentials.queryframework.DatabaseQuery query)
Replace the cached query with the given query.

        databaseQuery = query;
    
protected voidsetFirstResultInternal(int startPosition)
Set the position of the first result to retrieve.

param
start position of the first result, numbered from 0

        if (startPosition < 0) {
            throw new IllegalArgumentException(ExceptionLocalization.buildMessage("negative_start_position", (Object[])null));
        }
        firstResultIndex = startPosition;
    
protected voidsetHintInternal(java.lang.String hintName, java.lang.Object value)
Set an implementation-specific hint. If the hint name is not recognized, it is silently ignored.

param
hintName
param
value
throws
IllegalArgumentException if the second argument is not valid for the implementation

        QueryHintsHandler.apply(hintName, value, getDatabaseQuery());
    
public voidsetMaxResultsInternal(int maxResult)
Set the maximum number of results to retrieve.

param
maxResult

        if (maxResult < 0) {
            throw new IllegalArgumentException(ExceptionLocalization.buildMessage("negative_max_result", (Object[])null));
        }
        this.maxResults = maxResult;
    
protected voidsetParameterInternal(java.lang.String name, java.lang.Object value)
Bind an argument to a named parameter.

param
name the parameter name
param
value

        int index  = getDatabaseQuery().getArguments().indexOf(name);
        if (getDatabaseQuery().getEJBQLString() != null){  //only non native queries
            if (index == -1){
                throw new IllegalArgumentException(ExceptionLocalization.buildMessage("ejb30-wrong-argument-name",new Object[]{name, getDatabaseQuery().getEJBQLString()}));
            }
            if (!isValidActualParameter(value, getDatabaseQuery().getArgumentTypes().get(index))) {
                throw new IllegalArgumentException(ExceptionLocalization.buildMessage("ejb30-incorrect-parameter-type", new Object[] {name, value.getClass(), getDatabaseQuery().getArgumentTypes().get(index), getDatabaseQuery().getEJBQLString()}));
            }
        }
        parameters.put(name, value);
    
protected voidsetParameterInternal(int position, java.lang.Object value)
Bind an argument to a positional parameter.

param
position
param
value

        String pos = (new Integer(position)).toString();
        int index = getDatabaseQuery().getArguments().indexOf(pos);
        if (getDatabaseQuery().getEJBQLString() != null){  //only non native queries
            if (index == -1) {
                throw new IllegalArgumentException(ExceptionLocalization.buildMessage("ejb30-wrong-argument-index", new Object[]{position, getDatabaseQuery().getEJBQLString()}));
            }
            if (!isValidActualParameter(value, getDatabaseQuery().getArgumentTypes().get(index))) {
                throw new IllegalArgumentException(ExceptionLocalization.buildMessage("ejb30-incorrect-parameter-type", new Object[] {position, value.getClass(), getDatabaseQuery().getArgumentTypes().get(index), getDatabaseQuery().getEJBQLString()}));
            }
        }
        parameters.put(pos, value);
    
protected voidsetRollbackOnly()

        entityManager.setRollbackOnly();
    
protected abstract voidthrowNoResultException(java.lang.String message)

protected abstract voidthrowNonUniqueResultException(java.lang.String message)