org.eclipse.persistence.sessions.Project Maven / Gradle / Ivy
/*
* Copyright (c) 1998, 2021 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0,
* or the Eclipse Distribution License v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
// Contributors:
// Oracle - initial API and implementation from Oracle TopLink
//
// 04/30/2009-2.0 Michael O'Brien
// - 266912: JPA 2.0 Metamodel API (part of Criteria API)
// Add Set mappedSuperclassDescriptors
// to support the Metamodel API
// 06/17/2009-2.0 Michael O'Brien
// - 266912: change mappedSuperclassDescriptors Set to a Map
// keyed on MetadataClass - avoiding the use of a hashCode/equals
// override on RelationalDescriptor, but requiring a contains check prior to a put
// 09/23/2009-2.0 Michael O'Brien
// - 266912: Add metamodelIdClassMap to store IdClass types for exclusive
// use by the IdentifiableTypeImpl class in the JPA 2.0 Metamodel API
// 06/30/2011-2.3.1 Guy Pelletier
// - 341940: Add disable/enable allowing native queries
// 09/09/2011-2.3.1 Guy Pelletier
// - 356197: Add new VPD type to MultitenantType
// 09/14/2011-2.3.1 Guy Pelletier
// - 357533: Allow DDL queries to execute even when Multitenant entities are part of the PU
// 14/05/2012-2.4 Guy Pelletier
// - 376603: Provide for table per tenant support for multitenant applications
// 31/05/2012-2.4 Guy Pelletier
// - 381196: Multitenant persistence units with a dedicated emf should allow for DDL generation.
// 08/11/2012-2.5 Guy Pelletier
// - 393867: Named queries do not work when using EM level Table Per Tenant Multitenancy
// 04/11/2018 - Will Dazey
// - 533148 : Add the eclipselink.jpa.sql-call-deferral property
package org.eclipse.persistence.sessions;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Vector;
import org.eclipse.persistence.annotations.IdValidation;
import org.eclipse.persistence.config.CacheIsolationType;
import org.eclipse.persistence.core.sessions.CoreProject;
import org.eclipse.persistence.descriptors.ClassDescriptor;
import org.eclipse.persistence.descriptors.MultitenantPolicy;
import org.eclipse.persistence.descriptors.partitioning.PartitioningPolicy;
import org.eclipse.persistence.internal.helper.ConcurrentFixedCache;
import org.eclipse.persistence.internal.helper.Helper;
import org.eclipse.persistence.internal.helper.NonSynchronizedVector;
import org.eclipse.persistence.internal.identitymaps.AbstractIdentityMap;
import org.eclipse.persistence.internal.identitymaps.IdentityMap;
import org.eclipse.persistence.internal.sessions.AbstractSession;
import org.eclipse.persistence.internal.sessions.DatabaseSessionImpl;
import org.eclipse.persistence.queries.AttributeGroup;
import org.eclipse.persistence.queries.DatabaseQuery;
import org.eclipse.persistence.queries.QueryResultsCachePolicy;
import org.eclipse.persistence.queries.SQLResultSetMapping;
import org.eclipse.persistence.sessions.server.ConnectionPolicy;
import org.eclipse.persistence.sessions.server.Server;
import org.eclipse.persistence.sessions.server.ServerSession;
/**
* Purpose: Maintain all of the EclipseLink configuration information for a system.
* Responsibilities:
* - Project options and defaults
*
- Database login information
*
- Descriptors
*
- Validate Descriptors
*
- Maintain sequencing information {@literal &} other project options
*
*
* @see DatabaseLogin
*/
public class Project extends CoreProject implements Serializable, Cloneable {
protected String name;
protected Login datasourceLogin;
protected Map, ClassDescriptor> descriptors;
protected List orderedDescriptors;
// Currently only one is supported.
protected MultitenantPolicy multitenantPolicy;
/** Holds the default set of read-only classes that apply to each UnitOfWork. */
protected Vector> defaultReadOnlyClasses;
/** Cache the EJBQL descriptor aliases. */
protected Map aliasDescriptors;
/** Cache if any descriptor is isolated. (set during initialization) */
protected boolean hasIsolatedClasses;
/** Cache if all descriptors are isolated in the unit of work. (set during initialization) */
protected boolean hasNonIsolatedUOWClasses;
/** Cache if any descriptor has history. (set during initialization) */
protected boolean hasGenericHistorySupport;
/** Cache if any descriptor is using ProxyIndirection. (set during initialization */
protected boolean hasProxyIndirection;
/** This a collection of 'maps' that allow users to map custom SQL to query results */
protected Map sqlResultSetMappings;
/** PERF: Provide an JPQL parse cache to optimize dynamic JPQL. */
protected transient ConcurrentFixedCache jpqlParseCache;
/** Define the default setting for configuring if dates and calendars are mutable. */
protected boolean defaultTemporalMutable = false;
/** Indicates whether there is at least one descriptor that has at least on mapping that
* require a call on deleted objects to update change sets.
*/
protected transient boolean hasMappingsPostCalculateChangesOnDeleted = false;
/** Default value for ClassDescriptor.identityMapClass. */
protected Class defaultIdentityMapClass = AbstractIdentityMap.getDefaultIdentityMapClass();
/** Default value for ClassDescriptor.identityMapSize. */
protected int defaultIdentityMapSize = 100;
/** Default value for ClassDescriptor.isIsolated. */
protected CacheIsolationType defaultCacheIsolation;
/** Default value for query caching options for all named queries. */
protected QueryResultsCachePolicy defaultQueryResultsCachePolicy;
/** Default value for ClassDescriptor.idValidation. */
protected IdValidation defaultIdValidation;
/** List of queries - once Project is initialized, these are copied to the Session. */
protected List queries;
/** List of named AttributeGroups - once Project is initialized, these are copied to the Session. */
protected Map attributeGroups = null;
/** List of queries from JPA that need special processing before execution. */
protected List jpaQueries;
/** List of queries from JPA that may special processing and handling before execution. */
protected List jpaTablePerTenantQueries;
/** Flag that allows native queries or not */
protected boolean allowNativeSQLQueries = true;
/** Flag that allows DDL generation of table per tenant multitenant descriptors */
protected boolean allowTablePerMultitenantDDLGeneration = false;
/** Flag that allows call deferral to be disabled */
protected boolean allowSQLDeferral = true;
/** Flag that allows transform named stored procedure parameters into positional/index based */
protected boolean namingIntoIndexed = false;
/** Flag that allows extended logging of JPA L2 cache or not. */
protected boolean allowExtendedCacheLogging = false;
/** Flag that allows extended thread logging or not. */
protected boolean allowExtendedThreadLogging = false;
/** Flag that allows add to extended thread logging output thread stack trace or not.*/
protected boolean allowExtendedThreadLoggingThreadDump = false;
/** Flag that allows query result cache validation or not.*/
protected boolean allowQueryResultsCacheValidation = false;
/**
* Mapped Superclasses (JPA 2) collection of parent non-relational descriptors keyed on MetadataClass
* without creating a compile time dependency on JPA.
* The descriptor values of this map must not be replaced by a put() so that the
* mappings on the initial descriptor are not overwritten.
* These descriptors are only to be used by Metamodel generation.
* @since EclipseLink 1.2 for the JPA 2.0 Reference Implementation
*/
protected Map mappedSuperclassDescriptors;
/**
* Store the IdClass Id attributes for exclusive use by the Metamodel API
* Keyed on the fully qualified accessible object owner class name.
* Value is a List of the fully qualified id class name or id attribute name.
* @since EclipseLink 1.2 for the JPA 2.0 Reference Implementation
*/
protected Map> metamodelIdClassMap;
/** Map of named partitioning policies, keyed by their name. */
protected Map partitioningPolicies;
/** Ensures that only one thread at a time can add/remove descriptors */
protected Object descriptorsLock = Boolean.TRUE;
/** VPD connection settings */
protected String vpdIdentifier;
protected String vpdLastIdentifierClassName; // Used for validation exception.
/** used for Caching JPA projects */
protected Collection classNamesForWeaving;
protected Collection structConverters;
/** Force all queries and relationships to use deferred lock strategy during object building and L2 cache population. */
protected boolean queryCacheForceDeferredLocks = false;
/**
* PUBLIC:
* Create a new project.
*/
public Project() {
this.name = "";
this.descriptors = new HashMap<>();
this.defaultReadOnlyClasses = NonSynchronizedVector.newInstance();
this.orderedDescriptors = new ArrayList<>();
this.hasIsolatedClasses = false;
this.hasGenericHistorySupport = false;
this.hasProxyIndirection = false;
this.jpqlParseCache = new ConcurrentFixedCache(200);
this.queries = new ArrayList<>();
this.mappedSuperclassDescriptors = new HashMap<>(2);
this.metamodelIdClassMap = new HashMap<>();
this.attributeGroups = new HashMap<>();
}
/**
* PUBLIC:
* Create a new project that will connect through the login information.
* This method can be used if the project is being create in code instead of being read from a file.
*/
public Project(Login login) {
this();
this.datasourceLogin = login;
}
/**
* PUBLIC:
* Create a new project that will connect through JDBC using the login information.
* This method can be used if the project is being create in code instead of being read from a file.
*/
public Project(DatabaseLogin login) {
this();
this.datasourceLogin = login;
}
/**
* PUBLIC:
* Return the default values for query caching options for all named queries.
*/
public QueryResultsCachePolicy getDefaultQueryResultsCachePolicy() {
return defaultQueryResultsCachePolicy;
}
/**
* PUBLIC:
* Set the default values for query caching options for all named queries.
* By default no query caching is used.
*/
public void setDefaultQueryResultsCachePolicy(QueryResultsCachePolicy defaultQueryResultsCachePolicy) {
this.defaultQueryResultsCachePolicy = defaultQueryResultsCachePolicy;
}
/**
* PUBLIC:
* Get property to Force all queries and relationships to use deferred lock strategy during object building and L2 cache population.
*/
public boolean isQueryCacheForceDeferredLocks() {
return queryCacheForceDeferredLocks;
}
/**
* PUBLIC:
* Set property to Force all queries and relationships to use deferred lock strategy during object building and L2 cache population.
* By default there is false value - use use mixed object cache locking strategy (depends on relationship and fetch type) */
public void setQueryCacheForceDeferredLocks(boolean queryCacheForceDeferredLocks) {
this.queryCacheForceDeferredLocks = queryCacheForceDeferredLocks;
}
/**
* PUBLIC:
* Return the default setting for configuring if dates and calendars are mutable.
* Mutable means that changes to the date's year/month/day are detected.
* By default they are treated as not mutable.
*/
public boolean getDefaultTemporalMutable() {
return defaultTemporalMutable;
}
/**
* PUBLIC:
* Set the default setting for configuring if dates and calendars are mutable.
* Mutable means that changes to the date's year/month/day are detected.
* By default they are treated as not mutable.
*/
public void setDefaultTemporalMutable(boolean defaultTemporalMutable) {
this.defaultTemporalMutable = defaultTemporalMutable;
}
/**
* INTERNAL:
* Return all pre-defined not yet parsed JPQL queries.
*/
public List getJPAQueries() {
// PERF: lazy init, not normally required.
if (jpaQueries == null) {
jpaQueries = new ArrayList<>();
}
return jpaQueries;
}
/**
* INTERNAL:
* Return all pre-defined not yet parsed JPQL queries to table per tenant
* entities.
*/
public List getJPATablePerTenantQueries() {
// PERF: lazy init, not normally required.
if (jpaTablePerTenantQueries == null) {
jpaTablePerTenantQueries = new ArrayList<>();
}
return jpaTablePerTenantQueries;
}
/**
* INTERNAL:
* Return the JPQL parse cache.
* This is used to optimize dynamic JPQL.
*/
public ConcurrentFixedCache getJPQLParseCache() {
if (jpqlParseCache==null) {
jpqlParseCache = new ConcurrentFixedCache(200);
}
return jpqlParseCache;
}
/**
* ADVANCED:
* Set the JPQL parse cache max size.
* This is used to optimize dynamic JPQL.
*/
public void setJPQLParseCacheMaxSize(int maxSize) {
setJPQLParseCache(new ConcurrentFixedCache(maxSize));
}
/**
* ADVANCED:
* Return the JPQL parse cache max size.
* This is used to optimize dynamic JPQL.
*/
public int getJPQLParseCacheMaxSize() {
return getJPQLParseCache().getMaxSize();
}
/**
* INTERNAL:
* Set the JPQL parse cache.
* This is used to optimize dynamic JPQL.
*/
protected void setJPQLParseCache(ConcurrentFixedCache jpqlParseCache) {
this.jpqlParseCache = jpqlParseCache;
}
/**
* INTERNAL:
* List of queries that upon initialization are copied over to the session
*/
public List getQueries() {
return queries;
}
/**
* INTERNAL:
*/
public void setQueries(List queries) {
this.queries = queries;
}
/**
* INTERNAL:
* List of named AttributesGroups that will be copied to the session at initialization time.
*/
public Map getAttributeGroups(){
return this.attributeGroups;
}
/**
* INTERNAL:
* Set the VPD identifier for this project. This identifier should be
* populated from a descriptor VPDMultitenantPolicy and should not be
* set directly.
*/
public void setVPDIdentifier(String vpdIdentifier) {
this.vpdIdentifier = vpdIdentifier;
}
/**
* INTERNAL:
* Set from individual descriptors from the project that set a VPD
* identifier and used in validation exception.
*/
public void setVPDLastIdentifierClassName(String vpdLastIdentifierClassName) {
this.vpdLastIdentifierClassName = vpdLastIdentifierClassName;
}
/**
* PUBLIC:
* Add the read-only class which apply to each UnitOfWork created by default.
*/
public void addDefaultReadOnlyClass(Class readOnlyClass) {
getDefaultReadOnlyClasses().addElement(readOnlyClass);
}
/**
* PUBLIC:
* Add the descriptor to the project.
*/
@Override
public void addDescriptor(ClassDescriptor descriptor) {
getOrderedDescriptors().add(descriptor);
String alias = descriptor.getAlias();
if (alias != null) {
addAlias(alias, descriptor);
}
// Avoid loading class definition at this point if we haven't done so yet.
if ((descriptors != null) && !descriptors.isEmpty()) {
getDescriptors().put(descriptor.getJavaClass(), descriptor);
}
}
/**
* INTERNAL: Used by the BuilderInterface when reading a Project from INI files.
* @param descriptor The descriptor to be added to the session and the project.
* @param session The current database session.
*/
public void addDescriptor(final ClassDescriptor descriptor, final DatabaseSessionImpl session) {
synchronized (this.descriptorsLock) {
if (session.isConnected()) {
final String alias = descriptor.getAlias();
// Descriptor aliases may be concurrently accessed by other threads.
// Make a clone, add new descriptor to the clone, override original with the clone.
if (alias != null) {
@SuppressWarnings({"unchecked"})
final Map aliasDescriptorsClone = getAliasDescriptors() != null
? (Map)((HashMap) getAliasDescriptors()).clone()
: new HashMap<>();
aliasDescriptorsClone.put(alias, descriptor);
setAliasDescriptors(aliasDescriptorsClone);
}
// Descriptors may be concurrently accessed by other threads.
// Make a clone, add new descriptor to the clone, override original with the clone.
@SuppressWarnings({"unchecked"})
final Map, ClassDescriptor> descriptorsClone = (Map, ClassDescriptor>)((HashMap, ClassDescriptor>) getDescriptors()).clone();
descriptorsClone.put(descriptor.getJavaClass(), descriptor);
setDescriptors(descriptorsClone);
session.copyDescriptorsFromProject();
session.initializeDescriptorIfSessionAlive(descriptor);
getOrderedDescriptors().add(descriptor);
} else {
addDescriptor(descriptor);
}
}
}
/**
* INTERNAL:
* Add the descriptors to the session.
* All persistent classes must have a descriptor registered for them with the session.
* This method allows for a batch of descriptors to be added at once so that EclipseLink
* can resolve the dependencies between the descriptors and perform initialization optimally.
* @param descriptors The descriptors to be added to the session and the project.
* @param session The current database session.
*/
public void addDescriptors(final Collection descriptors, final DatabaseSessionImpl session) {
synchronized (this.descriptorsLock) {
if (session.isConnected()) {
// Descriptor aliases may be concurrently accessed by other threads.
// Make a clone, add new descriptors to the clone, override original with the clone.
@SuppressWarnings({"unchecked"})
final Map aliasDescriptorsClone = getAliasDescriptors() != null
? (Map)((HashMap) getAliasDescriptors()).clone()
: new HashMap<>();
// Descriptors may be concurrently accessed by other threads.
// Make a clone, add new descriptors to the clone, override original with the clone.
@SuppressWarnings({"unchecked"})
final Map, ClassDescriptor> descriptorsClone = (Map, ClassDescriptor>)((HashMap, ClassDescriptor>) getDescriptors()).clone();
for (ClassDescriptor descriptor : (Collection) descriptors) {
descriptorsClone.put(descriptor.getJavaClass(), descriptor);
final String alias = descriptor.getAlias();
if (alias != null) {
aliasDescriptorsClone.put(alias, descriptor);
}
}
if (!aliasDescriptorsClone.isEmpty()) {
setAliasDescriptors(aliasDescriptorsClone);
}
setDescriptors(descriptorsClone);
session.copyDescriptorsFromProject();
session.initializeDescriptors(descriptors);
} else {
final Map, ClassDescriptor> projectDescriptors = getDescriptors();
for (ClassDescriptor descriptor : (Collection) descriptors) {
final String alias = descriptor.getAlias();
projectDescriptors.put(descriptor.getJavaClass(), descriptor);
if (alias != null) {
addAlias(alias, descriptor);
}
}
}
getOrderedDescriptors().addAll(descriptors);
}
}
/**
* PUBLIC:
* Merge the descriptors from another project into this one.
* All persistent classes must have a descriptor registered for them with the session.
* This method allows for a batch of descriptors to be added at once so that EclipseLink
* can resolve the dependencies between the descriptors and perform initialization optimally.
*/
public void addDescriptors(Project project, DatabaseSessionImpl session) {
addDescriptors(project.getDescriptors().values(), session);
}
/**
* PUBLIC:
* Add a named SQLResultSetMapping to this project. These SQLResultSetMappings
* can be later used by ResultSetMappingQueries to map Custom sql results to
* results as defined by the SQLResultSetMappings.
*/
public void addSQLResultSetMapping(SQLResultSetMapping sqlResultSetMapping){
if (sqlResultSetMapping == null || sqlResultSetMapping.getName() == null){
return;
}
if (this.sqlResultSetMappings == null){
this.sqlResultSetMappings = new HashMap<>();
}
this.sqlResultSetMappings.put(sqlResultSetMapping.getName(), sqlResultSetMapping);
}
/**
* PUBLIC:
* Set all this project's descriptors to conform all read queries within the context of the unit of work.
*/
public void conformAllDescriptors() {
Iterator descriptors = getDescriptors().values().iterator();
while (descriptors.hasNext()) {
ClassDescriptor descriptor = descriptors.next();
descriptor.setShouldAlwaysConformResultsInUnitOfWork(true);
}
}
/**
* INTERNAL:
* Convert all the class-name-based settings in this project to actual class-based settings.
* This will also reset any class references to the version of the class from the class loader.
*/
@Override
public void convertClassNamesToClasses(ClassLoader classLoader){
Iterator ordered = orderedDescriptors.iterator();
while (ordered.hasNext()){
ClassDescriptor descriptor = ordered.next();
descriptor.convertClassNamesToClasses(classLoader);
}
for (AttributeGroup group : this.getAttributeGroups().values()){
group.convertClassNamesToClasses(classLoader);
}
// Clear old descriptors to allow rehash on new classes.
this.descriptors = new HashMap<>();
// convert class names to classes for each SQLResultSetMapping
if (this.sqlResultSetMappings != null) {
for (SQLResultSetMapping mapping : this.sqlResultSetMappings.values()) {
mapping.convertClassNamesToClasses(classLoader);
}
}
if (this.partitioningPolicies != null) {
for (PartitioningPolicy policy : this.partitioningPolicies.values()) {
policy.convertClassNamesToClasses(classLoader);
}
}
}
/**
* PUBLIC:
* Switch all descriptors to assume existence for non-null primary keys.
*/
public void assumeExistenceForDoesExist() {
Iterator descriptors = getDescriptors().values().iterator();
while (descriptors.hasNext()) {
ClassDescriptor descriptor = descriptors.next();
descriptor.getQueryManager().assumeExistenceForDoesExist();
}
}
/**
* PUBLIC:
* Switch all descriptors to check the cache for existence.
*/
public void checkCacheForDoesExist() {
Iterator descriptors = getDescriptors().values().iterator();
while (descriptors.hasNext()) {
ClassDescriptor descriptor = descriptors.next();
descriptor.getQueryManager().checkCacheForDoesExist();
}
}
/**
* PUBLIC:
* Switch all descriptors to check the database for existence.
*/
public void checkDatabaseForDoesExist() {
Iterator descriptors = getDescriptors().values().iterator();
while (descriptors.hasNext()) {
ClassDescriptor descriptor = descriptors.next();
descriptor.getQueryManager().checkDatabaseForDoesExist();
}
}
/**
* INTERNAL:
* Clones the descriptor
*/
@Override
public Project clone() {
try {
return (Project) super.clone();
} catch (CloneNotSupportedException exception) {
throw new InternalError(exception.toString());
}
}
/**
* PUBLIC:
* Factory method to create session.
* This returns an implementor of the DatabaseSession interface, which can be used to login
* and add descriptors from other projects. The Session interface however should be used for
* reading and writing once connected for complete portability.
*/
@Override
public DatabaseSession createDatabaseSession() {
return new DatabaseSessionImpl(this);
}
/**
* PUBLIC:
* Factory method to create a server session.
* This returns an implementor of the Server interface, which can be used to login
* and add descriptors from other projects, configure connection pooling and acquire client sessions.
*
* By default the ServerSession has a single shared read/write connection pool
* with 32 min/max connections and an initial of 1 connection.
*/
public Server createServerSession() {
return new ServerSession(this);
}
/**
* PUBLIC:
* Factory method to create a server session.
* This returns an implementor of the Server interface, which can be used to login
* and add descriptors from other projects, configure connection pooling and acquire client sessions.
* Configure the min and max number of connections for the default shared read/write pool.
*/
public Server createServerSession(int min, int max) {
return new ServerSession(this, min, max);
}
/**
* PUBLIC:
* Factory method to create a server session.
* This returns an implementor of the Server interface, which can be used to login
* and add descriptors from other projects, configure connection pooling and acquire client sessions.
* Configure the min and max number of connections for the default shared read/write pool.
*/
public Server createServerSession(int initial, int min, int max) {
return new ServerSession(this, initial, min, max);
}
/**
* PUBLIC:
* Factory method to create a server session.
* This returns an implementor of the Server interface, which can be used to login
* and add descriptors from other projects, configure connection pooling and acquire client sessions.
* Configure the default connection policy to be used.
* This policy is used on the "acquireClientSession()" protocol.
*
* By default the ServerSession has a single shared read/write connection pool
* with 32 min/max connections and an initial of 1 connection.
*/
public Server createServerSession(ConnectionPolicy defaultConnectionPolicy) {
return new ServerSession(this, defaultConnectionPolicy);
}
/**
* PUBLIC:
* Returns the default set of read-only classes.
*/
public Vector getDefaultReadOnlyClasses() {
return defaultReadOnlyClasses;
}
/**
* PUBLIC:
* Return default value for descriptor cache type.
*/
public Class getDefaultIdentityMapClass() {
return this.defaultIdentityMapClass;
}
/**
* PUBLIC:
* Return default value descriptor cache size.
*/
public int getDefaultIdentityMapSize() {
return this.defaultIdentityMapSize;
}
/**
* PUBLIC:
* Return the project level default for class cache isolation;
*/
public CacheIsolationType getDefaultCacheIsolation(){
return this.defaultCacheIsolation;
}
/**
* PUBLIC:
* Return default value for descriptor primary key validation.
*/
public IdValidation getDefaultIdValidation() {
return this.defaultIdValidation;
}
/**
* PUBLIC:
* Return the descriptor specified for the class.
* If the passed Class parameter is null, null will be returned.
*/
public ClassDescriptor getClassDescriptor(Class theClass) {
return getDescriptor(theClass);
}
/**
* PUBLIC:
* Return the descriptor specified for the class.
*/
@Override
public ClassDescriptor getDescriptor(Class theClass) {
if (theClass == null) {
return null;
}
return getDescriptors().get(theClass);
}
/**
* PUBLIC:
* Return the descriptors in a ClassDescriptors Map keyed on the Java class.
*/
public Map, ClassDescriptor> getDescriptors() {
// Lazy initialize class references from orderedDescriptors when reading from XML.
if (descriptors.isEmpty() && (!orderedDescriptors.isEmpty())) {
for (Iterator iterator = orderedDescriptors.iterator(); iterator.hasNext();) {
ClassDescriptor descriptor = iterator.next();
descriptors.put(descriptor.getJavaClass(), descriptor);
}
}
return descriptors;
}
/**
* INTERNAL:
* Return the descriptors in the order added.
* Used to maintain consistent order in XML.
*/
@Override
public List getOrderedDescriptors() {
return orderedDescriptors;
}
/**
* INTERNAL:
* Set the descriptors order.
* Used to maintain consistent order in XML.
*/
public void setOrderedDescriptors(List orderedDescriptors) {
this.orderedDescriptors = orderedDescriptors;
for (ClassDescriptor descriptor : orderedDescriptors) {
String alias = descriptor.getAlias();
if (alias != null) {
addAlias(alias, descriptor);
}
}
}
/**
* INTERNAL:
* Returns all classes in this project that are needed for weaving.
* This list currently includes entity, embeddables and mappedSuperClasses.
*/
public Collection getClassNamesForWeaving() {
return classNamesForWeaving;
}
/**
* INTERNAL:
* Returns all classes in this project that are needed for weaving.
* This list currently includes entity, embeddables and mappedSuperClasses.
*/
public void setClassNamesForWeaving(Collection classNamesForWeaving) {
this.classNamesForWeaving = classNamesForWeaving;
}
/**
* OBSOLETE:
* Return the login, the login holds any database connection information given.
* This has been replaced by getDatasourceLogin to make use of the Login interface
* to support non-relational datasources,
* if DatabaseLogin API is required it will need to be cast.
*/
public DatabaseLogin getLogin() {
return (DatabaseLogin)datasourceLogin;
}
/**
* PUBLIC:
* Return the login, the login holds any database connection information given.
* This return the Login interface and may need to be cast to the datasource specific implementation.
*/
@Override
public Login getDatasourceLogin() {
return datasourceLogin;
}
/**
* PUBLIC:
* get the name of the project.
*/
public String getName() {
return name;
}
/**
* PUBLIC:
* Get a named SQLResultSetMapping from this project. These SQLResultSetMappings
* can be used by ResultSetMappingQueries to map Custom sql results to
* results as defined by the SQLResultSetMappings.
*/
public SQLResultSetMapping getSQLResultSetMapping(String sqlResultSetMapping){
if (sqlResultSetMapping == null || this.sqlResultSetMappings == null){
return null;
}
return this.sqlResultSetMappings.get(sqlResultSetMapping);
}
/**
* INTERNAL:
* Returns structure converter class names that would be set on the databasePlatform instance
* This is used to avoid the platform instance changing at login.
*/
public Collection getStructConverters() {
return structConverters;
}
/**
* INTERNAL:
* Returns structure converter class names that would be set on the databasePlatform instance
* This is used to avoid the platform instance changing at login.
*/
public void setStructConverters(Collection structConverters) {
this.structConverters = structConverters;
}
/**
* INTERNAL:
* Return the name of the last class to set a VPD identifiers.
*/
public String getVPDLastIdentifierClassName() {
return vpdLastIdentifierClassName;
}
/**
* INTERNAL:
* Return the VPD identifier for this project.
*/
public String getVPDIdentifier() {
return vpdIdentifier;
}
/**
* INTERNAL:
*/
public MultitenantPolicy getMultitenantPolicy() {
return multitenantPolicy;
}
/**
* INTERNAL:
* Answers if at least one Descriptor or Mapping had a HistoryPolicy at initialize time.
*/
public boolean hasGenericHistorySupport() {
return hasGenericHistorySupport;
}
/**
* PUBLIC:
* Set the read-only classes which apply to each UnitOfWork create by default.
*/
public void setDefaultReadOnlyClasses(Collection newValue) {
this.defaultReadOnlyClasses = new Vector(newValue);
}
/**
* PUBLIC:
* Set default value for descriptor cache type.
*/
public void setDefaultIdentityMapClass(Class defaultIdentityMapClass) {
this.defaultIdentityMapClass = defaultIdentityMapClass;
}
/**
* PUBLIC:
* Set default value descriptor cache size.
*/
public void setDefaultIdentityMapSize(int defaultIdentityMapSize) {
this.defaultIdentityMapSize = defaultIdentityMapSize;
}
/**
* PUBLIC:
* Set project level default value for class cache isolation.
*/
public void setDefaultCacheIsolation(CacheIsolationType isolationType) {
this.defaultCacheIsolation = isolationType;
}
/**
* PUBLIC:
* Set default value for descriptor primary key validation.
*/
public void setDefaultIdValidation(IdValidation defaultIdValidation) {
this.defaultIdValidation = defaultIdValidation;
}
/**
* INTERNAL:
* Set the descriptors registered with this session.
*/
public void setDescriptors(Map descriptors) {
this.descriptors = descriptors;
for (Iterator iterator = descriptors.values().iterator(); iterator.hasNext();) {
ClassDescriptor descriptor = iterator.next();
String alias = descriptor.getAlias();
if (alias != null) {
addAlias(alias, descriptor);
}
}
}
/**
* ADVANCED:
* This method is a 'helper' method for updating all of the descriptors
* within this project to have a particular deferral level. The levels are
* as follows
* ClassDescriptor.ALL_MODIFICATIONS - this is the default and recommended.
* The writing of all changes will be deferred until the end of the
* transaction
* ClassDescriptor.UPDATE_MODIFICATIONS - this will cause the update changes to
* be deferred and all other changes to be written immediately.
* ClassDescriptor.NONE - this will cause all changes to be written on each
* container call.
*/
public void setDeferModificationsUntilCommit(int deferralLevel) {
for (Iterator iterator = descriptors.values().iterator(); iterator.hasNext();) {
ClassDescriptor descriptor = iterator.next();
if (descriptor.getCMPPolicy() != null) {
descriptor.getCMPPolicy().setDeferModificationsUntilCommit(deferralLevel);
}
}
}
/**
* INTERNAL:
* Set to true during descriptor initialize if any descriptor has history.
*/
public void setHasGenericHistorySupport(boolean hasGenericHistorySupport) {
this.hasGenericHistorySupport = hasGenericHistorySupport;
}
/**
* INTERNAL:
* Return whether this project has a descriptor that is both Isolated and
* has a cache isolation level other than ISOLATE_CACHE_ALWAYS
*/
public boolean hasIsolatedCacheClassWithoutUOWIsolation(){
// checked cached boolean to avoid iteration
if (!hasIsolatedClasses){
return false;
}
Iterator i = orderedDescriptors.iterator();
while (i.hasNext()){
ClassDescriptor descriptor = i.next();
if (descriptor.getCachePolicy().isIsolated() && !descriptor.getCachePolicy().shouldIsolateObjectsInUnitOfWork()) {
return true;
}
}
return false;
}
/**
* INTERNAL:
* Return if any descriptors are isolated.
* Set to true during descriptor initialize if any descriptor is isolated.
* Determines if an isolated client session is required.
*/
public boolean hasIsolatedClasses() {
return hasIsolatedClasses;
}
/**
* INTERNAL:
* Set to true during descriptor initialize if any descriptor is isolated.
* Determines if an isolated client session is required.
*/
public void setHasIsolatedClasses(boolean hasIsolatedClasses) {
this.hasIsolatedClasses = hasIsolatedClasses;
}
/**
* INTERNAL:
* Return if any descriptors are not isolated to the unit of work.
* Set to true during descriptor initialize if any descriptor is not isolated.
* Allows uow merge to be bypassed.
*/
public boolean hasNonIsolatedUOWClasses() {
return hasNonIsolatedUOWClasses;
}
/**
* INTERNAL:
* Set if any descriptors are not isolated to the unit of work.
* Set to true during descriptor initialize if any descriptor is not isolated.
* Allows uow merge to be bypassed.
*/
public void setHasNonIsolatedUOWClasses(boolean hasNonIsolatedUOWClasses) {
this.hasNonIsolatedUOWClasses = hasNonIsolatedUOWClasses;
}
/**
* INTERNAL:
* Return if any descriptors use ProxyIndirection.
* Set to true during descriptor initialize if any descriptor uses ProxyIndirection
* Determines if ProxyIndirectionPolicy.getValueFromProxy should be called.
*/
public boolean hasProxyIndirection() {
return this.hasProxyIndirection;
}
/**
* PUBLIC:
* Return true if the sql result set mapping name exists.
*/
public boolean hasSQLResultSetMapping(String sqlResultSetMapping) {
return sqlResultSetMappings.containsKey(sqlResultSetMapping);
}
/**
* PUBLIC:
* Return true if there is a VPD identifier for this project. Will not be
* set till after descriptor initialization.
*/
public boolean hasVPDIdentifier(AbstractSession session) {
return (vpdIdentifier != null && session.getProperty(vpdIdentifier) != null);
}
/**
* INTERNAL:
* Set to true during descriptor initialize if any descriptor uses ProxyIndirection
* Determines if ProxyIndirectionPolicy.getValueFromProxy should be called.
*/
public void setHasProxyIndirection(boolean hasProxyIndirection) {
this.hasProxyIndirection = hasProxyIndirection;
}
/**
* PUBLIC:
* Set the login to be used to connect to the database for this project.
*/
public void setLogin(DatabaseLogin datasourceLogin) {
this.datasourceLogin = datasourceLogin;
}
/**
* INTERNAL:
* Set the multitenant policy.
*/
public void setMultitenantPolicy(MultitenantPolicy policy) {
multitenantPolicy = policy;
}
/**
* PUBLIC:
* Set the login to be used to connect to the database for this project.
*/
@Override
public void setLogin(Login datasourceLogin) {
this.datasourceLogin = datasourceLogin;
}
/**
* PUBLIC:
* Set the login to be used to connect to the database for this project.
*/
public void setDatasourceLogin(Login datasourceLogin) {
this.datasourceLogin = datasourceLogin;
}
/**
* PUBLIC:
* Set the name of the project.
*/
public void setName(String name) {
this.name = name;
}
/**
* INTERNAL:
*/
@Override
public String toString() {
return Helper.getShortClassName(getClass()) + "(" + getName() + ")";
}
/**
* PUBLIC:
* Switch all descriptors to use the cache identity map.
*/
public void useCacheIdentityMap() {
Iterator descriptors = getDescriptors().values().iterator();
while (descriptors.hasNext()) {
ClassDescriptor descriptor = descriptors.next();
descriptor.useCacheIdentityMap();
}
}
/**
* PUBLIC:
* Switch all descriptors to use the cache identity map the size.
*/
public void useCacheIdentityMap(int cacheSize) {
Iterator descriptors = getDescriptors().values().iterator();
while (descriptors.hasNext()) {
ClassDescriptor descriptor = descriptors.next();
descriptor.useCacheIdentityMap();
descriptor.setIdentityMapSize(cacheSize);
}
}
/**
* PUBLIC:
* Switch all descriptors to use the full identity map.
*/
public void useFullIdentityMap() {
Iterator descriptors = getDescriptors().values().iterator();
while (descriptors.hasNext()) {
ClassDescriptor descriptor = descriptors.next();
descriptor.useFullIdentityMap();
}
}
/**
* PUBLIC:
* Switch all descriptors to use the full identity map with initial cache size.
*/
public void useFullIdentityMap(int initialCacheSize) {
Iterator descriptors = getDescriptors().values().iterator();
while (descriptors.hasNext()) {
ClassDescriptor descriptor = descriptors.next();
descriptor.useFullIdentityMap();
descriptor.setIdentityMapSize(initialCacheSize);
}
}
/**
* PUBLIC:
* Switch all descriptors to use no identity map.
*/
public void useNoIdentityMap() {
Iterator descriptors = getDescriptors().values().iterator();
while (descriptors.hasNext()) {
ClassDescriptor descriptor = descriptors.next();
descriptor.useNoIdentityMap();
}
}
/**
* PUBLIC:
* Switch all descriptors to use the soft cache weak identity map.
*/
public void useSoftCacheWeakIdentityMap() {
Iterator descriptors = getDescriptors().values().iterator();
while (descriptors.hasNext()) {
ClassDescriptor descriptor = descriptors.next();
descriptor.useSoftCacheWeakIdentityMap();
}
}
/**
* PUBLIC:
* Switch all descriptors to use the soft cache weak identity map with soft cache size.
*/
public void useSoftCacheWeakIdentityMap(int cacheSize) {
Iterator descriptors = getDescriptors().values().iterator();
while (descriptors.hasNext()) {
ClassDescriptor descriptor = descriptors.next();
descriptor.useSoftCacheWeakIdentityMap();
descriptor.setIdentityMapSize(cacheSize);
}
}
/**
* INTERNAL:
* Asks each descriptor if is uses optimistic locking.
*/
public boolean usesOptimisticLocking() {
Iterator descriptors = getDescriptors().values().iterator();
while (descriptors.hasNext()) {
ClassDescriptor descriptor = descriptors.next();
if (descriptor.usesOptimisticLocking()) {
return true;
}
}
return false;
}
/**
* INTERNAL:
* Asks each descriptor if is uses sequencing.
*/
public boolean usesSequencing() {
Iterator descriptors = getDescriptors().values().iterator();
while (descriptors.hasNext()) {
ClassDescriptor descriptor = descriptors.next();
if (descriptor.usesSequenceNumbers()) {
return true;
}
}
return false;
}
/**
* PUBLIC:
* Switch all descriptors to use the weak identity map.
*/
public void useWeakIdentityMap() {
Iterator descriptors = getDescriptors().values().iterator();
while (descriptors.hasNext()) {
ClassDescriptor descriptor = descriptors.next();
descriptor.useWeakIdentityMap();
}
}
/**
* PUBLIC:
* Switch all descriptors to use the weak identity map.
*/
public void useWeakIdentityMap(int initialCacheSize) {
Iterator descriptors = getDescriptors().values().iterator();
while (descriptors.hasNext()) {
ClassDescriptor descriptor = descriptors.next();
descriptor.useWeakIdentityMap();
descriptor.setIdentityMapSize(initialCacheSize);
}
}
/**
* INTERNAL:
* Default apply login implementation.
* Defined for generated subclasses that may not have a login.
* BUG#2669342
*/
public void applyLogin() {
// Do nothing by default.
}
/**
* INTERNAL:
* Returns the alias descriptors hashtable.
*/
public Map getAliasDescriptors() {
return aliasDescriptors;
}
/**
* PUBLIC:
* Add an alias for the descriptor.
*/
public void addAlias(String alias, ClassDescriptor descriptor) {
if (aliasDescriptors == null) {
aliasDescriptors = new HashMap<>(10);
}
aliasDescriptors.put(alias, descriptor);
}
/**
* INTERNAL:
* Return true if native sql is allowed on this project.
*/
public boolean allowTablePerMultitenantDDLGeneration() {
return this.allowTablePerMultitenantDDLGeneration;
}
/**
* INTERNAL:
* Return true if native sql is allowed on this project.
*/
public boolean allowNativeSQLQueries() {
return this.allowNativeSQLQueries;
}
/**
* INTERNAL:
* Return true if SQL calls can defer to EOT on this project.
*/
public boolean allowSQLDeferral() {
return this.allowSQLDeferral;
}
/**
* INTERNAL:
* Return true is allowed to transform named stored procedure parameters into positional/index based.
*/
public boolean namingIntoIndexed() {
return this.namingIntoIndexed;
}
/**
* INTERNAL:
* Return true if extended logging of JPA L2 cache usage is allowed on this project.
*/
public boolean allowExtendedCacheLogging() {
return this.allowExtendedCacheLogging;
}
/**
* INTERNAL:
* Return true if extended thread logging is allowed on this project.
*/
public boolean allowExtendedThreadLogging() {
return this.allowExtendedThreadLogging;
}
/**
* INTERNAL:
* Return true if thread dumps will be added to extended thread logging.
*/
public boolean allowExtendedThreadLoggingThreadDump() {
return this.allowExtendedThreadLoggingThreadDump;
}
/**
* INTERNAL:
* Flag that allows query result cache validation or not. If true result is presented via log messages.
*/
public boolean isAllowQueryResultsCacheValidation() {
return allowQueryResultsCacheValidation;
}
/**
* PUBLIC:
* Return the descriptor for the alias
*/
public ClassDescriptor getDescriptorForAlias(String alias) {
ClassDescriptor descriptor = null;
if (aliasDescriptors != null) {
descriptor = aliasDescriptors.get(alias);
}
return descriptor;
}
/**
* INTERNAL:
* Set the alias descriptors hashtable.
*/
public void setAliasDescriptors(Map aHashtable) {
aliasDescriptors = aHashtable;
}
/**
* INTERNAL:
* Set whether ddl generation should allowed for table per tenant
* multitenant descriptors. This will only be true when a non shared emf
* is used and all the tenant context properties are provided at deploy
* time.
*/
public void setAllowTablePerMultitenantDDLGeneration(boolean allowTablePerMultitenantDDLGeneration) {
this.allowTablePerMultitenantDDLGeneration = allowTablePerMultitenantDDLGeneration;
}
/**
* INTERNAL:
* Set whether native sql is allowed on this project.
*/
public void setAllowNativeSQLQueries(boolean allowNativeSQLQueries) {
this.allowNativeSQLQueries = allowNativeSQLQueries;
}
/**
* INTERNAL:
* Set whether sql deferral is allowed on this project
*/
public void setAllowSQLDeferral(boolean allowSQLDeferral) {
this.allowSQLDeferral = allowSQLDeferral;
}
/**
* INTERNAL:
* Set whether named stored procedure parameters is allowed to transform into positional/index based.
*/
public void setNamingIntoIndexed(boolean namingIntoIndexed) {
this.namingIntoIndexed = namingIntoIndexed;
}
/**
* INTERNAL:
* Set whether extended logging of JPA L2 cache usage is allowed on this project.
*/
public void setAllowExtendedCacheLogging(boolean allowExtendedCacheLogging) {
this.allowExtendedCacheLogging = allowExtendedCacheLogging;
}
/**
* INTERNAL:
* Set whether extended thread logging is allowed on this project.
*/
public void setAllowExtendedThreadLogging(boolean allowExtendedThreadLogging) {
this.allowExtendedThreadLogging = allowExtendedThreadLogging;
}
/**
* INTERNAL:
* Set if thread dumps will be added to extended thread logging.
*/
public void setAllowExtendedThreadLoggingThreadDump(boolean allowExtendedThreadLoggingThreadDump) {
this.allowExtendedThreadLoggingThreadDump = allowExtendedThreadLoggingThreadDump;
}
/**
* INTERNAL:
* Set to true to enable query result cache validation or not. Result is presented via log messages.
*/
public void setAllowQueryResultsCacheValidation(boolean allowQueryResultsCacheValidation) {
this.allowQueryResultsCacheValidation = allowQueryResultsCacheValidation;
}
/**
* INTERNAL:
* Indicates whether there is at least one descriptor that has at least on mapping that
* require a call on deleted objects to update change sets.
*/
public boolean hasMappingsPostCalculateChangesOnDeleted() {
return hasMappingsPostCalculateChangesOnDeleted;
}
/**
* INTERNAL:
* Indicates whether there is at least one descriptor that has at least on mapping that
* require a call on deleted objects to update change sets.
*/
public void setHasMappingsPostCalculateChangesOnDeleted(boolean hasMappingsPostCalculateChangesOnDeleted) {
this.hasMappingsPostCalculateChangesOnDeleted = hasMappingsPostCalculateChangesOnDeleted;
}
/**
* INTERNAL:
* Return whether there any mappings that are mapped superclasses.
* @since EclipseLink 1.2 for the JPA 2.0 Reference Implementation
*/
public boolean hasMappedSuperclasses() {
return (null != this.mappedSuperclassDescriptors && !this.mappedSuperclassDescriptors.isEmpty());
}
/**
* INTERNAL:
* Return whether the given class is mapped as superclass.
* @since EclipseLink 2.3 for the JPA 2.0 Reference Implementation
*/
public boolean hasMappedSuperclass(String className) {
if (!hasMappedSuperclasses()) {
return false;
}
return this.mappedSuperclassDescriptors.containsKey(className);
}
/**
* INTERNAL:
* Return all pre-defined not yet parsed EJBQL queries.
*/
public void addJPAQuery(DatabaseQuery query) {
getJPAQueries().add(query);
}
/**
* INTERNAL:
* Return all pre-defined not yet parsed EJBQL queries to table per tenant entities.
*/
public void addJPATablePerTenantQuery(DatabaseQuery query) {
getJPATablePerTenantQueries().add(query);
}
/**
* INTERNAL:
* 266912: Add a descriptor to the Map of mappedSuperclass descriptors
* @param key (Metadata class)
* @param value (RelationalDescriptor)
* @since EclipseLink 1.2 for the JPA 2.0 Reference Implementation
*/
public void addMappedSuperclass(String key, ClassDescriptor value, boolean replace) {
// Lazy initialization of the mappedSuperclassDescriptors field.
if(null == this.mappedSuperclassDescriptors) {
this.mappedSuperclassDescriptors = new HashMap<>(2);
}
// Avoid replacing the current RelationalDescriptor that may have mappings set
if(replace || !this.mappedSuperclassDescriptors.containsKey(key)) {
this.mappedSuperclassDescriptors.put(key, value);
}
}
/**
* INTERNAL:
* Use the Metadata key parameter to lookup the
* Descriptor from the Map of mappedSuperclass descriptors
* @param key - theMetadata class
* @since EclipseLink 1.2 for the JPA 2.0 Reference Implementation
*/
public ClassDescriptor getMappedSuperclass(String key) {
// TODO: this implementation may have side effects when we have the same class
// in different class loaders - however currently there is only one classLoader per project
// Lazy initialization of the mappedSuperclassDescriptors field.
if(null == this.mappedSuperclassDescriptors) {
this.mappedSuperclassDescriptors = new HashMap<>(2);
return null;
}
return this.mappedSuperclassDescriptors.get(key);
}
/**
* INTERNAL:
* Return the Map of RelationalDescriptor objects representing mapped superclass parents
* keyed by className of the metadata class.
* @since EclipseLink 1.2 for the JPA 2.0 Reference Implementation
*/
public Map getMappedSuperclassDescriptors() {
// Lazy initialization of the mappedSuperclassDescriptors field.
if(null == this.mappedSuperclassDescriptors) {
this.mappedSuperclassDescriptors = new HashMap<>(2);
}
return this.mappedSuperclassDescriptors;
}
/**
* INTERNAL:
* Add an IdClass entry to the map of ids for a particular owner
* This function is used exclusively by the Metamodel API.
* @since EclipseLink 1.2 for the JPA 2.0 Reference Implementation
*/
public void addMetamodelIdClassMapEntry(String ownerName, String name) {
// Add a possible composite key to the owner - this function will handle duplicates by overwriting the entry
if(this.metamodelIdClassMap.containsKey(ownerName)) {
// If we have a key entry then the list will always exist
this.metamodelIdClassMap.get(ownerName).add(name);
} else {
List ownerList = new ArrayList<>();
ownerList.add(name);
this.metamodelIdClassMap.put(ownerName, ownerList);
}
}
/**
* INTERNAL:
* Return the Map of IdClass attribute lists keyed on owner class name.
* @since EclipseLink 1.2 for the JPA 2.0 Reference Implementation
*/
public Map> getMetamodelIdClassMap() {
return metamodelIdClassMap;
}
/**
* PUBLIC:
* Return the map of partitioning policies, keyed by name.
*/
public Map getPartitioningPolicies() {
if (this.partitioningPolicies == null) {
this.partitioningPolicies = new HashMap<>();
}
return partitioningPolicies;
}
/**
* PUBLIC:
* Set the map of partitioning policies, keyed by name.
*/
public void setPartitioningPolicies(Map partitioningPolicies) {
this.partitioningPolicies = partitioningPolicies;
}
/**
* PUBLIC:
* Set the map of partitioning policies, keyed by name.
*/
public void addPartitioningPolicy(PartitioningPolicy partitioningPolicy) {
getPartitioningPolicies().put(partitioningPolicy.getName(), partitioningPolicy);
}
/**
* PUBLIC:
* Return the partitioning policies for the name.
*/
public PartitioningPolicy getPartitioningPolicy(String name) {
if (this.partitioningPolicies == null) {
return null;
}
return this.partitioningPolicies.get(name);
}
}