blob: 1d7eef7ddb8933de05fab7d7f1d6e505114a8dca [file] [log] [blame]
/**
* <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
* </copyright> $Id: EntityMapper.java,v 1.55 2011/10/29 06:13:50 mtaal Exp $
*/
package org.eclipse.emf.teneo.hibernate.mapper;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.teneo.Constants;
import org.eclipse.emf.teneo.annotations.pamodel.PAnnotatedEClass;
import org.eclipse.emf.teneo.annotations.pamodel.PAnnotatedEReference;
import org.eclipse.emf.teneo.annotations.pamodel.PAnnotatedEStructuralFeature;
import org.eclipse.emf.teneo.annotations.pannotation.Column;
import org.eclipse.emf.teneo.annotations.pannotation.DiscriminatorColumn;
import org.eclipse.emf.teneo.annotations.pannotation.DiscriminatorType;
import org.eclipse.emf.teneo.annotations.pannotation.DiscriminatorValue;
import org.eclipse.emf.teneo.annotations.pannotation.InheritanceType;
import org.eclipse.emf.teneo.annotations.pannotation.PannotationFactory;
import org.eclipse.emf.teneo.annotations.pannotation.PrimaryKeyJoinColumn;
import org.eclipse.emf.teneo.annotations.pannotation.SecondaryTable;
import org.eclipse.emf.teneo.annotations.pannotation.Table;
import org.eclipse.emf.teneo.extension.ExtensionPoint;
import org.eclipse.emf.teneo.hibernate.hbannotation.DiscriminatorFormula;
import org.eclipse.emf.teneo.hibernate.hbannotation.HbEntity;
import org.eclipse.emf.teneo.hibernate.hbannotation.OptimisticLockType;
import org.eclipse.emf.teneo.hibernate.hbmodel.HbAnnotatedEClass;
import org.eclipse.emf.teneo.simpledom.DocumentHelper;
import org.eclipse.emf.teneo.simpledom.Element;
/**
* Maps the entity and its features, also takes care of embedded superclass mapping.
*
* @author <a href="mailto:mtaal at elver.org">Martin Taal</a>
*/
public class EntityMapper extends AbstractMapper implements ExtensionPoint {
/** Log it all */
private static final Log log = LogFactory.getLog(EntityMapper.class);
/** Convenience maps to inheritance strategy names and discriminator types */
private static final String[] INHERITANCE_STRATEGY_NAMES;
private static final String[] DISCRIMINATOR_TYPE_NAMES;
/** Initialize the global arrays */
static {
INHERITANCE_STRATEGY_NAMES = new String[InheritanceType.VALUES.size()];
INHERITANCE_STRATEGY_NAMES[InheritanceType.JOINED.getValue()] = "joined-subclass";
INHERITANCE_STRATEGY_NAMES[InheritanceType.SINGLE_TABLE.getValue()] = "subclass";
INHERITANCE_STRATEGY_NAMES[InheritanceType.TABLE_PER_CLASS.getValue()] = "union-subclass";
DISCRIMINATOR_TYPE_NAMES = new String[DiscriminatorType.VALUES.size()];
DISCRIMINATOR_TYPE_NAMES[DiscriminatorType.CHAR.getValue()] = "character";
DISCRIMINATOR_TYPE_NAMES[DiscriminatorType.INTEGER.getValue()] = "integer";
DISCRIMINATOR_TYPE_NAMES[DiscriminatorType.STRING.getValue()] = "string";
}
// Key used for grouping properties to the primary and secondary tables.
private final String PRIMARY_TABLE_KEY = null;
/**
* @return Return the name used by hibernate to denote the given inheritance type. If the argument
* is null, the default inheritance type (SINGLE_TABLE) is used instead.
*/
private static String hbInheritanceName(InheritanceType inheritanceType) {
return EntityMapper.INHERITANCE_STRATEGY_NAMES[inheritanceType != null ? inheritanceType
.getValue() : InheritanceType.SINGLE_TABLE.getValue()];
}
/**
* @return Return the name used by hibernate for the given dicriminator type
*/
private static String hbDiscriminatorType(DiscriminatorType dType) {
return EntityMapper.DISCRIMINATOR_TYPE_NAMES[dType == null ? DiscriminatorType.STRING
.getValue() : dType.getValue()];
}
/**
* @return Returns a new hibernate element for the given entity.
*/
protected Element createEntity(PAnnotatedEClass entity, InheritanceType inhStrategy,
PAnnotatedEClass superEntity, DiscriminatorValue dValue, Table table) {
// determine what type of hibernate tag should be used
final InheritanceType inheritanceStrategy = inhStrategy != null ? inhStrategy
: InheritanceType.SINGLE_TABLE;
final EClass eclass = entity.getModelEClass();
final String hbClassName;
if (entity.getEavMapping() != null) {
hbClassName = EntityMapper.hbInheritanceName(InheritanceType.SINGLE_TABLE);
} else if (superEntity == null) {
hbClassName = "class";
} else {
hbClassName = EntityMapper.hbInheritanceName(inheritanceStrategy);
}
log.debug("Creating entity tag " + hbClassName);
final Element target;
final String entityName = getHbmContext().getEntityName(eclass);
final String isAbstractStr = eclass.isAbstract() ? "true" : "false";
final boolean doProxy = ((HbAnnotatedEClass) entity).getHbProxy() != null
&& ((HbAnnotatedEClass) entity).getHbProxy().isLazy();
if (entity.isOnlyMapAsEntity()) {
target = getHbmContext().getCurrent().addElement(hbClassName)
.addAttribute("entity-name", entityName).addAttribute("abstract", isAbstractStr)
.addAttribute("lazy", "false");
// note for composite ids the name must be set always!
// entity.getAnnotatedEClass().getInstanceClass() != null) { //
// ||
// entity.getAnnotatedEClass().getInstanceClass() != null ||
if (hasCompositeID(entity)) { // only for this specific case
// it is
// required to have the impl.name
target.addAttribute("name", hbmContext.getInstanceClassName(entity.getModelEClass()));
}
} else if (getHbmContext().forceUseOfInstance(entity)) {
final Element importElement = new Element("import");
importElement.addAttribute("class", hbmContext.getInstanceClassName(entity.getModelEClass()))
.addAttribute("rename", entityName);
getHbmContext().getCurrent().add(getImportIndex(), importElement);
target = getHbmContext().getCurrent().addElement(hbClassName)
.addAttribute("name", hbmContext.getInstanceClassName(entity.getModelEClass()))
.addAttribute("abstract", isAbstractStr).addAttribute("lazy", doProxy ? "true" : "false");
} else {
// don't specify the name as it is a dynamic eobject
if (getHbmContext().getInstanceClass(entity.getModelEClass()) == null) {
target = getHbmContext().getCurrent().addElement(hbClassName)
.addAttribute("entity-name", entityName).addAttribute("abstract", isAbstractStr)
.addAttribute("lazy", doProxy ? "true" : "false");
} else {
target = getHbmContext().getCurrent().addElement(hbClassName)
.addAttribute("name", hbmContext.getInstanceClassName(entity.getModelEClass()))
.addAttribute("entity-name", entityName).addAttribute("abstract", isAbstractStr)
.addAttribute("lazy", doProxy ? "true" : "false");
}
}
final HbAnnotatedEClass hbEntity = (HbAnnotatedEClass) entity;
// TODO: the immutable on the eclass should be removed as it is now
// covered through the HbEntity
if (superEntity == null && hbEntity.getImmutable() != null) {
target.addAttribute("mutable", "false");
}
if (hbEntity.getBatchSize() != null) {
target.addAttribute("batch-size", "" + hbEntity.getBatchSize().getSize());
}
if (hbEntity.getHbEntity() != null) {
final HbEntity hbEntityAnnon = hbEntity.getHbEntity();
if (superEntity == null) {
if (!hbEntityAnnon.isMutable() && target.getAttributeValue("mutable") == null) {
target.addAttribute("mutable", "false");
}
if (hbEntityAnnon.getPolymorphism() != null) {
target.addAttribute("polymorphism", hbEntityAnnon.getPolymorphism().getName()
.toLowerCase());
}
if (hbEntityAnnon.getOptimisticLock() != null) {
target.addAttribute("optimistic-lock", hbEntityAnnon.getOptimisticLock().getName()
.toLowerCase());
}
}
if (hbEntityAnnon.isDynamicInsert()) {
target.addAttribute("dynamic-insert", "true");
}
if (hbEntityAnnon.isDynamicUpdate()) {
target.addAttribute("dynamic-update", "true");
}
if (hbEntityAnnon.isSelectBeforeUpdate()) {
target.addAttribute("select-before-update", "true");
}
if (hbEntityAnnon.getPersister() != null) {
target.addAttribute("persister", hbEntityAnnon.getPersister());
}
}
if (superEntity != null) {
final String extendsEntity;
if (superEntity.isOnlyMapAsEntity() || !getHbmContext().forceUseOfInstance(superEntity)) {
extendsEntity = getHbmContext().getEntityName(superEntity.getModelEClass());
} else {
extendsEntity = getHbmContext().getInstanceClassName(superEntity.getModelEClass());
}
target.addAttribute("extends", extendsEntity);
log.debug("Extends " + extendsEntity);
}
if (entity.getEavMapping() != null) {
if (superEntity == null) {
target.addAttribute("extends", Constants.EAV_EOBJECT_ENTITY_NAME);
}
target.addAttribute("discriminator-value", dValue.getValue());
if (((HbAnnotatedEClass) entity).getHbProxy() != null
&& ((HbAnnotatedEClass) entity).getHbProxy().getProxyClass() != null) {
final String proxyInterfaceName = ((HbAnnotatedEClass) entity).getHbProxy().getProxyClass();
target.addAttribute("proxy", proxyInterfaceName);
}
// stop here for eav
return target;
}
if (dValue != null
&& !target.getName().equals(INHERITANCE_STRATEGY_NAMES[InheritanceType.JOINED.getValue()])
&& !target.getName().equals(InheritanceType.TABLE_PER_CLASS.getValue())) {
target.addAttribute("discriminator-value", dValue.getValue());
log.debug("DValue " + dValue.getValue());
}
if (table != null
&& hbClassName
.compareTo(INHERITANCE_STRATEGY_NAMES[InheritanceType.SINGLE_TABLE.getValue()]) == 0) {
log.warn("EClass/Entity ("
+ entityName
+ ") is mapped as subclass in a single table with its superclass but it also has a table annotation. This table annotation is ignored.");
} else if (table != null) {
if (table.getName() != null) {
target.addAttribute("table", getHbmContext().trunc(table, table.getName(), false));
log.debug("Table " + table.getName());
}
if (table.getSchema() != null) {
target.addAttribute("schema", getHbmContext().trunc(table, table.getSchema(), false));
log.debug("Schema " + table.getSchema());
}
if (table.getCatalog() != null) {
target.addAttribute("catalog", getHbmContext().trunc(table, table.getCatalog(), false));
log.debug("Catalog " + table.getCatalog());
}
}
if (((HbAnnotatedEClass) entity).getHbWhere() != null) {
target.addAttribute("where", ((HbAnnotatedEClass) entity).getHbWhere().getClause());
}
if (((HbAnnotatedEClass) entity).getHbProxy() != null
&& ((HbAnnotatedEClass) entity).getHbProxy().getProxyClass() != null) {
final String proxyInterfaceName = ((HbAnnotatedEClass) entity).getHbProxy().getProxyClass();
target.addAttribute("proxy", proxyInterfaceName);
}
return target;
}
/** Return index were to place the import */
protected int getImportIndex() {
final List<?> children = getHbmContext().getCurrent().getChildren();
int defaultResult = 0;
for (int i = 0; i < children.size(); i++) {
final Element e = (Element) children.get(i);
final String name = e.getName();
if (name.compareTo("class") == 0 || name.compareTo("subclass") == 0
|| name.compareTo("joined-subclass") == 0 || name.compareTo("union-subclass") == 0) {
return i;
}
if (name.compareTo("typedef") == 0 || name.compareTo("meta") == 0) {
defaultResult = i + 1;
}
}
return defaultResult;
}
/** Returns true if this entity or one of its superclasses has an idclass */
private boolean hasCompositeID(PAnnotatedEClass aClass) {
if (aClass.getIdClass() != null) {
return true;
}
if (aClass.getPaSuperEntity() != null) {
return hasCompositeID(aClass.getPaSuperEntity());
}
for (PAnnotatedEClass superAClass : aClass.getPaMappedSupers()) {
if (hasCompositeID(superAClass)) {
return true;
}
}
{
List<PAnnotatedEStructuralFeature> features = aClass.getPaEStructuralFeatures();
for (PAnnotatedEStructuralFeature feature : features) {
if (feature instanceof PAnnotatedEReference
&& ((PAnnotatedEReference) feature).getEmbeddedId() != null) {
return true;
}
}
}
return false;
}
/**
* Maps the given entity in its hbm context.
*/
public void processEntity(PAnnotatedEClass entity) {
if (log.isDebugEnabled()) {
log.debug("Mapping Entity " + entity);
}
final HbAnnotatedEClass hbEntity = (HbAnnotatedEClass) entity;
Element entityElement = createEntity(entity, entity.getInheritanceStrategy(),
entity.getPaSuperEntity(), entity.getDiscriminatorValue(), entity.getTable());
if (entity.getEavMapping() != null) {
return;
}
final MappingContext mc = getHbmContext();
mc.setCurrent(entityElement);
mc.setCurrentTable(entity.getTable());
// MT: moved to processFeatures method because this should be done after
// the id
// element has been placed
if (entity.getPaSuperEntity() == null && entity.getPrimaryKeyJoinColumns() != null
&& entity.getPrimaryKeyJoinColumns().size() > 0) {
log.warn("This entity (" + entity.getEntity().getName()
+ " is the root in the class hierarchy and "
+ "has a pk joincolum annotation, this is not correct, ignoring pk joincolumn annotation");
} else if (InheritanceType.SINGLE_TABLE.equals(entity.getInheritanceStrategy())
&& entity.getPrimaryKeyJoinColumns() != null
&& entity.getPrimaryKeyJoinColumns().size() > 0) {
log.warn("Single table inheritance strategy (entity " + entity.getEntity().getName()
+ ", primary key join column annotation is ignored for subclass");
} else if (entity.getPrimaryKeyJoinColumns() != null
&& entity.getPrimaryKeyJoinColumns().size() > 0) {
addPrimaryKeyJoinColumn(entity.getPrimaryKeyJoinColumns(), entity);
} else if (entity.getPaSuperEntity() != null
&& InheritanceType.JOINED.equals(entity.getInheritanceStrategy())) {
final ArrayList<PrimaryKeyJoinColumn> list = new ArrayList<PrimaryKeyJoinColumn>();
final PrimaryKeyJoinColumn pkjc = PannotationFactory.eINSTANCE.createPrimaryKeyJoinColumn();
final String entityName = mc.getEntityName(entity.getModelEClass());
mc.trunc(pkjc, entityName + "id"); // TODO improve name
// creation here
list.add(pkjc);
addPrimaryKeyJoinColumn(list, entity);
}
try {
final List<PAnnotatedEStructuralFeature> inheritedFeatures = mc.getInheritedFeatures(entity);
mc.setForceOptional(entity.getPaSuperEntity() != null
&& (entity.getInheritanceStrategy() == null || InheritanceType.SINGLE_TABLE.equals(entity
.getInheritanceStrategy())));
mc.pushOverrideOnStack();
mc.addAttributeOverrides(entity.getAttributeOverrides());
mc.addAssociationOverrides(entity.getAssociationOverrides());
if (inheritedFeatures.size() > 0) {
log.debug("There are " + inheritedFeatures.size() + " inherited features ");
}
try {
processFeatures(inheritedFeatures);
final EList<SecondaryTable> secondaryTables = entity.getSecondaryTables();
if (secondaryTables == null || secondaryTables.isEmpty()) {
// Process features normally.
processFeatures(entity.getPaEStructuralFeatures());
} else {
// Special processing needed for secondary tables.
processSecondaryTables(secondaryTables, entity);
}
} finally {
mc.popOverrideStack();
}
} finally {
mc.setForceOptional(false);
mc.setCurrentTable(null);
Element idElement = entityElement.element("id");
if (idElement == null) {
idElement = entityElement.element("composite-id");
}
// create a synthetic id for roots
if (idElement == null && entity.getPaSuperEntity() == null
&& entity.getPaMappedSupers().size() == 0) {
idElement = IdMapper.addSyntheticId(hbmContext, entityElement);
} else if (mc.mustAddSyntheticID(entity)) {
idElement = IdMapper.addSyntheticId(hbmContext, entityElement);
} else {
addAccessor(idElement, hbmContext.getIdPropertyHandlerName());
}
if (idElement != null) {
int index = entityElement.indexOf(idElement) + 1;
if (((HbAnnotatedEClass) entity).getDiscriminatorFormula() != null) {
entityElement.add(
index++,
createDiscriminatorElement(hbEntity.getDiscriminatorFormula(),
entity.getDiscriminatorColumn(), hbEntity.getForceDiscriminator() != null));
} else if (entity.getDiscriminatorColumn() != null) {
// add discriminator element immediately after id element
entityElement.add(
index++,
createDiscriminatorElement(entity.getDiscriminatorColumn(),
hbEntity.getForceDiscriminator() != null));
}
// create and/or move version element (if present) immediately
// after discriminator
Element versionElement = entityElement.element("version");
if (versionElement == null) {
versionElement = addVersionProperty(hbEntity);
}
if (null != versionElement) { // In case this is not versioned
entityElement.remove(versionElement);
entityElement.add(index, versionElement);
}
}
mapFilter(entityElement, ((HbAnnotatedEClass) entity).getFilter());
mc.setCurrent(entityElement.getParent());
// now process the featuremap entries if any
processFeatureMapFeatures();
int index = 1 + entityElement.getChildren().indexOf(idElement);
// check if there is a discriminator, if so put it behind that one
if (entityElement.element("discriminator") != null) {
final Element elem = entityElement.element("discriminator");
index = 1 + entityElement.getChildren().indexOf(elem);
}
handleNaturalId(entityElement, index);
}
// initially the comment is placed at the back, move it to the front
final Element comment = addCommentElement(entity.getModelEClass(), entityElement);
if (comment != null) {
entityElement.remove(comment);
entityElement.add(0, comment);
}
// place the tuplizer at the front
mc.addTuplizerElement(entityElement, entity);
if ((entity.getPaSuperEntity() == null || entity.getPaSuperEntity().getMappedSuperclass() != null)
&& ((HbAnnotatedEClass) entity).getHbCache() != null) {
// then add the cache at the front
addCacheElement(entityElement, ((HbAnnotatedEClass) entity).getHbCache());
}
// and add the metas at the front
final Element meta1 = new Element("meta");
meta1.addAttribute("attribute", HbMapperConstants.ECLASS_NAME_META).addText(
entity.getModelEClass().getName());
meta1.addAttribute("inherit", "false");
final Element meta2 = new Element("meta");
meta2.addAttribute("attribute", HbMapperConstants.EPACKAGE_META).addText(
entity.getModelEClass().getEPackage().getNsURI());
meta2.addAttribute("inherit", "false");
entityElement.add(0, meta1);
entityElement.add(1, meta2);
// and move the joins to the back
final List<Element> toMove = new ArrayList<Element>();
for (Element elem : entityElement.getChildren()) {
if (elem.getName().equals("join")) {
toMove.add(elem);
}
}
entityElement.getChildren().removeAll(toMove);
entityElement.getChildren().addAll(toMove);
}
// reorganize the elements which have a natural-id inside a natural-id tag
protected void handleNaturalId(Element parentElement, int index) {
log.debug("Checking for natural-ids");
final List<Element> naturalIdElements = new ArrayList<Element>();
boolean mutable = false;
for (Element element : parentElement.getChildren()) {
String value;
if ((value = element.getAttributeValue(HbMapperConstants.NATURAL_ID_ATTR)) != null) {
if (naturalIdElements.isEmpty()) {
log.debug("Found natural-id, mutable: " + mutable);
mutable = Boolean.parseBoolean(value);
}
naturalIdElements.add(element);
element.removeAttribute(HbMapperConstants.NATURAL_ID_ATTR);
}
}
if (!naturalIdElements.isEmpty()) {
log.debug("Found " + naturalIdElements.size()
+ " naturalid properies, putting them inside a natural-id tag");
parentElement.getChildren().removeAll(naturalIdElements);
final Element naturalId = parentElement.addElement("natural-id");
// remove it again to place it at the correct position a little
// lower
parentElement.remove(naturalId);
naturalId.addAttribute("mutable", Boolean.toString(mutable));
parentElement.add(index, naturalId);
naturalId.getChildren().addAll(naturalIdElements);
for (Element element : naturalIdElements) {
element.setParent(naturalId);
}
}
}
/** Process the featuremap entries */
private void processFeatureMapFeatures() {
// this is a while and for loop, in the for loop the features of a
// feature map
// are processed, these features can again be a featuremap which are
// added
// to the featuremapmappers in the context, therefore this process walks
// on
List<FeatureMapMapping> featureMapMappers = getHbmContext().getClearFeatureMapMappers();
while (featureMapMappers.size() > 0) {
for (FeatureMapMapping fmm : featureMapMappers) {
fmm.process();
}
// read again because the fmm.process can result in new feature map
// mappings
featureMapMappers = getHbmContext().getClearFeatureMapMappers();
}
}
/**
* Process the features of the mapped superclass so that they are added to the current mapping
*/
protected void processMappedSuper(PAnnotatedEClass paMappedSuper) {
processFeatures(paMappedSuper.getPaEStructuralFeatures());
}
/** process the features of the annotated eclass */
protected void processFeatures(List<PAnnotatedEStructuralFeature> features) {
for (PAnnotatedEStructuralFeature annotatedEStructuralFeature : features) {
processFeature(annotatedEStructuralFeature);
}
}
/** Process secondary tables. */
protected void processSecondaryTables(List<SecondaryTable> secondaryTables,
PAnnotatedEClass entity) {
// Group features by primary and secondary tables.
// For the primary table we use null as the surrogate key. (HashMap
// allows null keys.)
final Set<String> tableNames = new HashSet<String>();
tableNames.add(PRIMARY_TABLE_KEY);
for (SecondaryTable secondaryTable : secondaryTables) {
tableNames.add(secondaryTable.getName());
}
final Map<String, List<PAnnotatedEStructuralFeature>> featuresByTable = new HashMap<String, List<PAnnotatedEStructuralFeature>>();
for (PAnnotatedEStructuralFeature feature : entity.getPaEStructuralFeatures()) {
// find the table for the feature
final String tableName = getHbmContext().getSecondaryTableName(feature);
// if there put it in the correct list
if (!tableNames.contains(tableName)) {
final String message = "Feature \"" + feature.getModelElement().getName()
+ "\" was mapped to undeclared secondary table \"" + tableName + "\".";
log.error(message);
throw new MappingException(message);
}
List<PAnnotatedEStructuralFeature> featuresInTable = featuresByTable.get(tableName);
if (featuresInTable == null) {
featuresInTable = new ArrayList<PAnnotatedEStructuralFeature>();
featuresByTable.put(tableName, featuresInTable);
}
featuresInTable.add(feature);
}
// Process features in primary table.
{
final List<PAnnotatedEStructuralFeature> featuresInTable = featuresByTable
.get(PRIMARY_TABLE_KEY);
// can happen if there are only secondarytable features and no
// primary table
// features see bugzilla 235949
if (featuresInTable != null) {
for (PAnnotatedEStructuralFeature feature : featuresInTable) {
processFeature(feature);
}
}
}
// Process features in secondary tables.
for (SecondaryTable secondaryTable : secondaryTables) {
if (!featuresByTable.containsKey(secondaryTable.getName())) {
// The table was listed in the SecondaryTable annotation, but no
// features were actually mapped to this
// table.
log.warn("No features mapped to secondary table " + secondaryTable.getName());
continue;
}
final List<PAnnotatedEStructuralFeature> featuresInTable = featuresByTable.get(secondaryTable
.getName());
// Create <join> element
// See
// http://www.hibernate.org/hib_docs/v3/reference/en/html/mapping.html#mapping-declaration
// -join
final Element joinElement = getHbmContext().getCurrent().addElement("join");
joinElement.addAttribute("table",
getHbmContext().trunc(secondaryTable, (secondaryTable.isGenerated() ? secondaryTable.getName().toUpperCase() : secondaryTable.getName()), false));
log.debug("Mapping features to secondary table \"" + secondaryTable.getName() + "\"");
if (secondaryTable.getCatalog() != null) {
joinElement.addAttribute("catalog", secondaryTable.getCatalog());
}
if (secondaryTable.getSchema() != null) {
joinElement.addAttribute("schema", secondaryTable.getSchema());
}
entity.getModelEClass().getEIDAttribute();
final List<PrimaryKeyJoinColumn> pkJoinColumns = secondaryTable.getPkJoinColumns();
final Element keyElement = joinElement.addElement("key");
for (PrimaryKeyJoinColumn pkJoinColumn : pkJoinColumns) {
keyElement.addElement("column").addAttribute("name",
getHbmContext().trunc(pkJoinColumn, pkJoinColumn.getName()));
}
handleOndelete(keyElement, ((HbAnnotatedEClass) entity).getHbOnDelete());
// Process features in this secondary table.
try {
getHbmContext().setCurrent(joinElement);
getHbmContext().setCurrentSecondaryTable(secondaryTable);
for (PAnnotatedEStructuralFeature feature : featuresInTable) {
processFeature(feature);
}
} finally {
getHbmContext().setCurrentSecondaryTable(null);
getHbmContext().setCurrent(joinElement.getParent());
}
}
}
/** Process one feature */
protected void processFeature(PAnnotatedEStructuralFeature paFeature) {
hbmContext.getFeatureMapper().process(paFeature);
}
/**
* Adds a key element to the current entity mapping, is for example used to join to the super
* class table.
*/
private void addPrimaryKeyJoinColumn(List<PrimaryKeyJoinColumn> pkJCs, PAnnotatedEClass entity) {
log.debug("Adding primary key join column");
final Element jcElement = getHbmContext().getCurrent().addElement("key");
handleOndelete(jcElement, ((HbAnnotatedEClass) entity).getHbOnDelete());
for (PrimaryKeyJoinColumn pkJC : pkJCs) {
final Element columnElement = jcElement.addElement("column");
if (pkJC.getColumnDefinition() != null) {
columnElement.addAttribute("sql-type", pkJC.getColumnDefinition());
}
if (pkJC.getName() != null) {
columnElement.addAttribute("name", getHbmContext().trunc(pkJC, pkJC.getName()));
}
if (pkJC.getReferencedColumnName() != null) {
columnElement.addAttribute("property-ref", pkJC.getReferencedColumnName());
}
}
}
/**
* Creates a discriminator element and returns it, so the caller should add it to the parent
* element
*/
private Element createDiscriminatorElement(DiscriminatorColumn dColumn, boolean force) {
Element dcElement = DocumentHelper.createElement("discriminator");
if (dColumn.getColumn() != null) {
final Column col = dColumn.getColumn();
final Element colElement = dcElement.addElement("column");
colElement.addAttribute("name", getHbmContext().trunc(dColumn, col.getName()));
if (col.getIndex() != null) {
colElement.addAttribute("index", col.getIndex());
}
if (hbDiscriminatorType(dColumn.getDiscriminatorType()).equals("string")
&& col.getLength() > 0) {
colElement.addAttribute("length", Integer.toString(col.getLength()));
}
if (!col.isNullable()) {
colElement.addAttribute("not-null", "true");
}
if (col.getColumnDefinition() != null) {
colElement.addAttribute("sql-type", col.getColumnDefinition());
}
} else if (dColumn.getName() != null) {
dcElement.addAttribute("column", getHbmContext().trunc(dColumn, dColumn.getName()));
}
dcElement.addAttribute("type", hbDiscriminatorType(dColumn.getDiscriminatorType()));
if (force) {
dcElement.addAttribute("force", "true");
}
if (dColumn.isSetLength() && log.isDebugEnabled()) {
log.debug("Ignoring length for discriminator column " + dColumn);
}
if (dColumn.getColumnDefinition() != null) {
String colName = dcElement.getAttributeValue("column");
Element colElement = dcElement.element("column");
if (colElement == null) {
colElement = dcElement.addElement("column");
if (colName != null && colElement.getAttributeValue("name") == null) {
colElement.addAttribute("name", colName);
}
}
colElement.addAttribute("sql-type", dColumn.getColumnDefinition());
}
return dcElement;
}
// note dc can be null
private Element createDiscriminatorElement(DiscriminatorFormula formula, DiscriminatorColumn dc,
boolean force) {
Element dcElement = DocumentHelper.createElement("discriminator");
dcElement.addAttribute("formula", formula.getValue());
if (force) {
dcElement.addAttribute("force", "true");
}
if (dc != null && dc.getDiscriminatorType() != null) {
dcElement.addAttribute("type", hbDiscriminatorType(dc.getDiscriminatorType()));
}
return dcElement;
}
/**
* Add a synthetic version if the entity does not define one
*/
private Element addVersionProperty(HbAnnotatedEClass aClass) {
assert (getHbmContext().getCurrent().element("version") == null);
if (!getHbmContext().alwaysVersion()) {
return null;
}
// if none optimistic lock then return
if (aClass.getHbEntity() != null && aClass.getHbEntity().getOptimisticLock() != null
&& aClass.getHbEntity().getOptimisticLock().equals(OptimisticLockType.NONE)) {
return null;
}
final boolean skipVersionOnImmutable = !getHbmContext().getPersistenceOptions()
.isDiscriminatorVersionOnImmutableEClass();
if (aClass.getImmutable() != null && skipVersionOnImmutable) {
return null;
}
// note specific accessor is required because version accessor is not
// retrieved through
// emf tuplizer
final Element versionElement = getHbmContext().getCurrent().addElement("version")
.addAttribute("name", getHbmContext().getVersionColumnName())
.addAttribute("column", getHbmContext().getVersionColumnName());
final Element meta = new Element("meta");
meta.addAttribute("attribute", HbMapperConstants.VERSION_META).addText("true");
meta.addAttribute("inherit", "false");
versionElement.add(0, meta);
versionElement.addAttribute("access", getHbmContext().getSyntheticVersionPropertyHandlerName());
return versionElement;
}
}