Package org.jpox.store.rdbms.table

Source Code of org.jpox.store.rdbms.table.SecondaryTable

/**********************************************************************
Copyright (c) 2005 Andy Jefferson and others. All rights reserved.
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.

Contributors:
   ...
**********************************************************************/
package org.jpox.store.rdbms.table;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import org.jpox.ClassLoaderResolver;
import org.jpox.exceptions.JPOXException;
import org.jpox.exceptions.JPOXUserException;
import org.jpox.metadata.AbstractMemberMetaData;
import org.jpox.metadata.ClassMetaData;
import org.jpox.metadata.ForeignKeyAction;
import org.jpox.metadata.ForeignKeyMetaData;
import org.jpox.metadata.IdentityType;
import org.jpox.metadata.JoinMetaData;
import org.jpox.metadata.PrimaryKeyMetaData;
import org.jpox.store.mapped.DatastoreClass;
import org.jpox.store.mapped.DatastoreIdentifier;
import org.jpox.store.mapped.SecondaryDatastoreClass;
import org.jpox.store.mapped.mapping.JavaTypeMapping;
import org.jpox.store.mapped.mapping.MappingConsumer;
import org.jpox.store.mapped.mapping.PersistenceCapableMapping;
import org.jpox.store.rdbms.RDBMSManager;
import org.jpox.store.rdbms.key.ForeignKey;
import org.jpox.store.rdbms.key.PrimaryKey;

/**
* Representation of a secondary table for a class.
* Has a primary table that manages the main fields for that class and some fields are defined
* (using <field table="...">) to be stored in the secondary table.
* Many of the methods in this class defer to the equivalent method in the primary table.
*
* @version $Revision: 1.48 $
**/
public class SecondaryTable extends AbstractClassTable implements SecondaryDatastoreClass
{
    /** Primary table */
    private ClassTable primaryTable;

    /** MetaData for the join to the primary table. */
    private JoinMetaData joinMetaData;

    /**
     * Constructor. This is package level so that it SecondaryTables are only created by other tables.
     * @param tableName Table name SQL identifier
     * @param storeMgr Store Manager to manage this table
     * @param primaryTable The primary table for the class
     * @param jmd MetaData for the join to the primary table
     * @param clr The ClassLoaderResolver
     */
    SecondaryTable(DatastoreIdentifier tableName, RDBMSManager storeMgr, ClassTable primaryTable, JoinMetaData jmd, ClassLoaderResolver clr)
    {
        super(tableName, storeMgr);
        if (primaryTable == null)
        {
            throw new JPOXUserException(LOCALISER.msg("057045", tableName.getIdentifier()));
        }
        this.primaryTable = primaryTable;
        this.joinMetaData = jmd;
        if (this.joinMetaData == null)
        {
            //if a join was not declared at field level,
            //look for joins declared at class level
            JoinMetaData[] joins = this.primaryTable.getClassMetaData().getJoinMetaData();
            for (int i=0; i<joins.length; i++)
            {
                if (tableName.getIdentifier().equals(joins[i].getTable()))
                {
                    //found a join table with same name as this table name
                    this.joinMetaData = joins[i];
                    break;
                }
            }
        }
    }

    /**
     * Pre initilize. For things that must be initialized right after constructor
     * @param clr the ClassLoaderResolver
     */
    public void preInitialize(final ClassLoaderResolver clr)
    {
        assertIsUninitialized();
       
        // Initialise the PK field(s)
        if (!isPKInitialized())
        {
            initializePK(clr);
        }
    }
   
    /**
     * Post initilize. For things that must be set after all classes have been initialized before
     * @param clr the ClassLoaderResolver
     */
    public void postInitialize(final ClassLoaderResolver clr)
    {
        assertIsInitialized();
    }
   
    /**
     * Method to initialise the table.
     * This will initialise the primary key columns for the table. Any other columns
     * are added via the addFieldMapping() method.
     * @param clr The ClassLoaderResolver
     */
    public void initialize(ClassLoaderResolver clr)
    {
        assertIsUninitialized();

        // TODO Support <primary-key> specification of the columns to use in the PK.
        // This doesnt seem too important IMHO since the secondary table should *always* be
        // joined using the PK of the primary table (and one row in the secondary table matches
        // one row in the primary table).
        state = TABLE_STATE_INITIALIZED;
    }

    /**
     * Method to initialise the primary key of this table.
     * @see org.jpox.store.rdbms.table.AbstractClassTable#initializePK(ClassLoaderResolver)
     */
    protected void initializePK(ClassLoaderResolver clr)
    {
        assertIsPKUninitialized();

        // Generate the primary key using the primary table as reference
        if (primaryTable.getIdentityType() == IdentityType.APPLICATION)
        {
            addApplicationIdUsingClassTableId(joinMetaData, primaryTable, clr, primaryTable.getClassMetaData());
        }
        else if (primaryTable.getIdentityType() == IdentityType.DATASTORE)
        {
            addDatastoreId(joinMetaData, primaryTable, primaryTable.getClassMetaData());
        }

        state = TABLE_STATE_PK_INITIALIZED;
    }

    /**
     * Accessor for the primary key for this table. Overrides the method in TableImpl
     * to add on any specification of PK name in the metadata.
     * @return The primary key.
     */
    public PrimaryKey getPrimaryKey()
    {
        PrimaryKey pk = super.getPrimaryKey();
        if (joinMetaData == null)
        {
            // TODO Localise this message
            throw new JPOXUserException("A relationship to a secondary table requires a <join> specification. " +
                "The secondary table is " + this.getDatastoreIdentifierFullyQualified() +
                " and the primary table is " + this.getPrimaryDatastoreContainerObject() +
                ". The fields mapped to this secondary table are: " + fieldMappingsMap.keySet().toString());
        }
        PrimaryKeyMetaData pkmd = joinMetaData.getPrimaryKeyMetaData();
        if (pkmd != null && pkmd.getName() != null)
        {
            pk.setName(pkmd.getName());
        }

        return pk;
    }

    /**
     * Accessor for the primary datastore class that this is dependent on.
     * @return The associated primary datastore class.
     */
    public DatastoreClass getPrimaryDatastoreClass()
    {
        return primaryTable;
    }

    /**
     * Accessor for the JoinMetaData which is used to join to the primary DatastoreClass.
     * @return JoinMetaData
     */
    public JoinMetaData getJoinMetaData()
    {
        return joinMetaData;
    }

    /**
     * Accessor for the identity-type.
     * Simply returns the same as the primary table
     * @return identity-type tag value
     */   
    public IdentityType getIdentityType()
    {
        return primaryTable.getIdentityType();
    }

    /**
     * Accessor for the main type represented here.
     * @return Name of the principal class represented
     */
    public String getType()
    {
        return primaryTable.getType();
    }

    /**
     * Whether this table or super table has id (primary key) attributed by the datastore
     * @return true if the id attributed by the datastore
     */
    public boolean isObjectIDDatastoreAttributed()
    {
        // We never use auto increment since we only use the same value as the primary table entry
        return false;
    }

    /**
     * Whether this table is the base in the inheritance hierarchy.
     * @return true if this table is a root table
     */
    public boolean isBaseDatastoreClass()
    {
        return primaryTable.isBaseDatastoreClass();
    }

    /**
     * Convenience accessor for the base table for this table which has the specified field.
     * @param fmd Field MetaData for this field
     * @return The base table which has the field specified
     */
    public DatastoreClass getBaseDatastoreClassWithField(AbstractMemberMetaData fmd)
    {
        return primaryTable.getBaseDatastoreClassWithField(fmd);
    }

    /**
     * Accessor for the supertable for this table.
     * @return The supertable
     **/
    public DatastoreClass getSuperDatastoreClass()
    {
        return null;
    }

    /**
     * Accessor for any secondary tables for this table.
     * @return Secondary tables (if any)
     */
    public Collection getSecondaryDatastoreClasses()
    {
        return null;
    }

    /**
     * Accessor for whether this table manages the specified class
     * @param className Name of the class
     * @return Whether it is managed by this table
     */
    public boolean managesClass(String className)
    {
        // We dont manage classes as such (the primary table does that) so just return false
        return false;
    }

    /**
     * Accessor for the expected foreign keys for this table.
     * @return The expected foreign keys.
     **/
    protected List getExpectedForeignKeys()
    {
        assertIsInitialized();

        // Auto mode allows JPOX to decide which FKs are needed as well as using
        // what is in the users MetaData.
        boolean autoMode = false;
        if (storeMgr.getOMFContext().getPersistenceConfiguration().getStringProperty("org.jpox.rdbms.constraintCreateMode").equals("JPOX"))
        {
            autoMode = true;
        }

        ArrayList foreignKeys = new ArrayList();

        // Add FK back to the primary table unless requested not to
        ForeignKeyMetaData fkmd = joinMetaData != null ? joinMetaData.getForeignKeyMetaData() : null;
        if (autoMode || (fkmd != null && fkmd.getDeleteAction() != ForeignKeyAction.NONE))
        {
            ForeignKey fk = new ForeignKey(getIDMapping(), dba, primaryTable, fkmd != null && fkmd.isDeferred() ? true : false);
            if (fkmd != null && fkmd.getName() != null)
            {
                fk.setName(fkmd.getName());
            }
            foreignKeys.add(0, fk);
        }

        return foreignKeys;
    }

    /**
     * Accessor for the field/property Mapping.
     * Returns the mapping if it is present in this table.
     * @param mmd Field MetaData for this field/property
     * @return the Mapping for the field/property
     */
    public JavaTypeMapping getFieldMapping(AbstractMemberMetaData mmd)
    {
        assertIsInitialized();

        // Check if we manage this field
        JavaTypeMapping m = (JavaTypeMapping)fieldMappingsMap.get(mmd);
        if (m != null)
        {
            return m;
        }

        return null;
    }

    /**
     * Accessor for the mapping for the specified field only in this datastore class.
     * @param mmd Metadata of the field/property
     * @return The Mapping for the field (or null if not present here)
     */
    public JavaTypeMapping getFieldMappingInDatastoreClass(AbstractMemberMetaData mmd)
    {
        return getFieldMapping(mmd);
    }

    /**
     * Accessor for the field mapping for the specified field.
     * TODO Use of this is discouraged since the fieldName is not fully qualified
     * and if a superclass-table inheritance is used we could have 2 fields of that name here.
     * @param fieldName Name of the field
     * @return The mapping for the field
     */
    public JavaTypeMapping getFieldMapping(String fieldName)
    {
        return getFieldMapping(primaryTable.getFieldMetaData(fieldName));
    }

    /**
     * Accessor for the ID mapping for this table.
     * @return The ID mapping
     */
    public JavaTypeMapping getIDMapping()
    {
        if (idMapping != null)
        {
            return idMapping;
        }

        PersistenceCapableMapping mapping = new PersistenceCapableMapping();
        mapping.initialize(getStoreManager().getDatastoreAdapter(),primaryTable.getClassMetaData().getFullClassName());
        if (getIdentityType() == IdentityType.DATASTORE)
        {
            mapping.addJavaTypeMapping(datastoreIDMapping);
        }
        else if (getIdentityType() == IdentityType.APPLICATION)
        {
            for (int i = 0; i < pkMappings.length; i++)
            {
                mapping.addJavaTypeMapping(pkMappings[i]);
            }
        }
        idMapping = mapping;
        return mapping;
    }

    /**
     * Provide the mappings to the consumer for all primary-key fields mapped to
     * this table (for application identity).
     * @param consumer Consumer for the mappings
     */
    public void providePrimaryKeyMappings(MappingConsumer consumer)
    {
        consumer.preConsumeMapping(highestFieldNumber + 1);

        ClassMetaData cmd = primaryTable.getClassMetaData();
        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(getFieldMapping(pkfmd), pkfmd);
            }
        }
    }

    public void provideExternalMappings(MappingConsumer consumer, int mappingType)
    {
    }

    /**
     * Method to provide all unmapped datastore fields (columns) to the consumer.
     * @param consumer Consumer of information
     */
    public void provideUnmappedDatastoreFields(MappingConsumer consumer)
    {
    }

    public JavaTypeMapping getExternalMapping(AbstractMemberMetaData fmd, int mappingType)
    {
        throw new JPOXException("N/A").setFatal();
    }

    public AbstractMemberMetaData getMetaDataForExternalMapping(JavaTypeMapping mapping, int mappingType)
    {
        throw new JPOXException("N/A").setFatal();
    }
}
TOP

Related Classes of org.jpox.store.rdbms.table.SecondaryTable

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.