diff options
Diffstat (limited to 'hibernate/org.eclipse.emf.teneo.hibernate.mapper/src/org/eclipse/emf/teneo/hibernate/mapper/AbstractMapper.java')
-rwxr-xr-x | hibernate/org.eclipse.emf.teneo.hibernate.mapper/src/org/eclipse/emf/teneo/hibernate/mapper/AbstractMapper.java | 971 |
1 files changed, 971 insertions, 0 deletions
diff --git a/hibernate/org.eclipse.emf.teneo.hibernate.mapper/src/org/eclipse/emf/teneo/hibernate/mapper/AbstractMapper.java b/hibernate/org.eclipse.emf.teneo.hibernate.mapper/src/org/eclipse/emf/teneo/hibernate/mapper/AbstractMapper.java new file mode 100755 index 000000000..37f536660 --- /dev/null +++ b/hibernate/org.eclipse.emf.teneo.hibernate.mapper/src/org/eclipse/emf/teneo/hibernate/mapper/AbstractMapper.java @@ -0,0 +1,971 @@ +/** + * <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 Brian + * Vetter </copyright> $Id: AbstractMapper.java,v 1.55 2011/03/17 09:21:35 mtaal Exp $ + */ + +package org.eclipse.emf.teneo.hibernate.mapper; + +import java.sql.Timestamp; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +import org.eclipse.emf.ecore.EAttribute; +import org.eclipse.emf.ecore.EClass; +import org.eclipse.emf.ecore.EClassifier; +import org.eclipse.emf.ecore.EDataType; +import org.eclipse.emf.ecore.EModelElement; +import org.eclipse.emf.ecore.util.EcoreUtil; +import org.eclipse.emf.ecore.xml.type.XMLTypePackage; +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.Column; +import org.eclipse.emf.teneo.annotations.pannotation.EnumType; +import org.eclipse.emf.teneo.annotations.pannotation.Enumerated; +import org.eclipse.emf.teneo.annotations.pannotation.External; +import org.eclipse.emf.teneo.annotations.pannotation.JoinColumn; +import org.eclipse.emf.teneo.annotations.pannotation.PannotationFactory; +import org.eclipse.emf.teneo.annotations.pannotation.TemporalType; +import org.eclipse.emf.teneo.hibernate.hbannotation.Any; +import org.eclipse.emf.teneo.hibernate.hbannotation.AnyMetaDef; +import org.eclipse.emf.teneo.hibernate.hbannotation.Cache; +import org.eclipse.emf.teneo.hibernate.hbannotation.Filter; +import org.eclipse.emf.teneo.hibernate.hbannotation.GenerationTime; +import org.eclipse.emf.teneo.hibernate.hbannotation.HbCascadeType; +import org.eclipse.emf.teneo.hibernate.hbannotation.HbannotationFactory; +import org.eclipse.emf.teneo.hibernate.hbannotation.Index; +import org.eclipse.emf.teneo.hibernate.hbannotation.OnDelete; +import org.eclipse.emf.teneo.hibernate.hbannotation.Parameter; +import org.eclipse.emf.teneo.hibernate.hbmodel.HbAnnotatedEAttribute; +import org.eclipse.emf.teneo.hibernate.hbmodel.HbAnnotatedEDataType; +import org.eclipse.emf.teneo.hibernate.hbmodel.HbAnnotatedEReference; +import org.eclipse.emf.teneo.hibernate.hbmodel.HbAnnotatedETypeElement; +import org.eclipse.emf.teneo.mapping.strategy.EntityNameStrategy; +import org.eclipse.emf.teneo.simpledom.Element; +import org.eclipse.emf.teneo.util.EcoreDataTypes; +import org.eclipse.emf.teneo.util.StoreUtil; + +/** + * Base class for all mapping classes. Provides access to the hbmcontext. + * + * @author <a href="mailto:mtaal at elver.org">Martin Taal</a> + */ +public abstract class AbstractMapper { + /** The list of types which translate to a hibernate types */ + private static final String[] TEMPORAL_TYPE_NAMES; + + /** Initialize TEMPORAL_TYPE_NAMES */ + static { + TEMPORAL_TYPE_NAMES = new String[TemporalType.VALUES.size()]; + TEMPORAL_TYPE_NAMES[TemporalType.DATE.getValue()] = "date"; + TEMPORAL_TYPE_NAMES[TemporalType.TIME.getValue()] = "time"; + TEMPORAL_TYPE_NAMES[TemporalType.TIMESTAMP.getValue()] = "timestamp"; + } + + /** Returns the correct temporal type for hibernate */ + private static String hbType(TemporalType temporalType) { + return TEMPORAL_TYPE_NAMES[temporalType != null ? temporalType + .getValue() : TemporalType.TIMESTAMP.getValue()]; + } + + /** logs it all */ + // private static final Log log = LogFactory.getLog(AbstractMapper.class); + /** return the opposite of an association */ + protected PAnnotatedEReference getOtherSide(PAnnotatedEReference paReference) { + // TODO assuming that mappedBy coincide with opposite, check in + // validation + if (paReference.getModelEReference().getEOpposite() == null) { + return null; + } + return paReference.getPaModel().getPAnnotated( + paReference.getModelEReference().getEOpposite()); + } + + /** The mapping context of this mapping action */ + protected MappingContext hbmContext; + + /** + * @return The mapping context used by this mapper + */ + protected MappingContext getHbmContext() { + return hbmContext; + } + + /** Set the hbm context */ + protected void setHbmContext(MappingContext hbmContext) { + this.hbmContext = hbmContext; + } + + protected void addAccessor(Element element, String propertyHandler) { + if (propertyHandler != null && propertyHandler.length() > 0) { + element.addAttribute("access", hbmContext.getPropertyHandlerName()); + } + } + + protected void addAccessor(Element element) { + addAccessor(element, hbmContext.getPropertyHandlerName()); + } + + protected void setType(PAnnotatedEStructuralFeature paFeature, + Element propElement) { + if (paFeature instanceof PAnnotatedEAttribute) { + setType((PAnnotatedEAttribute) paFeature, propElement); + } else { + setType((PAnnotatedEReference) paFeature, propElement); + } + } + + /** Handles the External annotation */ + protected void setType(PAnnotatedEReference paReference, Element propElement) { + final External external = paReference.getExternal(); + if (external == null) { + throw new MappingException( + "External annotation not set on eReference " + + StoreUtil.toString(paReference + .getModelEReference())); + } + + final Element typeElement = propElement.addElement("type"); + if (external.getType() == null) { // standard external + typeElement.addAttribute("name", getHbmContext() + .getExternalUserType()); + } else { + typeElement.addAttribute("name", external.getType()); + } + typeElement + .addElement("param") + .addAttribute("name", HbMapperConstants.ECLASS_NAME_META) + .addText( + paReference.getModelEReference().getEReferenceType() + .getName()); + typeElement + .addElement("param") + .addAttribute("name", HbMapperConstants.EPACKAGE_PARAM) + .addText( + paReference.getModelEReference().getEReferenceType() + .getEPackage().getNsURI()); + + } + + /** Handles the type or typedef annotations */ + protected void setType(PAnnotatedEAttribute paAttribute, Element propElement) { + + // handle the type annotation + final HbAnnotatedEAttribute hea = (HbAnnotatedEAttribute) paAttribute; + final EDataType ed = (EDataType) hea.getModelEAttribute().getEType(); + final HbAnnotatedEDataType hed = (HbAnnotatedEDataType) hea + .getPaModel().getPAnnotated(ed); + + final String name; + final List<Parameter> params; + if (hea.getHbType() != null) { + name = hea.getHbType().getType(); + params = hea.getHbType().getParameters(); + } else if (hed != null && hed.getHbType() != null) { + name = hed.getHbType().getType(); + params = hed.getHbType().getParameters(); + } else if (hed != null && hed.getHbTypeDef() != null) { + name = hed.getHbTypeDef().getName(); + params = null; + } else { + name = null; + params = null; + } + if (name != null) { + if (params == null || params.isEmpty()) { + // simple + propElement.addAttribute("type", name); + } else { + final Element typeElement = propElement.addElement("type") + .addAttribute("name", name); + for (Parameter param : params) { + typeElement.addElement("param") + .addAttribute("name", param.getName()) + .addText(param.getValue()); + } + } + } else if (paAttribute.getEnumerated() != null) { + handleEnumType(paAttribute, propElement); + } else if (StoreUtil.isQName(paAttribute.getModelEAttribute())) { + propElement.addAttribute("type", + "org.eclipse.emf.teneo.hibernate.mapping.QNameUserType"); + } else { + final String hType = hbType(paAttribute); + if (hType != null) { + propElement.addAttribute("type", hType); + } else { + final Element typeElement = propElement.addElement("type") + .addAttribute("name", hbmContext.getDefaultUserType()); + typeElement + .addElement("param") + .addAttribute("name", HbMapperConstants.EDATATYPE_PARAM) + .addText( + paAttribute.getModelEAttribute() + .getEAttributeType().getName()); + typeElement + .addElement("param") + .addAttribute("name", HbMapperConstants.EPACKAGE_PARAM) + .addText( + paAttribute.getModelEAttribute().getEType() + .getEPackage().getNsURI()); + } + } + } + + /** Handle the enum type */ + private void handleEnumType(PAnnotatedEAttribute paAttribute, + Element propElement) { + final Enumerated enumerated = paAttribute.getEnumerated(); + assert (enumerated != null); + final EAttribute eattr = paAttribute.getModelEAttribute(); + final EClassifier eclassifier = eattr.getEType(); + if (!getHbmContext().isGeneratedByEMF() + && getHbmContext().getInstanceClass(eclassifier) != null) { + final Class<?> instanceClass = getHbmContext().getInstanceClass( + eclassifier); + final Element typeElement = propElement.addElement("type") + .addAttribute("name", getEnumUserType(enumerated)); + typeElement.addElement("param") + .addAttribute("name", HbMapperConstants.ENUM_CLASS_PARAM) + .addText(instanceClass.getName()); + typeElement.addElement("param") + .addAttribute("name", HbMapperConstants.ECLASSIFIER_PARAM) + .addText(eclassifier.getName()); + typeElement.addElement("param") + .addAttribute("name", HbMapperConstants.EPACKAGE_PARAM) + .addText(eclassifier.getEPackage().getNsURI()); + } else if (getHbmContext().isGeneratedByEMF() + && eclassifier.getInstanceClass() != null) { + final Element typeElement = propElement.addElement("type") + .addAttribute("name", getEnumUserType(enumerated)); + typeElement.addElement("param") + .addAttribute("name", HbMapperConstants.ENUM_CLASS_PARAM) + .addText(eclassifier.getInstanceClass().getName()); + typeElement.addElement("param") + .addAttribute("name", HbMapperConstants.ECLASSIFIER_PARAM) + .addText(eclassifier.getName()); + typeElement.addElement("param") + .addAttribute("name", HbMapperConstants.EPACKAGE_PARAM) + .addText(eclassifier.getEPackage().getNsURI()); + } else { // must be emf dynamic + final Element typeElement = propElement.addElement("type") + .addAttribute("name", hbDynamicEnumType(enumerated)); + typeElement.addElement("param") + .addAttribute("name", HbMapperConstants.ECLASSIFIER_PARAM) + .addText(eclassifier.getName()); + typeElement.addElement("param") + .addAttribute("name", HbMapperConstants.EPACKAGE_PARAM) + .addText(eclassifier.getEPackage().getNsURI()); + } + } + + // gather the pafeatures of the supertypes also + protected List<PAnnotatedEStructuralFeature> getAllFeatures( + PAnnotatedEClass componentAClass) { + final ArrayList<PAnnotatedEStructuralFeature> result = new ArrayList<PAnnotatedEStructuralFeature>(); + result.addAll(componentAClass.getPaEStructuralFeatures()); + for (EClass eClass : componentAClass.getModelEClass().getESuperTypes()) { + final PAnnotatedEClass aSuperClass = componentAClass.getPaModel() + .getPAnnotated(eClass); + if (aSuperClass != null) { + result.addAll(getAllFeatures(aSuperClass)); + } + } + return result; + } + + /** + * @return Returns the hibernate name for the given Ecore data type. + * @throws MappingException + * if no corresponding hb type is defined. + */ + protected String hbType(PAnnotatedEAttribute paAttribute) { + final EAttribute eAttribute = paAttribute.getModelEAttribute(); + final HbAnnotatedEDataType hed = (HbAnnotatedEDataType) paAttribute + .getPaModel().getPAnnotated(eAttribute.getEAttributeType()); + final EDataType eDataType = paAttribute.getModelEAttribute() + .getEAttributeType(); + if (hed != null && hed.getHbTypeDef() != null) { + return hed.getHbTypeDef().getName(); + } else if (paAttribute.getLob() != null) { + if (EcoreDataTypes.INSTANCE.isByteArray(eDataType)) { + return "binary"; + } else if (EcoreDataTypes.INSTANCE.isEString(eDataType)) { + return "text"; + } else { + throw new MappingException( + "Lob annotations can only be used with Strings or byte arrays. " + + "Attribute is of type: " + eDataType); + } + } else if (EcoreDataTypes.INSTANCE.isEWrapper(eDataType) + || EcoreDataTypes.INSTANCE.isEPrimitive(eDataType)) { + return eDataType.getInstanceClassName(); + } else if (EcoreDataTypes.INSTANCE.isEString(eDataType)) { + return eDataType.getInstanceClassName(); + } else if (EcoreDataTypes.INSTANCE.isEDateTime(eDataType) + || (paAttribute.getTemporal() != null && paAttribute + .getTemporal().getValue().getValue() == TemporalType.TIMESTAMP_VALUE)) { + return getEDateTimeClass(paAttribute); + } else if (EcoreDataTypes.INSTANCE.isETime(eDataType) + || (paAttribute.getTemporal() != null && paAttribute + .getTemporal().getValue().getValue() == TemporalType.TIME_VALUE)) { + return getETimeClass(paAttribute); + } else if (EcoreDataTypes.INSTANCE.isEDuration(eDataType)) { + return hbmContext.getDurationType(); + } else if (EcoreDataTypes.INSTANCE.isEDate(eDataType, getHbmContext() + .getPersistenceOptions()) + || (paAttribute.getTemporal() != null && paAttribute + .getTemporal().getValue().getValue() == TemporalType.DATE_VALUE)) { + return getEDateClass(paAttribute); + } else if (eDataType.getInstanceClass() != null + && eDataType.getInstanceClass() == Object.class) { + // null forces caller to use usertype + return null; // "org.eclipse.emf.teneo.hibernate.mapping.DefaultToStringUserType"; + // } else if (eDataType.getInstanceClass() != null) { + // return eDataType.getInstanceClassName(); + } else { + final String result = EcoreDataTypes.INSTANCE + .getTargetTypeName(paAttribute); + if (result.compareTo(Object.class.getName()) == 0) { + // all edatatypes are translatable to a string, done by caller + return null; // "org.eclipse.emf.teneo.hibernate.mapping.DefaultToStringUserType"; + } + return result; + } + } + + /** Returns the type name of a many attribute */ + protected String getTargetTypeName(PAnnotatedEAttribute aAttribute) { + final EAttribute eAttribute = aAttribute.getModelEAttribute(); + // check on equality on object.class is used for listunion simpleunions + final Class<?> instanceClass = eAttribute.getEAttributeType() + .getInstanceClass(); + if (instanceClass != null && !Object.class.equals(instanceClass) + && !List.class.equals(instanceClass)) { + if (instanceClass.isArray()) { + // get rid of the [] at the end + return eAttribute + .getEType() + .getInstanceClassName() + .substring( + 0, + eAttribute.getEType().getInstanceClassName() + .length() - 2); + } + return instanceClass.getName(); + } else { + // the type is hidden somewhere deep get it + // the edatatype is the java.util.list + // it has an itemType which is the name of the element edatatype + // which contains the instanceclass + // takes also into account inheritance between datatypes + // NOTE the otm.targetentity can consist of a comma delimited list + // of target + // entities this is required for listunion types but is not + // according to the ejb3 spec! + ArrayList<EClassifier> eclassifiers = EcoreDataTypes.INSTANCE + .getItemTypes((EDataType) eAttribute.getEType()); + if (eclassifiers.size() > 0) { + StringBuffer result = new StringBuffer(); + for (int i = 0; i < eclassifiers.size(); i++) { + final EClassifier eclassifier = eclassifiers.get(i); + if (i > 0) { + result.append(","); + } + result.append(eclassifier.getInstanceClassName()); + } + return result.toString(); + } else { + return Object.class.getName(); + } + } + } + + /** + * Returns the correct enum primitive hibernate type, for Elver this is a + * hibernate user type. + */ + public String getEnumUserType(Enumerated enumerated) { + if (EnumType.STRING == enumerated.getValue()) { + return getHbmContext().getEnumUserType(); + } else { + return getHbmContext().getEnumIntegerUserType(); + } + } + + /** + * Returns the correct enum primitive hibernate type, for Elver this is a + * hibernate user type. + */ + protected String hbDynamicEnumType(Enumerated enumerated) { + if (EnumType.STRING == enumerated.getValue()) { + return getHbmContext().getDynamicEnumUserType(); + } else { + return getHbmContext().getDynamicEnumIntegerUserType(); + } + } + + /* + * @return The name of the java class needed to map the date type + */ + public String getEDateClass(PAnnotatedEAttribute paAttribute) { + final EDataType eDataType = paAttribute.getModelEAttribute() + .getEAttributeType(); + + assert (EcoreDataTypes.INSTANCE.isEDate(eDataType, getHbmContext() + .getPersistenceOptions())); + + if (XMLTypePackage.eINSTANCE.getDate().equals(eDataType)) { + return getHbmContext().getXSDDateUserType(); + } + + if (paAttribute.getTemporal() != null) { + final TemporalType tt = paAttribute.getTemporal().getValue(); + return hbType(tt); + } + + // only override if the user did not specify a more specific class + if (EcoreDataTypes.INSTANCE.isEDate(eDataType, getHbmContext() + .getPersistenceOptions())) { + // EMF returns an XSD Date type as an Object instance. go figure. + // note that I would prefer to use the class instance to get the + // name + // but for other reasons I do not want to have references to the + // org.eclipse.emf.teneo.hibernate plugin. + return getHbmContext().getXSDDateUserType(); + } + + // TODO: should it not use the eDataType.getInstanceClass()? Hmm if the + // user + // really wants a different mapping he/she should use maybe a usertype?? + return Date.class.getName(); + } + + /* + * @return The name of the java class needed to map the time type + */ + public String getETimeClass(PAnnotatedEAttribute paAttribute) { + final EDataType eDataType = paAttribute.getModelEAttribute() + .getEAttributeType(); + + if (XMLTypePackage.eINSTANCE.getTime().equals(eDataType)) { + return getHbmContext().getXSDTimeUserType(); + } + + if (paAttribute.getTemporal() != null) { + final TemporalType tt = paAttribute.getTemporal().getValue(); + return hbType(tt); + } + + // bugzilla 277546 + if (eDataType.getInstanceClass() != null + && Timestamp.class.isAssignableFrom(eDataType + .getInstanceClass())) { + return eDataType.getInstanceClass().getName(); + } + + if (EcoreDataTypes.INSTANCE.isETime(eDataType)) { + // EMF returns an XSD Date type as an Object instance. go figure. + // note that I would prefer to use the class instance to get the + // name + // but for other reasons I do not want to have references to the + // org.eclipse.emf.teneo.hibernate plugin. + return getHbmContext().getXSDTimeUserType(); + } + + // TODO: should it not use the eDataType.getInstanceClass()? Hmm if the + // user + // really wants a different mapping he/she should use maybe a usertype?? + return Timestamp.class.getName(); + } + + /* + * @return The name of the java class needed to map the datetime/timestamp + * type + */ + public String getEDateTimeClass(PAnnotatedEAttribute paAttribute) { + final EDataType eDataType = paAttribute.getModelEAttribute() + .getEAttributeType(); + + assert (EcoreDataTypes.INSTANCE.isEDateTime(eDataType)); + + if (XMLTypePackage.eINSTANCE.getDateTime().equals(eDataType)) { + return getHbmContext().getXSDDateTimeUserType(); + } + + if (paAttribute.getTemporal() != null) { + final TemporalType tt = paAttribute.getTemporal().getValue(); + return hbType(tt); + } + + // bugzilla 277546 + if (eDataType.getInstanceClass() != null + && Date.class.isAssignableFrom(eDataType.getInstanceClass())) { + return eDataType.getInstanceClass().getName(); + } + + if (EcoreDataTypes.INSTANCE.isEDateTime(eDataType)) { + // EMF returns an XSD Date type as an Object instance. go figure. + // note that I would prefer to use the class instance to get the + // name + // but for other reasons I do not want to have references to the + // org.eclipse.emf.teneo.hibernate plugin. + return getHbmContext().getXSDDateTimeUserType(); + } + + // TODO: should it not use the eDataType.getInstanceClass()? Hmm if the + // user + // really wants a different mapping he/she should use maybe a usertype?? + return Timestamp.class.getName(); + } + + /** + * Returns the (possibly overridden) JoinColumns annotations for the given + * reference or an empty list if no JoinColumns were defined. + */ + protected List<JoinColumn> getJoinColumns(PAnnotatedEReference paReference) { + List<JoinColumn> joinColumns = getHbmContext().getAssociationOverrides( + paReference); + if (joinColumns == null) { + joinColumns = paReference.getJoinColumns(); + } + if (joinColumns == null) { + return new ArrayList<JoinColumn>(); + } + return joinColumns; + } + + /** Adds a cache element */ + protected void addCacheElement(Element parent, Cache cache) { + // translate to hibernate specific notation + final String usage = cache.getUsage().getName().toLowerCase() + .replaceAll("_", "-"); + + Element cacheElement = parent.addElement("cache").addAttribute("usage", + usage); + if (cache.getRegion() != null) { + cacheElement.addAttribute("region", cache.getRegion()); + } + if (cache.getInclude() != null) { + cacheElement.addAttribute("include", cache.getInclude()); + } + parent.remove(cacheElement); + parent.add(0, cacheElement); + } + + /** Same as above only handles multiple columns */ + protected void addColumnsAndFormula(Element propertyElement, + PAnnotatedEStructuralFeature pef, List<Column> columns, + boolean isNullable, boolean setColumnAttributesInProperty) { + addColumnsAndFormula(propertyElement, pef, columns, isNullable, + setColumnAttributesInProperty, false, false); + } + + /** Same as above only handles multiple columns */ + protected void addColumnsAndFormula(Element propertyElement, + PAnnotatedEStructuralFeature pef, List<Column> columns, + boolean isNullable, boolean setColumnAttributesInProperty, + boolean isUnique, boolean isIdProperty) { + // if no columns set then use some default + final HbAnnotatedETypeElement hbFeature = (HbAnnotatedETypeElement) pef; + if (columns.isEmpty() && hbFeature.getFormula() == null) { + final Column col = PannotationFactory.eINSTANCE.createColumn(); + col.setName(getColumnName(pef)); + col.setNullable(isNullable); + if (isIdProperty) { + col.setUnique(false); + } else { + col.setUnique(isUnique); + } + + if (pef instanceof HbAnnotatedEAttribute + && ((HbAnnotatedEAttribute) pef).getGenerated() != null + && ((HbAnnotatedEAttribute) pef).getGenerated().getValue() != null + && ((HbAnnotatedEAttribute) pef).getGenerated().getValue() != GenerationTime.NEVER) { + col.setInsertable(false); + col.setUpdatable(false); + } + + columns.add(col); + } + // if only one id column then it is not nullable! + if (isIdProperty && columns.size() == 1 + && pef.getPaEClass().getIdClass() == null) { + columns.get(0).setNullable(false); + // set to false, see bugzilla 280169 + columns.get(0).setUnique(false); + } + + for (Column column : columns) { + addColumn(propertyElement, pef, column, isNullable, + setColumnAttributesInProperty); + } + + // do the formula part + if (hbFeature.getFormula() != null) { + propertyElement.addElement("formula").addText( + hbFeature.getFormula().getValue()); + } + } + + protected String getColumnName(PAnnotatedEStructuralFeature pef) { + if (getHbmContext().getEmbeddingFeature() != null) { // embedded + // TODO: check illegal, embedded component can not really have an id + final PAnnotatedEStructuralFeature embeddingFeature = getHbmContext() + .getEmbeddingFeature(); + return getHbmContext().getSqlNameStrategy().getColumnName(pef, + embeddingFeature.getModelEStructuralFeature().getName()); + } else { + return getHbmContext().getSqlNameStrategy() + .getColumnName(pef, null); + } + } + + /** + * Add a comment element, if the eModelElement has documentation, returns + * the comment element + */ + protected Element addCommentElement(EModelElement eModelElement, + Element hbmElement) { + if (hbmContext.getMaximumCommentLength() == 0) { + return null; + } + final String commentData = EcoreUtil.getDocumentation(eModelElement); + if (commentData != null) { + final Element comment = hbmElement.addElement("comment"); + String commentText = commentData.replace('\'', ' ').replace('"', + ' '); + if (commentText.length() > hbmContext.getMaximumCommentLength()) { + commentText = commentText.substring(0, + hbmContext.getMaximumCommentLength()); + } + comment.addText(commentText); + return comment; + } + return null; + } + + /** Adds anytype columns */ + protected List<Column> getAnyTypeColumns(String featureName, + boolean isNullable) { + final ArrayList<Column> result = new ArrayList<Column>(); + final Column typeColumn = PannotationFactory.eINSTANCE.createColumn(); + typeColumn.setName(hbmContext.trunc(null, featureName + "_type")); + typeColumn.setNullable(isNullable); + result.add(typeColumn); + final Column idColumn = PannotationFactory.eINSTANCE.createColumn(); + idColumn.setName(hbmContext.trunc(null, featureName + "_id")); + idColumn.setNullable(isNullable); + result.add(idColumn); + return result; + } + + /** + * Returns the (possibly overridden) columns annotation for the given + * attribute. + */ + protected List<Column> getColumns(PAnnotatedEStructuralFeature paFeature) { + final Column defaultColumn = paFeature.getColumn(); + final Column oc = getHbmContext().getAttributeOverride(paFeature); + + if (oc != null) { + final ArrayList<Column> result = new ArrayList<Column>(); + result.add(oc); + return result; + } + // try multiple columns + final HbAnnotatedETypeElement hae = (HbAnnotatedETypeElement) paFeature; + if (hae.getHbColumns().size() > 0) { + return hae.getHbColumns(); + } + final ArrayList<Column> result = new ArrayList<Column>(); + if (defaultColumn != null) { + result.add(defaultColumn); + } + return result; + } + + /** Sets property attributes on the basis of the column */ + private void addColumn(Element propertyElement, + PAnnotatedEStructuralFeature pef, Column column, + boolean isNullable, boolean setColumnAttributesInProperty) { + if (column != null) { + if (setColumnAttributesInProperty) { + // this is not the nicest place to do this + if (propertyElement.getName().compareTo("property") == 0 + || propertyElement.getName().compareTo("many-to-one") == 0) { + propertyElement.addAttribute("insert", + column.isInsertable() ? "true" : "false"); + propertyElement.addAttribute("update", + column.isUpdatable() ? "true" : "false"); + } + // MT: I think that the column nullability should not be used + // for setting not-null + // on the property, this is already specified by the optional + // attribute on the + // basic annotation. Maybe a check can be used instead to detect + // inconsistenties + // in the column attributes and the basic ann. + // Note that the ejb3 spec says that optional should be + // disregarded for primitive + // types which I + // do not understand. + // I disabled it for now to ignore for the test cases. + // MT05032006: After some more thought the column nullability + // can be used in case of + // single table inheritance mapping + if (!propertyElement.getName().equals("any")) { + propertyElement.addAttribute("not-null", isNullable + || column.isNullable() ? "false" : "true"); + } + propertyElement.addAttribute("unique", + column.isUnique() ? "true" : "false"); + } + addColumnElement(propertyElement, pef, column, isNullable); + } + } + + protected void mapFilter(Element parentElement, List<Filter> filters) { + for (Filter filter : filters) { + final Element filterElement = parentElement.addElement("filter"); + filterElement.addAttribute("name", filter.getName()); + if (filter.getCondition() != null) { + filterElement.addAttribute("condition", filter.getCondition()); + } + } + } + + /** + * 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) { + // note comma at the end is trimmed off below + 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)); + } + } + + /** + * Create an any Element + */ + public Element createAny(String name, + PAnnotatedEStructuralFeature paFeature, Any any, + AnyMetaDef anyMetaDef, boolean isMany) { + + final AnyMetaDef localAnyMetaDef; + if (anyMetaDef == null) { + localAnyMetaDef = HbannotationFactory.eINSTANCE.createAnyMetaDef(); + localAnyMetaDef.setIdType("long"); + } else { + localAnyMetaDef = anyMetaDef; + } + final Any localAny; + if (any == null) { + localAny = HbannotationFactory.eINSTANCE.createAny(); + } else { + localAny = any; + } + + final String tagName; + if (isMany) { + tagName = "many-to-any"; + } else { + tagName = "any"; + } + + // don't know how to create an element, so add an remove it... + final Element anyElement = getHbmContext().getCurrent() + .addElement(tagName) + .addAttribute("id-type", localAnyMetaDef.getIdType()) + .addAttribute("meta-type", localAnyMetaDef.getMetaType()); + getHbmContext().getCurrent().remove(anyElement); + + if (!isMany) { + anyElement.addAttribute("name", name); + final List<HbCascadeType> cascades = new ArrayList<HbCascadeType>(); + if (paFeature instanceof HbAnnotatedEReference) { + if (((HbAnnotatedEReference) paFeature).getHbCascade() == null) { + cascades.add(HbCascadeType.ALL); + } else { + cascades.addAll(((HbAnnotatedEReference) paFeature) + .getHbCascade().getValue()); + } + } else { + cascades.add(HbCascadeType.ALL); + } + addCascades(anyElement, cascades, isMany); + } + + final List<Column> columns = new ArrayList<Column>(); + if (localAny.getMetaColumn() != null) { + columns.add(localAny.getMetaColumn()); + } else { + final Column typeColumn = PannotationFactory.eINSTANCE + .createColumn(); + // bugzilla 294201, trunc is also done later in addColumn + // typeColumn.setName(hbmContext.trunc(paFeature.getModelEStructuralFeature().getName() + // + "_type")); + typeColumn.setName(paFeature.getModelEStructuralFeature().getName() + + "_type"); + typeColumn.setNullable(localAny.isOptional()); + columns.add(typeColumn); + } + + if (paFeature.getColumn() != null) { + columns.add(paFeature.getColumn()); + } else { + final Column idColumn = PannotationFactory.eINSTANCE.createColumn(); + // bugzilla 294201, trunc is also done later in addColumn + // idColumn.setName(hbmContext.trunc(paFeature.getModelEStructuralFeature().getName() + // + "_id")); + idColumn.setName(paFeature.getModelEStructuralFeature().getName() + + "_id"); + idColumn.setNullable(localAny.isOptional()); + columns.add(idColumn); + } + addColumnsAndFormula(anyElement, paFeature, columns, paFeature + .getModelEStructuralFeature().isRequired(), false); + return anyElement; + } + + /** + * Add a columnelement to the property, takes into account length, precision + * etc. forceNullable is set when the feature belongs to a featuremap + */ + private void addColumnElement(Element propertyElement, + PAnnotatedEStructuralFeature pef, Column column, + boolean forceNullable) { + if (column != null) { + Element columnElement = propertyElement + .addElement("column") + .addAttribute( + "not-null", + column.isNullable() || forceNullable ? "false" + : "true") + .addAttribute("unique", + column.isUnique() ? "true" : "false"); + final String name; + if (column.getName() != null) { + name = column.getName(); + } else { + if (getHbmContext().getEmbeddingFeature() != null) { // embedded + // TODO: check illegal, embedded component can not really + // have an id + final PAnnotatedEStructuralFeature embeddingFeature = getHbmContext() + .getEmbeddingFeature(); + name = getHbmContext().getSqlNameStrategy().getColumnName( + pef, + embeddingFeature.getModelEStructuralFeature() + .getName()); + } else { + name = getHbmContext().getSqlNameStrategy().getColumnName( + pef, null); + } + } + if (column.getUniqueKey() != null) { + columnElement.addAttribute("unique-key", column.getUniqueKey()); + } + columnElement.addAttribute("name", + getHbmContext().trunc(column, name)); + if (column.isSetLength()) { + columnElement.addAttribute("length", + Integer.toString(column.getLength())); + } + if (column.isSetPrecision()) { + columnElement.addAttribute("precision", + Integer.toString(column.getPrecision())); + } + if (column.isSetScale()) { + columnElement.addAttribute("scale", + Integer.toString(column.getScale())); + } + if (column.getColumnDefinition() != null) { + columnElement.addAttribute("sql-type", + column.getColumnDefinition()); + } + final String uc = getHbmContext().getUniqueConstraintKey(name); + if (uc != null) { + columnElement.addAttribute("unique-key", uc); + } + if (pef instanceof HbAnnotatedETypeElement + && ((HbAnnotatedETypeElement) pef).getHbIndex() != null) { + final Index index = ((HbAnnotatedETypeElement) pef) + .getHbIndex(); + columnElement.addAttribute("index", index.getName()); + } + + // --- JJH, adapted by MT + addCommentElement(pef.getModelElement(), columnElement); + // --- JJH + } + } + + /** Add the ondelete mapping to the key */ + protected void handleOndelete(Element keyElement, OnDelete onDelete) { + // if (true || onDelete == null) { + // return; + // } + // + // if (onDelete.getAction().equals(OnDeleteAction.CASCADE)) { + // keyElement.addAttribute("on-delete", "cascade"); + // } else { + // keyElement.addAttribute("on-delete", "noaction"); + // } + } + + /** Returns true if the target is the general EObject type */ + protected boolean isEObject(String typeName) { + if (typeName == null) { + return false; + } + return typeName.compareTo(EntityNameStrategy.EOBJECT_ECLASS_NAME) == 0; + } +}
\ No newline at end of file |