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

org.eclipse.persistence.internal.jpa.QueryHintsHandler Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (c) 1998, 2024 Oracle and/or its affiliates. All rights reserved.
 * Copyright (c) 1998, 2024 IBM Corporation. All rights reserved.
 *
 * This program and the accompanying materials are made available under the
 * terms of the Eclipse Public License v. 2.0 which is available at
 * http://www.eclipse.org/legal/epl-2.0,
 * or the Eclipse Distribution License v. 1.0 which is available at
 * http://www.eclipse.org/org/documents/edl-v10.php.
 *
 * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
 */

// Contributors:
//     Oracle - initial API and implementation from Oracle TopLink
//     07/13/2009-2.0 Guy Pelletier
//       - 277039: JPA 2.0 Cache Usage Settings
//     corteggiano, Frank Schwarz, Tom Ware - Fix for bug Bug 320254 - EL 2.1.0 JPA: Query with hint eclipselink.batch
//              and org.eclipse.persistence.exceptions.QueryException.queryHintNavigatedNonExistantRelationship
//     10/29/2010-2.2 Michael O'Brien
//       - 325167: Make reserved # bind parameter char generic to enable native SQL pass through
//     06/30/2011-2.3.1 Guy Pelletier
//       - 341940: Add disable/enable allowing native queries
//     06/30/2015-2.6.0 Will Dazey
//       - 471487: Fixed eclipselink.jdbc.timeout hint not applying correctly to SQLCall
//     09/03/2015 - Will Dazey
//       - 456067 : Added support for defining query timeout units
//     09/04/2018-3.0 Ravi Babu Tummuru
//       - 538183: SETTING QUERYHINTS.CURSOR ON A NAMEDQUERY THROWS QUERYEXCEPTION
//     09/02/2019-3.0 Alexandre Jacob
//        - 527415: Fix code when locale is tr, az or lt
//     12/14/2023: Tomas Kraus
//       - New Jakarta Persistence 3.2 Features
package org.eclipse.persistence.internal.jpa;

import java.security.AccessController;
import java.security.PrivilegedActionException;
import java.sql.Time;
import java.util.Calendar;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.StringTokenizer;
import java.util.concurrent.TimeUnit;

import jakarta.persistence.CacheRetrieveMode;
import jakarta.persistence.CacheStoreMode;

import org.eclipse.persistence.exceptions.ConversionException;
import org.eclipse.persistence.exceptions.DescriptorException;
import org.eclipse.persistence.exceptions.QueryException;


import org.eclipse.persistence.queries.DatabaseQuery;
import org.eclipse.persistence.queries.ObjectLevelReadQuery;
import org.eclipse.persistence.queries.ReadAllQuery;
import org.eclipse.persistence.expressions.Expression;
import org.eclipse.persistence.annotations.BatchFetchType;
import org.eclipse.persistence.annotations.CacheType;
import org.eclipse.persistence.config.*;
import org.eclipse.persistence.descriptors.ClassDescriptor;
import org.eclipse.persistence.descriptors.invalidation.DailyCacheInvalidationPolicy;
import org.eclipse.persistence.descriptors.invalidation.TimeToLiveCacheInvalidationPolicy;
import org.eclipse.persistence.descriptors.partitioning.PartitioningPolicy;
import org.eclipse.persistence.history.AsOfClause;
import org.eclipse.persistence.history.AsOfSCNClause;
import org.eclipse.persistence.internal.helper.ClassConstants;
import org.eclipse.persistence.internal.helper.Helper;
import org.eclipse.persistence.internal.localization.ExceptionLocalization;
import org.eclipse.persistence.internal.queries.ContainerPolicy;
import org.eclipse.persistence.internal.security.PrivilegedAccessHelper;
import org.eclipse.persistence.internal.security.PrivilegedClassForName;
import org.eclipse.persistence.internal.security.PrivilegedNewInstanceFromClass;
import org.eclipse.persistence.internal.sessions.AbstractSession;
import org.eclipse.persistence.logging.SessionLog;
import org.eclipse.persistence.mappings.ForeignReferenceMapping;
import org.eclipse.persistence.mappings.DatabaseMapping;
import org.eclipse.persistence.queries.AttributeGroup;
import org.eclipse.persistence.queries.CursorPolicy;
import org.eclipse.persistence.queries.CursoredStreamPolicy;
import org.eclipse.persistence.queries.DataModifyQuery;
import org.eclipse.persistence.queries.DataReadQuery;
import org.eclipse.persistence.queries.DeleteAllQuery;
import org.eclipse.persistence.queries.DirectReadQuery;
import org.eclipse.persistence.queries.FetchGroup;
import org.eclipse.persistence.queries.InMemoryQueryIndirectionPolicy;
import org.eclipse.persistence.queries.LoadGroup;
import org.eclipse.persistence.queries.ModifyAllQuery;
import org.eclipse.persistence.queries.ModifyQuery;
import org.eclipse.persistence.queries.ObjectBuildingQuery;
import org.eclipse.persistence.queries.QueryRedirector;
import org.eclipse.persistence.queries.ReadObjectQuery;
import org.eclipse.persistence.queries.ReadQuery;
import org.eclipse.persistence.queries.ReportQuery;
import org.eclipse.persistence.queries.ResultSetMappingQuery;
import org.eclipse.persistence.queries.ScrollableCursorPolicy;
import org.eclipse.persistence.queries.UpdateAllQuery;
import org.eclipse.persistence.queries.ValueReadQuery;

/**
 * The class processes query hints.
 * 

* EclipseLink query hints and their values defined in org.eclipse.persistence.config package. *

* To add a new query hint: * Define a new hint in QueryHints; * Add a class containing hint's values if required to config package (like CacheUsage); * Alternatively values defined in HintValues may be used - Refresh and BindParameters hints do that. * Add an inner class to this class extending Hint corresponding to the new hint (like CacheUsageHint); * The first constructor parameter is hint name; the second is default value; * In constructor * provide 2-dimensional value array in case the values should be translated (currently all Hint classes do that); * in case translation is not required provide a single-dimension array (no such examples yet). * In inner class Hint static initializer addHint an instance of the new hint class (like addHint(new CacheUsageHint())). * * @see QueryHints * @see HintValues * @see CacheUsage * @see PessimisticLock */ public class QueryHintsHandler { public static final String QUERY_HINT_PROPERTY = "eclipselink.query.hints"; private QueryHintsHandler() { } /** * Verifies the hints. *

* If session != null then logs a FINEST message for each hint. * queryName parameter used only for identifying the query in messages, * if it's null then "null" will be used. * Throws IllegalArgumentException in case the hint value is illegal. */ public static void verify(Map hints, String queryName, AbstractSession session) { if(hints == null) { return; } Iterator it = hints.entrySet().iterator(); while(it.hasNext()) { Map.Entry entry = (Map.Entry)it.next(); String hintName = (String)entry.getKey(); verify(hintName, entry.getValue(), queryName, session); } } /** * Verifies the hint. *

* If session != null then logs a FINEST message. * queryName parameter used only for identifying the query in messages, * if it's null then "null" will be used. * Throws IllegalArgumentException in case the hint value is illegal. */ public static void verify(String hintName, Object hintValue, String queryName, AbstractSession session) { Hint.verify(hintName, shouldUseDefault(hintValue), hintValue, queryName, session); } // Retrieve query hints Map from DatabaseQuery @SuppressWarnings("unchecked") static Map get(DatabaseQuery query) { return (Map) query.getProperty(QUERY_HINT_PROPERTY); } /** * Applies the hints to the query. * Throws IllegalArgumentException in case the hint value is illegal. */ public static DatabaseQuery apply(Map hints, DatabaseQuery query, ClassLoader loader, AbstractSession activeSession) { if (hints == null) { return query; } DatabaseQuery hintQuery = query; for (Map.Entry entry : hints.entrySet()) { String hintName = entry.getKey(); if (entry.getValue() instanceof Object[] values) { for (int index = 0; index < values.length; index++) { hintQuery = apply(hintName, values[index], hintQuery, loader, activeSession); } } else { hintQuery = apply(hintName, entry.getValue(), hintQuery, loader, activeSession); } } return hintQuery; } /** * Applies the hint to the query. * Throws IllegalArgumentException in case the hint value is illegal. */ public static DatabaseQuery apply(String hintName, Object hintValue, DatabaseQuery query, ClassLoader loader, AbstractSession activeSession) { return Hint.apply(hintName, shouldUseDefault(hintValue), hintValue, query, loader, activeSession); } /** * Common hint value processing into an boolean value. If the hint is * null, false is returned. Those methods that need to handle a null hint * to be something other than false should not call this method. */ public static boolean parseBooleanHint(Object hint) { if (hint == null) { return false; } else { return Boolean.parseBoolean(hint.toString()); } } /** * Common hint value processing into an integer value. If the hint is * null, -1 is returned. */ public static int parseIntegerHint(Object hint, String hintName) { if (hint == null) { return -1; } else { try { return Integer.parseInt(hint.toString()); } catch (NumberFormatException e) { throw QueryException.queryHintContainedInvalidIntegerValue(hintName, hint, e); } } } /** * Empty String hintValue indicates that the default hint value * should be used. */ protected static boolean shouldUseDefault(Object hintValue) { return (hintValue != null) && (hintValue instanceof String) && (((String) hintValue).isEmpty()); } public static Set getSupportedHints(){ return Hint.getSupportedHints(); } /** * Define a generic Hint. * Hints should subclass this and override the applyToDatabaseQuery * and set the valueArray if the set of valid values is finite. */ protected static abstract class Hint { static HashMap mainMap = new HashMap<>(); Object[] valueArray; HashMap valueMap; String name; String defaultValue; Object defaultValueToApply; boolean valueToApplyMayBeNull; static { addHint(new BindParametersHint()); addHint(new CacheUsageHint()); addHint(new CacheRetrieveModeHint()); addHint(new CacheRetrieveModeLegacyHint()); addHint(new CacheStoreModeHint()); addHint(new CacheStoreModeLegacyHint()); addHint(new QueryTypeHint()); addHint(new PessimisticLockHint()); addHint(new PessimisticLockScope()); addHint(new PessimisticLockTimeoutHint()); addHint(new PessimisticLockTimeoutUnitHint()); addHint(new RefreshHint()); addHint(new CascadePolicyHint()); addHint(new BatchHint()); addHint(new BatchTypeHint()); addHint(new BatchSizeHint()); addHint(new FetchHint()); addHint(new LeftFetchHint()); addHint(new ReadOnlyHint()); addHint(new JDBCTimeoutHint()); //Enhancement addHint(new QueryTimeoutUnitHint()); //Enhancement addHint(new QueryTimeoutHint()); addHint(new JDBCFetchSizeHint()); addHint(new JDBCMaxRowsHint()); addHint(new JDBCFirstResultHint()); addHint(new ResultCollectionTypeHint()); addHint(new RedirectorHint()); addHint(new PartitioningHint()); addHint(new QueryCacheHint()); addHint(new QueryCacheSizeHint()); addHint(new QueryCacheExpiryHint()); addHint(new QueryCacheExpiryTimeOfDayHint()); addHint(new MaintainCacheHint()); addHint(new PrepareHint()); addHint(new CacheStatementHint()); addHint(new FlushHint()); addHint(new HintHint()); addHint(new NativeConnectionHint()); addHint(new CursorHint()); addHint(new CursorInitialSizeHint()); addHint(new CursorPageSizeHint()); addHint(new ScrollableCursorHint()); addHint(new CursorSizeHint()); addHint(new FetchGroupHint()); addHint(new FetchGraphHint()); addHint(new FetchGroupNameHint()); addHint(new FetchGroupDefaultHint()); addHint(new FetchGroupAttributeHint()); addHint(new FetchGroupLoadHint()); addHint(new LoadGroupHint()); addHint(new LoadGroupAttributeHint()); addHint(new LoadGraphHint()); addHint(new ExclusiveHint()); addHint(new InheritanceJoinHint()); addHint(new AsOfHint()); addHint(new AsOfSCNHint()); addHint(new ResultTypeHint()); addHint(new ResultSetTypeHint()); addHint(new ResultSetConcurrencyHint()); addHint(new IndirectionPolicyHint()); addHint(new QueryCacheTypeHint()); addHint(new QueryCacheIgnoreNullHint()); addHint(new QueryCacheInvalidateOnChangeHint()); addHint(new QueryCacheRandomizedExpiryHint()); // 325167: Make reserved # bind parameter char generic to enable native SQL pass through addHint(new ParameterDelimiterHint()); addHint(new CompositeMemberHint()); addHint(new AllowNativeSQLQueryHint()); addHint(new BatchWriteHint()); addHint(new ResultSetAccess()); addHint(new SerializedObject()); addHint(new ReturnNameValuePairsHint()); addHint(new PrintInnerJoinInWhereClauseHint()); addHint(new QueryResultsCacheValidation()); } Hint(String name, String defaultValue) { this.name = name; this.defaultValue = defaultValue; } abstract DatabaseQuery applyToDatabaseQuery(Object valueToApply, DatabaseQuery query, ClassLoader loader, AbstractSession activeSession); static void verify(String hintName, boolean shouldUseDefault, Object hintValue, String queryName, AbstractSession session) { Hint hint = mainMap.get(hintName); if(hint == null) { if(session != null) { session.log(SessionLog.FINEST, SessionLog.QUERY, "unknown_query_hint", new Object[]{getPrintValue(queryName), hintName}); } return; } hint.verify(hintValue, shouldUseDefault, queryName, session); } void verify(Object hintValue, boolean shouldUseDefault, String queryName, AbstractSession session) { if(shouldUseDefault) { hintValue = defaultValue; } if(session != null) { session.log(SessionLog.FINEST, SessionLog.QUERY, "query_hint", new Object[]{getPrintValue(queryName), name, getPrintValue(hintValue)}); } if(!shouldUseDefault && valueMap != null && !valueMap.containsKey(getUpperCaseString(hintValue))) { throw new IllegalArgumentException(ExceptionLocalization.buildMessage("ejb30-wrong-query-hint-value",new Object[]{getPrintValue(queryName), name, getPrintValue(hintValue)})); } } static DatabaseQuery apply(String hintName, boolean shouldUseDefault, Object hintValue, DatabaseQuery query, ClassLoader loader, AbstractSession activeSession) { Hint hint = mainMap.get(hintName); if (hint == null) { // unknown hint name - silently ignored. return query; } Map existingHints = (Map)query.getProperty(QUERY_HINT_PROPERTY); if (existingHints == null){ existingHints = new HashMap<>(); query.setProperty(QUERY_HINT_PROPERTY, existingHints); } existingHints.put(hintName, hintValue); return hint.apply(hintValue, shouldUseDefault, query, loader, activeSession); } DatabaseQuery apply(Object hintValue, boolean shouldUseDefault, DatabaseQuery query, ClassLoader loader, AbstractSession activeSession) { Object valueToApply = hintValue; if (shouldUseDefault) { valueToApply = defaultValueToApply; } else { if( valueMap != null) { String key = getUpperCaseString(hintValue); valueToApply = valueMap.get(key); if (valueToApply == null) { boolean wrongKey = true; if (valueToApplyMayBeNull) { wrongKey = !valueMap.containsKey(key); } if (wrongKey) { throw new IllegalArgumentException(ExceptionLocalization.buildMessage("ejb30-wrong-query-hint-value",new Object[]{getQueryId(query), name, getPrintValue(hintValue)})); } } } } return applyToDatabaseQuery(valueToApply, query, loader, activeSession); } static String getQueryId(DatabaseQuery query) { String queryId = query.getName(); if(queryId == null) { queryId = query.getEJBQLString(); } return getPrintValue(queryId); } static String getPrintValue(Object hintValue) { return hintValue != null ? hintValue.toString() : "null"; } static String getUpperCaseString(Object hintValue) { return hintValue != null ? hintValue.toString().toUpperCase(Locale.ROOT) : null; } static Class loadClass(String className, DatabaseQuery query, ClassLoader loader) throws QueryException { try { if (PrivilegedAccessHelper.shouldUsePrivilegedAccess()) { try { return AccessController.doPrivileged(new PrivilegedClassForName<>(className, true, loader)); } catch (PrivilegedActionException exception) { throw QueryException.classNotFoundWhileUsingQueryHint(query, className, exception.getException()); } } else { return PrivilegedAccessHelper.getClassForName(className, true, loader); } } catch (ClassNotFoundException exception){ throw QueryException.classNotFoundWhileUsingQueryHint(query, className, exception); } } static T newInstance(Class theClass, DatabaseQuery query, String hint) { try { if (PrivilegedAccessHelper.shouldUsePrivilegedAccess()){ return AccessController.doPrivileged(new PrivilegedNewInstanceFromClass<>(theClass)); } else { return PrivilegedAccessHelper.newInstanceFromClass(theClass); } } catch (Exception exception) { throw QueryException.errorInstantiatedClassForQueryHint(exception, query, theClass, hint); } } void initialize() { if(valueArray != null) { valueMap = new HashMap<>(valueArray.length); if(valueArray instanceof Object[][] valueArray2) { for(int i=0; i getSupportedHints(){ return mainMap.keySet(); } } /** * This hint can be used to indicate whether or not a ResultSetMapping query should * return populated DatabaseRecords vs. raw data. This hint is particularly useful * when the structure of the returned data is not known. */ protected static class ReturnNameValuePairsHint extends Hint { ReturnNameValuePairsHint() { super(QueryHints.RETURN_NAME_VALUE_PAIRS, HintValues.FALSE); valueArray = new Object[][] { {HintValues.TRUE, Boolean.TRUE}, {HintValues.FALSE, Boolean.FALSE} }; } /** * Applies the given hint value to the query if it is non-null. The given query * is expected to be a ResultSetMappingQuery instance. * @throws IllegalArgumentException if 'query' is not a ResultSetMappingQuery instance */ @Override DatabaseQuery applyToDatabaseQuery(Object valueToApply, DatabaseQuery query, ClassLoader loader, AbstractSession activeSession) { if (query.isResultSetMappingQuery()) { if (valueToApply != null) { ((ResultSetMappingQuery) query).setShouldReturnNameValuePairs(((Boolean) valueToApply)); } } else { throw new IllegalArgumentException(ExceptionLocalization.buildMessage("ejb30-wrong-type-for-query-hint",new Object[]{getQueryId(query), name, getPrintValue(valueToApply)})); } return query; } } protected static class BindParametersHint extends Hint { BindParametersHint() { super(QueryHints.BIND_PARAMETERS, HintValues.PERSISTENCE_UNIT_DEFAULT); valueArray = new Object[][] { {HintValues.PERSISTENCE_UNIT_DEFAULT, null}, {HintValues.TRUE, Boolean.TRUE}, {HintValues.FALSE, Boolean.FALSE} }; } @Override DatabaseQuery applyToDatabaseQuery(Object valueToApply, DatabaseQuery query, ClassLoader loader, AbstractSession activeSession) { if (valueToApply == null) { query.ignoreBindAllParameters(); } else { query.setShouldBindAllParameters(((Boolean)valueToApply).booleanValue()); } return query; } } protected static class AllowNativeSQLQueryHint extends Hint { AllowNativeSQLQueryHint() { super(QueryHints.ALLOW_NATIVE_SQL_QUERY, HintValues.PERSISTENCE_UNIT_DEFAULT); valueArray = new Object[][] { {HintValues.FALSE, Boolean.FALSE}, {HintValues.TRUE, Boolean.TRUE} }; } @Override DatabaseQuery applyToDatabaseQuery(Object valueToApply, DatabaseQuery query, ClassLoader loader, AbstractSession activeSession) { query.setAllowNativeSQLQuery((Boolean) valueToApply); return query; } } /** * INTERNAL: * 325167: Make reserved # bind parameter char generic to enable native SQL pass through */ protected static class ParameterDelimiterHint extends Hint { ParameterDelimiterHint() { super(QueryHints.PARAMETER_DELIMITER, ParameterDelimiterType.DEFAULT); // No valueArray modification is required for unrestricted values } @Override DatabaseQuery applyToDatabaseQuery(Object valueToApply, DatabaseQuery query, ClassLoader loader, AbstractSession activeSession) { // Only change the default set by the DatabaseQuery constructor - if an override is requested via the Hint if (valueToApply != null) { query.setParameterDelimiter(((String)valueToApply)); } return query; } } protected static class CacheRetrieveModeHint extends Hint { CacheRetrieveModeHint() { this(QueryHints.CACHE_RETRIEVE_MODE, CacheRetrieveMode.USE.name()); } CacheRetrieveModeHint(String name, String defaultValue) { super(name, defaultValue); } @Override DatabaseQuery applyToDatabaseQuery(Object valueToApply, DatabaseQuery query, ClassLoader loader, AbstractSession activeSession) { if (query.isObjectLevelReadQuery()) { if (valueToApply.equals(CacheRetrieveMode.BYPASS) || valueToApply.equals(CacheRetrieveMode.BYPASS.name())) { query.retrieveBypassCache(); } // CacheRetrieveMode.USE will use the EclipseLink default of // shouldCheckDescriptorForCacheUsage which in most cases is CheckCacheByPrimaryKey. } else { throw new IllegalArgumentException(ExceptionLocalization.buildMessage("ejb30-wrong-type-for-query-hint",new Object[]{getQueryId(query), name, getPrintValue(valueToApply)})); } return query; } } protected static class CacheRetrieveModeLegacyHint extends CacheRetrieveModeHint { CacheRetrieveModeLegacyHint() { super("jakarta.persistence.cacheRetrieveMode", CacheRetrieveMode.USE.name()); } @Override DatabaseQuery applyToDatabaseQuery(Object valueToApply, DatabaseQuery query, ClassLoader loader, AbstractSession activeSession) { if (activeSession != null) { String[] properties = new String[] { QueryHints.CACHE_RETRIEVE_MODE, "jakarta.persistence.cacheRetrieveMode" }; activeSession.log(SessionLog.INFO, SessionLog.TRANSACTION, "deprecated_property", properties); } return super.applyToDatabaseQuery(valueToApply, query, loader, activeSession); } } protected static class CacheStoreModeHint extends Hint { CacheStoreModeHint() { this(QueryHints.CACHE_STORE_MODE, CacheStoreMode.USE.name()); } CacheStoreModeHint(String name, String defaultValue) { super(name, defaultValue); } @Override DatabaseQuery applyToDatabaseQuery(Object valueToApply, DatabaseQuery query, ClassLoader loader, AbstractSession activeSession) { if (valueToApply.equals(CacheStoreMode.BYPASS) || valueToApply.equals(CacheStoreMode.BYPASS.name())) { query.storeBypassCache(); } else if (valueToApply.equals(CacheStoreMode.REFRESH) || valueToApply.equals(CacheStoreMode.REFRESH.name())) { if (query.isObjectLevelReadQuery()) { ((ObjectLevelReadQuery) query).refreshIdentityMapResult(); } else { throw new IllegalArgumentException(ExceptionLocalization.buildMessage("ejb30-wrong-type-for-query-hint",new Object[]{getQueryId(query), name, getPrintValue(valueToApply)})); } } // CacheStoreMode.USE will use the EclipseLink default maintainCache. return query; } } protected static class CacheStoreModeLegacyHint extends CacheStoreModeHint { CacheStoreModeLegacyHint() { super("jakarta.persistence.cacheStoreMode", CacheStoreMode.USE.name()); } @Override DatabaseQuery applyToDatabaseQuery(Object valueToApply, DatabaseQuery query, ClassLoader loader, AbstractSession activeSession) { if (activeSession != null) { String[] properties = new String[] { QueryHints.CACHE_STORE_MODE, "jakarta.persistence.cacheStoreMode" }; activeSession.log(SessionLog.INFO, SessionLog.TRANSACTION, "deprecated_property", properties); } return super.applyToDatabaseQuery(valueToApply, query, loader, activeSession); } } /** * Configure the cache usage of the query. * As many of the usages require a ReadObjectQuery, the hint may also require to change the query type. */ protected static class CacheUsageHint extends Hint { CacheUsageHint() { super(QueryHints.CACHE_USAGE, CacheUsage.DEFAULT); valueArray = new Object[][] { {CacheUsage.UseEntityDefault, ObjectLevelReadQuery.UseDescriptorSetting}, {CacheUsage.DoNotCheckCache, ObjectLevelReadQuery.DoNotCheckCache}, {CacheUsage.CheckCacheByExactPrimaryKey, ObjectLevelReadQuery.CheckCacheByExactPrimaryKey}, {CacheUsage.CheckCacheByPrimaryKey, ObjectLevelReadQuery.CheckCacheByPrimaryKey}, {CacheUsage.CheckCacheThenDatabase, ObjectLevelReadQuery.CheckCacheThenDatabase}, {CacheUsage.CheckCacheOnly, ObjectLevelReadQuery.CheckCacheOnly}, {CacheUsage.ConformResultsInUnitOfWork, ObjectLevelReadQuery.ConformResultsInUnitOfWork}, {CacheUsage.NoCache, ModifyAllQuery.NO_CACHE}, {CacheUsage.Invalidate, ModifyAllQuery.INVALIDATE_CACHE} }; } @Override DatabaseQuery applyToDatabaseQuery(Object valueToApply, DatabaseQuery query, ClassLoader loader, AbstractSession activeSession) { if (query.isObjectLevelReadQuery()) { int cacheUsage = (Integer) valueToApply; ((ObjectLevelReadQuery)query).setCacheUsage(cacheUsage); if (cacheUsage == ObjectLevelReadQuery.CheckCacheByExactPrimaryKey || cacheUsage == ObjectLevelReadQuery.CheckCacheByPrimaryKey || cacheUsage == ObjectLevelReadQuery.CheckCacheThenDatabase) { ReadObjectQuery newQuery = new ReadObjectQuery(); newQuery.copyFromQuery(query); return newQuery; } } else if (query.isModifyAllQuery()) { int cacheUsage = (Integer) valueToApply; ((ModifyAllQuery)query).setCacheUsage(cacheUsage); } else { throw new IllegalArgumentException(ExceptionLocalization.buildMessage("ejb30-wrong-type-for-query-hint",new Object[]{getQueryId(query), name, getPrintValue(valueToApply)})); } return query; } } /** * Configure the cache usage of the query. * As many of the usages require a ReadObjectQuery, the hint may also require to change the query type. */ protected static class BatchWriteHint extends Hint { BatchWriteHint() { super(QueryHints.BATCH_WRITING, HintValues.FALSE); valueArray = new Object[][] { {HintValues.FALSE, Boolean.FALSE}, {HintValues.TRUE, Boolean.TRUE} }; } @Override DatabaseQuery applyToDatabaseQuery(Object valueToApply, DatabaseQuery query, ClassLoader loader, AbstractSession activeSession) { if (query.isDataReadQuery()) { DataModifyQuery newQuery = new DataModifyQuery(); newQuery.copyFromQuery(query); newQuery.setIsBatchExecutionSupported((Boolean) valueToApply); return newQuery; } else if (query.isModifyQuery()) { ((ModifyQuery)query).setIsBatchExecutionSupported((Boolean) valueToApply); } else { throw new IllegalArgumentException(ExceptionLocalization.buildMessage("ejb30-wrong-type-for-query-hint",new Object[]{getQueryId(query), name, getPrintValue(valueToApply)})); } return query; } } protected static class CascadePolicyHint extends Hint { CascadePolicyHint() { super(QueryHints.REFRESH_CASCADE, CascadePolicy.DEFAULT); valueArray = new Object[][] { {CascadePolicy.NoCascading, DatabaseQuery.NoCascading}, {CascadePolicy.CascadePrivateParts, DatabaseQuery.CascadePrivateParts}, {CascadePolicy.CascadeAllParts, DatabaseQuery.CascadeAllParts}, {CascadePolicy.CascadeByMapping, DatabaseQuery.CascadeByMapping} }; } @Override DatabaseQuery applyToDatabaseQuery(Object valueToApply, DatabaseQuery query, ClassLoader loader, AbstractSession activeSession) { query.setCascadePolicy((Integer)valueToApply); return query; } } /** * Configure the type of the query. */ protected static class QueryTypeHint extends Hint { QueryTypeHint() { super(QueryHints.QUERY_TYPE, QueryType.DEFAULT); } @Override DatabaseQuery applyToDatabaseQuery(Object valueToApply, DatabaseQuery query, ClassLoader loader, AbstractSession activeSession) { if (valueToApply.equals(QueryType.DEFAULT)) { return query; } // Allows an query type, or a custom query class. DatabaseQuery newQuery = query; if (valueToApply.equals(QueryType.ReadAll)) { newQuery = new ReadAllQuery(); } else if (valueToApply.equals(QueryType.ReadObject)) { newQuery = new ReadObjectQuery(); } else if (valueToApply.equals(QueryType.Report)) { newQuery = new ReportQuery(); if (query.isObjectLevelReadQuery()) { ((ReportQuery)newQuery).addAttribute("root", ((ReportQuery)newQuery).getExpressionBuilder()); } } else if (valueToApply.equals(QueryType.ResultSetMapping)) { newQuery = new ResultSetMappingQuery(); } else if (valueToApply.equals(QueryType.UpdateAll)) { newQuery = new UpdateAllQuery(); } else if (valueToApply.equals(QueryType.DeleteAll)) { newQuery = new DeleteAllQuery(); } else if (valueToApply.equals(QueryType.DataModify)) { newQuery = new DataModifyQuery(); } else if (valueToApply.equals(QueryType.DataRead)) { newQuery = new DataReadQuery(); } else if (valueToApply.equals(QueryType.DirectRead)) { newQuery = new DirectReadQuery(); } else if (valueToApply.equals(QueryType.ValueRead)) { newQuery = new ValueReadQuery(); } else { Class queryClass = loadClass((String)valueToApply, query, loader); newQuery = (DatabaseQuery)newInstance(queryClass, query, QueryHints.QUERY_TYPE); } newQuery.copyFromQuery(query); return newQuery; } } protected static class PessimisticLockHint extends Hint { PessimisticLockHint() { super(QueryHints.PESSIMISTIC_LOCK, PessimisticLock.DEFAULT); valueArray = new Object[][] { {PessimisticLock.NoLock, ObjectLevelReadQuery.NO_LOCK}, {PessimisticLock.Lock, ObjectLevelReadQuery.LOCK}, {PessimisticLock.LockNoWait, ObjectLevelReadQuery.LOCK_NOWAIT} }; } @Override DatabaseQuery applyToDatabaseQuery(Object valueToApply, DatabaseQuery query, ClassLoader loader, AbstractSession activeSession) { if (query.isObjectBuildingQuery()) { ((ObjectBuildingQuery)query).setLockMode((Short) valueToApply); } else { throw new IllegalArgumentException(ExceptionLocalization.buildMessage("ejb30-wrong-type-for-query-hint",new Object[]{getQueryId(query), name, getPrintValue(valueToApply)})); } return query; } } protected static class PessimisticLockScope extends Hint { PessimisticLockScope() { super(QueryHints.PESSIMISTIC_LOCK_SCOPE, jakarta.persistence.PessimisticLockScope.NORMAL.name()); valueArray = new Object[] { jakarta.persistence.PessimisticLockScope.NORMAL.name(), jakarta.persistence.PessimisticLockScope.EXTENDED.name() }; } @Override DatabaseQuery applyToDatabaseQuery(Object valueToApply, DatabaseQuery query, ClassLoader loader, AbstractSession activeSession) { if (query.isObjectLevelReadQuery()) { boolean shouldExtend = valueToApply.equals(jakarta.persistence.PessimisticLockScope.EXTENDED.name()); ObjectLevelReadQuery olrQuery = (ObjectLevelReadQuery)query; olrQuery.setShouldExtendPessimisticLockScope(shouldExtend); if(shouldExtend) { olrQuery.extendPessimisticLockScope(); } } else { throw new IllegalArgumentException(ExceptionLocalization.buildMessage("ejb30-wrong-type-for-query-hint",new Object[]{getQueryId(query), name, getPrintValue(valueToApply)})); } return query; } } protected static class PessimisticLockTimeoutHint extends Hint { PessimisticLockTimeoutHint() { super(QueryHints.PESSIMISTIC_LOCK_TIMEOUT, ""); } @Override DatabaseQuery applyToDatabaseQuery(Object valueToApply, DatabaseQuery query, ClassLoader loader, AbstractSession activeSession) { if (query.isObjectLevelReadQuery()) { // According to QueryHints.PESSIMISTIC_LOCK_TIMEOUT javadoc valid values are Integer or Strings // that can be parsed to int values. // String class is final so no need to use instanceof if (valueToApply.getClass() == String.class) { ((ObjectLevelReadQuery) query).setWaitTimeout(QueryHintsHandler.parseIntegerHint(valueToApply, QueryHints.PESSIMISTIC_LOCK_TIMEOUT)); // Now the second case, which must be Number. Anything else will cause class cast exception. } else { int value; try { value = ((Number) valueToApply).intValue(); } catch (ClassCastException cce) { throw new IllegalArgumentException( ExceptionLocalization.buildMessage("ejb30-wrong-type-for-query-hint", new String[] {getQueryId(query), name, getPrintValue(valueToApply)})); } ((ObjectLevelReadQuery) query).setWaitTimeout(value); } } else { throw new IllegalArgumentException( ExceptionLocalization.buildMessage("ejb30-wrong-type-for-query-hint", new String[] {getQueryId(query), name, getPrintValue(valueToApply)})); } return query; } } protected static class PessimisticLockTimeoutUnitHint extends Hint { PessimisticLockTimeoutUnitHint() { super(QueryHints.PESSIMISTIC_LOCK_TIMEOUT_UNIT, ""); } @Override DatabaseQuery applyToDatabaseQuery(Object valueToApply, DatabaseQuery query, ClassLoader loader, AbstractSession activeSession) { if (query.isObjectLevelReadQuery()) { // According to QueryHints.PESSIMISTIC_LOCK_TIMEOUT_UNIT javadoc valid value is TimeUnit // But let's handle String values too to be foolproof // String class is final so no need to use instanceof if (valueToApply.getClass() == String.class) { ((ObjectLevelReadQuery) query).setWaitTimeoutUnit(TimeUnit.valueOf((String) valueToApply)); // Now the second case, which must be TimeUnit. Anything else will cause class cast exception. } else { TimeUnit unit; try { unit = (TimeUnit) valueToApply; } catch (ClassCastException cce) { throw new IllegalArgumentException( ExceptionLocalization.buildMessage("ejb30-wrong-type-for-query-hint", new String[] {getQueryId(query), name, getPrintValue(valueToApply)})); } ((ObjectLevelReadQuery) query).setWaitTimeoutUnit(unit); } } else { throw new IllegalArgumentException( ExceptionLocalization.buildMessage("ejb30-wrong-type-for-query-hint", new String[] {getQueryId(query), name, getPrintValue(valueToApply)})); } return query; } } protected static class RefreshHint extends Hint { RefreshHint() { super(QueryHints.REFRESH, HintValues.FALSE); valueArray = new Object[][] { {HintValues.FALSE, Boolean.FALSE}, {HintValues.TRUE, Boolean.TRUE} }; } @Override DatabaseQuery applyToDatabaseQuery(Object valueToApply, DatabaseQuery query, ClassLoader loader, AbstractSession activeSession) { if (query.isObjectBuildingQuery()) { ((ObjectBuildingQuery)query).setShouldRefreshIdentityMapResult((Boolean) valueToApply); // Set default cascade to be by mapping. if (!query.shouldCascadeParts()) { query.cascadeByMapping(); } } else { throw new IllegalArgumentException(ExceptionLocalization.buildMessage("ejb30-wrong-type-for-query-hint",new Object[]{getQueryId(query), name, getPrintValue(valueToApply)})); } return query; } } protected static class ResultTypeHint extends Hint { ResultTypeHint() { super(QueryHints.RESULT_TYPE, ResultType.DEFAULT); valueArray = new Object[][] { {ResultType.Map, ResultType.Map}, {ResultType.Array, ResultType.Array}, {ResultType.Value, ResultType.Value}, {ResultType.Attribute, ResultType.Attribute} }; } @Override DatabaseQuery applyToDatabaseQuery(Object valueToApply, DatabaseQuery query, ClassLoader loader, AbstractSession activeSession) { if (query.isDataReadQuery()) { if (valueToApply == ResultType.Map) { ((DataReadQuery)query).setResultType(DataReadQuery.MAP); } else if (valueToApply == ResultType.Array) { ((DataReadQuery)query).setResultType(DataReadQuery.ARRAY); } else if (valueToApply == ResultType.Attribute) { ((DataReadQuery)query).setResultType(DataReadQuery.ATTRIBUTE); } else if (valueToApply == ResultType.Value) { ((DataReadQuery)query).setResultType(DataReadQuery.VALUE); } } else if (query.isReportQuery()) { if (valueToApply == ResultType.Map) { ((ReportQuery)query).setReturnType(ReportQuery.ShouldReturnReportResult); } else if (valueToApply == ResultType.Array) { ((ReportQuery)query).setReturnType(ReportQuery.ShouldReturnArray); } else if (valueToApply == ResultType.Attribute) { ((ReportQuery)query).setReturnType(ReportQuery.ShouldReturnSingleAttribute); } else if (valueToApply == ResultType.Value) { ((ReportQuery)query).setReturnType(ReportQuery.ShouldReturnSingleValue); } } else { throw new IllegalArgumentException(ExceptionLocalization.buildMessage("ejb30-wrong-type-for-query-hint",new Object[]{getQueryId(query), name, getPrintValue(valueToApply)})); } return query; } } protected static class IndirectionPolicyHint extends Hint { IndirectionPolicyHint() { super(QueryHints.INDIRECTION_POLICY, CacheUsageIndirectionPolicy.DEFAULT); valueArray = new Object[][] { {CacheUsageIndirectionPolicy.Conform, InMemoryQueryIndirectionPolicy.SHOULD_IGNORE_EXCEPTION_RETURN_CONFORMED}, {CacheUsageIndirectionPolicy.NotConform, InMemoryQueryIndirectionPolicy.SHOULD_IGNORE_EXCEPTION_RETURN_CONFORMED}, {CacheUsageIndirectionPolicy.Trigger, InMemoryQueryIndirectionPolicy.SHOULD_TRIGGER_INDIRECTION}, {CacheUsageIndirectionPolicy.Exception, InMemoryQueryIndirectionPolicy.SHOULD_THROW_INDIRECTION_EXCEPTION} }; } @Override DatabaseQuery applyToDatabaseQuery(Object valueToApply, DatabaseQuery query, ClassLoader loader, AbstractSession activeSession) { if (query.isObjectLevelReadQuery()) { ((ObjectLevelReadQuery) query).setInMemoryQueryIndirectionPolicyState((Integer)valueToApply); } else { throw new IllegalArgumentException(ExceptionLocalization.buildMessage("ejb30-wrong-type-for-query-hint",new Object[]{getQueryId(query), name, getPrintValue(valueToApply)})); } return query; } } protected static class ResultSetTypeHint extends Hint { ResultSetTypeHint() { super(QueryHints.RESULT_SET_TYPE, ResultSetType.DEFAULT); valueArray = new Object[][] { {ResultSetType.Forward, ScrollableCursorPolicy.FETCH_FORWARD}, {ResultSetType.ForwardOnly, ScrollableCursorPolicy.TYPE_FORWARD_ONLY}, {ResultSetType.Reverse, ScrollableCursorPolicy.FETCH_REVERSE}, {ResultSetType.ScrollInsensitive, ScrollableCursorPolicy.TYPE_SCROLL_INSENSITIVE}, {ResultSetType.ScrollSensitive, ScrollableCursorPolicy.TYPE_SCROLL_SENSITIVE}, {ResultSetType.Unknown, ScrollableCursorPolicy.FETCH_UNKNOWN} }; } @Override DatabaseQuery applyToDatabaseQuery(Object valueToApply, DatabaseQuery query, ClassLoader loader, AbstractSession activeSession) { int value = (Integer)valueToApply; if (query.isReadAllQuery()) { if (!((ReadAllQuery) query).getContainerPolicy().isScrollableCursorPolicy()) { ((ReadAllQuery) query).useScrollableCursor(); } ((ScrollableCursorPolicy)((ReadAllQuery) query).getContainerPolicy()).setResultSetType(value); } else if (query.isDataReadQuery()) { if (!((DataReadQuery) query).getContainerPolicy().isScrollableCursorPolicy()) { ((DataReadQuery) query).useScrollableCursor(); } ((ScrollableCursorPolicy)((DataReadQuery) query).getContainerPolicy()).setResultSetType(value); } else { throw new IllegalArgumentException(ExceptionLocalization.buildMessage("ejb30-wrong-type-for-query-hint",new Object[]{getQueryId(query), name, getPrintValue(valueToApply)})); } return query; } } protected static class ResultSetConcurrencyHint extends Hint { ResultSetConcurrencyHint() { super(QueryHints.RESULT_SET_CONCURRENCY, ResultSetConcurrency.DEFAULT); valueArray = new Object[][] { {ResultSetConcurrency.ReadOnly, ScrollableCursorPolicy.CONCUR_READ_ONLY}, {ResultSetConcurrency.Updatable, ScrollableCursorPolicy.CONCUR_UPDATABLE} }; } @Override DatabaseQuery applyToDatabaseQuery(Object valueToApply, DatabaseQuery query, ClassLoader loader, AbstractSession activeSession) { int value = (Integer)valueToApply; if (query.isReadAllQuery()) { if (!((ReadAllQuery) query).getContainerPolicy().isScrollableCursorPolicy()) { ((ReadAllQuery) query).useScrollableCursor(); } ((ScrollableCursorPolicy)((ReadAllQuery) query).getContainerPolicy()).setResultSetConcurrency(value); } else if (query.isDataReadQuery()) { if (!((DataReadQuery) query).getContainerPolicy().isScrollableCursorPolicy()) { ((DataReadQuery) query).useScrollableCursor(); } ((ScrollableCursorPolicy)((DataReadQuery) query).getContainerPolicy()).setResultSetConcurrency(value); } else { throw new IllegalArgumentException(ExceptionLocalization.buildMessage("ejb30-wrong-type-for-query-hint",new Object[]{getQueryId(query), name, getPrintValue(valueToApply)})); } return query; } } protected static class ExclusiveHint extends Hint { ExclusiveHint() { super(QueryHints.EXCLUSIVE_CONNECTION, HintValues.FALSE); valueArray = new Object[][] { {HintValues.FALSE, Boolean.FALSE}, {HintValues.TRUE, Boolean.TRUE} }; } @Override DatabaseQuery applyToDatabaseQuery(Object valueToApply, DatabaseQuery query, ClassLoader loader, AbstractSession activeSession) { if (query.isObjectBuildingQuery()) { ((ObjectBuildingQuery)query).setShouldUseExclusiveConnection((Boolean) valueToApply); } else { throw new IllegalArgumentException(ExceptionLocalization.buildMessage("ejb30-wrong-type-for-query-hint",new Object[]{getQueryId(query), name, getPrintValue(valueToApply)})); } return query; } } protected static class InheritanceJoinHint extends Hint { InheritanceJoinHint() { super(QueryHints.INHERITANCE_OUTER_JOIN, HintValues.FALSE); valueArray = new Object[][] { {HintValues.FALSE, Boolean.FALSE}, {HintValues.TRUE, Boolean.TRUE} }; } @Override DatabaseQuery applyToDatabaseQuery(Object valueToApply, DatabaseQuery query, ClassLoader loader, AbstractSession activeSession) { if (query.isObjectLevelReadQuery()) { ((ObjectLevelReadQuery)query).setShouldOuterJoinSubclasses((Boolean) valueToApply); } else { throw new IllegalArgumentException(ExceptionLocalization.buildMessage("ejb30-wrong-type-for-query-hint",new Object[]{getQueryId(query), name, getPrintValue(valueToApply)})); } return query; } } protected static class FetchGroupDefaultHint extends Hint { FetchGroupDefaultHint() { super(QueryHints.FETCH_GROUP_DEFAULT, HintValues.TRUE); valueArray = new Object[][] { {HintValues.FALSE, Boolean.FALSE}, {HintValues.TRUE, Boolean.TRUE} }; } @Override DatabaseQuery applyToDatabaseQuery(Object valueToApply, DatabaseQuery query, ClassLoader loader, AbstractSession activeSession) { if (query.isObjectLevelReadQuery()) { ((ObjectLevelReadQuery)query).setShouldUseDefaultFetchGroup((Boolean) valueToApply); } else { throw new IllegalArgumentException(ExceptionLocalization.buildMessage("ejb30-wrong-type-for-query-hint",new Object[]{getQueryId(query), name, getPrintValue(valueToApply)})); } return query; } } protected static class FetchGroupNameHint extends Hint { FetchGroupNameHint() { super(QueryHints.FETCH_GROUP_NAME, ""); } @Override DatabaseQuery applyToDatabaseQuery(Object valueToApply, DatabaseQuery query, ClassLoader loader, AbstractSession activeSession) { if (query.isObjectLevelReadQuery()) { ((ObjectLevelReadQuery)query).setFetchGroupName((String)valueToApply); } else { throw new IllegalArgumentException(ExceptionLocalization.buildMessage("ejb30-wrong-type-for-query-hint",new Object[]{getQueryId(query), name, getPrintValue(valueToApply)})); } return query; } } protected static class FetchGroupHint extends Hint { FetchGroupHint() { super(QueryHints.FETCH_GROUP, ""); } @Override DatabaseQuery applyToDatabaseQuery(Object valueToApply, DatabaseQuery query, ClassLoader loader, AbstractSession activeSession) { if (query.isObjectLevelReadQuery()) { if(valueToApply != null) { ((ObjectLevelReadQuery)query).setFetchGroup(((AttributeGroup)valueToApply).toFetchGroup()); } else { ((ObjectLevelReadQuery)query).setFetchGroup(null); } } else { throw new IllegalArgumentException(ExceptionLocalization.buildMessage("ejb30-wrong-type-for-query-hint",new Object[]{getQueryId(query), name, getPrintValue(valueToApply)})); } return query; } } protected static class FetchGraphHint extends Hint { FetchGraphHint() { super(QueryHints.JPA_FETCH_GRAPH, ""); } @Override DatabaseQuery applyToDatabaseQuery(Object valueToApply, DatabaseQuery query, ClassLoader loader, AbstractSession activeSession) { if (query.isObjectLevelReadQuery()) { if(valueToApply != null) { if (valueToApply instanceof String){ AttributeGroup eg = activeSession.getAttributeGroups().get(valueToApply); if (eg != null){ FetchGroup fg = eg.toFetchGroup(); fg.setShouldLoadAll(true); ((ObjectLevelReadQuery)query).setFetchGroup(fg); }else{ throw new IllegalArgumentException(ExceptionLocalization.buildMessage("no_entity_graph_of_name", new Object[]{valueToApply})); } }else if (valueToApply instanceof EntityGraphImpl){ FetchGroup fg = ((EntityGraphImpl)valueToApply).getAttributeGroup().toFetchGroup(); fg.setShouldLoadAll(true); ((ObjectLevelReadQuery)query).setFetchGroup(fg); }else{ throw new IllegalArgumentException(ExceptionLocalization.buildMessage("not_usable_passed_to_entitygraph_hint", new Object[]{QueryHints.JPA_FETCH_GRAPH, valueToApply})); } } else { ((ObjectLevelReadQuery)query).setFetchGroup(null); } } else { throw new IllegalArgumentException(ExceptionLocalization.buildMessage("ejb30-wrong-type-for-query-hint",new Object[]{getQueryId(query), name, getPrintValue(valueToApply)})); } return query; } } protected static class FetchGroupAttributeHint extends Hint { FetchGroupAttributeHint() { super(QueryHints.FETCH_GROUP_ATTRIBUTE, ""); } @Override DatabaseQuery applyToDatabaseQuery(Object valueToApply, DatabaseQuery query, ClassLoader loader, AbstractSession activeSession) { if (query.isObjectLevelReadQuery()) { FetchGroup fetchGroup = ((ObjectLevelReadQuery)query).getFetchGroup(); if (fetchGroup == null) { fetchGroup = new FetchGroup(); ((ObjectLevelReadQuery)query).setFetchGroup(fetchGroup); } fetchGroup.addAttribute((String)valueToApply); } else { throw new IllegalArgumentException(ExceptionLocalization.buildMessage("ejb30-wrong-type-for-query-hint",new Object[]{getQueryId(query), name, getPrintValue(valueToApply)})); } return query; } } protected static class FetchGroupLoadHint extends Hint { FetchGroupLoadHint() { super(QueryHints.FETCH_GROUP_LOAD, HintValues.TRUE); valueArray = new Object[][] { {HintValues.FALSE, Boolean.FALSE}, {HintValues.TRUE, Boolean.TRUE} }; } @Override DatabaseQuery applyToDatabaseQuery(Object valueToApply, DatabaseQuery query, ClassLoader loader, AbstractSession activeSession) { if (query.isObjectLevelReadQuery()) { FetchGroup fetchGroup = ((ObjectLevelReadQuery)query).getFetchGroup(); if (fetchGroup == null) { fetchGroup = new FetchGroup(); ((ObjectLevelReadQuery)query).setFetchGroup(fetchGroup); } fetchGroup.setShouldLoadAll((Boolean)valueToApply); } else { throw new IllegalArgumentException(ExceptionLocalization.buildMessage("ejb30-wrong-type-for-query-hint",new Object[]{getQueryId(query), name, getPrintValue(valueToApply)})); } return query; } } protected static class LoadGroupHint extends Hint { LoadGroupHint() { super(QueryHints.LOAD_GROUP, ""); } @Override DatabaseQuery applyToDatabaseQuery(Object valueToApply, DatabaseQuery query, ClassLoader loader, AbstractSession activeSession) { if (query.isObjectLevelReadQuery()) { if(valueToApply != null) { ((ObjectLevelReadQuery)query).setLoadGroup(((AttributeGroup)valueToApply).toLoadGroup()); } else { ((ObjectLevelReadQuery)query).setLoadGroup(null); } } else { throw new IllegalArgumentException(ExceptionLocalization.buildMessage("ejb30-wrong-type-for-query-hint",new Object[]{getQueryId(query), name, getPrintValue(valueToApply)})); } return query; } } protected static class LoadGraphHint extends Hint { LoadGraphHint() { super(QueryHints.JPA_LOAD_GRAPH, ""); } @Override DatabaseQuery applyToDatabaseQuery(Object valueToApply, DatabaseQuery query, ClassLoader loader, AbstractSession activeSession) { if (query.isObjectLevelReadQuery()) { if(valueToApply != null) { if (valueToApply instanceof String){ AttributeGroup eg = activeSession.getAttributeGroups().get(valueToApply); if (eg != null){ ((ObjectLevelReadQuery)query).setLoadGroup(eg.toLoadGroup()); }else{ throw new IllegalArgumentException(ExceptionLocalization.buildMessage("no_entity_graph_of_name", new Object[]{valueToApply})); } }else if (valueToApply instanceof EntityGraphImpl){ ((ObjectLevelReadQuery)query).setLoadGroup(((EntityGraphImpl)valueToApply).getAttributeGroup().toLoadGroup()); }else{ throw new IllegalArgumentException(ExceptionLocalization.buildMessage("not_usable_passed_to_entitygraph_hint", new Object[]{QueryHints.JPA_LOAD_GRAPH, valueToApply})); } } else { ((ObjectLevelReadQuery)query).setFetchGroup(null); } } else { throw new IllegalArgumentException(ExceptionLocalization.buildMessage("ejb30-wrong-type-for-query-hint",new Object[]{getQueryId(query), name, getPrintValue(valueToApply)})); } return query; } } protected static class LoadGroupAttributeHint extends Hint { LoadGroupAttributeHint() { super(QueryHints.LOAD_GROUP_ATTRIBUTE, ""); } @Override DatabaseQuery applyToDatabaseQuery(Object valueToApply, DatabaseQuery query, ClassLoader loader, AbstractSession activeSession) { if (query.isObjectLevelReadQuery()) { LoadGroup loadGroup = ((ObjectLevelReadQuery)query).getLoadGroup(); if (loadGroup == null) { loadGroup = new LoadGroup(); ((ObjectLevelReadQuery)query).setLoadGroup(loadGroup); } loadGroup.addAttribute((String)valueToApply); } else { throw new IllegalArgumentException(ExceptionLocalization.buildMessage("ejb30-wrong-type-for-query-hint",new Object[]{getQueryId(query), name, getPrintValue(valueToApply)})); } return query; } } /** * Define the query cache hint. * Only reset the query cache if unset (as other query cache properties may be set first). */ protected static class QueryCacheHint extends Hint { QueryCacheHint() { super(QueryHints.QUERY_RESULTS_CACHE, HintValues.FALSE); valueArray = new Object[][] { {HintValues.FALSE, Boolean.FALSE}, {HintValues.TRUE, Boolean.TRUE} }; } @Override DatabaseQuery applyToDatabaseQuery(Object valueToApply, DatabaseQuery query, ClassLoader loader, AbstractSession activeSession) { if (query.isReadQuery()) { if ((Boolean) valueToApply) { if (((ReadQuery)query).getQueryResultsCachePolicy() == null) { ((ReadQuery)query).cacheQueryResults(); } } } else { throw new IllegalArgumentException(ExceptionLocalization.buildMessage("ejb30-wrong-type-for-query-hint",new Object[]{getQueryId(query), name, getPrintValue(valueToApply)})); } return query; } } /** * Define the query cache ignore null hint. * Only reset the query cache if unset (as other query cache properties may be set first). */ protected static class QueryCacheIgnoreNullHint extends Hint { QueryCacheIgnoreNullHint() { super(QueryHints.QUERY_RESULTS_CACHE_IGNORE_NULL, HintValues.FALSE); valueArray = new Object[][] { {HintValues.FALSE, Boolean.FALSE}, {HintValues.TRUE, Boolean.TRUE} }; } @Override DatabaseQuery applyToDatabaseQuery(Object valueToApply, DatabaseQuery query, ClassLoader loader, AbstractSession activeSession) { if (query.isReadQuery()) { if (((ReadQuery)query).getQueryResultsCachePolicy() == null) { ((ReadQuery)query).cacheQueryResults(); } ((ReadQuery)query).getQueryResultsCachePolicy().setIsNullIgnored((Boolean) valueToApply); } else { throw new IllegalArgumentException(ExceptionLocalization.buildMessage("ejb30-wrong-type-for-query-hint",new Object[]{getQueryId(query), name, getPrintValue(valueToApply)})); } return query; } } /** * Define the query cache ignore null hint. * Only reset the query cache if unset (as other query cache properties may be set first). */ protected static class QueryCacheInvalidateOnChangeHint extends Hint { QueryCacheInvalidateOnChangeHint() { super(QueryHints.QUERY_RESULTS_CACHE_INVALIDATE, HintValues.TRUE); valueArray = new Object[][] { {HintValues.FALSE, Boolean.FALSE}, {HintValues.TRUE, Boolean.TRUE} }; } @Override DatabaseQuery applyToDatabaseQuery(Object valueToApply, DatabaseQuery query, ClassLoader loader, AbstractSession activeSession) { if (query.isReadQuery()) { if (((ReadQuery)query).getQueryResultsCachePolicy() == null) { ((ReadQuery)query).cacheQueryResults(); } ((ReadQuery)query).getQueryResultsCachePolicy().setInvalidateOnChange((Boolean) valueToApply); } else { throw new IllegalArgumentException(ExceptionLocalization.buildMessage("ejb30-wrong-type-for-query-hint",new Object[]{getQueryId(query), name, getPrintValue(valueToApply)})); } return query; } } /** * Define the query cache randomized expiry hint. * Only reset the query cache if unset (as other query cache properties may be set first). */ protected static class QueryCacheRandomizedExpiryHint extends Hint { QueryCacheRandomizedExpiryHint() { super(QueryHints.QUERY_RESULTS_CACHE_RANDOMIZE_EXPIRY, HintValues.FALSE); valueArray = new Object[][] { {HintValues.FALSE, Boolean.FALSE}, {HintValues.TRUE, Boolean.TRUE} }; } @Override DatabaseQuery applyToDatabaseQuery(Object valueToApply, DatabaseQuery query, ClassLoader loader, AbstractSession activeSession) { if (query.isReadQuery()) { if (((ReadQuery)query).getQueryResultsCachePolicy() == null) { ((ReadQuery)query).cacheQueryResults(); } if (((ReadQuery)query).getQueryResultsCachePolicy().getCacheInvalidationPolicy() == null) { ((ReadQuery)query).getQueryResultsCachePolicy().setCacheInvalidationPolicy(new TimeToLiveCacheInvalidationPolicy()); } ((ReadQuery)query).getQueryResultsCachePolicy().getCacheInvalidationPolicy().setIsInvalidationRandomized((Boolean) valueToApply); } else { throw new IllegalArgumentException(ExceptionLocalization.buildMessage("ejb30-wrong-type-for-query-hint",new Object[]{getQueryId(query), name, getPrintValue(valueToApply)})); } return query; } } /** * Define the query cache size hint. * Only reset the query cache if unset (as other query cache properties may be set first). */ protected static class QueryCacheSizeHint extends Hint { QueryCacheSizeHint() { super(QueryHints.QUERY_RESULTS_CACHE_SIZE, ""); } @Override DatabaseQuery applyToDatabaseQuery(Object valueToApply, DatabaseQuery query, ClassLoader loader, AbstractSession activeSession) { if (query.isReadQuery()) { ReadQuery readQuery = (ReadQuery)query; if (readQuery.getQueryResultsCachePolicy() == null) { readQuery.cacheQueryResults(); } try { readQuery.getQueryResultsCachePolicy().setMaximumCachedResults(Integer.parseInt((String)valueToApply)); } catch (NumberFormatException exception) { throw QueryException.queryHintContainedInvalidIntegerValue(QueryHints.QUERY_RESULTS_CACHE_SIZE, valueToApply, exception); } } else { throw new IllegalArgumentException(ExceptionLocalization.buildMessage("ejb30-wrong-type-for-query-hint",new Object[]{getQueryId(query), name, getPrintValue(valueToApply)})); } return query; } } /** * Define the query cache expiry hint. * Only reset the query cache if unset (as other query cache properties may be set first). */ protected static class QueryCacheExpiryHint extends Hint { QueryCacheExpiryHint() { super(QueryHints.QUERY_RESULTS_CACHE_EXPIRY, ""); } @Override DatabaseQuery applyToDatabaseQuery(Object valueToApply, DatabaseQuery query, ClassLoader loader, AbstractSession activeSession) { if (query.isReadQuery()) { ReadQuery readQuery = (ReadQuery)query; if (readQuery.getQueryResultsCachePolicy() == null) { readQuery.cacheQueryResults(); } try { readQuery.getQueryResultsCachePolicy().setCacheInvalidationPolicy( new TimeToLiveCacheInvalidationPolicy(Integer.parseInt((String)valueToApply))); } catch (NumberFormatException exception) { throw QueryException.queryHintContainedInvalidIntegerValue(QueryHints.QUERY_RESULTS_CACHE_EXPIRY, valueToApply, exception); } } else { throw new IllegalArgumentException(ExceptionLocalization.buildMessage("ejb30-wrong-type-for-query-hint",new Object[]{getQueryId(query), name, getPrintValue(valueToApply)})); } return query; } } /** * Define the query cache type hint. * Only reset the query cache if unset (as other query cache properties may be set first). */ protected static class QueryCacheTypeHint extends Hint { QueryCacheTypeHint() { super(QueryHints.QUERY_RESULTS_CACHE_TYPE, ""); } @Override DatabaseQuery applyToDatabaseQuery(Object valueToApply, DatabaseQuery query, ClassLoader loader, AbstractSession activeSession) { if (query.isReadQuery()) { ReadQuery readQuery = (ReadQuery)query; if (readQuery.getQueryResultsCachePolicy() == null) { readQuery.cacheQueryResults(); } if (valueToApply == null) { // Leave as default. } else if (valueToApply.equals(CacheType.SOFT_WEAK.name())) { readQuery.getQueryResultsCachePolicy().setCacheType(ClassConstants.SoftCacheWeakIdentityMap_Class); } else if (valueToApply.equals(CacheType.FULL.name())) { readQuery.getQueryResultsCachePolicy().setCacheType(ClassConstants.FullIdentityMap_Class); } else if (valueToApply.equals(CacheType.WEAK.name())) { readQuery.getQueryResultsCachePolicy().setCacheType(ClassConstants.WeakIdentityMap_Class); } else if (valueToApply.equals(CacheType.SOFT.name())) { readQuery.getQueryResultsCachePolicy().setCacheType(ClassConstants.SoftIdentityMap_Class); } else if (valueToApply.equals(CacheType.HARD_WEAK.name())) { readQuery.getQueryResultsCachePolicy().setCacheType(ClassConstants.HardCacheWeakIdentityMap_Class); } else if (valueToApply.equals(CacheType.CACHE.name())) { readQuery.getQueryResultsCachePolicy().setCacheType(ClassConstants.CacheIdentityMap_Class); } else if (valueToApply.equals(CacheType.NONE.name())) { readQuery.getQueryResultsCachePolicy().setCacheType(ClassConstants.NoIdentityMap_Class); } else { throw new IllegalArgumentException(ExceptionLocalization.buildMessage("ejb30-wrong-query-hint-value",new Object[]{getQueryId(query), name, getPrintValue(valueToApply)})); } } else { throw new IllegalArgumentException(ExceptionLocalization.buildMessage("ejb30-wrong-type-for-query-hint",new Object[]{getQueryId(query), name, getPrintValue(valueToApply)})); } return query; } } /** * Define the query cache expiry time of day hint. * Only reset the query cache if unset (as other query cache properties may be set first). */ protected static class QueryCacheExpiryTimeOfDayHint extends Hint { QueryCacheExpiryTimeOfDayHint() { super(QueryHints.QUERY_RESULTS_CACHE_EXPIRY_TIME_OF_DAY, ""); } @Override DatabaseQuery applyToDatabaseQuery(Object valueToApply, DatabaseQuery query, ClassLoader loader, AbstractSession activeSession) { if (query.isReadQuery()) { ReadQuery readQuery = (ReadQuery)query; if (readQuery.getQueryResultsCachePolicy() == null) { readQuery.cacheQueryResults(); } try { Time time = Helper.timeFromString((String)valueToApply); Calendar calendar = Calendar.getInstance(); calendar.setTime(time); readQuery.getQueryResultsCachePolicy().setCacheInvalidationPolicy( new DailyCacheInvalidationPolicy(calendar.get(Calendar.HOUR_OF_DAY), calendar.get(Calendar.MINUTE), calendar.get(Calendar.SECOND), 0)); } catch (ConversionException exception) { throw QueryException.queryHintContainedInvalidIntegerValue(QueryHints.QUERY_RESULTS_CACHE_EXPIRY_TIME_OF_DAY, valueToApply, exception); } } else { throw new IllegalArgumentException(ExceptionLocalization.buildMessage("ejb30-wrong-type-for-query-hint",new Object[]{getQueryId(query), name, getPrintValue(valueToApply)})); } return query; } } protected static class BatchHint extends Hint { BatchHint() { super(QueryHints.BATCH, ""); } @Override DatabaseQuery applyToDatabaseQuery(Object valueToApply, DatabaseQuery query, ClassLoader loader, AbstractSession activeSession) { if (query.isObjectLevelReadQuery() && !query.isReportQuery()) { ObjectLevelReadQuery objectQuery = (ObjectLevelReadQuery)query; StringTokenizer tokenizer = new StringTokenizer((String)valueToApply, "."); if (tokenizer.countTokens() < 2){ throw QueryException.queryHintDidNotContainEnoughTokens(query, QueryHints.BATCH, valueToApply); } // ignore the first token since we are assuming an alias to the primary class // e.g. In e.phoneNumbers we will assume "e" refers to the base of the query String previousToken = tokenizer.nextToken(); objectQuery.checkDescriptor(activeSession); ClassDescriptor descriptor = objectQuery.getDescriptor(); Expression expression = objectQuery.getExpressionBuilder(); while (tokenizer.hasMoreTokens()) { String token = tokenizer.nextToken(); DatabaseMapping mapping = descriptor.getObjectBuilder().getMappingForAttributeName(token); if (mapping == null) { // Allow batching of subclass mappings. if (!descriptor.hasInheritance()) { throw QueryException.queryHintNavigatedNonExistantRelationship(query, QueryHints.BATCH, valueToApply, previousToken + "." + token); } } else if (!mapping.isForeignReferenceMapping() && !mapping.isAggregateObjectMapping()) { throw QueryException.queryHintNavigatedIllegalRelationship(query, QueryHints.BATCH, valueToApply, previousToken + "." + token); } expression = expression.get(token, false); previousToken = token; if (mapping != null){ descriptor = mapping.getReferenceDescriptor(); } } objectQuery.addBatchReadAttribute(expression); } else { throw new IllegalArgumentException(ExceptionLocalization.buildMessage("ejb30-wrong-type-for-query-hint",new Object[]{getQueryId(query), name, getPrintValue(valueToApply)})); } return query; } } protected static class BatchTypeHint extends Hint { BatchTypeHint() { super(QueryHints.BATCH_TYPE, ""); } @Override DatabaseQuery applyToDatabaseQuery(Object valueToApply, DatabaseQuery query, ClassLoader loader, AbstractSession activeSession) { if (query.isObjectLevelReadQuery()) { if (valueToApply instanceof BatchFetchType) { ((ObjectLevelReadQuery) query).setBatchFetchType((BatchFetchType)valueToApply); } else { ((ObjectLevelReadQuery) query).setBatchFetchType(BatchFetchType.valueOf((String)valueToApply)); } } else { throw new IllegalArgumentException(ExceptionLocalization.buildMessage("ejb30-wrong-type-for-query-hint",new Object[]{getQueryId(query), name, getPrintValue(valueToApply)})); } return query; } } protected static class BatchSizeHint extends Hint { BatchSizeHint() { super(QueryHints.BATCH_SIZE, ""); } @Override DatabaseQuery applyToDatabaseQuery(Object valueToApply, DatabaseQuery query, ClassLoader loader, AbstractSession activeSession) { if (query.isObjectLevelReadQuery()) { ((ObjectLevelReadQuery) query).setBatchFetchSize(QueryHintsHandler.parseIntegerHint(valueToApply, QueryHints.BATCH_SIZE)); } else { throw new IllegalArgumentException(ExceptionLocalization.buildMessage("ejb30-wrong-type-for-query-hint",new Object[]{getQueryId(query), name, getPrintValue(valueToApply)})); } return query; } } protected static class FetchHint extends Hint { FetchHint() { super(QueryHints.FETCH, ""); } @Override DatabaseQuery applyToDatabaseQuery(Object valueToApply, DatabaseQuery query, ClassLoader loader, AbstractSession activeSession) { if (query.isObjectLevelReadQuery() && !query.isReportQuery()) { ObjectLevelReadQuery olrq = (ObjectLevelReadQuery)query; StringTokenizer tokenizer = new StringTokenizer((String)valueToApply, "."); if (tokenizer.countTokens() < 2){ throw QueryException.queryHintDidNotContainEnoughTokens(query, QueryHints.FETCH, valueToApply); } // ignore the first token since we are assuming read all query // e.g. In e.phoneNumbers we will assume "e" refers to the base of the query String previousToken = tokenizer.nextToken(); olrq.checkDescriptor(activeSession); ClassDescriptor descriptor = olrq.getDescriptor(); Expression expression = olrq.getExpressionBuilder(); while (tokenizer.hasMoreTokens()){ String token = tokenizer.nextToken(); ForeignReferenceMapping frMapping = null; DatabaseMapping mapping = descriptor.getObjectBuilder().getMappingForAttributeName(token); if (mapping == null){ throw QueryException.queryHintNavigatedNonExistantRelationship(query, QueryHints.FETCH, valueToApply, previousToken + "." + token); } else if (!mapping.isForeignReferenceMapping()){ while (mapping.isAggregateObjectMapping() && tokenizer.hasMoreTokens()){ expression = expression.get(token); token = tokenizer.nextToken(); descriptor = mapping.getReferenceDescriptor(); mapping = descriptor.getObjectBuilder().getMappingForAttributeName(token); } if (!mapping.isForeignReferenceMapping()){ throw QueryException.queryHintNavigatedIllegalRelationship(query, QueryHints.FETCH, valueToApply, previousToken + "." + token); } } frMapping = (ForeignReferenceMapping)mapping; descriptor = frMapping.getReferenceDescriptor(); if (frMapping.isCollectionMapping()){ expression = expression.anyOf(token, false); } else { expression = expression.get(token); } previousToken = token; } olrq.addJoinedAttribute(expression); } else { throw new IllegalArgumentException(ExceptionLocalization.buildMessage("ejb30-wrong-type-for-query-hint",new Object[]{getQueryId(query), name, getPrintValue(valueToApply)})); } return query; } } protected static class LeftFetchHint extends Hint { LeftFetchHint() { super(QueryHints.LEFT_FETCH, ""); } @Override DatabaseQuery applyToDatabaseQuery(Object valueToApply, DatabaseQuery query, ClassLoader loader, AbstractSession activeSession) { if (query.isObjectLevelReadQuery() && !query.isReportQuery()) { ObjectLevelReadQuery olrq = (ObjectLevelReadQuery)query; StringTokenizer tokenizer = new StringTokenizer((String)valueToApply, "."); if (tokenizer.countTokens() < 2){ throw QueryException.queryHintDidNotContainEnoughTokens(query, QueryHints.LEFT_FETCH, valueToApply); } // ignore the first token since we are assuming read all query // e.g. In e.phoneNumbers we will assume "e" refers to the base of the query String previousToken = tokenizer.nextToken(); olrq.checkDescriptor(activeSession); ClassDescriptor descriptor = olrq.getDescriptor(); Expression expression = olrq.getExpressionBuilder(); while (tokenizer.hasMoreTokens()){ String token = tokenizer.nextToken(); ForeignReferenceMapping frMapping = null; DatabaseMapping mapping = descriptor.getObjectBuilder().getMappingForAttributeName(token); if (mapping == null){ throw QueryException.queryHintNavigatedNonExistantRelationship(query, QueryHints.LEFT_FETCH, valueToApply, previousToken + "." + token); } else if (!mapping.isForeignReferenceMapping()){ while (mapping.isAggregateObjectMapping() && tokenizer.hasMoreTokens()){ expression = expression.get(token); token = tokenizer.nextToken(); descriptor = mapping.getReferenceDescriptor(); mapping = descriptor.getObjectBuilder().getMappingForAttributeName(token); } if (!mapping.isForeignReferenceMapping()){ throw QueryException.queryHintNavigatedIllegalRelationship(query, QueryHints.LEFT_FETCH, valueToApply, previousToken + "." + token); } } frMapping = (ForeignReferenceMapping)mapping; descriptor = frMapping.getReferenceDescriptor(); if (frMapping.isCollectionMapping()){ expression = expression.anyOfAllowingNone(token, false); } else { expression = expression.getAllowingNull(token); } previousToken = token; } olrq.addJoinedAttribute(expression); } else { throw new IllegalArgumentException(ExceptionLocalization.buildMessage("ejb30-wrong-type-for-query-hint",new Object[]{getQueryId(query), name, getPrintValue(valueToApply)})); } return query; } } protected static class ReadOnlyHint extends Hint { ReadOnlyHint() { super(QueryHints.READ_ONLY, HintValues.FALSE); valueArray = new Object[][] { {HintValues.FALSE, Boolean.FALSE}, {HintValues.TRUE, Boolean.TRUE} }; } @Override DatabaseQuery applyToDatabaseQuery(Object valueToApply, DatabaseQuery query, ClassLoader loader, AbstractSession activeSession) { if (query.isObjectLevelReadQuery()) { ((ObjectLevelReadQuery)query).setIsReadOnly((Boolean) valueToApply); } else { throw new IllegalArgumentException(ExceptionLocalization.buildMessage("ejb30-wrong-type-for-query-hint",new Object[]{getQueryId(query), name, getPrintValue(valueToApply)})); } return query; } } protected static class NativeConnectionHint extends Hint { NativeConnectionHint() { super(QueryHints.NATIVE_CONNECTION, HintValues.FALSE); valueArray = new Object[][] { {HintValues.FALSE, Boolean.FALSE}, {HintValues.TRUE, Boolean.TRUE} }; } @Override DatabaseQuery applyToDatabaseQuery(Object valueToApply, DatabaseQuery query, ClassLoader loader, AbstractSession activeSession) { query.setIsNativeConnectionRequired((Boolean) valueToApply); return query; } } protected static class CursorHint extends Hint { CursorHint() { super(QueryHints.CURSOR, HintValues.FALSE); valueArray = new Object[][] { {HintValues.FALSE, Boolean.FALSE}, {HintValues.TRUE, Boolean.TRUE} }; } @Override DatabaseQuery applyToDatabaseQuery(Object valueToApply, DatabaseQuery query, ClassLoader loader, AbstractSession activeSession) { if (!(Boolean) valueToApply) { if (query.isReadAllQuery()) { if (((ReadAllQuery) query).getContainerPolicy().isCursoredStreamPolicy()) { ((ReadAllQuery) query).setContainerPolicy(ContainerPolicy.buildDefaultPolicy()); } } else if (query.isDataReadQuery()) { if (((DataReadQuery) query).getContainerPolicy().isCursoredStreamPolicy()) { ((DataReadQuery) query).setContainerPolicy(ContainerPolicy.buildDefaultPolicy()); } } } else { if (query.isReadAllQuery()) { if (!((ReadAllQuery) query).getContainerPolicy().isCursoredStreamPolicy()) { ((ReadAllQuery) query).useCursoredStream(); } } else if (query.isDataReadQuery()) { if (!((DataReadQuery) query).getContainerPolicy().isCursoredStreamPolicy()) { ((DataReadQuery) query).useCursoredStream(); } } else { throw new IllegalArgumentException(ExceptionLocalization.buildMessage("ejb30-wrong-type-for-query-hint",new Object[]{getQueryId(query), name, getPrintValue(valueToApply)})); } } query.setIsPrepared(false); return query; } } protected static class CursorInitialSizeHint extends Hint { CursorInitialSizeHint() { super(QueryHints.CURSOR_INITIAL_SIZE, ""); } @Override DatabaseQuery applyToDatabaseQuery(Object valueToApply, DatabaseQuery query, ClassLoader loader, AbstractSession activeSession) { if (query.isReadAllQuery()) { if (!((ReadAllQuery) query).getContainerPolicy().isCursoredStreamPolicy()) { ((ReadAllQuery) query).useCursoredStream(); } ((CursoredStreamPolicy)((ReadAllQuery) query).getContainerPolicy()).setInitialReadSize(QueryHintsHandler.parseIntegerHint(valueToApply, QueryHints.CURSOR_INITIAL_SIZE)); } else if (query.isDataReadQuery()) { if (!((DataReadQuery) query).getContainerPolicy().isCursoredStreamPolicy()) { ((DataReadQuery) query).useCursoredStream(); } ((CursoredStreamPolicy)((DataReadQuery) query).getContainerPolicy()).setInitialReadSize(QueryHintsHandler.parseIntegerHint(valueToApply, QueryHints.CURSOR_INITIAL_SIZE)); } else { throw new IllegalArgumentException(ExceptionLocalization.buildMessage("ejb30-wrong-type-for-query-hint",new Object[]{getQueryId(query), name, getPrintValue(valueToApply)})); } return query; } } protected static class CursorPageSizeHint extends Hint { CursorPageSizeHint() { super(QueryHints.CURSOR_PAGE_SIZE, ""); } @Override DatabaseQuery applyToDatabaseQuery(Object valueToApply, DatabaseQuery query, ClassLoader loader, AbstractSession activeSession) { if (query.isReadAllQuery()) { if (!((ReadAllQuery) query).getContainerPolicy().isCursorPolicy()) { ((ReadAllQuery) query).useCursoredStream(); } ((CursorPolicy)((ReadAllQuery) query).getContainerPolicy()).setPageSize(QueryHintsHandler.parseIntegerHint(valueToApply, QueryHints.CURSOR_PAGE_SIZE)); } else if (query.isDataReadQuery()) { if (!((DataReadQuery) query).getContainerPolicy().isCursorPolicy()) { ((DataReadQuery) query).useCursoredStream(); } ((CursorPolicy)((DataReadQuery) query).getContainerPolicy()).setPageSize(QueryHintsHandler.parseIntegerHint(valueToApply, QueryHints.CURSOR_PAGE_SIZE)); } else { throw new IllegalArgumentException(ExceptionLocalization.buildMessage("ejb30-wrong-type-for-query-hint",new Object[]{getQueryId(query), name, getPrintValue(valueToApply)})); } return query; } } protected static class CursorSizeHint extends Hint { CursorSizeHint() { super(QueryHints.CURSOR_SIZE, ""); } @Override DatabaseQuery applyToDatabaseQuery(Object valueToApply, DatabaseQuery query, ClassLoader loader, AbstractSession activeSession) { if (query.isReadAllQuery()) { if (!((ReadAllQuery) query).getContainerPolicy().isCursoredStreamPolicy()) { ((ReadAllQuery) query).useCursoredStream(); } ((CursoredStreamPolicy)((ReadAllQuery) query).getContainerPolicy()).setSizeQuery(new ValueReadQuery((String)valueToApply)); } else if (query.isDataReadQuery()) { if (!((DataReadQuery) query).getContainerPolicy().isCursoredStreamPolicy()) { ((DataReadQuery) query).useCursoredStream(); } ((CursoredStreamPolicy)((ReadAllQuery) query).getContainerPolicy()).setSizeQuery(new ValueReadQuery((String)valueToApply)); } else { throw new IllegalArgumentException(ExceptionLocalization.buildMessage("ejb30-wrong-type-for-query-hint",new Object[]{getQueryId(query), name, getPrintValue(valueToApply)})); } return query; } } protected static class ScrollableCursorHint extends Hint { ScrollableCursorHint() { super(QueryHints.SCROLLABLE_CURSOR, HintValues.FALSE); valueArray = new Object[][] { {HintValues.FALSE, Boolean.FALSE}, {HintValues.TRUE, Boolean.TRUE} }; } @Override DatabaseQuery applyToDatabaseQuery(Object valueToApply, DatabaseQuery query, ClassLoader loader, AbstractSession activeSession) { if (!(Boolean) valueToApply) { if (query.isReadAllQuery()) { if (((ReadAllQuery) query).getContainerPolicy().isScrollableCursorPolicy()) { ((ReadAllQuery) query).setContainerPolicy(ContainerPolicy.buildDefaultPolicy()); } } else if (query.isDataReadQuery()) { if (((DataReadQuery) query).getContainerPolicy().isScrollableCursorPolicy()) { ((DataReadQuery) query).setContainerPolicy(ContainerPolicy.buildDefaultPolicy()); } } } else { if (query.isReadAllQuery()) { if (!((ReadAllQuery) query).getContainerPolicy().isScrollableCursorPolicy()) { ((ReadAllQuery) query).useScrollableCursor(); } } else if (query.isDataReadQuery()) { if (!((DataReadQuery) query).getContainerPolicy().isScrollableCursorPolicy()) { ((DataReadQuery) query).useScrollableCursor(); } } else { throw new IllegalArgumentException(ExceptionLocalization.buildMessage("ejb30-wrong-type-for-query-hint",new Object[]{getQueryId(query), name, getPrintValue(valueToApply)})); } } return query; } } protected static class MaintainCacheHint extends Hint { MaintainCacheHint() { super(QueryHints.MAINTAIN_CACHE, HintValues.FALSE); valueArray = new Object[][] { {HintValues.FALSE, Boolean.FALSE}, {HintValues.TRUE, Boolean.TRUE} }; } @Override DatabaseQuery applyToDatabaseQuery(Object valueToApply, DatabaseQuery query, ClassLoader loader, AbstractSession activeSession) { query.setShouldMaintainCache((Boolean) valueToApply); return query; } } protected static class PrepareHint extends Hint { PrepareHint() { super(QueryHints.PREPARE, HintValues.FALSE); valueArray = new Object[][] { {HintValues.FALSE, Boolean.FALSE}, {HintValues.TRUE, Boolean.TRUE} }; } @Override DatabaseQuery applyToDatabaseQuery(Object valueToApply, DatabaseQuery query, ClassLoader loader, AbstractSession activeSession) { query.setShouldPrepare((Boolean) valueToApply); return query; } } protected static class CacheStatementHint extends Hint { CacheStatementHint() { super(QueryHints.CACHE_STATMENT, HintValues.FALSE); valueArray = new Object[][] { {HintValues.FALSE, Boolean.FALSE}, {HintValues.TRUE, Boolean.TRUE} }; } @Override DatabaseQuery applyToDatabaseQuery(Object valueToApply, DatabaseQuery query, ClassLoader loader, AbstractSession activeSession) { query.setShouldCacheStatement((Boolean) valueToApply); return query; } } protected static class FlushHint extends Hint { FlushHint() { super(QueryHints.FLUSH, HintValues.FALSE); valueArray = new Object[][] { {HintValues.FALSE, Boolean.FALSE}, {HintValues.TRUE, Boolean.TRUE} }; } @Override DatabaseQuery applyToDatabaseQuery(Object valueToApply, DatabaseQuery query, ClassLoader loader, AbstractSession activeSession) { query.setFlushOnExecute((Boolean)valueToApply); return query; } } protected static class HintHint extends Hint { HintHint() { super(QueryHints.HINT, ""); } @Override DatabaseQuery applyToDatabaseQuery(Object valueToApply, DatabaseQuery query, ClassLoader loader, AbstractSession activeSession) { query.setHintString((String)valueToApply); return query; } } protected static class JDBCTimeoutHint extends Hint { JDBCTimeoutHint() { super(QueryHints.JDBC_TIMEOUT, ""); } @Override DatabaseQuery applyToDatabaseQuery(Object valueToApply, DatabaseQuery query, ClassLoader loader, AbstractSession activeSession) { // According to QueryHints.JDBC_TIMEOUT javadoc valid values are Integer or Strings // that can be parsed to int values. // String class is final so no need to use instanceof if (valueToApply.getClass() == String.class) { query.setQueryTimeout(QueryHintsHandler.parseIntegerHint(valueToApply, QueryHints.JDBC_TIMEOUT)); // Now the second case, which must be Number. Anything else will cause class cast exception. } else { int value; try { value = ((Number) valueToApply).intValue(); } catch (ClassCastException cce) { throw new IllegalArgumentException( ExceptionLocalization.buildMessage("ejb30-wrong-type-for-query-hint", new String[] {getQueryId(query), name, getPrintValue(valueToApply)})); } query.setQueryTimeout(value); } query.setIsPrepared(false); return query; } } //Bug #456067: Added support for user defining the timeout units to use protected static class QueryTimeoutUnitHint extends Hint { QueryTimeoutUnitHint() { super(QueryHints.QUERY_TIMEOUT_UNIT, ""); } @Override DatabaseQuery applyToDatabaseQuery(Object valueToApply, DatabaseQuery query, ClassLoader loader, AbstractSession activeSession) { // According to QueryHints.QUERY_TIMEOUT_UNIT javadoc, provided value shall be TimeUnit // But let's handle String values too to be foolproof // String class is final so no need to use instanceof if (valueToApply.getClass() == String.class) { query.setQueryTimeoutUnit(TimeUnit.valueOf((String) valueToApply)); // Now the second case, which must be TimeUnit. Anything else will cause class cast exception. } else { TimeUnit unit; try { unit = (TimeUnit) valueToApply; } catch (ClassCastException cce) { throw new IllegalArgumentException( ExceptionLocalization.buildMessage("ejb30-wrong-type-for-query-hint", new String[] {getQueryId(query), name, getPrintValue(valueToApply)})); } query.setQueryTimeoutUnit(unit); } return query; } } //Bug #456067: Added support for query hint "jakarta.persistence.query.timeout" defined in the spec protected static class QueryTimeoutHint extends Hint { QueryTimeoutHint() { super(QueryHints.QUERY_TIMEOUT, ""); } @Override DatabaseQuery applyToDatabaseQuery(Object valueToApply, DatabaseQuery query, ClassLoader loader, AbstractSession activeSession) { // According to QueryHints.QUERY_TIMEOUT javadoc valid values are Strings that can be parsed to int values. // Let's also accept Number values to be compatible with QueryHints.PESSIMISTIC_LOCK_TIMEOUT // String class is final so no need to use instanceof if (valueToApply.getClass() == String.class) { query.setQueryTimeout(QueryHintsHandler.parseIntegerHint(valueToApply, QueryHints.QUERY_TIMEOUT)); // Now the second case, which must be Number. Anything else will cause class cast exception. } else { int value; try { value = ((Number) valueToApply).intValue(); } catch (ClassCastException cce) { throw new IllegalArgumentException( ExceptionLocalization.buildMessage("ejb30-wrong-type-for-query-hint", new String[] {getQueryId(query), name, getPrintValue(valueToApply)})); } query.setQueryTimeout(value); } query.setIsPrepared(false); return query; } } protected static class JDBCFetchSizeHint extends Hint { JDBCFetchSizeHint() { super(QueryHints.JDBC_FETCH_SIZE, ""); } @Override DatabaseQuery applyToDatabaseQuery(Object valueToApply, DatabaseQuery query, ClassLoader loader, AbstractSession activeSession) { if (query.isReadQuery()) { ((ReadQuery) query).setFetchSize(QueryHintsHandler.parseIntegerHint(valueToApply, QueryHints.JDBC_FETCH_SIZE)); } else { throw new IllegalArgumentException(ExceptionLocalization.buildMessage("ejb30-wrong-type-for-query-hint",new Object[]{getQueryId(query), name, getPrintValue(valueToApply)})); } return query; } } protected static class AsOfHint extends Hint { AsOfHint() { super(QueryHints.AS_OF, ""); } @Override DatabaseQuery applyToDatabaseQuery(Object valueToApply, DatabaseQuery query, ClassLoader loader, AbstractSession activeSession) { if (query.isObjectLevelReadQuery()) { ((ObjectLevelReadQuery) query).setAsOfClause(new AsOfClause(Helper.timestampFromString((String)valueToApply))); } else { throw new IllegalArgumentException(ExceptionLocalization.buildMessage("ejb30-wrong-type-for-query-hint",new Object[]{getQueryId(query), name, getPrintValue(valueToApply)})); } return query; } } protected static class AsOfSCNHint extends Hint { AsOfSCNHint() { super(QueryHints.AS_OF_SCN, ""); } @Override DatabaseQuery applyToDatabaseQuery(Object valueToApply, DatabaseQuery query, ClassLoader loader, AbstractSession activeSession) { if (query.isObjectLevelReadQuery()) { ((ObjectLevelReadQuery) query).setAsOfClause(new AsOfSCNClause(QueryHintsHandler.parseIntegerHint(valueToApply, QueryHints.AS_OF_SCN))); } else { throw new IllegalArgumentException(ExceptionLocalization.buildMessage("ejb30-wrong-type-for-query-hint",new Object[]{getQueryId(query), name, getPrintValue(valueToApply)})); } return query; } } protected static class JDBCMaxRowsHint extends Hint { JDBCMaxRowsHint() { super(QueryHints.JDBC_MAX_ROWS, ""); } @Override DatabaseQuery applyToDatabaseQuery(Object valueToApply, DatabaseQuery query, ClassLoader loader, AbstractSession activeSession) { if (query.isReadQuery()) { ((ReadQuery) query).setMaxRows(QueryHintsHandler.parseIntegerHint(valueToApply, QueryHints.JDBC_MAX_ROWS)); } else { throw new IllegalArgumentException(ExceptionLocalization.buildMessage("ejb30-wrong-type-for-query-hint",new Object[]{getQueryId(query), name, getPrintValue(valueToApply)})); } return query; } } protected static class JDBCFirstResultHint extends Hint { JDBCFirstResultHint() { super(QueryHints.JDBC_FIRST_RESULT, ""); } @Override DatabaseQuery applyToDatabaseQuery(Object valueToApply, DatabaseQuery query, ClassLoader loader, AbstractSession activeSession) { if (query.isReadQuery()) { ((ReadQuery) query).setFirstResult(QueryHintsHandler.parseIntegerHint(valueToApply, QueryHints.JDBC_FIRST_RESULT)); } else { throw new IllegalArgumentException(ExceptionLocalization.buildMessage("ejb30-wrong-type-for-query-hint",new Object[]{getQueryId(query), name, getPrintValue(valueToApply)})); } return query; } } protected static class ResultCollectionTypeHint extends Hint { ResultCollectionTypeHint() { super(QueryHints.RESULT_COLLECTION_TYPE, ""); } @Override DatabaseQuery applyToDatabaseQuery(Object valueToApply, DatabaseQuery query, ClassLoader loader, AbstractSession activeSession) { if (query.isReadAllQuery()) { Class collectionClass = null; if (valueToApply instanceof String) { collectionClass = loadClass((String)valueToApply, query, loader); } else { collectionClass = (Class)valueToApply; } ((ReadAllQuery)query).useCollectionClass(collectionClass); } else { throw new IllegalArgumentException(ExceptionLocalization.buildMessage("ejb30-wrong-type-for-query-hint",new Object[]{getQueryId(query), name, getPrintValue(valueToApply)})); } return query; } } protected static class RedirectorHint extends Hint { RedirectorHint() { super(QueryHints.QUERY_REDIRECTOR, ""); } @Override DatabaseQuery applyToDatabaseQuery(Object valueToApply, DatabaseQuery query, ClassLoader loader, AbstractSession activeSession) { // Can be an instance, class, or class name. try { Object redirector = valueToApply; if (valueToApply instanceof Class) { redirector = newInstance((Class)valueToApply, query, QueryHints.QUERY_REDIRECTOR); } else if (valueToApply instanceof String) { Class redirectorClass = loadClass((String)valueToApply, query, loader); redirector = newInstance(redirectorClass, query, QueryHints.QUERY_REDIRECTOR); } query.setRedirector((QueryRedirector)redirector); } catch (ClassCastException exception){ throw QueryException.unableToSetRedirectorOnQueryFromHint(query,QueryHints.QUERY_REDIRECTOR, valueToApply.getClass().getName(), exception); } return query; } } protected static class PartitioningHint extends Hint { PartitioningHint() { super(QueryHints.PARTITIONING, ""); } @Override DatabaseQuery applyToDatabaseQuery(Object valueToApply, DatabaseQuery query, ClassLoader loader, AbstractSession activeSession) { // Can be an instance, class, or name. Object policy = valueToApply; if (valueToApply instanceof Class) { policy = newInstance((Class)valueToApply, query, QueryHints.PARTITIONING); } else if (valueToApply instanceof String) { policy = activeSession.getProject().getPartitioningPolicy((String)valueToApply); if (policy == null) { throw DescriptorException.missingPartitioningPolicy((String)valueToApply, null, null); } } query.setPartitioningPolicy((PartitioningPolicy)policy); return query; } } protected static class CompositeMemberHint extends Hint { CompositeMemberHint() { super(QueryHints.COMPOSITE_UNIT_MEMBER, ""); } @Override DatabaseQuery applyToDatabaseQuery(Object valueToApply, DatabaseQuery query, ClassLoader loader, AbstractSession activeSession) { query.setSessionName((String)valueToApply); return query; } } protected static class ResultSetAccess extends Hint { ResultSetAccess() { super(QueryHints.RESULT_SET_ACCESS, HintValues.PERSISTENCE_UNIT_DEFAULT); valueArray = new Object[][] { {HintValues.PERSISTENCE_UNIT_DEFAULT, null}, {HintValues.TRUE, Boolean.TRUE}, {HintValues.FALSE, Boolean.FALSE} }; } @Override DatabaseQuery applyToDatabaseQuery(Object valueToApply, DatabaseQuery query, ClassLoader loader, AbstractSession activeSession) { if (query.isObjectLevelReadQuery()) { if (valueToApply != null) { ((ObjectLevelReadQuery)query).setIsResultSetAccessOptimizedQuery((Boolean)valueToApply); } else { ((ObjectLevelReadQuery)query).clearIsResultSetOptimizedQuery(); } } else { throw new IllegalArgumentException(ExceptionLocalization.buildMessage("ejb30-wrong-type-for-query-hint",new Object[]{getQueryId(query), name, getPrintValue(valueToApply)})); } return query; } } protected static class SerializedObject extends Hint { SerializedObject() { super(QueryHints.SERIALIZED_OBJECT, HintValues.FALSE); valueArray = new Object[][] { {HintValues.TRUE, Boolean.TRUE}, {HintValues.FALSE, Boolean.FALSE} }; } @Override DatabaseQuery applyToDatabaseQuery(Object valueToApply, DatabaseQuery query, ClassLoader loader, AbstractSession activeSession) { if (query.isObjectLevelReadQuery()) { ((ObjectLevelReadQuery)query).setShouldUseSerializedObjectPolicy((Boolean)valueToApply); } else { throw new IllegalArgumentException(ExceptionLocalization.buildMessage("ejb30-wrong-type-for-query-hint",new Object[]{getQueryId(query), name, getPrintValue(valueToApply)})); } return query; } } protected static class PrintInnerJoinInWhereClauseHint extends Hint { PrintInnerJoinInWhereClauseHint() { super(QueryHints.INNER_JOIN_IN_WHERE_CLAUSE, HintValues.TRUE); valueArray = new Object[][] { {HintValues.TRUE, Boolean.TRUE}, {HintValues.FALSE, Boolean.FALSE} }; } @Override DatabaseQuery applyToDatabaseQuery(Object valueToApply, DatabaseQuery query, ClassLoader loader, AbstractSession activeSession) { if (query.isObjectLevelReadQuery()) { ((ObjectLevelReadQuery)query).setPrintInnerJoinInWhereClause((Boolean)valueToApply); } else { throw new IllegalArgumentException(ExceptionLocalization.buildMessage("ejb30-wrong-type-for-query-hint",new Object[]{getQueryId(query), name, getPrintValue(valueToApply)})); } return query; } } protected static class QueryResultsCacheValidation extends Hint { QueryResultsCacheValidation() { super(QueryHints.QUERY_RESULTS_CACHE_VALIDATION, HintValues.FALSE); valueArray = new Object[][] { {HintValues.TRUE, Boolean.TRUE}, {HintValues.FALSE, Boolean.FALSE} }; } @Override DatabaseQuery applyToDatabaseQuery(Object valueToApply, DatabaseQuery query, ClassLoader loader, AbstractSession activeSession) { if (query instanceof ReadQuery) { ((ReadQuery)query).setAllowQueryResultsCacheValidation((Boolean)valueToApply); } else { throw new IllegalArgumentException(ExceptionLocalization.buildMessage("ejb30-wrong-type-for-query-hint",new Object[]{getQueryId(query), name, getPrintValue(valueToApply)})); } return query; } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy