/**
* <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: BaseEFeatureAnnotator.java,v 1.12 2008/10/12 11:38:11 mtaal Exp $
*/
package org.eclipse.emf.teneo.annotations.mapper;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
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.EClassifier;
import org.eclipse.emf.ecore.EDataType;
import org.eclipse.emf.ecore.EReference;
import org.eclipse.emf.ecore.xml.type.XMLTypePackage;
import org.eclipse.emf.teneo.PersistenceOptions;
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.ForeignKey;
import org.eclipse.emf.teneo.annotations.pannotation.JoinColumn;
import org.eclipse.emf.teneo.annotations.pannotation.PAnnotation;
import org.eclipse.emf.teneo.annotations.pannotation.Temporal;
import org.eclipse.emf.teneo.annotations.pannotation.TemporalType;
import org.eclipse.emf.teneo.util.EcoreDataTypes;
/**
* Placeholder for several utility methods which are relevant for annotating ereferences and
* eattributes.
*
* @author <a href="mailto:mtaal@elver.org">Martin Taal</a>
* @version $Revision: 1.12 $
*/
public abstract class BaseEFeatureAnnotator extends AbstractAnnotator {
// The logger
protected static final Log log = LogFactory.getLog(BaseEFeatureAnnotator.class);
private int defaultVarCharLength = -1;
/** Create a foreign key and set its name */
protected ForeignKey createFK(PAnnotatedEStructuralFeature aFeature) {
final ForeignKey fk = getFactory().createForeignKey();
fk.setName(getSqlNameStrategy().getForeignKeyName(aFeature));
return fk;
}
protected FetchType getFetch(PAnnotatedEClass aClass) {
return FetchType.EAGER;
}
/*
* (non-Javadoc)
*
* @see
* org.eclipse.emf.teneo.annotations.mapper.AbstractAnnotator#setPersistenceOptions(org.eclipse
* .emf.teneo.PersistenceOptions)
*/
@Override
public void setPersistenceOptions(PersistenceOptions persistenceOptions) {
super.setPersistenceOptions(persistenceOptions);
defaultVarCharLength = persistenceOptions.getDefaultVarCharLength();
}
/**
* Adds the column level constraints on the basis of the xsd extended meta data
*/
protected void addColumnConstraints(PAnnotatedEAttribute aAttribute) {
final EAttribute eAttribute = aAttribute.getModelEAttribute();
// decide if a column annotation should be added, this is done
// when the maxLength or length, totalDigits or fractionDigits are set
// and when no other column has been set
if (aAttribute.getColumn() == null) {
String maxLength = getExtendedMetaData(eAttribute, "maxLength");
if (maxLength == null) {
maxLength = getExtendedMetaData(eAttribute, "length");
}
if (maxLength == null && defaultVarCharLength > 0) {
maxLength = "" + defaultVarCharLength;
}
final String totalDigits = getExtendedMetaData(eAttribute, "totalDigits");
final String fractionDigits = getExtendedMetaData(eAttribute, "fractionDigits");
boolean setUnique = false;
// bugzilla 249246
if (getPersistenceOptions().isIDFeatureAsPrimaryKey() && eAttribute.isID() && aAttribute.getId() == null) {
if (aAttribute.getPaEClass().getPaSuperEntity() != null &&
aAttribute.getPaEClass().getPaSuperEntity().getMappedSuperclass() == null) {
setUnique = true;
}
}
if (maxLength != null || setUnique || totalDigits != null || fractionDigits != null ||
defaultVarCharLength > -1) {
final Column column = getFactory().createColumn();
// only support this for the string class, the length/maxlength
// is also
// used in case of the xsd list/union types but this can not be
// enforced using a constraint on the
// columnlength
if (maxLength != null && eAttribute.getEAttributeType().getInstanceClass() != null &&
eAttribute.getEAttributeType().getInstanceClass() == String.class) {
column.setLength(Integer.parseInt(maxLength)); // you'll
// find
// parse
// errors!
}
if (totalDigits != null) {
column.setPrecision(Integer.parseInt(totalDigits));
}
if (fractionDigits != null) {
column.setScale(Integer.parseInt(fractionDigits));
}
if (aAttribute.getBasic() != null) {
column.setNullable(aAttribute.getBasic().isOptional());
}
if (setUnique) {
column.setUnique(true);
}
aAttribute.setColumn(column);
}
} else if (aAttribute.getBasic() != null && !aAttribute.getColumn().isSetNullable()) {
// bugzilla 226775
aAttribute.getColumn().setNullable(aAttribute.getBasic().isOptional());
}
final Column c = aAttribute.getColumn();
if (isStringType(aAttribute.getModelEAttribute()) && c != null && defaultVarCharLength > 0 && !c.isSetLength()) {
c.setLength(defaultVarCharLength);
}
}
private boolean isStringType(EAttribute eAttribute) {
final Class<?> clz = eAttribute.getEAttributeType().getInstanceClass();
if (clz != null && String.class.isAssignableFrom(clz)) {
return true;
}
if (eAttribute.getEAttributeType() == XMLTypePackage.eINSTANCE.getString()) {
return true;
}
if (eAttribute.getEAttributeType() == XMLTypePackage.eINSTANCE.getName_()) {
return true;
}
if (eAttribute.getEAttributeType() == XMLTypePackage.eINSTANCE.getNCName()) {
return true;
}
if (eAttribute.getEAttributeType() == XMLTypePackage.eINSTANCE.getToken()) {
return true;
}
if (eAttribute.getEAttributeType() == XMLTypePackage.eINSTANCE.getQName()) {
return true;
}
return false;
}
/** Return a list of join columns */
protected List<JoinColumn> getJoinColumns(List<String> names, boolean optional, boolean isUpdateInsertable,
PAnnotation pAnnotation) {
final List<JoinColumn> result = new ArrayList<JoinColumn>();
for (String name : names) {
JoinColumn jc = getFactory().createJoinColumn();
jc.setName(name);
jc.setNullable(optional);
jc.setUpdatable(isUpdateInsertable);
jc.setInsertable(isUpdateInsertable);
result.add(jc);
}
return result;
}
protected String getTargetTypeName(PAnnotatedEAttribute aAttribute) {
return EcoreDataTypes.INSTANCE.getTargetTypeName(aAttribute);
}
/** Get a specific extended metadate */
protected String getExtendedMetaData(EAttribute eAttribute, String key) {
String value =
EcoreDataTypes.INSTANCE.getEAnnotationValue(eAttribute,
"http:///org/eclipse/emf/ecore/util/ExtendedMetaData", key);
if (value == null) {
value =
EcoreDataTypes.INSTANCE.getEAnnotationValue(eAttribute.getEAttributeType(),
"http:///org/eclipse/emf/ecore/util/ExtendedMetaData", key);
}
return value;
}
/** Determines if mapped by should be set */
protected boolean setMappedBy(EReference eReference) {
// only set in two way relation
// if has not been set on the other side (mappedtoFields)
// if not a containment relation, containment relations are handled
// differently
// the other side may neither be containment
final EReference eOpposite = eReference.getEOpposite();
if (eOpposite == null) {
return false;
}
final PAnnotatedEReference aOpposite = getAnnotatedModel().getPAnnotated(eOpposite);
if (aOpposite.getOneToOne() != null && aOpposite.getOneToOne().getMappedBy() != null) {
return false;
}
return compareNames(eReference, eOpposite);
// &&
// !eReference.isContainment() && !eOpposite.isContainment();
}
/**
* Determines where to place a certain annotation/characteristic, this is done by comparing
* names..
*/
protected boolean compareNames(EReference here, EReference there) {
final String nameHere = here.eClass().getName() + here.getName();
final String nameThere = there.eClass().getName() + there.getName();
assert (nameHere.compareTo(nameThere) != 0);
return nameHere.compareTo(nameThere) > 0;
}
/**
* Checks if the cascade should be set in the cascade list, is only done if the list is empty
*/
protected void setCascade(List<CascadeType> cascadeList, boolean isContainment) {
if (!cascadeList.isEmpty()) {
return;
}
if (isContainment) {
if (getPersistenceOptions().isSetCascadeAllOnContainment()) {
cascadeList.add(CascadeType.ALL);
} else {
if (getPersistenceOptions().isSetCascadeRemoveOnContainment()) {
cascadeList.add(CascadeType.REMOVE);
}
if (getPersistenceOptions().isSetCascadeMergeOnContainment()) {
cascadeList.add(CascadeType.MERGE);
}
if (getPersistenceOptions().isSetCascadePersistOnContainment()) {
cascadeList.add(CascadeType.PERSIST);
}
if (getPersistenceOptions().isSetCascadeRefreshOnContainment()) {
cascadeList.add(CascadeType.REFRESH);
}
}
} else if (getPersistenceOptions().isSetCascadePolicyForNonContainment()) {
if (getPersistenceOptions().isSetCascadeMergeOnNonContainment()) {
cascadeList.add(CascadeType.MERGE);
}
if (getPersistenceOptions().isSetCascadePersistOnNonContainment()) {
cascadeList.add(CascadeType.PERSIST);
}
if (getPersistenceOptions().isSetCascadeRefreshOnNonContainment()) {
cascadeList.add(CascadeType.REFRESH);
}
} else {
cascadeList.add(CascadeType.MERGE);
cascadeList.add(CascadeType.PERSIST);
cascadeList.add(CascadeType.REFRESH);
}
}
protected void setTemporal(PAnnotatedEAttribute aAttribute, TemporalType defaultTemporal) {
final EAttribute eAttribute = aAttribute.getModelEAttribute();
Class<?> clazz = eAttribute.getEAttributeType().getInstanceClass();
// clazz is hidden somewhere
if (clazz == null || Object.class.equals(clazz)) {
ArrayList<EClassifier> eclassifiers =
EcoreDataTypes.INSTANCE.getItemTypes((EDataType) eAttribute.getEType());
for (EClassifier eclassifier : eclassifiers) {
if (eclassifier.getInstanceClass() != null) {
clazz = eclassifier.getInstanceClass();
break;
}
}
}
final EDataType eDataType = aAttribute.getModelEAttribute().getEAttributeType();
if (clazz != null &&
(Date.class.isAssignableFrom(clazz) || eDataType == XMLTypePackage.eINSTANCE.getDate() || eDataType == XMLTypePackage.eINSTANCE
.getDateTime())) {
final Temporal temporal = getFactory().createTemporal();
if (eDataType == XMLTypePackage.eINSTANCE.getDate()) {
temporal.setValue(TemporalType.DATE);
} else if (eDataType == XMLTypePackage.eINSTANCE.getDateTime()) {
temporal.setValue(TemporalType.TIMESTAMP);
} else {
temporal.setValue(defaultTemporal);
}
aAttribute.setTemporal(temporal);
temporal.setEModelElement(eAttribute);
} else if (clazz != null &&
(Calendar.class.isAssignableFrom(clazz) || eDataType == XMLTypePackage.eINSTANCE.getDate() || eDataType == XMLTypePackage.eINSTANCE
.getDateTime())) {
final Temporal temporal = getFactory().createTemporal();
if (eDataType == XMLTypePackage.eINSTANCE.getDate()) {
temporal.setValue(TemporalType.DATE);
} else if (eDataType == XMLTypePackage.eINSTANCE.getDateTime()) {
temporal.setValue(TemporalType.TIMESTAMP);
} else {
temporal.setValue(defaultTemporal);
}
aAttribute.setTemporal(temporal);
temporal.setEModelElement(eAttribute);
}
}
}