/** * <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: * AbstractAssociationMapper.java,v 1.17 2007/04/17 15:49:50 mtaal Exp $ */ package org.eclipse.emf.teneo.hibernate.mapper; import java.util.ArrayList; import java.util.List; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.eclipse.emf.ecore.EAttribute; import org.eclipse.emf.ecore.EClass; import org.eclipse.emf.ecore.EReference; import org.eclipse.emf.ecore.EStructuralFeature; import org.eclipse.emf.teneo.annotations.pamodel.PAnnotatedEAttribute; 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.CascadeType; import org.eclipse.emf.teneo.annotations.pannotation.Column; import org.eclipse.emf.teneo.annotations.pannotation.FetchType; import org.eclipse.emf.teneo.annotations.pannotation.JoinColumn; import org.eclipse.emf.teneo.annotations.pannotation.JoinTable; import org.eclipse.emf.teneo.annotations.pannotation.MapKey; import org.eclipse.emf.teneo.hibernate.hbannotation.Cascade; import org.eclipse.emf.teneo.hibernate.hbannotation.HbCascadeType; import org.eclipse.emf.teneo.hibernate.hbannotation.IdBag; import org.eclipse.emf.teneo.hibernate.hbannotation.Index; import org.eclipse.emf.teneo.hibernate.hbannotation.MapKeyManyToMany; import org.eclipse.emf.teneo.hibernate.hbannotation.Parameter; import org.eclipse.emf.teneo.hibernate.hbannotation.Type; import org.eclipse.emf.teneo.hibernate.hbmodel.HbAnnotatedEClass; import org.eclipse.emf.teneo.hibernate.hbmodel.HbAnnotatedEReference; import org.eclipse.emf.teneo.hibernate.hbmodel.HbAnnotatedETypeElement; import org.eclipse.emf.teneo.simpledom.Element; import org.eclipse.emf.teneo.util.StoreUtil; /** * Class contains different convenience methods which are of use for association * mapping. * * @author <a href="mailto:mtaal at elver.org">Martin Taal</a> */ public abstract class AbstractAssociationMapper extends AbstractMapper { /** Logger */ private static final Log log = LogFactory .getLog(AbstractAssociationMapper.class); /** * @return */ protected Element addOneToOne(PAnnotatedEReference aReference, String assocName, String targetEntity) { final PAnnotatedEClass referedToAClass = aReference.getAReferenceType(); final Element element; if (referedToAClass.isOnlyMapAsEntity() || !getHbmContext().forceUseOfInstance(referedToAClass)) { element = getHbmContext().getCurrent().addElement("one-to-one") .addAttribute("name", assocName).addAttribute( "entity-name", targetEntity); } else { element = getHbmContext().getCurrent().addElement("one-to-one") .addAttribute("name", assocName).addAttribute( "class", getHbmContext().getInstanceClassName( referedToAClass.getModelEClass())); } if (aReference instanceof HbAnnotatedEReference) { final HbAnnotatedEReference hae = (HbAnnotatedEReference) aReference; if (hae.getHbFetch() != null) { element.addAttribute("fetch", hae.getHbFetch().getValue() .getName().toLowerCase()); } } return element; } // translates jpa CascadeType to HbCascadeType protected List<HbCascadeType> getCascades(Cascade cascade, List<CascadeType> cascades) { if (cascade != null) { return cascade.getValue(); } return convertCascade(cascades); } protected List<HbCascadeType> convertCascade(List<CascadeType> cascades) { final List<HbCascadeType> res = new ArrayList<HbCascadeType>(); for (CascadeType ct : cascades) { if (ct == CascadeType.ALL) { res.add(HbCascadeType.ALL); } else if (ct == CascadeType.MERGE) { res.add(HbCascadeType.MERGE); } else if (ct == CascadeType.PERSIST) { res.add(HbCascadeType.PERSIST); res.add(HbCascadeType.SAVE_UPDATE); res.add(HbCascadeType.LOCK); } else if (ct == CascadeType.REFRESH) { res.add(HbCascadeType.REFRESH); } else if (ct == CascadeType.REMOVE) { res.add(HbCascadeType.REMOVE); } else if (ct == CascadeType.NONE) { return new ArrayList<HbCascadeType>(); } } return res; } /** Adds a manytoone tag to the current element of the hbmcontext */ protected Element addManyToOne(Element currentParent, PAnnotatedEReference aReference, String referedTo, boolean isPartOfKey) { final String assocName = getHbmContext().getPropertyName( aReference.getModelEReference()); log.debug("addManyToOne " + assocName + "/" + referedTo); if (isEObject(referedTo)) { return getHbmContext().getCurrent().addElement("any").addAttribute( "name", assocName).addAttribute("id-type", "long"); } final String tagName; if (((HbAnnotatedEReference) aReference).getHbType() != null) { tagName = "property"; final Element element = currentParent.addElement(tagName) .addAttribute("name", assocName); final Type hbType = ((HbAnnotatedEReference) aReference) .getHbType(); final List<Parameter> params = hbType.getParameters(); if (params == null || params.isEmpty()) { element.addAttribute("type", hbType.getType()); } else { final Element typeElement = element.addElement("type") .addAttribute("name", hbType.getType()); for (Parameter param : params) { typeElement.addElement("param").addAttribute("name", param.getName()).addText(param.getValue()); } } return element; } else if (isPartOfKey) { tagName = "key-many-to-one"; } else { tagName = "many-to-one"; } final EClass referedToEClass = aReference.getModelEReference() .getEReferenceType(); final PAnnotatedEClass referedToAClass = aReference.getPaModel() .getPAnnotated(referedToEClass); final Element element; if (referedToAClass.isOnlyMapAsEntity() || !getHbmContext().forceUseOfInstance(referedToAClass)) { element = currentParent.addElement(tagName).addAttribute("name", assocName).addAttribute("entity-name", referedTo); } else { element = currentParent.addElement(tagName).addAttribute("name", assocName).addAttribute("class", getHbmContext().getInstanceClassName(referedToEClass)); } if (aReference instanceof HbAnnotatedEReference) { final HbAnnotatedEReference hae = (HbAnnotatedEReference) aReference; if (hae.getHbFetch() != null) { element.addAttribute("fetch", hae.getHbFetch().getValue() .getName().toLowerCase()); } } return element; } /** * Adds joincolumns to the associationElement, sets the insert and update * attributes of the associationElement on the basis of the * insertable/updatable attributes of the joinColumns. Note that the * joinColumns list can be empty. forcenullable is set to true when a * feature map entry is being processed. */ protected void addJoinColumns(PAnnotatedEReference per, Element associationElement, List<JoinColumn> joinColumns, boolean forceNullable) { log.debug("addJoinColumns " + associationElement.getName() + "/ no of joincolumns" + joinColumns.size()); // assumption is that if one column is not insertable then the // association is // not insertable, same for updatable boolean insertable = true; boolean updatable = true; for (JoinColumn joinColumn : joinColumns) { log.debug("JoinColumn " + joinColumn.getName()); Element columnElement = associationElement.addElement("column") .addAttribute( "not-null", (joinColumn.isNullable() && joinColumn .isSetNullable()) || forceNullable ? "false" : "true") .addAttribute("unique", joinColumn.isUnique() ? "true" : "false"); if (joinColumn.getName() != null) { columnElement.addAttribute("name", getHbmContext().trunc( joinColumn.getName())); final String uc = getHbmContext().getUniqueConstraintKey( joinColumn.getName()); if (uc != null) { columnElement.addAttribute("unique-key", uc); } } final Index index = ((HbAnnotatedETypeElement) per).getHbIndex(); if (index != null) { columnElement.addAttribute("index", index.getName()); } // keep track if all joinColumns are insertable/updatable for in // that case the // associationElement is also insertable/updatable or not insertable &= joinColumn.isInsertable(); updatable &= joinColumn.isUpdatable(); // disabled this because not-null is specified as optional on the // many-to-one tag // also unique is more difficult // associationElement.addAttribute("not-null", // !joinColumn.isNullable() ? "true" : "false"); // associationElement.addAttribute("unique", joinColumn.isUnique() ? // "true" : "false"); // if // (joinColumn.eIsSet(PannotationPackage.eINSTANCE.getJoinColumn_ReferencedColumnName())) // TODO is this foreign key ? // MT: see the property-ref in hibernate, is used when the reference // is not on the primary key // of the target table but on some other column // MT: TODO add check on not insertable/updatable which is strange // for a joincolumn, this check // is present in onetomany mapper // --- JJH addCommentElement(per.getModelEReference(), columnElement); // --- JJH } // ugly but effective if (associationElement.getName().compareTo("map-key-many-to-many") != 0 && associationElement.getName().compareTo("join") != 0 && associationElement.getName().compareTo("key-many-to-one") != 0) { associationElement.addAttribute("insert", Boolean .toString(insertable)); associationElement.addAttribute("update", Boolean .toString(updatable)); } } /** * Creates cascades for onetoone/manytoone, they differ from many relations * because no delete-orphan is supported. * * @param associationElement * : the element to which the cascades are added. * @param cascade * : list of cascade annotation types */ protected void addCascadesForSingle(Element associationElement, List<HbCascadeType> cascades) { addCascades(associationElement, cascades, false); } /** * Adds a foreign key attribute to the collection element, if the aFeature * has a foreign key */ protected void addForeignKeyAttribute(Element manyElement, PAnnotatedEStructuralFeature aFeature) { if (aFeature.getForeignKey() != null) { manyElement.addAttribute("foreign-key", aFeature.getForeignKey() .getName()); } } /** * Creates cascades for onetomany, it differs from single relations because * delete-orphan is supported when cascade=all * * @param associationElement * : the element to which the cascades are added. * @param cascade * : list of cascade annotation types */ protected void addCascadesForMany(Element associationElement, List<HbCascadeType> cascades) { addCascades(associationElement, cascades, true); } /** * Creates cascades for onetoone/manytoone, they differ from many relations * because no delete-orphan is supported. * * @param associationElement * : the element to which the cascades are added. * @param cascade * : list of cascade annotation types * @param addDeleteOrphan * : if true then delete-orphan is added in case of cascade all */ protected void addCascades(Element associationElement, List<HbCascadeType> cascades, boolean addDeleteOrphan) { if (!cascades.isEmpty()) { StringBuffer sb = new StringBuffer(); for (HbCascadeType cascade : cascades) { if (cascade == HbCascadeType.ALL) { sb.append("all,"); // assuming all appears alone if (addDeleteOrphan) { sb.append("delete-orphan,"); } break; } else if (cascade == HbCascadeType.PERSIST) { sb.append("persist,"); } else if (cascade == HbCascadeType.MERGE) { sb.append("merge,"); } else if (cascade == HbCascadeType.REFRESH) { sb.append("refresh,"); } else if (cascade == HbCascadeType.REMOVE) { sb.append("delete,"); } else if (cascade == HbCascadeType.DELETE) { sb.append("delete,"); } else if (cascade == HbCascadeType.DELETE_ORPHAN) { sb.append("delete-orphan,"); } else if (cascade == HbCascadeType.EVICT) { sb.append("evict,"); } else if (cascade == HbCascadeType.LOCK) { sb.append("lock,"); } else if (cascade == HbCascadeType.REPLICATE) { sb.append("replicate,"); } else if (cascade == HbCascadeType.SAVE_UPDATE) { sb.append("save-update,"); } else { throw new MappingException("Cascade " + cascade.getName() + " not supported"); } } associationElement.addAttribute("cascade", sb.substring(0, sb .length() - 1)); } } /** * Sets the lazy attribute of the associationElement based on the fetchtype. */ protected void addFetchType(Element associationElement, FetchType fetch) { if (fetch == null) { return; } // TODO: when proxies are supported the below should be changed! if (FetchType.EXTRA.equals(fetch)) { associationElement.addAttribute("lazy", "extra"); } else { associationElement.addAttribute("lazy", FetchType.LAZY .equals(fetch) ? "true" : "false"); } } protected void addLazyProxy(Element element, FetchType fetch, PAnnotatedEReference paReference) { final HbAnnotatedEClass haClass = (HbAnnotatedEClass) paReference .getAReferenceType(); boolean lazyFetch = fetch == null || fetch == FetchType.LAZY; boolean doProxy = lazyFetch && (haClass.getHbProxy() != null && haClass.getHbProxy() .isLazy()); if (doProxy && lazyFetch) { element.addAttribute("lazy", "proxy"); } else { element.addAttribute("lazy", "false"); } } /** * Adds a listindex element with the column name set to the give collection * element. */ protected void addListIndex(Element collElement, PAnnotatedEStructuralFeature aFeature) { // TODO use column name generator String name = getIndexColumnName(aFeature); log.debug("Add list index " + name + " to " + aFeature.getModelEStructuralFeature().getName()); collElement.addElement("list-index").addAttribute("column", getHbmContext().trunc(name)); } protected String getIndexColumnName(PAnnotatedEStructuralFeature aFeature) { return (aFeature.getPaEClass().getModelEClass().getName() + "_" + aFeature.getModelEStructuralFeature().getName() + "_IDX") .toUpperCase(); } /** * Adds a map-key element with the column name set to the give selected * column element. */ // bugzilla 238515 // protected void addMapKey(Element collElement, // PAnnotatedEStructuralFeature aFeature, MapKey // mapKey) { // // log.debug("Add map key " + mapKey.getName() + " to " + // aFeature.getModelEStructuralFeature().getName()); // // // now, we add the column type. this is a required field // final EStructuralFeature keyFeature = // ((EReference) // aFeature.getModelElement()).getEReferenceType().getEStructuralFeature("key"); // if (keyFeature instanceof EReference) { // final PAnnotatedEClass referedAClass = // aFeature.getPaModel().getPAnnotated(((EReference) // keyFeature).getEReferenceType()); // if (referedAClass.isOnlyMapAsEntity() || // !getHbmContext().forceUseOfInstance(referedAClass)) { // final String entityName = hbmContext.getEntityName(((EReference) // keyFeature).getEReferenceType()); // collElement.addElement("map-key-many-to-many").addAttribute("entity-name", // entityName); // } else { // collElement.addElement("map-key-many-to-many").addAttribute("class", // getHbmContext().getInstanceClassName(referedAClass.getModelEClass())); // } // } else { // final PAnnotatedEAttribute paAttribute = // (PAnnotatedEAttribute) aFeature.getPaModel().getPAnnotated(keyFeature); // final Element mapKeyElement = // collElement.addElement("map-key").addAttribute("column", // getHbmContext().trunc(mapKey.getName())); // setType(paAttribute, mapKeyElement); // } // // "type", attr.getEType().getInstanceClassName()); // } /** * Add a mapkey taking into account if the key is an entity or a simple type */ protected void addMapKey(Element collElement, PAnnotatedEReference aref) { final EReference eref = aref.getModelEReference(); final HbAnnotatedEReference hbRef = (HbAnnotatedEReference) aref; final EStructuralFeature keyFeature = eref.getEReferenceType() .getEStructuralFeature("key"); if (hbRef.getHbMapKey() != null && hbRef.getMapKey() != null) { log .warn("The EReference " + aref.getModelElement().getName() + " has both a javax.persistence.MapKey as well as a hibernate MapKey annotation this is not correct, only one of the two should be used."); } if (hbRef.getHbMapKey() != null) { final org.eclipse.emf.teneo.hibernate.hbannotation.HbMapKey mapKey = hbRef .getHbMapKey(); final PAnnotatedEAttribute paAttribute = (PAnnotatedEAttribute) aref .getPaModel().getPAnnotated(keyFeature); final Element mapKeyElement = collElement.addElement("map-key"); if (mapKey.getColumns() != null && mapKey.getColumns().size() > 0) { addColumnsAndFormula(mapKeyElement, aref, mapKey.getColumns(), false, false, false, false); } setType(paAttribute, mapKeyElement); } else if (hbRef.getMapKey() != null) { final MapKey mapKey = hbRef.getMapKey(); final PAnnotatedEAttribute paAttribute = (PAnnotatedEAttribute) aref .getPaModel().getPAnnotated(keyFeature); final Element mapKeyElement = collElement.addElement("map-key") .addAttribute("column", getHbmContext().trunc(mapKey.getName())); setType(paAttribute, mapKeyElement); } else if (hbRef.getMapKeyManyToMany() != null) { final MapKeyManyToMany mkm = hbRef.getMapKeyManyToMany(); final PAnnotatedEClass referedAClass = aref.getPaModel() .getPAnnotated( ((EReference) keyFeature).getEReferenceType()); final Element mkmElement = collElement .addElement("map-key-many-to-many"); if (referedAClass.isOnlyMapAsEntity() || !getHbmContext().forceUseOfInstance(referedAClass)) { final String entityName = mkm.getTargetEntity() != null ? mkm .getTargetEntity() : hbmContext .getEntityName(((EReference) keyFeature) .getEReferenceType()); mkmElement.addAttribute("entity-name", entityName); } else { mkmElement.addAttribute("class", getHbmContext() .getInstanceClassName(referedAClass.getModelEClass())); } if (mkm.getJoinColumns() != null && mkm.getJoinColumns().size() > 0) { addJoinColumns(hbRef, mkmElement, mkm.getJoinColumns(), false); } } else if (keyFeature instanceof EReference) { final PAnnotatedEClass referedAClass = aref.getPaModel() .getPAnnotated( ((EReference) keyFeature).getEReferenceType()); if (referedAClass.isOnlyMapAsEntity() || !getHbmContext().forceUseOfInstance(referedAClass)) { final String entityName = hbmContext .getEntityName(((EReference) keyFeature) .getEReferenceType()); collElement.addElement("map-key-many-to-many").addAttribute( "entity-name", entityName); } else { collElement.addElement("map-key-many-to-many").addAttribute( "class", getHbmContext().getInstanceClassName( referedAClass.getModelEClass())); } } else { // final String type = // hbType(aref.getPaModel().getPAnnotated((EAttribute) feature)); final Element mapKey = collElement.addElement("map-key"); // .addAttribute("type", // type); final PAnnotatedEAttribute paAttribute = aref.getPaModel() .getPAnnotated((EAttribute) keyFeature); setType(paAttribute, mapKey); } } /** * @return a newly added hibernate for given collection * @deprecated use addCollectionElement(PAnnotatedEStructuralFeature) * instead. protected Element addCollectionElement(String name, * boolean isIndexed) { return * getHbmContext().getCurrent().addElement(isIndexed ? "list" : * "bag").addAttribute("name", name); // .addAttribute("access", * "org.eclipse.emf.teneo.hibernate.mapping.elist.EListPropertyAccessor" * ); } */ /** * Creates a Hibernate collection element: * <ul> * <li>"<list>" if the collection is indexed. * <li>"<bag>" if the collection is not indexed. * <li>"<idbag>" if the collection is not indexed and has an IdBag * annotation. * </ul> * * @param hbFeature * The structural feature for which to create collection. * @return The collection element. */ protected Element addCollectionElement( PAnnotatedEStructuralFeature paFeature) { final Element collectionElement; HbAnnotatedETypeElement hbFeature = (HbAnnotatedETypeElement) paFeature; final IdBag idBag = hbFeature.getHbIdBag(); final EStructuralFeature estruct = paFeature .getModelEStructuralFeature(); final boolean isArray = estruct instanceof EAttribute && estruct.getEType().getInstanceClass() != null && estruct.getEType().getInstanceClass().isArray(); final boolean isMap = StoreUtil.isMap(estruct) && getHbmContext().isMapEMapAsTrueMap(); // disabled following check because it also failed for many eattribute // which even with a onetomany // do not create a onetomany tag // if (paFeature.getOneToMany() != null && paFeature.getJoinTable() == // null && idBag != null) { // throw new MappingException("Cannot use one-to-many attribute mapping // without jointable in combination with // IdBag."); // } final boolean hasOrderBy = paFeature instanceof PAnnotatedEReference && ((PAnnotatedEReference) paFeature).getOrderBy() != null; final boolean hasWhereClause = paFeature instanceof PAnnotatedEReference && ((HbAnnotatedEReference) paFeature).getHbWhere() != null; if (isArray) { // array type collectionElement = getHbmContext().getCurrent() .addElement("array"); } else if (isMap) { collectionElement = getHbmContext().getCurrent().addElement("map"); } else if (idBag != null) { collectionElement = getHbmContext().getCurrent() .addElement("idbag"); } else if (getHbmContext().isGeneratedByEMF() && hbFeature.getOneToMany() != null && hbFeature.getOneToMany().isList()) { if (hasOrderBy && hbFeature.getOneToMany().isIndexed()) { log .warn("One to many ereference has indexed=true and has orderby set. Ignoring indexed and using orderby, assuming set " + hbFeature); } if (hasOrderBy || !hbFeature.getOneToMany().isIndexed()) { collectionElement = getHbmContext().getCurrent().addElement( "bag"); } else { collectionElement = getHbmContext().getCurrent().addElement( "list"); } } else if (!getHbmContext().isGeneratedByEMF() && hbFeature.getOneToMany() != null) { if (hasOrderBy && hbFeature.getOneToMany().isIndexed()) { log .warn("One to many ereference has indexed=true and has orderby set. " + "Ignoring indexed and using orderby, assuming set " + hbFeature); } if (!hbFeature.getOneToMany().isList() || hasOrderBy) { collectionElement = getHbmContext().getCurrent().addElement( "set"); } else if (hbFeature.getOneToMany().isList() && !hbFeature.getOneToMany().isIndexed()) { collectionElement = getHbmContext().getCurrent().addElement( "bag"); } else { collectionElement = getHbmContext().getCurrent().addElement( "list"); } } else if (hbFeature instanceof PAnnotatedEReference && ((PAnnotatedEReference) hbFeature).getManyToMany() != null && ((PAnnotatedEReference) hbFeature).getManyToMany().isList()) { collectionElement = getHbmContext().getCurrent().addElement("list"); } else { collectionElement = getHbmContext().getCurrent().addElement("bag"); } collectionElement.addAttribute("name", getHbmContext().getPropertyName( hbFeature.getModelEStructuralFeature())); if (idBag != null) { final String generator = (idBag.getGenerator() == null ? "increment" : idBag.getGenerator()); final String type = (idBag.getType() == null ? "long" : idBag .getType()); if (false && idBag.getTable() != null) { collectionElement.addAttribute("table", idBag.getTable()); } final Element collectionIdElement = collectionElement .addElement("collection-id"); collectionIdElement.addAttribute("column", hbmContext .getIdbagIDColumnName()); collectionIdElement.addAttribute("type", type); collectionIdElement.addElement("generator").addAttribute("class", generator); } if (hbFeature instanceof HbAnnotatedEReference) { final HbAnnotatedEReference hae = (HbAnnotatedEReference) hbFeature; if (hae.getHbFetch() != null) { collectionElement.addAttribute("fetch", hae.getHbFetch() .getValue().getName().toLowerCase()); } } if (hasOrderBy) { final PAnnotatedEClass aClass = ((PAnnotatedEReference) paFeature) .getAReferenceType(); final String name = getColumnNameForOrderBy(aClass, ((PAnnotatedEReference) paFeature).getOrderBy().getValue()); collectionElement.addAttribute("order-by", name); } if (hasWhereClause) { collectionElement.addAttribute("where", ((HbAnnotatedEReference) paFeature).getHbWhere() .getClause()); } final boolean hasBatchSize = paFeature instanceof HbAnnotatedEReference && ((HbAnnotatedEReference) paFeature).getBatchSize() != null; if (hasBatchSize) { collectionElement.addAttribute("batch-size", "" + ((HbAnnotatedEReference) paFeature).getBatchSize() .getSize()); } return collectionElement; } // returns the column name of a certain feature in the target entity protected String getColumnNameForOrderBy(PAnnotatedEClass aClass, String orderBy) { // handle the case of multiple features separated by commas final StringBuilder sb = new StringBuilder(); final String[] orderBys = orderBy.split(","); for (String ob : orderBys) { // handle direction asc/desc ob = ob.trim(); String direction = " asc"; if (ob.indexOf(" ") != -1) { final int index = ob.lastIndexOf(" "); direction = ob.substring(index); ob = ob.substring(0, index).trim(); if (ob.trim().startsWith(getHbmContext().getEscapeCharacter())) { ob = ob.trim().substring( getHbmContext().getEscapeCharacter().length()); } if (ob.trim().endsWith(getHbmContext().getEscapeCharacter())) { ob = ob.trim().substring( 0, ob.trim().length() - getHbmContext().getEscapeCharacter() .length()); } } boolean found = false; for (PAnnotatedEStructuralFeature aFeature : getAllFeatures(aClass)) { if (aFeature.getModelElement().getName().compareTo(ob) == 0) { if (aFeature instanceof PAnnotatedEReference) { throw new MappingException( "Feature " + ob + " is an ereference, onle eattribute is supported"); } found = true; final PAnnotatedEAttribute attr = (PAnnotatedEAttribute) aFeature; final List<Column> cs = getColumns(attr); if (cs.isEmpty()) { if (sb.length() > 0) { sb.append(","); } sb.append(escapeName(getColumnName(attr)) + direction); } else { for (Column c : cs) { if (sb.length() > 0) { sb.append(","); } sb.append(escapeName(c.getName()) + direction); } } } } if (!found) { throw new MappingException("Feature " + ob + " not found in eclass " + aClass.getModelEClass().getName()); } } return sb.toString(); } private String escapeName(String name) { // assume it also ends with it... if (name.startsWith(getHbmContext().getEscapeCharacter())) { return name; } return getHbmContext().getEscapeCharacter() + name + getHbmContext().getEscapeCharacter(); } /** * Add Element element in given collection element. */ protected Element addElementElement(Element collElement, PAnnotatedEStructuralFeature paFeature, List<Column> columns, String targetEntity) { final Element elElement; // if (targetEntity == null || paAttribute.getEnumerated() != null || // StoreUtil.isQName(paAttribute.getModelEAttribute())) { // MT: the target type name is ignored for a many element, it is always // recomputed elElement = collElement.addElement("element"); setType(paFeature, elElement); // } else { // in this case the defaultannotator has set the // targetentity! // elElement = collElement.addElement("element").addAttribute("type", // targetEntity); // } if (columns != null && columns.size() > 0) { addColumnsAndFormula(elElement, paFeature, columns, getHbmContext() .isCurrentElementFeatureMap(), true); } return elElement; } /** * Adds columns to a key element. Also sets update on the key element based * on the values in the columns. */ protected void addKeyColumns(HbAnnotatedETypeElement per, Element keyElement, List<JoinColumn> joinColumns) { log.debug("Adding key columns"); boolean setUpdatable = false; boolean isUpdatable = false; for (JoinColumn joinColumn : joinColumns) { log.debug("Column " + joinColumn.getName()); if (!setUpdatable && keyElement.getName().compareTo("key") == 0) { isUpdatable = joinColumn.isUpdatable(); keyElement.addAttribute("update", isUpdatable ? "true" : "false"); setUpdatable = true; } // these checks are disabled because they do not apply in case the // join column // is added to a join table if (!joinColumn.isInsertable()) { log.error("Unsupported non insertable join column in " + joinColumn); throw new MappingException( "Unsupported non insertable join column", joinColumn); } if (setUpdatable && joinColumn.isUpdatable() != isUpdatable) { log.error("Unsupported join column updatable in " + joinColumn); throw new MappingException("Unsupported join column updatable", joinColumn); } final Element ce = keyElement.addElement("column").addAttribute( "name", getHbmContext().trunc(joinColumn.getName())) .addAttribute("not-null", joinColumn.isNullable() ? "false" : "true") .addAttribute("unique", joinColumn.isUnique() ? "true" : "false"); // --- JJH, adapted by Martin Taal addCommentElement(per.getModelElement(), ce); // --- JJH if (per != null) { // is null in case of jointables final Index index = (per).getHbIndex(); if (index != null) { ce.addAttribute("index", index.getName()); } } // bz247939, after disabling these lines it all seemed to work fine // if (joinColumn.getTable() != null) { // log.error("Unsupported secondary table in " + joinColumn); // throw new MappingException("Unsupported secondary table", // joinColumn); // } if (joinColumn.getColumnDefinition() != null) { log.error("Unsupported column definition in " + joinColumn); throw new MappingException("Unsupported column definition", joinColumn); } } // TODO jc.getReferencedColumnName(); } /** * Adds a jointable and possible joincolumns to the passed key element. * * @param collElement * @param joinTable */ protected void addJoinTable(HbAnnotatedETypeElement hbAnnotatedElement, Element collElement, Element keyElement, JoinTable joinTable) { if (joinTable == null) { log.debug("No joinTable"); return; } if (joinTable.getCatalog() != null) { collElement.addAttribute("catalog", joinTable.getCatalog()); } if (joinTable.getSchema() != null) { collElement.addAttribute("schema", joinTable.getSchema()); } if (joinTable.getName() != null) { collElement.addAttribute("table", getHbmContext().trunc( joinTable.getName())); } if (joinTable.getUniqueConstraints().size() > 0) { log.error("Unsupported unique constraints in " + joinTable); throw new MappingException("Unsupported unique constraints", joinTable); } addKeyColumns(hbAnnotatedElement, keyElement, joinTable .getJoinColumns()/* * == null ? new ArrayList() : (List)joinTable. * getJoinColumns ().getValue() */); } }