org.eclipse.persistence.internal.sessions.PropertiesHandler Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of eclipselink Show documentation
Show all versions of eclipselink Show documentation
EclipseLink build based upon Git transaction f2b9fc5
/*
* Copyright (c) 1998, 2023 Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1998, 2018 IBM Corporation and/or its affiliates. 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
// Gordon Yorke - VM managed entity detachment
// Eduard Bartsch, SAP - Fix for Bug 351186 - ConcurrentModificationException Exception in PropertiesHandler
// Rick Curtis - Add support for WebSphere Liberty platform.
// 08/11/2014-2.5 Rick Curtis
// - 440594: Tolerate invalid NamedQuery at EntityManager creation.
// 09/03/2015 - Will Dazey
// - 456067 : Added support for defining query timeout units
// 09/28/2015 - Will Dazey
// - 478331 : Added support for defining local or server as the default locale for obtaining timestamps
// 03/11/2016 - Jody Grassel
// - 489794 : Add support for WebSphere EJBEmbeddable platform.
// 08/29/2016 Jody Grassel
// - 500441: Eclipselink core has System.getProperty() calls that are not potentially executed under doPriv()
// 04/11/2018 - Will Dazey
// - 533148 : Add the eclipselink.jpa.sql-call-deferral property
package org.eclipse.persistence.internal.sessions;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import org.eclipse.persistence.annotations.IdValidation;
import org.eclipse.persistence.config.BatchWriting;
import org.eclipse.persistence.config.CacheType;
import org.eclipse.persistence.config.CommitOrderType;
import org.eclipse.persistence.config.EntityManagerProperties;
import org.eclipse.persistence.config.ExclusiveConnectionMode;
import org.eclipse.persistence.config.FlushClearCache;
import org.eclipse.persistence.config.LoggerType;
import org.eclipse.persistence.config.PersistenceUnitProperties;
import org.eclipse.persistence.config.ReferenceMode;
import org.eclipse.persistence.config.TargetDatabase;
import org.eclipse.persistence.config.TargetServer;
import org.eclipse.persistence.descriptors.DescriptorQueryManager;
import org.eclipse.persistence.internal.localization.ExceptionLocalization;
import org.eclipse.persistence.internal.security.PrivilegedAccessHelper;
import org.eclipse.persistence.internal.security.PrivilegedGetSystemProperty;
import org.eclipse.persistence.logging.SessionLog;
import org.eclipse.persistence.queries.ObjectLevelReadQuery;
/**
*
* The class processes some of EclipseLink properties.
* The class may be used for any properties, but it only makes sense
* to use it in the following two cases:
* 1. There is a set of legal values defined
* either requiring translation (like CacheTypeProp);
* or not (like LoggingLevelProp).
* 2. Property is really a prefix from which the property obtained by
* appending entity or class name (like DescriptorCustomizerProp -
* it corresponds to "eclipselink.descriptor.customizer." prefix that allows to
* define properties like "eclipselink.descriptor.customizer.myPackage.MyClass").
*
* EclipseLink properties and their values defined in org.eclipse.persistence.config package.
*
* To add a new property:
* Define a new property in PersistenceUnitProperties;
* Add a class containing property's values if required to config package (like CacheType);
* Alternatively values may be already defined elsewhere (like in LoggingLevelProp).
* Add an inner class to this class extending Prop corresponding to the new property (like CacheTypeProp);
* The first constructor parameter is property name; the second is default value;
* In constructor
* provide 2-dimensional value array in case the values should be translated (like CacheTypeProp);
* in case translation is not required provide a single-dimension array (like LoggingLevelProp).
* In inner class Prop static initializer addProp an instance of the new prop class (like addProp(new CacheTypeProp())).
*
* @see PersistenceUnitProperties
* @see CacheType
* @see TargetDatabase
* @see TargetServer
*
* 05/28/2008-1.0M8 Andrei Ilitchev.
* - 224964: Provide support for Proxy Authentication through JPA.
* Added support for CONNECTION_EXCLUSIVE. Also added BooleanProp to allow simpler way of creating boolean-valued properties:
* instead of defining a new class for each new Boolean property just add a new instance of BooleanProp with property name and default:
* addProp(new BooleanProp(PersistenceUnitProperties.CONNECTION_EXCLUSIVE, "false"));
* Changed the existing boolean-valued properties to use this approach, also
* applied the same approach to LOGGING_LEVEL and CATEGORY_LOGGING_LEVEL_
* Also introduced a new version of getSessionPropertyValue that takes properties:
* public static String getSessionPropertyValue(String name, Map m, AbstractSession session) {
* it's convenient for use in EntityManagerImpl: first searches the passed properties then (recursively) properties of the session, then System properties.
*/
public class PropertiesHandler {
/**
* INTERNAL:
* Gets property value from the map, if none found looks in System properties.
* Use this to get a value for a non-prefixed property.
* Could be used on prefixes (like "org.eclipse.persistence.cache-type.") too,
* but will always return null
* Throws IllegalArgumentException in case the property value is illegal.
*/
public static String getPropertyValue(String name, Map m) {
return getPropertyValue(name, m, true);
}
public static String getPropertyValueLogDebug(String name, Map m, AbstractSession session) {
return getPropertyValueLogDebug(name, m, session, true);
}
public static String getPropertyValue(String name, Map m, boolean useSystemAsDefault) {
return Prop.getPropertyValueToApply(name, m, null, useSystemAsDefault);
}
public static String getPropertyValueLogDebug(String name, Map m, AbstractSession session, boolean useSystemAsDefault) {
return Prop.getPropertyValueToApply(name, m, session, useSystemAsDefault);
}
/**
* INTERNAL:
* Given property name and value verifies and translates the value.
* Throws IllegalArgumentException in case the property value is illegal.
*/
public static String getPropertyValue(String name, String value) {
return Prop.getPropertyValueToApply(name, value, null);
}
public static String getPropertyValueLogDebug(String name, String value, AbstractSession session) {
return Prop.getPropertyValueToApply(name, value, session);
}
/**
* INTERNAL:
* Gets property value from the map, if none found looks in System properties.
* Use this to get a value for a prefixed property:
* for "org.eclipse.persistence.cache-type.Employee"
* pass "org.eclipse.persistence.cache-type.", "Employee".
* Throws IllegalArgumentException in case the property value is illegal.
*/
public static String getPrefixedPropertyValue(String prefix, String suffix, Map m) {
return (String)getPrefixValues(prefix, m).get(suffix);
}
/**
* INTERNAL:
* Gets properties' values from the map, if none found looks in System properties.
* In the returned map values keyed by suffixes.
* Use it with prefixes (like "org.eclipse.persistence.cache-type.").
* Could be used on simple properties (not prefixes, too),
* but will always return either an empty map or a map containing a single
* value keyed by an empty String.
* Throws IllegalArgumentException in case the property value is illegal.
*/
public static Map getPrefixValues(String prefix, Map m) {
return Prop.getPrefixValuesToApply(prefix, m, null, true);
}
public static Map getPrefixValuesLogDebug(String prefix, Map m, AbstractSession session) {
return Prop.getPrefixValuesToApply(prefix, m, session, true);
}
/**
* INTERNAL:
* Returns the default property value that should be applied.
* Throws IllegalArgumentException in case the name doesn't correspond
* to any property.
*/
public static String getDefaultPropertyValue(String name) {
return Prop.getDefaultPropertyValueToApply(name, null);
}
public static String getDefaultPropertyValueLogDebug(String name, AbstractSession session) {
return Prop.getDefaultPropertyValueToApply(name, session);
}
/**
* INTERNAL:
* Empty String value indicates that the default property value should be used.
*/
protected static boolean shouldUseDefault(String value) {
return value != null && value.length() == 0;
}
protected static abstract class Prop {
static HashMap mainMap = new HashMap();
Object[] valueArray;
HashMap valueMap;
String name;
String defaultValue;
String defaultValueToApply;
boolean valueToApplyMayBeNull;
boolean shouldReturnOriginalValueIfValueToApplyNotFound;
static {
addProp(new LoggerTypeProp());
addProp(new LoggingLevelProp(PersistenceUnitProperties.LOGGING_LEVEL, Level.INFO.getName()));
addProp(new LoggingLevelProp(PersistenceUnitProperties.CATEGORY_LOGGING_LEVEL_, Level.INFO.getName()));
addProp(new TargetDatabaseProp());
addProp(new TargetServerProp());
addProp(new JTACntrlrProp());
addProp(new CacheSizeProp());
addProp(new CacheTypeProp());
addProp(new BooleanProp(PersistenceUnitProperties.CACHE_SHARED_, "false"));
addProp(new DescriptorCustomizerProp());
addProp(new BatchWritingProp());
addProp(new FlushClearCacheProp());
addProp(new ReferenceModeProp());
addProp(new FlushModeProp());
addProp(new BooleanProp(PersistenceUnitProperties.PERSISTENCE_CONTEXT_CLOSE_ON_COMMIT, "false"));
addProp(new BooleanProp(PersistenceUnitProperties.PERSISTENCE_CONTEXT_PERSIST_ON_COMMIT, "true"));
addProp(new BooleanProp(PersistenceUnitProperties.PERSISTENCE_CONTEXT_COMMIT_WITHOUT_PERSIST_RULES, "false"));
addProp(new BooleanProp(PersistenceUnitProperties.VALIDATE_EXISTENCE, "false"));
addProp(new BooleanProp(PersistenceUnitProperties.ORDER_UPDATES, "true"));
addProp(new CommitOrderProp());
addProp(new BooleanProp(PersistenceUnitProperties.JOIN_EXISTING_TRANSACTION, "false"));
addProp(new BooleanProp(PersistenceUnitProperties.COMPOSITE_UNIT, "false"));
addProp(new BooleanProp(PersistenceUnitProperties.COMPOSITE_UNIT_MEMBER, "false"));
addProp(new ExclusiveConnectionModeProp());
addProp(new BooleanProp(PersistenceUnitProperties.EXCLUSIVE_CONNECTION_IS_LAZY, "true"));
addProp(new IdValidationProp());
addProp(new ConnectionPoolProp());
addProp(new BooleanProp(PersistenceUnitProperties.JDBC_RESULT_SET_ACCESS_OPTIMIZATION, Boolean.toString(ObjectLevelReadQuery.isResultSetAccessOptimizedQueryDefault)));
addProp(new BooleanProp(PersistenceUnitProperties.JPQL_TOLERATE, "false"));
addProp(new BooleanProp(PersistenceUnitProperties.MULTITENANT_SHARED_CACHE, "false"));
addProp(new BooleanProp(PersistenceUnitProperties.MULTITENANT_SHARED_EMF, "true"));
//Enhancement
addProp(new QueryTimeoutUnitProp());
addProp(new PessimisticLockTimeoutUnitProp());
addProp(new BooleanProp(PersistenceUnitProperties.USE_LOCAL_TIMESTAMP, "false"));
addProp(new BooleanProp(PersistenceUnitProperties.SQL_CALL_DEFERRAL, "true"));
addProp(new BooleanProp(PersistenceUnitProperties.NAMING_INTO_INDEXED, "false"));
}
Prop(String name) {
this.name = name;
}
Prop(String name, String defaultValue) {
this(name);
this.defaultValue = defaultValue;
}
static String getPropertyValueFromMap(String name, Map m, boolean useSystemAsDefault) {
String value = (String)m.get(name);
if (value == null && useSystemAsDefault) {
if (PrivilegedAccessHelper.shouldUsePrivilegedAccess()) {
value = AccessController.doPrivileged(new PrivilegedGetSystemProperty(name));
} else {
value = System.getProperty(name);
}
}
return value;
}
// Collect all entries corresponding to the prefix name.
// Note that entries from Map m override those from System properties.
static Map getPrefixValuesFromMap(String name, Map m, boolean useSystemAsDefault) {
Map mapOut = new HashMap();
if(useSystemAsDefault) {
Map.Entry[] entries = (Map.Entry[]) AccessController.doPrivileged(new PrivilegedAction() {
@Override
public Object run() {
return System.getProperties().entrySet().toArray(new Map.Entry[] {});
}
}
);
for (Map.Entry entry:entries) {
String str = (String)entry.getKey();
if(str.startsWith(name)) {
String entityName = str.substring(name.length(), str.length());
mapOut.put(entityName, entry.getValue());
}
}
}
Iterator it = m.entrySet().iterator();
while(it.hasNext()) {
Map.Entry entry = (Map.Entry)it.next();
String str = (String)entry.getKey();
if(str.startsWith(name)) {
String entityName = str.substring(name.length(), str.length());
mapOut.put(entityName, entry.getValue());
}
}
return mapOut;
}
static String getPropertyValue(String name, boolean shouldUseDefault, Map m, AbstractSession session, boolean useSystemAsDefault) {
Prop prop = (Prop)mainMap.get(name);
if(prop == null) {
// it's not our property
return null;
}
String value = getPropertyValueFromMap(name, m, useSystemAsDefault);
if(value == null) {
return null;
}
return prop.getValueToApply(value, shouldUseDefault, session);
}
static String getPropertyValueToApply(String name, Map m, AbstractSession session, boolean useSystemAsDefault) {
Prop prop = (Prop)mainMap.get(name);
if(prop == null) {
throw new IllegalArgumentException(name);
}
String value = getPropertyValueFromMap(name, m, useSystemAsDefault);
if(value == null) {
return null;
}
return prop.getValueToApply(value, shouldUseDefault(value), session);
}
static String getPropertyValueToApply(String name, String value, AbstractSession session) {
Prop prop = (Prop)mainMap.get(name);
if(prop == null) {
throw new IllegalArgumentException(name);
}
return prop.getValueToApply(value, shouldUseDefault(value), session);
}
static Map getPrefixValuesToApply(String prefix, Map m, AbstractSession session, boolean useSystemAsDefault) {
Prop prop = (Prop)mainMap.get(prefix);
// maps suffixes to property values
Map mapIn = getPrefixValuesFromMap(prefix, m, useSystemAsDefault);
if(mapIn.isEmpty()) {
return mapIn;
}
HashMap mapOut = new HashMap(mapIn.size());
Iterator it = mapIn.entrySet().iterator();
while(it.hasNext()) {
Map.Entry entry = (Map.Entry)it.next();
String suffix = (String)entry.getKey();
Object value = entry.getValue();
if ((prop != null) && (value instanceof String)) {
value = prop.getValueToApply((String)value, shouldUseDefault((String)value), suffix, session);
}
mapOut.put(suffix, value);
}
// maps suffixes to valuesToApply
return mapOut;
}
static String getDefaultPropertyValueToApply(String name, AbstractSession session) {
Prop prop = (Prop)mainMap.get(name);
if(prop == null) {
throw new IllegalArgumentException(ExceptionLocalization.buildMessage("ejb30-default-for-unknown-property", new Object[]{name}));
}
prop.logDefault(session);
return prop.defaultValueToApply;
}
String getValueToApply(String value, boolean shouldUseDefault, AbstractSession session) {
return getValueToApply(value, shouldUseDefault, null, session);
}
// suffix is used only for properties-prefixes (like CacheType)
String getValueToApply(String value, boolean shouldUseDefault, String suffix, AbstractSession session) {
if(shouldUseDefault) {
logDefault(session, suffix);
return defaultValueToApply;
}
String valueToApply = value;
if(valueMap != null) {
String key = getUpperCaseString(value);
valueToApply = (String)valueMap.get(key);
if(valueToApply == null) {
boolean notFound = true;
if(valueToApplyMayBeNull) {
notFound = !valueMap.containsKey(key);
}
if(notFound) {
if(shouldReturnOriginalValueIfValueToApplyNotFound) {
valueToApply = value;
} else {
String propertyName = name;
if(suffix != null) {
propertyName = propertyName + suffix;
}
throw new IllegalArgumentException(ExceptionLocalization.buildMessage("ejb30-illegal-property-value", new Object[]{propertyName, getPrintValue(value)}));
}
}
}
}
String logValue = PersistenceUnitProperties.getOverriddenLogStringForProperty(name);
if (logValue != null){
log(session, logValue, logValue, suffix);
} else {
log(session, value, valueToApply, suffix);
}
return valueToApply;
}
static String getUpperCaseString(String value) {
if(value != null) {
return value.toUpperCase();
} else {
return null;
}
}
static String getPrintValue(String value) {
if(value != null) {
return value;
} else {
return "null";
}
}
void initialize() {
if(valueArray != null) {
valueMap = new HashMap(valueArray.length);
if(valueArray instanceof Object[][]) {
Object[][] valueArray2 = (Object[][])valueArray;
for(int i=0; i