| /* |
| * Copyright (c) 1998, 2021 Oracle and/or its affiliates. All rights reserved. |
| * Copyright (c) 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 |
| // 12/24/2012-2.5 Guy Pelletier |
| // - 389090: JPA 2.1 DDL Generation Support |
| // 01/08/2013-2.5 Guy Pelletier |
| // - 389090: JPA 2.1 DDL Generation Support |
| // 01/11/2013-2.5 Guy Pelletier |
| // - 389090: JPA 2.1 DDL Generation Support |
| // 01/16/2013-2.5 Guy Pelletier |
| // - 389090: JPA 2.1 DDL Generation Support |
| // 01/24/2013-2.5 Guy Pelletier |
| // - 389090: JPA 2.1 DDL Generation Support |
| // 02/04/2013-2.5 Guy Pelletier |
| // - 389090: JPA 2.1 DDL Generation Support |
| // 02/19/2013-2.5 Guy Pelletier |
| // - 389090: JPA 2.1 DDL Generation Support |
| // 05/06/2015-2.7 Tomas Kraus |
| // - Added partition isolation for persistence units. |
| package org.eclipse.persistence.internal.jpa; |
| |
| import java.security.AccessController; |
| import java.util.Collection; |
| import java.util.HashMap; |
| import java.util.Iterator; |
| import java.util.Map; |
| |
| import org.eclipse.persistence.config.PersistenceUnitProperties; |
| import org.eclipse.persistence.config.TargetDatabase; |
| import org.eclipse.persistence.internal.jpa.EntityManagerSetupImpl.TableCreationType; |
| import org.eclipse.persistence.internal.security.PrivilegedAccessHelper; |
| import org.eclipse.persistence.internal.security.PrivilegedGetSystemProperty; |
| import org.eclipse.persistence.internal.sessions.AbstractSession; |
| import org.eclipse.persistence.internal.sessions.DatabaseSessionImpl; |
| import org.eclipse.persistence.logging.SessionLog; |
| import org.eclipse.persistence.tools.schemaframework.SchemaManager; |
| |
| /** |
| * This is a helper/impl class for the EclipseLink EJB 3.0 provider |
| * The default constructor can be used to build the provider by reflection, after which it can |
| * be used to create EntityManagerFactories |
| */ |
| public class EntityManagerFactoryProvider { |
| |
| public static final Map<String, EntityManagerSetupImpl> emSetupImpls = IsolatedHashMap.newMap(); |
| |
| // TEMPORARY - WILL BE REMOVED. |
| // Used to warn users about deprecated property name and suggest the valid name. |
| // TEMPORARY the old property names will be translated to the new ones and processed. |
| protected static final String oldPropertyNames[][] = { |
| {PersistenceUnitProperties.CONNECTION_POOL_MAX, "eclipselink.max-write-connections"}, |
| {PersistenceUnitProperties.CONNECTION_POOL_MIN, "eclipselink.min-write-connections"}, |
| {PersistenceUnitProperties.CONNECTION_POOL_MAX, "eclipselink.max-read-connections"}, |
| {PersistenceUnitProperties.CONNECTION_POOL_MIN, "eclipselink.min-read-connections"}, |
| {PersistenceUnitProperties.CONNECTION_POOL_MAX, "eclipselink.connections.max"}, |
| {PersistenceUnitProperties.CONNECTION_POOL_MIN, "eclipselink.connections.min"}, |
| {PersistenceUnitProperties.CONNECTION_POOL_INITIAL, "eclipselink.connections.initial"}, |
| {PersistenceUnitProperties.CONNECTION_POOL_WAIT, "eclipselink.connections.wait"}, |
| {PersistenceUnitProperties.CONNECTION_POOL_MAX, "eclipselink.write-connections.max"}, |
| {PersistenceUnitProperties.CONNECTION_POOL_MIN, "eclipselink.write-connections.min"}, |
| {PersistenceUnitProperties.CONNECTION_POOL_INITIAL, "eclipselink.write-connections.initial"}, |
| {PersistenceUnitProperties.CONNECTION_POOL_MAX, "eclipselink.read-connections.max"}, |
| {PersistenceUnitProperties.CONNECTION_POOL_MIN, "eclipselink.read-connections.min"}, |
| {PersistenceUnitProperties.CONNECTION_POOL_SHARED, "eclipselink.read-connections.shared"}, |
| {PersistenceUnitProperties.CONNECTION_POOL_INITIAL, "eclipselink.read-connections.initial"}, |
| {PersistenceUnitProperties.JDBC_BIND_PARAMETERS, "eclipselink.bind-all-parameters"}, |
| {PersistenceUnitProperties.TARGET_DATABASE, "eclipselink.platform.class.name"}, |
| {PersistenceUnitProperties.TARGET_SERVER, "eclipselink.server.platform.class.name"}, |
| {PersistenceUnitProperties.CACHE_SIZE_DEFAULT, "eclipselink.cache.default-size"}, |
| {PersistenceUnitProperties.JDBC_USER , "eclipselink.jdbc.user"}, |
| {PersistenceUnitProperties.JDBC_DRIVER ,"eclipselink.jdbc.driver"}, |
| {PersistenceUnitProperties.JDBC_URL , "eclipselink.jdbc.url"}, |
| {PersistenceUnitProperties.JDBC_PASSWORD , "eclipselink.jdbc.password"}, |
| {PersistenceUnitProperties.WEAVING , "persistence.tools.weaving"}, |
| {PersistenceUnitProperties.LOGGING_LEVEL + "." + SessionLog.METAMODEL, PersistenceUnitProperties.LOGGING_LEVEL + ".jpa_" + SessionLog.METAMODEL}, |
| {PersistenceUnitProperties.LOGGING_LEVEL + "." + SessionLog.METADATA, PersistenceUnitProperties.LOGGING_LEVEL + ".ejb_or_" + SessionLog.METADATA} |
| }; |
| |
| /** |
| * Default constructor to allow reflection. |
| */ |
| public EntityManagerFactoryProvider() { |
| } |
| |
| /** |
| * Add an EntityManagerSetupImpl to the cached list |
| * These are used to ensure all persistence units that are the same get the same underlying session |
| */ |
| public static void addEntityManagerSetupImpl(String name, EntityManagerSetupImpl setup){ |
| synchronized (EntityManagerFactoryProvider.emSetupImpls) { |
| if (name == null){ |
| EntityManagerFactoryProvider.emSetupImpls.put("", setup); |
| } |
| EntityManagerFactoryProvider.emSetupImpls.put(name, setup); |
| } |
| } |
| |
| /** |
| * Calls the appropriate create,replace or alter SchemaManager api. |
| * @param ddlType - ddl operation to be performed |
| */ |
| protected static void generateDefaultTables(SchemaManager mgr, TableCreationType ddlType) { |
| if (ddlType == null || ddlType == TableCreationType.CREATE) { |
| mgr.createDefaultTables(true); |
| } else if (ddlType == TableCreationType.DROP) { |
| mgr.dropDefaultTables(); |
| } else if (ddlType == TableCreationType.DROP_AND_CREATE) { |
| mgr.replaceDefaultTables(true, false, true); |
| } else if (ddlType == TableCreationType.EXTEND) { |
| mgr.extendDefaultTables(true); |
| } |
| } |
| |
| /** |
| * Get configuration {@link System} property indicated by the specified {@code propertyKey}. |
| * Property value may be overridden by {@code overrides} {@link Map}. |
| * @param propertyKey The name of the configuration {@link System} property. |
| * @param overrides {@link Map} with property overrides. |
| * @return The {@link String} value of the property from {@code overrides} {@link Map} or value of configuration |
| * {@link System} property or {@code null} if property identified by {@code propertyKey} does not exist. |
| */ |
| public static String getConfigPropertyAsString(final String propertyKey, final Map overrides) { |
| final String value = overrides != null ? (String)overrides.get(propertyKey) : null; |
| return value != null ? value : PrivilegedAccessHelper.getSystemProperty(propertyKey); |
| } |
| |
| /** |
| * Check the provided map for an object with the given key. If that object is not available, check the |
| * System properties. If it is not available from either location, return the default value. |
| */ |
| public static String getConfigPropertyAsString(String propertyKey, Map overrides, String defaultValue){ |
| String value = getConfigPropertyAsString(propertyKey, overrides); |
| if (value == null){ |
| value = defaultValue; |
| } |
| return value; |
| } |
| |
| protected static String getConfigPropertyAsStringLogDebug(String propertyKey, Map overrides, AbstractSession session) { |
| return (String)getConfigPropertyLogDebug(propertyKey, overrides, session); |
| } |
| |
| protected static String getConfigPropertyAsStringLogDebug(String propertyKey, Map overrides, AbstractSession session, boolean useSystemAsDefault) { |
| return (String)getConfigPropertyLogDebug(propertyKey, overrides, session, useSystemAsDefault); |
| } |
| |
| protected static String getConfigPropertyAsStringLogDebug(String propertyKey, Map overrides, String defaultValue, AbstractSession session){ |
| String value = getConfigPropertyAsStringLogDebug(propertyKey, overrides, session); |
| if (value == null){ |
| value = defaultValue; |
| session.log(SessionLog.FINEST, SessionLog.PROPERTIES, "property_value_default", new Object[]{propertyKey, value}); |
| } |
| return value; |
| } |
| |
| protected static Object getConfigPropertyLogDebug(String propertyKey, Map overrides, AbstractSession session){ |
| return getConfigPropertyLogDebug(propertyKey, overrides, session, true); |
| } |
| |
| protected static Object getConfigPropertyLogDebug(String propertyKey, Map overrides, AbstractSession session, boolean useSystemAsDefault){ |
| Object value = null; |
| if (overrides != null){ |
| value = overrides.get(propertyKey); |
| } |
| if ((value == null) && useSystemAsDefault){ |
| if (PrivilegedAccessHelper.shouldUsePrivilegedAccess()) { |
| value = AccessController.doPrivileged(new PrivilegedGetSystemProperty(propertyKey)); |
| } else { |
| value = System.getProperty(propertyKey); |
| } |
| } |
| if ((value != null) && (session != null)) { |
| if (session.shouldLog(SessionLog.FINEST, SessionLog.PROPERTIES)) { |
| String overrideValue = PersistenceUnitProperties.getOverriddenLogStringForProperty(propertyKey);; |
| Object logValue = (overrideValue == null) ? value : overrideValue; |
| session.log(SessionLog.FINEST, SessionLog.PROPERTIES, "property_value_specified", new Object[]{propertyKey, logValue}); |
| } |
| } |
| |
| return value; |
| } |
| |
| public static boolean hasConfigProperty(String propertyKey, Map overrides) { |
| return getConfigProperty(propertyKey, overrides) != null; |
| } |
| |
| protected static Object getConfigProperty(String propertyKey, Map overrides){ |
| return getConfigProperty(propertyKey, overrides, true); |
| } |
| |
| protected static Object getConfigProperty(String propertyKey, Map overrides, boolean useSystemAsDefault){ |
| Object value = null; |
| if (overrides != null){ |
| value = overrides.get(propertyKey); |
| } |
| if ((value == null) && useSystemAsDefault){ |
| if (PrivilegedAccessHelper.shouldUsePrivilegedAccess()) { |
| value = AccessController.doPrivileged(new PrivilegedGetSystemProperty(propertyKey)); |
| } else { |
| value = System.getProperty(propertyKey); |
| } |
| } |
| |
| return value; |
| } |
| |
| protected static Object getConfigProperty(String propertyKey, Map overrides, Object defaultObj){ |
| Object obj = getConfigProperty(propertyKey, overrides); |
| return (obj == null) ? defaultObj : obj; |
| } |
| |
| /** |
| * Return the setup class for a given entity manager name |
| */ |
| public static EntityManagerSetupImpl getEntityManagerSetupImpl(String emName) { |
| synchronized (EntityManagerFactoryProvider.emSetupImpls){ |
| if (emName == null){ |
| return EntityManagerFactoryProvider.emSetupImpls.get(""); |
| } |
| return EntityManagerFactoryProvider.emSetupImpls.get(emName); |
| } |
| } |
| |
| public static Map<String, EntityManagerSetupImpl> getEmSetupImpls(){ |
| return emSetupImpls; |
| } |
| |
| /** |
| * Logs in to given session. If user has not specified <code>TARGET_DATABASE</code> |
| * the platform would be auto detected |
| * @param session The session to login to. |
| * @param properties User specified properties for the persistence unit |
| */ |
| protected static void login(DatabaseSessionImpl session, Map properties, boolean requiresConnection) { |
| String databaseGenerationAction = getConfigPropertyAsString(PersistenceUnitProperties.SCHEMA_GENERATION_DATABASE_ACTION, properties); |
| |
| // Avoid an actual connection if we don't need one. If the user provides |
| // us with a user name and password we will connect. At minimum if they |
| // provide the platform we'll generate the DDL as if we had connected. |
| if ((databaseGenerationAction == null || databaseGenerationAction.equals(PersistenceUnitProperties.SCHEMA_GENERATION_NONE_ACTION)) && ! requiresConnection) { |
| session.setDatasourceAndInitialize(); |
| } else { |
| String eclipselinkPlatform = (String)properties.get(PersistenceUnitProperties.TARGET_DATABASE); |
| if (eclipselinkPlatform == null || eclipselinkPlatform.equals(TargetDatabase.Auto) || session.isBroker()) { |
| // if user has not specified a database platform, try to detect. |
| // Will also look for jpa 2.1 schema properties. |
| session.loginAndDetectDatasource(); |
| } else { |
| session.login(); |
| } |
| } |
| } |
| |
| /** |
| * Merge the properties from the source object into the target object. If the property |
| * exists in both objects, use the one from the target |
| * @return the target object |
| */ |
| public static <K, V> Map<K, V> mergeMaps(Map<K, V> target, Map<K, V> source){ |
| Map<K, V> map = new HashMap<>(); |
| if (source != null){ |
| map.putAll(source); |
| } |
| |
| if (target != null){ |
| map.putAll(target); |
| } |
| return map; |
| } |
| |
| /** |
| * Copies source into target, removes from target all keysToBeRemoved. |
| * @return the target object |
| */ |
| public static <K, V> Map<K, V> removeSpecifiedProperties(Map<K, V> source, Collection<K> keysToBeRemoved){ |
| Map<K, V> target = new HashMap<>(); |
| if (source != null){ |
| target.putAll(source); |
| Iterator<K> it = keysToBeRemoved.iterator(); |
| while(it.hasNext()) { |
| target.remove(it.next()); |
| } |
| } |
| return target; |
| } |
| |
| /** |
| * target contains the entries from source with keysToBeKept. |
| * @return the target object |
| */ |
| public static <K, V> Map<K, V> keepSpecifiedProperties(Map<K, V> source, Collection<K> keysToBeKept){ |
| Map<K, V> target = new HashMap<>(); |
| if (source != null){ |
| target.putAll(source); |
| Iterator<Map.Entry<K, V>> it = source.entrySet().iterator(); |
| while(it.hasNext()) { |
| Map.Entry<K, V> entry = it.next(); |
| if(keysToBeKept.contains(entry.getKey())) { |
| target.put(entry.getKey(), entry.getValue()); |
| } |
| } |
| } |
| return target; |
| } |
| |
| /** |
| * target is a array of two Maps |
| * the first one contains specified properties; |
| * the second all the rest. |
| * @return the target object |
| */ |
| public static <K, V> Map<K, V>[] splitSpecifiedProperties(Map<K, V> source, Collection<K> keysToBeKept){ |
| HashMap<K, V> in = new HashMap<>(); |
| HashMap<K, V> out = new HashMap<>(); |
| Map[] target = new Map[]{in, out}; |
| if (source != null){ |
| Iterator<Map.Entry<K, V>> it = source.entrySet().iterator(); |
| while(it.hasNext()) { |
| Map.Entry<K, V> entry = it.next(); |
| if(keysToBeKept.contains(entry.getKey())) { |
| in.put(entry.getKey(), entry.getValue()); |
| } else { |
| out.put(entry.getKey(), entry.getValue()); |
| } |
| } |
| } |
| return target; |
| } |
| |
| /** |
| * Source Map is divided between Map[] in target. |
| * Target's i-th member contains all source's Map.Entries |
| * keys for which are in keys[i] Collection. |
| * Target's size equals keys' size + 1: |
| * all the source's Map.Entries not found in any of keys Collections |
| * go into the last target's map. |
| * @param keys is array of Maps of size n |
| * @return the target object is array of Maps of size n+1 |
| */ |
| public static <K, V> Map<K, V>[] splitProperties(Map<K, V> source, Collection<K>[] keys){ |
| @SuppressWarnings({"unchecked"}) |
| Map<K, V>[] target = (Map<K, V>[]) new Map[keys.length + 1]; |
| for (int i=0; i <= keys.length; i++) { |
| target[i] = new HashMap<>(); |
| } |
| if (source != null){ |
| Iterator<Map.Entry<K, V>> it = source.entrySet().iterator(); |
| while(it.hasNext()) { |
| Map.Entry<K, V> entry = it.next(); |
| boolean isFound = false; |
| for (int i=0; i < keys.length && !isFound; i++) { |
| if (keys[i].contains(entry.getKey())) { |
| isFound = true; |
| target[i].put(entry.getKey(), entry.getValue()); |
| } |
| } |
| if (!isFound) { |
| target[keys.length].put(entry.getKey(), entry.getValue()); |
| } |
| } |
| } |
| return target; |
| } |
| |
| /** |
| * This is a TEMPORARY method that will be removed. |
| * DON'T USE THIS METHOD - for internal use only. |
| */ |
| protected static void translateOldProperties(Map m, AbstractSession session) { |
| for(int i=0; i < oldPropertyNames.length; i++) { |
| Object value = getConfigPropertyAsString(oldPropertyNames[i][1], m); |
| if(value != null) { |
| if(session != null){ |
| session.log(SessionLog.INFO, SessionLog.TRANSACTION, "deprecated_property", oldPropertyNames[i]); |
| } |
| m.put(oldPropertyNames[i][0], value); |
| } |
| } |
| } |
| |
| protected static void warnOldProperties(Map m, AbstractSession session) { |
| for(int i=0; i < oldPropertyNames.length; i++) { |
| Object value = m.get(oldPropertyNames[i][1]); |
| if(value != null) { |
| session.log(SessionLog.INFO, SessionLog.TRANSACTION, "deprecated_property", oldPropertyNames[i]); |
| } |
| } |
| } |
| } |