org.eclipse.persistence.internal.jpa.metadata.MetadataProject Maven / Gradle / Ivy
Show all versions of eclipselink Show documentation
/*
* Copyright (c) 1998, 2022 Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1998, 2018 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/16/2008-1.0M8 Guy Pelletier
// - 218084: Implement metadata merging functionality between mapping files
// 05/23/2008-1.0M8 Guy Pelletier
// - 211330: Add attributes-complete support to the EclipseLink-ORM.XML Schema
// 09/23/2008-1.1 Guy Pelletier
// - 241651: JPA 2.0 Access Type support
// 01/28/2009-2.0 Guy Pelletier
// - 248293: JPA 2.0 Element Collections (part 1)
// 02/06/2009-2.0 Guy Pelletier
// - 248293: JPA 2.0 Element Collections (part 2)
// 03/27/2009-2.0 Guy Pelletier
// - 241413: JPA 2.0 Add EclipseLink support for Map type attributes
// 04/24/2009-2.0 Guy Pelletier
// - 270011: JPA 2.0 MappedById support
// 04/30/2009-2.0 Michael O'Brien
// - 266912: JPA 2.0 Metamodel API (part of Criteria API)
// 06/16/2009-2.0 Guy Pelletier
// - 277039: JPA 2.0 Cache Usage Settings
// 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
// 06/25/2009-2.0 Michael O'Brien
// - 266912: change MappedSuperclass handling in stage2 to pre process accessors
// in support of the custom descriptors holding mappings required by the Metamodel
// 08/11/2009-2.0 Michael O'Brien
// - 284147: do not add a pseudo PK Field for MappedSuperclasses when
// 1 or more PK fields already exist on the descriptor.
// 10/21/2009-2.0 Guy Pelletier
// - 290567: mappedbyid support incomplete
// 11/13/2009-2.0 Guy Pelletier
// - 293629: An attribute referenced from orm.xml is not recognized correctly
// 03/08/2010-2.1 Guy Pelletier
// - 303632: Add attribute-type for mapping attributes to EclipseLink-ORM
// 03/08/2010-2.1 Michael O'Brien
// - 300051: JPA 2.0 Metamodel processing requires EmbeddedId validation moved higher from
// EmbeddedIdAccessor.process() to MetadataDescriptor.addAccessor() so we
// can better determine when to add the MAPPED_SUPERCLASS_RESERVED_PK_NAME
// temporary PK field used to process MappedSuperclasses for the Metamodel API
// during MetadataProject.addMetamodelMappedSuperclass()
// 04/09/2010-2.1 Guy Pelletier
// - 307050: Add defaults for access methods of a VIRTUAL access type
// 05/14/2010-2.1 Guy Pelletier
// - 253083: Add support for dynamic persistence using ORM.xml/eclipselink-orm.xml
// 06/09/2010-2.0.3 Guy Pelletier
// - 313401: shared-cache-mode defaults to NONE when the element value is unrecognized
// 06/14/2010-2.2 Guy Pelletier
// - 264417: Table generation is incorrect for JoinTables in AssociationOverrides
// 07/05/2010-2.1.1 Guy Pelletier
// - 317708: Exception thrown when using LAZY fetch on VIRTUAL mapping
// 07/23/2010-2.2 Guy Pelletier
// - 237902: DDL GEN doesn't qualify SEQUENCE table with persistence unit schema
// 08/11/2010-2.2 Guy Pelletier
// - 312123: JPA: Validation error during Id processing on parameterized generic OneToOne Entity relationship from MappedSuperclass
// 09/03/2010-2.2 Guy Pelletier
// - 317286: DB column lenght not in sync between @Column and @JoinColumn
// 12/01/2010-2.2 Guy Pelletier
// - 331234: xml-mapping-metadata-complete overriden by metadata-complete specification
// 12/02/2010-2.2 Guy Pelletier
// - 251554: ExcludeDefaultMapping annotation needed
// 12/02/2010-2.2 Guy Pelletier
// - 324471: Do not default to VariableOneToOneMapping for interfaces unless a managed class implementing it is found
// 03/24/2011-2.3 Guy Pelletier
// - 337323: Multi-tenant with shared schema support (part 1)
// 04/01/2011-2.3 Guy Pelletier
// - 337323: Multi-tenant with shared schema support (part 2)
// 08/09/2011
// Masumi Ito, Fujitsu - Bug 351791 - NPE occurs on specifying two kinds of primary key generators on orm.xml
// 09/09/2011-2.3.1 Guy Pelletier
// - 356197: Add new VPD type to MultitenantType
// 09/20/2011-2.3.1 Guy Pelletier
// - 357476: Change caching default to ISOLATED for multitenant's using a shared EMF.
// 02/08/2012-2.4 Guy Pelletier
// - 350487: JPA 2.1 Specification defined support for Stored Procedure Calls
// 06/20/2012-2.5 Guy Pelletier
// - 350487: JPA 2.1 Specification defined support for Stored Procedure Calls
// 10/09/2012-2.5 Guy Pelletier
// - 374688: JPA 2.1 Converter support
// 10/30/2012-2.5 Guy Pelletier
// - 374688: JPA 2.1 Converter support
// 11/19/2012-2.5 Guy Pelletier
// - 389090: JPA 2.1 DDL Generation Support (foreign key metadata support)
// 11/22/2012-2.5 Guy Pelletier
// - 389090: JPA 2.1 DDL Generation Support (index metadata support)
// 02/12/2013-2.5 Guy Pelletier
// - 397772: JPA 2.1 Entity Graph Support (XML support)
// 07/16/2013-2.5.1 Guy Pelletier
// - 412384: Applying Converter for parameterized basic-type for joda-time's DateTime does not work
// 09/01/2014-2.6.0 Dmitry Kornilov
// - JPARS 2.0 related changes
// 12/03/2015-2.6 Dalia Abo Sheasha
// - 483582: Add the jakarta.persistence.sharedCache.mode property
// 12/05/2016-2.6 Jody Grassel
// - 443546: Converter autoApply does not work for primitive types
package org.eclipse.persistence.internal.jpa.metadata;
import static org.eclipse.persistence.internal.jpa.metadata.MetadataConstants.JPA_EMBEDDABLE;
import java.lang.reflect.Method;
import java.security.AccessController;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import jakarta.persistence.SharedCacheMode;
import jakarta.persistence.spi.PersistenceUnitInfo;
import org.eclipse.persistence.descriptors.ClassDescriptor;
import org.eclipse.persistence.dynamic.DynamicClassLoader;
import org.eclipse.persistence.dynamic.DynamicType;
import org.eclipse.persistence.exceptions.ValidationException;
import org.eclipse.persistence.internal.helper.DatabaseField;
import org.eclipse.persistence.internal.helper.DatabaseTable;
import org.eclipse.persistence.internal.jpa.deployment.PersistenceUnitProcessor;
import org.eclipse.persistence.internal.jpa.metadata.accessors.classes.ClassAccessor;
import org.eclipse.persistence.internal.jpa.metadata.accessors.classes.ConverterAccessor;
import org.eclipse.persistence.internal.jpa.metadata.accessors.classes.EmbeddableAccessor;
import org.eclipse.persistence.internal.jpa.metadata.accessors.classes.EntityAccessor;
import org.eclipse.persistence.internal.jpa.metadata.accessors.classes.InterfaceAccessor;
import org.eclipse.persistence.internal.jpa.metadata.accessors.classes.MappedSuperclassAccessor;
import org.eclipse.persistence.internal.jpa.metadata.accessors.mappings.DirectCollectionAccessor;
import org.eclipse.persistence.internal.jpa.metadata.accessors.mappings.MappingAccessor;
import org.eclipse.persistence.internal.jpa.metadata.accessors.mappings.RelationshipAccessor;
import org.eclipse.persistence.internal.jpa.metadata.accessors.objects.MetadataAnnotation;
import org.eclipse.persistence.internal.jpa.metadata.accessors.objects.MetadataClass;
import org.eclipse.persistence.internal.jpa.metadata.converters.AbstractConverterMetadata;
import org.eclipse.persistence.internal.jpa.metadata.converters.StructConverterMetadata;
import org.eclipse.persistence.internal.jpa.metadata.listeners.EntityListenerMetadata;
import org.eclipse.persistence.internal.jpa.metadata.partitioning.AbstractPartitioningMetadata;
import org.eclipse.persistence.internal.jpa.metadata.queries.ComplexTypeMetadata;
import org.eclipse.persistence.internal.jpa.metadata.queries.NamedQueryMetadata;
import org.eclipse.persistence.internal.jpa.metadata.queries.SQLResultSetMappingMetadata;
import org.eclipse.persistence.internal.jpa.metadata.sequencing.GeneratedValueMetadata;
import org.eclipse.persistence.internal.jpa.metadata.sequencing.SequenceGeneratorMetadata;
import org.eclipse.persistence.internal.jpa.metadata.sequencing.TableGeneratorMetadata;
import org.eclipse.persistence.internal.jpa.metadata.sequencing.UuidGeneratorMetadata;
import org.eclipse.persistence.internal.jpa.metadata.tables.TableMetadata;
import org.eclipse.persistence.internal.jpa.metadata.xml.XMLEntityMappings;
import org.eclipse.persistence.internal.jpa.metadata.xml.XMLPersistenceUnitDefaults;
import org.eclipse.persistence.internal.jpa.metadata.xml.XMLPersistenceUnitMetadata;
import org.eclipse.persistence.internal.security.PrivilegedAccessHelper;
import org.eclipse.persistence.internal.security.PrivilegedGetDeclaredMethod;
import org.eclipse.persistence.internal.security.PrivilegedMethodInvoker;
import org.eclipse.persistence.internal.sessions.AbstractSession;
import org.eclipse.persistence.jpa.dynamic.JPADynamicTypeBuilder;
import org.eclipse.persistence.queries.AttributeGroup;
import org.eclipse.persistence.sequencing.Sequence;
import org.eclipse.persistence.sessions.DatasourceLogin;
import org.eclipse.persistence.sessions.Project;
/**
* INTERNAL:
* A MetadataProject stores metadata and also helps to facilitate the metadata
* processing.
*
* Key notes:
* - Care should be taken when using Sets to hold metadata and checking their
* equality. In most cases you should be able to us a List or Map since most
* additions to those lists should not occur multiple times for the same
* object. Just be aware of what you are gathering and how. For example, for
* ClassAccessors, they can always be stored in a map keyed on
* accessor.getJavaClassName(). List of mapping accessors is ok as well since
* in most cases we check isProcessed() before calling process on them etc.
* - methods should be preserved in alphabetical order.
*
* @author Guy Pelletier
* @since TopLink EJB 3.0 Reference Implementation
*/
public class MetadataProject {
// Sequencing constants.
public static final String DEFAULT_AUTO_GENERATOR = "SEQ_GEN";
public static final String DEFAULT_TABLE_GENERATOR = "SEQ_GEN_TABLE";
public static final String DEFAULT_SEQUENCE_GENERATOR = "SEQ_GEN_SEQUENCE";
public static final String DEFAULT_IDENTITY_GENERATOR = "SEQ_GEN_IDENTITY";
public static final String DEFAULT_UUID_GENERATOR = "SEQ_GEN_UUID";
// Boolean to specify if we should weave fetch groups.
private boolean m_isWeavingFetchGroupsEnabled;
// Boolean to specify if the user intends for the related EMF of this
// project to be shared for multitenants.
private boolean m_multitenantSharedEmf;
// Boolean to specify if the user intends for the related EMF cache of this
// project to be shared for multitenants.
private boolean m_multitenantSharedCache;
// Boolean to specify if we should weave eager relationships.
private boolean m_isWeavingEagerEnabled;
// Boolean to specify if we should weave lazy relationships.
private boolean m_isWeavingLazyEnabled;
// Boolean to specify if we should uppercase all field names.
// @see PersistenceUnitProperties.UPPERCASE_COLUMN_NAMES
private boolean m_forceFieldNamesToUpperCase;
// Cache the shared cache mode
private SharedCacheMode m_sharedCacheMode;
private boolean m_isSharedCacheModeInitialized;
// A composite PU processor.
private MetadataProcessor m_compositeProcessor;
// Persistence unit info that is represented by this project.
private PersistenceUnitInfo m_persistenceUnitInfo;
// The session we are currently processing for.
private AbstractSession m_session;
// The logger for the project.
private MetadataLogger m_logger;
// Persistence unit metadata for this project.
private XMLPersistenceUnitMetadata m_persistenceUnitMetadata;
// All owning relationship accessors.
private List m_owningRelationshipAccessors;
// All non-owning (mappedBy) relationship accessors.
private List m_nonOwningRelationshipAccessors;
// Accessors that map to an Embeddable class
private List m_embeddableMappingAccessors;
// All direct collection accessors.
private List m_directCollectionAccessors;
// Class accessors that have a customizer.
private List m_accessorsWithCustomizer;
// A linked map of all the entity mappings (XML file representation)
private Map m_entityMappings;
// Map of mapped-superclasses found in XML for this project/persistence unit.
private Map m_mappedSuperclasseAccessors;
// All the class accessors for this project (Entities and Embeddables).
private Map m_allAccessors;
// The entity accessors for this project
private Map m_entityAccessors;
// Contains those embeddables and entities that are VIRTUAL (do not exist)
private Map m_virtualClasses;
// The embeddable accessors for this project
private Map m_embeddableAccessors;
// Root level embeddable accessors. When we pre-process embeddable
// accessors we need to process them from the root down so as to set
// the correct owning descriptor.
private Map m_rootEmbeddableAccessors;
// The interface accessors for this project
private Map m_interfaceAccessors;
// Class accessors that have their id derived from a relationship.
private Map m_accessorsWithDerivedId;
// Query metadata.
private Map m_queries;
// SQL result set mapping
private Map m_sqlResultSetMappings;
// Sequencing metadata.
private Map m_generatedValues;
private Map m_tableGenerators;
private Map m_sequenceGenerators;
private Map m_uuidGenerators;
// Metadata converters, that is, EclipseLink converters.
private Map m_converters;
// The converter accessors for this project
private Map m_converterAccessors;
private Map m_autoApplyConvertAccessors;
// Store PLSQL record and table types, Oracle object types,
// array types and XMLType types by name, to allow reuse.
private Map m_complexMetadataTypes;
// Store partitioning policies by name, to allow reuse.
private Map m_partitioningPolicies;
// All mappedSuperclass accessors, identity is handled by keying on className.
private Map m_metamodelMappedSuperclasses;
// All id classes (IdClass and EmbeddedId classes) used through-out the
// persistence unit. We need this list to determine derived id accessors.
private Set m_idClasses;
// Contains a list of all interfaces that are implemented by entities in
// this project/pu.
private Set m_interfacesImplementedByEntities;
// Default listeners that need to be applied to each entity in the
// persistence unit (unless they exclude them).
private Set m_defaultListeners;
/**
* INTERNAL:
* Create and return a new MetadataProject with puInfo as its PersistenceUnitInfo,
* session as its Session and weavingEnabled as its global dynamic weaving state.
* @param puInfo - the PersistenceUnitInfo
* @param session - the Session
*/
public MetadataProject(PersistenceUnitInfo puInfo, AbstractSession session, boolean weaveLazy, boolean weaveEager, boolean weaveFetchGroups, boolean multitenantSharedEmf, boolean multitenantSharedCache) {
m_isSharedCacheModeInitialized = false;
m_persistenceUnitInfo = puInfo;
m_session = session;
m_logger = new MetadataLogger(session);
m_isWeavingEagerEnabled = weaveEager;
m_isWeavingLazyEnabled = weaveLazy;
m_isWeavingFetchGroupsEnabled = weaveFetchGroups;
m_multitenantSharedEmf = multitenantSharedEmf;
m_multitenantSharedCache = multitenantSharedCache;
m_owningRelationshipAccessors = new ArrayList();
m_nonOwningRelationshipAccessors = new ArrayList();
m_embeddableMappingAccessors = new ArrayList();
m_directCollectionAccessors = new ArrayList();
m_accessorsWithCustomizer = new ArrayList();
// Using linked collections since their ordering needs to be preserved.
m_entityMappings = new LinkedHashMap();
m_defaultListeners = new LinkedHashSet();
m_queries = new HashMap();
m_sqlResultSetMappings = new HashMap();
m_allAccessors = new HashMap();
m_entityAccessors = new HashMap();
m_embeddableAccessors = new HashMap();
m_rootEmbeddableAccessors = new HashMap();
m_interfaceAccessors = new HashMap();
m_mappedSuperclasseAccessors = new HashMap();
m_generatedValues = new HashMap();
m_tableGenerators = new HashMap();
m_sequenceGenerators = new HashMap();
m_uuidGenerators = new HashMap();
m_converters = new HashMap();
m_converterAccessors = new HashMap();
m_autoApplyConvertAccessors = new HashMap();
m_partitioningPolicies = new HashMap();
m_complexMetadataTypes = new HashMap();
m_metamodelMappedSuperclasses = new HashMap();
m_virtualClasses = new HashMap();
m_accessorsWithDerivedId = new HashMap();
m_idClasses = new HashSet();
m_interfacesImplementedByEntities = new HashSet();
}
/**
* INTERNAL:
* This method will add the descriptor to the actual EclipseLink project,
* if it has not already been added. This method if called for entities
* and embeddable classes (which are both weavable classes).
*/
protected void addAccessor(ClassAccessor accessor) {
MetadataDescriptor descriptor = accessor.getDescriptor();
// Process the persistence unit meta data (if there is any).
processPersistenceUnitMetadata(descriptor);
// Process and set the parent class (if one is available).
accessor.processParentClass();
// Add the descriptor to the actual EclipseLink Project.
m_session.getProject().addDescriptor(descriptor.getClassDescriptor());
// Keep a map of all the accessors that have been added.
m_allAccessors.put(accessor.getJavaClassName(), accessor);
}
/**
* INTERNAL:
*/
public void addAccessorWithCustomizer(ClassAccessor accessor) {
m_accessorsWithCustomizer.add(accessor);
}
/**
* INTERNAL:
*/
public void addAccessorWithDerivedId(ClassAccessor accessor) {
m_accessorsWithDerivedId.put(accessor.getJavaClassName(), accessor);
}
/**
* INTERNAL:
*/
public void addAlias(String alias, MetadataDescriptor descriptor) {
ClassDescriptor existingDescriptor = m_session.getProject().getDescriptorForAlias(alias);
if (existingDescriptor == null) {
descriptor.setAlias(alias);
m_session.getProject().addAlias(alias, descriptor.getClassDescriptor());
} else {
throw ValidationException.nonUniqueEntityName(existingDescriptor.getJavaClassName(), descriptor.getJavaClassName(), alias);
}
}
/**
* INTERNAL:
* Add a abstract converter metadata to the project. The actual processing
* isn't done until an accessor referencing the converter is processed.
*/
public void addConverter(AbstractConverterMetadata converter) {
// Check for another converter with the same name.
if (converter.shouldOverride(m_converters.get(converter.getName()))) {
m_converters.put(converter.getName(), converter);
}
}
/**
* INTERNAL:
* Add a abstract converter metadata to the project. The actual processing
* isn't done until an accessor referencing the converter is processed.
*/
public void addConverterAccessor(ConverterAccessor converterAccessor) {
// Check for another converter with the same name.
if (converterAccessor.shouldOverride(m_converterAccessors.get(converterAccessor.getIdentifier()))) {
m_converterAccessors.put(converterAccessor.getIdentifier(), converterAccessor);
}
}
/**
* INTERNAL:
*/
public void addDefaultListener(EntityListenerMetadata defaultListener) {
m_defaultListeners.add(defaultListener);
}
/**
* INTERNAL:
* Store basic collection accessors for later processing and quick look up.
*/
public void addDirectCollectionAccessor(MappingAccessor accessor) {
m_directCollectionAccessors.add((DirectCollectionAccessor) accessor);
}
/**
* INTERNAL:
* Add an embeddable accessor to this project. Assumes the embeddable
* needs to be added. That is, does not check if it already exists and
* cause a merge. The caller is responsible for that.
*/
public void addEmbeddableAccessor(EmbeddableAccessor accessor) {
// Add accessor will apply persistence unit defaults.
addAccessor(accessor);
accessor.getDescriptor().setIsEmbeddable();
m_embeddableAccessors.put(accessor.getJavaClassName(), accessor);
}
/**
* INTERNAL:
*/
public void addEmbeddableMappingAccessor(MappingAccessor accessor) {
m_embeddableMappingAccessors.add(accessor);
}
/**
* INTERNAL:
* Add an entity accessor to this project. Assumes the entity needs to be
* added. That is, does not check if it already exists and cause a merge.
* The caller is responsible for that.
*/
public void addEntityAccessor(EntityAccessor accessor) {
// Add accessor will apply persistence unit defaults.
addAccessor(accessor);
// Grab the implemented interfaces (used when defaulting v1-1 mappings)
m_interfacesImplementedByEntities.addAll(accessor.getJavaClass().getInterfaces());
m_entityAccessors.put(accessor.getJavaClassName(), accessor);
}
/**
* INTERNAL:
* Add the given entity graph (internal attribute group).
*/
public void addEntityGraph(AttributeGroup entityGraph) {
getProject().getAttributeGroups().put(entityGraph.getName(), entityGraph);
}
/**
* INTERNAL:
* The avoid processing the same mapping file twice (e.g. user may
* explicitly specify the orm.xml file) we store the list of entity
* mappings in a map keyed on their URL.
*/
public void addEntityMappings(XMLEntityMappings entityMappings) {
// Add the new entity mappings file to the list.
m_entityMappings.put(entityMappings.getMappingFileOrURL(), entityMappings);
}
/**
* INTERNAL:
*/
public void addGeneratedValue(GeneratedValueMetadata generatedvalue, MetadataClass entityClass) {
m_generatedValues.put(entityClass, generatedvalue);
}
/**
* INTERNAL:
* Add EmbeddedId and IdClass ids to the project
*/
public void addIdClass(String idClassName) {
m_idClasses.add(idClassName);
}
/**
* INTERNAL:
* Add a InterfaceAccessor to this project.
*/
public void addInterfaceAccessor(InterfaceAccessor accessor) {
m_interfaceAccessors.put(accessor.getJavaClassName(), accessor);
// Add it directly and avoid the persistence unit defaults and stuff for now.
m_session.getProject().addDescriptor(accessor.getDescriptor().getClassDescriptor());
}
/**
* INTERNAL:
* Add a mapped superclass accessor to this project. Assumes the mapped
* superclass needs to be added. That is, does not check if it already
* exists and cause a merge. The caller is responsible for that. At runtime,
* this map will contain mapped superclasses from XML only. The canonical
* model processor will populate all mapped superclasses in this map.
*/
public void addMappedSuperclass(MappedSuperclassAccessor mappedSuperclass) {
// Process and set the parent class (if one is available).
mappedSuperclass.processParentClass();
m_mappedSuperclasseAccessors.put(mappedSuperclass.getJavaClassName(), mappedSuperclass);
// add the mapped superclass to keep track of it in case it is not processed later (has no subclasses).
m_session.getProject().addMappedSuperclass(mappedSuperclass.getJavaClassName(), mappedSuperclass.getDescriptor().getClassDescriptor(), false);
}
/**
* INTERNAL:
* The metamodel API requires that descriptors exist for mappedSuperclasses
* in order to obtain their mappings.
* In order to accomplish this, this method that is called from EntityAccessor
* will ensure that the descriptors on all mappedSuperclass accessors
* are setup so that they can be specially processed later in
* MetadataProject.processStage2() - where the m_mappedSuperclassAccessors
* Map is required.
*
* We do not use the non-persisting MAPPED_SUPERCLASS_RESERVED_PK_NAME PK field.
* Normally when the MappedSuperclass is part of an inheritance hierarchy of the form MS->MS->E,
* where there is an PK Id on the root Entity E, we need to add the
* MAPPED_SUPERCLASS_RESERVED_PK_NAME PK field solely for metadata processing to complete.
* Why? because even though we treat MappedSuperclass objects as a RelationalDescriptor - we only persist
* RelationalDescriptor objects that relate to concrete Entities.
*
* This method is referenced by EntityAccessor.addPotentialMappedSuperclass()
* during an initial predeploy() and later during a deploy()
*
* @param accessor - The mappedSuperclass accessor for the field on the mappedSuperclass
* @since EclipseLink 1.2 for the JPA 2.0 Reference Implementation
*/
public void addMetamodelMappedSuperclass(MappedSuperclassAccessor accessor, MetadataDescriptor childDescriptor) {
// Check for an existing entry before proceeding. Metamodel mapped
// superclasses need only (and should only) be added once. This code
// will be called from every entity that inherits from it. There is no
// need to check for className == null here as the mapped superclass
// accessor is always created with a class.
if (! m_metamodelMappedSuperclasses.containsKey(accessor.getJavaClassName())) {
MetadataDescriptor metadataDescriptor = accessor.getDescriptor();
// Set a child entity descriptor on the mapped superclass descriptor.
// This descriptor (and its mapping accessors) will help to resolve
// any generic mapping accessors from the mapped superclass.
metadataDescriptor.setMetamodelMappedSuperclassChildDescriptor(childDescriptor);
// Note: set the back pointer from the MetadataDescriptor back to its' accessor manually before we add accessors
metadataDescriptor.setClassAccessor(accessor);
// Make sure you apply the persistence unit metadata and defaults.
processPersistenceUnitMetadata(metadataDescriptor);
// Need to apply the mapping file defaults (if there is one that loaded this mapped superclass).
if (accessor.getEntityMappings() != null) {
accessor.getEntityMappings().processEntityMappingsDefaults(accessor);
}
// After the pu metadata and defaults have been applied, it is safe to process the access type.
accessor.processAccessType();
// Set the referenceClass for Id mappings
// Generics Handler: Check if the referenceType is not set for Collection accessors
accessor.addAccessors();
// Add the accessor to our custom Map keyed on className for separate processing in stage2
m_metamodelMappedSuperclasses.put(accessor.getJavaClassName(), accessor);
// Fake out a database table and primary key for MappedSuperclasses
// We require string names for table processing that does not actually goto the database.
// There will be no conflict with customer values
// The descriptor is assumed never to be null
metadataDescriptor.setPrimaryTable(new DatabaseTable(MetadataConstants.MAPPED_SUPERCLASS_RESERVED_TABLE_NAME));
/*
* We need to add a PK field to the temporary mappedsuperclass table above - in order to continue processing.
* Note: we add this field only if no IdClass or EmbeddedId attributes are set on or above the MappedSuperclass.
* Both the table name and PK name are not used to actual database writes.
* Check accessor collection on the metadataDescriptor (note: getIdAttributeName() and getIdAttributeNames() are not populated yet - so are unavailable
* 300051: The check for at least one IdAccessor or an EmbeddedIdAccessor requires that the map and field respectively
* are set previously in MetadataDescriptor.addAccessor().
* The checks below will also avoid a performance hit on searching the accessor map directly on the descriptor.
*/
if (!metadataDescriptor.hasIdAccessor() && !metadataDescriptor.hasEmbeddedId()) {
DatabaseField pkField = new DatabaseField(MetadataConstants.MAPPED_SUPERCLASS_RESERVED_PK_NAME);
if (this.useDelimitedIdentifier()) {
pkField.setUseDelimiters(true);
} else if (this.getShouldForceFieldNamesToUpperCase()) {
pkField.useUpperCaseForComparisons(true);
}
metadataDescriptor.addPrimaryKeyField(pkField);
}
/*
* We store our descriptor on the core project for later retrieval by MetamodelImpl.
* Why not on MetadataProject? because the Metadata processing is transient.
* We could set the javaClass on the descriptor for the current classLoader
* but we do not need it until metamodel processing time avoiding a _persistence_new call.
* See MetamodelImpl.initialize()
*/
m_session.getProject().addMappedSuperclass(accessor.getJavaClassName(), metadataDescriptor.getClassDescriptor(), true);
}
}
/**
* INTERNAL:
* Add the partitioning policy by name.
*/
public void addPartitioningPolicy(AbstractPartitioningMetadata policy) {
// Check for another policy with the same name.
if (policy.shouldOverride(m_partitioningPolicies.get(policy.getName()))) {
m_partitioningPolicies.put(policy.getName(), policy);
}
}
/**
* INTERNAL:
* Add the named PLSQL or Oracle complex metadata type.
*/
public void addComplexMetadataType(ComplexTypeMetadata type) {
// Check for another type with the same name.
if (type.shouldOverride(m_complexMetadataTypes.get(type.getName()))) {
m_complexMetadataTypes.put(type.getName(), type);
}
}
/**
* INTERNAL:
* Add a query to the project overriding where necessary.
*/
public void addQuery(NamedQueryMetadata query) {
if (query.shouldOverride(m_queries.get(query.getName()))) {
m_queries.put(query.getName(), query);
}
}
/**
* INTERNAL:
*/
public void addRelationshipAccessor(RelationshipAccessor accessor) {
if (accessor.hasMappedBy()) {
m_nonOwningRelationshipAccessors.add(accessor);
} else {
m_owningRelationshipAccessors.add(accessor);
}
}
/**
* INTERNAL:
* Add a root level embeddable accessor.
*/
public void addRootEmbeddableAccessor(EmbeddableAccessor accessor) {
m_rootEmbeddableAccessors.put(accessor.getJavaClassName(), accessor);
}
/**
* INTERNAL:
* Add a sequence generator metadata to the project. The actual processing
* isn't done till processSequencing is called.
*/
public void addSequenceGenerator(SequenceGeneratorMetadata sequenceGenerator, String defaultCatalog, String defaultSchema) {
String name = sequenceGenerator.getName();
// Check if the sequence generator name uses a reserved name.
if (name.equals(DEFAULT_TABLE_GENERATOR)) {
throw ValidationException.sequenceGeneratorUsingAReservedName(DEFAULT_TABLE_GENERATOR, sequenceGenerator.getLocation());
} else if (name.equals(DEFAULT_IDENTITY_GENERATOR)) {
throw ValidationException.sequenceGeneratorUsingAReservedName(DEFAULT_IDENTITY_GENERATOR, sequenceGenerator.getLocation());
}
// Catalog could be "" or null, need to check for an XML default.
sequenceGenerator.setCatalog(MetadataHelper.getName(sequenceGenerator.getCatalog(), defaultCatalog, sequenceGenerator.getCatalogContext(), m_logger, sequenceGenerator.getLocation()));
// Schema could be "" or null, need to check for an XML default.
sequenceGenerator.setSchema(MetadataHelper.getName(sequenceGenerator.getSchema(), defaultSchema, sequenceGenerator.getSchemaContext(), m_logger, sequenceGenerator.getLocation()));
// Check if the name is used with a table generator.
TableGeneratorMetadata tableGenerator = m_tableGenerators.get(name);
if (tableGenerator != null) {
if (sequenceGenerator.shouldOverride(tableGenerator)) {
m_tableGenerators.remove(name);
} else {
throw ValidationException.conflictingSequenceAndTableGeneratorsSpecified(name, sequenceGenerator.getLocation(), tableGenerator.getLocation());
}
}
for (TableGeneratorMetadata otherTableGenerator : m_tableGenerators.values()) {
if ((tableGenerator != otherTableGenerator) && (otherTableGenerator.getPkColumnValue() != null) && otherTableGenerator.getPkColumnValue().equals(sequenceGenerator.getSequenceName())) { // generator name will be used instead of an empty sequence name / pk column name
// generator name will be used instead of an empty sequence name / pk column name
if (otherTableGenerator.getPkColumnValue().length() > 0) {
throw ValidationException.conflictingSequenceNameAndTablePkColumnValueSpecified(sequenceGenerator.getSequenceName(), sequenceGenerator.getLocation(), otherTableGenerator.getLocation());
}
}
}
// Add the sequence generator if there isn't an existing one or if
// we should override an existing one.
if (sequenceGenerator.shouldOverride(m_sequenceGenerators.get(name))) {
m_sequenceGenerators.put(sequenceGenerator.getName(), sequenceGenerator);
}
}
/**
* INTERNAL:
* Add a UUID generator metadata to the project. The actual processing
* isn't done till processSequencing is called.
*/
public void addUuidGenerator(UuidGeneratorMetadata uuidGenerator) {
String name = uuidGenerator.getName();
// Check if the name is used with a table generator.
TableGeneratorMetadata tableGenerator = m_tableGenerators.get(name);
if (tableGenerator != null) {
if (uuidGenerator.shouldOverride(tableGenerator)) {
m_tableGenerators.remove(name);
} else {
throw ValidationException.conflictingSequenceAndTableGeneratorsSpecified(name, uuidGenerator.getLocation(), tableGenerator.getLocation());
}
}
m_uuidGenerators.put(uuidGenerator.getName(), uuidGenerator);
}
/**
* INTERNAL:
* Add an sql results set mapping to the project overriding where necessary.
*/
public void addSQLResultSetMapping(SQLResultSetMappingMetadata sqlResultSetMapping) {
if (sqlResultSetMapping.shouldOverride(m_sqlResultSetMappings.get(sqlResultSetMapping.getName()))) {
m_sqlResultSetMappings.put(sqlResultSetMapping.getName(), sqlResultSetMapping);
}
}
/**
* INTERNAL:
* Add a discovered metamodel class to the session.
*/
public void addStaticMetamodelClass(MetadataAnnotation annotation, MetadataClass metamodelClass) {
MetadataClass modelClass = metamodelClass.getMetadataClass(annotation.getAttributeString("value"));
m_session.addStaticMetamodelClass(modelClass.getName(), metamodelClass.getName());
}
/**
* INTERNAL:
* Add a table generator metadata to the project. The actual processing
* isn't done till processSequencing is called.
*/
public void addTableGenerator(TableGeneratorMetadata tableGenerator, String defaultCatalog, String defaultSchema) {
// Process the default values.
processTable(tableGenerator, "", defaultCatalog, defaultSchema, tableGenerator);
String generatorName = tableGenerator.getGeneratorName();
// Check if the table generator name uses a reserved name.
if (generatorName.equals(DEFAULT_SEQUENCE_GENERATOR)) {
throw ValidationException.tableGeneratorUsingAReservedName(DEFAULT_SEQUENCE_GENERATOR, tableGenerator.getLocation());
} else if (generatorName.equals(DEFAULT_IDENTITY_GENERATOR)) {
throw ValidationException.tableGeneratorUsingAReservedName(DEFAULT_IDENTITY_GENERATOR, tableGenerator.getLocation());
}
// Check if the generator name is used with a sequence generator.
SequenceGeneratorMetadata otherSequenceGenerator = m_sequenceGenerators.get(generatorName);
if (otherSequenceGenerator != null) {
if (tableGenerator.shouldOverride(otherSequenceGenerator)) {
m_sequenceGenerators.remove(generatorName);
} else {
throw ValidationException.conflictingSequenceAndTableGeneratorsSpecified(generatorName, otherSequenceGenerator.getLocation(), tableGenerator.getLocation());
}
}
for (SequenceGeneratorMetadata sequenceGenerator : m_sequenceGenerators.values()) {
if ((otherSequenceGenerator != sequenceGenerator) && (sequenceGenerator.getSequenceName() != null) && sequenceGenerator.getSequenceName().equals(tableGenerator.getPkColumnValue())) {
// generator name will be used instead of an empty sequence name / pk column name
if (sequenceGenerator.getSequenceName().length() > 0) {
throw ValidationException.conflictingSequenceNameAndTablePkColumnValueSpecified(sequenceGenerator.getSequenceName(), sequenceGenerator.getLocation(), tableGenerator.getLocation());
}
}
}
// Add the table generator if there isn't an existing one or if we
// should override an existing one.
if (tableGenerator.shouldOverride(m_tableGenerators.get(generatorName))) {
m_tableGenerators.put(generatorName, tableGenerator);
}
}
/**
* INTERNAL:
* Add virtual class accessor to the project. A virtual class is one that
* has VIRTUAL access and the class does not exist on the classpath.
*/
public void addVirtualClass(ClassAccessor accessor) {
m_virtualClasses.put(accessor.getJavaClassName(), accessor);
}
/**
* INTERNAL:
* Create the dynamic class using JPA metadata processed descriptors. Called
* at deploy time after all metadata processing has completed.
*/
protected void createDynamicClass(MetadataDescriptor descriptor, Map virtualEntities, DynamicClassLoader dcl) {
// Build the virtual class only if we have not already done so.
if (! virtualEntities.containsKey(descriptor.getJavaClassName())) {
if (descriptor.isInheritanceSubclass()) {
// Get the parent descriptor.
MetadataDescriptor parentDescriptor = descriptor.getInheritanceParentDescriptor();
// Recursively call up the parents.
createDynamicClass(parentDescriptor, virtualEntities, dcl);
// Create and set the virtual class using the parent class.
descriptor.getClassDescriptor().setJavaClass(dcl.createDynamicClass(descriptor.getJavaClassName(), parentDescriptor.getClassDescriptor().getJavaClass()));
} else {
// Create and set the virtual class on the descriptor
descriptor.getClassDescriptor().setJavaClass(dcl.createDynamicClass(descriptor.getJavaClassName(), new MetadataDynamicClassWriter(descriptor)));
}
// Store the descriptor by java class name.
virtualEntities.put(descriptor.getJavaClassName(), descriptor);
}
}
/**
* INTERNAL:
* Create the dynamic class using JPA metadata processed descriptors. Called
* at deploy time after all metadata processing has completed.
*/
public void createDynamicClasses(ClassLoader loader) {
if (! m_virtualClasses.isEmpty()) {
if (DynamicClassLoader.class.isAssignableFrom(loader.getClass())) {
DynamicClassLoader dcl = (DynamicClassLoader) loader;
// Create the dynamic classes.
Map dynamicClasses = new HashMap();
for (ClassAccessor accessor : m_virtualClasses.values()) {
createDynamicClass(accessor.getDescriptor(), dynamicClasses, dcl);
}
// Create the dynamic types.
Map dynamicTypes = new HashMap();
for (MetadataDescriptor descriptor : dynamicClasses.values()) {
createDynamicType(descriptor, dynamicTypes, dcl);
}
} else {
// If we have virtual classes that need creation and we do not
// have a dynamic class loader throw an exception.
throw ValidationException.invalidClassLoaderForDynamicPersistence();
}
}
createRestInterfaces(loader);
}
private void createRestInterfaces(ClassLoader loader) {
if (loader != null && DynamicClassLoader.class.isAssignableFrom(loader.getClass())) {
DynamicClassLoader dcl = (DynamicClassLoader) loader;
for (EntityAccessor accessor : getEntityAccessors()) {
String className = accessor.getParentClassName();
if (className == null || getEntityAccessor(className) == null) {
dcl.createDynamicAdapter(accessor.getJavaClassName());
}
}
for (ClassAccessor classAccessor : getAllAccessors()) {
String className = classAccessor.getParentClassName();
if (className == null || getEntityAccessor(className) == null) {
dcl.createDynamicCollectionAdapter(classAccessor.getJavaClassName());
dcl.createDynamicReferenceAdapter(classAccessor.getJavaClassName());
}
}
}
}
/**
* INTERNAL:
* Create the dynamic types using JPA metadata processed descriptors. Called
* at deploy time after all metadata processing has completed.
*/
protected void createDynamicType(MetadataDescriptor descriptor, Map dynamicTypes, DynamicClassLoader dcl) {
// Build the dynamic class only if we have not already done so.
if (! dynamicTypes.containsKey(descriptor.getJavaClassName())) {
JPADynamicTypeBuilder typeBuilder = null;
if (descriptor.isInheritanceSubclass()) {
// Get the parent descriptor
MetadataDescriptor parentDescriptor = descriptor.getInheritanceParentDescriptor();
// Recursively call up the parents.
createDynamicType(parentDescriptor, dynamicTypes, dcl);
// Create the dynamic type using the parent type.
typeBuilder = new JPADynamicTypeBuilder(dcl, descriptor.getClassDescriptor(), dynamicTypes.get(parentDescriptor.getJavaClassName()));
} else {
// Create the dynamic type
typeBuilder = new JPADynamicTypeBuilder(dcl, descriptor.getClassDescriptor(), null);
}
// Store the type builder by java class name.
dynamicTypes.put(descriptor.getJavaClassName(), typeBuilder.getType());
}
}
/**
* INTERNAL:
* Set if the project should use indirection for lazy relationships.
*/
public void disableWeaving() {
m_isWeavingLazyEnabled = false;
m_isWeavingEagerEnabled = false;
m_isWeavingFetchGroupsEnabled = false;
}
/**
* INTERNAL:
* Return true if an exclude-default-mappings setting have been set for this
* persistence unit.
*/
public boolean excludeDefaultMappings() {
if (m_persistenceUnitMetadata != null) {
return m_persistenceUnitMetadata.excludeDefaultMappings();
}
return false;
}
/**
* INTERNAL:
* Return the accessor for the given class. Could be an entity or an
* embeddable. Note: It may return null.
*/
public ClassAccessor getAccessor(String className) {
return m_allAccessors.get(className);
}
/**
* INTERNAL:
*/
public List getAccessorsWithCustomizer() {
return m_accessorsWithCustomizer;
}
/**
* INTERNAL:
*/
public Collection getAllAccessors() {
return m_allAccessors.values();
}
/**
* Return the converter for the auto apply class type.
*/
public ConverterAccessor getAutoApplyConverter(MetadataClass cls) {
ConverterAccessor ca = m_autoApplyConvertAccessors.get(cls.getName());
if (ca == null) {
String wrapperType = resolvePrimitiveWrapper(cls);
if (wrapperType != null) {
ca = m_autoApplyConvertAccessors.get(wrapperType);
}
}
return ca;
}
private String resolvePrimitiveWrapper(MetadataClass cls) {
String wrapperType = null;
if (cls.isPrimitive() && !cls.isArray() && !m_autoApplyConvertAccessors.isEmpty()) {
// Look for Converters for the Wrapper equivalent of the primitive
switch (cls.getTypeName()) {
case "I": // int
wrapperType = "java.lang.Integer";
break;
case "J": // long
wrapperType = "java.lang.Long";
break;
case "S": // short
wrapperType = "java.lang.Short";
break;
case "Z": // boolean
wrapperType = "java.lang.Boolean";
break;
case "F": // float
wrapperType = "java.lang.Float";
break;
case "D": // double
wrapperType = "java.lang.Double";
break;
case "C": // char
wrapperType = "java.lang.Character";
break;
case "B": // byte
wrapperType = "java.lang.Byte";
break;
default: // unknown
}
}
return wrapperType;
}
/**
* INTERNAL:
*/
public MetadataProcessor getCompositeProcessor() {
return m_compositeProcessor;
}
/**
* INTERNAL:
*/
public AbstractConverterMetadata getConverter(String name) {
return m_converters.get(name);
}
/**
* INTERNAL:
*/
public ConverterAccessor getConverterAccessor(MetadataClass cls) {
return m_converterAccessors.get(cls.getName());
}
/**
* INTERNAL:
*/
public Map getConverterAccessors() {
return m_converterAccessors;
}
/**
* INTERNAL:
*/
public Set getDefaultListeners() {
return m_defaultListeners;
}
/**
* INTERNAL:
* This method will attempt to look up the embeddable accessor for the
* reference class provided. If no accessor is found, null is returned.
*/
public EmbeddableAccessor getEmbeddableAccessor(MetadataClass cls) {
return getEmbeddableAccessor(cls, false);
}
/**
* INTERNAL:
* This method will attempt to look up the embeddable accessor for the
* reference class provided. If no accessor is found, null is returned.
*/
public EmbeddableAccessor getEmbeddableAccessor(MetadataClass cls, boolean checkIsIdClass) {
EmbeddableAccessor accessor = m_embeddableAccessors.get(cls.getName());
if (accessor == null) {
// Before we return null we must make a couple final checks:
//
// 1 - Check for an Embeddable annotation on the class itself. At
// this point we know the class was not tagged as an embeddable in
// a mapping file and was not included in the list of classes for
// this persistence unit. Its inclusion therefore in the persistence
// unit is through the use of an Embedded annotation or an embedded
// element within a known entity.
// 2 - If checkIsIdClass is true, JPA 2.0 introduced support for
//
// derived id's where a parent entity's id class may be used within
// a dependants embedded id class. We will treat the id class as
// and embeddable accessor at this point.
//
// Callers to this method will have to handle the null case if they
// so desire.
if (cls.isAnnotationPresent(JPA_EMBEDDABLE) || (checkIsIdClass && isIdClass(cls))) {
accessor = new EmbeddableAccessor(cls.getAnnotation(JPA_EMBEDDABLE), cls, this);
addEmbeddableAccessor(accessor);
}
}
return accessor;
}
/**
* INTERNAL:
* Return the embeddable accessor with the given classname.
*/
public EmbeddableAccessor getEmbeddableAccessor(String className) {
return m_embeddableAccessors.get(className);
}
/**
* INTERNAL:
* Return the embeddable accessor with the given classname.
*/
public Collection getEmbeddableAccessors() {
return m_embeddableAccessors.values();
}
/**
* INTERNAL:
* Return the entity accessor for the given class name.
*/
public EntityAccessor getEntityAccessor(MetadataClass cls) {
return getEntityAccessor(cls.getName());
}
/**
* INTERNAL:
* Return the entity accessor for the given class name.
*/
public EntityAccessor getEntityAccessor(String className) {
return m_entityAccessors.get(className);
}
/**
* INTERNAL:
*/
public Collection getEntityAccessors() {
return m_entityAccessors.values();
}
/**
* INTERNAL:
*/
public Collection getEntityMappings() {
return m_entityMappings.values();
}
/**
* INTERNAL:
* Return the entity accessor for the given class.
*/
public InterfaceAccessor getInterfaceAccessor(String className) {
return m_interfaceAccessors.get(className);
}
/**
* INTERNAL:
* Return the logger used by the processor.
*/
public MetadataLogger getLogger() {
return m_logger;
}
/**
* INTERNAL:
*/
public MappedSuperclassAccessor getMappedSuperclassAccessor(MetadataClass cls) {
return getMappedSuperclassAccessor(cls.getName());
}
/**
* INTERNAL:
*/
public MappedSuperclassAccessor getMappedSuperclassAccessor(String className) {
return m_mappedSuperclasseAccessors.get(className);
}
/**
* INTERNAL:
*/
public Collection getMappedSuperclasses() {
return m_mappedSuperclasseAccessors.values();
}
/**
* INTERNAL:
* Returns the collection of metamodel MappedSuperclassAccessors. This
* collection is NOT and should NOT be used for any deployment descriptor
* metadata processing. It is used solely with the metamodel.
* @see #getMappedSuperclassAccessor(MetadataClass)
* @see #getMappedSuperclassAccessor(String)
* @see #getMappedSuperclasses()
* @since EclipseLink 1.2 for the JPA 2.0 Reference Implementation
*/
public Collection getMetamodelMappedSuperclasses() {
return m_metamodelMappedSuperclasses.values();
}
/**
* INTERNAL:
* Return the named partitioning policy.
*/
public AbstractPartitioningMetadata getPartitioningPolicy(String name) {
return m_partitioningPolicies.get(name);
}
/**
* INTERNAL:
* Return the persistence unit default catalog.
*/
protected String getPersistenceUnitDefaultCatalog() {
if (m_persistenceUnitMetadata != null) {
return m_persistenceUnitMetadata.getCatalog();
}
return null;
}
/**
* INTERNAL:
* Return the persistence unit default schema.
*/
protected String getPersistenceUnitDefaultSchema() {
if (m_persistenceUnitMetadata != null) {
return m_persistenceUnitMetadata.getSchema();
}
return null;
}
/**
* INTERNAL:
*/
public PersistenceUnitInfo getPersistenceUnitInfo() {
return m_persistenceUnitInfo;
}
/**
* INTERNAL:
*/
public XMLPersistenceUnitMetadata getPersistenceUnitMetadata() {
return m_persistenceUnitMetadata;
}
/**
* INTERNAL:
* Return the named PLSQL or Oracle complex metadata type.
*/
public ComplexTypeMetadata getComplexTypeMetadata(String name) {
return m_complexMetadataTypes.get(name);
}
/**
* INTERNAL:
* Return the core API Project associated with this MetadataProject.
* @since EclipseLink 1.2 for the JPA 2.0 Reference Implementation
*/
public Project getProject() {
return m_session.getProject();
}
/**
* INTERNAL:
* Add a root level embeddable accessor. Nested embeddables will be
* pre-processed from their roots down.
* @see processStage1()
*/
public Collection getRootEmbeddableAccessors() {
return m_rootEmbeddableAccessors.values();
}
/**
* INTERNAL:
*/
public AbstractSession getSession() {
return m_session;
}
/**
* INTERNAL:
* This method will return the name of the SharedCacheMode if specified in
* the persistence.xml file. Note, this is a JPA 2.0 feature, therefore,
* this method needs to catch any exception as a result of trying to access
* this information from a JPA 1.0 container.
*/
protected String getSharedCacheModeName() {
if (! m_isSharedCacheModeInitialized && m_sharedCacheMode == null) {
try {
Method method = null;
if (PrivilegedAccessHelper.shouldUsePrivilegedAccess()) {
method = AccessController.doPrivileged(new PrivilegedGetDeclaredMethod(PersistenceUnitInfo.class, "getSharedCacheMode", null));
m_sharedCacheMode = AccessController.doPrivileged(new PrivilegedMethodInvoker(method, m_persistenceUnitInfo));
} else {
method = PrivilegedAccessHelper.getDeclaredMethod(PersistenceUnitInfo.class, "getSharedCacheMode", null);
m_sharedCacheMode = PrivilegedAccessHelper.invokeMethod(method, m_persistenceUnitInfo, null);
}
} catch (Throwable exception) {
// Swallow any exceptions, shared cache mode will be null.
m_sharedCacheMode = null;
}
// Set the shared cache mode as initialized to avoid the reflective
// calls over and over again.
m_isSharedCacheModeInitialized = true;
}
return (m_sharedCacheMode == null) ? null : m_sharedCacheMode.name();
}
/**
* INTERNAL:
* Sets the SharedCacheMode value.
*/
public void setSharedCacheMode(SharedCacheMode m_sharedCacheMode) {
this.m_sharedCacheMode = m_sharedCacheMode;
}
/**
* INTERNAL:
* Used to uppercase default and user defined column field names
*/
public boolean getShouldForceFieldNamesToUpperCase(){
return m_forceFieldNamesToUpperCase;
}
/**
* INTERNAL:
*/
public List getStructConverters(){
List structConverters = new ArrayList();
for (AbstractConverterMetadata converter : m_converters.values()) {
if (converter.isStructConverter()) {
structConverters.add((StructConverterMetadata) converter);
}
}
return structConverters;
}
/**
* INTERNAL:
* Returns all those classes in this project that are available for
* weaving. This list currently includes entity, embeddables
* and mappedsuperclass with no children classes.
*/
public Collection getWeavableClassNames() {
Set weavableClassNames = new HashSet(m_allAccessors.keySet());
weavableClassNames.addAll(m_mappedSuperclasseAccessors.keySet());
return Collections.unmodifiableCollection(weavableClassNames);
}
/**
* Return true if there is an auto-apply converter for the given cls.
*/
public boolean hasAutoApplyConverter(MetadataClass cls) {
boolean hasCA = m_autoApplyConvertAccessors.containsKey(cls.getName());
if (hasCA == false) {
String wrapperType = resolvePrimitiveWrapper(cls);
if (wrapperType != null) {
hasCA = m_autoApplyConvertAccessors.containsKey(wrapperType);
}
}
return hasCA;
}
/**
* INTERNAL:
*/
public boolean hasConverter(String name) {
return m_converters.containsKey(name);
}
/**
* INTERNAL:
*/
public boolean hasConverterAccessor(MetadataClass cls) {
return m_converterAccessors.containsKey(cls.getName());
}
/**
* INTERNAL:
*/
public boolean hasEmbeddable(MetadataClass cls) {
return hasEmbeddable(cls.getName());
}
/**
* INTERNAL:
*/
public boolean hasEmbeddable(String className) {
return m_embeddableAccessors.containsKey(className);
}
/**
* INTERNAL:
*/
public boolean hasEntity(MetadataClass cls) {
return hasEntity(cls.getName());
}
/**
* INTERNAL:
*/
public boolean hasEntity(String className) {
return m_entityAccessors.containsKey(className);
}
/**
* INTERNAL:
* Return true is there exist and entity graph already for the given name.
*/
public boolean hasEntityGraph(String name) {
return getProject().getAttributeGroups().containsKey(name);
}
/**
* INTERNAL:
*/
public boolean hasEntityThatImplementsInterface(String interfaceName) {
return m_interfacesImplementedByEntities.contains(interfaceName);
}
/**
* INTERNAL:
*/
public boolean hasInterface(MetadataClass cls) {
return m_interfaceAccessors.containsKey(cls.getName());
}
/**
* INTERNAL:
*/
public boolean hasMappedSuperclass(MetadataClass cls) {
return hasMappedSuperclass(cls.getName());
}
/**
* INTERNAL:
*/
public boolean hasMappedSuperclass(String className) {
return m_mappedSuperclasseAccessors.containsKey(className);
}
/**
* INTERNAL:
*/
public boolean hasSharedCacheMode() {
return getSharedCacheModeName() != null;
}
/**
* INTERNAL:
*/
public boolean isIdClass(MetadataClass idClass) {
return m_idClasses.contains(idClass.getName());
}
/**
* INTERNAL:
* Return true if the caching has been specified as ALL in the
* persistence.xml.
*/
public boolean isSharedCacheModeAll() {
return hasSharedCacheMode() && getSharedCacheModeName().equals(SharedCacheMode.ALL.name());
}
/**
* INTERNAL:
* Return true if the caching has been specified as DISABLE_SELECTIVE in the
* persistence.xml. DISABLE_SELECTIVE is the default therefore this will
* also return true if no caching setting was set.
*/
public boolean isSharedCacheModeDisableSelective() {
return (! hasSharedCacheMode()) || getSharedCacheModeName().equals(SharedCacheMode.DISABLE_SELECTIVE.name());
}
/**
* INTERNAL:
* Return true if the caching has been specified as ENABLE_SELECTIVE in the
* persistence.xml.
*/
public boolean isSharedCacheModeEnableSelective() {
return hasSharedCacheMode() && getSharedCacheModeName().equals(SharedCacheMode.ENABLE_SELECTIVE.name());
}
/**
* INTERNAL:
* Return true if the caching has been specified as NONE in the
* persistence.xml.
*/
public boolean isSharedCacheModeNone() {
return hasSharedCacheMode() && getSharedCacheModeName().equals(SharedCacheMode.NONE.name());
}
/**
* INTERNAL:
* Return true if the caching has been specified as UNSPECIFIED in the
* persistence.xml.
*/
public boolean isSharedCacheModeUnspecified() {
return hasSharedCacheMode() && getSharedCacheModeName().equals(SharedCacheMode.UNSPECIFIED.name());
}
/**
* INTERNAL:
* Return if the project should use indirection for eager relationships.
*/
public boolean isWeavingEagerEnabled() {
return m_isWeavingEagerEnabled;
}
/**
* INTERNAL:
* Return if the project should process fetch groups.
*/
public boolean isWeavingFetchGroupsEnabled() {
return m_isWeavingFetchGroupsEnabled;
}
/**
* INTERNAL:
* Return if the project should use indirection for lazy relationships.
*/
public boolean isWeavingLazyEnabled() {
return m_isWeavingLazyEnabled;
}
/**
* INTERNAL:
* Return true if an xml-mapping-metadata-complete setting has been set
* for this persistence unit.
*/
public boolean isXMLMappingMetadataComplete() {
if (m_persistenceUnitMetadata != null) {
return m_persistenceUnitMetadata.isXMLMappingMetadataComplete();
}
return false;
}
/**
* INTERNAL:
* Process the embeddable mapping accessors.
*/
protected void processEmbeddableMappingAccessors() {
for (MappingAccessor mappingAccessor : m_embeddableMappingAccessors) {
if (! mappingAccessor.isProcessed()) {
mappingAccessor.process();
}
}
}
/**
* INTERNAL:
* Process descriptors with IDs derived from relationships. This will also
* complete unfinished validation as well as secondary table processing
* on entity accessors. This method will fast track some relationship
* mappings which is ok since simple primary keys will already have been
* discovered and processed whereas any derived id's and their fast tracking
* to be processed will be handled now.
*/
protected void processAccessorsWithDerivedIDs() {
HashSet processed = new HashSet<>();
HashSet processing = new HashSet<>();
for (ClassAccessor classAccessor : m_accessorsWithDerivedId.values()) {
classAccessor.processDerivedId(processing, processed);
}
}
/**
* INTERNAL:
* Process any BasicCollection annotation and/or BasicMap annotation that
* were found. They are not processed till after an id has been processed
* since they rely on one to map the collection table.
*/
public void processDirectCollectionAccessors() {
for (DirectCollectionAccessor accessor : m_directCollectionAccessors) {
accessor.process();
}
}
/**
* INTERNAL:
* This method will iterate through all the entities in the PU and check
* if we should add them to a variable one to one mapping that was either
* defined (incompletely) or defaulted.
*/
protected void processInterfaceAccessors() {
for (EntityAccessor accessor : getEntityAccessors()) {
for (String interfaceClass : accessor.getJavaClass().getInterfaces()) {
if (m_interfaceAccessors.containsKey(interfaceClass)) {
m_interfaceAccessors.get(interfaceClass).addEntityAccessor(accessor);
}
}
}
}
/**
* INTERNAL:
* Process the non-owning relationship accessors. All owning relationshuip
* accessors should be processed. Some non-owning relationships may have
* already been fast tracked to from an element collection containing
* an embeddable (with a non-owning relationship).
*/
protected void processNonOwningRelationshipAccessors() {
for (RelationshipAccessor accessor : m_nonOwningRelationshipAccessors) {
if (! accessor.isProcessed()) {
accessor.process();
}
}
}
/**
* INTERNAL:
* Process the owning relationship accessors. Some may have already been
* processed through the processing of derived id's therefore don't process
* them again.
*/
protected void processOwningRelationshipAccessors() {
for (RelationshipAccessor accessor : m_owningRelationshipAccessors) {
if (! accessor.isProcessed()) {
accessor.process();
}
}
}
/**
* INTERNAL:
* Process any and all persistence unit metadata and defaults to the given
* descriptor. This method for will called for every descriptor belonging
* to this project/persistence unit.
*
*/
protected void processPersistenceUnitMetadata(MetadataDescriptor descriptor) {
// Set the persistence unit meta data (if there is any) on the descriptor.
if (m_persistenceUnitMetadata != null) {
// Persistence unit metadata level annotations are not defaults
// and therefore should not be set on the descriptor.
// Set the persistence unit defaults (if there are any) on the descriptor.
XMLPersistenceUnitDefaults persistenceUnitDefaults = m_persistenceUnitMetadata.getPersistenceUnitDefaults();
if (persistenceUnitDefaults != null) {
descriptor.setDefaultAccess(persistenceUnitDefaults.getAccess());
descriptor.setDefaultSchema(persistenceUnitDefaults.getSchema());
descriptor.setDefaultCatalog(persistenceUnitDefaults.getCatalog());
descriptor.setDefaultTenantDiscriminatorColumns(persistenceUnitDefaults.getTenantDiscriminatorColumns());
descriptor.setIsCascadePersist(persistenceUnitDefaults.isCascadePersist());
// Set any default access methods if specified.
if (persistenceUnitDefaults.hasAccessMethods()) {
descriptor.setDefaultAccessMethods(persistenceUnitDefaults.getAccessMethods());
}
}
}
}
/**
* INTERNAL:
* Process the named native queries we found and add them to the given
* session.
*/
public void processQueries() {
// Step 1 - process the sql result set mappings first.
for (SQLResultSetMappingMetadata sqlResultSetMapping : m_sqlResultSetMappings.values()) {
m_session.getProject().addSQLResultSetMapping(sqlResultSetMapping.process());
}
// Step 2 - process the named queries second, some may need to validate
// a sql result set mapping specification.
for (NamedQueryMetadata query : m_queries.values()) {
query.process(m_session);
}
}
/**
* INTERNAL:
* Process the sequencing information. At this point, through validation, it
* is not possible to have:
* 1 - a table generator with the generator name equal to
* DEFAULT_SEQUENCE_GENERATOR or DEFAULT_IDENTITY_GENERATOR
* 2 - a sequence generator with the name eqaul to DEFAULT_TABLE_GENERATOR
* or DEFAULT_IDENTITY_GENERATOR
* 3 - you can't have both a sequence generator and a table generator with
* the same DEFAULT_AUTO_GENERATOR name.
*
* @see addTableGenerator and addSequenceGenerator.
*/
protected void processSequencingAccessors() {
if (! m_generatedValues.isEmpty()) {
// 1 - Build our map of sequences keyed on generator names.
Hashtable sequences = new Hashtable();
for (SequenceGeneratorMetadata sequenceGenerator : m_sequenceGenerators.values()) {
sequences.put(sequenceGenerator.getName(), sequenceGenerator.process(m_logger));
}
for (UuidGeneratorMetadata uuidGenerator : m_uuidGenerators.values()) {
sequences.put(uuidGenerator.getName(), uuidGenerator.process(m_logger));
}
for (TableGeneratorMetadata tableGenerator : m_tableGenerators.values()) {
sequences.put(tableGenerator.getGeneratorName(), tableGenerator.process(m_logger));
}
// 2 - Check if the user defined default generators, otherwise
// create them using the Table and Sequence generator metadata.
if (! sequences.containsKey(DEFAULT_TABLE_GENERATOR)) {
TableGeneratorMetadata tableGenerator = new TableGeneratorMetadata(DEFAULT_TABLE_GENERATOR);
// This code was attempting to use the platform default sequence name,
// however the platform has not been set yet, so it would never work,
// it was also causing the platform default sequence to be set, causing the DatabasePlatform default to be used,
// so I am removing this code, as it breaks the platform default sequence and does not work.
// Sequence seq = m_session.getDatasourcePlatform().getDefaultSequence();
// Using "" as the default should make the platform default it.
String defaultTableGeneratorName = "";
// Process the default values.
processTable(tableGenerator, defaultTableGeneratorName, getPersistenceUnitDefaultCatalog(), getPersistenceUnitDefaultSchema(), tableGenerator);
sequences.put(DEFAULT_TABLE_GENERATOR, tableGenerator.process(m_logger));
}
if (! sequences.containsKey(DEFAULT_SEQUENCE_GENERATOR)) {
sequences.put(DEFAULT_SEQUENCE_GENERATOR, new SequenceGeneratorMetadata(DEFAULT_SEQUENCE_GENERATOR, getPersistenceUnitDefaultCatalog(), getPersistenceUnitDefaultSchema()).process(m_logger));
}
if (! sequences.containsKey(DEFAULT_IDENTITY_GENERATOR)) {
sequences.put(DEFAULT_IDENTITY_GENERATOR, new SequenceGeneratorMetadata(DEFAULT_IDENTITY_GENERATOR, 1, getPersistenceUnitDefaultCatalog(), getPersistenceUnitDefaultSchema(), true).process(m_logger));
}
if (! sequences.containsKey(DEFAULT_UUID_GENERATOR)) {
sequences.put(DEFAULT_UUID_GENERATOR, new UuidGeneratorMetadata().process(m_logger));
}
// Use a temporary sequence generator to build a qualifier to set on
// the default generator. Don't use this generator as the default
// auto generator though.
SequenceGeneratorMetadata tempGenerator = new SequenceGeneratorMetadata(DEFAULT_AUTO_GENERATOR, getPersistenceUnitDefaultCatalog(), getPersistenceUnitDefaultSchema());
DatasourceLogin login = m_session.getProject().getLogin();
login.setTableQualifier(tempGenerator.processQualifier());
// 3 - Loop through generated values and set sequences for each.
for (MetadataClass entityClass : m_generatedValues.keySet()) {
// Skip setting sequences if our accessor is null, must be a mapped superclass
ClassAccessor accessor = m_allAccessors.get(entityClass.getName());
if (accessor != null) {
m_generatedValues.get(entityClass).process(accessor.getDescriptor(), sequences, login);
}
}
}
}
/**
* Process the partitioning metedata and add the PartitioningPolicys to the project.
*/
protected void processPartitioning() {
for (AbstractPartitioningMetadata metadata : m_partitioningPolicies.values()) {
m_session.getProject().addPartitioningPolicy(metadata.buildPolicy());
}
}
/**
* INTERNAL:
* Stage 1 processing is a pre-processing stage that will perform the
* following tasks:
* - gather a list of mapping accessors for all entities and embeddables.
* - discover all global converter specifications.
* - discover mapped superclasses and inheritance parents.
*
* NOTE: This method should only perform any preparatory work like, class
* discovery, flag settings etc. Hard processing will begin in stage 2.
*
* @see processStage2
*/
public void processStage1() {
// 1 - Pre-process the entities first. This will also pre-process
// the mapped superclasses and build/add/complete our list of
// embeddables that will be pre-processed in step 2 below. This is
// necessary so that we may gather our list of id classes which may be
// referenced in embeddable classes as part of a mapped by id accessor.
// This will avoid more complicated processing and ease in building the
// correct accessor at buildAccessor time.
for (EntityAccessor entity : getEntityAccessors()) {
if (! entity.isPreProcessed()) {
entity.preProcess();
}
}
// 2 - Pre-process the embeddables. This will also pre-process any and
// all nested embeddables as well. Embeddables must be processed from
// the root down.
for (EmbeddableAccessor embeddable : getRootEmbeddableAccessors()) {
if (! embeddable.isPreProcessed()) {
embeddable.preProcess();
}
}
// 3 - Build our global converter and auto-apply lists first
for (ConverterAccessor converterAccessor : getConverterAccessors().values()) {
if (converterAccessor.autoApply()) {
m_autoApplyConvertAccessors.put(converterAccessor.getAttributeClassification().getName(), converterAccessor);
}
}
// 4 - Pre-process the embeddables.
for (EmbeddableAccessor embeddable : getEmbeddableAccessors()) {
// If the accessor hasn't been processed yet, then process it. An
// EmbeddableAccessor is normally fast tracked if it is a reference.
if (! embeddable.isPreProcessed()) {
embeddable.preProcess();
}
}
}
/**
* INTERNAL:
* Stage 2 processing will perform the following tasks:
* - process all direct mapping accessors from entities, embeddables and
* mapped superclasses.
* - gather a list of relationship accessors and any other special interest
* accessors to be processed in stage 3.
*
* @see processStage3
*/
public void processStage2() {
// process metamodel mappedSuperclasses separately from entity descriptors
for (MappedSuperclassAccessor msAccessor : getMetamodelMappedSuperclasses()) {
if (! msAccessor.isProcessed()) {
msAccessor.processMetamodelDescriptor();
}
}
for (EntityAccessor entity : getEntityAccessors()) {
// If the accessor hasn't been processed yet, then process it. An
// EntityAccessor may get fast tracked if it is an inheritance
// parent.
if (! entity.isProcessed()) {
entity.process();
}
}
for (EmbeddableAccessor embeddable : getEmbeddableAccessors()) {
// If the accessor hasn't been processed yet, then process it. An
// EmbeddableAccessor is normally fast tracked if it is a reference.
if (! embeddable.isProcessed()) {
embeddable.process();
}
}
}
/**
* INTERNAL:
* Stage 3 processing does all the extra processing that couldn't be
* completed in the first two stages of processing. The biggest thing
* being that all entities will have processed an id by now and we can
* process those accessors that rely on them. NOTE: The order of invocation
* here is very important here, see the comments.
*/
public void processStage3(PersistenceUnitProcessor.Mode mode) {
if (mode == PersistenceUnitProcessor.Mode.ALL || mode == PersistenceUnitProcessor.Mode.COMPOSITE_MEMBER_MIDDLE) {
// 1 - Process accessors with IDs derived from relationships. This will
// finish up any stage2 processing that relied on the PK processing
// being complete as well. Note: some relationships mappings may be
// processed in this stage. This is ok since it is to determine and
// validate the primary key.
processAccessorsWithDerivedIDs();
// 2 - Process all the direct collection accessors we found. This list
// does not include direct collections to an embeddable class.
processDirectCollectionAccessors();
// 3 - Process the sequencing metadata now that every entity has a
// validated primary key.
processSequencingAccessors();
// 4 - Process the owning relationship accessors now that every entity
// has a validated primary key and we can process join columns.
processOwningRelationshipAccessors();
// 5 - Process the embeddable mapping accessors. These are the
// embedded, embedded id and element collection accessors that map
// to an embeddable class. We must hold off on their processing till
// now to ensure their owning relationship accessors have been processed
// and we can therefore process any association overrides correctly.
processEmbeddableMappingAccessors();
// composite persistence unit case
if (getCompositeProcessor() != null) {
for (EmbeddableAccessor accessor : getEmbeddableAccessors()) {
if (! accessor.isProcessed()) {
accessor.process();
}
}
}
}
if (mode == PersistenceUnitProcessor.Mode.ALL || mode == PersistenceUnitProcessor.Mode.COMPOSITE_MEMBER_FINAL) {
// 6 - Process the non owning relationship accessors now that every
// owning relationship should be fully processed.
processNonOwningRelationshipAccessors();
// 7 - Process the interface accessors which will iterate through all
// the entities in the PU and check if we should add them to a variable
// one to one mapping that was either defined (incompletely) or
// defaulted.
processInterfaceAccessors();
processPartitioning();
}
}
/**
* INTERNAL:
* Common table processing for table, secondary table, join table,
* collection table and table generators
*/
public void processTable(TableMetadata table, String defaultName, String defaultCatalog, String defaultSchema, ORMetadata owner) {
// Name could be "" or null, need to check against the default name.
String name = MetadataHelper.getName(table.getName(), defaultName, table.getNameContext(), m_logger, owner.getAccessibleObject());
// Catalog could be "" or null, need to check for an XML default.
String catalog = MetadataHelper.getName(table.getCatalog(), defaultCatalog, table.getCatalogContext(), m_logger, owner.getAccessibleObject());
// Schema could be "" or null, need to check for an XML default.
String schema = MetadataHelper.getName(table.getSchema(), defaultSchema, table.getSchemaContext(), m_logger, owner.getAccessibleObject());
// Build a fully qualified name and set it on the table.
// schema, attach it if specified
String tableName = name;
if (! schema.equals("")) {
tableName = schema + "." + tableName;
}
// catalog, attach it if specified
if (! catalog.equals("")) {
tableName = catalog + "." + tableName;
}
table.setFullyQualifiedTableName(tableName);
if (useDelimitedIdentifier()) {
table.setUseDelimiters(useDelimitedIdentifier());
}
// Process the unique constraints.
table.processUniqueConstraints();
// Process the index metadata.
table.processIndexes();
// Process the foreign key metadata.
table.processForeignKey();
// Process the creation suffix.
table.processCreationSuffix();
}
/**
* INTERNAL:
* Used from the canonical model generator. Specifically when the user
* removes the embeddable designation or changes the embeddable to either
* a mapped superclass or entity.
*/
public void removeEmbeddableAccessor(MetadataClass metadataClass) {
m_allAccessors.remove(metadataClass.getName());
m_embeddableAccessors.remove(metadataClass.getName());
}
/**
* INTERNAL:
* Used from the canonical model generator. Specifically when the user
* removes the entity designation or changes the entity to either
* a mapped superclass or embeddable.
*/
public void removeEntityAccessor(MetadataClass metadataClass) {
m_allAccessors.remove(metadataClass.getName());
m_entityAccessors.remove(metadataClass.getName());
}
/**
* INTERNAL:
* Used from the canonical model generator. Specifically when the user
* removes the mapped superclass designation or changes the mapped
* superclass to either an entity or embeddable.
*/
public void removeMappedSuperclassAccessor(MetadataClass metadataClass) {
m_mappedSuperclasseAccessors.remove(metadataClass.getName());
}
/**
* INTERNAL:
* When at least one entity is found that is multitenant, we turn off
* native SQL queries.
*/
public void setAllowNativeSQLQueries(boolean allowNativeSQLQueries) {
getProject().setAllowNativeSQLQueries(allowNativeSQLQueries);
}
/**
* INTERNAL:
* set compositeProcessor that owns this and pear MetadataProcessors used to create composite persistence unit.
*/
public void setCompositeProcessor(MetadataProcessor compositeProcessor) {
m_compositeProcessor = compositeProcessor;
}
/**
* INTERNAL:
*/
public void setPersistenceUnitMetadata(XMLPersistenceUnitMetadata persistenceUnitMetadata) {
// Set the persistence unit metadata if null otherwise try to merge.
if (m_persistenceUnitMetadata == null) {
m_persistenceUnitMetadata = persistenceUnitMetadata;
} else {
m_persistenceUnitMetadata.merge(persistenceUnitMetadata);
}
}
/**
* INTERNAL:
* Used to uppercase default and user defined column field names
*/
public void setShouldForceFieldNamesToUpperCase(boolean shouldForceFieldNamesToUpperCase){
m_forceFieldNamesToUpperCase = shouldForceFieldNamesToUpperCase;
}
/**
* INTERNAL:
*/
@Override
public String toString() {
return "Project[" + getPersistenceUnitInfo().getPersistenceUnitName() + "]";
}
/**
* INTERNAL:
*/
public boolean useDelimitedIdentifier() {
return m_persistenceUnitMetadata != null && m_persistenceUnitMetadata.isDelimitedIdentifiers();
}
/**
* INTERNAL:
* Return true if the entity manager factory cache for this project is
* intended to be shared amongst multitenants.
*/
public boolean usesMultitenantSharedCache() {
return m_multitenantSharedCache;
}
/**
* INTERNAL:
* Return true if the entity manager factory for this project is intended
* to be shared amongst multitenants.
*/
public boolean usesMultitenantSharedEmf() {
return m_multitenantSharedEmf;
}
/**
* INTERNAL:
* Return true if the entity manager factory for this project has any virtual classes
*
*/
public boolean hasVirtualClasses() {
if ((m_virtualClasses != null) && (!m_virtualClasses.isEmpty())) {
return true;
}
return false;
}
}