JPOX
JPOX
 Project  |  Ver 1.1  |  Ver 1.2  |  JDO  |  JPA  |  Guides  |  Tools
1.2 | Persistence | JDO ORM | JPA ORM | Runtime | JDO Runtime | JPA Runtime | Extensions | Developer
Extensions
Plugins : Identifier Factories

JPOX is developed as a plugin-driven framework and one of the components that is pluggable is the naming of datastore identifiers. JPOX provides its own internal identifier factories, but also allows you to plugin your own factory. This is available in JPOX from version 1.1.2

JPOX provides the mechanism to generate datastore identifiers (table/column names) when none are defined by the users metadata/annotations. In addition to the default JDO factory there is also an identifier factory that generates identifiers consistent with the JPA1 specification. You can extend JPOX's capabilities using the plugin extension org.jpox.store_identifierfactory.

Plugin extension-pointKeyDescriptionLocation
org.jpox.store_identifierfactoryjpoxIdentifier Factory providing JPOX 1.1 default namingsjpox-rdbms
org.jpox.store_identifierfactoryjpox2Identifier Factory providing new JPOX namingsjpox-rdbms
org.jpox.store_identifierfactoryjpaIdentifier Factory providing JPA-compliant namingsjpox-rdbms


Interface

Any identifier factory plugin will need to implement org.jpox.store.IdentifierFactory. So you need to implement the following interface

package org.jpox.store;

public interface IdentifierFactory
{
    /** Representation of an identifier specified in UPPER CASE */
    public static final int IDENTIFIER_UPPER_CASE = 0;

    /** Representation of an identifier specified in "UPPER CASE" */
    public static final int IDENTIFIER_UPPER_CASE_QUOTED = 1;

    /** Representation of an identifier specified in lower case. */
    public static final int IDENTIFIER_LOWER_CASE = 2;

    /** Representation of an identifier specified in "lower case" */
    public static final int IDENTIFIER_LOWER_CASE_QUOTED = 3;

    /** Representation of an identifier specified in Mixed Case. */
    public static final int IDENTIFIER_MIXED_CASE = 4;

    /** Representation of an identifier specified in "Mixed Case". */
    public static final int IDENTIFIER_MIXED_CASE_QUOTED = 5;

    /** identifier for table names **/
    public final static int TABLE = 0;

    /** column **/
    public final static int COLUMN = 1;

    /** foreign key **/
    public final static int FOREIGN_KEY = 2;

    /** index **/
    public final static int INDEX = 3;

    /** candidate key - unique index constraint **/
    public final static int CANDIDATE_KEY = 4;

    /** primary key **/
    public final static int PRIMARY_KEY = 5;

    /** identifier for datastore sequence. */
    public final static int SEQUENCE = 6;

    /**
     * Accessor for the datastore adapter that we are creating identifiers for.
     * @return The datastore adapter
     */
    DatastoreAdapter getDatastoreAdapter();

    /**
     * Accessor for the identifier case being used.
     * @return The identifier case
     */
    int getIdentifierCase();

    /**
     * Convenience method to return the name for the identifier case.
     * @return Identifier case name
     */
    String getNameOfIdentifierCase();

    /**
     * Accessor for an identifier for use in the datastore adapter
     * @param identifier The identifier name
     * @return Identifier name for use with the datastore adapter
     */
    String getIdentifierInAdapterCase(String identifier);

    /**
     * To be called when we want an identifier name creating based on the
     * identifier. Creates identifier for COLUMN, FOREIGN KEY, INDEX and TABLE
     * @param identifierType the type of identifier to be created
     * @param sqlIdentifier The SQL identifier name
     * @return The DatastoreIdentifier
     */
    DatastoreIdentifier newIdentifier(int identifierType, String sqlIdentifier);

    /**
     * Method to use to generate an identifier for a datastore field with the supplied name.
     * The passed name will not be changed (other than in its case) although it may
     * be truncated to fit the maximum length permitted for a datastore field identifier.
     * @param identifierName The identifier name
     * @return The DatastoreIdentifier for the table
     */
    DatastoreIdentifier newDatastoreContainerIdentifier(String identifierName);

    /**
     * Method to return a Table identifier for the specified class.
     * @param clr the ClassLoaderResolver
     * @param md Meta data for the class
     * @return The identifier for the table
     **/
    DatastoreIdentifier newDatastoreContainerIdentifier(ClassLoaderResolver clr, AbstractClassMetaData md);

    /**
     * Method to return a Table identifier for the specified field.
     * @param clr the ClassLoaderResolver
     * @param fmd Meta data for the field
     * @return The identifier for the table
     **/
    DatastoreIdentifier newDatastoreContainerIdentifier(ClassLoaderResolver clr, AbstractMemberMetaData fmd);

    /**
     * Method to use to generate an identifier for a datastore field with the supplied name.
     * The passed name will not be changed (other than in its case) although it may
     * be truncated to fit the maximum length permitted for a datastore field identifier.
     * @param identifierName The identifier name
     * @return The DatastoreIdentifier
     */
    DatastoreIdentifier newDatastoreFieldIdentifier(String identifierName);

    /**
     * Method to create an identifier for a datastore field where we want the
     * name based on the supplied java name, and the field has a particular
     * role (and so could have its naming set according to the role).
     * @param javaName The java field name
     * @param embedded Whether the identifier is for a field embedded
     * @param fieldRole The role to be performed by this column e.g FK, Index ?
     * @return The DatastoreIdentifier
     */
    DatastoreIdentifier newDatastoreFieldIdentifier(String javaName, boolean embedded, int fieldRole);

    /**
     * Method to generate an identifier name for reference field, based on the metadata for the
     * field, and the ClassMetaData for the implementation.
     * @param refMetaData the AbstractMemberMetaData for the reference field
     * @param implMetaData the AbstractClassMetaData for this implementation
     * @param implIdentifier PK identifier for the implementation
     * @param embedded Whether the identifier is for a field embedded
     * @param fieldRole The role to be performed by this column e.g FK, collection element ?
     * @return The DatastoreIdentifier
     */
    DatastoreIdentifier newReferenceFieldIdentifier(AbstractMemberMetaData refMetaData, 
            AbstractClassMetaData implMetaData, DatastoreIdentifier implIdentifier, 
            boolean embedded, int fieldRole);

    /**
     * Method to return an identifier for a discriminator datastore field.
     * @return The discriminator datastore field identifier
     */
    DatastoreIdentifier newDiscriminatorFieldIdentifier();

    /**
     * Method to return an identifier for a version datastore field.
     * @return The version datastore field identifier
     */
    DatastoreIdentifier newVersionFieldIdentifier();

    /**
     * Method to return a new Identifier based on the passed identifier, but adding on the passed suffix
     * @param identifier The current identifier
     * @param suffix The suffix
     * @return The new identifier
     */
    DatastoreIdentifier newIdentifier(DatastoreIdentifier identifier, String suffix);
}

In addition, if your IdentifierFactory is to be used for RDBMS datastores, then you need to implement org.jpox.store.rdbms.sqlidentifier.RDBMSIdentifierFactory

package org.jpox.store.rdbms.sqlidentifier;

public interface RDBMSIdentifierFactory extends IdentifierFactory
{
    /**
     * Method to generate a join-table identifier. The identifier could be for a foreign-key
     * to another table (if the destinationId is provided), or could be for a simple column
     * in the join table.
     * @param ownerFmd MetaData for the owner field
     * @param relatedFmd MetaData for the related field (if bidirectional)
     * @param destinationId Identifier for the identity field of the destination table
     * @param embedded Whether the identifier is for a field embedded
     * @param fieldRole The role to be performed by this column e.g FK, collection element ?
     * @return The identifier.
     */
    DatastoreIdentifier newJoinTableFieldIdentifier(AbstractMemberMetaData ownerFmd, 
            AbstractMemberMetaData relatedFmd,
            DatastoreIdentifier destinationId, boolean embedded, int fieldRole);

    /**
     * Method to generate a FK/FK-index field identifier. 
     * The identifier could be for the FK field itself, or for a related index for the FK.
     * @param ownerFmd MetaData for the owner field
     * @param relatedFmd MetaData for the related field (if bidirectional)
     * @param destinationId Identifier for the identity field of the destination table (if strict FK)
     * @param embedded Whether the identifier is for a field embedded
     * @param fieldRole The role to be performed by this column e.g owner, index ?
     * @return The identifier
     */
    DatastoreIdentifier newForeignKeyFieldIdentifier(AbstractMemberMetaData ownerFmd, 
            AbstractMemberMetaData relatedFmd,
            DatastoreIdentifier destinationId, boolean embedded, int fieldRole);

    /**
     * Method to return an identifier for an index datastore field.
     * @return The index datastore field identifier
     */
    DatastoreIdentifier newIndexFieldIdentifier();

    /**
     * Method to return an identifier for an adapter index datastore field.
     * An "adapter index" is a column added to be part of a primary key when some other
     * column cant perform that role.
     * @return The index datastore field identifier
     */
    DatastoreIdentifier newAdapterIndexFieldIdentifier();

    /**
     * Method to generate an identifier for a sequence using the passed name.
     * @param sequenceName the name of the sequence to use
     * @return The DatastoreIdentifier
     */
    DatastoreIdentifier newSequenceIdentifier(String sequenceName);

    /**
     * Method to generate an identifier for a primary key.
     * @param table the table
     * @return The DatastoreIdentifier
     */
    DatastoreIdentifier newPrimaryKeyIdentifier(DatastoreContainerObject table);

    /**
     * Method to generate an identifier for an index.
     * @param table the table
     * @param isUnique if the index is unique
     * @param seq the sequential number
     * @return The DatastoreIdentifier
     */
    DatastoreIdentifier newIndexIdentifier(DatastoreContainerObject table, boolean isUnique, int seq);

    /**
     * Method to generate an identifier for a candidate key.
     * @param table the table
     * @param seq Sequence number
     * @return The DatastoreIdentifier
     */
    DatastoreIdentifier newCandidateKeyIdentifier(DatastoreContainerObject table, int seq);

    /**
     * Method to create an identifier for a foreign key.
     * @param table the table
     * @param seq the sequential number
     * @return The DatastoreIdentifier
     */
    DatastoreIdentifier newForeignKeyIdentifier(DatastoreContainerObject table, int seq);
}

Be aware that you can extend org.jpox.store.rdbms.sqlidentifier.AbstractRDBMSIdentifierFactory.



Implementation

Let's assume that you want to provide your own identifier factory MyIdentifierFactory.

package mydomain;

import org.jpox.store.rdbms.sqlidentifier.AbstractRDBMSIdentifierFactory

public class MyIdentifierFactory extends AbstractRDBMSIdentifierFactory
{
    /**
     * Constructor.
     * @param dba Datastore adapter
     * @param defaultCatalog Name of the default catalog (if any)
     * @param defaultSchema Name of the default schema (if any)
     * @param requiredCase The case the user requires
     * @param wordSeparator Word separator for identifiers
     * @param tablePrefix Prefix for table names when being generated
     * @param tableSuffix Suffix for table names when being generated
     */
    public MyIdentifierFactory(DatastoreAdapter dba, String defaultCatalog, String defaultSchema, 
            String requiredCase, String wordSeparator, String tablePrefix, String tableSuffix)
    {
        super(dba, requiredCase, defaultCatalog, defaultSchema);
        ...
    }

    .. (implement the rest of the interface)
}
Plugin Specification

When we have defined our "IdentifierFactory" we just need to make it into a JPOX plugin. To do this you simply add a file plugin.xml to your JAR at the root. The file plugin.xml should look like this

<?xml version="1.0"?>
<plugin id="mydomain" name="JPOX plug-ins" provider-name="My Company">
    <extension point="org.jpox.store_identifierfactory">
        <identifierfactory name="myfactory" class-name="mydomain.MyIdentifierFactory"/>
    </extension>
</plugin>
Plugin Usage

The only thing remaining is to use your new IdentifierFactory plugin. You do this by having your plugin in the CLASSPATH at runtime, and setting the PMF property org.jpox.identifierFactory to myfactory (the name you specified in the plugin.xml file).