org.eclipse.emf.teneo.PersistenceOptions.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.emf.teneo.PersistenceOptions.java

Source

/**
 * <copyright>
 *
 * Copyright (c) 2005, 2006, 2007, 2008 Springsite BV (The Netherlands) and others
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *   Martin Taal - Initial API and implementation
 *   Jason Henriksen - Mapping File Path
 *   Jason Henriksen - XSDDate and XSDDateTime constants
 * </copyright>
 *
 * $Id: PersistenceOptions.java,v 1.71 2011/10/29 06:12:48 mtaal Exp $
 */

package org.eclipse.emf.teneo;

import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Properties;
import java.util.regex.Pattern;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.eclipse.emf.teneo.annotations.pannotation.CascadeType;
import org.eclipse.emf.teneo.extension.ExtensionPoint;

/**
 * Defines the property names used in the persistence mapping.
 * <p>
 * As a convenience, this class offers type-safe property accessor wrappers.
 * 
 * @author <a href="mailto:mtaal@elver.org">Martin Taal</a>
 * @version $Revision: 1.71 $
 */
public class PersistenceOptions implements ExtensionPoint {

    public static final String DEFAULT_CLASSPATH_FILENAME = "/teneo-persistence.properties";

    public static final String RUNTIME_PREFIX = "teneo.runtime.";

    public static final String MAPPING_PREFIX = "teneo.mapping.";

    public static final String NAMING_PREFIX = "teneo.naming.";

    /** The logger */
    private static Log log = LogFactory.getLog(PersistenceOptions.class);

    // START: ++++++++++++++++++++++ SQL Naming related Options
    // ++++++++++++++++++++++++++++++++++++

    /**
     * DiscriminatorColumn name, default is DTYPE.
     */
    public static final String DISCRIMINATOR_COLUMN_NAME = NAMING_PREFIX + "discriminator_column_name";

    /**
     * Join table naming strategy, two values: ejb3 and unique
     * 
     * @Deprecated use the extensionManager concept
     */
    public static final String JOIN_TABLE_NAMING_STRATEGY = NAMING_PREFIX + "join_table_naming_strategy";

    /**
     * Deprecated use JOIN_TABLE_NAMING_STRATEGY
     * 
     * @Deprecated
     */
    public static final String JOIN_TABLE_NAMING_STRATEGY_OLD = MAPPING_PREFIX + "join_table_naming_strategy";

    /**
     * Join column naming strategy, two values: unique and simple. unique is the
     * default and results in guaranteed unique naming for the join columns
     * simple will always try to use minimal name lengths and will most of the
     * time just use the efeaturename.
     */
    public static final String JOIN_COLUMN_NAMING_STRATEGY = NAMING_PREFIX + "join_column_naming_strategy";

    /** The column name of the id column in the idbag, default is id */
    public static final String IDBAG_ID_COLUMN_NAME = NAMING_PREFIX + "idbag_id_column_name";

    /** Name of version column, default value is e_version */
    public static final String VERSION_COLUMN_NAME = NAMING_PREFIX + "version_column";

    /** Name of id column, default value is e_id */
    public static final String ID_COLUMN_NAME = NAMING_PREFIX + "default_id_column";

    /**
     * Truncate the column name if the length is larger than this property. In
     * case of concatenating property names for foreign keys
     */
    public static final String MAXIMUM_SQL_NAME_LENGTH = NAMING_PREFIX + "max_sql_name_length";

    /**
     * The option which determines the casing of columns and table names,
     * lowercase will result in lowercase letters, uppercase in uppercase, none
     * will just work as it did until now
     */
    public static final String SQL_CASE_STRATEGY = NAMING_PREFIX + "strategy";

    /**
     * If set then the system will generate readable foreign key names. The
     * default is true. Set to false for backward compatibility. Note that
     * before the default value of this property was false.
     */
    public static final String SET_FOREIGN_KEY_NAME = NAMING_PREFIX + "set_foreign_key_name";

    /**
     * The escape character to use when escaping table and column names.
     * Standard Hibernate uses the ` (backtick). This is the default value.
     */
    public static final String SQL_NAME_ESCAPE_CHARACTER = MAPPING_PREFIX + "sql_name_escape_character";

    /**
     * The sql name strategy, if not set then the ClassicSQLNameStrategy is
     * used.
     * 
     * @Deprecated use the extensionManager concept
     */
    public static final String SQL_NAME_STRATEGY = NAMING_PREFIX + "sql_name_strategy";

    /**
     * The Table name prefix, as a default set to "".
     */
    public static final String SQL_TABLE_NAME_PREFIX = NAMING_PREFIX + "sql_table_name_prefix";

    /**
     * The Column name prefix, as a default set to "".
     */
    public static final String SQL_COLUMN_NAME_PREFIX = NAMING_PREFIX + "sql_column_name_prefix";

    /**
     * The FK name prefix, as a default set to "".
     */
    public static final String SQL_FOREIGN_KEY_NAME_PREFIX = NAMING_PREFIX + "sql_fk_name_prefix";

    /**
     * The Index name prefix, as a default set to "".
     */
    public static final String SQL_INDEX_KEY_NAME_PREFIX = NAMING_PREFIX + "sql_index_name_prefix";

    /**
     * Controls if manually set sql names (table name, column names) should also
     * be truncated or cased. Default is true for backward compatability.
     */
    public static final String AUTO_ADAPT_MANUAL_SET_SQL_NAMES = NAMING_PREFIX + "auto_adapt_manual_set_sql_names";

    // END: ++++++++++++++++++++++ SQL Naming related Options
    // ++++++++++++++++++++++++++++++++++++

    /**
     * Controls if non-mutable eclasses should have a discriminator or version
     * column. Default is false.
     * 
     * @Deprecated use the extensionManager concept
     */
    public static final String SQL_DISCRIMINATOR_VERSION_IMMUTABLE_ECLASS = NAMING_PREFIX
            + "sql_discriminator_version_immutable_eclass";

    /**
     * Controls how the econtainer feature id is persisted. There are three
     * values: featureid or featurename
     * 
     * @Deprecated use the extensionManager concept
     */
    public static final String ECONTAINER_FEATURE_PERSISTENCE_STRATEGY = NAMING_PREFIX
            + "econtainer_feature_persistence_strategy";

    /**
     * see bugzilla 227673, option can be used to set the hibernate usertype
     * used for xsd date and xsd date time fields.
     */
    public static final String USER_XSDDATE_TYPE = MAPPING_PREFIX + "UserDateType";
    public static final String USER_XSDDATETIME_TYPE = MAPPING_PREFIX + "UserDateTimeType";
    public static final String USER_XSDTIME_TYPE = MAPPING_PREFIX + "UserTimeType";

    /**
     * This option can be used to control the actual xsd date class used, as a
     * default the javax.xml.datatype.XMLGregorianCalendar class is used.
     */
    public static final String XSDDATE_CLASS = MAPPING_PREFIX + "XSDDateClass";

    /**
     * The default length of a varchar column. Normally hibernate will choose to
     * set this to 255.
     */
    public static final String DEFAULT_VARCHAR_LENGTH = MAPPING_PREFIX + "default_varchar_length";

    /**
     * The maximum length of the comments which are copied from the model to the
     * mapping file. The default is zero which means no comments are copied from
     * the model to the mapping.
     */
    public static final String MAX_COMMENT_LENGTH = MAPPING_PREFIX + "max_comment_length";

    /**
     * EClass marked with Embeddable is always embedded, default is false. If
     * this is set to true then it is not required anymore to set a
     * 
     * @Embedded annotation on an ereference,
     * @Embeddable on the EClass is then sufficient.
     */
    public static final String MAP_EMBEDDABLE_AS_EMBEDDED = MAPPING_PREFIX + "map_embeddable_as_embedded";

    /** Optimistic locking */
    public static final String OPTIMISTIC = MAPPING_PREFIX + "optimistic_locking";

    /**
     * Add an index for each foreign key mapping. Some databases do not add an
     * index for a foreign key automatically. Setting this to true will
     * automatically add an index field to each foreign key.
     */
    public static final String ADD_INDEX_FOR_FOREIGN_KEY = MAPPING_PREFIX + "add_index_for_fk";

    /**
     * Set or not set the cascade attribute on a mto, mtm or otm non-containment
     * relation. The backward compatible value is true. The better performing
     * value is false. The default is false.
     * 
     * @Deprecated use CASCADE_POLICY_ON_NON_CONTAINMENT
     */
    public static final String SET_DEFAULT_CASCADE_ON_NON_CONTAINMENT = MAPPING_PREFIX
            + "set_default_cascade_on_non_containment";

    /** Inheritance mapping */
    public static final String INHERITANCE_MAPPING = MAPPING_PREFIX + "inheritance";

    /**
     * Can be set to force an update of the schema when the application starts.
     * Note this option is only meaningfull for jpox, for hibernate use the
     * hibernate property: hibernate.hbm2ddl_auto
     */
    public static final String UPDATE_SCHEMA = RUNTIME_PREFIX + "update_schema";

    /** Force all containment relations to be eagerly loaded or not */
    public static final String FETCH_CONTAINMENT_EAGERLY = MAPPING_PREFIX + "fetch_containment_eagerly";

    /**
     * Force all associations to be extra lazy loaded See here
     * http://sites.google
     * .com/a/pintailconsultingllc.com/java/hibernate-extra-lazy
     * -collection-fetching for some information.
     * 
     * Default is false.
     */
    public static final String FETCH_ASSOCIATION_EXTRA_LAZY = MAPPING_PREFIX + "fetch_one_to_many_extra_lazy";

    /**
     * Set cascade all (incl. orphan delete) on containment relation.
     * 
     * @Deprecated use CASCADE_POLICY_ON_CONTAINMENT
     */
    public static final String SET_CASCADE_ALL_ON_CONTAINMENT = MAPPING_PREFIX + "cascade_all_on_containment";

    /**
     * Can be used to set custom cascade policy for containment : <br>
     * <code>ALL</code> or a combination of (<code>REMOVE</code>,
     * <code>REFRESH</code>, <code>PERSIST</code>, <code>MERGE</code>) <br>
     * e.g. : REMOVE,PERSIST,MERGE <br>
     * Warning : ALL != REMOVE,REFRESH,PERSIST,MERGE <br>
     * but ALL == REMOVE with delete Orphan, REFRESH,PERSIST,MERGE
     */
    public static final String CASCADE_POLICY_ON_CONTAINMENT = MAPPING_PREFIX + "cascade_policy_on_containment";

    /**
     * Can be used to set custom cascade policy for non containment : <br>
     * a combination of (<code>REFRESH</code>,<code>PERSIST</code>,
     * <code>MERGE</code>) e.g. : PERSIST,MERGE
     */
    public static final String CASCADE_POLICY_ON_NON_CONTAINMENT = MAPPING_PREFIX
            + "cascade_policy_on_non_containment";

    /**
     * Can be used to control if the entity ann. should be added automatically
     * to the model elements or that the default annotator should work according
     * to the ejb3 spec.
     */
    public static final String SET_ENTITY_AUTOMATICALLY = MAPPING_PREFIX + "set_entity_automatically";

    /**
     * Map all lists as a bag to the db (does not map the list index to the db),
     * default is false
     */
    public static final String ALWAYS_MAP_LIST_AS_BAG = MAPPING_PREFIX + "always_map_list_as_bag";

    /**
     * Map all lists as a hibernate idbag to the db (does not map the list index
     * to the db), default is false
     */
    public static final String MAP_ALL_LISTS_AS_IDBAG = MAPPING_PREFIX + "map_all_lists_as_idbag";

    /** Use static hibernate mapping file */
    public static final String USE_MAPPING_FILE = MAPPING_PREFIX + "hibernate_mapping_file";

    /**
     * The complete resource path to the mapping file, can be used instead of
     * the USE_MAPPING_FILE option
     */
    public static final String MAPPING_FILE_PATH = MAPPING_PREFIX + "mapping_file_name";

    /**
     * Automatically add @Id to ID feature
     * 
     * @id annotation to ID xsd type
     */
    public static final String ID_FEATURE_AS_PRIMARY_KEY = NAMING_PREFIX + "id_feature_as_primary_key";

    /**
     * Automatically add
     * 
     * @GeneratedValue to ID feature for which
     * @Id is added automatically, default is true.
     */
    public static final String SET_GENERATED_VALUE_ON_ID_FEATURE = NAMING_PREFIX
            + "set_generated_value_on_id_feature";

    /**
     * The name of the id feature if no feature has an id.
     * 
     * @id annotation
     */
    public static final String DEFAULT_ID_FEATURE_NAME = NAMING_PREFIX + "default_id_feature";

    /**
     * The path of the persistence XML file.
     */
    public static final String PERSISTENCE_XML = MAPPING_PREFIX + "persistence_xml";

    /**
     * Ignore mapping EAnnotations. Primarily meant for test cases that use
     * Persistence XML mapping, so that they can reuse the same sample models.
     */
    public static final String IGNORE_EANNOTATIONS = MAPPING_PREFIX + "ignore_eannotations";

    /**
     * Map all emaps as true hibernate maps, default is true. In EMF an EMap is
     * in fact an EList with Map entries. Originally Teneo maps this as a
     * hibernate list. In the new behavior hibernate can map the emap as a real
     * map. The default is true.
     */
    public static final String EMAP_AS_TRUE_MAP = MAPPING_PREFIX + "emap_as_true_map";

    /**
     * This option controls if in case of hibernate also a name attribute should
     * be added to the class/subclass tag. By adding this a class is mapped as
     * an entity as well as a normal class. Also mapping as a normal class has
     * the advantage that proxies can be used and that queries can use actual
     * class names and interface names. This option is really there for backward
     * compatibility. There are no apparent dis-advantages of adding a name
     * attribute so the default of this option is true. Note that an eclass must
     * have an implementation class otherwise this option has no effect.
     * Interfaces are for example always mapped as an entity.
     */
    public static final String ALSO_MAP_AS_CLASS = MAPPING_PREFIX + "also_map_as_class";

    /**
     * This option controls if as a default all classes should be proxied (for
     * hibernate). This means that you don't need to add a
     * 
     * @Proxy annotation to each eclass. As a default Teneo will use the eclass
     *        interface as the proxy class. When this is set to true then the
     *        option ALSO_MAP_AS_CLASS should also be true.
     */
    public static final String SET_PROXY = MAPPING_PREFIX + "set_proxy";

    /**
     * This option forces lazy=true without the proxy attribute in the hibernate
     * mapping.
     */
    public static final String FORCE_LAZY = MAPPING_PREFIX + "force_lazy";

    /**
     * Disable EContainer mapping.
     */
    public static final String DISABLE_ECONTAINER_MAPPING = MAPPING_PREFIX + "disable_econtainer";

    /**
     * Option to specify that for non-contained one-to-many always a join table
     * is used, default is true
     */
    public static final String JOIN_TABLE_FOR_NON_CONTAINED_ASSOCIATIONS = MAPPING_PREFIX
            + "join_table_for_non_contained_associations";

    /**
     * Determines whether to always include a version mapping even if one is not
     * specified. Defaults to "true"
     */
    public static final String ALWAYS_VERSION = MAPPING_PREFIX + "always_version";

    /**
     * The default cache strategy, can be one of: NONE, READ_ONLY,
     * NONSTRICT_READ_ONLY, READ_WRITE, TRANSACTIONAl. If different than NONE
     * (=default) then for Hibernate every class will be second-level cached!
     */
    public static final String DEFAULT_CACHE_STRATEGY = MAPPING_PREFIX + "default_cache_strategy";

    /** The default time/date type used */
    public static final String DEFAULT_TEMPORAL_VALUE = MAPPING_PREFIX + "default_temporal";

    /**
     * If true then EAttributes which are not set are stored as null in the
     * database, if false then the default values is stored in the database.
     */
    public static final String HANDLE_UNSET_AS_NULL = RUNTIME_PREFIX + "handle_unset_as_null";

    /**
     * When an unset feature is persisted, the database will get a null value,
     * default is false.
     */
    public static final String CONVERT_UNSET_TO_NULL = RUNTIME_PREFIX + "convert_unset_to_null";

    /**
     * If set to true then the document root is also mapped.
     */
    public static final String MAP_DOCUMENT_ROOT = MAPPING_PREFIX + "map_document_root";

    /**
     * If set to true then the system will automatically add referenced
     * epackages
     */
    public static final String AUTO_ADD_REFERENCED_EPACKAGES = MAPPING_PREFIX + "auto_add_referenced_epackages";

    /**
     * If set to true then the system will map all eclasses as an EAV mapping.
     * See http://www.elver.org/hibernate/eav_mapping.html
     */
    public static final String EAV_MAPPING = MAPPING_PREFIX + "eav_mapping";

    /**
     * If set then the eav mapping file is read from the location defined by
     * this property.
     */
    public static final String EAV_MAPPING_FILE = MAPPING_PREFIX + "eav_location";

    /**
     * Map the FeatureMap as a component entity
     */
    public static final String FEATUREMAP_AS_COMPONENT = MAPPING_PREFIX + "featuremap_as_component";

    /**
     * Additional sources which are taken into account parsing model
     * annotations. The value can be a comma delimited list of source values.
     */
    public static final String EXTRA_ANNOTATION_SOURCES = MAPPING_PREFIX + "extra_annotation_sources";

    public final static String ECONTAINER_CLASS_COLUMN = "econtainer_class_column";
    public final static String ECONTAINER_COLUMN = "e_container_column";
    public final static String ECONTAINER_FEATURE_NAME_COLUMN = "e_container_feature_name_column";

    /** Returns the default properties used in the system */
    public static Properties getDefaultProperties() {
        final Properties props = new Properties();
        props.setProperty(HANDLE_UNSET_AS_NULL, "false");
        props.setProperty(CONVERT_UNSET_TO_NULL, "false");
        props.setProperty(JOIN_TABLE_FOR_NON_CONTAINED_ASSOCIATIONS, "true");
        props.setProperty(USE_MAPPING_FILE, "false");
        // props.setProperty(MAPPING_FILE_PATH, null); // null is the default
        // anyway
        props.setProperty(SET_CASCADE_ALL_ON_CONTAINMENT, "");
        props.setProperty(CASCADE_POLICY_ON_CONTAINMENT, "ALL");
        props.setProperty(OPTIMISTIC, "true");
        props.setProperty(UPDATE_SCHEMA, "false");
        props.setProperty(FETCH_CONTAINMENT_EAGERLY, "false");
        props.setProperty(FETCH_ASSOCIATION_EXTRA_LAZY, "false");
        props.setProperty(SET_ENTITY_AUTOMATICALLY, "true");
        props.setProperty(VERSION_COLUMN_NAME, "e_version");
        props.setProperty(SQL_CASE_STRATEGY, "lowercase");
        props.setProperty(ID_COLUMN_NAME, "e_id");
        props.setProperty(DISABLE_ECONTAINER_MAPPING, "false");
        props.setProperty(MAXIMUM_SQL_NAME_LENGTH, "-1");
        props.setProperty(IGNORE_EANNOTATIONS, "false");
        props.setProperty(ALWAYS_VERSION, "true");
        props.setProperty(DEFAULT_CACHE_STRATEGY, "NONE");
        props.setProperty(DISCRIMINATOR_COLUMN_NAME, "DTYPE");
        props.setProperty(JOIN_TABLE_NAMING_STRATEGY, "unique");
        // props.setProperty(JOIN_TABLE_NAMING_STRATEGY_OLD, "unique");
        props.setProperty(JOIN_COLUMN_NAMING_STRATEGY, "unique");
        props.setProperty(DEFAULT_TEMPORAL_VALUE, "TIMESTAMP");
        props.setProperty(DEFAULT_ID_FEATURE_NAME, "e_id");
        props.setProperty(ID_FEATURE_AS_PRIMARY_KEY, "true");
        props.setProperty(SET_GENERATED_VALUE_ON_ID_FEATURE, "true");
        props.setProperty(EMAP_AS_TRUE_MAP, "true");
        props.setProperty(ALWAYS_MAP_LIST_AS_BAG, "false");
        props.setProperty(ALSO_MAP_AS_CLASS, "true");
        props.setProperty(SET_PROXY, "false");
        props.setProperty(FORCE_LAZY, "false");
        props.setProperty(MAP_ALL_LISTS_AS_IDBAG, "false");
        props.setProperty(IDBAG_ID_COLUMN_NAME, "ID");
        props.setProperty(ADD_INDEX_FOR_FOREIGN_KEY, "false");
        props.setProperty(SET_DEFAULT_CASCADE_ON_NON_CONTAINMENT, "");
        props.setProperty(CASCADE_POLICY_ON_NON_CONTAINMENT, "");
        props.setProperty(SET_FOREIGN_KEY_NAME, "true");
        props.setProperty(MAP_EMBEDDABLE_AS_EMBEDDED, "false");
        props.setProperty(MAX_COMMENT_LENGTH, "0");
        props.setProperty(DEFAULT_VARCHAR_LENGTH, "-1");
        props.setProperty(SQL_NAME_ESCAPE_CHARACTER, "`");
        props.setProperty(USER_XSDDATE_TYPE, "org.eclipse.emf.teneo.hibernate.mapping.XSDDate");
        props.setProperty(USER_XSDDATETIME_TYPE, "org.eclipse.emf.teneo.hibernate.mapping.XSDDateTime");
        props.setProperty(USER_XSDTIME_TYPE, "org.eclipse.emf.teneo.hibernate.mapping.XSDDateTime");
        props.setProperty(XSDDATE_CLASS, "javax.xml.datatype.XMLGregorianCalendar");
        props.setProperty(SQL_DISCRIMINATOR_VERSION_IMMUTABLE_ECLASS, "true");
        props.setProperty(ECONTAINER_FEATURE_PERSISTENCE_STRATEGY, "FEATURENAME");
        props.setProperty(SQL_TABLE_NAME_PREFIX, "");
        props.setProperty(SQL_COLUMN_NAME_PREFIX, "");
        props.setProperty(SQL_FOREIGN_KEY_NAME_PREFIX, "");
        props.setProperty(SQL_INDEX_KEY_NAME_PREFIX, "");
        props.setProperty(MAP_DOCUMENT_ROOT, "false");
        props.setProperty(EAV_MAPPING, "false");
        props.setProperty(AUTO_ADD_REFERENCED_EPACKAGES, "false");
        props.setProperty(ECONTAINER_CLASS_COLUMN, Constants.COLUMN_ECONTAINER_CLASS);
        props.setProperty(ECONTAINER_COLUMN, Constants.COLUMN_ECONTAINER);
        props.setProperty(ECONTAINER_FEATURE_NAME_COLUMN, Constants.COLUMN_ECONTAINER_FEATURE_NAME);
        props.setProperty(FEATUREMAP_AS_COMPONENT, "false");
        props.setProperty(EXTRA_ANNOTATION_SOURCES, "");
        props.setProperty(AUTO_ADAPT_MANUAL_SET_SQL_NAMES, "true");

        return props;
    }

    /**
     * The wrapped Properties instance.
     */
    private final Properties properties;

    /**
     * @return value of {@link #DISCRIMINATOR_COLUMN_NAME}
     */
    public String getDiscriminatorColumnName() {
        return properties.getProperty(DISCRIMINATOR_COLUMN_NAME);
    }

    /**
     * @return value of {@link #EXTRA_ANNOTATION_SOURCES}
     */
    public String getExtraAnnotationSources() {
        return properties.getProperty(EXTRA_ANNOTATION_SOURCES);
    }

    /**
     * @return value of {@link #FEATUREMAP_AS_COMPONENT}
     */
    public boolean isMapFeatureMapAsComponent() {
        return Boolean.valueOf(properties.getProperty(FEATUREMAP_AS_COMPONENT)).booleanValue();
    }

    /**
     * @return value of {@link AUTO_ADAPT_MANUAL_SET_SQL_NAMES}
     */
    public boolean isAutoAdaptManualSQLNames() {
        return Boolean.valueOf(properties.getProperty(AUTO_ADAPT_MANUAL_SET_SQL_NAMES)).booleanValue();
    }

    /**
     * @return value of {@link #ECONTAINER_COLUMN}
     */
    public String getEContainerColumn() {
        return properties.getProperty(ECONTAINER_COLUMN);
    }

    /**
     * @return value of {@link #ECONTAINER_CLASS_COLUMN}
     */
    public String getEContainerClassColumn() {
        return properties.getProperty(ECONTAINER_CLASS_COLUMN);
    }

    /**
     * @return value of {@link #ECONTAINER_FEATURE_NAME_COLUMN}
     */
    public String getEContainerFeatureNameColumn() {
        return properties.getProperty(ECONTAINER_FEATURE_NAME_COLUMN);
    }

    /**
     * @return value of {@link #EAV_MAPPING}
     */
    public boolean isEAVMapping() {
        return Boolean.valueOf(properties.getProperty(EAV_MAPPING)).booleanValue();
    }

    /**
     * @return value of {@link #EAV_MAPPING_FILE}
     */
    public String getEAVMappingFile() {
        return properties.getProperty(EAV_MAPPING_FILE);
    }

    /**
     * @return value of {@link #AUTO_ADD_REFERENCED_EPACKAGES}
     */
    public boolean isAutoAddReferencedEPackages() {
        return Boolean.valueOf(properties.getProperty(AUTO_ADD_REFERENCED_EPACKAGES)).booleanValue();
    }

    /**
     * @return value of {@link #MAP_DOCUMENT_ROOT}
     */
    public boolean isMapDocumentRoot() {
        return Boolean.valueOf(properties.getProperty(MAP_DOCUMENT_ROOT)).booleanValue();
    }

    /**
     * @return value of the {@link #HANDLE_UNSET_AS_NULL} option
     */
    public boolean getHandleUnsetAsNull() {
        return Boolean.valueOf(properties.getProperty(HANDLE_UNSET_AS_NULL)).booleanValue();
    }

    /**
     * @return value of the {@link #CONVERT_UNSET_TO_NULL} option
     */
    public boolean getConvertUnsetToNull() {
        return Boolean.valueOf(properties.getProperty(CONVERT_UNSET_TO_NULL)).booleanValue();
    }

    /**
     * Construct a new instance using Properties.
     */
    public PersistenceOptions(Properties properties) {
        this.properties = getDefaultProperties();

        if (properties != null) {
            this.properties.putAll(properties);
        }

        logProperties();
    }

    /**
     * Constructs a new instance by loading properties from
     * "/elver-persistence.properties" at the root of the classpath.
     */
    public PersistenceOptions() {
        this.properties = getDefaultProperties();

        final Properties props = new Properties();
        InputStream in = null;
        try {
            in = this.getClass().getResourceAsStream(DEFAULT_CLASSPATH_FILENAME);
            if (in != null) {
                if (log.isDebugEnabled()) {
                    log.debug("Loading persistence options from classpath \"" + DEFAULT_CLASSPATH_FILENAME + "\".");
                }
                props.load(in);
            }
        } catch (IOException e) {
            throw new RuntimeException(
                    "Error loading \"" + DEFAULT_CLASSPATH_FILENAME + "\" from classpath:" + e.getMessage(), e);
        } finally {
            try {
                if (in != null) {
                    in.close();
                }
            } catch (IOException e) {
                // Ignore.
            }
        }
        this.properties.putAll(props);

        logProperties();
    }

    /** Dump the props */
    public void logProperties() {
        if (!log.isDebugEnabled()) {
            return;
        }
        log.debug("Properties of PersistenceOptions:");
        for (Object key : properties.keySet()) {
            log.debug(key + ": " + properties.get(key));
        }
    }

    public String getSQLTableNamePrefix() {
        return properties.getProperty(SQL_TABLE_NAME_PREFIX);
    }

    public String getSQLColumnNamePrefix() {
        return properties.getProperty(SQL_COLUMN_NAME_PREFIX);
    }

    public String getSQLForeignKeyNamePrefix() {
        return properties.getProperty(SQL_FOREIGN_KEY_NAME_PREFIX);
    }

    public String getSQLIndexNamePrefix() {
        return properties.getProperty(SQL_INDEX_KEY_NAME_PREFIX);
    }

    /** Return the default temporal value */
    public String getDefaultTemporalValue() {
        return properties.getProperty(DEFAULT_TEMPORAL_VALUE);
    }

    /** Return the IDBAG_ID_COLUMN_NAME */
    public String getIDBagIDColumnName() {
        return getSQLColumnNamePrefix() + properties.getProperty(IDBAG_ID_COLUMN_NAME);
    }

    /**
     * Returns the value of the EMAP_AS_TRUE_MAP option, default is false
     */
    public boolean isMapEMapAsTrueMap() {
        return Boolean.valueOf(properties.getProperty(EMAP_AS_TRUE_MAP)).booleanValue();
    }

    /**
     * Returns the value of the SET_DEFAULT_CASCADE_ON_MTO_MTM option, default
     * is false
     */
    public boolean isSetDefaultCascadeOnNonContainment() {
        String property = properties.getProperty(SET_DEFAULT_CASCADE_ON_NON_CONTAINMENT);
        if (!property.equals("")) {
            return Boolean.valueOf(property).booleanValue();
        }
        return !properties.getProperty(CASCADE_POLICY_ON_NON_CONTAINMENT).equals("");
    }

    public boolean isSetCascadePolicyForNonContainment() {
        return !properties.getProperty(CASCADE_POLICY_ON_NON_CONTAINMENT).equals("");
    }

    public String getCascadePolicyForContainment() {
        return properties.getProperty(CASCADE_POLICY_ON_CONTAINMENT);
    }

    public String getCascadePolicyForNonContainment() {
        return properties.getProperty(CASCADE_POLICY_ON_NON_CONTAINMENT);
    }

    /**
     * Returns true if the CASCADE_POLICY_ON_NON_CONTAINMENT property contains
     * the merge cascade type
     */
    public boolean isSetCascadeMergeOnNonContainment() {
        return isSetCascadeOnNonContainement(CascadeType.MERGE.getName());
    }

    /**
     * Returns true if the CASCADE_POLICY_ON_NON_CONTAINMENT property contains
     * the persist cascade type
     */
    public boolean isSetCascadePersistOnNonContainment() {
        return isSetCascadeOnNonContainement(CascadeType.PERSIST.getName());
    }

    /**
     * Returns true if the CASCADE_POLICY_ON_NON_CONTAINMENT property contains
     * the refresh cascade type
     */
    public boolean isSetCascadeRefreshOnNonContainment() {
        return isSetCascadeOnNonContainement(CascadeType.REFRESH.getName());
    }

    /**
     * Returns true if the CASCADE_POLICY_ON_NON_CONTAINMENT property contains
     * the given cascade type
     */
    private boolean isSetCascadeOnNonContainement(String cascadeType) {
        return isSetCascade(properties.getProperty(CASCADE_POLICY_ON_NON_CONTAINMENT), cascadeType);
    }

    /**
     * Returns the value of the SET_FOREIGN_KEY_NAME option, default is true
     */
    public boolean isSetForeignKeyNames() {
        return Boolean.valueOf(properties.getProperty(SET_FOREIGN_KEY_NAME)).booleanValue();
    }

    /**
     * Returns the value of the ALSO_MAP_AS_CLASS option, default is false
     */
    public boolean isAlsoMapAsClass() {
        return Boolean.valueOf(properties.getProperty(ALSO_MAP_AS_CLASS)).booleanValue();
    }

    /**
     * Returns the value of the MAP_EMBEDDABLE_AS_EMBEDDED option, default is
     * false
     */
    public boolean isMapEmbeddableAsEmbedded() {
        return Boolean.valueOf(properties.getProperty(MAP_EMBEDDABLE_AS_EMBEDDED)).booleanValue();
    }

    /**
     * Returns true if the proxy annotation should be added automatically
     */
    public boolean isSetProxy() {
        return Boolean.valueOf(properties.getProperty(SET_PROXY)).booleanValue();
    }

    /**
     * Returns true if the lazy attribute should be forced to true in the hbm
     * mapping.
     */
    public boolean isForceLazy() {
        return Boolean.valueOf(properties.getProperty(FORCE_LAZY)).booleanValue();
    }

    /**
     * Returns the value of the ALWAYS_MAP_LIST_AS_BAG option, default is false
     */
    public boolean alwaysMapListAsBag() {
        return Boolean.valueOf(properties.getProperty(ALWAYS_MAP_LIST_AS_BAG)).booleanValue();
    }

    /**
     * Returns the value of the MAP_ALL_LISTS_AS_IDBAG option, default is false
     */
    public boolean alwaysMapListAsIdBag() {
        return Boolean.valueOf(properties.getProperty(MAP_ALL_LISTS_AS_IDBAG)).booleanValue();
    }

    /** Returns the value of the ADD_INDEX_FOR_FOREIGN_KEY option */
    public boolean isAddIndexForForeignKey() {
        return Boolean.valueOf(properties.getProperty(ADD_INDEX_FOR_FOREIGN_KEY)).booleanValue();
    }

    /**
     * Returns the value of the UseJoinTableForNonContainedAssociations option,
     * default is false
     */
    public boolean isJoinTableForNonContainedAssociations() {
        return Boolean.valueOf(properties.getProperty(JOIN_TABLE_FOR_NON_CONTAINED_ASSOCIATIONS)).booleanValue();
    }

    /** Returns the value of the UseMappingFile option, default is false */
    public boolean isUseMappingFile() {
        return Boolean.valueOf(properties.getProperty(USE_MAPPING_FILE)).booleanValue();
    }

    /** Returns the value of the MAPPING_FILE_PATH option, default is "" */
    public String getMappingFilePath() {
        return properties.getProperty(MAPPING_FILE_PATH);
    }

    /** Returns the value of the id feature as primary key */
    public boolean isIDFeatureAsPrimaryKey() {
        return Boolean.valueOf(properties.getProperty(ID_FEATURE_AS_PRIMARY_KEY)).booleanValue();
    }

    /** Returns the value of the SET_GENERATED_VALUE_ON_ID_FEATURE option */
    public boolean isSetGeneratedValueOnIDFeature() {
        return Boolean.valueOf(properties.getProperty(SET_GENERATED_VALUE_ON_ID_FEATURE)).booleanValue();
    }

    /** Returns the value of the orphan delete on containment, default is true */
    public boolean isSetCascadeAllOnContainment() {
        if (!properties.getProperty(SET_CASCADE_ALL_ON_CONTAINMENT).equals("")) {
            return Boolean.valueOf(properties.getProperty(SET_CASCADE_ALL_ON_CONTAINMENT)).booleanValue();
        }
        return isSetCascadeOnContainement(CascadeType.ALL.getName());
    }

    /**
     * Returns true if CASCADE_POLICY_ON_CONTAINMENT property contains the MERGE
     * cascade type
     */
    public boolean isSetCascadeMergeOnContainment() {
        return isSetCascadeOnContainement(CascadeType.MERGE.getName());
    }

    /**
     * Returns true if CASCADE_POLICY_ON_CONTAINMENT property contains the
     * PERSIST cascade type
     */
    public boolean isSetCascadePersistOnContainment() {
        return isSetCascadeOnContainement(CascadeType.PERSIST.getName());
    }

    /**
     * Returns true if CASCADE_POLICY_ON_CONTAINMENT property contains the
     * REMOVE cascade type
     */
    public boolean isSetCascadeRemoveOnContainment() {
        return isSetCascadeOnContainement(CascadeType.REMOVE.getName());
    }

    /**
     * Returns true if CASCADE_POLICY_ON_CONTAINMENT property contains the
     * REFRESH cascade type
     */
    public boolean isSetCascadeRefreshOnContainment() {
        return isSetCascadeOnContainement(CascadeType.REFRESH.getName());
    }

    /**
     * Returns true if CASCADE_POLICY_ON_CONTAINMENT property contains the given
     * cascade type
     */
    private boolean isSetCascadeOnContainement(String cascadeType) {
        return isSetCascade(properties.getProperty(CASCADE_POLICY_ON_CONTAINMENT), cascadeType);
    }

    /** Returns true if property contains the given cascade type */
    private boolean isSetCascade(String property, String cascadeType) {
        return Pattern.matches(".*\\b" + cascadeType.toUpperCase() + "\\b.*", property.toUpperCase());
    }

    /** Returns the value of the Optimistic option, default is true */
    public boolean isUseOptimisticLocking() {
        return Boolean.valueOf(properties.getProperty(OPTIMISTIC)).booleanValue();
    }

    /** Returns the value of the UpdateSchema option, default is true */
    public boolean isUpdateSchema() {
        return Boolean.valueOf(properties.getProperty(UPDATE_SCHEMA)).booleanValue();
    }

    /** Returns the value of the fetch containment eagerly, default is false */
    public boolean isFetchContainmentEagerly() {
        return Boolean.valueOf(properties.getProperty(FETCH_CONTAINMENT_EAGERLY)).booleanValue();
    }

    /** Returns the value of the fetch extra lazy option, default is false */
    public boolean isFetchAssociationExtraLazy() {
        return Boolean.valueOf(properties.getProperty(FETCH_ASSOCIATION_EXTRA_LAZY)).booleanValue();
    }

    /** Is set entity automatically, default is true */
    public boolean isSetEntityAutomatically() {
        return Boolean.valueOf(properties.getProperty(SET_ENTITY_AUTOMATICALLY)).booleanValue();
    }

    /** Returns the inheritance mapping strategy, can be null */
    public String getInheritanceMapping() {
        return properties.getProperty(INHERITANCE_MAPPING);
    }

    /** Returns the value of the version column option, returns null if not set */
    public String getVersionColumnName() {
        return getSQLColumnNamePrefix() + properties.getProperty(VERSION_COLUMN_NAME);
    }

    /** Returns the value of the naming strategy, default is lower case */
    public String getSQLCaseStrategy() {
        return properties.getProperty(SQL_CASE_STRATEGY);
    }

    /** Returns the value of the id column option, returns null if not set */
    public String getIdColumnName() {
        return getSQLColumnNamePrefix() + properties.getProperty(ID_COLUMN_NAME);
    }

    /** Returns the value of the default id property */
    public String getDefaultIDFeatureName() {
        return properties.getProperty(DEFAULT_ID_FEATURE_NAME);
    }

    /** Return the sql escape character, default is ` */
    public String getSqlNameEscapeCharacter() {
        return properties.getProperty(SQL_NAME_ESCAPE_CHARACTER);
    }

    /** Returns the value of the join table naming strategy */
    public String getJoinTableNamingStrategy() {
        if (properties.get(JOIN_TABLE_NAMING_STRATEGY_OLD) != null) {
            log.warn("The option " + JOIN_TABLE_NAMING_STRATEGY_OLD + " is deprecated, please use: "
                    + JOIN_TABLE_NAMING_STRATEGY);
            return properties.getProperty(JOIN_TABLE_NAMING_STRATEGY);
        }
        return properties.getProperty(JOIN_TABLE_NAMING_STRATEGY);
    }

    /** Returns the value of the join column naming strategy */
    public String getJoinColumnNamingStrategy() {
        return properties.getProperty(JOIN_COLUMN_NAMING_STRATEGY);
    }

    /**
     * Returns the default second level caching strategy, default value is NONE
     * (no second level caching).
     */
    public String getDefaultCacheStrategy() {
        return properties.getProperty(DEFAULT_CACHE_STRATEGY);
    }

    /** Return the default varchar length */
    public int getDefaultVarCharLength() {
        return Integer.parseInt(properties.getProperty(DEFAULT_VARCHAR_LENGTH));
    }

    /** Are econtainer mappings (hibernate) disabled */
    public boolean isDisableEContainerMapping() {
        return Boolean.valueOf(properties.getProperty(DISABLE_ECONTAINER_MAPPING)).booleanValue();
    }

    /** Return the value of the MAX_COMMENT_LENGTH */
    public int getMaximumCommentLength() {
        final String colLength = properties.getProperty(MAX_COMMENT_LENGTH);
        try {
            final int maxLength = Integer.parseInt(colLength);
            return maxLength;
        } catch (NumberFormatException e) {
            log.error("Property " + MAXIMUM_SQL_NAME_LENGTH + " as a non-integer value: " + colLength
                    + " value is ignored");
            return 0;
        }
    }

    /** Return the max. sql name length, or -1 if not set or illegal */
    public int getMaximumSqlNameLength() {
        final String colLength = properties.getProperty(MAXIMUM_SQL_NAME_LENGTH);
        try {
            final int maxLength = Integer.parseInt(colLength);
            if (maxLength == 0) {
                throw new TeneoException("The option MAXIMUM_SQL_NAME_LENGTH has a value of zero. "
                        + "This will result in empty column and table names in the mapping! "
                        + "Please change this option to a more usable value.");
            }
            if (maxLength < 4 && maxLength > -1) {
                log.warn("The option MAXIMUM_SQL_NAME_LENGTH has a low value: " + maxLength
                        + ". Are you sure this is correct?");
            }
            return maxLength;
        } catch (NumberFormatException e) {
            log.error("Property " + MAXIMUM_SQL_NAME_LENGTH + " as a non-integer value: " + colLength
                    + " value is ignored");
            return -1;
        }
    }

    /**
     * Returns the value of the SQL_DISCRIMINATOR_VERSION_IMMUTABLE_ECLASS
     * option.
     */
    public Boolean isDiscriminatorVersionOnImmutableEClass() {
        return Boolean.valueOf(properties.getProperty(SQL_DISCRIMINATOR_VERSION_IMMUTABLE_ECLASS)).booleanValue();
    }

    /**
     * Returns the path of the XML persistence mapping file or null if the
     * property has not been defined.
     */
    public String getPersistenceXmlPath() {
        return properties.getProperty(PERSISTENCE_XML);
    }

    /**
     * Returns a boolean indication whether to ignore mapping EAnnotations.
     */
    public boolean isIgnoreEAnnotations() {
        return Boolean.valueOf(properties.getProperty(IGNORE_EANNOTATIONS)).booleanValue();
    }

    /**
     * Returns an array of all String constants.
     * 
     * @return
     */
    public static String[] propertyNames() {
        final List<String> names = new ArrayList<String>();
        for (Field field : PersistenceOptions.class.getFields()) {
            try {
                if ((field.getModifiers() & Modifier.STATIC) > 0 & field.getType().equals(String.class)) {
                    final String value = (String) field.get(null);
                    if (value.startsWith("teneo.")) {
                        names.add(value);
                    }
                }
            } catch (IllegalAccessException e) {
            }
        }
        Collections.sort(names);
        return names.toArray(new String[names.size()]);
    }

    public boolean getAlwaysVersion() {
        return Boolean.valueOf(properties.getProperty(ALWAYS_VERSION)).booleanValue();
    }

    /**
     * @return the properties
     */
    public Properties getProperties() {
        return properties;
    }

    /**
     * Creates the correct sql name strategy based on the String setting.
     * 
     * @Deprecated use the SQLNameStrategy and extensionManager concept
     */
    public String getSQLNameStrategy() {
        return properties.getProperty(SQL_NAME_STRATEGY);
    }

    public String getUserXSDDateType() {
        return properties.getProperty(USER_XSDDATE_TYPE);
    }

    public String getUserXSDTime() {
        return properties.getProperty(USER_XSDTIME_TYPE);
    }

    public String getUserXSDDateTime() {
        return properties.getProperty(USER_XSDDATETIME_TYPE);
    }

    public String getXSDDateClass() {
        return properties.getProperty(XSDDATE_CLASS);
    }

    public EContainerFeaturePersistenceStrategy getEContainerFeaturePersistenceStrategy() {
        String strategy = properties.getProperty(ECONTAINER_FEATURE_PERSISTENCE_STRATEGY);
        if (strategy == null) {
            throw new TeneoException(
                    "Option ECONTAINER_FEATURE_PERSISTENCE_STRATEGY not set, please set it to one of: featureid, featurename, both");
        }
        EContainerFeaturePersistenceStrategy result = EContainerFeaturePersistenceStrategy
                .valueOf(strategy.toUpperCase());
        if (result == null) {
            throw new TeneoException("Option ECONTAINER_FEATURE_PERSISTENCE_STRATEGY not set correctly (" + strategy
                    + "), please set it to one of: featureid, featurename, both");
        }
        return result;
    }

    public enum EContainerFeaturePersistenceStrategy {
        FEATURENAME, FEATUREID, BOTH
    }
}