| /* |
| * Copyright (c) 1998, 2021 Oracle and/or its affiliates. All rights reserved. |
| * Copyright (c) 1998, 2021 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 |
| 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); |
| } |
| |
| /** |
| * Applies the hints to the query. |
| * Throws IllegalArgumentException in case the hint value is illegal. |
| */ |
| public static DatabaseQuery apply(Map<String, Object> hints, DatabaseQuery query, ClassLoader loader, AbstractSession activeSession) { |
| if (hints == null) { |
| return query; |
| } |
| DatabaseQuery hintQuery = query; |
| for (Map.Entry<String, Object> entry : hints.entrySet()) { |
| String hintName = entry.getKey(); |
| if (entry.getValue() instanceof Object[]) { |
| Object[] values = (Object[])entry.getValue(); |
| 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).length() == 0); |
| } |
| |
| public static Set<String> 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<String, Hint> mainMap = new HashMap<>(); |
| Object[] valueArray; |
| HashMap<String, Object> 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()); |
| } |
| |
| 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<String, Object> existingHints = (Map<String, Object>)query.getProperty(QUERY_HINT_PROPERTY); |
| if (existingHints == null){ |
| existingHints = new HashMap<String, Object>(); |
| 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> T newInstance(Class<T> theClass, DatabaseQuery query, String hint) { |
| try { |
| if (PrivilegedAccessHelper.shouldUsePrivilegedAccess()){ |
| return AccessController.doPrivileged(new PrivilegedNewInstanceFromClass<T>(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[][]) { |
| Object[][] valueArray2 = (Object[][])valueArray; |
| for(int i=0; i<valueArray2.length; i++) { |
| valueMap.put(getUpperCaseString(valueArray2[i][0]), valueArray2[i][1]); |
| if(valueArray2[i][1] == null) { |
| valueToApplyMayBeNull = true; |
| } |
| } |
| } else { |
| for(int i=0; i<valueArray.length; i++) { |
| valueMap.put(getUpperCaseString(valueArray[i]), valueArray[i]); |
| if(valueArray[i] == null) { |
| valueToApplyMayBeNull = true; |
| } |
| } |
| } |
| defaultValueToApply = valueMap.get(defaultValue.toUpperCase(Locale.ROOT)); |
| } |
| } |
| |
| static void addHint(Hint hint) { |
| hint.initialize(); |
| mainMap.put(hint.name, hint); |
| } |
| |
| static Set<String> 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()) { |
| ((ObjectLevelReadQuery) query).setWaitTimeout(QueryHintsHandler.parseIntegerHint(valueToApply, QueryHints.PESSIMISTIC_LOCK_TIMEOUT)); |
| } else { |
| throw new IllegalArgumentException(ExceptionLocalization.buildMessage("ejb30-wrong-type-for-query-hint",new Object[]{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()) { |
| TimeUnit unit = TimeUnit.valueOf((String)valueToApply); |
| ((ObjectLevelReadQuery) query).setWaitTimeoutUnit(unit); |
| } else { |
| throw new IllegalArgumentException(ExceptionLocalization.buildMessage("ejb30-wrong-type-for-query-hint",new Object[]{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) { |
| query.setQueryTimeout(QueryHintsHandler.parseIntegerHint(valueToApply, QueryHints.JDBC_TIMEOUT)); |
| 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) { |
| try { |
| TimeUnit unit = TimeUnit.valueOf((String)valueToApply); |
| query.setQueryTimeoutUnit(unit); |
| } |
| catch(IllegalArgumentException e) { |
| throw new IllegalArgumentException(ExceptionLocalization.buildMessage("ejb30-wrong-type-for-query-hint",new Object[]{getQueryId(query), name, getPrintValue(valueToApply)})); |
| } |
| 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) { |
| query.setQueryTimeout(QueryHintsHandler.parseIntegerHint(valueToApply, QueryHints.QUERY_TIMEOUT)); |
| 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; |
| } |
| } |
| } |