/src/com/google/appengine/datanucleus/mapping/DatastoreTable.java
Java | 1430 lines | 1026 code | 156 blank | 248 comment | 351 complexity | 0653b973053f01eba9e16fc25da0dd34 MD5 | raw file
Possible License(s): Apache-2.0
- /**********************************************************************
- Copyright (c) 2009 Google Inc.
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
- http://www.apache.org/licenses/LICENSE-2.0
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- **********************************************************************/
- package com.google.appengine.datanucleus.mapping;
- import org.datanucleus.ClassLoaderResolver;
- import org.datanucleus.exceptions.NucleusException;
- import org.datanucleus.exceptions.NucleusUserException;
- import org.datanucleus.exceptions.NucleusFatalUserException;
- import org.datanucleus.identity.OID;
- import org.datanucleus.metadata.AbstractClassMetaData;
- import org.datanucleus.metadata.AbstractMemberMetaData;
- import org.datanucleus.metadata.ClassMetaData;
- import org.datanucleus.metadata.ColumnMetaData;
- import org.datanucleus.metadata.ColumnMetaDataContainer;
- import org.datanucleus.metadata.DiscriminatorMetaData;
- import org.datanucleus.metadata.DiscriminatorStrategy;
- import org.datanucleus.metadata.FieldPersistenceModifier;
- import org.datanucleus.metadata.FieldRole;
- import org.datanucleus.metadata.IdentityStrategy;
- import org.datanucleus.metadata.IdentityType;
- import org.datanucleus.metadata.InheritanceStrategy;
- import org.datanucleus.metadata.MetaData;
- import org.datanucleus.metadata.MetaDataManager;
- import org.datanucleus.metadata.OrderMetaData;
- import org.datanucleus.metadata.PropertyMetaData;
- import org.datanucleus.metadata.RelationType;
- import org.datanucleus.metadata.VersionMetaData;
- import org.datanucleus.plugin.ConfigurationElement;
- import org.datanucleus.store.types.SCOUtils;
- import org.datanucleus.store.mapped.exceptions.NoSuchPersistentFieldException;
- import org.datanucleus.store.mapped.exceptions.NoTableManagedException;
- import org.datanucleus.store.mapped.DatastoreAdapter;
- import org.datanucleus.store.mapped.DatastoreClass;
- import org.datanucleus.store.mapped.DatastoreField;
- import org.datanucleus.store.mapped.DatastoreIdentifier;
- import org.datanucleus.store.mapped.IdentifierFactory;
- import org.datanucleus.store.mapped.IdentifierType;
- import org.datanucleus.store.mapped.MappedStoreManager;
- import org.datanucleus.store.mapped.exceptions.DuplicateDatastoreFieldException;
- import org.datanucleus.store.mapped.mapping.CorrespondentColumnsMapper;
- import org.datanucleus.store.mapped.mapping.DatastoreMapping;
- import org.datanucleus.store.mapped.mapping.DiscriminatorLongMapping;
- import org.datanucleus.store.mapped.mapping.DiscriminatorStringMapping;
- import org.datanucleus.store.mapped.mapping.IndexMapping;
- import org.datanucleus.store.mapped.mapping.IntegerMapping;
- import org.datanucleus.store.mapped.mapping.JavaTypeMapping;
- import org.datanucleus.store.mapped.mapping.LongMapping;
- import org.datanucleus.store.mapped.mapping.MappingConsumer;
- import org.datanucleus.store.mapped.mapping.OIDMapping;
- import org.datanucleus.store.mapped.mapping.PersistableMapping;
- import org.datanucleus.util.MultiMap;
- import org.datanucleus.util.NucleusLogger;
- import org.datanucleus.util.StringUtils;
- import com.google.appengine.datanucleus.DatastoreManager;
- import com.google.appengine.datanucleus.MetaDataUtils;
- import com.google.appengine.datanucleus.Utils;
- import java.text.MessageFormat;
- import java.util.Collection;
- import java.util.HashMap;
- import java.util.HashSet;
- import java.util.LinkedHashMap;
- import java.util.LinkedList;
- import java.util.List;
- import java.util.Map;
- import java.util.Set;
- /**
- * Describes a 'table' in the datastore. We don't actually have tables, but
- * we need to represent this logically in order to take care of all the nice
- * mapping logic that datanucleus does for us.
- *
- * This code is largely copied from AbstractClassTable, ClassTable, TableImpl, and AbstractTable
- *
- * TODO : Drop the code adding "foreign key" when we drop support for old storage versions
- *
- * @author Max Ross <maxr@google.com>
- */
- public class DatastoreTable implements DatastoreClass {
- /** All callbacks for class tables waiting to be performed. */
- private static final MultiMap callbacks = new MultiMap();
- private final DatastoreManager storeMgr;
- private final AbstractClassMetaData cmd;
- private final ClassLoaderResolver clr;
- private final DatastoreAdapter dba;
- private final DatastoreIdentifier identifier;
- /**
- * Mappings for fields mapped to this table, keyed by the FieldMetaData.
- * Supports fast lookup but also preserves order.
- */
- private final Map<AbstractMemberMetaData, JavaTypeMapping> fieldMappingsMap =
- new LinkedHashMap<AbstractMemberMetaData, JavaTypeMapping>();
- /**
- * Similar to {@link #fieldMappingsMap} except primary key fields are added as
- * well. This is needed to support persistence capable classes that can be
- * persisted as top-level classes and as embedded classes.
- */
- private final Map<AbstractMemberMetaData, JavaTypeMapping> embeddedFieldMappingsMap =
- new LinkedHashMap<AbstractMemberMetaData, JavaTypeMapping>();
- /**
- * All the properties in the table. Even though the datastore is schemaless,
- * the mappings provided by the ORM effectively impose a schema. This allows
- * us to know, up front, what properties we can expect.
- */
- private final List<DatastoreProperty> datastoreProperties = Utils.newArrayList();
- /**
- * Index to the props, keyed by name.
- */
- protected Map<String, DatastoreProperty> datastorePropertiesByName = Utils.newHashMap();
- /** Mapping for datastore identity (optional). */
- private JavaTypeMapping datastoreIDMapping;
- /** Mappings for application identity (optional). */
- private JavaTypeMapping[] pkMappings;
- /** Mapping for the id of the table. */
- private JavaTypeMapping idMapping;
- /** MetaData for discriminator for objects stored in this kind. */
- protected DiscriminatorMetaData discriminatorMetaData;
- /** Mapping for any discriminator column. */
- private JavaTypeMapping discriminatorMapping;
-
- /** Highest absolute field number managed by this table */
- private int highestFieldNumber = 0;
- /** Mappings to the owner where this is an element. */
- private final Map<AbstractMemberMetaData, JavaTypeMapping> externalFkMappings = Utils.newHashMap();
- /** Mappings of the position where this is an element in a List. */
- private final Map<AbstractMemberMetaData, JavaTypeMapping> externalOrderMappings = Utils.newHashMap();
- private AbstractMemberMetaData parentMappingMemberMetaData;
- /** MetaData for all classes being managed here. */
- private final Collection<AbstractClassMetaData> managedClassMetaData = new HashSet<AbstractClassMetaData>();
-
- public DatastoreTable(String kind, DatastoreManager storeMgr, AbstractClassMetaData cmd,
- ClassLoaderResolver clr, DatastoreAdapter dba) {
- this.storeMgr = storeMgr;
- this.cmd = cmd;
- this.clr = clr;
- this.dba = dba;
- this.identifier = new DatastoreKind(kind);
- }
- public String getType() {
- return cmd.getFullClassName();
- }
- public IdentityType getIdentityType() {
- return cmd.getIdentityType();
- }
- public boolean isObjectIdDatastoreAttributed() {
- return true;
- }
- public boolean isBaseDatastoreClass() {
- return true;
- }
- public DatastoreClass getBaseDatastoreClass() {
- return this;
- }
- public DatastoreClass getBaseDatastoreClassWithMember(AbstractMemberMetaData fmd) {
- if (fieldMappingsMap.get(fmd) != null) {
- return this;
- }
- return null;
- }
- public DatastoreClass getSuperDatastoreClass() {
- return null;
- }
- public Collection getSecondaryDatastoreClasses() {
- return null;
- }
- public boolean managesClass(String className) {
- return cmd.getFullClassName().equals(className);
- }
- public JavaTypeMapping getDatastoreObjectIdMapping() {
- return datastoreIDMapping;
- }
- public JavaTypeMapping getMemberMapping(String fieldName) {
- AbstractMemberMetaData fmd = getFieldMetaData(fieldName);
- JavaTypeMapping m = getMemberMapping(fmd);
- if (m == null) {
- throw new NoSuchPersistentFieldException(cmd.getFullClassName(), fieldName);
- }
- return m;
- }
- private AbstractMemberMetaData getFieldMetaData(String fieldName) {
- return cmd.getMetaDataForMember(fieldName);
- }
- public JavaTypeMapping getMemberMapping(AbstractMemberMetaData mmd) {
- if (mmd == null) {
- return null;
- }
- return fieldMappingsMap.get(mmd);
- }
- public JavaTypeMapping getMemberMappingInDatastoreClass(AbstractMemberMetaData mmd) {
- return getMemberMapping(mmd);
- }
- // Mostly copied from AbstractTable.addDatastoreField
- public DatastoreProperty addDatastoreField(String storedJavaType, DatastoreIdentifier name,
- JavaTypeMapping mapping, ColumnMetaData colmd) {
- // Create the column
- DatastoreProperty prop =
- new DatastoreProperty(this, mapping.getJavaType().getName(), name, (ColumnMetaData) colmd);
- if (hasColumnName(name)) {
- if (colmd == null || !(colmd instanceof ColumnMetaData)) {
- throw new NucleusException(
- "invalid column meta data property name on class " + getType() + " : " + colmd);
- }
- if (((ColumnMetaData) colmd).getInsertable() || ((ColumnMetaData) colmd).getUpdateable()) {
- // duplicate property names are ok if the field is neither insertable nor updatable
- if (!isSuperclassColumn(prop, mapping, colmd)) {
- throw new NucleusException(
- "Duplicate property name on class " + getType() + " : " + name);
- }
- }
- }
- DatastoreIdentifier colName = prop.getIdentifier();
- datastoreProperties.add(prop);
- datastorePropertiesByName.put(colName.getIdentifierName(), prop);
- return prop;
- }
- protected boolean hasColumnName(DatastoreIdentifier colName) {
- return getDatastoreField(colName) != null;
- }
- public boolean hasDatastoreField(DatastoreIdentifier identifier) {
- return (hasColumnName(identifier));
- }
- public boolean isSuperclassColumn(DatastoreField col, JavaTypeMapping mapping, MetaData colmd) {
- // Verify if a duplicate column is valid. A duplicate column name is (currently) valid when :-
- // 1. subclasses defining the duplicated column are using "super class table" strategy
- //
- // Find the MetaData for the existing column
- DatastoreIdentifier name = col.getIdentifier();
- DatastoreField existingCol = getDatastoreField(name);
- MetaData md = existingCol.getColumnMetaData().getParent();
- while (!(md instanceof AbstractClassMetaData)) {
- if (md == null) {
- // ColumnMetaData for existing column has no parent class somehow!
- throw new NucleusUserException(MessageFormat.format(
- "The property \"{0}\" exists in entity \"{1}\" and has invalid metadata. The existing property is \"{2}\"",
- name, this.identifier, colmd.toString()));
- }
- md = md.getParent();
- }
- // Find the MetaData for the column to be added
- MetaData dupMd = colmd.getParent();
- while (!(dupMd instanceof AbstractClassMetaData)) {
- dupMd = dupMd.getParent();
- if (dupMd == null) {
- // ColumnMetaData for required column has no parent class somehow!
- throw new NucleusUserException(MessageFormat.format(
- "The column \"{0}\" exists in table \"{1}\" and cannot be validated because a duplicated column has been specified and the metadata is invalid. The column is \"{2}\"",
- name, this.identifier, colmd.toString()));
- }
- }
- if (((AbstractClassMetaData) md).getFullClassName().equals(
- ((AbstractClassMetaData) dupMd).getFullClassName())) {
- // compare the current column defining class and the duplicated column defining class. if the same class,
- // we raise an exception when within one class it is defined a column twice
- // in some cases it could still be possible to have these duplicated columns, but does not make too
- // much sense in most of the cases. (this whole block of duplicated column check, could be optional, like a pmf property)
- throw new DuplicateDatastoreFieldException(this.toString(), existingCol, col);
- }
- // Make sure the field JavaTypeMappings are compatible
- if (mapping != null &&
- !mapping.getClass().isAssignableFrom(existingCol.getJavaTypeMapping().getClass()) &&
- !existingCol.getJavaTypeMapping().getClass().isAssignableFrom(mapping.getClass())) {
- // the mapping class must be the same (not really required, but to avoid user mistakes)
- throw new DuplicateDatastoreFieldException(this.toString(), existingCol, col);
- }
- // Make sure the field java types are compatible
- Class<?> fieldStoredJavaTypeClass = null;
- Class<?> existingColStoredJavaTypeClass = null;
- try {
- ClassLoaderResolver clr = storeMgr.getNucleusContext().getClassLoaderResolver(null);
- fieldStoredJavaTypeClass = clr.classForName(col.getStoredJavaType());
- existingColStoredJavaTypeClass = clr.classForName(col.getStoredJavaType());
- }
- catch (RuntimeException cnfe) {
- // Do nothing
- }
- if (fieldStoredJavaTypeClass != null && existingColStoredJavaTypeClass != null &&
- !fieldStoredJavaTypeClass.isAssignableFrom(existingColStoredJavaTypeClass) &&
- !existingColStoredJavaTypeClass.isAssignableFrom(fieldStoredJavaTypeClass)) {
- // the stored java type must be the same (not really required, but to avoid user mistakes)
- throw new DuplicateDatastoreFieldException(this.toString(), existingCol, col);
- }
- return true;
- }
- public DatastoreField getDatastoreField(String colName) {
- return datastorePropertiesByName.get(colName);
- }
- public DatastoreField getDatastoreField(DatastoreIdentifier identifier) {
- return getDatastoreField(identifier.getIdentifierName());
- }
- public JavaTypeMapping getIdMapping() {
- return idMapping;
- }
- public MappedStoreManager getStoreManager() {
- return storeMgr;
- }
- public DatastoreIdentifier getIdentifier() {
- return identifier;
- }
- public boolean isSuperDatastoreClass(DatastoreClass datastoreClass) {
- return false;
- }
- public boolean managesMapping(JavaTypeMapping javaTypeMapping) {
- return true;
- }
- public DatastoreField[] getDatastoreFields() {
- return datastoreProperties.toArray(new DatastoreField[datastoreProperties.size()]);
- }
- public void buildMapping() {
- initializePK();
- initializeNonPK();
- initializeDiscriminatorMapping(cmd.getDiscriminatorMetaDataForTable());
- runCallBacks();
- this.managedClassMetaData.add(cmd);
- }
- public void manageClass(AbstractClassMetaData cmd) {
- // We demand DiscriminatorMetaData, because in cases where an object of the
- // top class in the inheritance hierarchy will be persisted and the subclasses
- // are not yet known to datanucleus, we already need to know about the discriminator
- // property. At this point here the exception can be too late, if an object of
- // the top class has been persisted already. But at least the developer is
- // now informed, that he should add the DiscriminatorMetaData.
- if (getDiscriminatorMetaData() == null) {
- throw new NucleusUserException("Descriminator meta data for " +
- cmd.getFullClassName() +
- " is missing. Please specify at least the discriminator column.");
- }
- // Go through the fields for this class and add columns for them
- for (AbstractMemberMetaData fmd : cmd.getManagedMembers()) {
- addFieldMapping(cmd, fmd);
- }
- this.managedClassMetaData.add(cmd);
- }
- /**
- * returns the names of all classes managed by this table.
- * @return Names of the classes managed (stored) here
- */
- public String[] getManagedClasses() {
- List<String> list = Utils.transform(managedClassMetaData, new Utils.Function<AbstractClassMetaData, String>() {
- public String apply(AbstractClassMetaData cmd) {
- return cmd.getFullClassName();
- }
- });
- return list.toArray(new String[list.size()]);
- }
- private void initializeNonPK() {
- // We only support inheritance strategies that resolve to all fields for
- // a class plus all its subclasses living in every "table," so we'll
- // iterate over all managed fields in the entire chain, topmost classes
- // first so that overrides work properly.
- List<AbstractClassMetaData> cmdl = buildClassMetaDataList();
-
- // get the class level overridden members
- // simply reversing the order we iterate through the hierarchy
- // of ClassMetaData disorders the field numbers
- Map<String, AbstractMemberMetaData> overriddenFieldMap = new HashMap<String, AbstractMemberMetaData>();
- for (AbstractClassMetaData curCmd : cmdl) {
- for (AbstractMemberMetaData fmd : curCmd.getOverriddenMembers()) {
- overriddenFieldMap.put(fmd.getFullFieldName(), fmd);
- }
- }
-
- for (AbstractClassMetaData curCmd : cmdl) {
- // Go through the fields for this class and add columns for them
- for (AbstractMemberMetaData fmd : curCmd.getManagedMembers()) {
- if (overriddenFieldMap.containsKey(fmd.getFullFieldName())) {
- fmd = overriddenFieldMap.get(fmd.getFullFieldName());
- }
- addFieldMapping(curCmd, fmd);
- }
- }
- Class curClass = clr.classForName(cmd.getFullClassName()).getSuperclass();
- // see if any of our superclasses have a parentMappingField
- while (!Object.class.equals(curClass)) {
- DatastoreTable dt = null;
- try {
- dt = (DatastoreTable) storeMgr.getDatastoreClass(curClass.getName(), clr);
- } catch (NoTableManagedException ntme) {
- // this is ok, not all parent classes need to be managed
- }
- // sometimes the parent table is not yet initialized
- if (dt != null) {
- // inherit the parentMappingField
- if (parentMappingMemberMetaData == null) {
- if (dt.parentMappingMemberMetaData != null) {
- parentMappingMemberMetaData = dt.parentMappingMemberMetaData;
- break;
- }
- }
- // inherit any external fk mappings
- if (!dt.externalFkMappings.isEmpty()) {
- externalFkMappings.putAll(dt.externalFkMappings);
- }
- }
- curClass = curClass.getSuperclass();
- }
- }
- private void addFieldMapping(AbstractClassMetaData curCmd, AbstractMemberMetaData fmd) {
- // Primary key fields are added by the initialisePK method
- if (fmd.isPrimaryKey()) {
- // We need to know about this mapping when accessing the class as an embedded field.
- embeddedFieldMappingsMap.put(fmd, pkMappings[0]);
- } else {
- if (managesField(fmd.getFullFieldName())) {
- if (!fmd.getClassName(true).equals(curCmd.getFullClassName())) {
- throw new UnsupportedOperationException("Overrides not currently supported.");
- }
- } else {
- MetaDataManager mmgr = storeMgr.getMetaDataManager();
- // Manage the field if not already managed (may already exist if overriding a superclass field)
- JavaTypeMapping mapping = null;
- if (fmd.getPersistenceModifier() == FieldPersistenceModifier.PERSISTENT) {
- boolean isPrimary = true;
- if (fmd.getTable() != null && fmd.getJoinMetaData() == null) {
- // Field has a table specified and is not a 1-N with join table so is mapped to a secondary table
- isPrimary = false;
- }
- if (isPrimary) {
- // Add the field to this table
- mapping = dba.getMappingManager(storeMgr).getMapping(this, fmd, clr, FieldRole.ROLE_FIELD);
- addFieldMapping(mapping);
- embeddedFieldMappingsMap.put(fmd, fieldMappingsMap.get(fmd));
- } else {
- throw new UnsupportedOperationException("No support for secondary tables.");
- }
- } else if (fmd.getPersistenceModifier() != FieldPersistenceModifier.TRANSACTIONAL) {
- throw new NucleusException("Invalid persistence-modifier for field ").setFatal();
- }
- // Calculate if we need a FK adding due to a 1-N relationship TODO Remove this when no longer supporting old storageVersion
- // Note that we ignore any "join" setting since we don't use join tables
- boolean needsFKToContainerOwner = false;
- RelationType relationType = fmd.getRelationType(clr);
- if (relationType == RelationType.ONE_TO_MANY_BI) {
- /*AbstractMemberMetaData[] relatedMmds = fmd.getRelatedMemberMetaData(clr);
- if (fmd.getJoinMetaData() == null && relatedMmds[0].getJoinMetaData() == null) {*/
- needsFKToContainerOwner = true;
- /*}*/
- } else if (relationType == RelationType.ONE_TO_MANY_UNI) {
- /*if (fmd.getJoinMetaData() == null) {*/
- needsFKToContainerOwner = true;
- /*}*/
- } else if (relationType == RelationType.ONE_TO_ONE_BI) {
- if (fmd.getMappedBy() != null && MetaDataUtils.isOwnedRelation(fmd, storeMgr)) {
- // This element type has a many-to-one pointing back.
- // We assume that our pk is part of the pk of the element type.
- DatastoreTable dt = storeMgr.getDatastoreClass(fmd.getAbstractClassMetaData().getFullClassName(), clr);
- dt.runCallBacks();
- dt.markFieldAsParentKeyProvider(fmd.getName());
- }
- } else if (relationType == RelationType.MANY_TO_ONE_BI) {
- }
- if (needsFKToContainerOwner) {
- // 1-N uni/bidirectional using FK, so update the element side with a FK
- if ((fmd.getCollection() != null && !SCOUtils.collectionHasSerialisedElements(fmd)) ||
- (fmd.getArray() != null && !SCOUtils.arrayIsStoredInSingleColumn(fmd, mmgr))) {
- // 1-N ForeignKey collection/array, so add FK to element table
- AbstractClassMetaData elementCmd;
- if (fmd.hasCollection()) {
- // Collection
- elementCmd = mmgr.getMetaDataForClass(fmd.getCollection().getElementType(), clr);
- } else {
- // Array
- elementCmd = mmgr.getMetaDataForClass(fmd.getType().getComponentType(), clr);
- }
- if (elementCmd == null) {
- // Elements that are reference types or non-PC will come through here
- } else {
- AbstractClassMetaData[] elementCmds;
- // TODO : Cater for interface elements, and get the metadata for the implementation classes here
- if (elementCmd.getInheritanceMetaData().getStrategy() == InheritanceStrategy.SUBCLASS_TABLE) {
- elementCmds = storeMgr.getClassesManagingTableForClass(elementCmd, clr);
- } else {
- elementCmds = new ClassMetaData[1];
- elementCmds[0] = elementCmd;
- }
- // Run callbacks for each of the element classes.
- for (AbstractClassMetaData elementCmd1 : elementCmds) {
- callbacks.put(elementCmd1.getFullClassName(), new CallBack(fmd, cmd.getFullClassName()));
- DatastoreTable dt =
- (DatastoreTable) storeMgr.getDatastoreClass(elementCmd1.getFullClassName(), clr);
- dt.runCallBacks();
- if (fmd.getMappedBy() != null && MetaDataUtils.isOwnedRelation(fmd, storeMgr)) {
- // This element type has a many-to-one pointing back.
- // We assume that our pk is part of the pk of the element type.
- dt.markFieldAsParentKeyProvider(fmd.getMappedBy());
- }
- }
- }
- } else if (fmd.getMap() != null && !SCOUtils.mapHasSerialisedKeysAndValues(fmd)) {
- // 1-N ForeignKey map, so add FK to value table
- if (fmd.getKeyMetaData() != null && fmd.getKeyMetaData().getMappedBy() != null) {
- // Key is stored in the value table so add the FK to the value table
- AbstractClassMetaData valueCmd = mmgr.getMetaDataForClass(fmd.getMap().getValueType(), clr);
- if (valueCmd == null) {
- // Interface elements will come through here and java.lang.String and others as well
- }
- } else if (fmd.getValueMetaData() != null
- && fmd.getValueMetaData().getMappedBy() != null) {
- // Value is stored in the key table so add the FK to the key table
- AbstractClassMetaData keyCmd = mmgr.getMetaDataForClass(fmd.getMap().getKeyType(), clr);
- if (keyCmd == null) {
- // Interface elements will come through here and java.lang.String and others as well
- } else {
- }
- }
- }
- }
- }
- }
- }
- /**
- * Constructs a list containing the class meta data of {@link #cmd} and all
- * its superclasses. We add to the beginning of the list as we iterate up so
- * the class at the top of the hierarchy is returned first.
- */
- private LinkedList<AbstractClassMetaData> buildClassMetaDataList() {
- LinkedList<AbstractClassMetaData> stack = Utils.newLinkedList();
- AbstractClassMetaData curCmd = cmd;
- while (curCmd != null) {
- stack.addFirst(curCmd);
- curCmd = curCmd.getSuperAbstractClassMetaData();
- }
- return stack;
- }
- private void markFieldAsParentKeyProvider(String mappedBy) {
- AbstractMemberMetaData newParentMappingField = getFieldMetaData(mappedBy);
- if (parentMappingMemberMetaData == null) {
- parentMappingMemberMetaData = newParentMappingField;
- } else if (parentMappingMemberMetaData != newParentMappingField) { // intentional reference compare
- throw new NucleusException(
- "App Engine ORM does not support multiple parent key provider fields : class=" + cmd.getFullClassName() +
- " requested to have member=" + mappedBy +
- " but already have member=" + parentMappingMemberMetaData.getName());
- }
- }
- protected void addFieldMapping(JavaTypeMapping fieldMapping) {
- AbstractMemberMetaData fmd = fieldMapping.getMemberMetaData();
- fieldMappingsMap.put(fmd, fieldMapping);
- // Update highest field number if this is higher
- int absoluteFieldNumber = fmd.getAbsoluteFieldNumber();
- if (absoluteFieldNumber > highestFieldNumber) {
- highestFieldNumber = absoluteFieldNumber;
- }
- }
- public boolean managesField(String fieldName) {
- return fieldName != null && getMappingForFullFieldName(fieldName) != null;
- }
- /**
- * Accessor for the JavaTypeMapping that is handling the field of the specified name. Returns the
- * first one that matches.
- *
- * @param fieldName Name of the field
- * @return The java type mapping
- */
- public JavaTypeMapping getMappingForFullFieldName(String fieldName) {
- Set fields = fieldMappingsMap.keySet();
- for (Object field : fields) {
- AbstractMemberMetaData fmd = (AbstractMemberMetaData) field;
- if (fmd.getFullFieldName().equals(fieldName)) {
- return fieldMappingsMap.get(fmd);
- }
- }
- return null;
- }
- public JavaTypeMapping getMappingForSimpleFieldName(String fieldName) {
- Set fields = fieldMappingsMap.keySet();
- for (Object field : fields) {
- AbstractMemberMetaData fmd = (AbstractMemberMetaData) field;
- if (fmd.getName().equals(fieldName)) {
- return fieldMappingsMap.get(fmd);
- }
- }
- return null;
- }
- void addDatastoreId(ColumnMetaData columnMetaData, DatastoreClass refTable,
- AbstractClassMetaData cmd) {
- datastoreIDMapping = new OIDMapping();
- datastoreIDMapping.initialize(storeMgr, cmd.getFullClassName());
- // Create a ColumnMetaData in the container if none is defined
- ColumnMetaData colmd;
- if (columnMetaData == null) {
- colmd = new ColumnMetaData();
- } else {
- colmd = columnMetaData;
- }
- if (colmd.getName() == null) {
- // Provide default column naming if none is defined
- if (refTable != null) {
- colmd.setName(storeMgr.getIdentifierFactory()
- .newDatastoreFieldIdentifier(refTable.getIdentifier().getIdentifierName(),
- this.storeMgr.getNucleusContext().getTypeManager().isDefaultEmbeddedType(OID.class),
- FieldRole.ROLE_OWNER).getIdentifierName());
- } else {
- colmd.setName(
- storeMgr.getIdentifierFactory().newDatastoreFieldIdentifier(identifier.getIdentifierName(),
- this.storeMgr.getNucleusContext().getTypeManager().isDefaultEmbeddedType(OID.class),
- FieldRole.ROLE_NONE).getIdentifierName());
- }
- }
- // Add the datastore identity column as the PK
- DatastoreField idColumn = addDatastoreField(OID.class.getName(),
- storeMgr.getIdentifierFactory().newIdentifier(IdentifierType.COLUMN, colmd.getName()),
- datastoreIDMapping, colmd);
- idColumn.setAsPrimaryKey();
- // Set the identity column type based on the IdentityStrategy
- String strategyName = cmd.getIdentityMetaData().getValueStrategy().toString();
- if (cmd.getIdentityMetaData().getValueStrategy().equals(IdentityStrategy.CUSTOM)) {
- strategyName = cmd.getIdentityMetaData().getValueStrategy().getCustomName();
- }
- // Check the POID type being stored
- Class poidClass = Long.class;
- ConfigurationElement elem =
- storeMgr.getNucleusContext().getPluginManager().getConfigurationElementForExtension(
- "org.datanucleus.store_valuegenerator",
- new String[]{"name", "unique"}, new String[]{strategyName, "true"});
- if (elem == null) {
- // Not datastore-independent, so try for this datastore
- elem = storeMgr.getNucleusContext().getPluginManager().getConfigurationElementForExtension(
- "org.datanucleus.store_valuegenerator",
- new String[]{"name", "datastore"},
- new String[]{strategyName, storeMgr.getStoreManagerKey()});
- }
- if (elem != null) {
- // Set the generator name (for use by the PoidManager)
- String generatorClassName = elem.getAttribute("class-name");
- Class generatorClass =
- getStoreManager().getNucleusContext().getClassLoaderResolver(null)
- .classForName(generatorClassName);
- try {
- poidClass = (Class) generatorClass.getMethod("getStorageClass").invoke(null);
- }
- catch (Exception e) {
- // Unable to get the storage class from the PoidGenerator class
- NucleusLogger.VALUEGENERATION
- .warn("Error retrieving storage class for POID generator " + generatorClassName +
- " " + e.getMessage());
- }
- }
- dba.getMappingManager(storeMgr)
- .createDatastoreMapping(datastoreIDMapping, idColumn, poidClass.getName());
- // Handle any auto-increment requirement
- if (isObjectIdDatastoreAttributed()) {
- // Only the base class can be autoincremented
- // idColumn.setAutoIncrement(true);
- }
- }
- private void initializePK() {
- AbstractMemberMetaData[] fieldsToAdd = new AbstractMemberMetaData[cmd.getNoOfPrimaryKeyMembers()];
- // Initialise Primary Key mappings for application id with PK fields in this class
- int pkFieldNum = 0;
- int fieldCount = cmd.getNoOfManagedMembers();
- boolean hasPrimaryKeyInThisClass = false;
- if (cmd.getNoOfPrimaryKeyMembers() > 0) {
- pkMappings = new JavaTypeMapping[cmd.getNoOfPrimaryKeyMembers()];
- if (cmd.getInheritanceMetaData().getStrategy() == InheritanceStrategy.COMPLETE_TABLE) {
- // COMPLETE-TABLE so use root class metadata and add PK members
- // TODO Does this allow for overridden PK field info ?
- AbstractClassMetaData baseCmd = cmd.getBaseAbstractClassMetaData();
- fieldCount = baseCmd.getNoOfManagedMembers();
- for (int relFieldNum = 0; relFieldNum < fieldCount; ++relFieldNum) {
- AbstractMemberMetaData mmd = baseCmd.getMetaDataForManagedMemberAtRelativePosition(relFieldNum);
- if (mmd.isPrimaryKey()) {
- if (mmd.getPersistenceModifier() == FieldPersistenceModifier.PERSISTENT) {
- fieldsToAdd[pkFieldNum++] = mmd;
- hasPrimaryKeyInThisClass = true;
- } else if (mmd.getPersistenceModifier() != FieldPersistenceModifier.TRANSACTIONAL) {
- throw new NucleusException("Invalid persistence-modifier for field " + mmd.getName()).setFatal();
- }
- }
- }
- } else {
- for (int relFieldNum = 0; relFieldNum < fieldCount; ++relFieldNum) {
- AbstractMemberMetaData fmd = cmd.getMetaDataForManagedMemberAtRelativePosition(relFieldNum);
- if (fmd.isPrimaryKey()) {
- if (fmd.getPersistenceModifier() == FieldPersistenceModifier.PERSISTENT) {
- fieldsToAdd[pkFieldNum++] = fmd;
- hasPrimaryKeyInThisClass = true;
- } else if (fmd.getPersistenceModifier() != FieldPersistenceModifier.TRANSACTIONAL) {
- throw new NucleusException("Invalid persistence-modifier for field" + fmd.getName()).setFatal();
- }
- }
- }
- }
- }
- // No Primary Key defined, so search for superclass or handle datastore id
- if (!hasPrimaryKeyInThisClass) {
- if (cmd.getIdentityType() == IdentityType.APPLICATION) {
- // application-identity
- DatastoreClass elementCT =
- storeMgr.getDatastoreClass(cmd.getPersistenceCapableSuperclass(), clr);
- if (elementCT != null) {
- // Superclass has a table so copy its PK mappings
- ColumnMetaDataContainer colContainer = null;
- if (cmd.getInheritanceMetaData() != null) {
- // Try via <inheritance><join>...</join></inheritance>
- colContainer = cmd.getInheritanceMetaData().getJoinMetaData();
- }
- if (colContainer == null) {
- // Try via <primary-key>...</primary-key>
- colContainer = cmd.getPrimaryKeyMetaData();
- }
- addApplicationIdUsingClassTableId(colContainer, elementCT, clr, cmd);
- } else {
- // Superclass has no table so create new mappings and columns
- AbstractClassMetaData pkCmd =
- storeMgr.getClassWithPrimaryKeyForClass(cmd.getSuperAbstractClassMetaData(), clr);
- if (pkCmd != null) {
- pkMappings = new JavaTypeMapping[pkCmd.getNoOfPrimaryKeyMembers()];
- pkFieldNum = 0;
- fieldCount = pkCmd.getNoOfInheritedManagedMembers() + pkCmd.getNoOfManagedMembers();
- for (int absFieldNum = 0; absFieldNum < fieldCount; ++absFieldNum) {
- AbstractMemberMetaData fmd = pkCmd
- .getMetaDataForManagedMemberAtAbsolutePosition(absFieldNum);
- if (fmd.isPrimaryKey()) {
- AbstractMemberMetaData overriddenFmd = cmd.getOverriddenMember(fmd.getName());
- if (overriddenFmd != null) {
- // PK field is overridden so use the overriding definition
- fmd = overriddenFmd;
- }
- if (fmd.getPersistenceModifier() == FieldPersistenceModifier.PERSISTENT) {
- fieldsToAdd[pkFieldNum++] = fmd;
- } else if (fmd.getPersistenceModifier() != FieldPersistenceModifier.TRANSACTIONAL) {
- throw new NucleusException("Invalid persistence-modifier for field " + fmd.getName()).setFatal();
- }
- }
- }
- }
- }
- } else if (cmd.getIdentityType() == IdentityType.DATASTORE) {
- // datastore-identity
- ColumnMetaData colmd = null;
- if (cmd.getIdentityMetaData() != null
- && cmd.getIdentityMetaData().getColumnMetaData() != null) {
- // Try via <datastore-identity>...</datastore-identity>
- colmd = cmd.getIdentityMetaData().getColumnMetaData();
- }
- if (colmd == null) {
- // Try via <primary-key>...</primary-key>
- if (cmd.getPrimaryKeyMetaData() != null && cmd.getPrimaryKeyMetaData().getColumnMetaData() != null &&
- cmd.getPrimaryKeyMetaData().getColumnMetaData().length > 0) {
- colmd = cmd.getPrimaryKeyMetaData().getColumnMetaData()[0];
- }
- }
- addDatastoreId(colmd, null, cmd);
- } else if (cmd.getIdentityType() == IdentityType.NONDURABLE) {
- // Do nothing since no identity!
- }
- }
- //add field mappings in the end, so we compute all columns after the post initialize
- for (int i = 0; i < fieldsToAdd.length; i++) {
- if (fieldsToAdd[i] != null) {
- try {
- DatastoreClass datastoreClass = getStoreManager()
- .getDatastoreClass(fieldsToAdd[i].getType().getName(), clr);
- if (datastoreClass.getIdMapping() == null) {
- throw new NucleusException(
- "Unsupported relationship with field " + fieldsToAdd[i].getFullFieldName())
- .setFatal();
- }
- }
- catch (NoTableManagedException ex) {
- //do nothing
- }
- JavaTypeMapping fieldMapping = dba.getMappingManager(storeMgr)
- .getMapping(this, fieldsToAdd[i], clr, FieldRole.ROLE_FIELD);
- addFieldMapping(fieldMapping);
- pkMappings[i] = fieldMapping;
- }
- }
- initializeIDMapping();
- }
- private void initializeDiscriminatorMapping(DiscriminatorMetaData dismd) {
- if (dismd != null) {
- discriminatorMetaData = dismd;
- if (dismd.getStrategy() == DiscriminatorStrategy.CLASS_NAME) {
- discriminatorMapping = new DiscriminatorStringMapping(
- dba, this, dba.getMappingManager(storeMgr).getMapping(String.class));
- } else if (dismd.getStrategy() == DiscriminatorStrategy.VALUE_MAP) {
- ColumnMetaData disColmd = dismd.getColumnMetaData();
- if (disColmd != null && disColmd.getJdbcType() != null) {
- if (disColmd.getJdbcType().equalsIgnoreCase("INTEGER")
- || disColmd.getJdbcType().equalsIgnoreCase("BIGINT")
- || disColmd.getJdbcType().equalsIgnoreCase("NUMERIC")) {
- discriminatorMapping = new DiscriminatorLongMapping(dba, this, dba
- .getMappingManager(storeMgr).getMapping(Long.class));
- } else {
- discriminatorMapping = new DiscriminatorStringMapping(
- dba, this, dba.getMappingManager(storeMgr).getMapping(String.class));
- }
- } else {
- discriminatorMapping = new DiscriminatorStringMapping(
- dba, this, dba.getMappingManager(storeMgr).getMapping(String.class));
- }
- }
- }
- }
- /**
- * Initialize the ID Mapping
- */
- private void initializeIDMapping() {
- if (idMapping != null) {
- return;
- }
- final PersistableMapping mapping = new PersistableMapping();
- mapping.initialize(getStoreManager(), cmd.getFullClassName());
- if (getIdentityType() == IdentityType.DATASTORE) {
- mapping.addJavaTypeMapping(datastoreIDMapping);
- } else if (getIdentityType() == IdentityType.APPLICATION) {
- for (JavaTypeMapping pkMapping : pkMappings) {
- mapping.addJavaTypeMapping(pkMapping);
- }
- } else {
- // Nothing to do for nondurable since no identity
- }
- idMapping = mapping;
- }
- final void addApplicationIdUsingClassTableId(ColumnMetaDataContainer columnContainer,
- DatastoreClass refTable, ClassLoaderResolver clr, AbstractClassMetaData cmd) {
- ColumnMetaData[] userdefinedCols = null;
- int nextUserdefinedCol = 0;
- if (columnContainer != null) {
- userdefinedCols = columnContainer.getColumnMetaData();
- }
- pkMappings = new JavaTypeMapping[cmd.getPKMemberPositions().length];
- for (int i = 0; i < cmd.getPKMemberPositions().length; i++) {
- AbstractMemberMetaData fmd = cmd
- .getMetaDataForManagedMemberAtAbsolutePosition(cmd.getPKMemberPositions()[i]);
- JavaTypeMapping mapping = refTable.getMemberMapping(fmd);
- if (mapping == null) {
- //probably due to invalid metadata defined by the user
- throw new NucleusUserException("Cannot find mapping for field " + fmd.getFullFieldName() +
- " in table " + refTable.toString() + " " +
- StringUtils.objectArrayToString(refTable.getDatastoreFields()));
- }
- JavaTypeMapping masterMapping = storeMgr.getMappingManager()
- .getMapping(clr.classForName(mapping.getType()));
- masterMapping.setMemberMetaData(fmd); // Update field info in mapping
- pkMappings[i] = masterMapping;
- // Loop through each id column in the reference table and add the same here
- // applying the required names from the columnContainer
- for (int j = 0; j < mapping.getNumberOfDatastoreMappings(); j++) {
- JavaTypeMapping m = masterMapping;
- DatastoreField refColumn = mapping.getDatastoreMapping(j).getDatastoreField();
- if (mapping instanceof PersistableMapping) {
- m = storeMgr.getMappingManager()
- .getMapping(clr.classForName(refColumn.getJavaTypeMapping().getType()));
- ((PersistableMapping) masterMapping).addJavaTypeMapping(m);
- }
- ColumnMetaData userdefinedColumn = null;
- if (userdefinedCols != null) {
- for (ColumnMetaData userdefinedCol : userdefinedCols) {
- if (refColumn.getIdentifier().toString().equals(userdefinedCol.getTarget())) {
- userdefinedColumn = userdefinedCol;
- break;
- }
- }
- if (userdefinedColumn == null && nextUserdefinedCol < userdefinedCols.length) {
- userdefinedColumn = userdefinedCols[nextUserdefinedCol++];
- }
- }
- // Add this application identity column
- DatastoreField idColumn;
- if (userdefinedColumn != null) {
- // User has provided a name for this column
- // Currently we only use the column namings from the users definition but we could easily
- // take more of their details.
- idColumn = addDatastoreField(refColumn.getStoredJavaType(),
- storeMgr.getIdentifierFactory().newIdentifier(IdentifierType.COLUMN,
- userdefinedColumn.getName()),
- m, refColumn.getColumnMetaData());
- } else {
- // No name provided so take same as superclass
- idColumn = addDatastoreField(refColumn.getStoredJavaType(), refColumn.getIdentifier(),
- m, refColumn.getColumnMetaData());
- }
- if (mapping != null
- && mapping.getDatastoreMapping(j).getDatastoreField().getColumnMetaData() != null) {
- refColumn.copyConfigurationTo(idColumn);
- }
- idColumn.setAsPrimaryKey();
- // Set the column type based on the field.getType()
- getStoreManager().getMappingManager()
- .createDatastoreMapping(m, idColumn, refColumn.getJavaTypeMapping().getType());
- }
- // Update highest field number if this is higher
- int absoluteFieldNumber = fmd.getAbsoluteFieldNumber();
- if (absoluteFieldNumber > highestFieldNumber) {
- highestFieldNumber = absoluteFieldNumber;
- }
- }
- }
- public void provideDatastoreIdMappings(MappingConsumer consumer) {
- consumer.preConsumeMapping(highestFieldNumber + 1);
- if (getIdentityType() == IdentityType.DATASTORE) {
- consumer.consumeMapping(getDatastoreObjectIdMapping(), MappingConsumer.MAPPING_TYPE_DATASTORE_ID);
- }
- }
- public void providePrimaryKeyMappings(MappingConsumer consumer) {
- consumer.preConsumeMapping(highestFieldNumber + 1);
- if (pkMappings != null) {
- // Application identity
- int[] primaryKeyFieldNumbers = cmd.getPKMemberPositions();
- for (int i = 0; i < pkMappings.length; i++) {
- // Make the assumption that the pkMappings are in the same order as the absolute field numbers
- AbstractMemberMetaData fmd = cmd
- .getMetaDataForManagedMemberAtAbsolutePosition(primaryKeyFieldNumbers[i]);
- consumer.consumeMapping(pkMappings[i], fmd);
- }
- } else {
- // Datastore identity
- int[] primaryKeyFieldNumbers = cmd.getPKMemberPositions();
- int countPkFields = cmd.getNoOfPrimaryKeyMembers();
- for (int i = 0; i < countPkFields; i++) {
- AbstractMemberMetaData pkfmd = cmd
- .getMetaDataForManagedMemberAtAbsolutePosition(primaryKeyFieldNumbers[i]);
- consumer.consumeMapping(getMemberMapping(pkfmd), pkfmd);
- }
- }
- }
- public void provideNonPrimaryKeyMappings(MappingConsumer consumer) {
- provideNonPrimaryKeyMappings(consumer, false);
- }
- public void provideNonPrimaryKeyMappings(MappingConsumer consumer, boolean isEmbedded) {
- consumer.preConsumeMapping(highestFieldNumber + 1);
- Set<Map.Entry<AbstractMemberMetaData, JavaTypeMapping>> entries =
- isEmbedded ? embeddedFieldMappingsMap.entrySet() : fieldMappingsMap.entrySet();
- for (Map.Entry<AbstractMemberMetaData, JavaTypeMapping> entry : entries) {
- if (entry.getValue() != null) {
- if (!entry.getKey().isPrimaryKey() || isEmbedded) {
- consumer.consumeMapping(entry.getValue(), entry.getKey());
- }
- }
- }
- }
- public void provideMappingsForMembers(MappingConsumer consumer, AbstractMemberMetaData[] mmds,
- boolean includeSecondaryTables) {
- for (AbstractMemberMetaData aFieldMetaData : mmds) {
- JavaTypeMapping fieldMapping = fieldMappingsMap.get(aFieldMetaData);
- if (fieldMapping != null) {
- if (!aFieldMetaData.isPrimaryKey()) {
- consumer.consumeMapping(fieldMapping, aFieldMetaData);
- }
- }
- }
- }
- public void provideVersionMappings(MappingConsumer consumer) {
- }
- public void provideDiscriminatorMappings(MappingConsumer consumer) {
- consumer.preConsumeMapping(highestFieldNumber + 1);
- if (getDiscriminatorMapping(false) != null) {
- consumer.consumeMapping(getDiscriminatorMapping(false),
- MappingConsumer.MAPPING_TYPE_DISCRIMINATOR);
- }
- }
- public void provideUnmappedDatastoreFields(MappingConsumer consumer) {
- }
- public void provideExternalMappings(MappingConsumer consumer, int mappingType) {
- }
- public JavaTypeMapping getExternalMapping(AbstractMemberMetaData fmd, int mappingType) {
- if (mappingType == MappingConsumer.MAPPING_TYPE_EXTERNAL_FK) {
- return getExternalFkMappings().get(fmd);
- } else if (mappingType == MappingConsumer.MAPPING_TYPE_EXTERNAL_FK_DISCRIM) {
- return null; //getExternalFkDiscriminatorMappings().get(fmd);
- } else if (mappingType == MappingConsumer.MAPPING_TYPE_EXTERNAL_INDEX) {
- return getExternalOrderMappings().get(fmd);
- } else {
- return null;
- }
- }
- public AbstractMemberMetaData getMetaDataForExternalMapping(JavaTypeMapping mapping,
- int mappingType) {
- if (mappingType == MappingConsumer.MAPPING_TYPE_EXTERNAL_FK) {
- Set entries = getExternalFkMappings().entrySet();
- for (Object entry1 : entries) {
- Map.Entry entry = (Map.Entry) entry1;
- if (entry.getValue() == mapping) {
- return (AbstractMemberMetaData) entry.getKey();
- }
- }
- }
- return null;
- }
- public DiscriminatorMetaData getDiscriminatorMetaData() {
- return discriminatorMetaData;
- }
- public JavaTypeMapping getDiscriminatorMapping(boolean allowSuperclasses) {
- return discriminatorMapping;
- }
- public VersionMetaData getVersionMetaData() {
- return null;
- }
- public JavaTypeMapping getVersionMapping(boolean allowSuperclasses) {
- return null;
- }
- /**
- * Accessor for all of the external FK mappings (used by FK Lists, Collections, Arrays)
- * @return The mappings for the FKs of 1-Ns, keyed by the field/property metadata.
- */
- public Map<AbstractMemberMetaData, JavaTypeMapping> getExternalFkMappings() {
- return externalFkMappings;
- }
- /**
- * Accessor for all of the order mappings (used by FK Lists, Collections, Arrays)
- * @return The mappings for the order columns of Lists, keyed by the field/property metadata.
- */
- public Map<AbstractMemberMetaData, JavaTypeMapping> getExternalOrderMappings() {
- return externalOrderMappings;
- }
- /**
- * Execute the callbacks for the classes that this table maps to.
- */
- private void runCallBacks() {
- Collection c = (Collection) callbacks.remove(cmd.getFullClassName());
- if (c == null) {
- return;
- }
- for (Object aC : c) {
- CallBack callback = (CallBack) aC;
- /* if (callback.fmd.getJoinMetaData() == null) {*/
- // 1-N relationship
- AbstractMemberMetaData ownerFmd = callback.fmd;
- if (ownerFmd.getMappedBy() != null) {
- // Bidirectional (element has a PC mapping to the owner)
- // Check that the "mapped-by" field in the other class actually exists
- AbstractMemberMetaData fmd = cmd.getMetaDataForMember(ownerFmd.getMappedBy());
- if (fmd == null) {
- throw new NucleusUserException(
- String.format(
- "Unable to find the field \"{0}\" in the class \"{1}\" with a relationship to the field \"{2}\"",
- ownerFmd.getMappedBy(),
- cmd.getFullClassName(),
- ownerFmd.getFullFieldName()));
- }
- // Add the order mapping as necessary
- addOrderMapping(ownerFmd, null);
- } else {
- // Unidirectional (element knows nothing about the owner)
- String ownerClassName = callback.ownerClassName;
- JavaTypeMapping fkMapping = new PersistableMapping();
- fkMapping.initialize(storeMgr, ownerClassName);
- JavaTypeMapping orderMapping = null;
- // Get the owner id mapping of the "1" end
- JavaTypeMapping ownerIdMapping =
- storeMgr.getDatastoreClass(ownerClassName, clr).getIdMapping();
- ColumnMetaDataContainer colmdContainer = null;
- if (ownerFmd.hasCollection() || ownerFmd.hasArray()) {
- // 1-N Collection/array
- colmdContainer = ownerFmd.getElementMetaData();
- } else if (ownerFmd.hasMap() && ownerFmd.getKeyMetaData() != null
- && ownerFmd.getKeyMetaData().getMappedBy() != null) {
- // 1-N Map with key stored in the value
- colmdContainer = ownerFmd.getValueMetaData();
- } else if (ownerFmd.hasMap() && ownerFmd.getValueMetaData() != null
- && ownerFmd.getValueMetaData().getMappedBy() != null) {
- // 1-N Map with value stored in the key
- colmdContainer = ownerFmd.getKeyMetaData();
- }
- CorrespondentColumnsMapper correspondentColumnsMapping =
- new CorrespondentColumnsMapper(colmdContainer, ownerIdMapping, true);
- int countIdFields = ownerIdMapping.getNumberOfDatastoreMappings();
- for (int i = 0; i < countIdFields; i++) {
- DatastoreMapping refDatastoreMapping = ownerIdMapping.getDatastoreMapping(i);
- JavaTypeMapping mapping = storeMgr.getMappingManager()
- .getMapping(refDatastoreMapping.getJavaTypeMapping().getJavaType());
- ColumnMetaData colmd = correspondentColumnsMapping.getColumnMetaDataByIdentifier(
- refDatastoreMapping.getDatastoreField().getIdentifier());
- if (colmd == null) {
- throw new NucleusFatalUserException(
- String.format("Primary Key column \"%s\" for table \"%s\" is not mapped.",
- refDatastoreMapping.getDatastoreField().getIdentifier(),
- toString()));
- }
- DatastoreIdentifier identifier;
- IdentifierFactory idFactory = storeMgr.getIdentifierFactory();
- if (colmd.getName() == null || colmd.getName().length() < 1) {
- // No user provided name so generate one
- identifier = idFactory.newForeignKeyFieldIdentifier(
- ownerFmd, null, refDatastoreMapping.getDatastoreField().getIdentifier(),
- storeMgr.getNucleusContext().getTypeManager().isDefaultEmbeddedType(mapping.getJavaType()),
- FieldRole.ROLE_OWNER);
- } else {
- // User-defined name
- identifier = idFactory.newDatastoreFieldIdentifier(colmd.getName());
- }
- // When we have an inherited relationship we end up
- // trying to add an owner property twice - once from the super-class
- // and once from the sub-class. This generates an exception for
- // duplicate property names. To avoid this we check to see if
- // the table already has a property with this name before attempting
- // to add the mapping
- if (!datastorePropertiesByName.containsKey(identifier.getIdentifierName())) {
- DatastoreProperty refColumn =
- addDatastoreField(mapping.getJavaType().getName(), identifier, mapping, colmd);
- refDatastoreMapping.getDatastoreField().copyConfigurationTo(refColumn);
- if ((colmd.getAllowsNull() == null) ||
- (colmd.getAllowsNull() != null && colmd.isAllowsNull())) {
- // User either wants it nullable, or havent specified anything, so make it nullable
- refColumn.setNullable();
- }
- // this is needed for one-to-many sets
- fkMapping.addDatastoreMapping(getStoreManager().getMappingManager()
- .createDatastoreMapping(mapping, refColumn,
- refDatastoreMapping.getJavaTypeMapping().getJavaType().getName()));
- ((PersistableMapping) fkMapping).addJavaTypeMapping(mapping);
- }
- }
- // Save the external FK
- getExternalFkMappings().put(ownerFmd, fkMapping);
- // Add the order mapping as necessary
- addOrderMapping(ownerFmd, orderMapping);
- }
- }
- /*}*/
- }
- private JavaTypeMapping addOrderMapping(AbstractMemberMetaData fmd, JavaTypeMapping orderMapping) {
- boolean needsOrderMapping = false;
- OrderMetaData omd = fmd.getOrderMetaData();
- if (fmd.hasArray()) {
- // Array field always has the index mapping
- needsOrderMapping = true;
- } else if (List.class.isAssignableFrom(fmd.getType())) {
- // List field
- needsOrderMapping = !(omd != null && !omd.isIndexedList());
- } else if (java.util.Collection.class.isAssignableFrom(fmd.getType()) &&
- omd != null && omd.isIndexedList() && omd.getMappedBy() == null) {
- // Collection field with <order> and is indexed list so needs order mapping
- needsOrderMapping = true;
- }
- if (needsOrderMapping) {
- // if the field is list or array type, add index column
- if (orderMapping == null) {
- // Create new order mapping since we need one and we aren't using a shared FK
- orderMapping = addOrderColumn(fmd);
- }
- if (!MetaDataUtils.readRelatedKeysFromParent(storeMgr, fmd)) {
- getExternalOrderMappings().put(fmd, orderMapping);
- }
- }
- return orderMapping;
- }
- /**
- * Adds an ordering column to the element table (this) in inverse list relationships. Used to
- * store the position of the element in the List. If the <order> provides a mapped-by, this
- * will return the existing column mapping.
- *
- * @param fmd The MetaData for the column to map to
- * @return The Mapping for the order column
- */
- private JavaTypeMapping addOrderColumn(AbstractMemberMetaData fmd) {
- Class indexType = Integer.class;
- JavaTypeMapping indexMapping = new IndexMapping();
- indexMapping.initialize(storeMgr, indexType.getName());
- IdentifierFactory idFactory = storeMgr.getIdentifierFactory();
- DatastoreIdentifier indexColumnName = null;
- ColumnMetaData colmd = null;
- // Allow for any user definition in OrderMetaData
- OrderMetaData omd = fmd.getOrderMetaData();
- if (omd != null) {
- colmd =
- (omd.getColumnMetaData() != null && omd.getColumnMetaData().length > 0 ? omd.getColumnMetaData()[0] : null);
- if (omd.getMappedBy() != null) {
- // User has defined ordering using the column(s) of an existing field.
- JavaTypeMapping orderMapping = getMemberMapping(omd.getMappedBy());
- if (orderMapping == null) {
- throw new NucleusUserException(String.format(
- "Field \"{0}\" has an <order> defined to be persisted into the columns in the element table for element field \"{1}\". This field is not found in the element class.",
- fmd.getFullFieldName(), omd.getMappedBy()));
- }
- if (!(orderMapping instanceof IntegerMapping) && !(orderMapping instanceof LongMapping)) {
- throw new NucleusUserException(
- String.format(
- "Field \"{0}\" has an <order> defined to be persisted into the column of field \"{1}\". This field is of an invalid type. Must be an int/Integer.",
- fmd.getFullFieldName(), omd.getMappedBy()));
- }
- return orderMapping;
- }
- String colName;
- if (omd.getColumnMetaData() != null && omd.getColumnMetaData().length > 0
- && omd.getColumnMetaData()[0].getName() != null) {
- // User-defined name so create an identifier using it
- colName = omd.getColumnMetaData()[0].getName();
- indexColumnName = idFactory.newDatastoreFieldIdentifier(colName);
- }
- }
- if (indexColumnName == null) {
- // No index column name defined so generate one
- indexColumnName = idFactory.newForeignKeyFieldIdentifier(fmd, null, null, true, FieldRole.ROLE_INDEX);
- }
- // if the relationship is in a base class with multiple subclasses, each
- // subclass will try to add the index column. We need to avoid adding
- // the same column twice.
- DatastoreField column = datastorePropertiesByName.get(indexColumnName.getIdentifierName());
- if (column == null) {
- column = addDatastoreField(indexType.getName(), indexColumnName, indexMapping, colmd);
- }
- if (colmd == null || (colmd.getAllowsNull() == null) ||
- (colmd.getAllowsNull() != null && colmd.isAllowsNull())) {
- // User either wants it nullable, or havent specified anything, so make it nullable
- column.setNullable();
- }
- DatastoreFKMapping fkMapping =
- (DatastoreFKMapping) storeMgr.getMappingManager().createDatastoreMapping(
- indexMapping, column, indexType.getName());
- DatastoreProperty field = fkMapping.getDatastoreField();
- DatastoreTable elementTable = field.getDatastoreContainerObject();
- PropertyMetaData pmd = new PropertyMetaData(elementTable.getClassMetaData(), indexColumnName.getIdentifierName());
- field.setMemberMetaData(pmd);
- return indexMapping;
- }
- public boolean isParentKeyProvider(AbstractMemberMetaData ammd) {
- return ammd.equals(parentMappingMemberMetaData);
- }
- public AbstractMemberMetaData getParentMappingMemberMetaData() {
- return parentMappingMemberMetaData;
- }
- /**
- * Callbacks is used for inverse relationships to run some operation in the target table. The
- * operation is creation of columns, indexes, or whatever needed.
- */
- private static class CallBack {
- final AbstractMemberMetaData fmd;
- final String ownerClassName;
- /**
- * Default constructor
- *
- * @param fmd The FieldMetaData
- * @param ownerClassName The concrete type of the relationship
- */
- public CallBack(AbstractMemberMetaData fmd, String ownerClassName) {
- this.fmd = fmd;
- this.ownerClassName = ownerClassName;
- }
- }
- public String toString() {
- return cmd.getFullClassName();
- }
- public AbstractClassMetaData getClassMetaData() {
- return cmd;
- }
- public JavaTypeMapping getMultitenancyMapping() {
- // Don't support multitenancy via discriminator currently
- return null;
- }
- public void provideMultitenancyMapping(MappingConsumer consumer) {
- // Don't support multitenancy via discriminator currently
- }
- class DatastoreKind implements DatastoreIdentifier {
- private final String identifier;
- public DatastoreKind(String identifier) {
- this.identifier = identifier;
- }
- public String getIdentifierName() {
- return identifier;
- }
- public String getFullyQualifiedName(boolean adapterCase) {
- return getIdentifierName();
- }
- public void setCatalogName(String s) {
- }
- public void setSchemaName(String s) {
- }
- public String getCatalogName() {
- return null;
- }
- public String getSchemaName() {
- return null;
- }
- }
- }