| /* |
| * Copyright (c) 1998, 2021 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"; |
| |
| // 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<RelationshipAccessor> m_owningRelationshipAccessors; |
| |
| // All non-owning (mappedBy) relationship accessors. |
| private List<RelationshipAccessor> m_nonOwningRelationshipAccessors; |
| |
| // Accessors that map to an Embeddable class |
| private List<MappingAccessor> m_embeddableMappingAccessors; |
| |
| // All direct collection accessors. |
| private List<DirectCollectionAccessor> m_directCollectionAccessors; |
| |
| // Class accessors that have a customizer. |
| private List<ClassAccessor> m_accessorsWithCustomizer; |
| |
| // A linked map of all the entity mappings (XML file representation) |
| private Map<String, XMLEntityMappings> m_entityMappings; |
| |
| // Map of mapped-superclasses found in XML for this project/persistence unit. |
| private Map<String, MappedSuperclassAccessor> m_mappedSuperclasseAccessors; |
| |
| // All the class accessors for this project (Entities and Embeddables). |
| private Map<String, ClassAccessor> m_allAccessors; |
| |
| // The entity accessors for this project |
| private Map<String, EntityAccessor> m_entityAccessors; |
| |
| // Contains those embeddables and entities that are VIRTUAL (do not exist) |
| private Map<String, ClassAccessor> m_virtualClasses; |
| |
| // The embeddable accessors for this project |
| private Map<String, EmbeddableAccessor> 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<String, EmbeddableAccessor> m_rootEmbeddableAccessors; |
| |
| // The interface accessors for this project |
| private Map<String, InterfaceAccessor> m_interfaceAccessors; |
| |
| // Class accessors that have their id derived from a relationship. |
| private Map<String, ClassAccessor> m_accessorsWithDerivedId; |
| |
| // Query metadata. |
| private Map<String, NamedQueryMetadata> m_queries; |
| |
| // SQL result set mapping |
| private Map<String, SQLResultSetMappingMetadata> m_sqlResultSetMappings; |
| |
| // Sequencing metadata. |
| private Map<MetadataClass, GeneratedValueMetadata> m_generatedValues; |
| private Map<String, TableGeneratorMetadata> m_tableGenerators; |
| private Map<String, SequenceGeneratorMetadata> m_sequenceGenerators; |
| private Map<String, UuidGeneratorMetadata> m_uuidGenerators; |
| |
| // Metadata converters, that is, EclipseLink converters. |
| private Map<String, AbstractConverterMetadata> m_converters; |
| |
| // The converter accessors for this project |
| private Map<String, ConverterAccessor> m_converterAccessors; |
| private Map<String, ConverterAccessor> m_autoApplyConvertAccessors; |
| |
| // Store PLSQL record and table types, Oracle object types, |
| // array types and XMLType types by name, to allow reuse. |
| private Map<String, ComplexTypeMetadata> m_complexMetadataTypes; |
| |
| // Store partitioning policies by name, to allow reuse. |
| private Map<String, AbstractPartitioningMetadata> m_partitioningPolicies; |
| |
| // All mappedSuperclass accessors, identity is handled by keying on className. |
| private Map<String, MappedSuperclassAccessor> 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<String> m_idClasses; |
| |
| // Contains a list of all interfaces that are implemented by entities in |
| // this project/pu. |
| private Set<String> m_interfacesImplementedByEntities; |
| |
| // Default listeners that need to be applied to each entity in the |
| // persistence unit (unless they exclude them). |
| private Set<EntityListenerMetadata> 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<RelationshipAccessor>(); |
| m_nonOwningRelationshipAccessors = new ArrayList<RelationshipAccessor>(); |
| m_embeddableMappingAccessors = new ArrayList<MappingAccessor>(); |
| m_directCollectionAccessors = new ArrayList<DirectCollectionAccessor>(); |
| m_accessorsWithCustomizer = new ArrayList<ClassAccessor>(); |
| |
| // Using linked collections since their ordering needs to be preserved. |
| m_entityMappings = new LinkedHashMap<String, XMLEntityMappings>(); |
| m_defaultListeners = new LinkedHashSet<EntityListenerMetadata>(); |
| |
| m_queries = new HashMap<String, NamedQueryMetadata>(); |
| m_sqlResultSetMappings = new HashMap<String, SQLResultSetMappingMetadata>(); |
| m_allAccessors = new HashMap<String, ClassAccessor>(); |
| m_entityAccessors = new HashMap<String, EntityAccessor>(); |
| m_embeddableAccessors = new HashMap<String, EmbeddableAccessor>(); |
| m_rootEmbeddableAccessors = new HashMap<String, EmbeddableAccessor>(); |
| m_interfaceAccessors = new HashMap<String, InterfaceAccessor>(); |
| m_mappedSuperclasseAccessors = new HashMap<String, MappedSuperclassAccessor>(); |
| m_generatedValues = new HashMap<MetadataClass, GeneratedValueMetadata>(); |
| m_tableGenerators = new HashMap<String, TableGeneratorMetadata>(); |
| m_sequenceGenerators = new HashMap<String, SequenceGeneratorMetadata>(); |
| m_uuidGenerators = new HashMap<String, UuidGeneratorMetadata>(); |
| m_converters = new HashMap<String, AbstractConverterMetadata>(); |
| m_converterAccessors = new HashMap<String, ConverterAccessor>(); |
| m_autoApplyConvertAccessors = new HashMap<String, ConverterAccessor>(); |
| m_partitioningPolicies = new HashMap<String, AbstractPartitioningMetadata>(); |
| m_complexMetadataTypes = new HashMap<String, ComplexTypeMetadata>(); |
| m_metamodelMappedSuperclasses = new HashMap<String, MappedSuperclassAccessor>(); |
| m_virtualClasses = new HashMap<String, ClassAccessor>(); |
| m_accessorsWithDerivedId = new HashMap<String, ClassAccessor>(); |
| |
| m_idClasses = new HashSet<String>(); |
| m_interfacesImplementedByEntities = new HashSet<String>(); |
| } |
| |
| /** |
| * 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.<p> |
| * 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. |
| * <p> |
| * 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. |
| * <p> |
| * This method is referenced by EntityAccessor.addPotentialMappedSuperclass() |
| * during an initial predeploy() and later during a deploy() |
| * </p> |
| * @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<String, MetadataDescriptor> 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<String, MetadataDescriptor> dynamicClasses = new HashMap<String, MetadataDescriptor>(); |
| for (ClassAccessor accessor : m_virtualClasses.values()) { |
| createDynamicClass(accessor.getDescriptor(), dynamicClasses, dcl); |
| } |
| |
| // Create the dynamic types. |
| Map<String, DynamicType> dynamicTypes = new HashMap<String, DynamicType>(); |
| 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 (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<String, DynamicType> 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<ClassAccessor> getAccessorsWithCustomizer() { |
| return m_accessorsWithCustomizer; |
| } |
| |
| /** |
| * INTERNAL: |
| */ |
| public Collection<ClassAccessor> 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<String, ConverterAccessor> getConverterAccessors() { |
| return m_converterAccessors; |
| } |
| |
| /** |
| * INTERNAL: |
| */ |
| public Set<EntityListenerMetadata> 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<EmbeddableAccessor> 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<EntityAccessor> getEntityAccessors() { |
| return m_entityAccessors.values(); |
| } |
| |
| /** |
| * INTERNAL: |
| */ |
| public Collection<XMLEntityMappings> 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<MappedSuperclassAccessor> 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<MappedSuperclassAccessor> 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. |
| * @return |
| * @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<EmbeddableAccessor> 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<SharedCacheMode>(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<StructConverterMetadata> getStructConverters(){ |
| List<StructConverterMetadata> structConverters = new ArrayList<StructConverterMetadata>(); |
| |
| 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<String> getWeavableClassNames() { |
| Set<String> weavableClassNames = new HashSet<String>(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<ClassAccessor> processed = new HashSet<>(); |
| HashSet<ClassAccessor> 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<String, Sequence> sequences = new Hashtable<String, Sequence>(); |
| |
| 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)); |
| } |
| |
| // 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; |
| } |
| } |
| |
| |