blob: d7390fdce321ba1c21c96b3aea7ea3937ae1177c [file] [log] [blame]
/*
* 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
//
// 05/28/2008-1.0M8 Andrei Ilitchev
// - 224964: Provide support for Proxy Authentication through JPA.
// Added updateConnectionPolicy method to support EXCLUSIVE_CONNECTION property.
// Some methods, like setSessionEventListener called from deploy still used predeploy properties,
// that meant it was impossible to set listener through createEMF property in SE case with an agent - fixed that.
// Also if creating / closing the same emSetupImpl many times (24 in my case) "java.lang.OutOfMemoryError: PermGen space" resulted:
// partially fixed partially worked around this - see a big comment in predeploy method.
// 12/23/2008-1.1M5 Michael O'Brien
// - 253701: add persistenceInitializationHelper field used by undeploy() to clear the JavaSECMPInitializer
// 10/14/2009-2.0 Michael O'Brien
// - 266912: add Metamodel instance field as part of the JPA 2.0 implementation
// 10/21/2009-2.0 Guy Pelletier
// - 290567: mappedbyid support incomplete
// cdelahun - Bug 214534: changes to allow JMSPublishingTransportManager configuration through properties
// 05/14/2010-2.1 Guy Pelletier
// - 253083: Add support for dynamic persistence using ORM.xml/eclipselink-orm.xml
// 04/01/2011-2.3 Guy Pelletier
// - 337323: Multi-tenant with shared schema support (part 2)
// 06/30/2011-2.3.1 Guy Pelletier
// - 341940: Add disable/enable allowing native queries
// 09/20/2011-2.3.1 Guy Pelletier
// - 357476: Change caching default to ISOLATED for multitenant's using a shared EMF.
// 08/01/2012-2.5 Chris Delahunt
// - 371950: Metadata caching
// 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
// 08/11/2014-2.5 Rick Curtis
// - 440594: Tolerate invalid NamedQuery at EntityManager creation.
// 11/20/2014-2.5 Rick Curtis
// - 452187: Support multiple ClassLoaders to load properties.
// 01/05/2015 Rick Curtis
// - 455683: Automatically detect target server
// 01/13/2015 - Rick Curtis
// - 438871 : Add support for writing statement terminator character(s) when generating ddl to script.
// 02/19/2015 - Rick Curtis
// - 458877 : Add national character support
// 03/04/2015 - Will Dazey
// - 460862 : Added support for JTA schema generation without JTA-DS
// 03/23/2015 - Rick Curtis
// - 462888 : SessionCustomizer instance based configuration
// 08/24/2015 - Dalia Abo Sheasha
// - 475285 : Create a generic application-id property to generate unique session names
// 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
// 11/05/2015 - Dalia Abo Sheasha
// - 480787 : Wrap several privileged method calls with a doPrivileged block
// 12/03/2015-2.6 Dalia Abo Sheasha
// - 483582: Add the jakarta.persistence.sharedCache.mode property
// 09/29/2016-2.7 Tomas Kraus
// - 426852: @GeneratedValue(strategy=GenerationType.IDENTITY) support in Oracle 12c
// 09/14/2017-2.6 Will Dazey
// - 522312: Add the eclipselink.sequencing.start-sequence-at-nextval property
// 10/24/2017-3.0 Tomas Kraus
// - 526419: Modify EclipseLink to reflect changes in JTA 1.1.
// 01/16/2018-2.7 Joe Grassel
// - 529907: EntityManagerSetupImpl.addBeanValidationListeners() should fall back on old method for finding helperClass
// 12/06/2018 - Will Dazey
// - 542491: Add new 'eclipselink.jdbc.force-bind-parameters' property to force enable binding
// 09/02/2019-3.0 Alexandre Jacob
// - 527415: Fix code when locale is tr, az or lt
package org.eclipse.persistence.internal.jpa;
import static org.eclipse.persistence.config.PersistenceUnitProperties.DDL_GENERATION;
import static org.eclipse.persistence.config.PersistenceUnitProperties.NONE;
import static org.eclipse.persistence.config.PersistenceUnitProperties.SCHEMA_GENERATION_CREATE_ACTION;
import static org.eclipse.persistence.config.PersistenceUnitProperties.SCHEMA_GENERATION_CREATE_DATABASE_SCHEMAS;
import static org.eclipse.persistence.config.PersistenceUnitProperties.SCHEMA_GENERATION_CREATE_SCRIPT_SOURCE;
import static org.eclipse.persistence.config.PersistenceUnitProperties.SCHEMA_GENERATION_CREATE_SOURCE;
import static org.eclipse.persistence.config.PersistenceUnitProperties.SCHEMA_GENERATION_DATABASE_ACTION;
import static org.eclipse.persistence.config.PersistenceUnitProperties.SCHEMA_GENERATION_DROP_ACTION;
import static org.eclipse.persistence.config.PersistenceUnitProperties.SCHEMA_GENERATION_DROP_AND_CREATE_ACTION;
import static org.eclipse.persistence.config.PersistenceUnitProperties.SCHEMA_GENERATION_DROP_SCRIPT_SOURCE;
import static org.eclipse.persistence.config.PersistenceUnitProperties.SCHEMA_GENERATION_DROP_SOURCE;
import static org.eclipse.persistence.config.PersistenceUnitProperties.SCHEMA_GENERATION_METADATA_SOURCE;
import static org.eclipse.persistence.config.PersistenceUnitProperties.SCHEMA_GENERATION_METADATA_THEN_SCRIPT_SOURCE;
import static org.eclipse.persistence.config.PersistenceUnitProperties.SCHEMA_GENERATION_NONE_ACTION;
import static org.eclipse.persistence.config.PersistenceUnitProperties.SCHEMA_GENERATION_SCRIPTS_ACTION;
import static org.eclipse.persistence.config.PersistenceUnitProperties.SCHEMA_GENERATION_SCRIPTS_CREATE_TARGET;
import static org.eclipse.persistence.config.PersistenceUnitProperties.SCHEMA_GENERATION_SCRIPTS_DROP_TARGET;
import static org.eclipse.persistence.config.PersistenceUnitProperties.SCHEMA_GENERATION_SCRIPT_SOURCE;
import static org.eclipse.persistence.config.PersistenceUnitProperties.SCHEMA_GENERATION_SCRIPT_THEN_METADATA_SOURCE;
import static org.eclipse.persistence.config.PersistenceUnitProperties.SCHEMA_GENERATION_SQL_LOAD_SCRIPT_SOURCE;
import static org.eclipse.persistence.internal.jpa.EntityManagerFactoryProvider.generateDefaultTables;
import static org.eclipse.persistence.internal.jpa.EntityManagerFactoryProvider.getConfigProperty;
import static org.eclipse.persistence.internal.jpa.EntityManagerFactoryProvider.getConfigPropertyAsString;
import static org.eclipse.persistence.internal.jpa.EntityManagerFactoryProvider.getConfigPropertyAsStringLogDebug;
import static org.eclipse.persistence.internal.jpa.EntityManagerFactoryProvider.getConfigPropertyLogDebug;
import static org.eclipse.persistence.internal.jpa.EntityManagerFactoryProvider.hasConfigProperty;
import static org.eclipse.persistence.internal.jpa.EntityManagerFactoryProvider.login;
import static org.eclipse.persistence.internal.jpa.EntityManagerFactoryProvider.mergeMaps;
import static org.eclipse.persistence.internal.jpa.EntityManagerFactoryProvider.translateOldProperties;
import static org.eclipse.persistence.internal.jpa.EntityManagerFactoryProvider.warnOldProperties;
import java.io.File;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Reader;
import java.io.UnsupportedEncodingException;
import java.io.Writer;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLDecoder;
import java.rmi.Naming;
import java.rmi.RemoteException;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.security.PrivilegedActionException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.StringTokenizer;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.TimeUnit;
import jakarta.persistence.OptimisticLockException;
import jakarta.persistence.PersistenceException;
import jakarta.persistence.SharedCacheMode;
import jakarta.persistence.ValidationMode;
import jakarta.persistence.metamodel.Attribute;
import jakarta.persistence.metamodel.CollectionAttribute;
import jakarta.persistence.metamodel.ListAttribute;
import jakarta.persistence.metamodel.ManagedType;
import jakarta.persistence.metamodel.MapAttribute;
import jakarta.persistence.metamodel.Metamodel;
import jakarta.persistence.metamodel.SetAttribute;
import jakarta.persistence.metamodel.SingularAttribute;
import jakarta.persistence.spi.ClassTransformer;
import jakarta.persistence.spi.PersistenceUnitInfo;
import jakarta.persistence.spi.PersistenceUnitTransactionType;
import org.eclipse.persistence.annotations.IdValidation;
import org.eclipse.persistence.config.BatchWriting;
import org.eclipse.persistence.config.CacheCoordinationProtocol;
import org.eclipse.persistence.config.CacheIsolationType;
import org.eclipse.persistence.config.DescriptorCustomizer;
import org.eclipse.persistence.config.ExclusiveConnectionMode;
import org.eclipse.persistence.config.LoggerType;
import org.eclipse.persistence.config.ParserType;
import org.eclipse.persistence.config.PersistenceUnitProperties;
import org.eclipse.persistence.config.ProfilerType;
import org.eclipse.persistence.config.PropertiesUtils;
import org.eclipse.persistence.config.RemoteProtocol;
import org.eclipse.persistence.config.SessionCustomizer;
import org.eclipse.persistence.descriptors.ClassDescriptor;
import org.eclipse.persistence.descriptors.MultitenantPolicy;
import org.eclipse.persistence.descriptors.SchemaPerMultitenantPolicy;
import org.eclipse.persistence.descriptors.TimestampLockingPolicy;
import org.eclipse.persistence.descriptors.partitioning.PartitioningPolicy;
import org.eclipse.persistence.dynamic.DynamicClassLoader;
import org.eclipse.persistence.eis.EISConnectionSpec;
import org.eclipse.persistence.eis.EISLogin;
import org.eclipse.persistence.eis.EISPlatform;
import org.eclipse.persistence.exceptions.ConversionException;
import org.eclipse.persistence.exceptions.DatabaseException;
import org.eclipse.persistence.exceptions.DescriptorException;
import org.eclipse.persistence.exceptions.EclipseLinkException;
import org.eclipse.persistence.exceptions.EntityManagerSetupException;
import org.eclipse.persistence.exceptions.ExceptionHandler;
import org.eclipse.persistence.exceptions.IntegrityException;
import org.eclipse.persistence.exceptions.PersistenceUnitLoadingException;
import org.eclipse.persistence.exceptions.ValidationException;
import org.eclipse.persistence.internal.databaseaccess.BatchWritingMechanism;
import org.eclipse.persistence.internal.databaseaccess.DatabaseAccessor;
import org.eclipse.persistence.internal.databaseaccess.DatasourcePlatform;
import org.eclipse.persistence.internal.databaseaccess.Platform;
import org.eclipse.persistence.internal.descriptors.OptimisticLockingPolicy;
import org.eclipse.persistence.internal.descriptors.OptimisticLockingPolicy.LockOnChange;
import org.eclipse.persistence.internal.helper.ClassConstants;
import org.eclipse.persistence.internal.helper.ConcurrencyManager;
import org.eclipse.persistence.internal.helper.ConcurrencyUtil;
import org.eclipse.persistence.internal.helper.Helper;
import org.eclipse.persistence.internal.helper.JPAClassLoaderHolder;
import org.eclipse.persistence.internal.helper.JPAConversionManager;
import org.eclipse.persistence.internal.jpa.deployment.BeanValidationInitializationHelper;
import org.eclipse.persistence.internal.jpa.deployment.PersistenceUnitProcessor;
import org.eclipse.persistence.internal.jpa.deployment.SEPersistenceUnitInfo;
import org.eclipse.persistence.internal.jpa.jdbc.DataSourceImpl;
import org.eclipse.persistence.internal.jpa.metadata.MetadataHelper;
import org.eclipse.persistence.internal.jpa.metadata.MetadataLogger;
import org.eclipse.persistence.internal.jpa.metadata.MetadataProcessor;
import org.eclipse.persistence.internal.jpa.metadata.MetadataProject;
import org.eclipse.persistence.internal.jpa.metadata.accessors.objects.MetadataAsmFactory;
import org.eclipse.persistence.internal.jpa.metadata.accessors.objects.MetadataClass;
import org.eclipse.persistence.internal.jpa.metadata.xml.XMLEntityMappingsReader;
import org.eclipse.persistence.internal.jpa.metamodel.ManagedTypeImpl;
import org.eclipse.persistence.internal.jpa.metamodel.MetamodelImpl;
import org.eclipse.persistence.internal.jpa.metamodel.proxy.AttributeProxyImpl;
import org.eclipse.persistence.internal.jpa.metamodel.proxy.CollectionAttributeProxyImpl;
import org.eclipse.persistence.internal.jpa.metamodel.proxy.ListAttributeProxyImpl;
import org.eclipse.persistence.internal.jpa.metamodel.proxy.MapAttributeProxyImpl;
import org.eclipse.persistence.internal.jpa.metamodel.proxy.SetAttributeProxyImpl;
import org.eclipse.persistence.internal.jpa.metamodel.proxy.SingularAttributeProxyImpl;
import org.eclipse.persistence.internal.jpa.weaving.ClassDetails;
import org.eclipse.persistence.internal.jpa.weaving.PersistenceWeaver;
import org.eclipse.persistence.internal.jpa.weaving.TransformerFactory;
import org.eclipse.persistence.internal.localization.ExceptionLocalization;
import org.eclipse.persistence.internal.localization.LoggingLocalization;
import org.eclipse.persistence.internal.security.PrivilegedAccessHelper;
import org.eclipse.persistence.internal.security.PrivilegedClassForName;
import org.eclipse.persistence.internal.security.PrivilegedGetDeclaredField;
import org.eclipse.persistence.internal.security.PrivilegedGetDeclaredFields;
import org.eclipse.persistence.internal.security.PrivilegedGetDeclaredMethod;
import org.eclipse.persistence.internal.security.PrivilegedGetValueFromField;
import org.eclipse.persistence.internal.security.PrivilegedMethodInvoker;
import org.eclipse.persistence.internal.security.PrivilegedNewInstanceFromClass;
import org.eclipse.persistence.internal.security.SecurableObjectHolder;
import org.eclipse.persistence.internal.sessions.AbstractSession;
import org.eclipse.persistence.internal.sessions.DatabaseSessionImpl;
import org.eclipse.persistence.internal.sessions.PropertiesHandler;
import org.eclipse.persistence.internal.sessions.remote.RemoteConnection;
import org.eclipse.persistence.jpa.metadata.FileBasedProjectCache;
import org.eclipse.persistence.jpa.metadata.MetadataSource;
import org.eclipse.persistence.jpa.metadata.ProjectCache;
import org.eclipse.persistence.jpa.metadata.XMLMetadataSource;
import org.eclipse.persistence.logging.AbstractSessionLog;
import org.eclipse.persistence.logging.SessionLog;
import org.eclipse.persistence.platform.database.converters.StructConverter;
import org.eclipse.persistence.platform.database.events.DatabaseEventListener;
import org.eclipse.persistence.platform.database.partitioning.DataPartitioningCallback;
import org.eclipse.persistence.platform.server.CustomServerPlatform;
import org.eclipse.persistence.platform.server.ServerPlatform;
import org.eclipse.persistence.platform.server.ServerPlatformBase;
import org.eclipse.persistence.platform.server.ServerPlatformUtils;
import org.eclipse.persistence.queries.QueryResultsCachePolicy;
import org.eclipse.persistence.sequencing.Sequence;
import org.eclipse.persistence.sessions.Connector;
import org.eclipse.persistence.sessions.DatabaseLogin;
import org.eclipse.persistence.sessions.DatasourceLogin;
import org.eclipse.persistence.sessions.DefaultConnector;
import org.eclipse.persistence.sessions.ExternalTransactionController;
import org.eclipse.persistence.sessions.JNDIConnector;
import org.eclipse.persistence.sessions.Project;
import org.eclipse.persistence.sessions.Session;
import org.eclipse.persistence.sessions.SessionEventListener;
import org.eclipse.persistence.sessions.SessionProfiler;
import org.eclipse.persistence.sessions.broker.SessionBroker;
import org.eclipse.persistence.sessions.coordination.MetadataRefreshListener;
import org.eclipse.persistence.sessions.coordination.RemoteCommandManager;
import org.eclipse.persistence.sessions.coordination.TransportManager;
import org.eclipse.persistence.sessions.coordination.jms.JMSPublishingTransportManager;
import org.eclipse.persistence.sessions.coordination.jms.JMSTopicTransportManager;
import org.eclipse.persistence.sessions.coordination.rmi.RMITransportManager;
import org.eclipse.persistence.sessions.factories.SessionManager;
import org.eclipse.persistence.sessions.factories.XMLSessionConfigLoader;
import org.eclipse.persistence.sessions.remote.RemoteSession;
import org.eclipse.persistence.sessions.remote.rmi.RMIConnection;
import org.eclipse.persistence.sessions.remote.rmi.RMIServerSessionManager;
import org.eclipse.persistence.sessions.remote.rmi.RMIServerSessionManagerDispatcher;
import org.eclipse.persistence.sessions.serializers.JavaSerializer;
import org.eclipse.persistence.sessions.serializers.Serializer;
import org.eclipse.persistence.sessions.server.ConnectionPolicy;
import org.eclipse.persistence.sessions.server.ConnectionPool;
import org.eclipse.persistence.sessions.server.ExternalConnectionPool;
import org.eclipse.persistence.sessions.server.ReadConnectionPool;
import org.eclipse.persistence.sessions.server.ServerSession;
import org.eclipse.persistence.tools.profiler.PerformanceMonitor;
import org.eclipse.persistence.tools.profiler.PerformanceProfiler;
import org.eclipse.persistence.tools.profiler.QueryMonitor;
import org.eclipse.persistence.tools.schemaframework.SchemaManager;
import org.eclipse.persistence.tools.tuning.SafeModeTuner;
import org.eclipse.persistence.tools.tuning.SessionTuner;
import org.eclipse.persistence.tools.tuning.StandardTuner;
/**
* INTERNAL:
* This class handles deployment of a persistence unit.
* In predeploy the meta-data is processed and weaver transformer is returned to allow weaving of the persistent classes.
* In deploy the project and session are initialize and registered.
*/
public class EntityManagerSetupImpl implements MetadataRefreshListener {
/*
* Design Pattern in use: Builder pattern
* EntityManagerSetupImpl, MetadataProcessor and MetadataProject
* play the role of director, builder and product respectively.
* See processORMetadata which is the factory method.
*
*/
// this name should uniquely identify the persistence unit
protected String persistenceUnitUniqueName;
// session name should uniquely identify the session
protected String sessionName;
private MetadataProcessor processor = null;
/** Holds a reference to the weaver class transformer so it can be cleared after login. */
private PersistenceWeaver weaver = null;
protected PersistenceUnitInfo persistenceUnitInfo = null;
// count a number of open factories that use this object.
protected int factoryCount = 0;
protected AbstractSession session = null;
// true if predeploy called by createContainerEntityManagerFactory; false - createEntityManagerFactory
protected boolean isInContainerMode = false;
protected boolean isSessionLoadedFromSessionsXML=false;
//project caching:
protected ProjectCache projectCacheAccessor = null;
protected boolean shouldBuildProject = true;
// indicates whether weaving was used on the first run through predeploy (in STATE_INITIAL)
protected Boolean enableWeaving = null;
// indicates that classes have already been woven
protected boolean isWeavingStatic = false;
// used by static weaving
protected StaticWeaveInfo staticWeaveInfo;
protected SecurableObjectHolder securableObjectHolder = new SecurableObjectHolder();
// used by deploy method
protected ConcurrencyManager deployLock = new ConcurrencyManager();
protected boolean requiresConnection;
// 266912: Criteria API and Metamodel API (See Ch 5 of the JPA 2.0 Specification)
/** Reference to the Metamodel for this deployment and session.
* Please use the accessor and not the instance variable directly*/
private Metamodel metaModel;
protected List<StructConverter> structConverters = null;
// factoryCount==0; session==null
public static final String STATE_INITIAL = "Initial";
// session != null
public static final String STATE_PREDEPLOYED = "Predeployed";
// factoryCount>0; session != null; session stored in SessionManager
// for compositeMember factoryCount is always 0; session is never stored in SessionBroker
// the session has not yet connected for the first time or failed to connect for the first time
public static final String STATE_HALF_DEPLOYED = "HalfDeployed";
// factoryCount>0; session != null; session stored in SessionManager
// for compositeMember factoryCount is always 0; session is never stored in SessionBroker
// the session has connected for the first time
public static final String STATE_DEPLOYED = "Deployed";
// factoryCount==0; session==null
public static final String STATE_PREDEPLOY_FAILED="PredeployFailed";
// factoryCount>0; session != null
// for compositeMember factoryCount is always 0
public static final String STATE_DEPLOY_FAILED = "DeployFailed";
// factoryCount==0; session==null
public static final String STATE_UNDEPLOYED = "Undeployed";
// factoryCount==0; session==null
// only composite member persistence unit can be in this state
public static final String STATE_HALF_PREDEPLOYED_COMPOSITE_MEMBER = "HalfPredeployedCompositeMember";
/**
* Initial -----&gt; HalfPredeployedCompositeMember -----&gt; PredeployFailed
* | ^ |
* V-------&gt;| V
* Predeployed
*/
protected String state = STATE_INITIAL;
/**
* Initial -----------&gt; PredeployFailed ---
* | |
* V |
* Predeployed ---&gt; DeployFailed -- |
* | | |
* V V V
* HalfDeployed --&gt; Deployed -&gt; Undeployed
* | ^
* V |
* DeployFailed -------------------
*
*/
public static final String ERROR_LOADING_XML_FILE = "error_loading_xml_file";
public static final String EXCEPTION_LOADING_ENTITY_CLASS = "exception_loading_entity_class";
/*
* Properties used to generate sessionName if none is provided.
*/
public static String[] connectionPropertyNames = {
PersistenceUnitProperties.TRANSACTION_TYPE,
PersistenceUnitProperties.JTA_DATASOURCE,
PersistenceUnitProperties.NON_JTA_DATASOURCE,
PersistenceUnitProperties.JDBC_URL,
PersistenceUnitProperties.JDBC_USER,
PersistenceUnitProperties.NOSQL_CONNECTION_SPEC,
PersistenceUnitProperties.NOSQL_CONNECTION_FACTORY,
PersistenceUnitProperties.NOSQL_USER,
PersistenceUnitProperties.JDBC_CONNECTOR
};
/*
* Composite, not null only if it's a composite member.
*/
protected EntityManagerSetupImpl compositeEmSetupImpl;
/*
* Composite members, not null only if it's a composite.
*/
protected Set<EntityManagerSetupImpl> compositeMemberEmSetupImpls;
/*
* In HalfPredeployedCompositeMember predeploy method called several times,
* each call uses mode, then updating it before returning.
* So mode value could be viewed as a substate of HalfPredeployedCompositeMember state.
* The mode is required for staging of processing OR metadata for composite members:
* each processing stage should be completed for ALL composite members before
* any one of then could proceed to the next processing stage.
*/
PersistenceUnitProcessor.Mode mode;
boolean throwExceptionOnFail;
boolean weaveChangeTracking;
boolean weaveLazy;
boolean weaveEager;
boolean weaveFetchGroups;
boolean weaveInternal;
boolean weaveRest;
boolean weaveMappedSuperClass;
/**
* Used to indicate that an EntityManagerFactoryImpl based on this
* EntityManagerSetupImpl has been refreshed. This means this EntityManagerSetupImpl
* will no longer be associated with new EntityManagerFactories
*/
protected boolean isMetadataExpired = false;
/*
* Used to distinguish the various DDL options
*/
protected enum TableCreationType {NONE, CREATE, DROP, DROP_AND_CREATE, EXTEND};
/*
* PersistenceException responsible for the invalid state.
*/
protected PersistenceException persistenceException;
public EntityManagerSetupImpl(String persistenceUnitUniqueName, String sessionName) {
this.persistenceUnitUniqueName = persistenceUnitUniqueName;
this.sessionName = sessionName;
this.requiresConnection = true;
}
public EntityManagerSetupImpl() {
this("", "");
}
protected static String addFileSeperator(String appLocation) {
int strLength = appLocation.length();
if (appLocation.substring(strLength -1, strLength).equals(File.separator)) {
return appLocation;
} else {
return appLocation + File.separator;
}
}
/*
* Return session name if specified.
* Otherwise build one from the connection properties names and values.
* Note that specifying value "" in properties causes
* the property value specified in PersistenceUnitInfo to be ignored.
* Never returns null.
*/
public static String getOrBuildSessionName(Map properties, PersistenceUnitInfo puInfo, String persistenceUnitUniqueName) {
// Weblogic server was found to prefix the file path on Windows platform with a slash, so mandating that for compatibility
String persistenceUnitName = assertCompatiblePersistenceUnitName(persistenceUnitUniqueName);
// if SESSION_NAME is specified in either properties or puInfo properties - use it as session name (unless it's an empty String).
String sessionName = (String)properties.get(PersistenceUnitProperties.SESSION_NAME);
if (sessionName == null) {
sessionName = (String)puInfo.getProperties().get(PersistenceUnitProperties.SESSION_NAME);
}
// Specifying empty String in properties allows to remove SESSION_NAME specified in puInfo properties.
if(sessionName != null && sessionName.length() > 0) {
return sessionName;
}
// ELBug 355603 - Prepend the application id if present in properties.
// This property will be set by the WebLogic Server if the persistence unit
// is deployed as part of shared library to construct a unique session name
String applicationId = (String)properties.get("weblogic.application-id");
// ELBug 475285 - Added a more generic version of the weblogic.application-id property.
if (applicationId == null) {
applicationId = (String) properties.get("eclipselink.application-id");
}
if (isComposite(puInfo)) {
// Composite doesn't use connection properties.
if (applicationId != null) {
return applicationId + persistenceUnitName;
}
return persistenceUnitName;
} else {
// In case no SESSION_NAME specified (or empty String) - build one
// by concatenating persistenceUnitUniqueName and suffix build of connection properties' names and values.
if (applicationId != null) {
return applicationId + persistenceUnitName + buildSessionNameSuffixFromConnectionProperties(properties);
}
return persistenceUnitName + buildSessionNameSuffixFromConnectionProperties(properties);
}
}
private static String assertCompatiblePersistenceUnitName(String persistenceUnitUniqueName) {
if(persistenceUnitUniqueName != null && !persistenceUnitUniqueName.startsWith("/")) {
return '/' + persistenceUnitUniqueName;
}
return persistenceUnitUniqueName;
}
protected static String buildSessionNameSuffixFromConnectionProperties(Map properties) {
StringBuilder suffix = new StringBuilder(32);
for (int i=0; i < connectionPropertyNames.length; i++) {
String name = connectionPropertyNames[i];
Object value = properties.get(name);
if (value != null) {
String strValue = null;
if (value instanceof String) {
strValue = (String)value;
} else {
if (value instanceof javax.sql.DataSource) {
// value of JTA_DATASOURCE / NON_JTA_DATASOURCE may be a DataSource (we would prefer DataSource name)
strValue = Integer.toString(System.identityHashCode(value));
} else if (value instanceof PersistenceUnitTransactionType) {
strValue = value.toString();
} else {
strValue = Integer.toString(System.identityHashCode(value));
}
}
// don't set an empty String
if (strValue.length() > 0) {
suffix.append("_").append(Helper.getShortClassName(name)).append("=").append(strValue);
}
}
}
return suffix.toString();
}
/*
* Should only be called when emSetupImpl created during SE initialization is set into a new EMF.
* emSetupImpl must be in PREDEPLOYED state.
*/
public void changeSessionName(String newSessionName) {
if(!session.getName().equals(newSessionName)) {
session.log(SessionLog.FINEST, SessionLog.PROPERTIES, "session_name_change", new Object[]{getPersistenceUnitInfo().getPersistenceUnitName(), session.getName(), newSessionName});
sessionName = newSessionName;
session.setName(newSessionName);
}
}
/**
* This method can be used to ensure the session represented by emSetupImpl
* is removed from the SessionManager.
*/
protected void removeSessionFromGlobalSessionManager() {
if (this.session != null){
try {
if (this.session.isDatabaseSession() && this.session.isConnected()) {
getDatabaseSession().logout();
}
} finally {
SessionManager manager = SessionManager.getManager();
manager.getSessions().remove(this.session.getName(), this.session);
manager.destroy();
}
}
}
/**
* Deploy a persistence session and return an EntityManagerFactory.
*
* Deployment takes a session that was partially created in the predeploy call and makes it whole.
*
* This means doing any configuration that requires the real class definitions for the entities. In
* the predeploy phase we were in a stage where we were not let allowed to load the real classes.
*
* Deploy could be called several times - but only the first call does the actual deploying -
* additional calls allow to update session properties (in case the session is not connected).
*
* Note that there is no need to synchronize deploy method - it doesn't alter factoryCount
* and while deploy is executed no other method can alter the current state
* (predeploy call would just increment factoryCount; undeploy call would not drop factoryCount to 0).
* However precautions should be taken to handle concurrent calls to deploy, because those may
* alter the current state or connect the session.
*
* @param realClassLoader The class loader that was used to load the entity classes. This loader
* will be maintained for the lifespan of the loaded classes.
* @param additionalProperties added to persistence unit properties for updateServerSession overriding existing properties.
* In JSE case it allows to alter properties in main (as opposed to preMain where preDeploy is called).
* @return An EntityManagerFactory to be used by the Container to obtain EntityManagers
*/
public AbstractSession deploy(ClassLoader realClassLoader, Map additionalProperties) {
if (this.state != STATE_PREDEPLOYED && this.state != STATE_DEPLOYED && this.state != STATE_HALF_DEPLOYED) {
if (mustBeCompositeMember()) {
throw new PersistenceException(EntityManagerSetupException.compositeMemberCannotBeUsedStandalone(this.persistenceUnitInfo.getPersistenceUnitName()));
}
throw new PersistenceException(EntityManagerSetupException.cannotDeployWithoutPredeploy(this.persistenceUnitInfo.getPersistenceUnitName(), this.state, this.persistenceException));
}
// state is PREDEPLOYED or DEPLOYED
this.session.log(SessionLog.FINEST, SessionLog.JPA, "deploy_begin", new Object[]{getPersistenceUnitInfo().getPersistenceUnitName(), this.session.getName(), this.state, this.factoryCount});
ClassLoader classLoaderToUse = realClassLoader;
if (additionalProperties.containsKey(PersistenceUnitProperties.CLASSLOADER)) {
classLoaderToUse = (ClassLoader) additionalProperties.get(PersistenceUnitProperties.CLASSLOADER);
} else if ((this.processor != null) && (this.processor.getProject() != null) && (this.processor.getProject().hasVirtualClasses()) && (this.state == STATE_PREDEPLOYED) && (!(classLoaderToUse instanceof DynamicClassLoader))) {
classLoaderToUse = new DynamicClassLoader(classLoaderToUse);
}
// indicates whether session has failed to connect, determines whether HALF_DEPLOYED state should be kept in case of exception.
boolean isLockAcquired = false;
try {
Map deployProperties = mergeMaps(additionalProperties, this.persistenceUnitInfo.getProperties());
updateTunerPreDeploy(deployProperties, classLoaderToUse);
translateOldProperties(deployProperties, this.session);
if (isComposite()) {
updateCompositeMembersProperties(deployProperties);
}
if (this.state == STATE_PREDEPLOYED) {
this.deployLock.acquire();
isLockAcquired = true;
if (this.state == STATE_PREDEPLOYED) {
if (this.shouldBuildProject && !this.isSessionLoadedFromSessionsXML) {
if (isComposite()) {
deployCompositeMembers(deployProperties, classLoaderToUse);
} else {
if (this.processor.getMetadataSource() != null) {
Map metadataProperties = this.processor.getMetadataSource().getPropertyOverrides(deployProperties, classLoaderToUse, this.session.getSessionLog());
if (metadataProperties != null && !metadataProperties.isEmpty()) {
translateOldProperties(metadataProperties, this.session);
deployProperties = mergeMaps(metadataProperties, deployProperties);
}
}
// listeners and queries require the real classes and are therefore built during deploy using the realClassLoader
this.processor.setClassLoader(classLoaderToUse);
this.processor.createDynamicClasses();
this.processor.addEntityListeners();
if (this.projectCacheAccessor != null) {
//cache the project:
this.projectCacheAccessor.storeProject(this.session.getProject(), deployProperties, this.session.getSessionLog());
}
// The project is initially created using class names rather than classes. This call will make the conversion.
// If the session was loaded from sessions.xml this will also convert the descriptor classes to the correct class loader.
this.session.getProject().convertClassNamesToClasses(classLoaderToUse);
if (!isCompositeMember()) {
addBeanValidationListeners(deployProperties, classLoaderToUse);
}
// Process the customizers last.
this.processor.processCustomizers();
}
this.processor = null;
} else {
// The project is initially created using class names rather than classes. This call will make the conversion.
// If the session was loaded from sessions.xml this will also convert the descriptor classes to the correct class loader.
this.session.getProject().convertClassNamesToClasses(classLoaderToUse);
if (!this.shouldBuildProject) {
//process anything that might not have been serialized/cached in the project correctly:
if (!isCompositeMember()) {
addBeanValidationListeners(deployProperties, classLoaderToUse);
}
//process Descriptor customizers:
processDescriptorsFromCachedProject(classLoaderToUse);
}
}
finishProcessingDescriptorEvents(classLoaderToUse);
this.structConverters = getStructConverters(classLoaderToUse);
updateRemote(deployProperties, classLoaderToUse);
initSession();
if (this.session.getIntegrityChecker().hasErrors()){
this.session.handleException(new IntegrityException(session.getIntegrityChecker()));
}
this.session.getDatasourcePlatform().getConversionManager().setLoader(classLoaderToUse);
this.state = STATE_HALF_DEPLOYED;
// keep deployLock
} else {
// state is HALF_DEPLOYED or DEPLOY_FAILED
this.deployLock.release();
isLockAcquired = false;
if (this.state == STATE_DEPLOY_FAILED) {
// while this thread waited in STATE_PREDEPLOYED another thread attempted to deploy and failed.
// Rethrow the cache PersistenceException, which caused STATE_DEPLOYED_FAILED.
throw persistenceException;
}
}
}
// state is HALF_DEPLOYED or DEPLOYED
if (!isCompositeMember()) {
if (this.session.isDatabaseSession() && !((DatabaseSessionImpl)session).isLoggedIn()) {
// If it's HALF_DEPLOYED then deployLock has been already acquired.
if (!isLockAcquired) {
this.deployLock.acquire();
isLockAcquired = true;
}
if (!((DatabaseSessionImpl)this.session).isLoggedIn()) {
if (this.state == STATE_DEPLOY_FAILED) {
// while this thread waited in STATE_HALF_DEPLOYED another thread attempted to connect the session and failed.
// Rethrow the cache PersistenceException, which caused STATE_DEPLOYED_FAILED.
throw persistenceException;
}
this.session.setProperties(deployProperties);
updateSession(deployProperties, classLoaderToUse);
if (isValidationOnly(deployProperties, false)) {
/**
* for 324213 we could add a session.loginAndDetectDatasource() call
* before calling initializeDescriptors when validation-only is True
* to avoid a native sequence exception on a generic DatabasePlatform
* by auto-detecting the correct DB platform.
* However, this would introduce a DB login when validation is on
* - in opposition to the functionality of the property (to only validate)
*/
if (this.state == STATE_HALF_DEPLOYED) {
getDatabaseSession().initializeDescriptors();
this.state = STATE_DEPLOYED;
}
} else {
try {
updateTunerDeploy(deployProperties, classLoaderToUse);
updateFreeMemory(deployProperties);
if (this.isSessionLoadedFromSessionsXML) {
getDatabaseSession().login();
} else {
login(getDatabaseSession(), deployProperties, requiresConnection);
}
final Platform platform = getDatabaseSession().getDatasourcePlatform();
String dbProperties = getConfigPropertyAsStringLogDebug(PersistenceUnitProperties.TARGET_DATABASE_PROPERTIES, deployProperties, this.session);
PropertiesUtils.set(platform, PersistenceUnitProperties.TARGET_DATABASE_PROPERTIES, dbProperties);
// Make JTA integration throw JPA exceptions.
if (this.session.hasExternalTransactionController()) {
if (this.session.getExternalTransactionController().getExceptionHandler() == null) {
this.session.getExternalTransactionController().setExceptionHandler(new ExceptionHandler() {
@Override
public Object handleException(RuntimeException exception) {
if (exception instanceof org.eclipse.persistence.exceptions.OptimisticLockException) {
throw new OptimisticLockException(exception);
} else if (exception instanceof EclipseLinkException) {
throw new PersistenceException(exception);
} else {
throw exception;
}
}
});
}
}
this.state = STATE_DEPLOYED;
} catch (Throwable loginException) {
if (this.state == STATE_HALF_DEPLOYED) {
if (this.session.isConnected()) {
// session is connected, but postConnect has failed.
// Likely this is caused by failure in initializeDescriptors:
// either descriptor exception or by invalid named jpql query.
// Cannot recover from that - the user has to fix the persistence unit and redeploy it.
try {
getDatabaseSession().logout();
} catch (Throwable logoutException) {
// Ignore
}
this.state = STATE_DEPLOY_FAILED;
}
}
throw loginException;
}
if (!this.isSessionLoadedFromSessionsXML) {
addStructConverters();
}
// Generate the DDL using the correct connection.
writeDDL(deployProperties, getDatabaseSession(deployProperties), classLoaderToUse);
}
}
// Initialize platform specific identity sequences.
session.getDatasourcePlatform().initIdentitySequences(getDatabaseSession(), MetadataProject.DEFAULT_IDENTITY_GENERATOR);
updateTunerPostDeploy(deployProperties, classLoaderToUse);
this.deployLock.release();
isLockAcquired = false;
}
// 266912: Initialize the Metamodel, a login should have already occurred.
try {
this.getMetamodel(classLoaderToUse);
} catch (Exception e) {
this.session.log(SessionLog.FINEST, SessionLog.METAMODEL, "metamodel_init_failed", new Object[]{e.getMessage()});
}
}
// Clear the weaver's reference to meta-data information, as it is held by the class loader and will never gc.
if (this.weaver != null) {
this.weaver.clear();
this.weaver = null;
}
return this.session;
} catch (Throwable exception) {
// before releasing deployLock switch to the correct state
if (this.state == STATE_PREDEPLOYED) {
this.state = STATE_DEPLOY_FAILED;
}
PersistenceException persistenceEx;
if (this.state == STATE_DEPLOY_FAILED) {
if (exception == persistenceException) {
persistenceEx = new PersistenceException(EntityManagerSetupException.cannotDeployWithoutPredeploy(this.persistenceUnitInfo.getPersistenceUnitName(), this.state, this.persistenceException));
} else {
// before releasing deployLock cache the exception
persistenceEx = createDeployFailedPersistenceException(exception);
}
} else {
if (exception instanceof PersistenceException) {
persistenceEx = (PersistenceException)exception;
} else {
persistenceEx = new PersistenceException(exception);
}
}
if (isLockAcquired) {
this.deployLock.release();
}
this.session.logThrowable(SessionLog.SEVERE, SessionLog.EJB, exception);
throw persistenceEx;
} finally {
this.session.log(SessionLog.FINEST, SessionLog.JPA, "deploy_end", new Object[]{getPersistenceUnitInfo().getPersistenceUnitName(), this.session.getName(), this.state, this.factoryCount});
}
}
/**
* INTERNAL:
* This method is used to resolve Descriptor Customizers that might have been stored in the project
* for JPA project caching.
*
*/
private void processDescriptorsFromCachedProject(ClassLoader realClassLoader) throws ClassNotFoundException, PrivilegedActionException, IllegalAccessException, InstantiationException {
for (ClassDescriptor descriptor: session.getProject().getDescriptors().values()) {
//process customizers:
if (descriptor.getDescriptorCustomizerClassName() != null) {
Class listenerClass = findClass(descriptor.getDescriptorCustomizerClassName(), realClassLoader);
DescriptorCustomizer customizer = (DescriptorCustomizer) buildObjectForClass(listenerClass, DescriptorCustomizer.class);
try {
customizer.customize(descriptor);
} catch (Exception e) {
session.getSessionLog().logThrowable(SessionLog.FINER, SessionLog.METADATA, e);
}
}
}
}
/**
* INTERNAL:
* This method is used to resolve Descriptor Events processed earlier into EventHolders that now need to be
* used to create the DescriptorEventListeners and added to the DescriptorEventManager
*
*/
private void finishProcessingDescriptorEvents(ClassLoader realClassLoader) {
for (ClassDescriptor descriptor: session.getProject().getDescriptors().values()) {
if (descriptor.hasEventManager()) {
descriptor.getEventManager().processDescriptorEventHolders(session, realClassLoader);
}
}
}
protected PersistenceException createDeployFailedPersistenceException(Throwable ex) {
PersistenceException perEx = new PersistenceException(EntityManagerSetupException.deployFailed(persistenceUnitInfo.getPersistenceUnitName(), ex));
if (persistenceException == null) {
persistenceException = perEx;
}
return perEx;
}
/**
* Adds descriptors plus sequencing info found on the project to the session.
*/
protected void addProjectToSession(ServerSession session, Project project) {
DatasourcePlatform sessionPlatform = (DatasourcePlatform)session.getDatasourceLogin().getDatasourcePlatform();
DatasourcePlatform projectPlatform = (DatasourcePlatform)project.getDatasourceLogin().getDatasourcePlatform();
if (!sessionPlatform.hasDefaultSequence() && projectPlatform.hasDefaultSequence()) {
sessionPlatform.setDefaultSequence(projectPlatform.getDefaultSequence());
}
if ((sessionPlatform.getSequences() == null) || sessionPlatform.getSequences().isEmpty()) {
if ((projectPlatform.getSequences() != null) && !projectPlatform.getSequences().isEmpty()) {
sessionPlatform.setSequences(projectPlatform.getSequences());
}
} else {
if ((projectPlatform.getSequences() != null) && !projectPlatform.getSequences().isEmpty()) {
Iterator<Sequence> itProjectSequences = projectPlatform.getSequences().values().iterator();
while (itProjectSequences.hasNext()) {
Sequence sequence = itProjectSequences.next();
if (!sessionPlatform.getSequences().containsKey(sequence.getName())) {
sessionPlatform.addSequence(sequence);
}
}
}
}
session.addDescriptors(project);
}
/**
* Put the given session into the session manager so it can be looked up later
*/
protected void addSessionToGlobalSessionManager() {
SessionManager sm = SessionManager.getManager();
ConcurrentMap<String,Session> sessions = sm.getSessions();
AbstractSession oldSession = (AbstractSession) sessions.get(session.getName());
if(oldSession != null) {
throw new PersistenceException(EntityManagerSetupException.attemptedRedeployWithoutClose(session.getName()));
}
sm.addSession(session);
}
/**
* Add the StructConverters that were specified by annotation on the DatabasePlatform
* This method must be called after the DatabasePlatform has been detected
*/
public void addStructConverters(){
if (this.compositeMemberEmSetupImpls == null) {
for (StructConverter structConverter : structConverters){
if (session.getPlatform().getTypeConverters().get(structConverter.getJavaType()) != null){
throw ValidationException.twoStructConvertersAddedForSameClass(structConverter.getJavaType().getName());
}
session.getPlatform().addStructConverter(structConverter);
}
} else {
// composite
for(EntityManagerSetupImpl compositeMemberEmSetupImpl : this.compositeMemberEmSetupImpls) {
if (!compositeMemberEmSetupImpl.structConverters.isEmpty()) {
String compositeMemberPuName = compositeMemberEmSetupImpl.getPersistenceUnitInfo().getPersistenceUnitName();
// debug output added to make it easier to navigate the log because the method is called outside of composite member deploy
compositeMemberEmSetupImpl.session.log(SessionLog.FINEST, SessionLog.PROPERTIES, "composite_member_begin_call", new Object[]{"addStructConverters", compositeMemberPuName, state});
compositeMemberEmSetupImpl.addStructConverters();
compositeMemberEmSetupImpl.session.log(SessionLog.FINEST, SessionLog.PROPERTIES, "composite_member_end_call", new Object[]{"addStructConverters", compositeMemberPuName, state});
}
}
}
}
/**
* Assign a CMP3Policy to each descriptor, and sets the OptimisticLockingPolicy's LockOnChangeMode if applicable.
*/
protected void assignCMP3Policy() {
// all descriptors assigned CMP3Policy
Project project = session.getProject();
for (Iterator<ClassDescriptor> iterator = project.getDescriptors().values().iterator(); iterator.hasNext();){
//bug:4406101 changed class cast to base class, which is used in projects generated from 904 xml
ClassDescriptor descriptor = iterator.next();
if(descriptor.getCMPPolicy() == null) {
descriptor.setCMPPolicy(new CMP3Policy());
}
OptimisticLockingPolicy olp = descriptor.getOptimisticLockingPolicy();
if (olp != null && olp.getLockOnChangeMode() == null){
olp.setLockOnChangeMode(LockOnChange.OWNING);
}
}
// TODO: Look into setting a CMPPolicy on the MappedSuperclass descriptors.
// Will require some tweaking however to ensure the primary key fields are
// set/initialized correctly. Currently rely on the descriptor initialized
// object builder which is not available to mapped superclass descriptors.
}
/**
* Updates the EclipseLink ServerPlatform class for use with this platform.
* @return true if the ServerPlatform has changed.
*/
protected boolean updateServerPlatform(Map m, ClassLoader loader) {
final String serverPlatformClassNameProperty =
PropertiesHandler.getPropertyValueLogDebug(PersistenceUnitProperties.TARGET_SERVER, m, session);
final String jtaControllerClassNameProperty =
PropertiesHandler.getPropertyValueLogDebug(PersistenceUnitProperties.JTA_CONTROLLER, m, session);
final String serverPlatformClassName;
if (serverPlatformClassNameProperty == null) {
// property is not specified - try to detect.
serverPlatformClassName = ServerPlatformUtils.detectServerPlatform(getSession());
if (serverPlatformClassName == null) {
// Unable to detect what platform we're running on. Use default/NoServer.
return false;
}
} else {
serverPlatformClassName = serverPlatformClassNameProperty;
}
// originalServerPlatform is always non-null - Session's constructor sets serverPlatform to NoServerPlatform
final ServerPlatform originalServerPlatform = session.getServerPlatform();
final String originalServerPlatformClassName = originalServerPlatform.getClass().getName();
final Class originalServerPlatformTransCtrlClass = originalServerPlatform.getExternalTransactionControllerClass();
final String originalServerPlatformTransCtrlClassName = originalServerPlatformTransCtrlClass != null
? originalServerPlatform.getExternalTransactionControllerClass().getName() : null;
if (serverPlatformClassName.equals(originalServerPlatformClassName)
&& (serverPlatformClassNameProperty == null || serverPlatformClassNameProperty.equals(originalServerPlatformClassName))
&& (jtaControllerClassNameProperty == null || jtaControllerClassNameProperty.equals(originalServerPlatformTransCtrlClassName))) {
// nothing to do - use the same value as before
return false;
}
// the new serverPlatform
ServerPlatform serverPlatform = null;
// New platform - create the new instance and set it.
Class cls = findClassForProperty(serverPlatformClassName, PersistenceUnitProperties.TARGET_SERVER, loader);
boolean isTargetServerTransCtrl = false;
try {
Constructor constructor = cls.getConstructor(org.eclipse.persistence.sessions.DatabaseSession.class);
serverPlatform = (ServerPlatform)constructor.newInstance(new Object[]{session});
} catch (Exception ex) {
if(ExternalTransactionController.class.isAssignableFrom(cls)) {
// the new serverPlatform is CustomServerPlatform, cls is its ExternalTransactionController class
if(originalServerPlatform.getClass().equals(CustomServerPlatform.class)) {
// both originalServerPlatform and the new serverPlatform are Custom,
// just set externalTransactionController class (if necessary) into
// originalServerPlatform
CustomServerPlatform originalCustomServerPlatform = (CustomServerPlatform)originalServerPlatform;
if (cls.equals(originalCustomServerPlatform.getExternalTransactionControllerClass())) {
// externalTransactionController classes are the same - nothing to do
} else {
originalCustomServerPlatform.setExternalTransactionControllerClass(cls);
}
} else {
// originalServerPlatform is not custom - need a new one.
serverPlatform = new CustomServerPlatform(getDatabaseSession());
serverPlatform.setExternalTransactionControllerClass(cls);
}
isTargetServerTransCtrl = true;
} else {
throw EntityManagerSetupException.failedToInstantiateServerPlatform(serverPlatformClassName, PersistenceUnitProperties.TARGET_SERVER, ex);
}
}
// Override JTA transaction controller class by eclipselink.jta.controller property, but only when
// eclipselink.target-server does not contain ExternalTransactionController implementing class.
if (jtaControllerClassNameProperty != null) {
if (isTargetServerTransCtrl) {
session.getSessionLog().log(SessionLog.WARNING, "jta_duplicate_ctrl_property");
} else {
if (!originalServerPlatform.getClass().equals(CustomServerPlatform.class)) {
serverPlatform = new CustomServerPlatform(getDatabaseSession());
}
updateJTAControllerInPlatform(serverPlatform != null ? serverPlatform : originalServerPlatform, jtaControllerClassNameProperty, loader);
}
}
if (serverPlatform != null) {
getDatabaseSession().setServerPlatform(serverPlatform);
return true;
}
return false;
}
/**
* Update JTA transaction controller class of provided {@link ServerPlatform} instance.
*
* @param serverPlatform target {@link ServerPlatform} instance
* @param jtaControllerClassName JTA transaction controller class name
* @param loader class loader containing JTA transaction controller class
*/
private static void updateJTAControllerInPlatform(
final ServerPlatform serverPlatform, final String jtaControllerClassName, final ClassLoader loader) {
Class jtaCls = findClassForProperty(jtaControllerClassName, PersistenceUnitProperties.JTA_CONTROLLER, loader);
serverPlatform.setExternalTransactionControllerClass(jtaCls);
}
/**
* Checks for partitioning properties.
*/
protected void updatePartitioning(Map m, ClassLoader loader) {
// Partitioning
String partitioning = getConfigPropertyAsStringLogDebug(PersistenceUnitProperties.PARTITIONING, m, this.session);
if (partitioning != null) {
PartitioningPolicy partitioningPolicy = this.session.getProject().getPartitioningPolicy(partitioning);
if (partitioningPolicy == null) {
throw DescriptorException.missingPartitioningPolicy(partitioning, null, null);
}
this.session.setPartitioningPolicy(partitioningPolicy);
}
String callbackClassName = getConfigPropertyAsStringLogDebug(PersistenceUnitProperties.PARTITIONING_CALLBACK, m, this.session);
if (callbackClassName != null) {
Class cls = findClassForProperty(callbackClassName, PersistenceUnitProperties.PARTITIONING_CALLBACK, loader);
DataPartitioningCallback callback = null;
try {
Constructor constructor = cls.getConstructor();
callback = (DataPartitioningCallback)constructor.newInstance();
} catch (Exception exception) {
throw EntityManagerSetupException.failedToInstantiateProperty(callbackClassName, PersistenceUnitProperties.PARTITIONING_CALLBACK, exception);
}
this.session.getLogin().setPartitioningCallback(callback);
}
}
/**
* Checks for partitioning properties.
*/
protected void updateRemote(Map m, ClassLoader loader) {
String protocol = getConfigPropertyAsStringLogDebug(PersistenceUnitProperties.REMOTE_PROTOCOL, m, this.session);
String serverName = getConfigPropertyAsStringLogDebug(PersistenceUnitProperties.REMOTE_SERVER_NAME, m, this.session);
if (serverName == null) {
// Configure as client.
if (protocol != null) {
RemoteConnection connection = null;
if (protocol.equalsIgnoreCase(RemoteProtocol.RMI)) {
String url = getConfigPropertyAsStringLogDebug(PersistenceUnitProperties.REMOTE_URL, m, this.session);
if (url == null) {
throw EntityManagerSetupException.missingProperty(PersistenceUnitProperties.REMOTE_URL);
}
try {
connection = new RMIConnection(((RMIServerSessionManager)Naming.lookup(url)).createRemoteSessionController());
} catch (Exception exception) {
throw ValidationException.invalidValueForProperty(url, PersistenceUnitProperties.REMOTE_URL, exception);
}
} else {
Class cls = findClassForProperty(protocol, PersistenceUnitProperties.REMOTE_PROTOCOL, loader);
try {
Constructor constructor = cls.getConstructor();
connection = (RemoteConnection)constructor.newInstance();
} catch (Exception exception) {
throw ValidationException.invalidValueForProperty(protocol, PersistenceUnitProperties.REMOTE_PROTOCOL, exception);
}
}
RemoteSession remoteSession = new RemoteSession();
remoteSession.setIsMetadataRemote(false);
remoteSession.setProject(this.session.getProject());
remoteSession.setProfiler(this.session.getProfiler());
remoteSession.setSessionLog(this.session.getSessionLog());
remoteSession.setEventManager(this.session.getEventManager());
remoteSession.setQueries(this.session.getQueries());
remoteSession.setProperties(this.session.getProperties());
remoteSession.setName(this.session.getName());
remoteSession.setRemoteConnection(connection);
this.session = remoteSession;
}
} else {
// Configure as server.
if (protocol.equalsIgnoreCase(RemoteProtocol.RMI)) {
RMIServerSessionManager manager = null;
// Make sure RMI registry is started.
try {
java.rmi.registry.LocateRegistry.createRegistry(1099);
} catch (Exception exception) {
System.out.println("Security violation " + exception.toString());
}
// Create local instance of the factory
try {
manager = new RMIServerSessionManagerDispatcher(session);
} catch (RemoteException exception) {
throw ValidationException.invalidValueForProperty(serverName, PersistenceUnitProperties.REMOTE_SERVER_NAME, exception);
}
// Put the local instance into the Registry
try {
Naming.unbind(serverName);
} catch (Exception exception) {
// Ignore.
}
// Put the local instance into the Registry
try {
Naming.rebind(serverName, manager);
} catch (Exception exception) {
throw ValidationException.invalidValueForProperty(serverName, PersistenceUnitProperties.REMOTE_SERVER_NAME, exception);
}
}
}
}
/**
* Checks for database events listener properties.
*/
protected void updateDatabaseEventListener(Map m, ClassLoader loader) {
String listenerClassName = getConfigPropertyAsStringLogDebug(PersistenceUnitProperties.DATABASE_EVENT_LISTENER, m, this.session);
if (listenerClassName != null) {
if (listenerClassName.equalsIgnoreCase("DCN") || listenerClassName.equalsIgnoreCase("QCN")) {
listenerClassName = "org.eclipse.persistence.platform.database.oracle.dcn.OracleChangeNotificationListener";
}
Class cls = findClassForProperty(listenerClassName, PersistenceUnitProperties.DATABASE_EVENT_LISTENER, loader);
DatabaseEventListener listener = null;
try {
Constructor constructor = cls.getConstructor();
listener = (DatabaseEventListener)constructor.newInstance();
} catch (Exception exception) {
throw EntityManagerSetupException.failedToInstantiateProperty(listenerClassName, PersistenceUnitProperties.DATABASE_EVENT_LISTENER, exception);
}
getDatabaseSession().setDatabaseEventListener(listener);
}
}
/**
* Update loggers and settings for the singleton logger and the session logger.
* @param persistenceProperties the properties map
* @param serverPlatformChanged the boolean that denotes a serverPlatform change in the session.
*/
protected void updateLoggers(Map persistenceProperties, boolean serverPlatformChanged, ClassLoader loader) {
// Logger(SessionLog type) can be specified by the logger property or ServerPlatform.getServerLog().
// The logger property has a higher priority to ServerPlatform.getServerLog().
String loggerClassName = PropertiesHandler.getPropertyValueLogDebug(PersistenceUnitProperties.LOGGING_LOGGER, persistenceProperties, session);
// The sessionLog instance should be different from the singletonLog because they have
// different state.
SessionLog singletonLog = null, sessionLog = null;
if (loggerClassName != null) {
SessionLog currentLog = session.getSessionLog();
if(loggerClassName.equals(LoggerType.ServerLogger)){
ServerPlatform serverPlatform = session.getServerPlatform();
singletonLog = serverPlatform.getServerLog();
sessionLog = serverPlatform.getServerLog();
} else if (!currentLog.getClass().getName().equals(loggerClassName)) {
// Logger class was specified and it's not what's already there.
Class sessionLogClass = findClassForProperty(loggerClassName, PersistenceUnitProperties.LOGGING_LOGGER, loader);
try {
singletonLog = (SessionLog)sessionLogClass.getConstructor().newInstance();
sessionLog = (SessionLog)sessionLogClass.getConstructor().newInstance();
} catch (Exception ex) {
throw EntityManagerSetupException.failedToInstantiateLogger(loggerClassName, PersistenceUnitProperties.LOGGING_LOGGER, ex);
}
}
} else if (serverPlatformChanged) {
ServerPlatform serverPlatform = session.getServerPlatform();
singletonLog = serverPlatform.getServerLog();
sessionLog = serverPlatform.getServerLog();
}
// Don't change default loggers if the new loggers have not been created.
if (singletonLog != null && sessionLog != null) {
AbstractSessionLog.setLog(singletonLog);
session.setSessionLog(sessionLog);
}
// Bug5389828. Update the logging settings for the singleton logger.
initOrUpdateLogging(persistenceProperties, AbstractSessionLog.getLog());
initOrUpdateLogging(persistenceProperties, session.getSessionLog());
// Set logging file.
String loggingFileString = (String)persistenceProperties.get(PersistenceUnitProperties.LOGGING_FILE);
if (loggingFileString != null) {
if (!loggingFileString.trim().equals("")) {
try {
if (sessionLog!=null){
if (sessionLog instanceof AbstractSessionLog) {
FileOutputStream fos = new FileOutputStream(loggingFileString);
((AbstractSessionLog)sessionLog).setWriter(fos);
} else {
FileWriter fw = new FileWriter(loggingFileString);
sessionLog.setWriter(fw);
}
}
} catch (IOException e) {
session.handleException(ValidationException.invalidLoggingFile(loggingFileString,e));
}
} else {
session.handleException(ValidationException.invalidLoggingFile());
}
}
}
/**
* Check for the PROFILER persistence or system property and set the Session's profiler.
* This can also set the QueryMonitor.
*/
protected void updateProfiler(Map persistenceProperties,ClassLoader loader) {
// This must use config property as the profiler is not in the PropertiesHandler and requires
// supporting generic profiler classes.
String newProfilerClassName = getConfigPropertyAsStringLogDebug(PersistenceUnitProperties.PROFILER, persistenceProperties, session);
if (newProfilerClassName == null) {
ServerPlatformBase plaftorm = ((ServerPlatformBase)session.getServerPlatform());
if (plaftorm != null) {
plaftorm.configureProfiler(session);
}
} else {
if (newProfilerClassName.equals(ProfilerType.NoProfiler)) {
session.setProfiler(null);
return;
}
if (newProfilerClassName.equals(ProfilerType.QueryMonitor)) {
session.setProfiler(null);
QueryMonitor.shouldMonitor=true;
return;
}
if (newProfilerClassName.equals(ProfilerType.PerformanceProfiler)) {
session.setProfiler(new PerformanceProfiler());
return;
}
if (newProfilerClassName.equals(ProfilerType.PerformanceMonitor)) {
session.setProfiler(new PerformanceMonitor());
return;
}
if (newProfilerClassName.equals(ProfilerType.DMSProfiler)) {
newProfilerClassName = ProfilerType.DMSProfilerClassName;
}
String originalProfilerClassNamer = null;
if (session.getProfiler() != null) {
originalProfilerClassNamer = session.getProfiler().getClass().getName();
if (originalProfilerClassNamer.equals(newProfilerClassName)) {
return;
}
}
// New profiler - create the new instance and set it.
try {
Class newProfilerClass = findClassForProperty(newProfilerClassName, PersistenceUnitProperties.PROFILER, loader);
SessionProfiler sessionProfiler = (SessionProfiler)buildObjectForClass(newProfilerClass, SessionProfiler.class);
if (sessionProfiler != null) {
session.setProfiler(sessionProfiler);
} else {
session.handleException(ValidationException.invalidProfilerClass(newProfilerClassName));
}
} catch (IllegalAccessException e) {
session.handleException(ValidationException.cannotInstantiateProfilerClass(newProfilerClassName,e));
} catch (PrivilegedActionException e) {
session.handleException(ValidationException.cannotInstantiateProfilerClass(newProfilerClassName,e));
} catch (InstantiationException e) {
session.handleException(ValidationException.cannotInstantiateProfilerClass(newProfilerClassName,e));
}
}
}
protected static Class findClass(String className, ClassLoader loader) throws ClassNotFoundException, PrivilegedActionException {
if (PrivilegedAccessHelper.shouldUsePrivilegedAccess()) {
return AccessController.doPrivileged(new PrivilegedClassForName<>(className, true, loader));
} else {
return org.eclipse.persistence.internal.security.PrivilegedAccessHelper.getClassForName(className, true, loader);
}
}
protected static Class findClassForProperty(String className, String propertyName, ClassLoader loader) {
ClassLoader eclipselinkLoader = EntityManagerSetupImpl.class.getClassLoader();
boolean multipleLoaders = eclipselinkLoader != loader;
if (multipleLoaders) {
return findClassForPropertyInternal(className, propertyName, loader, eclipselinkLoader);
} else {
return findClassForPropertyInternal(className, propertyName, loader);
}
}
private static Class findClassForPropertyInternal(String clsName, String propName, ClassLoader... loaders) {
RuntimeException e = null;
for (ClassLoader loader : loaders) {
try {
return findClass(clsName, loader);
} catch (PrivilegedActionException exception1) {
e = EntityManagerSetupException.classNotFoundForProperty(clsName, propName, exception1.getException());
} catch (ClassNotFoundException exception2) {
e = EntityManagerSetupException.classNotFoundForProperty(clsName, propName, exception2);
}
}
throw e;
}
/**
* Internal:
* Returns a list of StructConverter instances from a list of StructConverter names stored within the project.
*
*/
protected List<StructConverter> getStructConverters(ClassLoader realClassLoader) {
List<StructConverter> structConverters = new ArrayList<StructConverter>();
if (session.getProject().getStructConverters() != null) {
for (String converter: session.getProject().getStructConverters()) {
Class clazz = null;
try {
clazz = findClass(converter, realClassLoader);
} catch (PrivilegedActionException exception) {
throw ValidationException.unableToLoadClass(converter, exception.getException());
} catch (ClassNotFoundException exception) {
throw ValidationException.unableToLoadClass(converter, exception);
}
try {
structConverters.add((StructConverter) buildObjectForClass(clazz, StructConverter.class));
} catch (PrivilegedActionException e) {
throw ValidationException.errorInstantiatingClass(clazz, e.getException());
} catch (IllegalAccessException e) {
throw ValidationException.errorInstantiatingClass(clazz, e);
} catch (InstantiationException e) {
throw ValidationException.errorInstantiatingClass(clazz, e);
}
}
}
return structConverters;
}
protected boolean hasSchemaDatabaseGeneration(Map m) {
if (hasConfigProperty(SCHEMA_GENERATION_DATABASE_ACTION, m)) {
return getConfigPropertyAsString(SCHEMA_GENERATION_DATABASE_ACTION, m) != null && ! getConfigPropertyAsString(SCHEMA_GENERATION_DATABASE_ACTION, m).equals(SCHEMA_GENERATION_NONE_ACTION);
}
return false;
}
protected boolean hasSchemaScriptsGeneration(Map m) {
if (hasConfigProperty(SCHEMA_GENERATION_SCRIPTS_ACTION, m)) {
return getConfigPropertyAsString(SCHEMA_GENERATION_SCRIPTS_ACTION, m) != null && ! getConfigPropertyAsString(SCHEMA_GENERATION_SCRIPTS_ACTION, m).equals(SCHEMA_GENERATION_NONE_ACTION);
}
return false;
}
public AbstractSession getSession() {
return session;
}
public DatabaseSessionImpl getDatabaseSession() {
return (DatabaseSessionImpl)session;
}
/**
* We may be provided a connection via the properties to use. Check for
* one and build a database session around it. Otherwise return the pu
* database session.
*/
public DatabaseSessionImpl getDatabaseSession(Map props) {
DatabaseSessionImpl databaseSession = getDatabaseSession();
Object connection = getConfigProperty(PersistenceUnitProperties.SCHEMA_GENERATION_CONNECTION, props);
if (connection == null) {
return databaseSession;
} else {
// A connection was provided. Build a database session using that
// connection and use the same log level set on the original
// database session.
DatabaseSessionImpl newDatabaseSession = new DatabaseSessionImpl();
newDatabaseSession.setAccessor(new DatabaseAccessor(connection));
newDatabaseSession.setLogLevel(databaseSession.getLogLevel());
newDatabaseSession.setProject(databaseSession.getProject().clone());
return newDatabaseSession;
}
}
/**
* This method will be used to validate the specified class and return it's instance.
*/
protected static Object buildObjectForClass(Class clazz, Class mustBeImplementedInterface) throws IllegalAccessException, PrivilegedActionException,InstantiationException {
if(clazz!=null && Helper.classImplementsInterface(clazz,mustBeImplementedInterface)){
if (PrivilegedAccessHelper.shouldUsePrivilegedAccess()){
return AccessController.doPrivileged(new PrivilegedNewInstanceFromClass(clazz));
} else {
return PrivilegedAccessHelper.newInstanceFromClass(clazz);
}
} else {
return null;
}
}
protected void updateDescriptorCacheSettings(Map m, ClassLoader loader) {
String queryCache = getConfigPropertyAsStringLogDebug(PersistenceUnitProperties.QUERY_CACHE, m, session);
if ((queryCache != null) && queryCache.equalsIgnoreCase("true")) {
session.getProject().setDefaultQueryResultsCachePolicy(new QueryResultsCachePolicy());
}
String queryCacheForceDeferredLocks = getConfigPropertyAsStringLogDebug(PersistenceUnitProperties.CACHE_QUERY_FORCE_DEFERRED_LOCKS, m, session);
if ((queryCacheForceDeferredLocks != null) && queryCacheForceDeferredLocks.equalsIgnoreCase("true")) {
session.getProject().setQueryCacheForceDeferredLocks(true);
} else {
session.getProject().setQueryCacheForceDeferredLocks(false);
}
Map typeMap = PropertiesHandler.getPrefixValuesLogDebug(PersistenceUnitProperties.CACHE_TYPE_, m, session);
Map sizeMap = PropertiesHandler.getPrefixValuesLogDebug(PersistenceUnitProperties.CACHE_SIZE_, m, session);
Map sharedMap = PropertiesHandler.getPrefixValuesLogDebug(PersistenceUnitProperties.CACHE_SHARED_, m, session);
if(typeMap.isEmpty() && sizeMap.isEmpty() && sharedMap.isEmpty()) {
return;
}
String defaultTypeName = (String)typeMap.remove(PersistenceUnitProperties.DEFAULT);
if (defaultTypeName != null) {
// Always use the EclipseLink class loader, otherwise can have loader/redeployment issues.
Class defaultType = findClassForProperty(defaultTypeName, PersistenceUnitProperties.CACHE_TYPE_DEFAULT, getClass().getClassLoader());
session.getProject().setDefaultIdentityMapClass(defaultType);
}
String value = null;
try {
String defaultSizeString = (String)sizeMap.remove(PersistenceUnitProperties.DEFAULT);
if (defaultSizeString != null) {
value = defaultSizeString;
int defaultSize = Integer.parseInt(defaultSizeString);
session.getProject().setDefaultIdentityMapSize(defaultSize);
}
String defaultSharedString = (String)sharedMap.remove(PersistenceUnitProperties.DEFAULT);
if (defaultSharedString != null) {
boolean defaultShared = Boolean.parseBoolean(defaultSharedString);
session.getProject().setDefaultCacheIsolation(defaultShared
? CacheIsolationType.SHARED : CacheIsolationType.ISOLATED);
}
Iterator<ClassDescriptor> it = session.getDescriptors().values().iterator();
while (it.hasNext() && (!typeMap.isEmpty() || !sizeMap.isEmpty() || !sharedMap.isEmpty())) {
ClassDescriptor descriptor = it.next();
if (descriptor.isDescriptorTypeAggregate()) {
continue;
}
String entityName = descriptor.getAlias();
String className = descriptor.getJavaClass().getName();
String name;
name = entityName;
String typeName = (String)typeMap.remove(name);
if( typeName == null) {
name = className;
typeName = (String)typeMap.remove(name);
}
if (typeName != null) {
Class type = findClassForProperty(typeName, PersistenceUnitProperties.CACHE_TYPE_ + name, getClass().getClassLoader());
descriptor.setIdentityMapClass(type);
}
name = entityName;
String sizeString = (String)sizeMap.remove(name);
if (sizeString == null) {
name = className;
sizeString = (String)sizeMap.remove(name);
}
if (sizeString != null) {
value = sizeString;
int size = Integer.parseInt(sizeString);
descriptor.setIdentityMapSize(size);
}
name = entityName;
String sharedString = (String)sharedMap.remove(name);
if (sharedString == null) {
name = className;
sharedString = (String)sharedMap.remove(name);
}
if (sharedString != null) {
boolean shared = Boolean.parseBoolean(sharedString);
descriptor.setCacheIsolation(shared ? CacheIsolationType.SHARED : CacheIsolationType.ISOLATED);
}
}
} catch (NumberFormatException exception) {
this.session.handleException(ValidationException.invalidValueForProperty(value, PersistenceUnitProperties.CACHE_SIZE_, exception));
}
}
/**
* Process all properties under "eclipselink.connection-pool.".
* This allows for named connection pools.
* It also processes "read", "write", "default" and "sequence" connection pools.
*/
protected void updateConnectionSettings(ServerSession serverSession, Map properties) {
Map<String, Object> connectionsMap = PropertiesHandler.getPrefixValuesLogDebug(PersistenceUnitProperties.CONNECTION_POOL, properties, serverSession);
if (connectionsMap.isEmpty()) {
return;
}
for (Map.Entry<String, Object> entry : connectionsMap.entrySet()) {
String poolName = "default";
String attribute = null;
try {
int dotIdx = entry.getKey().indexOf('.');
if (dotIdx == -1) {
attribute = entry.getKey();
} else {
String key = entry.getKey();
poolName = key.substring(0, dotIdx);
attribute = key.substring(dotIdx + 1);
}
ConnectionPool pool = null;
if (poolName.equals("write")) {
poolName = "default";
}
if (poolName.equals("read")) {
pool = serverSession.getReadConnectionPool();
// By default there is no connection pool, so if the default, create a new one.
if ((pool == null) || (pool == serverSession.getDefaultConnectionPool())) {
if (this.session.getDatasourceLogin().shouldUseExternalConnectionPooling()) {
pool = new ExternalConnectionPool(poolName, serverSession.getDatasourceLogin(), serverSession);
} else {
pool = new ConnectionPool(poolName, serverSession.getDatasourceLogin(), serverSession);
}
serverSession.setReadConnectionPool(pool);
}
} else if (poolName.equals("sequence")) {
pool = getDatabaseSession().getSequencingControl().getConnectionPool();
if (pool == null) {
if (this.session.getDatasourceLogin().shouldUseExternalConnectionPooling()) {
pool = new ExternalConnectionPool(poolName, serverSession.getDatasourceLogin(), serverSession);
} else {
pool = new ConnectionPool(poolName, serverSession.getDatasourceLogin(), serverSession);
}
getDatabaseSession().getSequencingControl().setConnectionPool(pool);
}
} else {
pool = serverSession.getConnectionPool(poolName);
if (pool == null) {
if (this.session.getDatasourceLogin().shouldUseExternalConnectionPooling()) {
pool = new ExternalConnectionPool(poolName, serverSession.getDatasourceLogin(), serverSession);
} else {
pool = new ConnectionPool(poolName, serverSession.getDatasourceLogin(), serverSession);
}
serverSession.addConnectionPool(pool);
}
}
if (attribute.equals(PersistenceUnitProperties.CONNECTION_POOL_INITIAL)) {
pool.setInitialNumberOfConnections(Integer.parseInt((String)entry.getValue()));
} else if (attribute.equals(PersistenceUnitProperties.CONNECTION_POOL_MIN)) {
pool.setMinNumberOfConnections(Integer.parseInt((String)entry.getValue()));
} else if (attribute.equals(PersistenceUnitProperties.CONNECTION_POOL_MAX)) {
pool.setMaxNumberOfConnections(Integer.parseInt((String)entry.getValue()));
} else if (attribute.equals(PersistenceUnitProperties.CONNECTION_POOL_URL)) {
pool.setLogin(pool.getLogin().clone());
((DatabaseLogin)pool.getLogin()).setURL((String)entry.getValue());
} else if (attribute.equals(PersistenceUnitProperties.CONNECTION_POOL_NON_JTA_DATA_SOURCE)) {
pool.setLogin(pool.getLogin().clone());
((DatabaseLogin)pool.getLogin()).useDataSource((String)entry.getValue());
} else if (attribute.equals(PersistenceUnitProperties.CONNECTION_POOL_JTA_DATA_SOURCE)) {
pool.setLogin(pool.getLogin().clone());
((DatabaseLogin)pool.getLogin()).useDataSource((String)entry.getValue());
} else if (attribute.equals(PersistenceUnitProperties.CONNECTION_POOL_USER)) {
pool.setLogin(pool.getLogin().clone());
pool.getLogin().setUserName((String)entry.getValue());
} else if (attribute.equals(PersistenceUnitProperties.CONNECTION_POOL_PASSWORD)) {
pool.setLogin(pool.getLogin().clone());
pool.getLogin().setPassword((String)entry.getValue());
} else if (attribute.equals(PersistenceUnitProperties.CONNECTION_POOL_WAIT)) {
pool.setWaitTimeout(Integer.parseInt((String)entry.getValue()));
} else if (attribute.equals(PersistenceUnitProperties.CONNECTION_POOL_FAILOVER)) {
String failoverPools = (String)entry.getValue();
if ((failoverPools.indexOf(',') != -1) || (failoverPools.indexOf(' ') != -1)) {
StringTokenizer tokenizer = new StringTokenizer(failoverPools, " ,");
while (tokenizer.hasMoreTokens()) {
pool.addFailoverConnectionPool(tokenizer.nextToken());
}
} else {
pool.addFailoverConnectionPool((String)entry.getValue());
}
} else if (poolName.equals("read") && attribute.equals(PersistenceUnitProperties.CONNECTION_POOL_SHARED)) {
boolean shared = Boolean.parseBoolean((String)entry.getValue());
if (shared) {
ReadConnectionPool readPool = new ReadConnectionPool(poolName, serverSession.getDatasourceLogin(), serverSession);
readPool.setInitialNumberOfConnections(pool.getInitialNumberOfConnections());
readPool.setMinNumberOfConnections(pool.getMinNumberOfConnections());
readPool.setMaxNumberOfConnections(pool.getMaxNumberOfConnections());
readPool.setWaitTimeout(pool.getWaitTimeout());
readPool.setLogin(pool.getLogin());
serverSession.setReadConnectionPool(readPool);
}
}
} catch (RuntimeException exception) {
this.session.handleException(ValidationException.invalidValueForProperty(entry.getValue(), entry.getKey(), exception));
}
}
}
protected void updateConnectionPolicy(ServerSession serverSession, Map m) {
String isLazyString = getConfigPropertyAsStringLogDebug(PersistenceUnitProperties.EXCLUSIVE_CONNECTION_IS_LAZY, m, session);
if(isLazyString != null) {
serverSession.getDefaultConnectionPolicy().setIsLazy(Boolean.parseBoolean(isLazyString));
}
ConnectionPolicy.ExclusiveMode exclusiveMode = getConnectionPolicyExclusiveModeFromProperties(m, session, true);
if(exclusiveMode != null) {
serverSession.getDefaultConnectionPolicy().setExclusiveMode(exclusiveMode);
}
}
public static ConnectionPolicy.ExclusiveMode getConnectionPolicyExclusiveModeFromProperties(Map m, AbstractSession abstractSession, boolean useSystemAsDefault) {
String exclusiveConnectionModeString = PropertiesHandler.getPropertyValueLogDebug(PersistenceUnitProperties.EXCLUSIVE_CONNECTION_MODE, m, abstractSession, useSystemAsDefault);
if(exclusiveConnectionModeString != null) {
if(exclusiveConnectionModeString == ExclusiveConnectionMode.Isolated) {
return ConnectionPolicy.ExclusiveMode.Isolated;
} else if(exclusiveConnectionModeString == ExclusiveConnectionMode.Always) {
return ConnectionPolicy.ExclusiveMode.Always;
} else {
return ConnectionPolicy.ExclusiveMode.Transactional;
}
} else {
return null;
}
}
/**
* Perform any steps necessary prior to actual deployment. This includes any steps in the session
* creation that do not require the real loaded domain classes.
*
* The first call to this method caches persistenceUnitInfo which is reused in the following calls.
*
* Note that in JSE case factoryCount is NOT incremented on the very first call
* (by JavaSECMPInitializer.callPredeploy, typically in preMain).
* That provides 1 to 1 correspondence between factoryCount and the number of open factories.
*
* In case factoryCount &gt; 0 the method just increments factoryCount.
* factory == 0 triggers creation of a new session.
*
* This method and undeploy - the only methods altering factoryCount - should be synchronized.
*
* @return A transformer (which may be null) that should be plugged into the proper
* classloader to allow classes to be transformed as they get loaded.
* @see #deploy(ClassLoader, Map)
*/
public synchronized ClassTransformer predeploy(PersistenceUnitInfo info, Map extendedProperties) {
ClassLoader classLoaderToUse = null;
// session == null
if (state == STATE_DEPLOY_FAILED || state == STATE_UNDEPLOYED) {
throw new PersistenceException(EntityManagerSetupException.cannotPredeploy(persistenceUnitInfo.getPersistenceUnitName(), state, persistenceException));
}
// session != null
if (state == STATE_PREDEPLOYED || state == STATE_DEPLOYED || state == STATE_HALF_DEPLOYED) {
session.log(SessionLog.FINEST, SessionLog.JPA, "predeploy_begin", new Object[]{getPersistenceUnitInfo().getPersistenceUnitName(), session.getName(), state, factoryCount});
factoryCount++;
session.log(SessionLog.FINEST, SessionLog.JPA, "predeploy_end", new Object[]{getPersistenceUnitInfo().getPersistenceUnitName(), session.getName(), state, factoryCount});
return null;
// session == null
} else if (state == STATE_INITIAL) {
persistenceUnitInfo = info;
if (!isCompositeMember()) {
if (mustBeCompositeMember(persistenceUnitInfo)) {
if (this.staticWeaveInfo == null) {
return null;
} else {
// predeploy is used for static weaving
throw new PersistenceException(EntityManagerSetupException.compositeMemberCannotBeUsedStandalone(persistenceUnitInfo.getPersistenceUnitName()));
}
}
}
}
// state is INITIAL or PREDEPLOY_FAILED or STATE_HALF_PREDEPLOYED_COMPOSITE_MEMBER, session == null
try {
// properties not used in STATE_HALF_PREDEPLOYED_COMPOSITE_MEMBER
Map predeployProperties = null;
// composite can't be in STATE_HALF_PREDEPLOYED_COMPOSITE_MEMBER
boolean isComposite = false;
if(state != STATE_HALF_PREDEPLOYED_COMPOSITE_MEMBER) {
//set the claasloader early on and change it if needed
classLoaderToUse = persistenceUnitInfo.getClassLoader();
predeployProperties = mergeMaps(extendedProperties, persistenceUnitInfo.getProperties());
// Translate old properties.
// This should be done before using properties (i.e. ServerPlatform).
translateOldProperties(predeployProperties, null);
String sessionsXMLStr = (String)predeployProperties.get(PersistenceUnitProperties.SESSIONS_XML);
if (sessionsXMLStr != null) {
isSessionLoadedFromSessionsXML = true;
}
// Create session (it needs to be done before initializing ServerPlatform and logging).
// If a sessions-xml is used this will get replaced later, but is required for logging.
isComposite = isComposite(persistenceUnitInfo);
if (isComposite) {
if (isSessionLoadedFromSessionsXML) {
throw EntityManagerSetupException.compositeIncompatibleWithSessionsXml(persistenceUnitInfo.getPersistenceUnitName());
}
session = new SessionBroker();
((SessionBroker)session).setShouldUseDescriptorAliases(true);
} else {
session = new ServerSession(new Project(new DatabaseLogin()));
//set the listener to process RCM metadata refresh commands
session.setRefreshMetadataListener(this);
}
session.setName(this.sessionName);
updateTunerPreDeploy(predeployProperties, classLoaderToUse);
updateTolerateInvalidJPQL(predeployProperties);
if (this.compositeEmSetupImpl == null) {
// session name and ServerPlatform must be set prior to setting the loggers.
if (this.staticWeaveInfo == null) {
updateServerPlatform(predeployProperties, classLoaderToUse);
// Update loggers and settings for the singleton logger and the session logger.
updateLoggers(predeployProperties, true, classLoaderToUse);
// log the server platform being used by the session
if (session.getSessionLog().shouldLog(SessionLog.FINE)) {
session.getSessionLog().log(SessionLog.FINE, SessionLog.SERVER,
"configured_server_platform", session.getServerPlatform().getClass().getName()); // NOI18N
}
// Get the temporary classLoader based on the platform
//Update performance profiler
updateProfiler(predeployProperties, classLoaderToUse);
} else {
// predeploy is used for static weaving
Writer writer = this.staticWeaveInfo.getLogWriter();
if (writer != null) {
session.getSessionLog().setWriter(writer);
}
session.setLogLevel(this.staticWeaveInfo.getLogLevel());
}
} else {
// composite member
session.setSessionLog(this.compositeEmSetupImpl.session.getSessionLog());
session.setProfiler(this.compositeEmSetupImpl.session.getProfiler());
}
// Cannot start logging until session and log and initialized, so log start of predeploy here.
session.log(SessionLog.FINEST, SessionLog.JPA, "predeploy_begin", new Object[]{getPersistenceUnitInfo().getPersistenceUnitName(), session.getName(), state, factoryCount});
//Project Cache accessor processing
updateProjectCache(predeployProperties, classLoaderToUse);
if (projectCacheAccessor!=null) {
//get the project from the cache
Project project = projectCacheAccessor.retrieveProject(predeployProperties, classLoaderToUse, session.getSessionLog());
if (project!=null) {
try {
DatabaseSessionImpl tempSession = (DatabaseSessionImpl)project.createServerSession();
tempSession.setName(this.sessionName);
tempSession.setSessionLog(session.getSessionLog());
tempSession.getSessionLog().setSession(tempSession);
if (this.staticWeaveInfo != null) {
tempSession.setLogLevel(this.staticWeaveInfo.getLogLevel());
}
tempSession.setProfiler(session.getProfiler());
tempSession.setRefreshMetadataListener(this);
session = tempSession;
// reusing the serverPlatform from the existing session would have been preferred,
// but its session is only set through the ServerPlatform constructor.
updateServerPlatform(predeployProperties, classLoaderToUse);
shouldBuildProject = false;
} catch (Exception e) {
//need a better exception here
throw new PersistenceException(e);
}
}
}
if (isSessionLoadedFromSessionsXML) {
if (this.compositeEmSetupImpl == null && this.staticWeaveInfo == null) {
JPAClassLoaderHolder privateClassLoaderHolder = session.getServerPlatform().getNewTempClassLoader(persistenceUnitInfo);
classLoaderToUse = privateClassLoaderHolder.getClassLoader();
} else {
classLoaderToUse = persistenceUnitInfo.getNewTempClassLoader();
}
// Loading session from sessions-xml.
String tempSessionName = sessionName;
if (isCompositeMember()) {
// composite member session name is always the same as puName
// need the session name specified in properties to read correct session from sessions.xml
tempSessionName = (String)predeployProperties.get(PersistenceUnitProperties.SESSION_NAME);
}
session.log(SessionLog.FINEST, SessionLog.PROPERTIES, "loading_session_xml", sessionsXMLStr, tempSessionName);
if (tempSessionName == null) {
throw EntityManagerSetupException.sessionNameNeedBeSpecified(persistenceUnitInfo.getPersistenceUnitName(), sessionsXMLStr);
}
XMLSessionConfigLoader xmlLoader = new XMLSessionConfigLoader(sessionsXMLStr);
// Do not register the session with the SessionManager at this point, create temporary session using a local SessionManager and private class loader.
// This allows for the project to be accessed without loading any of the classes to allow weaving.
// Note that this method assigns sessionName to session.
Session tempSession = new SessionManager().getSession(xmlLoader, tempSessionName, classLoaderToUse, false, false);
// Load path of sessions-xml resource before throwing error so user knows which sessions-xml file was found (may be multiple).
session.log(SessionLog.FINEST, SessionLog.PROPERTIES, "sessions_xml_path_where_session_load_from", xmlLoader.getSessionName(), xmlLoader.getResourcePath());
if (tempSession == null) {
throw ValidationException.noSessionFound(sessionName, sessionsXMLStr);
}
// Currently the session must be either a ServerSession or a SessionBroker, cannot be just a DatabaseSessionImpl.
if (tempSession.isServerSession() || tempSession.isSessionBroker()) {
session = (DatabaseSessionImpl) tempSession;
if (tempSessionName != sessionName) {
// set back the original session name
session.setName(sessionName);
}
} else {
throw EntityManagerSetupException.sessionLoadedFromSessionsXMLMustBeServerSession(persistenceUnitInfo.getPersistenceUnitName(), (String)predeployProperties.get(PersistenceUnitProperties.SESSIONS_XML), tempSession);
}
if (this.staticWeaveInfo == null) {
// Must now reset logging and server-platform on the loaded session.
// ServerPlatform must be set prior to setting the loggers.
updateServerPlatform(predeployProperties, classLoaderToUse);
// Update loggers and settings for the singleton logger and the session logger.
updateLoggers(predeployProperties, true, classLoaderToUse);
}
} else {
classLoaderToUse = persistenceUnitInfo.getClassLoader();
}
warnOldProperties(predeployProperties, session);
session.getPlatform().setConversionManager(new JPAConversionManager());
if (this.staticWeaveInfo == null) {
if (!isComposite) {
PersistenceUnitTransactionType transactionType=null;
//bug 5867753: find and override the transaction type
String transTypeString = getConfigPropertyAsStringLogDebug(PersistenceUnitProperties.TRANSACTION_TYPE, predeployProperties, session);
if (transTypeString != null && transTypeString.length() > 0) {
transactionType=PersistenceUnitTransactionType.valueOf(transTypeString);
} else if (persistenceUnitInfo!=null){
transactionType=persistenceUnitInfo.getTransactionType();
}
if (!isValidationOnly(predeployProperties, false) && persistenceUnitInfo != null && transactionType == PersistenceUnitTransactionType.JTA) {
if (predeployProperties.get(PersistenceUnitProperties.JTA_DATASOURCE) == null && persistenceUnitInfo.getJtaDataSource() == null) {
if (predeployProperties.get(PersistenceUnitProperties.SCHEMA_DATABASE_PRODUCT_NAME) == null ||
predeployProperties.get(PersistenceUnitProperties.SCHEMA_DATABASE_MAJOR_VERSION) == null ||
predeployProperties.get(PersistenceUnitProperties.SCHEMA_DATABASE_MINOR_VERSION) == null) {
throw EntityManagerSetupException.jtaPersistenceUnitInfoMissingJtaDataSource(persistenceUnitInfo.getPersistenceUnitName());
}
}
}
}
// this flag is used to disable work done as a result of the LAZY hint on OneToOne and ManyToOne mappings
if(state == STATE_INITIAL) {
if (compositeEmSetupImpl == null) {
if(null == enableWeaving) {
enableWeaving = Boolean.TRUE;
}
isWeavingStatic = false;
String weaving = getConfigPropertyAsString(PersistenceUnitProperties.WEAVING, predeployProperties);
if (weaving != null && weaving.equalsIgnoreCase("false")) {
enableWeaving = Boolean.FALSE;
}else if (weaving != null && weaving.equalsIgnoreCase("static")) {
isWeavingStatic = true;
}
} else {
// composite member
// no weaving for composite forces no weaving for members
if (!compositeEmSetupImpl.enableWeaving) {
enableWeaving = Boolean.FALSE;
} else {
if(null == enableWeaving) {
enableWeaving = Boolean.TRUE;
}
String weaving = getConfigPropertyAsString(PersistenceUnitProperties.WEAVING, predeployProperties);
if (weaving != null && weaving.equalsIgnoreCase("false")) {
enableWeaving = Boolean.FALSE;
}
}
// static weaving is dictated by composite
isWeavingStatic = compositeEmSetupImpl.isWeavingStatic;
}
}
if (compositeEmSetupImpl == null) {
throwExceptionOnFail = "true".equalsIgnoreCase(
EntityManagerFactoryProvider.getConfigPropertyAsStringLogDebug(PersistenceUnitProperties.THROW_EXCEPTIONS, predeployProperties, "true", session));
} else {
// composite member
throwExceptionOnFail = compositeEmSetupImpl.throwExceptionOnFail;
}
} else {
// predeploy is used for static weaving
enableWeaving = Boolean.TRUE;
}
weaveChangeTracking = false;
weaveLazy = false;
weaveEager = false;
weaveFetchGroups = false;
weaveInternal = false;
weaveRest = false;
weaveMappedSuperClass = false;
if (enableWeaving) {
weaveChangeTracking = "true".equalsIgnoreCase(EntityManagerFactoryProvider.getConfigPropertyAsStringLogDebug(PersistenceUnitProperties.WEAVING_CHANGE_TRACKING, predeployProperties, "true", session));
weaveLazy = "true".equalsIgnoreCase(EntityManagerFactoryProvider.getConfigPropertyAsStringLogDebug(PersistenceUnitProperties.WEAVING_LAZY, predeployProperties, "true", session));
weaveEager = "true".equalsIgnoreCase(EntityManagerFactoryProvider.getConfigPropertyAsStringLogDebug(PersistenceUnitProperties.WEAVING_EAGER, predeployProperties, "false", session));
weaveFetchGroups = "true".equalsIgnoreCase(EntityManagerFactoryProvider.getConfigPropertyAsStringLogDebug(PersistenceUnitProperties.WEAVING_FETCHGROUPS, predeployProperties, "true", session));
weaveInternal = "true".equalsIgnoreCase(EntityManagerFactoryProvider.getConfigPropertyAsStringLogDebug(PersistenceUnitProperties.WEAVING_INTERNAL, predeployProperties, "true", session));
weaveRest = "true".equalsIgnoreCase(EntityManagerFactoryProvider.getConfigPropertyAsStringLogDebug(PersistenceUnitProperties.WEAVING_REST, predeployProperties, shouldWeaveRestByDefault(classLoaderToUse), session));
weaveMappedSuperClass = "true".equalsIgnoreCase(EntityManagerFactoryProvider.getConfigPropertyAsStringLogDebug(PersistenceUnitProperties.WEAVING_MAPPEDSUPERCLASS, predeployProperties, "true", session));
}
}
if (shouldBuildProject && !isSessionLoadedFromSessionsXML ) {
if (isComposite) {
predeployCompositeMembers(predeployProperties, classLoaderToUse);
} else {
MetadataProcessor compositeProcessor = null;
if (compositeEmSetupImpl == null) {
mode = PersistenceUnitProcessor.Mode.ALL;
} else {
// composite member
if (state != STATE_HALF_PREDEPLOYED_COMPOSITE_MEMBER) {
state = STATE_HALF_PREDEPLOYED_COMPOSITE_MEMBER;
mode = PersistenceUnitProcessor.Mode.COMPOSITE_MEMBER_INITIAL;
}
compositeProcessor = compositeEmSetupImpl.processor;
}
if (mode == PersistenceUnitProcessor.Mode.ALL || mode == PersistenceUnitProcessor.Mode.COMPOSITE_MEMBER_INITIAL) {
boolean usesMultitenantSharedEmf = "true".equalsIgnoreCase(EntityManagerFactoryProvider.getConfigPropertyAsStringLogDebug(PersistenceUnitProperties.MULTITENANT_SHARED_EMF, predeployProperties, "true", session));
boolean usesMultitenantSharedCache = "true".equalsIgnoreCase(EntityManagerFactoryProvider.getConfigPropertyAsStringLogDebug(PersistenceUnitProperties.MULTITENANT_SHARED_CACHE, predeployProperties, "false", session));
// Create an instance of MetadataProcessor for specified persistence unit info
processor = new MetadataProcessor(persistenceUnitInfo, session, classLoaderToUse, weaveLazy, weaveEager, weaveFetchGroups, usesMultitenantSharedEmf, usesMultitenantSharedCache, predeployProperties, compositeProcessor);
//need to use the real classloader to create the repository class
updateMetadataRepository(predeployProperties, classLoaderToUse);
//bug:299926 - Case insensitive table / column matching with native SQL queries
EntityManagerSetupImpl.updateCaseSensitivitySettings(predeployProperties, processor.getProject(), session);
}
// Set the shared cache mode to the jakarta.persistence.sharedCache.mode property value.
updateSharedCacheMode(predeployProperties);
// Process the Object/relational metadata from XML and annotations.
// If Java Security is enabled, surround this call with a doPrivileged block.
if (PrivilegedAccessHelper.shouldUsePrivilegedAccess()) {
AccessController.doPrivileged(new PrivilegedAction<Void>() {
@Override
public Void run() {
PersistenceUnitProcessor.processORMetadata(processor, throwExceptionOnFail, mode);
return null;
}
});
} else {
PersistenceUnitProcessor.processORMetadata(processor, throwExceptionOnFail, mode);
}
if (mode == PersistenceUnitProcessor.Mode.COMPOSITE_MEMBER_INITIAL) {
mode = PersistenceUnitProcessor.Mode.COMPOSITE_MEMBER_MIDDLE;
session.log(SessionLog.FINEST, SessionLog.JPA, "predeploy_end", new Object[]{getPersistenceUnitInfo().getPersistenceUnitName(), session.getName(), state + " " + mode , factoryCount});
return null;
} else if (mode == PersistenceUnitProcessor.Mode.COMPOSITE_MEMBER_MIDDLE) {
mode = PersistenceUnitProcessor.Mode.COMPOSITE_MEMBER_FINAL;
session.log(SessionLog.FINEST, SessionLog.JPA, "predeploy_end", new Object[]{getPersistenceUnitInfo().getPersistenceUnitName(), session.getName(), state + " " + mode , factoryCount});
return null;
}
// mode == PersistenceUnitProcessor.Mode.ALL || mode == PersistenceUnitProcessor.Mode.COMPOSITE_MEMBER_FINAL
// clear mode and proceed
mode = null;
if (session.getIntegrityChecker().hasErrors()){
session.handleException(new IntegrityException(session.getIntegrityChecker()));
}
// The transformer is capable of altering domain classes to handle a LAZY hint for OneToOne mappings. It will only
// be returned if we we are mean to process these mappings
if (enableWeaving) {
// build a list of entities the persistence unit represented by this EntityManagerSetupImpl will use
Collection<MetadataClass> entities = PersistenceUnitProcessor.buildEntityList(processor, classLoaderToUse);
this.weaver = TransformerFactory.createTransformerAndModifyProject(session, entities, classLoaderToUse, weaveLazy, weaveChangeTracking, weaveFetchGroups, weaveInternal, weaveRest, weaveMappedSuperClass);
session.getProject().setClassNamesForWeaving(new ArrayList<>(processor.getProject().getWeavableClassNames()));
}
//moved from deployment:
processor.addNamedQueries();
processor.addStructConverterNames();
}
} else {
//This means this session is from sessions.xml or a cached project
// The transformer is capable of altering domain classes to handle a LAZY hint for OneToOne mappings. It will only
// be returned if we we are meant to process these mappings.
if (enableWeaving) {
Collection<MetadataClass> persistenceClasses = new ArrayList<>();
MetadataAsmFactory factory = new MetadataAsmFactory(new MetadataLogger(session), classLoaderToUse);
if (shouldBuildProject) {
// If deploying from a sessions-xml it is still desirable to allow the classes to be weaved.
// build a list of entities the persistence unit represented by this EntityManagerSetupImpl will use
for (Iterator<Class<?>> iterator = session.getProject().getDescriptors().keySet().iterator(); iterator.hasNext(); ) {
persistenceClasses.add(factory.getMetadataClass(iterator.next().getName()));
}
} else {
// build a list of entities the persistence unit represented by this EntityManagerSetupImpl will use
for (String className : session.getProject().getClassNamesForWeaving()) {
persistenceClasses.add(factory.getMetadataClass(className));
}
}
this.weaver = TransformerFactory.createTransformerAndModifyProject(session, persistenceClasses, classLoaderToUse, weaveLazy, weaveChangeTracking, weaveFetchGroups, weaveInternal, weaveRest, weaveMappedSuperClass);
}
}
// composite member never has a factory - it is predeployed by the composite.
if (!isCompositeMember()) {
// factoryCount is not incremented only in case of a first call to preDeploy
// in non-container mode: this call is not associated with a factory
// but rather done by JavaSECMPInitializer.callPredeploy (typically in preMain).
if(state != STATE_INITIAL || this.isInContainerMode()) {
factoryCount++;
}
preInitializeMetamodel();
}
state = STATE_PREDEPLOYED;
session.log(SessionLog.FINEST, SessionLog.JPA, "predeploy_end", new Object[]{getPersistenceUnitInfo().getPersistenceUnitName(), session.getName(), state, factoryCount});
//gf3146: if static weaving is used, we should not return a transformer. Transformer should still be created though as it modifies descriptors
if (isWeavingStatic) {
return null;
} else {
return this.weaver;
}
} catch (Throwable ex) {
state = STATE_PREDEPLOY_FAILED;
// cache this.persistenceException before slow logging
PersistenceException persistenceEx = createPredeployFailedPersistenceException(ex);
// If session exists, use it for logging
if (session != null) {
session.log(SessionLog.FINEST, SessionLog.JPA, "predeploy_end", new Object[]{getPersistenceUnitInfo().getPersistenceUnitName(), session.getName(), state, factoryCount});
// If at least staticWeaveInfo exists, use it for logging
} else if (staticWeaveInfo != null && staticWeaveInfo.getLogLevel() <= SessionLog.FINEST) {
Writer logWriter = staticWeaveInfo.getLogWriter();
if (logWriter != null) {
String message = LoggingLocalization.buildMessage("predeploy_end", new Object[]{getPersistenceUnitInfo().getPersistenceUnitName(), "N/A", state, factoryCount});
try {
logWriter.write(message);
logWriter.write(Helper.cr());
} catch (IOException ioex) {
// Ignore IOException
}
}
}
session = null;
mode = null;
throw persistenceEx;
}
}
protected PersistenceException createPredeployFailedPersistenceException(Throwable ex) {
PersistenceException perEx = new PersistenceException(EntityManagerSetupException.predeployFailed(persistenceUnitInfo.getPersistenceUnitName(), ex));
if (persistenceException == null) {
persistenceException = perEx;
}
return perEx;
}
/**
* Return the name of the session this SetupImpl is building. The session name is only known at deploy
* time and if this method is called prior to that, this method will return null.
*/
public String getDeployedSessionName(){
return session != null ? session.getName() : null;
}
public PersistenceUnitInfo getPersistenceUnitInfo(){
return persistenceUnitInfo;
}
public boolean isValidationOnly(Map m) {
return isValidationOnly(m, true);
}
protected boolean isValidationOnly(Map m, boolean shouldMergeMap) {
if (shouldMergeMap) {
m = mergeWithExistingMap(m);
}
String validationOnlyString = getConfigPropertyAsStringLogDebug(PersistenceUnitProperties.VALIDATION_ONLY_PROPERTY, m, session);
if (validationOnlyString != null) {
return Boolean.parseBoolean(validationOnlyString);
} else {
return false;
}
}
/**
* Return if the session should be deployed and connected during the creation of the EntityManagerFactory,
* or if it should be deferred until createEntityManager().
* The default is to defer, but is only validating, or can be configured to deploy upfront to avoid hanging the
* application at runtime.
*/
public boolean shouldGetSessionOnCreateFactory(Map m) {
m = mergeWithExistingMap(m);
if (isValidationOnly(m, false)) {
return true;
}
String deployString = getConfigPropertyAsStringLogDebug(PersistenceUnitProperties.DEPLOY_ON_STARTUP, m, this.session);
if (deployString != null) {
return Boolean.parseBoolean(deployString);
} else {
// If DDL schame generation is turned on, we need to deploy.
return hasSchemaDatabaseGeneration(m) || hasSchemaScriptsGeneration(m);
}
}
protected Map mergeWithExistingMap(Map m) {
if(persistenceUnitInfo != null) {
return mergeMaps(m, persistenceUnitInfo.getProperties());
} else {
return m;
}
}
public boolean isInContainerMode(){
return isInContainerMode;
}
/**
* Configure cache coordination using properties.
*/
protected void updateCacheCoordination(Map m, ClassLoader loader) {
String protocol = getConfigPropertyAsStringLogDebug(PersistenceUnitProperties.COORDINATION_PROTOCOL, m, this.session);
String value = "";
String property = "";
try {
if (protocol != null) {
RemoteCommandManager rcm = new RemoteCommandManager(this.session);
if (protocol.equalsIgnoreCase(CacheCoordinationProtocol.JGROUPS)) {
property = PersistenceUnitProperties.COORDINATION_PROTOCOL;
value = "org.eclipse.persistence.sessions.coordination.jgroups.JGroupsTransportManager";
// Avoid compile and runtime dependency.
Class transportClass = findClassForProperty(value, PersistenceUnitProperties.COORDINATION_PROTOCOL, loader);
TransportManager transport = (TransportManager)transportClass.getConstructor().newInstance();
rcm.setTransportManager(transport);
String config = getConfigPropertyAsStringLogDebug(PersistenceUnitProperties.COORDINATION_JGROUPS_CONFIG, m, this.session);
if (config != null) {
transport.setConfig(config);
}
} else if (protocol.equalsIgnoreCase(CacheCoordinationProtocol.JMS) || protocol.equalsIgnoreCase(CacheCoordinationProtocol.JMSPublishing)) {
JMSPublishingTransportManager transport = null;
if (protocol.equalsIgnoreCase(CacheCoordinationProtocol.JMS)) {
transport = new JMSTopicTransportManager(rcm);
} else {
transport = new JMSPublishingTransportManager(rcm);
}
rcm.setTransportManager(transport);
String host = getConfigPropertyAsStringLogDebug(PersistenceUnitProperties.COORDINATION_JMS_HOST, m, this.session);
if (host != null) {
transport.setTopicHostUrl(host);
}
String topic = getConfigPropertyAsStringLogDebug(PersistenceUnitProperties.COORDINATION_JMS_TOPIC, m, this.session);
if (topic != null) {
transport.setTopicName(topic);
}
String factory = getConfigPropertyAsStringLogDebug(PersistenceUnitProperties.COORDINATION_JMS_FACTORY, m, this.session);
if (factory != null) {
transport.setTopicConnectionFactoryName(factory);
}
String reuse_publisher = getConfigPropertyAsStringLogDebug(PersistenceUnitProperties.COORDINATION_JMS_REUSE_PUBLISHER, m, this.session);
if (reuse_publisher != null) {
transport.setShouldReuseJMSTopicPublisher(reuse_publisher.equalsIgnoreCase("true"));
}
} else if (protocol.equalsIgnoreCase(CacheCoordinationProtocol.RMI) || protocol.equalsIgnoreCase(CacheCoordinationProtocol.RMIIIOP)) {
if (protocol.equalsIgnoreCase(CacheCoordinationProtocol.RMIIIOP)) {
((RMITransportManager) rcm.getTransportManager()).setIsRMIOverIIOP(true);
}
// Default protocol.
String delay = getConfigPropertyAsStringLogDebug(PersistenceUnitProperties.COORDINATION_RMI_ANNOUNCEMENT_DELAY, m, this.session);
property = PersistenceUnitProperties.COORDINATION_RMI_ANNOUNCEMENT_DELAY;
value = delay;
if (delay != null) {
rcm.getDiscoveryManager().setAnnouncementDelay(Integer.parseInt(delay));
}
String multicast = getConfigPropertyAsStringLogDebug(PersistenceUnitProperties.COORDINATION_RMI_MULTICAST_GROUP, m, this.session);
if (multicast != null) {
rcm.getDiscoveryManager().setMulticastGroupAddress(multicast);
}
String port = getConfigPropertyAsStringLogDebug(PersistenceUnitProperties.COORDINATION_RMI_MULTICAST_GROUP_PORT, m, this.session);
property = PersistenceUnitProperties.COORDINATION_RMI_MULTICAST_GROUP_PORT;
value = port;
if (port != null) {
rcm.getDiscoveryManager().setMulticastPort(Integer.parseInt(port));
}
String timeToLive = getConfigPropertyAsStringLogDebug(PersistenceUnitProperties.COORDINATION_RMI_PACKET_TIME_TO_LIVE, m, this.session);
property = PersistenceUnitProperties.COORDINATION_RMI_PACKET_TIME_TO_LIVE;
value = timeToLive;
if (timeToLive != null) {
rcm.getDiscoveryManager().setPacketTimeToLive(Integer.parseInt(timeToLive));
}
String url = getConfigPropertyAsStringLogDebug(PersistenceUnitProperties.COORDINATION_RMI_URL, m, this.session);
if (url != null) {
rcm.setUrl(url);
}
} else {
property = PersistenceUnitProperties.COORDINATION_PROTOCOL;
value = protocol;
Class transportClass = findClassForProperty(protocol, PersistenceUnitProperties.COORDINATION_PROTOCOL, loader);
rcm.setTransportManager((TransportManager)transportClass.getConstructor().newInstance());
}
String serializer = getConfigPropertyAsStringLogDebug(PersistenceUnitProperties.COORDINATION_SERIALIZER, m, this.session);
if (serializer != null) {
property = PersistenceUnitProperties.COORDINATION_SERIALIZER;
value = serializer;
Class transportClass = findClassForProperty(serializer, PersistenceUnitProperties.COORDINATION_SERIALIZER, loader);
rcm.setSerializer((Serializer)transportClass.getConstructor().newInstance());
}
String naming = getConfigPropertyAsStringLogDebug(PersistenceUnitProperties.COORDINATION_NAMING_SERVICE, m, this.session);
if (naming != null) {
if (naming.equalsIgnoreCase("jndi")) {
rcm.getTransportManager().setNamingServiceType(TransportManager.JNDI_NAMING_SERVICE);
} else if (naming.equalsIgnoreCase("rmi")) {
rcm.getTransportManager().setNamingServiceType(TransportManager.REGISTRY_NAMING_SERVICE);
}
}
String user = getConfigPropertyAsStringLogDebug(PersistenceUnitProperties.COORDINATION_JNDI_USER, m, this.session);
if (user != null) {
rcm.getTransportManager().setUserName(user);
}
String password = getConfigPropertyAsStringLogDebug(PersistenceUnitProperties.COORDINATION_JNDI_PASSWORD, m, this.session);
if (password != null) {
rcm.getTransportManager().setPassword(password);
}
String context = getConfigPropertyAsStringLogDebug(PersistenceUnitProperties.COORDINATION_JNDI_CONTEXT, m, this.session);
if (context != null) {
rcm.getTransportManager().setInitialContextFactoryName(context);
}
String removeOnError = getConfigPropertyAsStringLogDebug(PersistenceUnitProperties.COORDINATION_REMOVE_CONNECTION, m, this.session);
if (removeOnError != null) {
rcm.getTransportManager().setShouldRemoveConnectionOnError(removeOnError.equalsIgnoreCase("true"));
}
String asynch = getConfigPropertyAsStringLogDebug(PersistenceUnitProperties.COORDINATION_ASYNCH, m, this.session);
if (asynch != null) {
rcm.setShouldPropagateAsynchronously(asynch.equalsIgnoreCase("true"));
}
String threadPoolSize = getConfigPropertyAsStringLogDebug(PersistenceUnitProperties.COORDINATION_THREAD_POOL_SIZE, m, this.session);
property = PersistenceUnitProperties.COORDINATION_THREAD_POOL_SIZE;
value = threadPoolSize;
if (threadPoolSize != null) {
this.session.getServerPlatform().setThreadPoolSize(Integer.parseInt(threadPoolSize));
}
String channel = getConfigPropertyAsStringLogDebug(PersistenceUnitProperties.COORDINATION_CHANNEL, m, this.session);
if (channel != null) {
rcm.setChannel(channel);
}
this.session.setCommandManager(rcm);
this.session.setShouldPropagateChanges(true);
}
} catch (ReflectiveOperationException | NumberFormatException exception) {
this.session.handleException(ValidationException.invalidValueForProperty(value, property, exception));
}
}
/**
* Update session serializer.
*/
protected void updateSerializer(Map m, ClassLoader loader) {
String serializer = getConfigPropertyAsStringLogDebug(PersistenceUnitProperties.SERIALIZER, m, this.session);
if (serializer != null) {
if (serializer.length() > 0) {
try {
Class transportClass = findClassForProperty(serializer, PersistenceUnitProperties.SERIALIZER, loader);
this.session.setSerializer((Serializer)transportClass.getConstructor().newInstance());
} catch (Exception exception) {
this.session.handleException(ValidationException.invalidValueForProperty(serializer, PersistenceUnitProperties.SERIALIZER, exception));
}
} else {
this.session.setSerializer(JavaSerializer.instance);
}
}
}
/**
* Update whether session ShouldOptimizeResultSetAccess.
*/
protected void updateShouldOptimizeResultSetAccess(Map m) {
String resultSetAccessOptimization = PropertiesHandler.getPropertyValueLogDebug(PersistenceUnitProperties.JDBC_RESULT_SET_ACCESS_OPTIMIZATION, m, this.session);
if (resultSetAccessOptimization != null) {
this.session.setShouldOptimizeResultSetAccess(resultSetAccessOptimization.equals("true"));
}
}
/**
* Update whether session should use externally defined multi tenancy.
*/
protected void updateTenancy(Map m, ClassLoader loader) {
String tenantStrategy = getConfigPropertyAsStringLogDebug(PersistenceUnitProperties.MULTITENANT_STRATEGY, m, this.session);
if(tenantStrategy != null) {
if ("external".equalsIgnoreCase(tenantStrategy)) {
SchemaPerMultitenantPolicy policy = new SchemaPerMultitenantPolicy();
String prop = getConfigPropertyAsStringLogDebug(PersistenceUnitProperties.MULTITENANT_SHARED_EMF, m, session);
if (prop != null) {
policy.setShouldUseSharedEMF(Boolean.parseBoolean(prop));
}
prop = getConfigPropertyAsStringLogDebug(PersistenceUnitProperties.MULTITENANT_SHARED_CACHE, m, session);
if (prop != null) {
policy.setShouldUseSharedCache(Boolean.parseBoolean(prop));
}
session.getProject().setMultitenantPolicy(policy);
} else {
//assume it is a class with default constructor implementing existing interface
Class cls = findClassForProperty(tenantStrategy, PersistenceUnitProperties.MULTITENANT_STRATEGY, loader);
MultitenantPolicy policy = null;
try {
Constructor constructor = cls.getConstructor();
policy = (MultitenantPolicy) constructor.newInstance();
} catch (NoSuchMethodException | SecurityException | InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException ex) {
throw EntityManagerSetupException.failedToInstantiateProperty(tenantStrategy, PersistenceUnitProperties.MULTITENANT_STRATEGY, ex);
}
session.getProject().setMultitenantPolicy(policy);
}
}
}
/**
* Update whether session should tolerate invalid JPQL at creation time.
*/
protected void updateTolerateInvalidJPQL(Map m) {
String config =
PropertiesHandler.getPropertyValueLogDebug(PersistenceUnitProperties.JPQL_TOLERATE, m, this.session);
// Tolerate invalid JPQL is ignored if running in validation only mode
if (config != null && isValidationOnly(m) == false) {
this.session.setTolerateInvalidJPQL(config.equals("true"));
}
}
/**
* Override the default login creation method.
* If persistenceInfo is available, use the information from it to setup the login
* and possibly to set readConnectionPool.
*/
protected void updateLogins(Map m){
DatasourceLogin login = (DatasourceLogin)this.session.getDatasourceLogin();
String eclipselinkPlatform = PropertiesHandler.getPropertyValueLogDebug(PersistenceUnitProperties.TARGET_DATABASE, m, this.session);
if (eclipselinkPlatform != null) {
login.setPlatformClassName(eclipselinkPlatform, this.persistenceUnitInfo.getClassLoader());
}
// Check for EIS platform, need to use an EIS login.
boolean isEIS = false;
if (login.getDatasourcePlatform() instanceof EISPlatform) {
isEIS = true;
EISLogin newLogin = new EISLogin();
newLogin.setDatasourcePlatform(login.getDatasourcePlatform());
this.session.setDatasourceLogin(newLogin);
if (this.session.isServerSession()) {
for (ConnectionPool pool : ((ServerSession)this.session).getConnectionPools().values()) {
pool.setLogin(newLogin);
}
}
login = newLogin;
}
// Check for EIS or custom (JDBC) Connector class.
Object connectorValue = getConfigPropertyLogDebug(PersistenceUnitProperties.NOSQL_CONNECTION_SPEC, m, this.session);
String connectorProperty = PersistenceUnitProperties.NOSQL_CONNECTION_SPEC;
if (connectorValue == null) {
connectorValue = getConfigPropertyLogDebug(PersistenceUnitProperties.JDBC_CONNECTOR, m, this.session);
connectorProperty = PersistenceUnitProperties.JDBC_CONNECTOR;
}
if (connectorValue instanceof Connector) {
login.setConnector((Connector)connectorValue);
} else if (connectorValue instanceof String) {
Class cls = null;
// Try both class loaders.
try {
cls = findClassForProperty((String)connectorValue, connectorProperty, this.persistenceUnitInfo.getClassLoader());
} catch (Throwable failed) {
cls = findClassForProperty((String)connectorValue, connectorProperty, getClass().getClassLoader());
}
Connector connector = null;
try {
Constructor constructor = cls.getConstructor();
connector = (Connector)constructor.newInstance();
} catch (Exception exception) {
throw EntityManagerSetupException.failedToInstantiateProperty((String)connectorValue, connectorProperty, exception);
}
if (connector != null) {
login.setConnector(connector);
}
} else if (connectorValue != null) {
// Assume JCA connection spec.
((EISConnectionSpec)login.getConnector()).setConnectionSpecObject(connectorValue);
}
// Check for EIS ConnectionFactory.
Object factoryValue = getConfigPropertyLogDebug(PersistenceUnitProperties.NOSQL_CONNECTION_FACTORY, m, this.session);
if (factoryValue instanceof String) {
// JNDI name.
((EISConnectionSpec)login.getConnector()).setName((String)factoryValue);
} else if (factoryValue != null) {
((EISConnectionSpec)login.getConnector()).setConnectionFactoryObject(factoryValue);
}
// Process EIS or JDBC connection properties.
Map propertiesMap = PropertiesHandler.getPrefixValuesLogDebug(PersistenceUnitProperties.NOSQL_PROPERTY, m, session);
if (propertiesMap.isEmpty()) {
propertiesMap = PropertiesHandler.getPrefixValuesLogDebug(PersistenceUnitProperties.JDBC_PROPERTY, m, session);
}
for (Iterator iterator = propertiesMap.entrySet().iterator(); iterator.hasNext(); ) {
Map.Entry entry = (Map.Entry)iterator.next();
String property = (String)entry.getKey();
Object value = entry.getValue();
login.setProperty(property, value);
}
// Note: This call does not checked the stored persistenceUnitInfo or extended properties because
// the map passed into this method should represent the full set of properties we expect to process
String user = getConfigPropertyAsStringLogDebug(PersistenceUnitProperties.JDBC_USER, m, this.session);
String password = getConfigPropertyAsStringLogDebug(PersistenceUnitProperties.JDBC_PASSWORD, m, this.session);
if(user != null) {
login.setUserName(user);
}
if (password != null) {
login.setPassword(this.securableObjectHolder.getSecurableObject().decryptPassword(password));
}
PersistenceUnitTransactionType transactionType = this.persistenceUnitInfo.getTransactionType();
//bug 5867753: find and override the transaction type using properties
String transTypeString = getConfigPropertyAsStringLogDebug(PersistenceUnitProperties.TRANSACTION_TYPE, m, this.session);
if (transTypeString != null && transTypeString.length() > 0) {
transactionType = PersistenceUnitTransactionType.valueOf(transTypeString);
}
//find the jta datasource
javax.sql.DataSource jtaDatasource = getDatasourceFromProperties(m, PersistenceUnitProperties.JTA_DATASOURCE, this.persistenceUnitInfo.getJtaDataSource());
//find the non jta datasource
javax.sql.DataSource nonjtaDatasource = getDatasourceFromProperties(m, PersistenceUnitProperties.NON_JTA_DATASOURCE, this.persistenceUnitInfo.getNonJtaDataSource());
if (isValidationOnly(m, false) && transactionType == PersistenceUnitTransactionType.JTA && jtaDatasource == null) {
updateLoginDefaultConnector(login, m);
return;
}
login.setUsesExternalTransactionController(transactionType == PersistenceUnitTransactionType.JTA);
// Avoid processing data-source if EIS, as container may pass in a default one.
if (isEIS) {
return;
}
javax.sql.DataSource mainDatasource = null;
javax.sql.DataSource readDatasource = null;
if (login.shouldUseExternalTransactionController()) {
// JtaDataSource is guaranteed to be non null - otherwise exception would've been thrown earlier
mainDatasource = jtaDatasource;
// only define readDatasource if there is jta mainDatasource
readDatasource = nonjtaDatasource;
} else {
// JtaDataSource will be ignored because transactionType is RESOURCE_LOCAL
if (jtaDatasource != null) {
session.log(SessionLog.WARNING, SessionLog.TRANSACTION, "resource_local_persistence_init_info_ignores_jta_data_source", this.persistenceUnitInfo.getPersistenceUnitName());
}
if (nonjtaDatasource != null) {
mainDatasource = nonjtaDatasource;
} else {
updateLoginDefaultConnector(login, m);
return;
}
}
// mainDatasource is guaranteed to be non null - TODO: No it is not, if they did not set one it is null, should raise error, not null-pointer.
if (!(login.getConnector() instanceof JNDIConnector)) {
JNDIConnector jndiConnector;
if (mainDatasource instanceof DataSourceImpl) {
//Bug5209363 Pass in the datasource name instead of the dummy datasource
jndiConnector = new JNDIConnector(((DataSourceImpl)mainDatasource).getName());
} else {
jndiConnector = new JNDIConnector(mainDatasource);
}
login.setConnector(jndiConnector);
String useInternalConnectionPool = getConfigPropertyAsStringLogDebug(PersistenceUnitProperties.CONNECTION_POOL_INTERNALLY_POOL_DATASOURCE, m, this.session);
if (!"true".equalsIgnoreCase(useInternalConnectionPool)){
login.setUsesExternalConnectionPooling(true);
}
}
if (this.session.isServerSession()) {
// set readLogin
if (readDatasource != null) {
DatasourceLogin readLogin = login.clone();
readLogin.dontUseExternalTransactionController();
JNDIConnector jndiConnector;
if (readDatasource instanceof DataSourceImpl) {
//Bug5209363 Pass in the datasource name instead of the dummy datasource
jndiConnector = new JNDIConnector(((DataSourceImpl)readDatasource).getName());
} else {
jndiConnector = new JNDIConnector(readDatasource);
}
readLogin.setConnector(jndiConnector);
((ServerSession)this.session).setReadConnectionPool(readLogin);
}
}
}
/**
* This is used to return either the defaultDatasource or, if one exists, a datasource
* defined under the property from the Map m. This method will build a DataSourceImpl
* object to hold the url if the property in Map m defines a string instead of a datasource.
*/
protected javax.sql.DataSource getDatasourceFromProperties(Map m, String property, javax.sql.DataSource defaultDataSource){
Object datasource = getConfigPropertyLogDebug(property, m, session);
if ( datasource == null ){
return defaultDataSource;
}
if ( datasource instanceof String){
if(((String)datasource).length() > 0) {
// Create a dummy DataSource that will throw an exception on access
return new DataSourceImpl((String)datasource, null, null, null);
} else {
// allow an empty string data source property passed to createEMF to cancel data source specified in persistence.xml
return null;
}
}
if ( !(datasource instanceof javax.sql.DataSource) ){
//A warning should be enough. Though an error might be better, the properties passed in could contain anything
session.log(SessionLog.WARNING, SessionLog.PROPERTIES, "invalid_datasource_property_value", property, datasource);
return defaultDataSource;
}
return (javax.sql.DataSource)datasource;
}
/**
* In cases where there is no data source, we will use properties to configure the login for
* our session. This method gets those properties and sets them on the login.
*/
protected void updateLoginDefaultConnector(DatasourceLogin login, Map m){
//Login info might be already set with sessions.xml and could be overridden by session customizer after this
//If login has default connector then JDBC properties update(override) the login info
if ((login.getConnector() instanceof DefaultConnector)) {
DatabaseLogin dbLogin = (DatabaseLogin)login;
// Note: This call does not checked the stored persistenceUnitInfo or extended properties because
// the map passed into this method should represent the full set of properties we expect to process
String jdbcDriver = getConfigPropertyAsStringLogDebug(PersistenceUnitProperties.JDBC_DRIVER, m, session);
String connectionString = getConfigPropertyAsStringLogDebug(PersistenceUnitProperties.JDBC_URL, m, session);
if(connectionString != null) {
dbLogin.setConnectionString(connectionString);
}
if(jdbcDriver != null) {
dbLogin.setDriverClassName(jdbcDriver);
}
}
}
/**
* Configure the internal connection pooling parameters.
* By default if nothing is configured a default shared (exclusive) read/write pool is used with 32 min/max connections and 1 initial.
*/
@SuppressWarnings("deprecation")
protected void updatePools(ServerSession serverSession, Map m) {
String value = null;
String property = null;
try {
// Configure default/write connection pool.
// Sizes are irrelevant for external connection pool
if (!serverSession.getDefaultConnectionPool().getLogin().shouldUseExternalConnectionPooling()) {
// CONNECTION and WRITE_CONNECTION properties both configure the default pool (mean the same thing, but WRITE normally used with READ).
property = PersistenceUnitProperties.JDBC_CONNECTIONS_MIN;
value = getConfigPropertyAsStringLogDebug(property, m, serverSession);
if (value != null) {
serverSession.getDefaultConnectionPool().setMinNumberOfConnections(Integer.parseInt(value));
}
property = PersistenceUnitProperties.JDBC_CONNECTIONS_MAX;
value = getConfigPropertyAsStringLogDebug(property, m, serverSession);
if (value != null) {
serverSession.getDefaultConnectionPool().setMaxNumberOfConnections(Integer.parseInt(value));
}
property = PersistenceUnitProperties.JDBC_CONNECTIONS_INITIAL;
value = getConfigPropertyAsStringLogDebug(property, m, serverSession);
if (value != null) {
serverSession.getDefaultConnectionPool().setInitialNumberOfConnections(Integer.parseInt(value));
}
property = PersistenceUnitProperties.JDBC_WRITE_CONNECTIONS_MIN;
value = getConfigPropertyAsStringLogDebug(property, m, serverSession);
if (value != null) {
serverSession.getDefaultConnectionPool().setMinNumberOfConnections(Integer.parseInt(value));
}
property = PersistenceUnitProperties.JDBC_WRITE_CONNECTIONS_MAX;
value = getConfigPropertyAsStringLogDebug(property, m, serverSession);
if (value != null) {
serverSession.getDefaultConnectionPool().setMaxNumberOfConnections(Integer.parseInt(value));
}
property = PersistenceUnitProperties.JDBC_WRITE_CONNECTIONS_INITIAL;
value = getConfigPropertyAsStringLogDebug(property, m, serverSession);
if (value != null) {
serverSession.getDefaultConnectionPool().setInitialNumberOfConnections(Integer.parseInt(value));
}
}
// Configure read connection pool if set.
// Sizes and shared option are irrelevant for external connection pool
if (!serverSession.getReadConnectionPool().getLogin().shouldUseExternalConnectionPooling()) {
String shared = getConfigPropertyAsStringLogDebug(PersistenceUnitProperties.JDBC_READ_CONNECTIONS_SHARED, m, serverSession);
boolean isShared = false;
if (shared != null) {
isShared = Boolean.parseBoolean(shared);
}
ConnectionPool pool = null;
if (isShared) {
pool = new ReadConnectionPool("read", serverSession.getReadConnectionPool().getLogin(), serverSession);
} else {
pool = new ConnectionPool("read", serverSession.getReadConnectionPool().getLogin(), serverSession);
}
String min = getConfigPropertyAsStringLogDebug(PersistenceUnitProperties.JDBC_READ_CONNECTIONS_MIN, m, serverSession);
if (min != null) {
value = min;
property = PersistenceUnitProperties.JDBC_READ_CONNECTIONS_MIN;
pool.setMinNumberOfConnections(Integer.parseInt(min));
}
String max = getConfigPropertyAsStringLogDebug(PersistenceUnitProperties.JDBC_READ_CONNECTIONS_MAX, m, serverSession);
if (max != null) {
value = max;
property = PersistenceUnitProperties.JDBC_READ_CONNECTIONS_MAX;
pool.setMaxNumberOfConnections(Integer.parseInt(max));
}
String initial = getConfigPropertyAsStringLogDebug(PersistenceUnitProperties.JDBC_READ_CONNECTIONS_INITIAL, m, serverSession);
if (initial != null) {
value = initial;
property = PersistenceUnitProperties.JDBC_READ_CONNECTIONS_INITIAL;
pool.setInitialNumberOfConnections(Integer.parseInt(initial));
}
// Only set the read pool if they configured it, otherwise use default shared read/write.
if (isShared || (min != null) || (max != null) || (initial != null)) {
serverSession.setReadConnectionPool(pool);
}
String wait = getConfigPropertyAsStringLogDebug(PersistenceUnitProperties.JDBC_CONNECTIONS_WAIT, m, serverSession);
if (wait != null) {
value = wait;
property = PersistenceUnitProperties.JDBC_CONNECTIONS_WAIT;
serverSession.getDefaultConnectionPool().setWaitTimeout(Integer.parseInt(wait));
pool.setWaitTimeout(Integer.parseInt(wait));
}
}
// Configure sequence connection pool if set.
String sequence = getConfigPropertyAsStringLogDebug(PersistenceUnitProperties.JDBC_SEQUENCE_CONNECTION_POOL, m, serverSession);
if (sequence != null) {
serverSession.getSequencingControl().setShouldUseSeparateConnection(Boolean.parseBoolean(sequence));
}
String sequenceDataSource = getConfigPropertyAsStringLogDebug(PersistenceUnitProperties.JDBC_SEQUENCE_CONNECTION_POOL_DATASOURCE, m, serverSession);
if (sequenceDataSource != null) {
DatasourceLogin login = this.session.getLogin().clone();
login.dontUseExternalTransactionController();
JNDIConnector jndiConnector = new JNDIConnector(sequenceDataSource);
login.setConnector(jndiConnector);
serverSession.getSequencingControl().setLogin(login);
}
// Sizes and shared option are irrelevant for external connection pool
if (!serverSession.getReadConnectionPool().getLogin().shouldUseExternalConnectionPooling()) {
value = getConfigPropertyAsStringLogDebug(PersistenceUnitProperties.JDBC_SEQUENCE_CONNECTION_POOL_MIN, m, serverSession);
if (value != null) {
property = PersistenceUnitProperties.JDBC_SEQUENCE_CONNECTION_POOL_MIN;
serverSession.getSequencingControl().setMinPoolSize(Integer.parseInt(value));
}
value = getConfigPropertyAsStringLogDebug(PersistenceUnitProperties.JDBC_SEQUENCE_CONNECTION_POOL_MAX, m, serverSession);
if (value != null) {
property = PersistenceUnitProperties.JDBC_SEQUENCE_CONNECTION_POOL_MAX;
serverSession.getSequencingControl().setMaxPoolSize(Integer.parseInt(value));
}
value = getConfigPropertyAsStringLogDebug(PersistenceUnitProperties.JDBC_SEQUENCE_CONNECTION_POOL_INITIAL, m, serverSession);
if (value != null) {
property = PersistenceUnitProperties.JDBC_SEQUENCE_CONNECTION_POOL_INITIAL;
serverSession.getSequencingControl().setInitialPoolSize(Integer.parseInt(value));
}
}
} catch (NumberFormatException exception) {
serverSession.handleException(ValidationException.invalidValueForProperty(value, property, exception));
}
}
/**
* Normally when a property is missing nothing should be applied to the session.
* However there are several session attributes that defaulted in EJB3 to the values
* different from EclipseLink defaults.
* This function applies defaults for such properties and registers the session.
* All other session-related properties are applied in updateServerSession.
* Note that updateSession may be called several times on the same session
* (before login), but initSession is called just once - before the first call
* to updateSession.
*/
protected void initSession() {
assignCMP3Policy();
if(!isCompositeMember()) {
// Register session that has been created earlier.
addSessionToGlobalSessionManager();
}
}
/**
* Make any changes to our ServerSession that can be made after it is created.
*/
protected void updateSession(Map m, ClassLoader loader) {
if (session == null || (session.isDatabaseSession() && ((DatabaseSessionImpl)session).isLoggedIn())) {
return;
}
// In deploy ServerPlatform could've changed which will affect the loggers.
boolean serverPlatformChanged = updateServerPlatform(m, loader);
updateJPQLParser(m);
if (!session.hasBroker()) {
updateLoggers(m, serverPlatformChanged, loader);
updateProfiler(m,loader);
}
// log the server platform being used by the session if it has been changed
if (serverPlatformChanged && session.getSessionLog().shouldLog(SessionLog.FINE)) {
session.getSessionLog().log(SessionLog.FINE, SessionLog.SERVER,
"configured_server_platform", session.getServerPlatform().getClass().getName()); // NOI18N
}
if(session.isBroker()) {
PersistenceUnitTransactionType transactionType = persistenceUnitInfo.getTransactionType();
//bug 5867753: find and override the transaction type using properties
String transTypeString = getConfigPropertyAsStringLogDebug(PersistenceUnitProperties.TRANSACTION_TYPE, m, session);
if (transTypeString != null) {
transactionType = PersistenceUnitTransactionType.valueOf(transTypeString);
}
((DatasourceLogin)session.getDatasourceLogin()).setUsesExternalTransactionController(transactionType == PersistenceUnitTransactionType.JTA);
} else {
String shouldBindString = getConfigPropertyAsStringLogDebug(PersistenceUnitProperties.JDBC_BIND_PARAMETERS, m, session);
if (shouldBindString != null) {
session.getPlatform().setShouldBindAllParameters(Boolean.parseBoolean(shouldBindString));
}
String shouldForceBindString = getConfigPropertyAsStringLogDebug(PersistenceUnitProperties.JDBC_FORCE_BIND_PARAMETERS, m, session);
if(shouldForceBindString != null) {
session.getPlatform().setShouldForceBindAllParameters(Boolean.parseBoolean(shouldForceBindString));
}
updateLogins(m);
}
if (!session.getDatasourceLogin().shouldUseExternalTransactionController()) {
session.getServerPlatform().disableJTA();
}
if(session.isServerSession()) {
updatePools((ServerSession)session, m);
updateConnectionSettings((ServerSession)session, m);
if (!isSessionLoadedFromSessionsXML) {
updateDescriptorCacheSettings(m, loader);
}
updateConnectionPolicy((ServerSession)session, m);
}
if(session.isBroker()) {
if (this.compositeMemberEmSetupImpls != null) {
// composite
Map compositeMemberMapOfProperties = (Map)getConfigProperty(PersistenceUnitProperties.COMPOSITE_UNIT_PROPERTIES, m);
for(EntityManagerSetupImpl compositeMemberEmSetupImpl : this.compositeMemberEmSetupImpls) {
// the properties guaranteed to be non-null after updateCompositeMemberProperties call
String compositeMemberPuName = compositeMemberEmSetupImpl.getPersistenceUnitInfo().getPersistenceUnitName();
Map compositeMemberProperties = (Map)compositeMemberMapOfProperties.get(compositeMemberPuName);
// debug output added to make it easier to navigate the log because the method is called outside of composite member deploy
compositeMemberEmSetupImpl.session.log(SessionLog.FINEST, SessionLog.PROPERTIES, "composite_member_begin_call", new Object[]{"updateSession", compositeMemberPuName, state});
compositeMemberEmSetupImpl.updateSession(compositeMemberProperties, loader);
compositeMemberEmSetupImpl.session.log(SessionLog.FINEST, SessionLog.PROPERTIES, "composite_member_end_call", new Object[]{"updateSession", compositeMemberPuName, state});
}
}
setSessionEventListener(m, loader);
setExceptionHandler(m, loader);
updateAllowZeroIdSetting(m);
updateCacheCoordination(m, loader);
processSessionCustomizer(m, loader);
} else {
setSessionEventListener(m, loader);
setExceptionHandler(m, loader);
updateBatchWritingSetting(m, loader);
updateNativeSQLSetting(m);
updateSequencing(m);
updateSequencingStart(m);
updateAllowNativeSQLQueriesSetting(m);
updateSQLCastSetting(m);
updateUppercaseSetting(m);
updateCacheStatementSettings(m);
updateAllowExtendedCacheLogging(m);
updateAllowExtendedThreadLogging(m);
updateAllowExtendedThreadLoggingThreadDump(m);
updateTemporalMutableSetting(m);
updateTableCreationSettings(m);
updateIndexForeignKeys(m);
if (!session.hasBroker()) {
updateAllowZeroIdSetting(m);
}
updateIdValidation(m);
updatePessimisticLockTimeout(m);
updatePessimisticLockTimeoutUnit(m);
updateQueryTimeout(m);
updateQueryTimeoutUnit(m);
updateLockingTimestampDefault(m);
updateSQLCallDeferralDefault(m);
updateNamingIntoIndexed(m);
if (!session.hasBroker()) {
updateCacheCoordination(m, loader);
}
updatePartitioning(m, loader);
updateDatabaseEventListener(m, loader);
updateSerializer(m, loader);
updateShouldOptimizeResultSetAccess(m);
updateTolerateInvalidJPQL(m);
updateTenancy(m, loader);
// ConcurrencyManager properties
updateConcurrencyManagerWaitTime(m);
updateConcurrencyManagerBuildObjectCompleteWaitTime(m);
updateConcurrencyManagerMaxAllowedSleepTime(m);
updateConcurrencyManagerMaxAllowedFrequencyToProduceTinyDumpLogMessage(m);
updateConcurrencyManagerMaxAllowedFrequencyToProduceMassiveDumpLogMessage(m);
updateConcurrencyManagerAllowInterruptedExceptionFired(m);
updateConcurrencyManagerAllowConcurrencyExceptionToBeFiredUp(m);
updateConcurrencyManagerAllowTakingStackTraceDuringReadLockAcquisition(m);
updateConcurrencyManagerUseObjectBuildingSemaphore(m);
updateConcurrencyManagerUseWriteLockManagerSemaphore(m);
updateConcurrencyManagerNoOfThreadsAllowedToObjectBuildInParallel(m);
updateConcurrencyManagerNoOfThreadsAllowedToDoWriteLockManagerAcquireRequiredLocksInParallel(m);
updateConcurrencySemaphoreMaxTimePermit(m);
updateConcurrencySemaphoreLogTimeout(m);
// Customizers should be processed last
processDescriptorCustomizers(m, loader);
processSessionCustomizer(m, loader);
setDescriptorNamedQueries(m);
}
}
/**
* This sets the isInContainerMode flag.
* "true" indicates container case, "false" - SE.
*/
public void setIsInContainerMode(boolean isInContainerMode) {
this.isInContainerMode = isInContainerMode;
}
/**
* Used to indicate that an EntityManagerFactoryImpl based on this
* EntityManagerSetupImpl has been refreshed. This means this EntityManagerSetupImpl
* will no longer be associated with new EntityManagerFactories
*/
public void setIsMetadataExpired(boolean hasExpiredMetadata) {
this.isMetadataExpired = hasExpiredMetadata;
}
protected void processSessionCustomizer(Map m, ClassLoader loader) {
SessionCustomizer sessionCustomizer;
Object customizer = getConfigPropertyLogDebug(PersistenceUnitProperties.SESSION_CUSTOMIZER, m, session);
if (customizer == null) {
return;
}
if (customizer instanceof String) {
Class sessionCustomizerClass = findClassForProperty((String) customizer, PersistenceUnitProperties.SESSION_CUSTOMIZER, loader);
try {
sessionCustomizer = (SessionCustomizer) sessionCustomizerClass.getConstructor().newInstance();
} catch (Exception ex) {
throw EntityManagerSetupException.failedWhileProcessingProperty(PersistenceUnitProperties.SESSION_CUSTOMIZER, (String) customizer, ex);
}
} else {
sessionCustomizer = (SessionCustomizer) customizer;
}
try {
sessionCustomizer.customize(session);
} catch (Exception ex) {
throw EntityManagerSetupException.failedWhileProcessingProperty(PersistenceUnitProperties.SESSION_CUSTOMIZER, customizer.toString(), ex);
}
}
protected void initOrUpdateLogging(Map m, SessionLog log) {
String logLevelString = PropertiesHandler.getPropertyValueLogDebug(PersistenceUnitProperties.LOGGING_LEVEL, m, session);
if (logLevelString != null) {
log.setLevel(AbstractSessionLog.translateStringToLoggingLevel(logLevelString));
}
// category-specific logging level
Map categoryLogLevelMap = PropertiesHandler.getPrefixValuesLogDebug(PersistenceUnitProperties.CATEGORY_LOGGING_LEVEL_, m, session);
if(!categoryLogLevelMap.isEmpty()) {
Iterator it = categoryLogLevelMap.entrySet().iterator();
while (it.hasNext()) {
Map.Entry entry = (Map.Entry)it.next();
String category = (String)entry.getKey();
String value = (String)entry.getValue();
log.setLevel(AbstractSessionLog.translateStringToLoggingLevel(value), category);
}
}
String tsString = getConfigPropertyAsStringLogDebug(PersistenceUnitProperties.LOGGING_TIMESTAMP, m, session);
if (tsString != null) {
log.setShouldPrintDate(Boolean.parseBoolean(tsString));
}
String threadString = getConfigPropertyAsStringLogDebug(PersistenceUnitProperties.LOGGING_THREAD, m, session);
if (threadString != null) {
log.setShouldPrintThread(Boolean.parseBoolean(threadString));
}
String sessionString = getConfigPropertyAsStringLogDebug(PersistenceUnitProperties.LOGGING_SESSION, m, session);
if (sessionString != null) {
log.setShouldPrintSession(Boolean.parseBoolean(sessionString));
}
String connectionString = getConfigPropertyAsStringLogDebug(PersistenceUnitProperties.LOGGING_CONNECTION, m, session);
if (connectionString != null) {
log.setShouldPrintConnection(Boolean.parseBoolean(connectionString));
}
String exString = getConfigPropertyAsStringLogDebug(PersistenceUnitProperties.LOGGING_EXCEPTIONS, m, session);
if (exString != null) {
log.setShouldLogExceptionStackTrace(Boolean.parseBoolean(exString));
}
String shouldDisplayData = getConfigPropertyAsStringLogDebug(PersistenceUnitProperties.LOGGING_PARAMETERS, m, session);
if (shouldDisplayData != null) {
log.setShouldDisplayData(Boolean.parseBoolean(shouldDisplayData));
}
}
protected void processDescriptorCustomizers(Map m, ClassLoader loader) {
Map customizerMap = PropertiesHandler.getPrefixValuesLogDebug(PersistenceUnitProperties.DESCRIPTOR_CUSTOMIZER_, m, session);
if (customizerMap.isEmpty()) {
return;
}
Iterator it = customizerMap.entrySet().iterator();
while (it.hasNext()) {
Map.Entry entry = (Map.Entry)it.next();
String name = (String)entry.getKey();
String customizerClassName = (String)entry.getValue();
ClassDescriptor descriptor = session.getDescriptorForAlias(name);
if (descriptor == null) {
try {
Class javaClass = findClass(name, loader);
descriptor = session.getDescriptor(javaClass);
} catch (Exception ex) {
throw EntityManagerSetupException.failedWhileProcessingProperty(PersistenceUnitProperties.DESCRIPTOR_CUSTOMIZER_ + name, customizerClassName, ex);
}
}
if (descriptor != null) {
Class customizerClass = findClassForProperty(customizerClassName, PersistenceUnitProperties.DESCRIPTOR_CUSTOMIZER_ + name, loader);
try {
DescriptorCustomizer customizer = (DescriptorCustomizer)customizerClass.getConstructor().newInstance();
customizer.customize(descriptor);
} catch (Exception ex) {
throw EntityManagerSetupException.failedWhileProcessingProperty(PersistenceUnitProperties.DESCRIPTOR_CUSTOMIZER_ + name, customizerClassName, ex);
}
} else {
// TODO throw a better error, missing descriptor for property.
throw EntityManagerSetupException.failedWhileProcessingProperty(PersistenceUnitProperties.DESCRIPTOR_CUSTOMIZER_ + name, customizerClassName, null);
}
}
}
public boolean isInitial() {
return state == STATE_INITIAL;
}
/**
* Used to indicate that an EntityManagerFactoryImpl based on this
* EntityManagerSetupImpl has been refreshed. This means this EntityManagerSetupImpl
* will no longer be associated with new EntityManagerFactories
*/
public boolean isMetadataExpired() {
return isMetadataExpired;
}
public boolean isPredeployed() {
return state == STATE_PREDEPLOYED;
}
public boolean isDeployed() {
return state == STATE_DEPLOYED;
}
public boolean isHalfDeployed() {
return state == STATE_HALF_DEPLOYED;
}
public boolean isUndeployed() {
return state == STATE_UNDEPLOYED;
}
public boolean isPredeployFailed() {
return state == STATE_PREDEPLOY_FAILED;
}
public boolean isDeployFailed() {
return state == STATE_DEPLOY_FAILED;
}
public boolean isHalfPredeployedCompositeMember() {
return state == STATE_HALF_PREDEPLOYED_COMPOSITE_MEMBER;
}
public String getPersistenceUnitUniqueName() {
return this.persistenceUnitUniqueName;
}
public int getFactoryCount() {
return factoryCount;
}
public String getSessionName() {
return this.sessionName;
}
public boolean shouldRedeploy() {
return state == STATE_UNDEPLOYED || state == STATE_PREDEPLOY_FAILED;
}
/**
* Return if MetadataSource refresh commands should be sent when refresh is called
* Checks the PersistenceUnitProperties.METADATA_SOURCE_RCM_COMMAND property and defaults to true.
*/
public boolean shouldSendMetadataRefreshCommand(Map m) {
String sendCommand = getConfigPropertyAsStringLogDebug(PersistenceUnitProperties.METADATA_SOURCE_RCM_COMMAND, m, this.session);
if (sendCommand != null) {
return Boolean.parseBoolean(sendCommand);
} else {
return true;
}
}
/**
* Undeploy may be called several times, but only the call that decreases
* factoryCount to 0 disconnects the session and removes it from the session manager.
* This method and predeploy - the only methods altering factoryCount - should be synchronized.
* After undeploy call that turns factoryCount to 0:
* session==null;
* PREDEPLOYED, DEPLOYED and DEPLOYED_FAILED states change to UNDEPLOYED state.
*/
public synchronized void undeploy() {
if (state == STATE_INITIAL || state == STATE_PREDEPLOY_FAILED || state == STATE_UNDEPLOYED) {
// must already have factoryCount==0 and session==null
return;
}
// state is PREDEPLOYED, DEPLOYED or DEPLOY_FAILED
session.log(SessionLog.FINEST, SessionLog.JPA, "undeploy_begin", new Object[]{getPersistenceUnitInfo().getPersistenceUnitName(), session.getName(), state, factoryCount});
try {
factoryCount--;
if(factoryCount > 0) {
return;
}
synchronized (EntityManagerFactoryProvider.emSetupImpls) {
state = STATE_UNDEPLOYED;
removeSessionFromGlobalSessionManager();
// remove undeployed emSetupImpl from the map
EntityManagerSetupImpl emSetupImpl = EntityManagerFactoryProvider.emSetupImpls.get(sessionName);
if ((emSetupImpl != null) && (emSetupImpl.equals(this))) {
EntityManagerFactoryProvider.emSetupImpls.remove(sessionName);
}
}
} finally {
session.log(SessionLog.FINEST, SessionLog.JPA, "undeploy_end", new Object[]{getPersistenceUnitInfo().getPersistenceUnitName(), session.getName(), state, factoryCount});
if(state == STATE_UNDEPLOYED) {
session = null;
}
}
}
/**
* INTERNAL:
* By default we require a connection to the database. However, when
* generating schema to scripts only, this is not required.
*/
public void setRequiresConnection(boolean requiresConnection) {
this.requiresConnection = requiresConnection;
}
/**
* Allow customized session event listener to be added into session.
* The method needs to be called in deploy stage.
*/
protected void setSessionEventListener(Map m, ClassLoader loader){
//Set event listener if it has been specified.
String sessionEventListenerClassName = EntityManagerFactoryProvider.getConfigPropertyAsStringLogDebug(PersistenceUnitProperties.SESSION_EVENT_LISTENER_CLASS, m, session);
if(sessionEventListenerClassName!=null){
Class sessionEventListenerClass = findClassForProperty(sessionEventListenerClassName,PersistenceUnitProperties.SESSION_EVENT_LISTENER_CLASS, loader);
try {
SessionEventListener sessionEventListener = (SessionEventListener)buildObjectForClass(sessionEventListenerClass, SessionEventListener.class);
if(sessionEventListener!=null){
session.getEventManager().addListener(sessionEventListener);
} else {
session.handleException(ValidationException.invalidSessionEventListenerClass(sessionEventListenerClassName));
}
} catch (IllegalAccessException e) {
session.handleException(ValidationException.cannotInstantiateSessionEventListenerClass(sessionEventListenerClassName,e));
} catch (PrivilegedActionException e) {
session.handleException(ValidationException.cannotInstantiateSessionEventListenerClass(sessionEventListenerClassName,e));
} catch (InstantiationException e) {
session.handleException(ValidationException.cannotInstantiateSessionEventListenerClass(sessionEventListenerClassName,e));
}
}
}
/**
* Allow customized exception handler to be added into session.
* The method needs to be called in deploy and pre-deploy stage.
*/
protected void setExceptionHandler(Map m, ClassLoader loader){
//Set exception handler if it was specified.
String exceptionHandlerClassName = EntityManagerFactoryProvider.getConfigPropertyAsStringLogDebug(PersistenceUnitProperties.EXCEPTION_HANDLER_CLASS, m, session);
if(exceptionHandlerClassName!=null){
Class exceptionHandlerClass = findClassForProperty(exceptionHandlerClassName,PersistenceUnitProperties.EXCEPTION_HANDLER_CLASS, loader);
try {
ExceptionHandler exceptionHandler = (ExceptionHandler)buildObjectForClass(exceptionHandlerClass, ExceptionHandler.class);
if (exceptionHandler!=null){
session.setExceptionHandler(exceptionHandler);
} else {
session.handleException(ValidationException.invalidExceptionHandlerClass(exceptionHandlerClassName));
}
} catch (IllegalAccessException e) {
session.handleException(ValidationException.cannotInstantiateExceptionHandlerClass(exceptionHandlerClassName,e));
} catch (PrivilegedActionException e) {
session.handleException(ValidationException.cannotInstantiateExceptionHandlerClass(exceptionHandlerClassName,e));
} catch (InstantiationException e) {
session.handleException(ValidationException.cannotInstantiateExceptionHandlerClass(exceptionHandlerClassName,e));
}
}
}
/**
* Update batch writing setting.
* The method needs to be called in deploy stage.
*/
protected void updateBatchWritingSetting(Map persistenceProperties, ClassLoader loader) {
String batchWritingSettingString = PropertiesHandler.getPropertyValueLogDebug(PersistenceUnitProperties.BATCH_WRITING, persistenceProperties, this.session);
if (batchWritingSettingString != null) {
this.session.getPlatform().setUsesBatchWriting(batchWritingSettingString != BatchWriting.None);
if (batchWritingSettingString == BatchWriting.JDBC) {
this.session.getPlatform().setUsesJDBCBatchWriting(true);
this.session.getPlatform().setUsesNativeBatchWriting(false);
} else if (batchWritingSettingString == BatchWriting.Buffered) {
this.session.getPlatform().setUsesJDBCBatchWriting(false);
this.session.getPlatform().setUsesNativeBatchWriting(false);
} else if (batchWritingSettingString == BatchWriting.OracleJDBC) {
this.session.getPlatform().setUsesNativeBatchWriting(true);
this.session.getPlatform().setUsesJDBCBatchWriting(true);
} else if (batchWritingSettingString == BatchWriting.None) {
// Nothing required.
} else {
if (batchWritingSettingString.equalsIgnoreCase("ExaLogic")) {
batchWritingSettingString = "oracle.toplink.exalogic.batch.DynamicParameterizedBatchWritingMechanism";
}
Class cls = findClassForProperty(batchWritingSettingString, PersistenceUnitProperties.BATCH_WRITING, loader);
BatchWritingMechanism mechanism = null;
try {
Constructor constructor = cls.getConstructor();
mechanism = (BatchWritingMechanism)constructor.newInstance();
} catch (Exception exception) {
if (batchWritingSettingString.indexOf('.') == -1) {
throw new IllegalArgumentException(ExceptionLocalization.buildMessage("ejb30-illegal-property-value", new Object[]{PersistenceUnitProperties.BATCH_WRITING, batchWritingSettingString}));
} else {
throw EntityManagerSetupException.failedToInstantiateProperty(batchWritingSettingString, PersistenceUnitProperties.BATCH_WRITING, exception);
}
}
this.session.getPlatform().setBatchWritingMechanism(mechanism);
}
}
// Set batch size.
String sizeString = EntityManagerFactoryProvider.getConfigPropertyAsStringLogDebug(PersistenceUnitProperties.BATCH_WRITING_SIZE, persistenceProperties, this.session);
if (sizeString != null) {
try {
this.session.getPlatform().setMaxBatchWritingSize(Integer.parseInt(sizeString));
} catch (NumberFormatException invalid) {
session.handleException(ValidationException.invalidValueForProperty(sizeString, PersistenceUnitProperties.BATCH_WRITING_SIZE, invalid));
}
}
}
/**
* Load the Metadata Repository for Extensibility
*/
protected void updateMetadataRepository(Map m, ClassLoader loader){
Object metadataSource = EntityManagerFactoryProvider.getConfigPropertyLogDebug(PersistenceUnitProperties.METADATA_SOURCE, m, session);
if (metadataSource != null && metadataSource instanceof MetadataSource){
processor.setMetadataSource((MetadataSource)metadataSource);
} else {
if (metadataSource!=null) {
String repository = (String)metadataSource;
if (repository.equalsIgnoreCase("XML")) {
processor.setMetadataSource(new XMLMetadataSource());
} else {
Class transportClass = findClassForProperty(repository, PersistenceUnitProperties.METADATA_SOURCE, loader);
try {
processor.setMetadataSource((MetadataSource)transportClass.getConstructor().newInstance());
} catch (Exception invalid) {
session.handleException(EntityManagerSetupException.failedToInstantiateProperty(repository, PersistenceUnitProperties.METADATA_SOURCE,invalid));
}
}
}
}
}
/**
* Check for a tuning property and run the tuner preDeploy.
*/
protected void updateTunerPreDeploy(Map m, ClassLoader loader) {
String tuning = (String)EntityManagerFactoryProvider.getConfigPropertyLogDebug(PersistenceUnitProperties.TUNING, m, this.session);
if (tuning != null) {
SessionTuner tuner = null;
if (tuning.equalsIgnoreCase("Safe")) {
tuner = new SafeModeTuner();
} else if (tuning.equalsIgnoreCase("Standard")) {
tuner = new StandardTuner();
} else {
if (tuning.equalsIgnoreCase("ExaLogic")) {
tuning = "oracle.toplink.exalogic.tuning.ExaLogicTuner";
}
Class tunerClass = findClassForProperty(tuning, PersistenceUnitProperties.TUNING, loader);
try {
tuner = (SessionTuner)tunerClass.getConstructor().newInstance();
} catch (Exception invalid) {
this.session.handleException(EntityManagerSetupException.failedToInstantiateProperty(tuning, PersistenceUnitProperties.TUNING, invalid));
}
}
getDatabaseSession().setTuner(tuner);
if (tuner != null) {
tuner.tunePreDeploy(m);
}
}
}
/**
* Check for a tuning property and run the tuner deploy.
*/
protected void updateTunerDeploy(Map m, ClassLoader loader) {
if (getDatabaseSession().getTuner() != null) {
getDatabaseSession().getTuner().tuneDeploy(getDatabaseSession());
}
}
/**
* Check for a tuning property and run the tuner deploy.
*/
protected void updateTunerPostDeploy(Map m, ClassLoader loader) {
if (getDatabaseSession().getTuner() != null) {
getDatabaseSession().getTuner().tunePostDeploy(getDatabaseSession());
}
}
/**
* Allow the deployment metadata to be freed post-deploy to conserve memory.
*/
protected void updateFreeMemory(Map m) {
String freeMemory = EntityManagerFactoryProvider.getConfigPropertyAsStringLogDebug(PersistenceUnitProperties.FREE_METADATA, m, session);
if (freeMemory != null) {
if (freeMemory.equalsIgnoreCase("true")) {
XMLEntityMappingsReader.clear();
} else if (freeMemory.equalsIgnoreCase("false")) {
// default.
} else {
session.handleException(ValidationException.invalidBooleanValueForProperty(freeMemory, PersistenceUnitProperties.FREE_METADATA));
}
}
}
/**
* Enable or disable the capability of Native SQL function.
* The method needs to be called in deploy stage.
*/
protected void updateNativeSQLSetting(Map m){
//Set Native SQL flag if it was specified.
String nativeSQLString = EntityManagerFactoryProvider.getConfigPropertyAsStringLogDebug(PersistenceUnitProperties.NATIVE_SQL, m, session);
if(nativeSQLString!=null){
if(nativeSQLString.equalsIgnoreCase("true") ){
session.getProject().getLogin().useNativeSQL();
}else if (nativeSQLString.equalsIgnoreCase("false")){
session.getProject().getLogin().dontUseNativeSQL();
}else{
session.handleException(ValidationException.invalidBooleanValueForSettingNativeSQL(nativeSQLString));
}
}
}
/**
* Configure sequencing settings.
*/
protected void updateSequencing(Map m){
String useTable = EntityManagerFactoryProvider.getConfigPropertyAsStringLogDebug(PersistenceUnitProperties.SEQUENCING_SEQUENCE_DEFAULT, m, session);
if (useTable != null) {
if (useTable.equalsIgnoreCase("true")) {
this.session.getPlatform().setDefaultNativeSequenceToTable(true);
} else if (useTable.equalsIgnoreCase("false")) {
this.session.getPlatform().setDefaultNativeSequenceToTable(false);
} else {
this.session.handleException(ValidationException.invalidBooleanValueForProperty(useTable, PersistenceUnitProperties.SEQUENCING_SEQUENCE_DEFAULT));
}
}
}
protected void updateSequencingStart(Map m) {
String local = EntityManagerFactoryProvider.getConfigPropertyAsStringLogDebug(PersistenceUnitProperties.SEQUENCING_START_AT_NEXTVAL, m, session);
try {
if (local != null) {
this.session.getPlatform().setDefaultSeqenceAtNextValue(Boolean.parseBoolean(local));
}
} catch (NumberFormatException exception) {
this.session.handleException(ValidationException.invalidValueForProperty(local, PersistenceUnitProperties.USE_LOCAL_TIMESTAMP, exception));
}
}
/**
* Load the projectCacheAccessor for JPA project caching
*/
protected void updateProjectCache(Map m, ClassLoader loader){
Object accessor = EntityManagerFactoryProvider.getConfigPropertyLogDebug(PersistenceUnitProperties.PROJECT_CACHE, m, session);
if (accessor != null ) {
if (accessor instanceof ProjectCache) {
projectCacheAccessor = (ProjectCache)accessor;
} else {
String accessorType = (String)accessor;
if (accessorType.equalsIgnoreCase("java-serialization")) {
projectCacheAccessor = new FileBasedProjectCache();
} else {
Class transportClass = findClassForProperty(accessorType, PersistenceUnitProperties.PROJECT_CACHE, loader);
try {
projectCacheAccessor = (ProjectCache)transportClass.getConstructor().newInstance();
} catch (Exception invalid) {
session.handleException(EntityManagerSetupException.failedToInstantiateProperty(accessorType, PersistenceUnitProperties.METADATA_SOURCE,invalid));
}
}
}
}
}
/**
* Enable or disable the capability of Native SQL function.
* The method needs to be called in deploy stage.
*/
protected void updateJPQLParser(Map m) {
// Set JPQL parser if it was specified.
String parser = EntityManagerFactoryProvider.getConfigPropertyAsStringLogDebug(PersistenceUnitProperties.JPQL_PARSER, m, this.session);
if (parser != null) {
if (parser.equalsIgnoreCase(ParserType.Hermes)) {
parser = "org.eclipse.persistence.internal.jpa.jpql.HermesParser";
} else if (parser.equalsIgnoreCase(ParserType.ANTLR)) {
parser = "org.eclipse.persistence.queries.ANTLRQueryBuilder";
}
this.session.setProperty(PersistenceUnitProperties.JPQL_PARSER, parser);
}
// Set JPQL parser validation mode if it was specified.
String validation = EntityManagerFactoryProvider.getConfigPropertyAsStringLogDebug(PersistenceUnitProperties.JPQL_VALIDATION, m, this.session);
if (validation != null) {
this.session.setProperty(PersistenceUnitProperties.JPQL_VALIDATION, validation);
}
}
/**
* Enable or disable the capability of Native SQL function.
* The method needs to be called in deploy stage.
*/
protected void updateAllowNativeSQLQueriesSetting(Map m){
// Set allow native SQL queries flag if it was specified.
String allowNativeSQLQueriesString = EntityManagerFactoryProvider.getConfigPropertyAsStringLogDebug(PersistenceUnitProperties.ALLOW_NATIVE_SQL_QUERIES, m, session);
if (allowNativeSQLQueriesString != null) {
if (allowNativeSQLQueriesString.equalsIgnoreCase("true")) {
session.getProject().setAllowNativeSQLQueries(true);
} else if (allowNativeSQLQueriesString.equalsIgnoreCase("false")) {
session.getProject().setAllowNativeSQLQueries(false);
} else {
session.handleException(ValidationException.invalidBooleanValueForSettingAllowNativeSQLQueries(allowNativeSQLQueriesString));
}
}
}
/**
* Enable or disable SQL casting.
*/
protected void updateSQLCastSetting(Map m) {
//Set Native SQL flag if it was specified.
String sqlCastString = EntityManagerFactoryProvider.getConfigPropertyAsStringLogDebug(PersistenceUnitProperties.SQL_CAST, m, session);
if (sqlCastString != null) {
if (sqlCastString.equalsIgnoreCase("true")) {
session.getProject().getLogin().getPlatform().setIsCastRequired(true);
} else if (sqlCastString.equalsIgnoreCase("false")) {
session.getProject().getLogin().getPlatform().setIsCastRequired(false);
} else {
session.handleException(ValidationException.invalidBooleanValueForProperty(sqlCastString, PersistenceUnitProperties.SQL_CAST));
}
}
}
/**
* Enable or disable forcing field names to uppercase.
* The method needs to be called in deploy stage.
*/
protected void updateUppercaseSetting(Map m){
//Set Native SQL flag if it was specified.
String uppercaseString = EntityManagerFactoryProvider.getConfigPropertyAsStringLogDebug(PersistenceUnitProperties.NATIVE_QUERY_UPPERCASE_COLUMNS, m, session);
if (uppercaseString != null) {
if (uppercaseString.equalsIgnoreCase("true") ){
this.session.getProject().getLogin().setShouldForceFieldNamesToUpperCase(true);
} else if (uppercaseString.equalsIgnoreCase("false")) {
this.session.getProject().getLogin().setShouldForceFieldNamesToUpperCase(false);
} else {
this.session.handleException(ValidationException.invalidBooleanValueForProperty(uppercaseString, PersistenceUnitProperties.NATIVE_QUERY_UPPERCASE_COLUMNS));
}
}
}
/**
/**
* Enable or disable forcing field names to be case insensitive. Implementation of case insensitive column handling relies on setting
* both sides to uppercase (the column names from annotations/xml as well as what is returned from the JDBC/statement)
* The method needs to be called in deploy stage.
*/
public static void updateCaseSensitivitySettings(Map m, MetadataProject project, AbstractSession session){
//Set Native SQL flag if it was specified.
String insensitiveString = EntityManagerFactoryProvider.getConfigPropertyAsStringLogDebug(PersistenceUnitProperties.UPPERCASE_COLUMN_NAMES, m, session);
if (insensitiveString == null || insensitiveString.equalsIgnoreCase("true")) {
// Set or default to case in-sensitive.
project.setShouldForceFieldNamesToUpperCase(true);
session.getProject().getLogin().setShouldForceFieldNamesToUpperCase(true);
} else if (insensitiveString.equalsIgnoreCase("false")) {
project.setShouldForceFieldNamesToUpperCase(false);
session.getProject().getLogin().setShouldForceFieldNamesToUpperCase(false);
} else {
session.handleException(ValidationException.invalidBooleanValueForProperty(insensitiveString, PersistenceUnitProperties.UPPERCASE_COLUMN_NAMES));
}
}
/**
* Update the default pessimistic lock timeout value.
* @param persistenceProperties the properties map
*/
protected void updatePessimisticLockTimeout(Map persistenceProperties) {
String pessimisticLockTimeout = EntityManagerFactoryProvider.getConfigPropertyAsStringLogDebug(PersistenceUnitProperties.PESSIMISTIC_LOCK_TIMEOUT, persistenceProperties, session);
if (pessimisticLockTimeout != null) {
try {
session.setPessimisticLockTimeoutDefault(Integer.parseInt(pessimisticLockTimeout));
} catch (NumberFormatException invalid) {
session.handleException(ValidationException.invalidValueForProperty(pessimisticLockTimeout, PersistenceUnitProperties.PESSIMISTIC_LOCK_TIMEOUT, invalid));
}
}
}
/**
* Update the default pessimistic lock timeout unit value.
* @param persistenceProperties the properties map
*/
protected void updatePessimisticLockTimeoutUnit(Map persistenceProperties) {
String pessimisticLockTimeoutUnit = EntityManagerFactoryProvider.getConfigPropertyAsStringLogDebug(PersistenceUnitProperties.PESSIMISTIC_LOCK_TIMEOUT_UNIT, persistenceProperties, session);
if (pessimisticLockTimeoutUnit != null) {
try {
TimeUnit unit = TimeUnit.valueOf(pessimisticLockTimeoutUnit);
session.setPessimisticLockTimeoutUnitDefault(unit);
} catch (NumberFormatException invalid) {
session.handleException(ValidationException.invalidValueForProperty(pessimisticLockTimeoutUnit, PersistenceUnitProperties.PESSIMISTIC_LOCK_TIMEOUT_UNIT, invalid));
}
}
}
/**
* Enable or disable statements cached, update statements cache size.
* The method needs to be called in deploy stage.
*/
protected void updateCacheStatementSettings(Map m){
// Cache statements if flag was specified.
String statmentsNeedBeCached = EntityManagerFactoryProvider.getConfigPropertyAsStringLogDebug(PersistenceUnitProperties.CACHE_STATEMENTS, m, session);
if (statmentsNeedBeCached!=null) {
if (statmentsNeedBeCached.equalsIgnoreCase("true")) {
if (session.isServerSession() && ((ServerSession)session).getConnectionPools().isEmpty()){
session.log(SessionLog.WARNING, SessionLog.PROPERTIES, "persistence_unit_ignores_statments_cache_setting", new Object[]{null});
} else {
session.getProject().getLogin().setShouldCacheAllStatements(true);
}
} else if (statmentsNeedBeCached.equalsIgnoreCase("false")) {
session.getProject().getLogin().setShouldCacheAllStatements(false);
} else {
session.handleException(ValidationException.invalidBooleanValueForEnableStatmentsCached(statmentsNeedBeCached));
}
}
// Set statement cache size if specified.
String cacheStatementsSize = EntityManagerFactoryProvider.getConfigPropertyAsStringLogDebug(PersistenceUnitProperties.CACHE_STATEMENTS_SIZE, m, session);
if (cacheStatementsSize!=null) {
try {
session.getProject().getLogin().setStatementCacheSize(Integer.parseInt(cacheStatementsSize));
} catch (NumberFormatException e) {
session.handleException(ValidationException.invalidCacheStatementsSize(cacheStatementsSize,e.getMessage()));
}
}
}
/**
* Enable or disable default allowing 0 as an id.
*/
@SuppressWarnings("deprecation")
protected void updateAllowZeroIdSetting(Map m) {
String allowZero = EntityManagerFactoryProvider.getConfigPropertyAsStringLogDebug(PersistenceUnitProperties.ALLOW_ZERO_ID, m, this.session);
if (allowZero != null) {
if (allowZero.equalsIgnoreCase("true")) {
Helper.isZeroValidPrimaryKey = true;
} else if (allowZero.equalsIgnoreCase("false")) {
Helper.isZeroValidPrimaryKey = false;
} else {
session.handleException(ValidationException.invalidBooleanValueForProperty(allowZero, PersistenceUnitProperties.ALLOW_ZERO_ID));
}
}
}
/**
* Enable or disable default allowing 0 as an id.
*/
protected void updateIdValidation(Map m) {
String idValidationString = EntityManagerFactoryProvider.getConfigPropertyAsStringLogDebug(PersistenceUnitProperties.ID_VALIDATION, m, session);
if (idValidationString != null) {
session.getProject().setDefaultIdValidation(IdValidation.valueOf(idValidationString));
}
}
/**
* Sets the SharedCacheMode with values from the jakarta.persistence.sharedCache.mode property. If
* user enters an invalid caching type, valueOf will throw an illegal argument exception, e.g.
* java.lang.IllegalArgumentException: No enum const class
* jakarta.persistence.SharedCacheMode.ALLBOGUS
*/
protected void updateSharedCacheMode(Map m) {
String sharedCacheMode = EntityManagerFactoryProvider.getConfigPropertyAsStringLogDebug(PersistenceUnitProperties.SHARED_CACHE_MODE, m, session);
if (sharedCacheMode != null) {
processor.getProject().setSharedCacheMode(SharedCacheMode.valueOf(sharedCacheMode));
}
}
/**
* sets the TABLE_CREATION_SUFFIX property on the session's project to be applied to all table creation statements (DDL)
*/
protected void updateTableCreationSettings(Map m) {
String tableCreationSuffix = EntityManagerFactoryProvider.getConfigPropertyAsStringLogDebug(PersistenceUnitProperties.TABLE_CREATION_SUFFIX, m, session);
if (tableCreationSuffix != null && tableCreationSuffix.length()>0) {
session.getPlatform().setTableCreationSuffix(tableCreationSuffix);
}
}
/**
* Sets shouldCreateIndicesOnForeignKeys DDL generation option.
*/
protected void updateIndexForeignKeys(Map m) {
String indexForeignKeys = EntityManagerFactoryProvider.getConfigPropertyAsStringLogDebug(PersistenceUnitProperties.DDL_GENERATION_INDEX_FOREIGN_KEYS, m, this.session);
if (indexForeignKeys != null && (indexForeignKeys.length() > 0)) {
if (indexForeignKeys.equalsIgnoreCase("true") ){
this.session.getProject().getLogin().setShouldCreateIndicesOnForeignKeys(true);
} else if (indexForeignKeys.equalsIgnoreCase("false")){
this.session.getProject().getLogin().setShouldCreateIndicesOnForeignKeys(false);
} else {
this.session.handleException(ValidationException.invalidBooleanValueForProperty(indexForeignKeys, PersistenceUnitProperties.DDL_GENERATION_INDEX_FOREIGN_KEYS));
}
}
}
/**
* Enable or disable default temporal mutable setting.
* The method needs to be called in deploy stage.
*/
protected void updateTemporalMutableSetting(Map m) {
// Cache statements if flag was specified.
String temporalMutable = EntityManagerFactoryProvider.getConfigPropertyAsStringLogDebug(PersistenceUnitProperties.TEMPORAL_MUTABLE, m, session);
if (temporalMutable != null) {
if (temporalMutable.equalsIgnoreCase("true")) {
session.getProject().setDefaultTemporalMutable(true);
} else if (temporalMutable.equalsIgnoreCase("false")) {
session.getProject().setDefaultTemporalMutable(false);
} else {
session.handleException(ValidationException.invalidBooleanValueForProperty(temporalMutable, PersistenceUnitProperties.TEMPORAL_MUTABLE));
}
}
}
/**
* Copy named queries defined in EclipseLink descriptor into the session if it was indicated to do so.
*/
protected void setDescriptorNamedQueries(Map m) {
// Copy named queries to session if the flag has been specified.
String addNamedQueriesString = EntityManagerFactoryProvider.getConfigPropertyAsStringLogDebug(PersistenceUnitProperties.INCLUDE_DESCRIPTOR_QUERIES, m, session);
if (addNamedQueriesString!=null) {
if (addNamedQueriesString.equalsIgnoreCase("true")) {
session.copyDescriptorNamedQueries(false);
} else {
if (!addNamedQueriesString.equalsIgnoreCase("false")) {
session.handleException(ValidationException.invalidBooleanValueForAddingNamedQueries(addNamedQueriesString));
}
}
}
}
private void updateQueryTimeout(Map persistenceProperties) {
String timeout = EntityManagerFactoryProvider.getConfigPropertyAsStringLogDebug(PersistenceUnitProperties.QUERY_TIMEOUT, persistenceProperties, session);
try {
if (timeout != null) {
session.setQueryTimeoutDefault(Integer.parseInt(timeout));
}
} catch (NumberFormatException exception) {
this.session.handleException(ValidationException.invalidValueForProperty(timeout, PersistenceUnitProperties.QUERY_TIMEOUT, exception));
}
}
//Bug #456067: Added persistence unit support for timeout units
private void updateQueryTimeoutUnit(Map persistenceProperties) {
String timeoutUnit = EntityManagerFactoryProvider.getConfigPropertyAsStringLogDebug(PersistenceUnitProperties.QUERY_TIMEOUT_UNIT, persistenceProperties, session);
try {
if (timeoutUnit != null) {
TimeUnit unit = TimeUnit.valueOf(timeoutUnit);
session.setQueryTimeoutUnitDefault(unit);
}
} catch (IllegalArgumentException exception) {
this.session.handleException(ValidationException.invalidValueForProperty(timeoutUnit, PersistenceUnitProperties.QUERY_TIMEOUT_UNIT, exception));
}
}
private void updateLockingTimestampDefault(Map persistenceProperties) {
String local = EntityManagerFactoryProvider.getConfigPropertyAsStringLogDebug(PersistenceUnitProperties.USE_LOCAL_TIMESTAMP, persistenceProperties, session);
try {
if (local != null) {
for (ClassDescriptor descriptor: session.getProject().getDescriptors().values()) {
OptimisticLockingPolicy policy = descriptor.getOptimisticLockingPolicy();
if (policy instanceof TimestampLockingPolicy) {
((TimestampLockingPolicy)policy).setUsesServerTime(!Boolean.parseBoolean(local));
}
}
}
} catch (NumberFormatException exception) {
this.session.handleException(ValidationException.invalidValueForProperty(local, PersistenceUnitProperties.USE_LOCAL_TIMESTAMP, exception));
}
}
//Bug #333100: Added support for turning off SQL deferral default behavior
private void updateSQLCallDeferralDefault(Map persistenceProperties) {
String defer = EntityManagerFactoryProvider.getConfigPropertyAsStringLogDebug(PersistenceUnitProperties.SQL_CALL_DEFERRAL, persistenceProperties, this.session);
if (defer != null) {
if (defer.equalsIgnoreCase("true")) {
this.session.getProject().setAllowSQLDeferral(true);
} else if (defer.equalsIgnoreCase("false")) {
this.session.getProject().setAllowSQLDeferral(false);
} else {
this.session.handleException(ValidationException.invalidBooleanValueForProperty(defer, PersistenceUnitProperties.SQL_CALL_DEFERRAL));
}
}
}
private void updateNamingIntoIndexed(Map persistenceProperties) {
String namingIntoIndexed = EntityManagerFactoryProvider.getConfigPropertyAsStringLogDebug(PersistenceUnitProperties.NAMING_INTO_INDEXED, persistenceProperties, this.session);
if (namingIntoIndexed != null) {
if (namingIntoIndexed.equalsIgnoreCase("true")) {
this.session.getProject().setNamingIntoIndexed(true);
} else if (namingIntoIndexed.equalsIgnoreCase("false")) {
this.session.getProject().setNamingIntoIndexed(false);
} else {
this.session.handleException(ValidationException.invalidBooleanValueForProperty(namingIntoIndexed, PersistenceUnitProperties.NAMING_INTO_INDEXED));
}
}
}
private void updateConcurrencyManagerWaitTime(Map persistenceProperties) {
String acquireWaitTime = EntityManagerFactoryProvider.getConfigPropertyAsStringLogDebug(PersistenceUnitProperties.CONCURRENCY_MANAGER_ACQUIRE_WAIT_TIME, persistenceProperties, session);
try {
if (acquireWaitTime != null) {
ConcurrencyUtil.SINGLETON.setAcquireWaitTime(Long.parseLong(acquireWaitTime));
}
} catch (NumberFormatException exception) {
this.session.handleException(ValidationException.invalidValueForProperty(acquireWaitTime, PersistenceUnitProperties.CONCURRENCY_MANAGER_ACQUIRE_WAIT_TIME, exception));
}
}
private void updateConcurrencyManagerBuildObjectCompleteWaitTime(Map persistenceProperties) {
String buildObjectCompleteWaitTime = EntityManagerFactoryProvider.getConfigPropertyAsStringLogDebug(PersistenceUnitProperties.CONCURRENCY_MANAGER_BUILD_OBJECT_COMPLETE_WAIT_TIME, persistenceProperties, session);
try {
if (buildObjectCompleteWaitTime != null) {
ConcurrencyUtil.SINGLETON.setBuildObjectCompleteWaitTime(Long.parseLong(buildObjectCompleteWaitTime));
}
} catch (NumberFormatException exception) {
this.session.handleException(ValidationException.invalidValueForProperty(buildObjectCompleteWaitTime, PersistenceUnitProperties.CONCURRENCY_MANAGER_BUILD_OBJECT_COMPLETE_WAIT_TIME, exception));
}
}
private void updateConcurrencyManagerMaxAllowedSleepTime(Map persistenceProperties) {
String maxAllowedSleepTime = EntityManagerFactoryProvider.getConfigPropertyAsStringLogDebug(PersistenceUnitProperties.CONCURRENCY_MANAGER_MAX_SLEEP_TIME, persistenceProperties, session);
try {
if (maxAllowedSleepTime != null) {
ConcurrencyUtil.SINGLETON.setMaxAllowedSleepTime(Long.parseLong(maxAllowedSleepTime));
}
} catch (NumberFormatException exception) {
this.session.handleException(ValidationException.invalidValueForProperty(maxAllowedSleepTime, PersistenceUnitProperties.CONCURRENCY_MANAGER_MAX_SLEEP_TIME, exception));
}
}
private void updateConcurrencyManagerMaxAllowedFrequencyToProduceTinyDumpLogMessage(Map persistenceProperties) {
String maxAllowedSleepTime = EntityManagerFactoryProvider.getConfigPropertyAsStringLogDebug(PersistenceUnitProperties.CONCURRENCY_MANAGER_MAX_FREQUENCY_DUMP_TINY_MESSAGE, persistenceProperties, session);
try {
if (maxAllowedSleepTime != null) {
ConcurrencyUtil.SINGLETON.setMaxAllowedFrequencyToProduceTinyDumpLogMessage(Long.parseLong(maxAllowedSleepTime));
}
} catch (NumberFormatException exception) {
this.session.handleException(ValidationException.invalidValueForProperty(maxAllowedSleepTime, PersistenceUnitProperties.CONCURRENCY_MANAGER_MAX_FREQUENCY_DUMP_TINY_MESSAGE, exception));
}
}
private void updateConcurrencyManagerMaxAllowedFrequencyToProduceMassiveDumpLogMessage(Map persistenceProperties) {
String maxAllowedSleepTime = EntityManagerFactoryProvider.getConfigPropertyAsStringLogDebug(PersistenceUnitProperties.CONCURRENCY_MANAGER_MAX_FREQUENCY_DUMP_MASSIVE_MESSAGE, persistenceProperties, session);
try {
if (maxAllowedSleepTime != null) {
ConcurrencyUtil.SINGLETON.setMaxAllowedFrequencyToProduceMassiveDumpLogMessage(Long.parseLong(maxAllowedSleepTime));
}
} catch (NumberFormatException exception) {
this.session.handleException(ValidationException.invalidValueForProperty(maxAllowedSleepTime, PersistenceUnitProperties.CONCURRENCY_MANAGER_MAX_FREQUENCY_DUMP_MASSIVE_MESSAGE, exception));
}
}
private void updateConcurrencyManagerAllowInterruptedExceptionFired(Map persistenceProperties) {
String allowInterruptedExceptionFired = EntityManagerFactoryProvider.getConfigPropertyAsStringLogDebug(PersistenceUnitProperties.CONCURRENCY_MANAGER_ALLOW_INTERRUPTED_EXCEPTION, persistenceProperties, session);
try {
if (allowInterruptedExceptionFired != null) {
ConcurrencyUtil.SINGLETON.setAllowInterruptedExceptionFired(Boolean.parseBoolean(allowInterruptedExceptionFired));
}
} catch (NumberFormatException exception) {
this.session.handleException(ValidationException.invalidValueForProperty(allowInterruptedExceptionFired, PersistenceUnitProperties.CONCURRENCY_MANAGER_ALLOW_INTERRUPTED_EXCEPTION, exception));
}
}
private void updateConcurrencyManagerAllowConcurrencyExceptionToBeFiredUp(Map persistenceProperties) {
String allowConcurrencyExceptionToBeFiredUp = EntityManagerFactoryProvider.getConfigPropertyAsStringLogDebug(PersistenceUnitProperties.CONCURRENCY_MANAGER_ALLOW_CONCURRENCY_EXCEPTION, persistenceProperties, session);
try {
if (allowConcurrencyExceptionToBeFiredUp != null) {
ConcurrencyUtil.SINGLETON.setAllowConcurrencyExceptionToBeFiredUp(Boolean.parseBoolean(allowConcurrencyExceptionToBeFiredUp));
}
} catch (NumberFormatException exception) {
this.session.handleException(ValidationException.invalidValueForProperty(allowConcurrencyExceptionToBeFiredUp, PersistenceUnitProperties.CONCURRENCY_MANAGER_ALLOW_CONCURRENCY_EXCEPTION, exception));
}
}
private void updateConcurrencyManagerAllowTakingStackTraceDuringReadLockAcquisition(Map persistenceProperties) {
String allowTakingStackTraceDuringReadLockAcquisition = EntityManagerFactoryProvider.getConfigPropertyAsStringLogDebug(PersistenceUnitProperties.CONCURRENCY_MANAGER_ALLOW_STACK_TRACE_READ_LOCK, persistenceProperties, session);
try {
if (allowTakingStackTraceDuringReadLockAcquisition != null) {
ConcurrencyUtil.SINGLETON.setAllowTakingStackTraceDuringReadLockAcquisition(Boolean.parseBoolean(allowTakingStackTraceDuringReadLockAcquisition));
}
} catch (NumberFormatException exception) {
this.session.handleException(ValidationException.invalidValueForProperty(allowTakingStackTraceDuringReadLockAcquisition, PersistenceUnitProperties.CONCURRENCY_MANAGER_ALLOW_STACK_TRACE_READ_LOCK, exception));
}
}
private void updateConcurrencyManagerUseObjectBuildingSemaphore(Map persistenceProperties) {
String useObjectBuildingSemaphore = EntityManagerFactoryProvider.getConfigPropertyAsStringLogDebug(PersistenceUnitProperties.CONCURRENCY_MANAGER_USE_SEMAPHORE_TO_SLOW_DOWN_OBJECT_BUILDING, persistenceProperties, session);
try {
if (useObjectBuildingSemaphore != null) {
ConcurrencyUtil.SINGLETON.setUseSemaphoreInObjectBuilder(Boolean.parseBoolean(useObjectBuildingSemaphore));
}
} catch (NumberFormatException exception) {
this.session.handleException(ValidationException.invalidValueForProperty(useObjectBuildingSemaphore, PersistenceUnitProperties.CONCURRENCY_MANAGER_USE_SEMAPHORE_TO_SLOW_DOWN_OBJECT_BUILDING, exception));
}
}
private void updateConcurrencyManagerUseWriteLockManagerSemaphore(Map persistenceProperties) {
String useWriteLockManagerSemaphore = EntityManagerFactoryProvider.getConfigPropertyAsStringLogDebug(PersistenceUnitProperties.CONCURRENCY_MANAGER_USE_SEMAPHORE_TO_SLOW_DOWN_WRITE_LOCK_MANAGER_ACQUIRE_REQUIRED_LOCKS, persistenceProperties, session);
try {
if (useWriteLockManagerSemaphore != null) {
ConcurrencyUtil.SINGLETON.setUseSemaphoreToLimitConcurrencyOnWriteLockManagerAcquireRequiredLocks(Boolean.parseBoolean(useWriteLockManagerSemaphore));
}
} catch (NumberFormatException exception) {
this.session.handleException(ValidationException.invalidValueForProperty(useWriteLockManagerSemaphore, PersistenceUnitProperties.CONCURRENCY_MANAGER_USE_SEMAPHORE_TO_SLOW_DOWN_WRITE_LOCK_MANAGER_ACQUIRE_REQUIRED_LOCKS, exception));
}
}
private void updateConcurrencyManagerNoOfThreadsAllowedToObjectBuildInParallel(Map persistenceProperties) {
String noOfThreadsAllowedToObjectBuildInParallel = EntityManagerFactoryProvider.getConfigPropertyAsStringLogDebug(PersistenceUnitProperties.CONCURRENCY_MANAGER_OBJECT_BUILDING_NO_THREADS, persistenceProperties, session);
try {
if (noOfThreadsAllowedToObjectBuildInParallel != null) {
ConcurrencyUtil.SINGLETON.setNoOfThreadsAllowedToObjectBuildInParallel(Integer.parseInt(noOfThreadsAllowedToObjectBuildInParallel));
}
} catch (NumberFormatException exception) {
this.session.handleException(ValidationException.invalidValueForProperty(noOfThreadsAllowedToObjectBuildInParallel, PersistenceUnitProperties.CONCURRENCY_MANAGER_OBJECT_BUILDING_NO_THREADS, exception));
}
}
private void updateConcurrencyManagerNoOfThreadsAllowedToDoWriteLockManagerAcquireRequiredLocksInParallel(Map persistenceProperties) {
String noOfThreadsAllowedToDoWriteLockManagerAcquireRequiredLocksInParallel = EntityManagerFactoryProvider.getConfigPropertyAsStringLogDebug(PersistenceUnitProperties.CONCURRENCY_MANAGER_WRITE_LOCK_MANAGER_ACQUIRE_REQUIRED_LOCKS_NO_THREADS, persistenceProperties, session);
try {
if (noOfThreadsAllowedToDoWriteLockManagerAcquireRequiredLocksInParallel != null) {
ConcurrencyUtil.SINGLETON.setNoOfThreadsAllowedToDoWriteLockManagerAcquireRequiredLocksInParallel(Integer.parseInt(noOfThreadsAllowedToDoWriteLockManagerAcquireRequiredLocksInParallel));
}
} catch (NumberFormatException exception) {
this.session.handleException(ValidationException.invalidValueForProperty(noOfThreadsAllowedToDoWriteLockManagerAcquireRequiredLocksInParallel, PersistenceUnitProperties.CONCURRENCY_MANAGER_WRITE_LOCK_MANAGER_ACQUIRE_REQUIRED_LOCKS_NO_THREADS, exception));
}
}
private void updateConcurrencySemaphoreMaxTimePermit(Map persistenceProperties) {
String concurrencySemaphoreMaxTimePermit = EntityManagerFactoryProvider.getConfigPropertyAsStringLogDebug(PersistenceUnitProperties.CONCURRENCY_SEMAPHORE_MAX_TIME_PERMIT, persistenceProperties, session);
try {
if (concurrencySemaphoreMaxTimePermit != null) {
ConcurrencyUtil.SINGLETON.setConcurrencySemaphoreMaxTimePermit(Long.parseLong(concurrencySemaphoreMaxTimePermit));
}
} catch (NumberFormatException exception) {
this.session.handleException(ValidationException.invalidValueForProperty(concurrencySemaphoreMaxTimePermit, PersistenceUnitProperties.CONCURRENCY_SEMAPHORE_MAX_TIME_PERMIT, exception));
}
}
private void updateConcurrencySemaphoreLogTimeout(Map persistenceProperties) {
String concurrencySemaphoreLogTimeout = EntityManagerFactoryProvider.getConfigPropertyAsStringLogDebug(PersistenceUnitProperties.CONCURRENCY_SEMAPHORE_LOG_TIMEOUT, persistenceProperties, session);
try {
if (concurrencySemaphoreLogTimeout != null) {
ConcurrencyUtil.SINGLETON.setConcurrencySemaphoreLogTimeout(Long.parseLong(concurrencySemaphoreLogTimeout));
}
} catch (NumberFormatException exception) {
this.session.handleException(ValidationException.invalidValueForProperty(concurrencySemaphoreLogTimeout, PersistenceUnitProperties.CONCURRENCY_SEMAPHORE_LOG_TIMEOUT, exception));
}
}
/**
* Enable or disable extended logging of JPA L2 cache usage.
* The method needs to be called in deploy stage.
*/
protected void updateAllowExtendedCacheLogging(Map m){
String allowExtendedCacheLogging = EntityManagerFactoryProvider.getConfigPropertyAsStringLogDebug(PersistenceUnitProperties.CACHE_EXTENDED_LOGGING, m, session);
if (allowExtendedCacheLogging != null) {
if (allowExtendedCacheLogging.equalsIgnoreCase("true")) {
session.getProject().setAllowExtendedCacheLogging(true);
} else if (allowExtendedCacheLogging.equalsIgnoreCase("false")) {
session.getProject().setAllowExtendedCacheLogging(false);
} else {
session.handleException(ValidationException.invalidBooleanValueForProperty(allowExtendedCacheLogging, PersistenceUnitProperties.CACHE_EXTENDED_LOGGING));
}
}
}
/**
* Enable or disable extended thread logging.
* The method needs to be called in deploy stage.
*/
protected void updateAllowExtendedThreadLogging(Map m){
String allowExtendedThreadLogging = EntityManagerFactoryProvider.getConfigPropertyAsStringLogDebug(PersistenceUnitProperties.THREAD_EXTENDED_LOGGING, m, session);
if (allowExtendedThreadLogging != null) {
if (allowExtendedThreadLogging.equalsIgnoreCase("true")) {
session.getProject().setAllowExtendedThreadLogging(true);
} else if (allowExtendedThreadLogging.equalsIgnoreCase("false")) {
session.getProject().setAllowExtendedThreadLogging(false);
} else {
session.handleException(ValidationException.invalidBooleanValueForProperty(allowExtendedThreadLogging, PersistenceUnitProperties.THREAD_EXTENDED_LOGGING));
}
}
}
/**
* Enable or disable thread dump addition to extended thread logging.
* The method needs to be called in deploy stage.
*/
protected void updateAllowExtendedThreadLoggingThreadDump(Map m){
String allowExtendedThreadLoggingThreadDump = EntityManagerFactoryProvider.getConfigPropertyAsStringLogDebug(PersistenceUnitProperties.THREAD_EXTENDED_LOGGING_THREADDUMP, m, session);
if (allowExtendedThreadLoggingThreadDump != null) {
if (allowExtendedThreadLoggingThreadDump.equalsIgnoreCase("true")) {
session.getProject().setAllowExtendedThreadLoggingThreadDump(true);
} else if (allowExtendedThreadLoggingThreadDump.equalsIgnoreCase("false")) {
session.getProject().setAllowExtendedThreadLoggingThreadDump(false);
} else {
session.handleException(ValidationException.invalidBooleanValueForProperty(allowExtendedThreadLoggingThreadDump, PersistenceUnitProperties.THREAD_EXTENDED_LOGGING_THREADDUMP));
}
}
}
/**
* If Bean Validation is enabled, bootstraps Bean Validation on descriptors.
* @param puProperties merged properties for this persistence unit
*/
private void addBeanValidationListeners(Map puProperties, ClassLoader appClassLoader) {
ValidationMode validationMode = getValidationMode(persistenceUnitInfo, puProperties);
if (validationMode == ValidationMode.AUTO || validationMode == ValidationMode.CALLBACK) {
// BeanValidationInitializationHelper contains static reference to jakarta.validation.* classes. We need to support
// environment where these classes are not available.
// To guard against some vms that eagerly resolve, reflectively load class to prevent any static reference to it
String helperClassName = "org.eclipse.persistence.internal.jpa.deployment.BeanValidationInitializationHelper$BeanValidationInitializationHelperImpl";
Class helperClass;
try {
if (PrivilegedAccessHelper.shouldUsePrivilegedAccess()) {
try {
helperClass = AccessController.doPrivileged(
new PrivilegedClassForName<>(helperClassName, true, appClassLoader));
} catch (Throwable t) {
// Try the ClassLoader that loaded Eclipselink classes
ClassLoader eclipseLinkClassLoader = EntityManagerSetupImpl.class.getClassLoader();
helperClass = AccessController.doPrivileged(new PrivilegedClassForName<>(helperClassName, true, eclipseLinkClassLoader));
}
} else {
try {
helperClass = PrivilegedAccessHelper.getClassForName(helperClassName, true, appClassLoader);
} catch (Throwable t) {
// Try the ClassLoader that loaded Eclipselink classes
ClassLoader eclipseLinkClassLoader = EntityManagerSetupImpl.class.getClassLoader();
helperClass = PrivilegedAccessHelper.getClassForName(helperClassName, true, eclipseLinkClassLoader);
}
}
BeanValidationInitializationHelper beanValidationInitializationHelper = (BeanValidationInitializationHelper)helperClass.getConstructor().newInstance();
beanValidationInitializationHelper.bootstrapBeanValidation(puProperties, session, appClassLoader);
} catch (Throwable e) { //Catching Throwable to catch any linkage errors on vms that resolve eagerly
if (validationMode == ValidationMode.CALLBACK) {
throw PersistenceUnitLoadingException.exceptionObtainingRequiredBeanValidatorFactory(e);
} // else validationMode == ValidationMode.AUTO. Log a message, Ignore the exception
this.session.log(SessionLog.FINEST, SessionLog.JPA, "validation_factory_not_initialized", new Object[]{ e.getMessage() });
}
}
}
/**
* Validation mode from information in persistence.xml and properties specified at EMF creation
* @param persitenceUnitInfo PersitenceUnitInfo instance for this persistence unit
* @param puProperties merged properties for this persistence unit
* @return validation mode
*/
private static ValidationMode getValidationMode(PersistenceUnitInfo persitenceUnitInfo, Map puProperties) {
//Check if overridden at emf creation
String validationModeAtEMFCreation = (String) puProperties.get(PersistenceUnitProperties.VALIDATION_MODE);
if(validationModeAtEMFCreation != null) {
// User will receive IllegalArgumentException if an invalid mode has been specified
return ValidationMode.valueOf(validationModeAtEMFCreation.toUpperCase(Locale.ROOT));
}
//otherwise:
ValidationMode validationMode = null;
// Initialize with value in persitence.xml
// Using reflection to call getValidationMode to prevent blowing up while we are running in JPA 1.0 environment
// (This would be all JavaEE5 appservers) where PersistenceUnitInfo does not implement method getValidationMode().
try {
Method method = null;
if (PrivilegedAccessHelper.shouldUsePrivilegedAccess()) {
method = AccessController.doPrivileged(new PrivilegedGetDeclaredMethod(PersistenceUnitInfo.class, "getValidationMode", null));
validationMode = (ValidationMode) AccessController.doPrivileged(new PrivilegedMethodInvoker(method, persitenceUnitInfo));
} else {
method = PrivilegedAccessHelper.getDeclaredMethod(PersistenceUnitInfo.class, "getValidationMode", null);
validationMode = PrivilegedAccessHelper.invokeMethod(method, persitenceUnitInfo, null);
}
} catch (Throwable exception) {
// We are running in JavaEE5 environment. Catch and swallow any exceptions and return null.
}
if(validationMode == null) {
// Default to AUTO as specified in JPA spec.
validationMode = ValidationMode.AUTO;
}
return validationMode;
}
/**
* INTERNAL:
* Return an instance of Metamodel interface for access to the
* metamodel of the persistence unit.
* This method will complete any initialization done in the predeploy phase
* of deployment.
* @return Metamodel instance
* @since Java Persistence 2.0
*/
public Metamodel getMetamodel(ClassLoader classLoader) {
preInitializeMetamodel();
if (!((MetamodelImpl)metaModel).isInitialized()){
((MetamodelImpl)metaModel).initialize(classLoader);
// If the canonical metamodel classes exist, initialize them
initializeCanonicalMetamodel(metaModel);
}
return metaModel;
}
/**
* INTERNAL:
* Initialize the Canonical Metamodel classes generated by EclipseLink
* @since Java Persistence 2.0
*/
protected void initializeCanonicalMetamodel(Metamodel model) {
// 338837: verify that the collection is not empty - this would mean entities did not make it into the search path
if(null == model.getManagedTypes() || model.getManagedTypes().isEmpty()) {
getSession().log(SessionLog.FINER, SessionLog.METAMODEL, "metamodel_type_collection_empty");
}
for (ManagedType manType : model.getManagedTypes()) {
boolean classInitialized = false;
String className = MetadataHelper.getQualifiedCanonicalName(manType.getJavaType().getName(), getSession());
try {
Class clazz = this.getSession().getDatasourcePlatform().convertObject(className, ClassConstants.CLASS);
classInitialized=true;
this.getSession().log(SessionLog.FINER, SessionLog.METAMODEL, "metamodel_canonical_model_class_found", className);
String fieldName = "";
for(Object attribute : manType.getDeclaredAttributes()) {
try {
fieldName = ((Attribute)attribute).getName();
if (PrivilegedAccessHelper.shouldUsePrivilegedAccess()){
AccessController.doPrivileged(new PrivilegedGetDeclaredField(clazz, fieldName, false)).set(clazz, attribute);
} else {
PrivilegedAccessHelper.getDeclaredField(clazz, fieldName, false).set(clazz, attribute);
}
} catch (NoSuchFieldException nsfe) {
// Ignore fields missing in canonical model (dclarke bug 346106)
} catch (Exception e) {
ValidationException v = ValidationException.invalidFieldForClass(fieldName, clazz);
v.setInternalException(e);
throw v;
}
}
} catch (ConversionException exception){
}
if (!classInitialized) {
getSession().log(SessionLog.FINER, SessionLog.METAMODEL, "metamodel_canonical_model_class_not_found", className);
}
}
}
/**
* INTERNAL:
* Convenience function to allow us to reset the Metamodel
* in the possible case that we want to regenerate it.
* This function is outside of the JPA 2.0 specification.
* @since Java Persistence 2.0
*/
public void setMetamodel(Metamodel aMetamodel) {
this.metaModel = aMetamodel;
}
public boolean mustBeCompositeMember() {
return mustBeCompositeMember(this.persistenceUnitInfo);
}
public boolean isCompositeMember() {
return this.compositeEmSetupImpl != null;
}
public boolean isComposite() {
return this.compositeMemberEmSetupImpls != null;
}
public static boolean mustBeCompositeMember(PersistenceUnitInfo puInfo) {
String mustBeCompositeMemberStr = PropertiesHandler.getPropertyValue(PersistenceUnitProperties.COMPOSITE_UNIT_MEMBER, puInfo.getProperties(), false);
if(mustBeCompositeMemberStr != null) {
return mustBeCompositeMemberStr.equals("true");
} else {
return false;
}
}
public static boolean isComposite(PersistenceUnitInfo puInfo) {
String isCompositeString = PropertiesHandler.getPropertyValue(PersistenceUnitProperties.COMPOSITE_UNIT, puInfo.getProperties(), false);
if(isCompositeString != null) {
return isCompositeString.equals("true");
} else {
return false;
}
}
public void setCompositeEmSetupImpl(EntityManagerSetupImpl compositeEmSetupImpl) {
this.compositeEmSetupImpl = compositeEmSetupImpl;
}
public EntityManagerSetupImpl getCompositeEmSetupImpl() {
return this.compositeEmSetupImpl;
}
// predeploy method will be used for static weaving
public void setStaticWeaveInfo(StaticWeaveInfo staticWeaveInfo) {
this.staticWeaveInfo = staticWeaveInfo;
}
protected void predeployCompositeMembers(Map predeployProperties, ClassLoader tempClassLoader) {
// get all puInfos found in jar-files specified in composite's persistence.xml
// all these puInfos are not composite because composites are recursively "taken apart", too.
Set<SEPersistenceUnitInfo> compositeMemberPuInfos = getCompositeMemberPuInfoSet(persistenceUnitInfo, predeployProperties);
// makes sure each member has a non-null property, overrides where required properties with composite's predeploy properties.
updateCompositeMembersProperties(compositeMemberPuInfos, predeployProperties);
// Don't log these properties - may contain passwords. The properties will be logged by contained persistence units.
Map compositeMemberMapOfProperties = (Map)getConfigProperty(PersistenceUnitProperties.COMPOSITE_UNIT_PROPERTIES, predeployProperties);
this.compositeMemberEmSetupImpls = new HashSet<>(compositeMemberPuInfos.size());
this.processor = new MetadataProcessor();
if (enableWeaving) {
this.weaver = new PersistenceWeaver(new HashMap<String, ClassDetails>());
}
// create containedEmSetupImpls and predeploy them for the first time.
// predeploy divided in three stages (modes):
// all composite members should complete a stage before any of them can move to the next one.
for (SEPersistenceUnitInfo compositeMemberPuInfo : compositeMemberPuInfos) {
// set composite's temporary classloader
compositeMemberPuInfo.setNewTempClassLoader(tempClassLoader);
String containedPuName = compositeMemberPuInfo.getPersistenceUnitName();
EntityManagerSetupImpl containedEmSetupImpl = new EntityManagerSetupImpl(containedPuName, containedPuName);
// set composite
containedEmSetupImpl.setCompositeEmSetupImpl(this);
// non-null only in case predeploy is used for static weaving
containedEmSetupImpl.setStaticWeaveInfo(this.staticWeaveInfo);
// the properties guaranteed to be non-null after updateCompositeMemberProperties call
Map compositeMemberProperties = (Map)compositeMemberMapOfProperties.get(containedPuName);
containedEmSetupImpl.predeploy(compositeMemberPuInfo, compositeMemberProperties);
// reset temporary classloader back to the original
compositeMemberPuInfo.setNewTempClassLoader(compositeMemberPuInfo.getClassLoader());
this.compositeMemberEmSetupImpls.add(containedEmSetupImpl);
}
// after the first loop containedEmSetupImpls are in HalfPredeployed state,
// mode = COMPOSITE_MEMBER_MIDDLE mode
for(EntityManagerSetupImpl containedEmSetupImpl : this.compositeMemberEmSetupImpls) {
// properties not used, puInfo already set
containedEmSetupImpl.predeploy(null, null);
}
// after the second loop containedEmSetupImpls are still in HalfPredeployed state,
// mode = COMPOSITE_MEMBER_FINAL mode
for(EntityManagerSetupImpl containedEmSetupImpl : this.compositeMemberEmSetupImpls) {
// properties not used, puInfo already set
PersistenceWeaver containedWeaver = (PersistenceWeaver)containedEmSetupImpl.predeploy(null, null);
// containedEmSetupImpl is finally in Predeployed state.
// if both composite and composite member weavings enabled copy class details from member's weaver to composite's one.
if(enableWeaving && containedWeaver != null) {
this.weaver.getClassDetailsMap().putAll(containedWeaver.getClassDetailsMap());
}
}
if(enableWeaving && this.weaver.getClassDetailsMap().isEmpty()) {
this.weaver = null;
}
}
protected void deployCompositeMembers(Map deployProperties, ClassLoader realClassLoader) {
// Don't log these properties - may contain passwords. The properties will be logged by contained persistence units.
Map compositeMemberMapOfProperties = (Map)getConfigProperty(PersistenceUnitProperties.COMPOSITE_UNIT_PROPERTIES, deployProperties);
for(EntityManagerSetupImpl compositeMemberEmSetupImpl : this.compositeMemberEmSetupImpls) {
// the properties guaranteed to be non-null after updateCompositeMemberProperties call
Map compositeMemberProperties = (Map)compositeMemberMapOfProperties.get(compositeMemberEmSetupImpl.getPersistenceUnitInfo().getPersistenceUnitName());
compositeMemberEmSetupImpl.deploy(realClassLoader, compositeMemberProperties);
AbstractSession containedSession = compositeMemberEmSetupImpl.getSession();
((SessionBroker)session).registerSession(containedSession.getName(), containedSession);
}
}
/**
* INTERNAL:
* Cause the first phase of metamodel initialization. This phase involves detecting the classes involved
* and build metamodel instances for them.
*/
public void preInitializeMetamodel(){
// perform lazy initialisation
Metamodel tempMetaModel = null;
if (null == metaModel){
// 338837: verify that the collection is not empty - this would mean entities did not make it into the search path
tempMetaModel = new MetamodelImpl(this);
// set variable after init has executed without exception
metaModel = tempMetaModel;
}
}
/**
* INTERNAL:
* First phase of canonical metamodel initialization. For each class the metamodel is aware of, check
* for a canonical metamodel class and initialize each attribute in it with a proxy that can cause the
* rest of the metamodel population. Attributes are found reflectively rather than through the metamodel
* to avoid having to further initialize the metamodel.
*/
public void preInitializeCanonicalMetamodel(EntityManagerFactoryImpl factory){
// 338837: verify that the collection is not empty - this would mean entities did not make it into the search path
if(null == metaModel.getManagedTypes() || metaModel.getManagedTypes().isEmpty()) {
getSession().log(SessionLog.FINER, SessionLog.METAMODEL, "metamodel_type_collection_empty");
}
for (ManagedType manType : metaModel.getManagedTypes()) {
boolean classInitialized = false;
String className = MetadataHelper.getQualifiedCanonicalName(((ManagedTypeImpl)manType).getJavaTypeName(), getSession());
try {
Class clazz = this.getSession().getDatasourcePlatform().convertObject(className, ClassConstants.CLASS);
classInitialized=true;
this.getSession().log(SessionLog.FINER, SessionLog.METAMODEL, "metamodel_canonical_model_class_found", className);
Field[] fields = null;
if (PrivilegedAccessHelper.shouldUsePrivilegedAccess()){
fields = AccessController.doPrivileged(new PrivilegedGetDeclaredFields(clazz));
} else {
fields = PrivilegedAccessHelper.getDeclaredFields(clazz);
}
for(Field attribute : fields) {
if (Attribute.class.isAssignableFrom(attribute.getType())){
Object assignedAttribute = null;
if (PrivilegedAccessHelper.shouldUsePrivilegedAccess()){
assignedAttribute = AccessController.doPrivileged(new PrivilegedGetValueFromField(attribute, null));
} else {
assignedAttribute =PrivilegedAccessHelper.getValueFromField(attribute, null);
}
AttributeProxyImpl proxy = null;
if (assignedAttribute == null){
if (SingularAttribute.class.isAssignableFrom(attribute.getType())){
proxy = new SingularAttributeProxyImpl();
} else if (MapAttribute.class.isAssignableFrom(attribute.getType())){
proxy = new MapAttributeProxyImpl();
} else if (SetAttribute.class.isAssignableFrom(attribute.getType())){
proxy = new SetAttributeProxyImpl();
} else if (ListAttribute.class.isAssignableFrom(attribute.getType())){
proxy = new ListAttributeProxyImpl();
} else if (CollectionAttribute.class.isAssignableFrom(attribute.getType())){
proxy = new CollectionAttributeProxyImpl();
}
if (proxy != null){
attribute.setAccessible(true);
attribute.set(null, proxy);
}
} else if (assignedAttribute instanceof AttributeProxyImpl){
proxy = (AttributeProxyImpl)assignedAttribute;
}
if (proxy != null){
proxy.addFactory(factory);
}
}
}
} catch (PrivilegedActionException pae){
getSession().logThrowable(SessionLog.FINEST, SessionLog.METAMODEL, pae);
} catch (IllegalAccessException iae){
getSession().logThrowable(SessionLog.FINEST, SessionLog.METAMODEL, iae);
} catch (ConversionException ce){
}
if (!classInitialized) {
getSession().log(SessionLog.FINER, SessionLog.METAMODEL, "metamodel_canonical_model_class_not_found", className);
}
}
}
/*
* Overide composite member properties' map with a new one, which
* has (possibly empty but non-null) properties for each composite member,
* for required properties overrides values with those from composite properties.
*/
protected void updateCompositeMembersProperties(Map compositeProperties) {
Set<SEPersistenceUnitInfo> compositePuInfos = new HashSet<>(compositeMemberEmSetupImpls.size());
for (EntityManagerSetupImpl compositeMemberEmSetupImpl : compositeMemberEmSetupImpls) {
compositePuInfos.add((SEPersistenceUnitInfo)compositeMemberEmSetupImpl.persistenceUnitInfo);
}
updateCompositeMembersProperties(compositePuInfos, compositeProperties);
}
/*
* Overide composite member properties' map with a new one, which
* has (possibly empty but non-null) properties for each composite member,
* for required properties overrides values with those from composite properties.
* Parameter compositePuInfo indicates whether compositeMemberPreoperties should be merged (overriding) with its puInfo properties
* (false for predeploy, true for deploy).
*/
protected void updateCompositeMembersProperties(Set<SEPersistenceUnitInfo> compositePuInfos, Map compositeProperties) {
// Don't log these properties - may contain passwords. The properties will be logged by contained persistence units.
Map compositeMemberMapOfProperties = (Map)getConfigProperty(PersistenceUnitProperties.COMPOSITE_UNIT_PROPERTIES, compositeProperties);
Map newCompositeMemberMapOfProperties;
if (compositeMemberMapOfProperties == null) {
newCompositeMemberMapOfProperties = new HashMap<>(compositePuInfos.size());
} else {
// Don't alter user-supplied properties' map - create a copy instead
newCompositeMemberMapOfProperties = new HashMap<>(compositeMemberMapOfProperties);
}
for (SEPersistenceUnitInfo compositePuInfo : compositePuInfos) {
String compositeMemberPuName = compositePuInfo.getPersistenceUnitName();
Map compositeMemberProperties = (Map)newCompositeMemberMapOfProperties.get(compositeMemberPuName);
Map newCompositeMemberProperties;
if (compositeMemberProperties == null) {
newCompositeMemberProperties = new HashMap<>();
} else {
// Don't alter user-supplied properties - create a copy instead
newCompositeMemberProperties = new HashMap<>(compositeMemberProperties);
}
overrideMemberProperties(newCompositeMemberProperties, compositeProperties);
newCompositeMemberProperties = mergeMaps(newCompositeMemberProperties, compositePuInfo.getProperties());
translateOldProperties(newCompositeMemberProperties, session);
newCompositeMemberMapOfProperties.put(compositeMemberPuName, newCompositeMemberProperties);
}
// set the new COMPOSITE_PROPERTIES into compositeProperties
compositeProperties.put(PersistenceUnitProperties.COMPOSITE_UNIT_PROPERTIES, newCompositeMemberMapOfProperties);
}
/*
* For required properties overrides values with those from composite properties.
*/
protected static void overrideMemberProperties(Map memberProperties, Map compositeProperties) {
String transactionTypeProp = (String)compositeProperties.get(PersistenceUnitProperties.TRANSACTION_TYPE);
if (transactionTypeProp != null) {
memberProperties.put(PersistenceUnitProperties.TRANSACTION_TYPE, transactionTypeProp);
} else {
memberProperties.remove(PersistenceUnitProperties.TRANSACTION_TYPE);
}
String serverPlatformProp = (String)compositeProperties.get(PersistenceUnitProperties.TARGET_SERVER);
if (serverPlatformProp != null) {
memberProperties.put(PersistenceUnitProperties.TARGET_SERVER, serverPlatformProp);
} else {
memberProperties.remove(PersistenceUnitProperties.TARGET_SERVER);
}
Boolean isValidationOnly = (Boolean)compositeProperties.get(PersistenceUnitProperties.VALIDATION_ONLY_PROPERTY);
if (isValidationOnly != null) {
memberProperties.put(PersistenceUnitProperties.VALIDATION_ONLY_PROPERTY, isValidationOnly);
} else {
memberProperties.remove(PersistenceUnitProperties.VALIDATION_ONLY_PROPERTY);
}
}
/*
* If a member is composite then add its members instead.
* All members' puNames must be unique.
* Return a Map of composite member SEPersistenceUnitInfo keyed by persistence unit name.
*/
protected static Map<String, SEPersistenceUnitInfo> getCompositeMemberPuInfoMap(PersistenceUnitInfo puInfo, Map predeployProperties) {
Set<SEPersistenceUnitInfo> memeberPuInfoSet = PersistenceUnitProcessor.getPersistenceUnits(puInfo.getClassLoader(), predeployProperties, puInfo.getJarFileUrls());
HashMap<String, SEPersistenceUnitInfo> memberPuInfoMap = new HashMap<>(memeberPuInfoSet.size());
for (SEPersistenceUnitInfo memberPuInfo : memeberPuInfoSet) {
// override transaction type with composite's transaction type
memberPuInfo.setTransactionType(puInfo.getTransactionType());
// override properties that should be overridden by composit's properties
overrideMemberProperties(memberPuInfo.getProperties(), puInfo.getProperties());
if (isComposite(memberPuInfo)) {
Map<String, SEPersistenceUnitInfo> containedMemberPuInfoMap = getCompositeMemberPuInfoMap(memberPuInfo, memberPuInfo.getProperties());
Iterator<Map.Entry<String, SEPersistenceUnitInfo>> it = containedMemberPuInfoMap.entrySet().iterator();
while (it.hasNext()) {
Map.Entry<String, SEPersistenceUnitInfo> entry = it.next();
String containedMemberPuName = entry.getKey();
SEPersistenceUnitInfo containedMemberPuInfo = entry.getValue();
SEPersistenceUnitInfo anotherMemeberPuInfo = memberPuInfoMap.get(containedMemberPuName);
if (anotherMemeberPuInfo == null) {
memberPuInfoMap.put(containedMemberPuName, containedMemberPuInfo);
} else {
throwPersistenceUnitNameAlreadyInUseException(containedMemberPuName, containedMemberPuInfo, anotherMemeberPuInfo);
}
}
} else {
String memberPuName = memberPuInfo.getPersistenceUnitName();
SEPersistenceUnitInfo anotherMemeberPuInfo = memberPuInfoMap.get(memberPuName);
if (anotherMemeberPuInfo == null) {
memberPuInfoMap.put(memberPuName, memberPuInfo);
} else {
throwPersistenceUnitNameAlreadyInUseException(memberPuName, memberPuInfo, anotherMemeberPuInfo);
}
}
}
return memberPuInfoMap;
}
/*
* If a member is composite then add its members instead.
* All members' puNames must be unique.
* Return a Set of composite member SEPersistenceUnitInfo.
*/
protected static Set<SEPersistenceUnitInfo> getCompositeMemberPuInfoSet(PersistenceUnitInfo puInfo, Map predeployProperties) {
return new HashSet<>(getCompositeMemberPuInfoMap(puInfo, predeployProperties).values());
}
public static void throwPersistenceUnitNameAlreadyInUseException(String puName, PersistenceUnitInfo newPuInfo, PersistenceUnitInfo exsitingPuInfo) {
String puUrl;
String anotherPuUrl;
try {
puUrl = URLDecoder.decode(newPuInfo.getPersistenceUnitRootUrl().toString(), "UTF8");
anotherPuUrl = URLDecoder.decode(exsitingPuInfo.getPersistenceUnitRootUrl().toString(), "UTF8");
} catch (UnsupportedEncodingException e) {
puUrl = newPuInfo.getPersistenceUnitRootUrl().toString();
anotherPuUrl = exsitingPuInfo.getPersistenceUnitRootUrl().toString();
}
throw PersistenceUnitLoadingException.persistenceUnitNameAlreadyInUse(puName, puUrl, anotherPuUrl);
}
/**
* Create a new version of this EntityManagerSetupImpl and cache it. Prepare "this" EntityManagerSetupImpl
* for garbage collection.
*
* This call will mean any users of this EntityManagerSetupImpl will get the new version the next time
* they look it up (for instance and EntityManager creation time)
*/
public EntityManagerSetupImpl refreshMetadata(Map properties){
String sessionName = getSessionName();
String uniqueName = getPersistenceUnitUniqueName();
EntityManagerSetupImpl newSetupImpl = new EntityManagerSetupImpl(uniqueName, sessionName);
newSetupImpl.setIsInContainerMode(isInContainerMode);
newSetupImpl.enableWeaving = enableWeaving;
Map<Object, Object> refreshProperties = new HashMap<>();
refreshProperties.putAll(getSession().getProperties());
if (properties != null){
refreshProperties.putAll(properties);
}
newSetupImpl.predeploy(getPersistenceUnitInfo(), refreshProperties);
// newSetupImpl has been already predeployed, predeploy will just increment factoryCount.
if (!isInContainerMode) {
newSetupImpl.predeploy(getPersistenceUnitInfo(), refreshProperties);
}
synchronized (EntityManagerFactoryProvider.emSetupImpls) {
SessionManager.getManager().getSessions().remove(sessionName, getSession());
if (EntityManagerFactoryProvider.emSetupImpls.get(sessionName).equals(this)){
EntityManagerFactoryProvider.emSetupImpls.remove(sessionName);
}
setIsMetadataExpired(true);
//stop this EntityManagerSetupImpl's session from processing refresh commands. The new session should listen instead.
getSession().setRefreshMetadataListener(null);
EntityManagerFactoryProvider.addEntityManagerSetupImpl(sessionName, newSetupImpl);
}
return newSetupImpl;
}
/**
* This method is just a wrapper on refreshMetadata so that core does not need a dependency on JPA
* due to the EntityManagerSetupImpl return value. This method satisfies the MetedataRefreshListener implementation
* and is called by incoming RCM refresh commands
*
* @see refreshMetadata
*/
@Override
public void triggerMetadataRefresh(Map properties){
refreshMetadata(properties);
}
/**
* INTERNAL:
* Generate the DDL per the properties specified.
*/
public void writeDDL(Map props, DatabaseSessionImpl session, ClassLoader classLoader) {
if (this.compositeMemberEmSetupImpls == null) {
// Generate the DDL if we find either EclipseLink or JPA DDL generation properties.
// Note, we do one or the other, that is, we do not mix the properties by default
// but we may use some with both, e.g. APP_LOCATION. EclipseLink properties
// override JPA properties.
if (hasConfigProperty(DDL_GENERATION, props)) {
// We have EclipseLink DDL generation properties.
String ddlGeneration = getConfigPropertyAsString(DDL_GENERATION, props).toLowerCase(Locale.ROOT);
if (! ddlGeneration.equals(NONE)) {
writeDDL(ddlGeneration, props, session, classLoader);
}
} else {
// Look for JPA schema generation properties.
// Schema generation for the database.
if (hasConfigProperty(SCHEMA_GENERATION_DATABASE_ACTION, props)) {
String databaseGenerationAction = getConfigPropertyAsString(SCHEMA_GENERATION_DATABASE_ACTION, props).toLowerCase(Locale.ROOT);
if (! databaseGenerationAction.equals(SCHEMA_GENERATION_NONE_ACTION)) {
if (databaseGenerationAction.equals(SCHEMA_GENERATION_CREATE_ACTION)) {
writeDDL(SCHEMA_GENERATION_CREATE_SOURCE, SCHEMA_GENERATION_CREATE_SCRIPT_SOURCE, TableCreationType.CREATE, props, session, classLoader);
} else if (databaseGenerationAction.equals(PersistenceUnitProperties.CREATE_OR_EXTEND)) {
writeDDL(SCHEMA_GENERATION_CREATE_SOURCE, SCHEMA_GENERATION_CREATE_SCRIPT_SOURCE, TableCreationType.EXTEND, props, session, classLoader);
} else if (databaseGenerationAction.equals(SCHEMA_GENERATION_DROP_ACTION)) {
writeDDL(SCHEMA_GENERATION_DROP_SOURCE, SCHEMA_GENERATION_DROP_SCRIPT_SOURCE, TableCreationType.DROP, props, session, classLoader);
} else if (databaseGenerationAction.equals(SCHEMA_GENERATION_DROP_AND_CREATE_ACTION)) {
writeDDL(SCHEMA_GENERATION_DROP_SOURCE, SCHEMA_GENERATION_DROP_SCRIPT_SOURCE, TableCreationType.DROP, props, session, classLoader);
writeDDL(SCHEMA_GENERATION_CREATE_SOURCE, SCHEMA_GENERATION_CREATE_SCRIPT_SOURCE, TableCreationType.CREATE, props, session, classLoader);
} else {
String validOptions = SCHEMA_GENERATION_CREATE_ACTION + ", " + SCHEMA_GENERATION_DROP_ACTION + ", " + SCHEMA_GENERATION_DROP_AND_CREATE_ACTION + ", " + PersistenceUnitProperties.CREATE_OR_EXTEND;
session.log(SessionLog.WARNING, SessionLog.PROPERTIES, "ddl_generation_unknown_property_value", new Object[] {SCHEMA_GENERATION_DATABASE_ACTION, databaseGenerationAction, persistenceUnitInfo.getPersistenceUnitName(), validOptions});
}
}
}
// Schema generation for target scripts.
if (hasConfigProperty(SCHEMA_GENERATION_SCRIPTS_ACTION, props)) {
String scriptsGenerationAction = getConfigPropertyAsString(SCHEMA_GENERATION_SCRIPTS_ACTION, props).toLowerCase(Locale.ROOT);
if (! scriptsGenerationAction.equals(SCHEMA_GENERATION_NONE_ACTION)) {
if (scriptsGenerationAction.equals(SCHEMA_GENERATION_CREATE_ACTION)) {
writeMetadataDDLToScript(TableCreationType.CREATE, props, session, classLoader);
} else if (scriptsGenerationAction.equals(PersistenceUnitProperties.CREATE_OR_EXTEND)) {
writeMetadataDDLToScript(TableCreationType.EXTEND, props, session, classLoader);
} else if (scriptsGenerationAction.equals(SCHEMA_GENERATION_DROP_ACTION)) {
writeMetadataDDLToScript(TableCreationType.DROP, props, session, classLoader);
} else if (scriptsGenerationAction.equals(SCHEMA_GENERATION_DROP_AND_CREATE_ACTION)) {
writeMetadataDDLToScript(TableCreationType.DROP_AND_CREATE, props, session, classLoader);
} else {
String validOptions = SCHEMA_GENERATION_CREATE_ACTION + ", " + SCHEMA_GENERATION_DROP_ACTION + ", " + SCHEMA_GENERATION_DROP_AND_CREATE_ACTION;
session.log(SessionLog.WARNING, SessionLog.PROPERTIES, "ddl_generation_unknown_property_value", new Object[] {SCHEMA_GENERATION_SCRIPTS_ACTION, scriptsGenerationAction, persistenceUnitInfo.getPersistenceUnitName(), validOptions});
}
}
}
// Once we've generated any and all DDL, check for load scripts.
writeSourceScriptToDatabase(getConfigProperty(SCHEMA_GENERATION_SQL_LOAD_SCRIPT_SOURCE, props), session, classLoader);
}
} else {
// composite
Map compositeMemberMapOfProperties = (Map)getConfigProperty(PersistenceUnitProperties.COMPOSITE_UNIT_PROPERTIES, props);
for(EntityManagerSetupImpl compositeMemberEmSetupImpl : this.compositeMemberEmSetupImpls) {
// the properties guaranteed to be non-null after updateCompositeMemberProperties call
Map compositeMemberProperties = (Map)compositeMemberMapOfProperties.get(compositeMemberEmSetupImpl.getPersistenceUnitInfo().getPersistenceUnitName());
compositeMemberEmSetupImpl.writeDDL(compositeMemberProperties, session, classLoader);
}
}
}
/**
* INTERNAL:
* Generate the DDL from the persistence unit metadata. This DDL generation
* utilizes the EclipseLink DDL properties.
*/
protected void writeDDL(String ddlGeneration, Map props, DatabaseSessionImpl session, ClassLoader classLoader) {
// By default the table creation type will be 'none'.
TableCreationType ddlType = TableCreationType.NONE;
if (ddlGeneration.equals(PersistenceUnitProperties.CREATE_ONLY)) {
ddlType = TableCreationType.CREATE;
} else if (ddlGeneration.equals(PersistenceUnitProperties.DROP_ONLY)) {
ddlType = TableCreationType.DROP;
} else if (ddlGeneration.equals(PersistenceUnitProperties.DROP_AND_CREATE)) {
ddlType = TableCreationType.DROP_AND_CREATE;
} else if (ddlGeneration.equals(PersistenceUnitProperties.CREATE_OR_EXTEND)) {
ddlType = TableCreationType.EXTEND;
} else {
// Log a warning if we have an unknown ddl generation.
String validOptions = PersistenceUnitProperties.NONE + ", " +
PersistenceUnitProperties.CREATE_ONLY + ", " +
PersistenceUnitProperties.DROP_ONLY + ", " +
PersistenceUnitProperties.DROP_AND_CREATE + ", " +
PersistenceUnitProperties.CREATE_OR_EXTEND;
session.log(SessionLog.WARNING, SessionLog.PROPERTIES, "ddl_generation_unknown_property_value", new Object[] {PersistenceUnitProperties.DDL_GENERATION, ddlGeneration, persistenceUnitInfo.getPersistenceUnitName(), validOptions});
}
if (ddlType != TableCreationType.NONE) {
String ddlGenerationMode = getConfigPropertyAsString(PersistenceUnitProperties.DDL_GENERATION_MODE, props, PersistenceUnitProperties.DEFAULT_DDL_GENERATION_MODE);
// Optimize for cases where the value is explicitly set to NONE
if (! ddlGenerationMode.equals(NONE)) {
if (isCompositeMember()) {
// debug output added to make it easier to navigate the log because the method is called outside of composite member deploy
session.log(SessionLog.FINEST, SessionLog.PROPERTIES, "composite_member_begin_call", new Object[]{"generateDDL", persistenceUnitInfo.getPersistenceUnitName(), state});
}
SchemaManager mgr = new SchemaManager(session);
if (ddlGenerationMode.equals(PersistenceUnitProperties.DDL_DATABASE_GENERATION) || ddlGenerationMode.equals(PersistenceUnitProperties.DDL_BOTH_GENERATION)) {
writeDDLToDatabase(mgr, ddlType);
}
if (ddlGenerationMode.equals(PersistenceUnitProperties.DDL_SQL_SCRIPT_GENERATION)|| ddlGenerationMode.equals(PersistenceUnitProperties.DDL_BOTH_GENERATION)) {
String appLocation = getConfigPropertyAsString(PersistenceUnitProperties.APP_LOCATION, props, PersistenceUnitProperties.DEFAULT_APP_LOCATION);
// These could be a string (file name urls) or actual writers.
Object createDDLJdbc = getConfigProperty(PersistenceUnitProperties.CREATE_JDBC_DDL_FILE, props, PersistenceUnitProperties.DEFAULT_CREATE_JDBC_FILE_NAME);
Object dropDDLJdbc = getConfigProperty(PersistenceUnitProperties.DROP_JDBC_DDL_FILE, props, PersistenceUnitProperties.DEFAULT_DROP_JDBC_FILE_NAME);
writeDDLToFiles(mgr, appLocation, createDDLJdbc, dropDDLJdbc, ddlType, props);
}
// Log a warning if we have an unknown ddl generation mode.
if ( (! ddlGenerationMode.equals(PersistenceUnitProperties.DDL_DATABASE_GENERATION)) && (! ddlGenerationMode.equals(PersistenceUnitProperties.DDL_SQL_SCRIPT_GENERATION)) && (! ddlGenerationMode.equals(PersistenceUnitProperties.DDL_BOTH_GENERATION))) {
String validOptions = PersistenceUnitProperties.DDL_DATABASE_GENERATION + ", " +
PersistenceUnitProperties.DDL_SQL_SCRIPT_GENERATION + ", " +
PersistenceUnitProperties.DDL_BOTH_GENERATION;
session.log(SessionLog.WARNING, SessionLog.PROPERTIES, "ddl_generation_unknown_property_value", new Object[] {PersistenceUnitProperties.DDL_GENERATION_MODE, ddlGenerationMode, persistenceUnitInfo.getPersistenceUnitName(), validOptions});
}
if (isCompositeMember()) {
// debug output added to make it easier to navigate the log because the method is called outside of composite member deploy
session.log(SessionLog.FINEST, SessionLog.PROPERTIES, "composite_member_end_call", new Object[]{"generateDDL", persistenceUnitInfo.getPersistenceUnitName(), state});
}
}
}
}
/**
* INTERNAL:
* Generate the DDL per the properties given.
*/
protected void writeDDL(String generationSourceProperty, String scriptGenerationSourceProperty, TableCreationType tableCreationType, Map props, DatabaseSessionImpl session, ClassLoader loader) {
String generationSource = getConfigPropertyAsString(generationSourceProperty, props);
Object scriptGenerationSource = getConfigProperty(scriptGenerationSourceProperty, props);
if (generationSource == null) {
if (scriptGenerationSource == null) {
writeMetadataDDLToDatabase(tableCreationType, props, session, loader);
} else {
writeSourceScriptToDatabase(scriptGenerationSource, session, loader);
}
} else if (generationSource.equals(SCHEMA_GENERATION_METADATA_SOURCE)) {
writeMetadataDDLToDatabase(tableCreationType, props, session, loader);
} else if (generationSource.equals(SCHEMA_GENERATION_SCRIPT_SOURCE)) {
writeSourceScriptToDatabase(scriptGenerationSource, session, loader);
} else if (generationSource.equals(SCHEMA_GENERATION_METADATA_THEN_SCRIPT_SOURCE)) {
writeMetadataDDLToDatabase(tableCreationType, props, session, loader);
writeSourceScriptToDatabase(scriptGenerationSource, session, loader);
} else if (generationSource.equals(SCHEMA_GENERATION_SCRIPT_THEN_METADATA_SOURCE)) {
writeSourceScriptToDatabase(scriptGenerationSource, session, loader);
writeMetadataDDLToDatabase(tableCreationType, props, session, loader);
} else {
String validOptions = SCHEMA_GENERATION_METADATA_SOURCE + ", " +
SCHEMA_GENERATION_SCRIPT_SOURCE + ", " +
SCHEMA_GENERATION_METADATA_THEN_SCRIPT_SOURCE + ", " +
SCHEMA_GENERATION_SCRIPT_THEN_METADATA_SOURCE;
session.log(SessionLog.WARNING, SessionLog.PROPERTIES, "ddl_generation_unknown_property_value", new Object[] {generationSourceProperty, generationSource, persistenceUnitInfo.getPersistenceUnitName(), validOptions});
}
}
/**
* INTERNAL:
* Generate and write DDL from the persistence unit metadata to the database.
*/
protected void writeDDLToDatabase(SchemaManager mgr, TableCreationType ddlType) {
String str = getConfigPropertyAsString(PersistenceUnitProperties.JAVASE_DB_INTERACTION, null ,"true");
boolean interactWithDB = Boolean.parseBoolean(str.toLowerCase());
if (!interactWithDB){
return;
}
generateDefaultTables(mgr, ddlType);
}
/**
* @deprecated Extenders should now use
* {@link #writeDDLToFiles(SchemaManager, String, Object, Object, TableCreationType, Map)}
*/
@Deprecated
protected void writeDDLToFiles(SchemaManager mgr, String appLocation, Object createDDLJdbc, Object dropDDLJdbc,
TableCreationType ddlType) {
writeDDLToFiles(mgr, appLocation, createDDLJdbc, dropDDLJdbc, ddlType, Collections.EMPTY_MAP);
}
/**
* Write the DDL to the files provided.
*/
protected void writeDDLToFiles(SchemaManager mgr, String appLocation, Object createDDLJdbc, Object dropDDLJdbc, TableCreationType ddlType, Map props) {
// Ensure that the appLocation string ends with File.separator if
// specified. In JPA there is no default for app location, however, if
// the user did specify one, we'll use it.
String appLocationPrefix = (appLocation == null) ? "" : addFileSeperator(appLocation);
if (ddlType.equals(TableCreationType.CREATE) || ddlType.equals(TableCreationType.DROP_AND_CREATE) || ddlType.equals(TableCreationType.EXTEND)) {
if (createDDLJdbc == null) {
// Using EclipseLink properties, the create script has a default.
// Using JPA properties, the user must specify the target else an exception must be thrown.
throw new IllegalArgumentException(ExceptionLocalization.buildMessage("jpa21-ddl-create-script-target-not-specified"));
} else if (createDDLJdbc instanceof Writer) {
mgr.outputCreateDDLToWriter((Writer) createDDLJdbc);
} else {
// Assume it is a String file name.
mgr.outputCreateDDLToFile(appLocationPrefix + createDDLJdbc);
}
}
if (ddlType.equals(TableCreationType.DROP) || ddlType.equals(TableCreationType.DROP_AND_CREATE)) {
if (dropDDLJdbc == null) {
// Using EclipseLink properties, the drop script has a default.
// Using JPA properties, the user must specify the target else an exception must be thrown.
throw new IllegalArgumentException(ExceptionLocalization.buildMessage("jpa21-ddl-drop-script-target-not-specified"));
} else if (dropDDLJdbc instanceof Writer) {
mgr.outputDropDDLToWriter((Writer) dropDDLJdbc);
} else if (dropDDLJdbc instanceof String) {
mgr.outputDropDDLToFile(appLocationPrefix + dropDDLJdbc);
} else {
throw new PersistenceException(ExceptionLocalization.buildMessage("jpa21-ddl-invalid-target-script-type", new Object[]{ dropDDLJdbc , dropDDLJdbc.getClass()}));
}
}
String propString = getConfigPropertyAsString(PersistenceUnitProperties.SCHEMA_GENERATION_SCRIPT_TERMINATE_STATEMENTS, props);
boolean terminator = Boolean.parseBoolean(propString);
mgr.setCreateSQLFiles(terminator);
generateDefaultTables(mgr, ddlType);
mgr.closeDDLWriter();
}
/**
* INTERNAL:
* Generate and write DDL from the persistence unit metadata to the database.
*/
protected void writeMetadataDDLToDatabase(TableCreationType tableCreationType, Map props, DatabaseSessionImpl session, ClassLoader classLoader) {
SchemaManager mgr = new SchemaManager(session);
// Set the create database schemas flag on the schema manager.
String createSchemas = getConfigPropertyAsString(SCHEMA_GENERATION_CREATE_DATABASE_SCHEMAS, props);
mgr.setCreateDatabaseSchemas(createSchemas != null && createSchemas.equalsIgnoreCase("true"));
writeDDLToDatabase(mgr, tableCreationType);
}
/**
* INTERNAL:
* Generate and write DDL from the persistence unit metadata to scripts.
*/
protected void writeMetadataDDLToScript(TableCreationType tableCreationType, Map props, DatabaseSessionImpl session, ClassLoader classLoader) {
SchemaManager mgr = new SchemaManager(session);
// Set the create database schemas flag on the schema manager.
String createSchemas = getConfigPropertyAsString(SCHEMA_GENERATION_CREATE_DATABASE_SCHEMAS, props);
mgr.setCreateDatabaseSchemas(createSchemas != null && createSchemas.equalsIgnoreCase("true"));
writeDDLToFiles(mgr, getConfigPropertyAsString(PersistenceUnitProperties.APP_LOCATION, props), getConfigProperty(SCHEMA_GENERATION_SCRIPTS_CREATE_TARGET, props), getConfigProperty(SCHEMA_GENERATION_SCRIPTS_DROP_TARGET, props), tableCreationType, props);
}
/**
* This method will read SQL from a reader or URL and send it through
* to the database. This could open up the database to SQL injection if
* not careful.
*/
protected void writeSourceScriptToDatabase(Object source, DatabaseSessionImpl session, ClassLoader loader) {
if (source != null) {
Reader reader = null;
try {
if (source instanceof Reader) {
reader = (Reader) source;
} else if (source instanceof String) {
// Try to load the resource first, if not assume it as a well formed URL. If not, throw an exception.
URL sourceURL = loader.getResource((String) source);
if (sourceURL == null) {
try {
sourceURL = new URL((String) source);
} catch (MalformedURLException e) {
throw new PersistenceException(ExceptionLocalization.buildMessage("jpa21-ddl-source-script-not-found", new Object[]{ source }), e);
}
}
URLConnection connection = sourceURL.openConnection();
// Set to false to prevent locking of jar files on Windows. EclipseLink issue 249664
connection.setUseCaches(false);
reader = new InputStreamReader(connection.getInputStream(), "UTF-8");
} else {
throw new PersistenceException(ExceptionLocalization.buildMessage("jpa21-ddl-invalid-source-script-type", new Object[]{ source , source.getClass()}));
}
if (reader != null) {
StringBuffer sqlBuffer;
int data = reader.read();
// While there is still data to read, read line by line.
while (data != -1) {
sqlBuffer = new StringBuffer();
char aChar = (char) data;
// Read till the end of the line or maybe even file.
while (aChar != '\n' && data != -1) {
sqlBuffer.append(aChar);
// Read next character.
data = reader.read();
aChar = (char) data;
}
// Remove trailing and leading white space characters.
String sqlString = sqlBuffer.toString().trim();
// If the string isn't empty, then fire it.
if ((! sqlString.equals("")) && (! sqlString.startsWith("#"))) {
try {
session.executeNonSelectingSQL(sqlString);
} catch (DatabaseException e) {
// Swallow any database exceptions as these could
// be drop failures of a table that doesn't exist etc.
// SQLExceptions will be thrown to the user.
}
}
data = reader.read();
}
reader.close();
}
} catch (IOException e) {
throw new PersistenceException(ExceptionLocalization.buildMessage("jpa21-ddl-source-script-io-exception", new Object[]{source}), e);
} finally {
if (reader != null) {
try {
reader.close();
} catch (IOException e) {
// ignore.
}
}
}
}
}
//JPA-RS feature may be provided by a jar on the path or missing
private static String shouldWeaveRestByDefault(ClassLoader cl) {
try {
cl.loadClass("org.eclipse.persistence.internal.jpa.rs.weaving.PersistenceWeavedRest");
return "true";
} catch (Throwable t) {
//ignore
}
return "false";
}
}