diff options
Diffstat (limited to 'core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/annotations')
37 files changed, 7376 insertions, 0 deletions
diff --git a/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/annotations/StoreAnnotationsException.java b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/annotations/StoreAnnotationsException.java new file mode 100755 index 000000000..86fb963d2 --- /dev/null +++ b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/annotations/StoreAnnotationsException.java @@ -0,0 +1,39 @@ +/** + * <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: + * StoreAnnotationsException.java,v 1.4 2007/02/01 12:35:03 mtaal Exp $ + */ + +package org.eclipse.emf.teneo.annotations; + +import org.eclipse.emf.teneo.TeneoException; + +/** + * Is thrown in the org.eclipse.emf.teneo.annotations package. Takes care of logging the cause. + * + * @author <a href="mailto:mtaal@elver.org">Martin Taal</a> + * @version $Revision: 1.2 $ + */ + +public class StoreAnnotationsException extends TeneoException { + /** + * Serial id + */ + private static final long serialVersionUID = 4685665979865102829L; + + /** + * The constructor, logs the exception also + */ + public StoreAnnotationsException(String msg, Throwable cause) { + super(msg, cause); + } + + /** + * The constructor, logs the exception also + */ + public StoreAnnotationsException(String msg) { + super(msg); + } +} diff --git a/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/annotations/mapper/AbstractAnnotator.java b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/annotations/mapper/AbstractAnnotator.java new file mode 100755 index 000000000..a09855927 --- /dev/null +++ b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/annotations/mapper/AbstractAnnotator.java @@ -0,0 +1,170 @@ +/** + * <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: AbstractAnnotator.java,v 1.7 2009/03/30 07:53:04 mtaal Exp $ + */ + +package org.eclipse.emf.teneo.annotations.mapper; + +import org.eclipse.emf.ecore.EClass; +import org.eclipse.emf.teneo.PersistenceOptions; +import org.eclipse.emf.teneo.annotations.pamodel.PAnnotatedModel; +import org.eclipse.emf.teneo.annotations.pannotation.PannotationFactory; +import org.eclipse.emf.teneo.extension.ExtensionInitializable; +import org.eclipse.emf.teneo.extension.ExtensionManager; +import org.eclipse.emf.teneo.extension.ExtensionManagerAware; +import org.eclipse.emf.teneo.mapping.strategy.EntityNameStrategy; +import org.eclipse.emf.teneo.mapping.strategy.SQLNameStrategy; +import org.eclipse.emf.teneo.mapping.strategy.StrategyUtil; + +/** + * The parent class of all annotator classes. + * + * @author <a href="mailto:mtaal@elver.org">Martin Taal</a> + * @version $Revision: 1.7 $ + */ + +public abstract class AbstractAnnotator implements ExtensionManagerAware, ExtensionInitializable { + + protected PannotationFactory factory = PannotationFactory.eINSTANCE; + private ExtensionManager extensionManager; + private PAnnotatedModel annotatedModel; + private SQLNameStrategy sqlNameStrategy; + private EntityNameStrategy entityNameStrategy; + private PersistenceOptions persistenceOptions; + private EFeatureAnnotator eFeatureAnnotator; + + /* + * (non-Javadoc) + * + * @see org.eclipse.emf.teneo.extension.ExtensionInitializable#initializeExtension () + */ + public void initializeExtension() { + sqlNameStrategy = getExtensionManager().getExtension(SQLNameStrategy.class); + entityNameStrategy = getExtensionManager().getExtension(EntityNameStrategy.class); + } + + /** Method is called after all the important members have been set */ + protected void initialize() { + + } + + /** + * Returns the entity name of the eclass, note that in case of maps a different approach is + * followed (the entity name of the value is returned. + */ + public String getEntityName(EClass eClass) { + return StrategyUtil.getEntityName(entityNameStrategy, persistenceOptions, annotatedModel, eClass); + } + + /** + * @return the extensionManager + */ + public ExtensionManager getExtensionManager() { + return extensionManager; + } + + /** + * @param extensionManager + * the extensionManager to set + */ + public void setExtensionManager(ExtensionManager extensionManager) { + this.extensionManager = extensionManager; + } + + /** + * @return the annotatedModel + */ + public PAnnotatedModel getAnnotatedModel() { + return annotatedModel; + } + + /** + * @param annotatedModel + * the annotatedModel to set + */ + public void setAnnotatedModel(PAnnotatedModel annotatedModel) { + this.annotatedModel = annotatedModel; + } + + /** + * @return the factory + */ + public PannotationFactory getFactory() { + return factory; + } + + /** + * @param factory + * the factory to set + */ + public void setFactory(PannotationFactory factory) { + this.factory = factory; + } + + /** + * @return the sqlNameStrategy + */ + public SQLNameStrategy getSqlNameStrategy() { + return sqlNameStrategy; + } + + /** + * @return the entityNameStrategy + */ + public EntityNameStrategy getEntityNameStrategy() { + return entityNameStrategy; + } + + /** + * @return the persistenceOptions + */ + public PersistenceOptions getPersistenceOptions() { + return persistenceOptions; + } + + /** + * @param persistenceOptions + * the persistenceOptions to set + */ + public void setPersistenceOptions(PersistenceOptions persistenceOptions) { + this.persistenceOptions = persistenceOptions; + } + + /** Creates an annotator and sets all kinds of default info */ + protected <T extends AbstractAnnotator> T createAnnotator(Class<T> clz) { + final T annotator = getExtensionManager().getExtension(clz); + annotator.setAnnotatedModel(annotatedModel); + annotator.setExtensionManager(getExtensionManager()); + annotator.setPersistenceOptions(persistenceOptions); + annotator.setFactory(getFactory()); + annotator.initialize(); + return annotator; + } + + /** + * @return the eFeatureAnnotator + */ + public EFeatureAnnotator getEFeatureAnnotator() { + return eFeatureAnnotator; + } + + /** + * @param featureAnnotator + * the eFeatureAnnotator to set + */ + public void setEFeatureAnnotator(EFeatureAnnotator featureAnnotator) { + eFeatureAnnotator = featureAnnotator; + } + +} diff --git a/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/annotations/mapper/AbstractProcessingContext.java b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/annotations/mapper/AbstractProcessingContext.java new file mode 100755 index 000000000..698859f60 --- /dev/null +++ b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/annotations/mapper/AbstractProcessingContext.java @@ -0,0 +1,364 @@ +/** + * <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: AbstractProcessingContext.java,v 1.10 2010/04/22 17:57:24 mtaal Exp $ + */ + +package org.eclipse.emf.teneo.annotations.mapper; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Stack; + +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.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.pamodel.PAnnotatedModel; +import org.eclipse.emf.teneo.annotations.pannotation.AssociationOverride; +import org.eclipse.emf.teneo.annotations.pannotation.AttributeOverride; +import org.eclipse.emf.teneo.annotations.pannotation.Column; +import org.eclipse.emf.teneo.annotations.pannotation.JoinColumn; + +/** + * ProcessingContext which handles attributes overrides. + * + * @author <a href="mailto:mtaal@elver.org">Martin Taal</a> + * @version $Revision: 1.10 $ + */ + +public class AbstractProcessingContext { + + /** The logger for all these exceptions */ + protected static final Log log = LogFactory + .getLog(AbstractProcessingContext.class); + + /** The current list of overrides */ + private Map<String, Object> currentOverrides = new HashMap<String, Object>(); + + /** + * Pushes the current overrides on the stack, to be popped later, this is to + * handle nested components + */ + private Stack<Map<String, Object>> overrideStack = new Stack<Map<String, Object>>(); + + /** + * Pushes the current embedding feature on the stack, to be popped later, + * this is to handle nested components and automatic renaming of props + */ + private Stack<PAnnotatedEStructuralFeature> embeddingFeatureStack = new Stack<PAnnotatedEStructuralFeature>(); + + /** + * Add attribute overrides, happens for each mapped superclass and each + * embedded component + */ + public void addAttributeOverrides(EList<AttributeOverride> aos) { + if (aos != null) { + for (AttributeOverride override : aos) { + currentOverrides.put(override.getName(), override.getColumn()); + } + } + } + + /** Add association overrides, for each mapped subclass */ + public void addAssociationOverrides(EList<AssociationOverride> overrides) { + if (overrides != null) { + for (AssociationOverride override : overrides) { + currentOverrides.put(override.getName(), override + .getJoinColumns()); + } + } + } + + /** + * Pushes the current overrides on the stack, to be popped later, this is to + * handle nested components + */ + public void pushOverrideOnStack() { + overrideStack.push(new HashMap<String, Object>(currentOverrides)); + } + + /** Pop the current overrides on the stack */ + public void popOverrideStack() { + currentOverrides = overrideStack.pop(); + } + + /** Pushes the current embedding feature on the stack */ + public void pushEmbeddingFeature(PAnnotatedEStructuralFeature er) { + embeddingFeatureStack.push(er); + } + + /** Pops the current embedding feature from the stack */ + public void popEmbeddingFeature() { + embeddingFeatureStack.pop(); + } + + /** Peeks for the current embedding feature */ + public PAnnotatedEStructuralFeature getEmbeddingFeature() { + if (embeddingFeatureStack.isEmpty()) { + return null; + } + return embeddingFeatureStack.peek(); + } + + /** Clear the override is done before an entity is processed */ + public void clearOverrides() { + currentOverrides.clear(); + } + + /** Return the overridden column for the passed attribute */ + public Column getAttributeOverride(PAnnotatedEStructuralFeature paFeature) { + return getAttributeOverride(paFeature.getModelElement().getName()); + } + + public Column getAttributeOverride(String featureName) { + return getAttributeOverride(featureName, -1); + } + + /** Return the overridden columns for the indicated featureName */ + public Column getAttributeOverride(String featureName, + int embeddingFeatureIndex) { + final Column c = (Column) currentOverrides.get(featureName); + if (c == null) { + final Object o = getFromStack(featureName); + if (o != null && o instanceof Column) { + return (Column) o; + } + // o == null, try one level deeper + if (embeddingFeatureIndex == -1 && !embeddingFeatureStack.isEmpty()) { + String newFeatureName = embeddingFeatureStack.peek() + .getModelElement().getName() + + "." + featureName; + return getAttributeOverride(newFeatureName, + embeddingFeatureStack.size() - 1); + } else if (embeddingFeatureIndex > 0) { + String newFeatureName = embeddingFeatureStack.get( + embeddingFeatureIndex - 1).getModelElement().getName() + + "." + featureName; + return getAttributeOverride(newFeatureName, + embeddingFeatureIndex - 1); + } + } + return c; + } + + /** Return the overridden JoinColumns for this reference */ + public List<JoinColumn> getAssociationOverrides( + PAnnotatedEReference paReference) { + return getAssociationOverrides(paReference.getModelEReference() + .getName()); + } + + public List<JoinColumn> getAssociationOverrides(String featureName) { + return getAssociationOverrides(featureName, -1); + } + + @SuppressWarnings("unchecked") + public List<JoinColumn> getAssociationOverrides(String featureName, + int embeddingFeatureIndex) { + final List<JoinColumn> jcs = (List<JoinColumn>) currentOverrides + .get(featureName); + if (jcs == null) { + final Object o = getFromStack(featureName); + if (o instanceof List<?>) { + return (List<JoinColumn>) o; + } + // o == null, try one level deeper + if (embeddingFeatureIndex == -1 && !embeddingFeatureStack.isEmpty()) { + String newFeatureName = embeddingFeatureStack.peek() + .getModelElement().getName() + + "." + featureName; + return getAssociationOverrides(newFeatureName, + embeddingFeatureStack.size() - 1); + } else if (embeddingFeatureIndex > 0) { + String newFeatureName = embeddingFeatureStack.get( + embeddingFeatureIndex - 1).getModelElement().getName() + + "." + featureName; + return getAssociationOverrides(newFeatureName, + embeddingFeatureIndex - 1); + } + } + return jcs; + } + + private Object getFromStack(String name) { + for (int i = (overrideStack.size() - 1); i >= 0; i--) { + final Map<String, Object> checkOverride = overrideStack.get(i); + final Object o = checkOverride.get(name); + if (o != null) { + return o; + } + } + return null; + } + + /** + * This method returns all inherited features which need to be added to the + * mapping of the aclass itself. The method makes a distinction makes a + * distinction between the first supertype (the first one in the list) and + * later ones. The features of the first type are only added to the mapping + * if the first type is a mappedsuperclass, in all other cases the features + * of the first type are not mapped in the aclass itself because they are + * inherited (the mapping describes the inheritance relation). For the other + * supertypes (located at index 1 and up in getESuperTypes) the features are + * mapped as properties in the class itself. The superEntity is the super + * aclass denoted as the real supertype extended by teneo. + */ + public List<PAnnotatedEStructuralFeature> getInheritedFeatures( + PAnnotatedEClass aClass) { + // if no supertypes then there are no inherited features + final EClass eclass = aClass.getModelEClass(); + if (eclass.getESuperTypes().size() == 0) { + return new ArrayList<PAnnotatedEStructuralFeature>(); + } + log.debug("Determining inherited features which are mapped locally for " + + aClass.getModelEClass().getName()); + final List<EStructuralFeature> inheritedFeatures = new ArrayList<EStructuralFeature>( + eclass.getEAllStructuralFeatures()); + + // remove all the features of the eclass itself + inheritedFeatures.removeAll(eclass.getEStructuralFeatures()); + + // check if the type has a supertype (a non-transient, + // non-mappedsuperclass, if so then + // remove all features inherited from the first supertype + // as this inheritance is done in the mapping file + if (aClass.getPaSuperEntity() != null) { + inheritedFeatures.removeAll(aClass.getPaSuperEntity() + .getModelEClass().getEAllStructuralFeatures()); + } + + // get all efeatures from direct mappedsuperclasses + // the id feature inherited from a direct mappedsuperclass should be + // maintained in other cases the id features are not mapped locally. + // The system can also ignore this and let the user be more carefull not + // to + // add id features here and there in the inheritance structure but this + // is + // more robust + removeIdFeatures(aClass, inheritedFeatures); + + // convert the result + final PAnnotatedModel paModel = aClass.getPaModel(); + final ArrayList<PAnnotatedEStructuralFeature> result = new ArrayList<PAnnotatedEStructuralFeature>(); + for (EStructuralFeature esf : inheritedFeatures) { + result.add(paModel.getPAnnotated(esf)); + } + + return result; + } + + /** + * Remove all id-features not inherited from a direct mapped superclass, and + * add the features from the mapped superclass + */ + private void removeIdFeatures(PAnnotatedEClass aClass, + List<EStructuralFeature> inheritedFeatures) { + // first get all the mapped superclasses + final ArrayList<EClass> mappedSuperEClasses = new ArrayList<EClass>(); + for (EClass superEClass : aClass.getModelEClass().getESuperTypes()) { + final PAnnotatedEClass superPAClass = aClass.getPaModel() + .getPAnnotated(superEClass); + if (superPAClass != null + && superPAClass.getMappedSuperclass() != null) { + mappedSuperEClasses.add(superPAClass.getModelEClass()); + } + } + + // now get all the efeatures of the mappedsuperclasses to prevent any id + // features from them being removed, only do that when the aclass does + // not + // have a real super type, in that case the id can be inherited from the + // mappedsuperclass + final ArrayList<EStructuralFeature> mappedSuperFeatures = new ArrayList<EStructuralFeature>(); + if (aClass.getPaSuperEntity() == null + || aClass.getPaSuperEntity().getMappedSuperclass() != null) { + for (EClass mappedSuperEClass : mappedSuperEClasses) { + mappedSuperFeatures.removeAll(mappedSuperEClass + .getEAllStructuralFeatures()); + mappedSuperFeatures.addAll(mappedSuperEClass + .getEAllStructuralFeatures()); + } + } + + // now remove all id features not coming from a direct mapped superclass + final ArrayList<EStructuralFeature> toRemove = new ArrayList<EStructuralFeature>(); + for (EStructuralFeature esf : inheritedFeatures) { + final PAnnotatedEStructuralFeature pef = aClass.getPaModel() + .getPAnnotated(esf); + + if (pef instanceof PAnnotatedEAttribute + && ((PAnnotatedEAttribute) pef).getId() != null + && !mappedSuperFeatures.contains(esf)) { + toRemove.add(esf); + } + } + inheritedFeatures.removeAll(toRemove); + } + + // + // /** Returns all mapped super classes */ + // public List<PAnnotatedEClass> getMappedSuperClasses(PAnnotatedEClass + // entity) { + // final List<PAnnotatedEClass> result = new ArrayList<PAnnotatedEClass>(); + // for (EClass superEClass : entity.getAnnotatedEClass().getESuperTypes()) { + // final PAnnotatedEClass superPAClass = entity.getPaModel() + // .getPAnnotated(superEClass); + // if (superPAClass != null + // && superPAClass.getMappedSuperclass() != null) { + // result.add(superPAClass); + // // and add the mapped super classes of the mapped superclass + // // note that only the unbroken chain of mappedsuperclasses is + // // added to the result, if there + // // is a non-mappedsuperclass in the inheritance then it stops + // // there + // // issue also identified by Douglas Bitting + // result.addAll(getMappedSuperClasses(superPAClass)); + // } + // } + // + // return result; + // } + + /** + * Returns true if the eclass only has mappedsuperclasses without id + * annotated property + */ + public boolean mustAddSyntheticID(PAnnotatedEClass entity) { + if (entity.hasIdAnnotatedFeature()) { + return false; + } + for (EClass superEClass : entity.getModelEClass().getEAllSuperTypes()) { + final PAnnotatedEClass superPAClass = entity.getPaModel() + .getPAnnotated(superEClass); + if (superPAClass != null + && superPAClass.getMappedSuperclass() == null) { + return false; + } else if (superPAClass != null + && superPAClass.getMappedSuperclass() != null) { + if (superPAClass.hasIdAnnotatedFeature()) { + return false; + } + } + } + + return true; + } +}
\ No newline at end of file diff --git a/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/annotations/mapper/AnnotationGenerator.java b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/annotations/mapper/AnnotationGenerator.java new file mode 100755 index 000000000..a50720554 --- /dev/null +++ b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/annotations/mapper/AnnotationGenerator.java @@ -0,0 +1,180 @@ +/** + * <copyright> + * + * Copyright (c) 2005, 2006, 2007, 2008 Springsite BV (The Netherlands) and others + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Martin Taal - Initial API and implementation + * + * </copyright> + * + * $Id: AnnotationGenerator.java,v 1.8 2010/03/02 21:43:57 mtaal Exp $ + */ + +package org.eclipse.emf.teneo.annotations.mapper; + +import java.util.List; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.eclipse.emf.ecore.EClass; +import org.eclipse.emf.ecore.EClassifier; +import org.eclipse.emf.ecore.EPackage; +import org.eclipse.emf.ecore.EStructuralFeature; +import org.eclipse.emf.ecore.EcorePackage; +import org.eclipse.emf.ecore.util.EcoreUtil; +import org.eclipse.emf.teneo.Constants; +import org.eclipse.emf.teneo.PersistenceOptions; +import org.eclipse.emf.teneo.annotations.pamodel.PAnnotatedEClass; +import org.eclipse.emf.teneo.annotations.pamodel.PAnnotatedEDataType; +import org.eclipse.emf.teneo.annotations.pamodel.PAnnotatedEPackage; +import org.eclipse.emf.teneo.annotations.pamodel.PAnnotatedModel; +import org.eclipse.emf.teneo.annotations.pannotation.PannotationFactory; +import org.eclipse.emf.teneo.ecore.EModelResolver; +import org.eclipse.emf.teneo.extension.ExtensionManager; +import org.eclipse.emf.teneo.extension.ExtensionManagerAware; +import org.eclipse.emf.teneo.extension.ExtensionPoint; +import org.eclipse.emf.teneo.mapping.strategy.EntityNameStrategy; +import org.eclipse.emf.teneo.mapping.strategy.SQLNameStrategy; + +/** + * Adds default annotations to an existing pamodel. Default annotations are added on the basis of + * the emf type information. It sets the default annotations according to the ejb3 spec. + * + * @author <a href="mailto:mtaal@elver.org">Martin Taal</a> + * @version $Revision: 1.8 $ + */ +public class AnnotationGenerator implements ExtensionPoint, ExtensionManagerAware { + + // The logger + protected static final Log log = LogFactory.getLog(AnnotationGenerator.class); + + protected PersistenceOptions persistenceOptions; + + // the extension manager + private ExtensionManager extensionManager; + + // Convenience link to pamodel factory + private final PannotationFactory aFactory = PannotationFactory.eINSTANCE; + + // The annotated model which is being processed + private PAnnotatedModel annotatedModel; + + // The annotators + private EClassAnnotator eClassAnnotator; + private EDataTypeAnnotator eDataTypeAnnotator; + + /** + * Adds default annotations to a pamodel, the method is synchronized because globals are set. + * Not necessary because this class should always be used single threaded but okay. + */ + public synchronized void map(PAnnotatedModel annotatedModel, PersistenceOptions po) { + + persistenceOptions = po; + + final List<PAnnotatedEPackage> apacks = annotatedModel.getPaEPackages(); + + final EPackage[] epacks = new EPackage[apacks.size()]; + int cnt = 0; + for (PAnnotatedEPackage apack : apacks) { + epacks[cnt++] = apack.getModelEPackage(); + } + + final EModelResolver eModelResolver = EModelResolver.instance(); + log.debug("Registering epackages in model resolver, modelresolver instance is: " + + eModelResolver.getClass().getName()); + eModelResolver.register(epacks); + + // if force fully classify typename then use the EModelResolver/ERuntime + if (persistenceOptions.isAlsoMapAsClass()) { + log.debug("Class names are to be fully classified, registering all the " + "epackages"); + // and now set the map as entity for each eclass + for (PAnnotatedEPackage apack : annotatedModel.getPaEPackages()) { + for (PAnnotatedEClass aclass : apack.getPaEClasses()) { + aclass.setOnlyMapAsEntity(!eModelResolver.hasImplementationClass(aclass.getModelEClass())); + } + } + } + + // solve a specific case of the EcorePackage going wrong for the + // eSuperTypes + // see bugzilla: https://bugs.eclipse.org/bugs/show_bug.cgi?id=205790 + for (EPackage epack : epacks) { + if (epack.getNsURI() != null && epack.getNsURI().compareTo(EcorePackage.eINSTANCE.getNsURI()) == 0) { + // now find the + for (EClassifier eClassifier : epack.getEClassifiers()) { + if (eClassifier.eClass() == EcorePackage.eINSTANCE.getEClass()) { + final EClass eClass = (EClass) eClassifier; + for (EStructuralFeature eFeature : eClass.getEAllStructuralFeatures()) { + if (eFeature.getName().compareTo("eSuperTypes") == 0) { + if (eFeature.getEAnnotation(Constants.ANNOTATION_SOURCE_TENEO_JPA) == null) { + EcoreUtil.setAnnotation(eFeature, Constants.ANNOTATION_SOURCE_TENEO_JPA, "value", "@ManyToMany"); + break; + } + } + } + } + } + } + } + + annotatedModel.setInitialized(true); + this.annotatedModel = annotatedModel; + + // initialize the strategies so they have the correct information + // TODO this should be handled in aware like interfaces + final EntityNameStrategy entityNameStrategy = extensionManager.getExtension(EntityNameStrategy.class); + entityNameStrategy.setPaModel(annotatedModel); // is maybe already set? + final SQLNameStrategy sqlNameStrategy = extensionManager.getExtension(SQLNameStrategy.class); + sqlNameStrategy.setPersistenceOptions(po); + + setAnnotators(); + for (PAnnotatedEPackage pae : annotatedModel.getPaEPackages()) { + processPackage(pae); + } + } + + /** Set the annotators */ + protected void setAnnotators() { + eClassAnnotator = createAnnotator(EClassAnnotator.class); + eDataTypeAnnotator = createAnnotator(EDataTypeAnnotator.class); + } + + /** Creates an annotator and sets all kinds of default info */ + private <T extends AbstractAnnotator> T createAnnotator(Class<T> clz) { + final T annotator = extensionManager.getExtension(clz); + annotator.setAnnotatedModel(annotatedModel); + annotator.setExtensionManager(extensionManager); + annotator.setPersistenceOptions(persistenceOptions); + annotator.setFactory(aFactory); + annotator.initialize(); + return annotator; + } + + /** Maps one epackage */ + protected void processPackage(PAnnotatedEPackage aPackage) { + log.debug(">>>> Adding default annotations for EPackage " + aPackage.getModelElement().getName()); + + log.debug("Processing EDataTypes"); + for (PAnnotatedEDataType annotatedEDataType : aPackage.getPaEDataTypes()) { + eDataTypeAnnotator.annotate(annotatedEDataType); + } + + log.debug("Processing EClasses"); + for (PAnnotatedEClass annotatedEClass : aPackage.getPaEClasses()) { + eClassAnnotator.annotate(annotatedEClass); + } + } + + /** + * @param extensionManager + * the extensionManager to set + */ + public void setExtensionManager(ExtensionManager extensionManager) { + this.extensionManager = extensionManager; + } +}
\ No newline at end of file diff --git a/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/annotations/mapper/BaseEFeatureAnnotator.java b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/annotations/mapper/BaseEFeatureAnnotator.java new file mode 100755 index 000000000..b26d54445 --- /dev/null +++ b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/annotations/mapper/BaseEFeatureAnnotator.java @@ -0,0 +1,336 @@ +/** + * <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.17 2010/08/18 12:56:38 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.17 $ + */ + +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) + * + * @seeorg.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) { + + // disabled because of bugzilla: + // 317479 +// if (aAttribute.getId() != null) { +// aAttribute.getModelEAttribute().setLowerBound(1); +// } + + 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); + } + + // disable unique constraint as the uniqueness is covered by the primary + // key + // constraints. See issue 280169 + if (c != null && aAttribute.getId() != null) { + c.setUnique(false); + } + } + + 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); + } + } +} diff --git a/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/annotations/mapper/BasicPamodelBuilder.java b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/annotations/mapper/BasicPamodelBuilder.java new file mode 100755 index 000000000..5ce949aa7 --- /dev/null +++ b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/annotations/mapper/BasicPamodelBuilder.java @@ -0,0 +1,363 @@ +/** + * <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 + * Davide Marchignoli + * </copyright> + * + * $Id: BasicPamodelBuilder.java,v 1.7 2009/07/27 22:09:46 mtaal Exp $ + */ + +package org.eclipse.emf.teneo.annotations.mapper; + +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.ENamedElement; +import org.eclipse.emf.ecore.EPackage; +import org.eclipse.emf.ecore.EStructuralFeature; +import org.eclipse.emf.ecore.EcorePackage; +import org.eclipse.emf.teneo.annotations.pamodel.PAnnotatedEClass; +import org.eclipse.emf.teneo.annotations.pamodel.PAnnotatedEDataType; +import org.eclipse.emf.teneo.annotations.pamodel.PAnnotatedEModelElement; +import org.eclipse.emf.teneo.annotations.pamodel.PAnnotatedEPackage; +import org.eclipse.emf.teneo.annotations.pamodel.PAnnotatedEStructuralFeature; +import org.eclipse.emf.teneo.annotations.pamodel.PAnnotatedModel; +import org.eclipse.emf.teneo.annotations.pamodel.PamodelFactory; +import org.eclipse.emf.teneo.extension.ExtensionPoint; + +/** + * Convience class for building a <code>PAnnotatedModel</code>. + * + * @author <a href="mailto:marchign at elver.org">Davide Marchignoli</a> + */ +public class BasicPamodelBuilder implements ExtensionPoint { + + private PAnnotatedModel target = null; + + /** + * Uses an empty freshly instantiated PAnnotatedModel as target. + */ + public BasicPamodelBuilder() { + setPAnnotatedModel(createPAnnotatedModel()); + } + + /** Create the pAnnotatedModel */ + public PAnnotatedModel createPAnnotatedModel() { + return PamodelFactory.eINSTANCE.createPAnnotatedModel(); + } + + /** + * Uses the given PAnnotatedMmodel as target. + */ + public BasicPamodelBuilder(PAnnotatedModel target) { + setPAnnotatedModel(target); + } + + /** + * Sets the target PAnnotatedModel + */ + public void setPAnnotatedModel(PAnnotatedModel target) { + this.target = target; + } + + /** + * @return the target model. + */ + public PAnnotatedModel getPAnnotatedModel() { + return target; + } + + /** + * @return a <code>PAnnotatedModelElement</code> assoiciated to the given <code>EModelElement</code>. The element is + * created only if not already present in the model. + */ + protected PAnnotatedEModelElement create(EModelElement eModelElement) { + PAnnotatedEModelElement paElement = target.getPAnnotated(eModelElement); + if (paElement == null) { + // Factor out actual model creation so that extensions can create + // their + // own model elements. + paElement = doCreate(eModelElement); + } + return paElement; + } + + /** + * @return A newly created PAnnotatedEModelElement. This method is only responsible for the actual creation (and + * initialization) of this object. No other logic should happen here. This allows subclasses to alter how + * objects are created. If you'd like to alter any other logic around the creation, you should override the + * <code>create</code> method(s). + * @throws AssertionError + */ + protected PAnnotatedEModelElement doCreate(EModelElement eModelElement) throws AssertionError { + final EClass eModelElementEClass = eModelElement.eClass(); + PAnnotatedEModelElement paElement; + switch (eModelElementEClass.getClassifierID()) { + case EcorePackage.EATTRIBUTE: + paElement = PamodelFactory.eINSTANCE.createPAnnotatedEAttribute(); + break; + case EcorePackage.EREFERENCE: + paElement = PamodelFactory.eINSTANCE.createPAnnotatedEReference(); + break; + case EcorePackage.ECLASS: + paElement = PamodelFactory.eINSTANCE.createPAnnotatedEClass(); + break; + case EcorePackage.EPACKAGE: + paElement = PamodelFactory.eINSTANCE.createPAnnotatedEPackage(); + break; + case EcorePackage.EENUM: + case EcorePackage.EDATA_TYPE: + paElement = PamodelFactory.eINSTANCE.createPAnnotatedEDataType(); + break; + default: + throw new AssertionError("Trying to build PAnnotatedEModelElement for a " + eModelElementEClass); + } + paElement.setModelElement((ENamedElement) eModelElement); + return paElement; + } + + /** + * @return a <code>PAnnotatedEPackage</code> associated to the given <code>EPackage</code> and adds it the model. + * <p> + * The <code>PAnnotatedEPackage</code> is created only if not already present in the model. + */ + public PAnnotatedEPackage pElement(EPackage ePackage) { + PAnnotatedEPackage pPackage = (PAnnotatedEPackage) create(ePackage); + if (pPackage.eContainer() == null) { + target.getPaEPackages().add(pPackage); + } + return pPackage; + } + + /** + * @return a <code>PAnnotatedEClass</code> associated to the given <code>EClass</code> and adds it the model. + * <p> + * The <code>PAnnotatedEClass</code> is created only if not already present in the model. + * <p> + * The operation may involve the creation of a <code>PAnnotatedEPackage</code> associated to the given + * <code>EClass</code> package. + */ + protected PAnnotatedEClass pElement(EClass eClass) { + PAnnotatedEClass pClass = (PAnnotatedEClass) create(eClass); + pElement(eClass.getEPackage()).getPaEClasses().add(pClass); + return pClass; + } + + /** + * @return a <code>PAnnotatedEStructuralFeature</code> associated to the given <code>EStructuralFeature</code> and + * adds it the model. + * <p> + * The <code>PAnnotatedEStructuralFeature</code> is created only if not already present in the model. + * <p> + * The operation may involve the creation of a <code>PAnnotatedEPackage</code> and a + * <code>PAnnotatedEClass</code>. + */ + protected PAnnotatedEModelElement pElement(EStructuralFeature eFeature) { + PAnnotatedEStructuralFeature pFeature = (PAnnotatedEStructuralFeature) create(eFeature); + pElement(eFeature.getEContainingClass()).getPaEStructuralFeatures().add(pFeature); + return pFeature; + } + + /** + * @return a <code>PAnnotatedEStructuralFeature</code> associated to the given <code>EStructuralFeature</code> and + * adds it the model. + * <p> + * The <code>PAnnotatedEStructuralFeature</code> is created only if not already present in the model. + * <p> + * The operation may involve the creation of a <code>PAnnotatedEPackage</code> and a + * <code>PAnnotatedEClass</code>. + */ + protected PAnnotatedEDataType pElement(EDataType eDataType) { + PAnnotatedEDataType pDataType = (PAnnotatedEDataType) create(eDataType); + pElement(eDataType.getEPackage()).getPaEDataTypes().add(pDataType); + return pDataType; + } + + /** + * @return a <code>PAnnotatedEModelElement</code> associated to the given <code>EModelElement</code> and adds it the + * model. + * @see #pElement(EPackage) + * @see #pElement(EClass) + * @see #pElement(EStructuralFeature) + */ + protected PAnnotatedEModelElement pElement(final EModelElement eElement) throws AssertionError { + PAnnotatedEModelElement pElement = null; + switch (eElement.eClass().getClassifierID()) { + case EcorePackage.EATTRIBUTE: + case EcorePackage.EREFERENCE: + pElement = pElement((EStructuralFeature) eElement); + break; + case EcorePackage.ECLASS: + pElement = pElement((EClass) eElement); + break; + case EcorePackage.EPACKAGE: + pElement = pElement((EPackage) eElement); + break; + case EcorePackage.EDATA_TYPE: + pElement = pElement((EDataType) eElement); + break; + default: + throw new AssertionError("Trying to build PAnnotatedEModelElement for a " + eElement.eClass()); + } + return pElement; + } + + /** + * Builds a <code>PAnnotatedEPackage</code> associated to the given <code>EPackage</code> (if such an + * <code>PAnnotatedEPackage</code> does not yet exists) and adds it to the target model. + */ + public void add(EPackage ePackage) { + pElement(ePackage); + } + + /** + * Builds a <code>PAnnotatedEClass</code> associated to the given <code>EClass</code> (if such an + * <code>PAnnotatedEClass</code> does not yet exists) and adds it to the target model. + * + * <p> + * The creation of a new <code>PAnnotatedEClass</code> may involve the creation of a <code>PAnnotatedEPackage</code> + * associated to the containing <code>EPackage</code> of the given class. + */ + public void add(EClass eClass) { + pElement(eClass); + } + + /** + * Add to the the target model a new <code>PAnnotatedEStructuralFeature</code> refering to the given + * EStructuralFeature. + * + * <p> + * A PAnnotatedEClass and a PAnnotatedEPackage for the containing EClass and EPackage are added if needed. + * + * <p> + * The added element have no annotations. Elements for which a corresponding PAnnotatedElement is already present in + * the target model are ignored. + */ + public void add(EStructuralFeature eFeature) { + pElement(eFeature); + } + + /** + * Add the given annotation to the given PAnnotatedEModelElement. + * + * @throws IllegalArgumentException + * if the given PAnnotation is not admitted for the given PAnnotatedEModelElement. protected void + * setPAnnotation(PAnnotatedEModelElement pElement, PAnnotation pAnnotation) { EReference pAnnotationRef + * = PamodelPackage.eINSTANCE .pAnnotationReference(pElement.eClass(), pAnnotation.eClass()); if + * (pAnnotationRef == null) throw new IllegalArgumentException("PAnnotation of type '" + + * pAnnotation.eClass() + "' does not apply to elements of type '" + pElement.eClass() + "'"); + * pElement.eSet(pAnnotationRef, pAnnotation); } + */ + + /** + * Add the given PAnnotation to the target model. + * + * <p> + * This operation may involve the addition to the model of a newly created PAnnotatedEModelElement for the + * PAnnotation EModelElement. + * + * @throws NullPointerException + * if either <code>pAnnotation</code> or <code>pAnnotation.getEModelElement()</code> are null. + * @throws IllegalArgumentException + * if the given <code>PAnnotation</code> references an invalid <code>PAnnotatedElement</code> public + * void add(PAnnotation pAnnotation) { PAnnotatedEModelElement pElement = + * pElement(pAnnotation.getEModelElement()); setPAnnotation(pElement, pAnnotation); } + */ + + /** + * Add to the the target model a new PAnnotatedPackage refering to the given EPackage. Recursively adds a + * PAnnotatedEClass for each EClass in the given EPackage (see {@link addEClass}). + * + * <p> + * The added elements have no annotations. Elements for which a corresponding PAnnotatedElement is already present + * in the target model are ignored. + */ + public void addRecurse(EPackage ePackage) { + PAnnotatedEPackage paPackage = pElement(ePackage); + for (EClassifier eClassifier : ePackage.getEClassifiers()) { + if (eClassifier instanceof EClass) { + addRecurse(paPackage, (EClass) eClassifier); + } else if (eClassifier instanceof EDataType) { + pElement((EDataType) eClassifier); + } + } + } + + /** + * used by {@link #addRecurse(EPackage)} to avoid recomputing the container multiple times. + */ + protected void addRecurse(PAnnotatedEPackage paPackage, EClass eClass) { + PAnnotatedEClass paClass = (PAnnotatedEClass) create(eClass); + if (paClass.eContainer() == null) { + paPackage.getPaEClasses().add(paClass); + } + for (EStructuralFeature eStructuralFeature : eClass.getEStructuralFeatures()) { + add(paClass, eStructuralFeature); + } + } + + /** + * Adds only this eClass and its EPackage to the pamodel + * + * @param eClass + */ + public void addSpecificEClass(EClass eClass) { + final EPackage ePackage = eClass.getEPackage(); + PAnnotatedEPackage paPackage = null; + for (PAnnotatedEPackage aPackage : target.getPaEPackages()) { + if (aPackage.getModelEPackage() == ePackage) { + paPackage = aPackage; + break; + } + } + if (paPackage == null) { + paPackage = pElement(ePackage); + addRecurse(paPackage, eClass); + } else { + boolean alreadyDefined = false; + for (PAnnotatedEClass paClass : paPackage.getPaEClasses()) { + if (paClass.getModelEClass() == eClass) { + alreadyDefined = true; + } + } + if (!alreadyDefined) { + addRecurse(paPackage, eClass); + } + } + } + + /** + * Add to the the target model a new PAnnotatedPackage refering to the given EClass. Recursively adds a + * PAnnotatedEStructuralFeature for each EStructuralFeature in the given EClass (see {@link addEStructuralFeature} + * ). + * + * <p> + * A PAnnotatedEPackage for the containng EPackage is added if needed. + * + * <p> + * The added elements have no annotations. + * + * <p> + * Elements for which a corresponding PAnnotatedElement is already present in the target model are ignored. public + * void addRecurse(EClass eClass) { addRecurse((PAnnotatedEPackage) pElement(eClass), eClass); } + */ + + /** + * used by {@link #addRecurse(EClass)} to avoid recomputing the container multiple times. + */ + protected void add(PAnnotatedEClass paClass, EStructuralFeature eFeature) { + PAnnotatedEStructuralFeature paFeature = (PAnnotatedEStructuralFeature) create(eFeature); + if (paFeature.eContainer() == null) { + paClass.getPaEStructuralFeatures().add(paFeature); + } + } +} diff --git a/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/annotations/mapper/BidirectionalManyToManyAnnotator.java b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/annotations/mapper/BidirectionalManyToManyAnnotator.java new file mode 100755 index 000000000..a5e321c3c --- /dev/null +++ b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/annotations/mapper/BidirectionalManyToManyAnnotator.java @@ -0,0 +1,133 @@ +/** + * <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: BidirectionalManyToManyAnnotator.java,v 1.10 2009/03/30 07:53:04 mtaal Exp $ + */ + +package org.eclipse.emf.teneo.annotations.mapper; + +import java.util.List; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.eclipse.emf.ecore.EReference; +import org.eclipse.emf.teneo.annotations.pamodel.PAnnotatedEReference; +import org.eclipse.emf.teneo.annotations.pannotation.JoinTable; +import org.eclipse.emf.teneo.annotations.pannotation.ManyToMany; +import org.eclipse.emf.teneo.extension.ExtensionPoint; + +/** + * Annotates a bidirectional many-to-many ereference. + * + * @author <a href="mailto:mtaal@elver.org">Martin Taal</a> + * @version $Revision: 1.10 $ + */ + +public class BidirectionalManyToManyAnnotator extends BaseEFeatureAnnotator implements ExtensionPoint { + + // The logger + protected static final Log log = LogFactory.getLog(BidirectionalManyToManyAnnotator.class); + + /** Process the features of the eclass */ + public void annotate(PAnnotatedEReference aReference) { + final String featureLogStr = + aReference.getModelEReference().getName() + "/" + + aReference.getModelEReference().getEContainingClass().getName(); + + if (aReference.getOneToMany() != null || aReference.getOneToOne() != null || aReference.getManyToOne() != null) { + throw new StoreMappingException("The feature/eclass " + featureLogStr + " should be a ManyToMany but " + + "it already has a OneToMany, OneToOne or ManyToOne annotation"); + } + + final EReference eReference = (EReference) aReference.getModelElement(); + final EReference eOpposite = eReference.getEOpposite(); + assert (eOpposite != null && eOpposite.isMany()); + + ManyToMany mtm = aReference.getManyToMany(); + final boolean mtmWasSet = mtm != null; // mtm was set manually + if (mtm == null) { + log.debug("Adding manytomany annotations to ereference: " + featureLogStr); + mtm = getFactory().createManyToMany(); + aReference.setManyToMany(mtm); + mtm.setEModelElement(eReference); + } else { + log.debug("ManyToMany present check if default information should be added"); + } + + if (eReference.isContainment() || getPersistenceOptions().isSetDefaultCascadeOnNonContainment()) { + setCascade(mtm.getCascade(), eReference.isContainment()); + } + + if (mtm.getTargetEntity() == null) { + mtm.setTargetEntity(getEntityName(eReference.getEReferenceType())); + } + + if (getPersistenceOptions().isSetForeignKeyNames() && aReference.getForeignKey() == null) { + aReference.setForeignKey(createFK(aReference)); + } + + // determine where to place the jointable annotation and where to place + // the mappedby + // use a certain logic to determine as each is only set on one side + // note that the join is always set on the other side of mapped by! + // note that we can not do setJoinHere = !setMappedByHere because there + // are situations + // that even for mtm no mappedby is set on either side, nl. in case of + // containment + + // also check if the other side has a (manual) manytomany with mappedby + // set + // bugzilla: 164808 + final PAnnotatedEReference otherPA = aReference.getPaModel().getPAnnotated(eOpposite); + if (mtm.getMappedBy() == null && setMappedBy(eReference) && + (otherPA.getManyToMany() == null || otherPA.getManyToMany().getMappedBy() == null)) { + mtm.setMappedBy(eOpposite.getName()); + } + + JoinTable joinTable = aReference.getJoinTable(); + if (joinTable == null) { + joinTable = getFactory().createJoinTable(); + aReference.setJoinTable(joinTable); + } + joinTable.setEModelElement(eReference); + + // set unique and indexed + // disabled because indexed = false now for mtm, + // to overcome this the user has to explicitly set a mtm annotation. + if (!mtmWasSet) { + log.debug("Setting indexed and unique from ereference.isOrdered/isUnique " + + "because mtm was not set manually!"); + mtm.setIndexed(!getPersistenceOptions().alwaysMapListAsBag() && eReference.isOrdered()); + } + + // NOTE that the ejb3 spec states that the jointable should be the + // concatenation of the + // tablenames of the owning entities with an underscore, this will + // quickly lead to nameclashes + // in the case there is more than one relation between two classes. This + // can be pretty likely + // if the inheritance strategy is single_table. + // now possibility to use a different naming strategy + if (joinTable.getName() == null) { + joinTable.setName(getSqlNameStrategy().getJoinTableName(aReference)); + } + if (joinTable.getJoinColumns().size() == 0) { + final List<String> names = getSqlNameStrategy().getJoinTableJoinColumns(aReference, false); + joinTable.getJoinColumns().addAll(getJoinColumns(names, false, true, mtm)); + } + if (joinTable.getInverseJoinColumns().size() == 0) { + final List<String> names = getSqlNameStrategy().getJoinTableJoinColumns(aReference, true); + joinTable.getInverseJoinColumns().addAll(getJoinColumns(names, false, true, mtm)); + } + } +} diff --git a/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/annotations/mapper/EClassAnnotator.java b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/annotations/mapper/EClassAnnotator.java new file mode 100755 index 000000000..9260e4b76 --- /dev/null +++ b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/annotations/mapper/EClassAnnotator.java @@ -0,0 +1,414 @@ +/** + * <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: EClassAnnotator.java,v 1.20 2009/10/31 07:10:35 mtaal Exp $ + */ + +package org.eclipse.emf.teneo.annotations.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.common.util.EList; +import org.eclipse.emf.ecore.EClass; +import org.eclipse.emf.ecore.util.ExtendedMetaData; +import org.eclipse.emf.teneo.PersistenceOptions; +import org.eclipse.emf.teneo.annotations.StoreAnnotationsException; +import org.eclipse.emf.teneo.annotations.pamodel.PAnnotatedEClass; +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.Entity; +import org.eclipse.emf.teneo.annotations.pannotation.Inheritance; +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.mapping.strategy.StrategyUtil; + +/** + * Sets the annotation on an eclass. + * + * @author <a href="mailto:mtaal@elver.org">Martin Taal</a> + * @version $Revision: 1.20 $ + */ + +public class EClassAnnotator extends AbstractAnnotator implements ExtensionPoint { + + // The logger + protected static final Log log = LogFactory.getLog(EClassAnnotator.class); + + private InheritanceType optionDefaultInheritanceMapping = InheritanceType.SINGLE_TABLE; + + // The list of processed eclasses, is used to ensure that a superclass is + // done before a subclass + private final ArrayList<PAnnotatedEClass> processedAClasses = new ArrayList<PAnnotatedEClass>(); + + private EFeatureAnnotator eFeatureAnnotator = null; + + /** + * Returns the annotated version of an EClass, Returns false if no efeatures of this eclass should be annotated, + * true if its features can be annotated. + */ + protected boolean annotate(PAnnotatedEClass aClass) { + if (aClass == null) { + throw new StoreAnnotationsException( + "Mapping Exception, no Annotated Class for EClass, " + + "a common cause is that you did not register all EPackages in the DataStore/Helper Class. " + + "When there are references between EClasses in different EPackages then they need to be handled in one DataStore/Helper Class."); + } + + final EClass eclass = (EClass) aClass.getModelElement(); + + // check if already processed + if (processedAClasses.contains(aClass)) { + return false; + } + + // do not process the document root + if (!getPersistenceOptions().isMapDocumentRoot() && ExtendedMetaData.INSTANCE.isDocumentRoot(eclass)) { + return false; + } + + log.debug("Creating mapping for eclass " + eclass.getName()); + + // first do the superclasses + for (EClass superEclass : aClass.getModelEClass().getESuperTypes()) { + final PAnnotatedEClass superAClass = aClass.getPaModel().getPAnnotated(superEclass); + if (superAClass == null) { + throw new StoreAnnotationsException( + "Mapping Exception, no Annotated Class for EClass: " + + superEclass.getName() + + " a common cause is that you did not register all EPackages in the DataStore/Helper Class. " + + "When there are references between EClasses in different EPackages then they need to be handled in one DataStore/Helper Class."); + } + if (!processedAClasses.contains(superAClass)) { + annotate(superAClass); + if (superAClass.getEavMapping() != null) { + aClass.setEavMapping(PannotationFactory.eINSTANCE.createEAVMapping()); + } + } + } + + if (getPersistenceOptions().isEAVMapping() && aClass.getNoEAVMapping() == null) { + aClass.setEavMapping(PannotationFactory.eINSTANCE.createEAVMapping()); + } + + log.debug(" Adding default annotations for EClass: " + aClass.getModelElement().getName()); + + processedAClasses.add(aClass); + + log.debug("Setting the superentity of the eclass"); + setSuperEntity(aClass); + final boolean isInheritanceRoot = aClass.getPaSuperEntity() == null + || aClass.getPaSuperEntity().getMappedSuperclass() != null; // last + + // force single table + if (isInheritanceRoot && aClass.getEavMapping() != null) { + final Inheritance inheritance = PannotationFactory.eINSTANCE.createInheritance(); + inheritance.setStrategy(InheritanceType.SINGLE_TABLE); + aClass.setInheritance(inheritance); + } + + // A not mappable type will not get an entity annotation. + // Even the features of non-mappable types are mapped because + // the efeatures can be inherited through multiple inheritance + final boolean mappable = isMappableAnnotatedClass(aClass); + + // add entity or set entity name + if (mappable && aClass.getEntity() == null && aClass.getEmbeddable() == null) { + Entity entity = getFactory().createEntity(); + entity.setEModelElement(eclass); + aClass.setEntity(entity); + } + if (aClass.getEntity() != null && aClass.getEntity().getName() == null) { + aClass.getEntity().setName(getEntityNameStrategy().toEntityName(eclass)); + } + // if (aClass.getEavMapping() != null && EModelResolver.instance().getJavaClass(aClass.getModelEClass()) != + // null) { + // aClass.getEntity().setName(EModelResolver.instance().getJavaClass(aClass.getModelEClass()).getName()); + // } + + // get the inheritance from the supertype or use the global inheritance + // setting + // Note only an 'entitied' root gets an inheritance annotation. This is + // according to the spec. + final InheritanceType inheritanceType; + if (aClass.getInheritance() != null) { + inheritanceType = aClass.getInheritance().getStrategy(); + } else { + // get the inheritance from the supers, if defined there + final Inheritance inheritanceFromSupers = getInheritanceFromSupers(aClass); + inheritanceType = inheritanceFromSupers != null ? inheritanceFromSupers.getStrategy() + : optionDefaultInheritanceMapping; + // if this is the root then add a specific inheritance annotation + if (isInheritanceRoot) { + final Inheritance inheritance = getFactory().createInheritance(); + inheritance.setStrategy(inheritanceType); + inheritance.setEModelElement(eclass); + aClass.setInheritance(inheritance); + } + } + + // add PrimaryKeyJoinColumn in case of a joined + if (!isInheritanceRoot && inheritanceType.equals(InheritanceType.JOINED) + && aClass.getPrimaryKeyJoinColumns().size() == 0) { + ArrayList<String> idFeatures = new ArrayList<String>(); + PAnnotatedEClass aSuperClass = null; + for (EClass eSuperClass : aClass.getModelEClass().getESuperTypes()) { + aSuperClass = getAnnotatedModel().getPAnnotated(eSuperClass); + idFeatures.addAll(StrategyUtil.getIDFeaturesNames(aSuperClass, getPersistenceOptions() + .getDefaultIDFeatureName())); + if (!idFeatures.isEmpty()) { + break; + } + } + + for (String idFeature : idFeatures) { + final PrimaryKeyJoinColumn pkjc = getFactory().createPrimaryKeyJoinColumn(); + pkjc.setName(getSqlNameStrategy().getPrimaryKeyJoinColumnName(aSuperClass, idFeature)); + aClass.getPrimaryKeyJoinColumns().add(pkjc); + } + } + + // add the table annotation or the name annotation of the table + // only do this if this is the root in case of singletable or when this + // is the joined table strategy + if (aClass.getTable() == null + && ((isInheritanceRoot && inheritanceType.equals(InheritanceType.SINGLE_TABLE)) + || inheritanceType.equals(InheritanceType.JOINED) || inheritanceType + .equals(InheritanceType.TABLE_PER_CLASS))) { + final Table table = getFactory().createTable(); + table.setEModelElement(eclass); + // name is set in next step + aClass.setTable(table); + } + if (aClass.getTable() != null && aClass.getTable().getName() == null) { + aClass.getTable().setName(getSqlNameStrategy().getTableName(aClass)); + } + + if (addDiscriminator(aClass)) { + // For hibernate as well as jpox the discriminator column is only + // required for single table, the ejb3 spec does not make a clear + // statement about the requirement to also have a discriminator + // column for joined + if (isInheritanceRoot && aClass.getDiscriminatorColumn() == null + && inheritanceType.equals(InheritanceType.SINGLE_TABLE)) { + // note defaults of primitive types are all defined in the model + final DiscriminatorColumn dc = getFactory().createDiscriminatorColumn(); + dc.setEModelElement(eclass); + dc.setName(getSqlNameStrategy().getDiscriminatorColumnName()); + aClass.setDiscriminatorColumn(dc); + } + if (aClass.getDiscriminatorColumn() != null) { + if (aClass.getDiscriminatorColumn().getColumn() == null) { + final DiscriminatorColumn dc = aClass.getDiscriminatorColumn(); + final Column col = getFactory().createColumn(); + dc.setColumn(col); + col.setName(dc.getName()); + col.setIndex(aClass.getTable().getName() + dc.getName()); + col.setNullable(false); + } + if (aClass.getDiscriminatorColumn().getColumn().getName() == null) { + aClass.getDiscriminatorColumn().getColumn().setName(aClass.getDiscriminatorColumn().getName()); + } + } + + // add a discriminator value + if (aClass.getDiscriminatorValue() == null && inheritanceType.equals(InheritanceType.SINGLE_TABLE)) { + final DiscriminatorValue dv = getFactory().createDiscriminatorValue(); + + final DiscriminatorColumn dc = getDiscriminatorColumn(aClass); + if (dc != null && dc.getDiscriminatorType() != null + && dc.getDiscriminatorType().getValue() == DiscriminatorType.INTEGER_VALUE) { + + // use the entityname to translate to an int value, + // hopefully hashcode is more or less unique... + final String entityName = getEntityName(eclass); + log + .warn("Generating an integer discriminator value for entity " + + entityName + + ". The hashcode of the entityName is used as the discriminatorvalue. This may not be unique! To ensure uniques you should set a @DiscriminatorValue annotation"); + dv.setValue("" + entityName.hashCode()); + } else { + dv.setValue(getEntityName(eclass)); + } + dv.setEModelElement(eclass); + aClass.setDiscriminatorValue(dv); + } + } + + // Add default PkJoinColumns for SecondaryTables. + for (SecondaryTable secondaryTable : aClass.getSecondaryTables()) { + final EList<PrimaryKeyJoinColumn> pkJoinColumns = secondaryTable.getPkJoinColumns(); + if (pkJoinColumns.size() == 0) { + // No PkJoinColumns configured for this secondary table, so + // populate with defaults based on the ID + // attributes of the primary table. + final List<PAnnotatedEStructuralFeature> aIdFeatures = aClass.getPaIdFeatures(); + for (PAnnotatedEStructuralFeature idef : aIdFeatures) { + final PrimaryKeyJoinColumn pkJoinColumn = PannotationFactory.eINSTANCE.createPrimaryKeyJoinColumn(); + pkJoinColumn.setName(getSqlNameStrategy().getSecondaryTablePrimaryKeyJoinColumnName(idef)); + pkJoinColumns.add(pkJoinColumn); + } + } + } + + for (PAnnotatedEStructuralFeature aStructuralFeature : aClass.getPaEStructuralFeatures()) { + eFeatureAnnotator.annotate(aStructuralFeature); + } + return true; + } + + protected boolean addDiscriminator(PAnnotatedEClass aClass) { + return true; + } + + // finds the DiscriminatorColumn in the aClass or its super entities + protected DiscriminatorColumn getDiscriminatorColumn(PAnnotatedEClass aClass) { + if (aClass.getDiscriminatorColumn() != null) { + return aClass.getDiscriminatorColumn(); + } + + // or use aClass.getPaMappedSupers()? + if (aClass.getPaSuperEntity() != null) { + return getDiscriminatorColumn(aClass.getPaSuperEntity()); + } + return null; + } + + /** Sets the {@link EFeatureAnnotator} */ + @Override + protected void initialize() { + super.initialize(); + eFeatureAnnotator = createAnnotator(EFeatureAnnotator.class); + } + + /** + * Returns the inheritance of the passed annotated class or from one of its super annotated class + */ + protected Inheritance getInheritanceFromSupers(PAnnotatedEClass childPA) { + if (childPA == null) { + return null; + } + if (childPA.getInheritance() != null) { + return childPA.getInheritance(); + } + return getInheritanceFromSupers(childPA.getPaSuperEntity()); + } + + /** Set the super entity */ + protected void setSuperEntity(PAnnotatedEClass aClass) { + assert (aClass.getPaSuperEntity() == null); + final EClass eclass = aClass.getModelEClass(); + if (eclass.getESuperTypes().size() == 0) { + return; + } + // check for overridden using extends + if (aClass.getEntity() != null && aClass.getEntity().getExtends() != null) { + final EClass superEClass = aClass.getPaModel().getEClass(aClass.getEntity().getExtends()); + final PAnnotatedEClass superAClass = aClass.getPaModel().getPAnnotated(superEClass); + if (!processedAClasses.contains(superAClass)) { + annotate(superAClass); + } + aClass.setPaSuperEntity(superAClass); + return; + } + + final PAnnotatedEClass superAClass = aClass.getPaModel().getPAnnotated(eclass.getESuperTypes().get(0)); + if (superAClass.getEntity() != null || superAClass.getMappedSuperclass() != null) { + aClass.setPaSuperEntity(superAClass); + } + } + + /** Returns fals for jpox and true for hibernate */ + protected boolean isMappableAnnotatedClass(PAnnotatedEClass aClass) { + + final EClass eclass = aClass.getModelEClass(); + + if (!mapInterfaceEClass() && eclass.isInterface()) { + log.debug("Not mapping interfaces and this is an interface eclass, ignore it"); + return false; + } + + if (aClass.getTransient() != null) { + return false; // not mappable + } + + if (!getPersistenceOptions().isSetEntityAutomatically() && aClass.getEntity() == null + && aClass.getEmbeddable() == null) { + log.debug("Entities are not added automatically and this eclass: " + aClass.getModelEClass().getName() + + " does not have an entity/embeddable annotation."); + return false; + } + + // ignore these + if (!mapMappedSuperEClass() && aClass.getMappedSuperclass() != null) { + if (aClass.getEntity() != null) { + log + .warn("EClass " + + eclass.getName() + + " has entity as well as mappedsuperclass annotation, following mappedsuperclass annotation, therefore ignoring it for the mapping"); + } + return false; + } + + return true; + } + + /** + * Map Interface EClasses, default false, overridden by hibernate to return true + */ + protected boolean mapInterfaceEClass() { + return false; + } + + /** Map a mapped superclass, this differs for jpox and hibernate */ + protected boolean mapMappedSuperEClass() { + return true; + } + + /* + * (non-Javadoc) + * + * @seeorg.eclipse.emf.teneo.annotations.mapper.AbstractAnnotator# setPersistenceOptions(org.eclipse + * .emf.teneo.PersistenceOptions) + */ + @Override + public void setPersistenceOptions(PersistenceOptions persistenceOptions) { + super.setPersistenceOptions(persistenceOptions); + if (persistenceOptions.getInheritanceMapping() != null) { + InheritanceType it = InheritanceType.get(persistenceOptions.getInheritanceMapping()); + if (it == InheritanceType.JOINED) { + optionDefaultInheritanceMapping = InheritanceType.JOINED; + log.debug("Option inheritance: joined"); + } else if (it == InheritanceType.SINGLE_TABLE) { + optionDefaultInheritanceMapping = InheritanceType.SINGLE_TABLE; + log.debug("Option inheritance: single"); + } else if (it == InheritanceType.TABLE_PER_CLASS) { + optionDefaultInheritanceMapping = InheritanceType.TABLE_PER_CLASS; + log.debug("Option inheritance: table per class"); + } else { + throw new IllegalArgumentException("Inheritance mapping option: " + + persistenceOptions.getInheritanceMapping() + " is not supported"); + } + } + } + +} diff --git a/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/annotations/mapper/EDataTypeAnnotator.java b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/annotations/mapper/EDataTypeAnnotator.java new file mode 100755 index 000000000..2fe3c346a --- /dev/null +++ b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/annotations/mapper/EDataTypeAnnotator.java @@ -0,0 +1,39 @@ +/** + * <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: EDataTypeAnnotator.java,v 1.6 2009/03/30 07:53:04 mtaal Exp $ + */ + +package org.eclipse.emf.teneo.annotations.mapper; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.eclipse.emf.teneo.annotations.pamodel.PAnnotatedEDataType; +import org.eclipse.emf.teneo.extension.ExtensionPoint; + +/** + * Annotates an EDataType, does nothing in this implementation. + * + * @author <a href="mailto:mtaal@elver.org">Martin Taal</a> + * @version $Revision: 1.6 $ + */ + +public class EDataTypeAnnotator extends AbstractAnnotator implements ExtensionPoint { + + // The logger + protected static final Log log = LogFactory.getLog(EDataTypeAnnotator.class); + + /** Annotate it */ + public void annotate(PAnnotatedEDataType aDataType) { + } +} diff --git a/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/annotations/mapper/EFeatureAnnotator.java b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/annotations/mapper/EFeatureAnnotator.java new file mode 100755 index 000000000..a9ff50c5c --- /dev/null +++ b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/annotations/mapper/EFeatureAnnotator.java @@ -0,0 +1,272 @@ +/** + * <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: EFeatureAnnotator.java,v 1.15 2010/07/15 07:46:30 mtaal Exp $ + */ + +package org.eclipse.emf.teneo.annotations.mapper; + +import java.util.Collection; +import java.util.List; +import java.util.Set; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.eclipse.emf.ecore.EAnnotation; +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.Constants; +import org.eclipse.emf.teneo.annotations.pamodel.PAnnotatedEAttribute; +import org.eclipse.emf.teneo.annotations.pamodel.PAnnotatedEReference; +import org.eclipse.emf.teneo.annotations.pamodel.PAnnotatedEStructuralFeature; +import org.eclipse.emf.teneo.annotations.pannotation.Transient; +import org.eclipse.emf.teneo.extension.ExtensionPoint; +import org.eclipse.emf.teneo.util.StoreUtil; + +/** + * Sets the annotation on an efeature. In fact determines which efeature annotator to use (one-to-many, many-to-many + * etc.). + * + * @author <a href="mailto:mtaal@elver.org">Martin Taal</a> + * @version $Revision: 1.15 $ + */ + +public class EFeatureAnnotator extends AbstractAnnotator implements ExtensionPoint { + + // The logger + protected static final Log log = LogFactory.getLog(EFeatureAnnotator.class); + + // the annotators + protected OneToManyAttributeAnnotator otmAttributeAnnotator; + protected SingleAttributeAnnotator singleAttributeAnnotator; + protected BidirectionalManyToManyAnnotator bidirectionalManyToManyAnnotator; + protected UnidirectionalManyToManyAnnotator unidirectionalManyToManyAnnotator; + protected OneToManyReferenceAnnotator oneToManyReferenceAnnotator; + protected OneToOneReferenceAnnotator oneToOneReferenceAnnotator; + protected ManyToOneReferenceAnnotator manyToOneReferenceAnnotator; + + @Override + protected void initialize() { + super.initialize(); + otmAttributeAnnotator = createAnnotator(OneToManyAttributeAnnotator.class); + otmAttributeAnnotator.setEFeatureAnnotator(this); + singleAttributeAnnotator = createAnnotator(SingleAttributeAnnotator.class); + singleAttributeAnnotator.setEFeatureAnnotator(this); + bidirectionalManyToManyAnnotator = createAnnotator(BidirectionalManyToManyAnnotator.class); + bidirectionalManyToManyAnnotator.setEFeatureAnnotator(this); + unidirectionalManyToManyAnnotator = createAnnotator(UnidirectionalManyToManyAnnotator.class); + unidirectionalManyToManyAnnotator.setEFeatureAnnotator(this); + oneToManyReferenceAnnotator = createAnnotator(OneToManyReferenceAnnotator.class); + oneToManyReferenceAnnotator.setEFeatureAnnotator(this); + oneToOneReferenceAnnotator = createAnnotator(OneToOneReferenceAnnotator.class); + oneToOneReferenceAnnotator.setEFeatureAnnotator(this); + manyToOneReferenceAnnotator = createAnnotator(ManyToOneReferenceAnnotator.class); + manyToOneReferenceAnnotator.setEFeatureAnnotator(this); + } + + /** Process the features of the eclass */ + public void annotate(PAnnotatedEStructuralFeature aStructuralFeature) { + EStructuralFeature eStructuralFeature = aStructuralFeature.getModelEStructuralFeature(); + + boolean errorOccured = true; + try { + // a feature is transient if: + // - transient is true and it is an eattribute or + // - transient is true and it does not have an opposite + // - transietn is true and it's opposite is not a containment + // relation + // - it refers to an eclass which is transient + boolean isTransient = eStructuralFeature.isTransient() + && (eStructuralFeature instanceof EAttribute + || ((EReference) eStructuralFeature).getEOpposite() == null + || !((EReference) eStructuralFeature).getEOpposite().isContainment() || ((EReference) eStructuralFeature) + .getEOpposite().isTransient()); + + // check if the refered to eclass is transient if so then this + // efeature is + // also transient + if (!isTransient && eStructuralFeature instanceof EReference) { + final PAnnotatedEReference aReference = (PAnnotatedEReference) aStructuralFeature; + if (aReference.getTransient() != null) { + final Transient trans = getFactory().createTransient(); + trans.setEModelElement(eStructuralFeature); + aStructuralFeature.setTransient(trans); + } else if (hasTransientAnnotation(aReference.getEReferenceType())) { + final Transient trans = getFactory().createTransient(); + trans.setEModelElement(eStructuralFeature); + aStructuralFeature.setTransient(trans); + } else if (aReference.getAReferenceType() != null) { + isTransient = aReference.getAReferenceType().getTransient() != null; + } + } + + // don't do anything with the explicitly transient + if (aStructuralFeature.getTransient() != null) { + return; + } + + if (aStructuralFeature.getTransient() == null + && ((!mapVolitatileFeature() && eStructuralFeature.isVolatile()) || isTransient)) { + log.debug("Structural feature " + eStructuralFeature.getName() + + " is transient, therefore adding transient annotation"); + final Transient trans = getFactory().createTransient(); + trans.setEModelElement(eStructuralFeature); + aStructuralFeature.setTransient(trans); + } + + // process transients further because they can be part of a + // featuremap, the specific mapper should + // handle transient + // Note that this means that transient features will still have + // additional annotations such as basic etc. + // if (aStructuralFeature.getTransient() != null) return; + if (aStructuralFeature instanceof PAnnotatedEAttribute) { + final PAnnotatedEAttribute aAttribute = (PAnnotatedEAttribute) aStructuralFeature; + if (((PAnnotatedEAttribute) aStructuralFeature).getVersion() != null) { + return; + } + + final Class<?> instanceClass = eStructuralFeature.getEType().getInstanceClass(); + boolean isMany = false; + // instanceClass will be null for enums + // Lob-annotated attributes must not be treated as one-to-many. + // eattributes with a hibernate type annotations should not be + // treated as a list + if (instanceClass != null && aAttribute.getLob() == null) { + isMany = eStructuralFeature.isMany() || instanceClass.isArray() + || Collection.class.isAssignableFrom(instanceClass) + || Set.class.isAssignableFrom(instanceClass) || List.class.isAssignableFrom(instanceClass); + // note this causes a featuremap within a featuremap to get the + // basic annotation! + isMany = isMany && !StoreUtil.isElementOfAGroup(eStructuralFeature); + } + + if (isMany) { + otmAttributeAnnotator.annotate(aAttribute); + } else { + singleAttributeAnnotator.annotate(aAttribute); + } + + if (aAttribute.getColumn() != null && aAttribute.getColumn().getName() == null) { + aAttribute.getColumn().setName(getSqlNameStrategy().getColumnName(aAttribute, null)); + } + + } else if (aStructuralFeature instanceof PAnnotatedEReference) { + + final PAnnotatedEReference aReference = (PAnnotatedEReference) aStructuralFeature; + + // detect the type of relation + // note using the emf model it can not be checked if a relation + // is a + // uni-manytoone (2.1.8.3.2) or a uni onetoone (2.1.8.3.1) + // neither can a uni-manytomany (2.1.8.5.2) be detected + // because there is no eopposite. However this can be + // specified manually, the system as a default will choose + // uni-manytoone + + final EReference eReference = (EReference) aStructuralFeature.getModelElement(); + final EReference eOpposite = eReference.getEOpposite(); + + // elements of a group are never multi-occurence because the + // multi-occurence is + // handled by the containing featuremap + final boolean isMany = eReference.isMany() && !StoreUtil.isElementOfAGroup(eReference); + final boolean isOppositeMany = eOpposite != null && eOpposite.isMany() + && !StoreUtil.isElementOfAGroup(eOpposite); + + final boolean mtmBidirectionalRelation = isMany && eOpposite != null && isOppositeMany; + final boolean mtmUnidirectionalRelation = isMany && eOpposite == null + && aReference.getManyToMany() != null; + final boolean otmBidirectionalRelation = isMany && eOpposite != null && !isOppositeMany; + final boolean otmUnidirectionalRelation = isMany && eOpposite == null; + + // note as a default if the system has to choose between oto uni + // or mto uni then it will + // place a mto + final boolean otoBidirectionalRelation = aReference.getManyToOne() == null && !isMany + && eOpposite != null && !isOppositeMany; + final boolean otoUnidirectionalRelation = aReference.getManyToOne() == null && !isMany + && eOpposite == null + && (aReference.getOneToOne() != null || !aReference.getPrimaryKeyJoinColumns().isEmpty()); + final boolean mtoBidirectionalRelation = !isMany && eOpposite != null && isOppositeMany; + final boolean mtoUnidirectionalRelation = !isMany && eOpposite == null && !otoUnidirectionalRelation; + + if (mtmBidirectionalRelation) { + bidirectionalManyToManyAnnotator.annotate(aReference); + } else if (mtmUnidirectionalRelation) { + unidirectionalManyToManyAnnotator.annotate(aReference); + } else if (otmBidirectionalRelation || otmUnidirectionalRelation) { + oneToManyReferenceAnnotator.annotate(aReference); + } else if (aReference.getManyToOne() == null && (otoBidirectionalRelation || otoUnidirectionalRelation)) { + oneToOneReferenceAnnotator.annotate(aReference); + } else if (mtoBidirectionalRelation) { + manyToOneReferenceAnnotator.annotate(aReference); + } else if (mtoUnidirectionalRelation) { + manyToOneReferenceAnnotator.annotate(aReference); + } + + // handle column naming at this level + if (aReference.getColumn() != null && aReference.getColumn().getName() == null) { + aReference.getColumn().setName(getSqlNameStrategy().getColumnName(aReference, null)); + } + + } else { + throw new IllegalArgumentException("This type of StructuralFeature is not supported: " + + aStructuralFeature.getClass().getName()); + } + errorOccured = false; + } finally { + + // check that at least one ann was set + if (aStructuralFeature instanceof PAnnotatedEAttribute) { + PAnnotatedEAttribute pae = (PAnnotatedEAttribute) aStructuralFeature; + assert (errorOccured || pae.getBasic() != null || pae.getVersion() != null || pae.getId() != null + || pae.getTransient() != null || pae.getOneToMany() != null); + } else { + PAnnotatedEReference par = (PAnnotatedEReference) aStructuralFeature; + assert (errorOccured || par.getTransient() != null || par.getOneToMany() != null + || par.getManyToMany() != null || par.getManyToOne() != null || par.getOneToOne() != null); + } + } + } + + /** Map the feature if it is volatile, default is false */ + protected boolean mapVolitatileFeature() { + return false; + } + + /** + * @return the manyToOneReferenceAnnotator + */ + public ManyToOneReferenceAnnotator getManyToOneReferenceAnnotator() { + return manyToOneReferenceAnnotator; + } + + // checks for the presence of the @Transient annotation + // without requiring the refered class to be processed + private boolean hasTransientAnnotation(EClass eClass) { + final EAnnotation eAnnotation = eClass.getEAnnotation(Constants.ANNOTATION_SOURCE_TENEO_JPA); + if (eAnnotation == null) { + return false; + } + for (String value : eAnnotation.getDetails().values()) { + if (value.contains("@Transient")) { + return true; + } + } + return false; + } + +} diff --git a/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/annotations/mapper/ManyToOneReferenceAnnotator.java b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/annotations/mapper/ManyToOneReferenceAnnotator.java new file mode 100755 index 000000000..c372ef3f5 --- /dev/null +++ b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/annotations/mapper/ManyToOneReferenceAnnotator.java @@ -0,0 +1,155 @@ +/** + * <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: ManyToOneReferenceAnnotator.java,v 1.18 2010/03/25 00:12:45 mtaal Exp $ + */ + +package org.eclipse.emf.teneo.annotations.mapper; + +import java.util.List; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.eclipse.emf.ecore.EReference; +import org.eclipse.emf.teneo.annotations.pamodel.PAnnotatedEReference; +import org.eclipse.emf.teneo.annotations.pannotation.FetchType; +import org.eclipse.emf.teneo.annotations.pannotation.JoinColumn; +import org.eclipse.emf.teneo.annotations.pannotation.ManyToOne; +import org.eclipse.emf.teneo.extension.ExtensionPoint; + +/** + * Annotates an ereference. + * + * @author <a href="mailto:mtaal@elver.org">Martin Taal</a> + * @version $Revision: 1.18 $ + */ + +public class ManyToOneReferenceAnnotator extends BaseEFeatureAnnotator implements ExtensionPoint { + + // The logger + protected static final Log log = LogFactory.getLog(ManyToOneReferenceAnnotator.class); + + /** Annotate it */ + public void annotate(PAnnotatedEReference aReference) { + final String logStr = aReference.getModelEReference().getName() + "/" + + aReference.getModelEReference().getEContainingClass().getName(); + + if (aReference.getOneToMany() != null || aReference.getManyToMany() != null || aReference.getOneToOne() != null) { + throw new StoreMappingException("The feature/eclass " + logStr + " should be a ManyToOne but " + + "it already has a OneToMany, ManyToMany or OneToOne annotation"); + } + + final EReference eReference = (EReference) aReference.getModelElement(); + + ManyToOne mto = aReference.getManyToOne(); + if (mto == null) { + log.debug("EReference + " + logStr + " does not have a manytoone annotation, adding one"); + mto = getFactory().createManyToOne(); + aReference.setManyToOne(mto); + // removed unsettable because it is not used to define optional, it + // is used + // to allow distinction between the default value set or a feature + // which has not been + // set, this is used in validation + // mto.setOptional(!eReference.isRequired() || + // eReference.isUnsettable() || + // eReference.getEOpposite() != null); + mto.setOptional(!eReference.isRequired() || eReference.getEOpposite() != null || eReference.isUnsettable()); + mto.setEModelElement(eReference); + } else { + log.debug("EReference + " + logStr + " does have a manytoone annotation, using it"); + } + + if (!mto.isSetFetch()) { + mto.setFetch(getFetch(aReference.getAReferenceType())); + } + + if (eReference.isContainment() || getPersistenceOptions().isSetDefaultCascadeOnNonContainment()) { + setCascade(mto.getCascade(), eReference.isContainment()); + } + + // NOTE: Sometimes EMF generated getters/setters have a + // very generic type (EObject), if the type can be derived here then + // this should + // be added here + if (mto.getTargetEntity() == null) { + mto.setTargetEntity(getEntityName(eReference.getEReferenceType())); + } + + if (getPersistenceOptions().isSetForeignKeyNames() && aReference.getForeignKey() == null) { + aReference.setForeignKey(createFK(aReference)); + } + + if (getPersistenceOptions().isMapEmbeddableAsEmbedded() + && aReference.getAReferenceType().getEmbeddable() != null) { + aReference.setEmbedded(getFactory().createEmbedded()); + } + + // create a set of joincolumns, note that if this is a two-way relation + // then + // the other side will use the name of the ereference as second + // parameter, + // matching the joincolumns on the other side + if (aReference.getJoinColumns() == null || aReference.getJoinColumns().isEmpty()) { + if (aReference.getAReferenceType() != null) { + // == null if the reference is to a high level type such as an + // eobject + + // Set the join columns to not insertable/updatable if this is + // the many-to-one side + // of a bidirectional relation with a one-to-many list + // (indexed!) on the other side. + boolean hasJoinTable = false; + boolean isInsertableUpdatable = true; + if (eReference.getEOpposite() != null && !eReference.getEOpposite().isTransient()) { + final PAnnotatedEReference aOpposite = getAnnotatedModel().getPAnnotated(eReference.getEOpposite()); + + hasJoinTable = (!aOpposite.getModelEReference().isContainment() && getPersistenceOptions() + .isJoinTableForNonContainedAssociations()) + || aOpposite.getJoinTable() != null; + + if (!hasJoinTable && aOpposite.getOneToMany() != null && aOpposite.getOneToMany().isList() && !aOpposite.getOneToMany().getFetch().equals(FetchType.EXTRA)) { + isInsertableUpdatable = false; + } + // if the refered to is stored as an eav then do the update of the columns from here. + if (aReference.getAReferenceType().getEavMapping() != null) { + isInsertableUpdatable = true; + } + } + // old: + // isInsertableUpdatable = eReference.getEOpposite() == null || + // eReference.getEOpposite().isTransient() + + // NOTE that currently in all cases if there is an opposite + // Teneo assumes + // that it is managed from the other side. In reality this only + // needs to + // be done if the other side is indexed. + // NOTE: otm/mto with join table is not supported at the moment! + if (!hasJoinTable) { + final List<String> names = getSqlNameStrategy().getManyToOneJoinColumnNames(aReference); + aReference.getJoinColumns().addAll( + getJoinColumns(names, mto.isOptional(), isInsertableUpdatable, mto)); + } + } + } else { + // if nullable was not set explicitly then use the mto optional + // feature + for (JoinColumn jc : aReference.getJoinColumns()) { + if (!jc.isSetNullable()) { + jc.setNullable(mto.isOptional()); + } + } + } + } +} diff --git a/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/annotations/mapper/OneToManyAttributeAnnotator.java b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/annotations/mapper/OneToManyAttributeAnnotator.java new file mode 100755 index 000000000..3237024ba --- /dev/null +++ b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/annotations/mapper/OneToManyAttributeAnnotator.java @@ -0,0 +1,153 @@ +/** + * <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: OneToManyAttributeAnnotator.java,v 1.11 2010/03/28 09:20:25 mtaal Exp $ + */ + +package org.eclipse.emf.teneo.annotations.mapper; + +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.EEnum; +import org.eclipse.emf.ecore.util.FeatureMapUtil; +import org.eclipse.emf.teneo.PersistenceOptions; +import org.eclipse.emf.teneo.annotations.pamodel.PAnnotatedEAttribute; +import org.eclipse.emf.teneo.annotations.pannotation.CascadeType; +import org.eclipse.emf.teneo.annotations.pannotation.EnumType; +import org.eclipse.emf.teneo.annotations.pannotation.Enumerated; +import org.eclipse.emf.teneo.annotations.pannotation.FetchType; +import org.eclipse.emf.teneo.annotations.pannotation.JoinTable; +import org.eclipse.emf.teneo.annotations.pannotation.OneToMany; +import org.eclipse.emf.teneo.annotations.pannotation.TemporalType; +import org.eclipse.emf.teneo.extension.ExtensionPoint; + +/** + * Annotates a one-to-many attribute (an eattribute with ismany=true), an + * example is a list of primitives (list of ints). + * + * @author <a href="mailto:mtaal@elver.org">Martin Taal</a> + * @version $Revision: 1.11 $ + */ + +public class OneToManyAttributeAnnotator extends BaseEFeatureAnnotator + implements ExtensionPoint { + + // The logger + protected static final Log log = LogFactory + .getLog(OneToManyAttributeAnnotator.class); + + private TemporalType optionDefaultTemporal = null; + + /** Process the features of the eclass */ + public void annotate(PAnnotatedEAttribute aAttribute) { + final String logStr = aAttribute.getModelEAttribute().getName() + + "/" + + aAttribute.getModelEAttribute().getEContainingClass() + .getName(); + + log.debug("EAttribute " + logStr + " needs a onetomany"); + + final EAttribute eAttribute = (EAttribute) aAttribute.getModelElement(); + + OneToMany otm = aAttribute.getOneToMany(); + final boolean otmWasSet = otm != null; // otm was set manually + if (otm == null) { + log.debug("One to many not present adding one"); + otm = getFactory().createOneToMany(); + aAttribute.setOneToMany(otm); + otm.setEModelElement(eAttribute); + + if (getPersistenceOptions().isFetchContainmentEagerly()) { + otm.setFetch(FetchType.EAGER); + } else if (getPersistenceOptions().isFetchAssociationExtraLazy()) { + otm.setFetch(FetchType.EXTRA); + } + } else { + log + .debug("One to many present adding default information if required"); + } + + if (getPersistenceOptions().isSetForeignKeyNames() + && aAttribute.getForeignKey() == null) { + aAttribute.setForeignKey(createFK(aAttribute)); + } + + // handle list of enums + if (eAttribute.getEType() instanceof EEnum + && aAttribute.getEnumerated() == null) { + final Enumerated enumerated = getFactory().createEnumerated(); + enumerated.setValue(EnumType.STRING); + enumerated.setEModelElement(eAttribute); + aAttribute.setEnumerated(enumerated); + } + + if (aAttribute.getTemporal() == null) { + setTemporal(aAttribute, optionDefaultTemporal); + } + + // set cascade if not set + if (otm.getCascade().isEmpty()) { + otm.getCascade().add(CascadeType.ALL); + } + + if (otm.getTargetEntity() == null) { + otm.setTargetEntity(getTargetTypeName(aAttribute)); + } + + if (aAttribute.getJoinTable() == null) { + // note not optional because lists of simple types are embedded + final JoinTable jt = getFactory().createJoinTable(); + jt.setName(getSqlNameStrategy().getJoinTableName(aAttribute)); + aAttribute.setJoinTable(jt); + } + + if (aAttribute.getJoinColumns().size() == 0) { + final List<String> names = getSqlNameStrategy() + .getOneToManyEAttributeJoinColumns(aAttribute); + aAttribute.getJoinColumns().addAll( + getJoinColumns(names, FeatureMapUtil + .isFeatureMap(eAttribute), true, otm)); + } + + // set unique and indexed + if (!otmWasSet) { + log + .debug("Setting indexed and unique on otm from eAttribute.isOrdered/isUnique " + + "because otm was not set manually"); + otm.setIndexed(eAttribute.isOrdered()); + otm.setUnique(eAttribute.isUnique()); + } + } + + /* + * (non-Javadoc) + * + * @seeorg.eclipse.emf.teneo.annotations.mapper.AbstractAnnotator# + * setPersistenceOptions(org.eclipse.emf.teneo.PersistenceOptions) + */ + @Override + public void setPersistenceOptions(PersistenceOptions persistenceOptions) { + super.setPersistenceOptions(persistenceOptions); + + optionDefaultTemporal = TemporalType.get(persistenceOptions + .getDefaultTemporalValue()); + if (optionDefaultTemporal == null) { + throw new StoreMappingException("Temporal value not found: " + + persistenceOptions.getDefaultTemporalValue()); + } + } + +} diff --git a/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/annotations/mapper/OneToManyReferenceAnnotator.java b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/annotations/mapper/OneToManyReferenceAnnotator.java new file mode 100755 index 000000000..722c2b177 --- /dev/null +++ b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/annotations/mapper/OneToManyReferenceAnnotator.java @@ -0,0 +1,348 @@ +/** + * <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: OneToManyReferenceAnnotator.java,v 1.20 2010/03/25 00:12:44 mtaal Exp $ + */ + +package org.eclipse.emf.teneo.annotations.mapper; + +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.ecore.util.EcoreUtil; +import org.eclipse.emf.teneo.annotations.pamodel.PAnnotatedEReference; +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.OneToMany; +import org.eclipse.emf.teneo.extension.ExtensionPoint; +import org.eclipse.emf.teneo.mapping.strategy.EntityNameStrategy; +import org.eclipse.emf.teneo.util.StoreUtil; + +/** + * Annotates an ereference. + * + * @author <a href="mailto:mtaal@elver.org">Martin Taal</a> + * @version $Revision: 1.20 $ + */ + +public class OneToManyReferenceAnnotator extends BaseEFeatureAnnotator + implements ExtensionPoint { + + // The logger + protected static final Log log = LogFactory + .getLog(OneToManyReferenceAnnotator.class); + + /** Annotate it */ + public void annotate(PAnnotatedEReference aReference) { + final String logStr = aReference.getModelEReference().getName() + + "/" + + aReference.getModelEReference().getEContainingClass() + .getName(); + + if (aReference.getManyToMany() != null + || aReference.getOneToOne() != null + || aReference.getManyToOne() != null) { + throw new StoreMappingException( + "The feature/eclass " + + logStr + + " should be a OneToMany but " + + "it already has a ManyToMany, OneToOne or ManyToOne annotation"); + } + + final EReference eReference = (EReference) aReference.getModelElement(); + OneToMany otm = aReference.getOneToMany(); + final boolean otmWasSet = otm != null; // otm was set manually + if (otm == null) { + log.debug("EReference + " + logStr + + " does not have a onetomany annotation, adding one"); + otm = getFactory().createOneToMany(); + aReference.setOneToMany(otm); + otm.setEModelElement(eReference); + + if (eReference.isContainment() + && getPersistenceOptions().isFetchContainmentEagerly()) { + otm.setFetch(FetchType.EAGER); + } else if (getPersistenceOptions().isFetchAssociationExtraLazy()) { + otm.setFetch(FetchType.EXTRA); + } + } else { + log.debug("EReference + " + logStr + + " has onetomany, check if defaults should be set"); + } + + // don't set mappedBy explicitly anymore + // mappedBy is not set anymore because it controls inverse + // see bugzilla 242479 + // if (otm.getMappedBy() == null && eReference.getEOpposite() != null) { + // otm.setMappedBy(eReference.getEOpposite().getName()); + // } + + if (getPersistenceOptions().isMapEmbeddableAsEmbedded() + && aReference.getAReferenceType().getEmbeddable() != null) { + aReference.setEmbedded(getFactory().createEmbedded()); + } + + if (getPersistenceOptions().isSetForeignKeyNames() + && aReference.getForeignKey() == null) { + // See bugzilla 211798: handle a specific case when this is a + // bidirectional + // one-to-many/many-to-one. In that case the foreign key name has to + // be + // the same on both sides and is set on the many-side. So use the + // annotated reference from the other side to ensure that the same + // foreign key name + // is used. + if (eReference.getEOpposite() != null + && !eReference.getEOpposite().isMany() + && !eReference.getEOpposite().isTransient()) { + final PAnnotatedEReference aOpposite = aReference.getPaModel() + .getPAnnotated(eReference.getEOpposite()); + if (aOpposite != null && aOpposite.getTransient() == null) { + // don't do anything as otherwise hibernate will create two + // fk's with the same name + + // if (aOpposite.getForeignKey() != null) { + // final ForeignKey fk = getFactory().createForeignKey(); + // fk.setName(aOpposite.getForeignKey().getName()); + // aReference.setForeignKey(fk); + // } else { + // aReference.setForeignKey(createFK(aOpposite)); + // } + } else { + aReference.setForeignKey(createFK(aReference)); + } + } else { + aReference.setForeignKey(createFK(aReference)); + } + } + + if (eReference.isContainment() + || getPersistenceOptions() + .isSetDefaultCascadeOnNonContainment()) { + setCascade(otm.getCascade(), eReference.isContainment()); + } + + // handle a special case, an emap which is mapped as a real map and + // which has an + // enumerate as the key + // Disabled for now as the hibernate map-key does not support enumerates + // as the type + // for the key when mapping as a true map + // if (false && StoreUtil.isMap(eReference) && + // getPersistenceOptions().isMapEMapAsTrueMap()) { + // final EStructuralFeature keyFeature = + // aReference.getEReferenceType().getEStructuralFeature("key"); + // if (keyFeature instanceof EAttribute) { + // final EAttribute keyAttribute = (EAttribute) keyFeature; + // final PAnnotatedEAttribute aKeyAttribute = + // aReference.getPaModel().getPAnnotated(keyAttribute); + // if (keyAttribute.getEType() instanceof EEnum && + // aKeyAttribute.getEnumerated() == null) { + // final Enumerated enumerated = getFactory().createEnumerated(); + // enumerated.setValue(EnumType.STRING); + // enumerated.setEModelElement(keyAttribute); + // aKeyAttribute.setEnumerated(enumerated); + // } + // } + // } + + // NOTE Sometimes EMF generated getters/setters have a + // very generic type (EObject), if the type can be derived here then + // this should + // be added here + if (otm.getTargetEntity() == null) { + otm.setTargetEntity(getEntityName(eReference.getEReferenceType())); + } + + // set unique and indexed + if (!otmWasSet) { + log + .debug("Setting indexed and unique from ereference because otm was not set manually!"); + // note force a join table in case of idbag! + otm.setIndexed(!getPersistenceOptions().alwaysMapListAsBag() + && !getPersistenceOptions().alwaysMapListAsIdBag() + && eReference.isOrdered() + && aReference.getOrderBy() == null); + // in case of containment it is always unique + // in case optionidbag then ignore the unique attribute on the + // ereference + otm + .setUnique(eReference.isContainment() + || (!getPersistenceOptions().alwaysMapListAsIdBag() && eReference + .isUnique())); + + if (aReference.getModelEReference().getEOpposite() != null) { + log + .debug("Setting unique because is bidirectional (has eopposite) otm"); + otm.setUnique(true); + } + } else if (!otm.isUnique() && !eReference.isUnique() + && aReference.getModelEReference().getEOpposite() != null) { + log + .warn("The EReference " + + logStr + + " is not unique (allows duplicates) but it is bi-directional, this is not logical"); + } + + // only use a jointable if the relation is non unique + final boolean isEObject = EntityNameStrategy.EOBJECT_ECLASS_NAME + .compareTo(otm.getTargetEntity()) == 0; + // in case of eobject always a join table is required + boolean mapJoinTable = aReference.getJoinTable() != null + || isEObject + || (getPersistenceOptions() + .isJoinTableForNonContainedAssociations() && !eReference + .isContainment()) || !otm.isUnique(); + + // also always map join table if the one refered to is an EAV + mapJoinTable |= (aReference.getAReferenceType() != null && aReference + .getAReferenceType().getEavMapping() != null); + + if (mapJoinTable) { + JoinTable joinTable = aReference.getJoinTable(); + if (joinTable == null) { + joinTable = getFactory().createJoinTable(); + aReference.setJoinTable(joinTable); + } + joinTable.setEModelElement(eReference); + + // see remark in manytomany about naming of jointables + if (joinTable.getName() == null) { + joinTable.setName(getSqlNameStrategy().getJoinTableName( + aReference)); + } + + // note joincolumns in jointable can be generated automatically by + // hib/jpox. need to explicitly do this in case of + // composite id + if (joinTable.getJoinColumns().size() == 0) { + final List<String> names = getSqlNameStrategy() + .getJoinTableJoinColumns(aReference, false); + joinTable.getJoinColumns().addAll( + getJoinColumns(names, false, true, otm)); + } + if (joinTable.getInverseJoinColumns().size() == 0 + && aReference.getAReferenceType() != null) { + final List<String> names = getSqlNameStrategy() + .getJoinTableJoinColumns(aReference, true); + // todo: should the inverse join columns not be + joinTable.getInverseJoinColumns().addAll( + getJoinColumns(names, false, true, otm)); + } + } else if (aReference.getJoinColumns() == null + || aReference.getJoinColumns().isEmpty()) { // add + boolean borrowJoinColumnsOtherSide = false; + + final EReference eOther = getOpposite(aReference); + if (eOther != null) { + final PAnnotatedEReference aOther = aReference.getPaModel() + .getPAnnotated(eOther); + + // map the other side, before checking if there are joincolumns + getEFeatureAnnotator().getManyToOneReferenceAnnotator() + .annotate(aOther); + + if (aOther.getJoinColumns() != null + && !aOther.getJoinColumns().isEmpty()) { + borrowJoinColumnsOtherSide = true; + for (JoinColumn jc : aOther.getJoinColumns()) { + aReference.getJoinColumns().add( + (JoinColumn) EcoreUtil.copy(jc)); + } + // repair updatable/insertable + for (JoinColumn jc : aReference.getJoinColumns()) { + jc.setUpdatable(true); + jc.setInsertable(true); + } + } + } + if (!borrowJoinColumnsOtherSide) { + final List<String> names = getSqlNameStrategy() + .getOneToManyEReferenceJoinColumns(aReference); + aReference.getJoinColumns().addAll( + getJoinColumns(names, aReference.getEmbedded() == null, + true, otm)); + } + + // In case of a bidirectional relation without a join table + // do a special thing: if this is a list (with an index) then the + // association is always + // managed from this side of the relation. This means that + // update/insert of the + // joincolumns + // on the other side is set to false. + // See the hibernate manual: 6.3.3. Bidirectional associations with + // indexed collections + boolean thisEAVMapped = aReference.getPaEClass().getEavMapping() != null; + if (otm.isList() && eOther != null && !thisEAVMapped) { + final PAnnotatedEReference aOpposite = getAnnotatedModel() + .getPAnnotated(eOther); + if (aReference.getTransient() == null) { + if (aOpposite.getJoinColumns().size() > 0) { + for (JoinColumn jc : aOpposite.getJoinColumns()) { + if (otm.getFetch().equals(FetchType.EXTRA)) { + jc.setInsertable(true); + jc.setUpdatable(true); + } else { + jc.setInsertable(false); + jc.setUpdatable(false); + } + } + } + } + } + } + } + + protected EReference getOpposite(PAnnotatedEReference aReference) { + final EReference eReference = (EReference) aReference.getModelElement(); + if (eReference.getEOpposite() != null) { + return eReference.getEOpposite(); + } + + // now handle a special case, the aReference is a map + // and there is a mapped by and a one to many + if (aReference.getOneToMany() == null + || aReference.getOneToMany().getMappedBy() == null) { + return null; + } + + final EClass eclass = eReference.getEReferenceType(); + if (getPersistenceOptions().isMapEMapAsTrueMap() + && StoreUtil.isMapEntry(eclass)) { + EStructuralFeature feature = eclass.getEStructuralFeature("value"); + if (feature instanceof EReference) { + final String mappedBy = aReference.getOneToMany().getMappedBy(); + final EReference valueERef = (EReference) feature; + final EClass valueEClass = valueERef.getEReferenceType(); + final EStructuralFeature ef = valueEClass + .getEStructuralFeature(mappedBy); + if (ef == null || ef instanceof EAttribute) { + return null; + } + + return (EReference) ef; + } else { + return null; + } + } else { + return null; + } + } +} diff --git a/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/annotations/mapper/OneToOneReferenceAnnotator.java b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/annotations/mapper/OneToOneReferenceAnnotator.java new file mode 100755 index 000000000..f9f8c406c --- /dev/null +++ b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/annotations/mapper/OneToOneReferenceAnnotator.java @@ -0,0 +1,123 @@ +/** + * <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: OneToOneReferenceAnnotator.java,v 1.11 2009/03/30 07:53:04 mtaal Exp $ + */ + +package org.eclipse.emf.teneo.annotations.mapper; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.eclipse.emf.ecore.EReference; +import org.eclipse.emf.teneo.annotations.pamodel.PAnnotatedEReference; +import org.eclipse.emf.teneo.annotations.pannotation.OneToOne; +import org.eclipse.emf.teneo.extension.ExtensionPoint; + +/** + * Annotates an ereference. + * + * @author <a href="mailto:mtaal@elver.org">Martin Taal</a> + * @version $Revision: 1.11 $ + */ + +public class OneToOneReferenceAnnotator extends BaseEFeatureAnnotator implements ExtensionPoint { + + // The logger + protected static final Log log = LogFactory.getLog(OneToOneReferenceAnnotator.class); + + /** Annotate it */ + public void annotate(PAnnotatedEReference aReference) { + final String logStr = + aReference.getModelEReference().getName() + "/" + + aReference.getModelEReference().getEContainingClass().getName(); + + if (aReference.getOneToMany() != null || aReference.getManyToMany() != null || + aReference.getManyToOne() != null) { + throw new StoreMappingException("The feature/eclass " + logStr + " should be a OneToOne but " + + "it already has a OneToMany, ManyToMany or ManyToOne annotation"); + } + + final EReference eReference = (EReference) aReference.getModelElement(); + + OneToOne oto = aReference.getOneToOne(); + if (oto == null) { + log.debug("EReference + " + logStr + " does not have a onetoone annotation, adding one"); + oto = getFactory().createOneToOne(); + aReference.setOneToOne(oto); + // removed unsettable because it is not used to define optional, it + // is used + // to allow distinction between the default value set or a feature + // which has not been + // set, this is used in validation + // oto.setOptional(!eReference.isRequired() || + // eReference.isUnsettable()); + oto.setOptional(!eReference.isRequired()); + oto.setEModelElement(eReference); + } else { + log.debug("EReference + " + logStr + " has an onetoone annotation setting defaults if required"); + } + + if (!oto.isSetFetch()) { + oto.setFetch(getFetch(aReference.getAReferenceType())); + } + + // determine where to put the mapped-by + if (oto.getMappedBy() == null && setMappedBy(eReference)) { + oto.setMappedBy(eReference.getEOpposite().getName()); + } + + if (getPersistenceOptions().isSetForeignKeyNames() && aReference.getForeignKey() == null) { + // See bugzilla 211798: handle a specific case when this is a + // bidirectional + // association. In that case the foreign key name has to be + // the same on both sides and is set on the many-side. So use the + // annotated reference from the other side to ensure that the same + // foreign key name + // is used. + if (eReference.getEOpposite() != null && !eReference.getEOpposite().isTransient()) { + final PAnnotatedEReference aOpposite = aReference.getPaModel().getPAnnotated(eReference.getEOpposite()); + if (aOpposite != null && aOpposite.getTransient() == null) { + // don't do anything as otherwise hibernate will create two + // fk's with the same name + + // if (aOpposite.getForeignKey() != null) { + // final ForeignKey fk = getFactory().createForeignKey(); + // fk.setName(aOpposite.getForeignKey().getName()); + // aReference.setForeignKey(fk); + // } else { + // aReference.setForeignKey(createFK(aOpposite)); + // } + } else { + aReference.setForeignKey(createFK(aReference)); + } + } else { + aReference.setForeignKey(createFK(aReference)); + } + } + + setCascade(oto.getCascade(), eReference.isContainment()); + + if (getPersistenceOptions().isMapEmbeddableAsEmbedded() && + aReference.getAReferenceType().getEmbeddable() != null) { + aReference.setEmbedded(getFactory().createEmbedded()); + } + + // Note: Sometimes EMF generated getters/setters have a + // very generic type (EObject), if the type can be derived here then + // this should + // be added here + if (oto.getTargetEntity() == null) { + oto.setTargetEntity(getEntityName(eReference.getEReferenceType())); + } + } +} diff --git a/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/annotations/mapper/PersistenceFileProvider.java b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/annotations/mapper/PersistenceFileProvider.java new file mode 100644 index 000000000..d851a8e98 --- /dev/null +++ b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/annotations/mapper/PersistenceFileProvider.java @@ -0,0 +1,50 @@ +/** + * <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: + * PersistenceMappingBuilder.java,v 1.10 2007/02/08 23:12:35 mtaal Exp $ + */ + +package org.eclipse.emf.teneo.annotations.mapper; + +import java.io.InputStream; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.eclipse.emf.teneo.extension.ExtensionPoint; + +/** + * Provides files to the mapping as well as to the runtime layers. It can be customized with an own + * implementation by replacing the class in the ExtensionManager. + * + * @author <a href="mailto:mtaal@elver.org">Martin Taal</a> + * @version $Revision: 1.3 $ + */ +public class PersistenceFileProvider implements ExtensionPoint { + + /** The logger */ + protected static final Log log = LogFactory.getLog(PersistenceFileProvider.class); + + /** + * Returns an InputStream with the file content, note if the file does not exist then null may + * be returned. This implementation searches for the file in the classpath using the path + * parameters. + * + * Custom implementations of this class may use any other method to find the file. + * + * @param clz + * the class to use when reading the file through a classloader + * @param path + * the path to the file (incl. the filename and extension) + * + * @return an InputStream if found, or null otherwise + */ + public InputStream getFileContent(Class<?> clz, String path) { + if (clz == null) { + return this.getClass().getClassLoader().getResourceAsStream(path); + } else { + return clz.getResourceAsStream(path); + } + } +}
\ No newline at end of file diff --git a/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/annotations/mapper/PersistenceMappingBuilder.java b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/annotations/mapper/PersistenceMappingBuilder.java new file mode 100755 index 000000000..f60660343 --- /dev/null +++ b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/annotations/mapper/PersistenceMappingBuilder.java @@ -0,0 +1,296 @@ +/** + * <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: + * PersistenceMappingBuilder.java,v 1.10 2007/02/08 23:12:35 mtaal Exp $ + */ + +package org.eclipse.emf.teneo.annotations.mapper; + +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.eclipse.emf.ecore.EClass; +import org.eclipse.emf.ecore.EClassifier; +import org.eclipse.emf.ecore.EDataType; +import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.ecore.EPackage; +import org.eclipse.emf.ecore.EStructuralFeature; +import org.eclipse.emf.ecore.EcorePackage; +import org.eclipse.emf.ecore.util.EcoreUtil; +import org.eclipse.emf.ecore.util.ExtendedMetaData; +import org.eclipse.emf.ecore.xml.type.XMLTypePackage; +import org.eclipse.emf.teneo.PackageRegistryProvider; +import org.eclipse.emf.teneo.PersistenceOptions; +import org.eclipse.emf.teneo.annotations.StoreAnnotationsException; +import org.eclipse.emf.teneo.annotations.pamodel.PAnnotatedEAttribute; +import org.eclipse.emf.teneo.annotations.pamodel.PAnnotatedEClass; +import org.eclipse.emf.teneo.annotations.pamodel.PAnnotatedEDataType; +import org.eclipse.emf.teneo.annotations.pamodel.PAnnotatedEPackage; +import org.eclipse.emf.teneo.annotations.pamodel.PAnnotatedEStructuralFeature; +import org.eclipse.emf.teneo.annotations.pamodel.PAnnotatedModel; +import org.eclipse.emf.teneo.annotations.parser.EAnnotationParserImporter; +import org.eclipse.emf.teneo.annotations.xml.XmlPersistenceMapper; +import org.eclipse.emf.teneo.extension.ExtensionManager; +import org.eclipse.emf.teneo.extension.ExtensionPoint; +import org.eclipse.emf.teneo.util.StoreUtil; + +/** + * Receives a list of ecore files and generates a mapping model using different strategies. The mapping model is + * returned. + * + * @author <a href="mailto:mtaal@elver.org">Martin Taal</a> + * @version $Revision: 1.14 $ + */ +public class PersistenceMappingBuilder implements ExtensionPoint { + + /** The logger */ + protected static final Log log = LogFactory.getLog(PersistenceMappingBuilder.class); + + /** The instance to use */ + public static final PersistenceMappingBuilder INSTANCE = new PersistenceMappingBuilder(); + + /** + * Receives a list of ecore files and returns a Mapping + */ + public PAnnotatedModel buildMapping(String[] ecoreFiles, PersistenceOptions po, ExtensionManager extensionManager) { + return buildMapping(StoreUtil.readEPackages(ecoreFiles), po, extensionManager); + } + + /** + * Builds a persistence mapping for one or more epackages + * + * @Deprecated use the method with the List<EPackage> parameter + */ + public PAnnotatedModel buildMapping(EPackage[] epackages, PersistenceOptions po, ExtensionManager extensionManager) { + return buildMapping(Arrays.asList(epackages), po, extensionManager); + } + + /** + * Builds a persistence mapping for one or more epackages + */ + public PAnnotatedModel buildMapping(List<EPackage> epacks, PersistenceOptions po, ExtensionManager extensionManager) { + // read the subepackages + List<EPackage> epackages = new ArrayList<EPackage>(); + for (EPackage epack : epacks) { + resolveSubPackages(epack, epackages); + } + + if (po.isAutoAddReferencedEPackages()) { + final List<EPackage> allEPackages = new ArrayList<EPackage>(); + for (EPackage ePackage : epackages) { + addAllUsedEPackages(ePackage, allEPackages); + } + if (epackages.contains(EcorePackage.eINSTANCE)) { + allEPackages.add(EcorePackage.eINSTANCE); + } + if (epackages.contains(XMLTypePackage.eINSTANCE)) { + allEPackages.add(XMLTypePackage.eINSTANCE); + } + epackages = allEPackages; + } + + // DCB: Introduce indirection so that extensions to annotation + // processing mechanism + // can provide their own model builder. + BasicPamodelBuilder pamodelBuilder = extensionManager.getExtension(BasicPamodelBuilder.class); + log.debug("Creating pamodel for the following epackages"); + for (EPackage element : epackages) { + log.debug(element.getName()); + pamodelBuilder.addRecurse(element); + } + + if (po.isMapDocumentRoot()) { + // use the ecore package which is present in the package registry + final EPackage ecorePackage = PackageRegistryProvider.getInstance().getPackageRegistry().getEPackage( + EcorePackage.eNS_URI); + final EClassifier eClassifier = ecorePackage.getEClassifier(EcorePackage.eINSTANCE + .getEStringToStringMapEntry().getName()); + pamodelBuilder.addSpecificEClass((EClass) eClassifier); + } + + log.debug("Create base pannotated model"); + PAnnotatedModel pam = pamodelBuilder.getPAnnotatedModel(); + + log.debug("Deprecated eannotations with http://annotations.elver.org or http://ejb.elver.org are ignored."); + // if (po.isIgnoreEAnnotations()) { + // log.debug("Ignoring eannotations"); + // } else { + // log.debug("Import eannotations"); + // // DCB: Introduce indirection so that extensions to annotation + // processing mechanism + // // can provide their own model builder. + // EannotationPamodelBuilder epb = getAnnotationModelBuilder(); + // epb.setPAnnotatedModel(pam); + // epb.processCurrentPAnnotatedModel(); + // } + + if (po.isIgnoreEAnnotations()) { + log.debug("Ignoring annotations"); + } else { + log.debug("Parse annotations"); + final EAnnotationParserImporter parserImporter = extensionManager + .getExtension(EAnnotationParserImporter.class); + parserImporter.setExtraAnnotationSources(po); + parserImporter.process(pam); + } + + if (po.getPersistenceXmlPath() != null) { + try { + final PersistenceFileProvider fileProvider = extensionManager + .getExtension(PersistenceFileProvider.class); + final InputStream in = fileProvider.getFileContent(null, po.getPersistenceXmlPath()); + if (in == null) { + throw new RuntimeException("Could not find persistence XML resource in classpath: \"" + + po.getPersistenceXmlPath() + "\"."); + } + final XmlPersistenceMapper xmlPersistenceMapper = extensionManager + .getExtension(XmlPersistenceMapper.class); + xmlPersistenceMapper.setXmlMapping(in); + xmlPersistenceMapper.applyPersistenceMapping(pam); + in.close(); + final InputStream[] iss = getAdditionalXMLMappings(); + for (InputStream element : iss) { + xmlPersistenceMapper.setXmlMapping(element); + xmlPersistenceMapper.applyPersistenceMapping(pam); + element.close(); + } + } catch (IOException e) { + throw new StoreAnnotationsException("Exception while loading xml persistence mappings", e); + } + } + + // now the annotations on the edatatype should be copied to the + // annotations on the + // eattribute, overwrite may not occur! + processEDataTypeAnnotations(pam); + + log.debug("Add default annotations"); + // DCB: Introduce indirection so that extensions to annotation + // processing mechanism + // can provide their own default annotation. + pam.setInitialized(true); + extensionManager.getExtension(AnnotationGenerator.class).map(pam, po); + + log.debug("Returning created pamodel"); + return pam; + } + + private void resolveSubPackages(EPackage epack, List<EPackage> epacks) { + if (!epacks.contains(epack)) { + epacks.add(epack); + } + + for (EPackage subEPackage : epack.getESubpackages()) { + resolveSubPackages(subEPackage, epacks); + } + } + + private void addAllUsedEPackages(EPackage eCurrentEPackage, List<EPackage> ePackages) { + if (eCurrentEPackage == null) { + return; + } + if (ePackages.contains(eCurrentEPackage)) { + return; + } + // do not resolve these + if (eCurrentEPackage instanceof EcorePackage || eCurrentEPackage instanceof XMLTypePackage) { + return; + } + // prevent recursion + ePackages.add(eCurrentEPackage); + + // note super epackage can be null, handled in first if above + addAllUsedEPackages(eCurrentEPackage.getESuperPackage(), ePackages); + for (EPackage subPackage : eCurrentEPackage.getESubpackages()) { + addAllUsedEPackages(subPackage, ePackages); + } + + // now capture each type + for (EClassifier eClassifier : eCurrentEPackage.getEClassifiers()) { + addAllUsedEPackages(eClassifier, ePackages); + } + } + + private void addAllUsedEPackages(EClassifier eClassifier, List<EPackage> ePackages) { + if (eClassifier instanceof EClass) { + addAllUsedEPackages((EClass) eClassifier, ePackages); + } else { + addAllUsedEPackages((EDataType) eClassifier, ePackages); + } + } + + private void addAllUsedEPackages(EClass eClass, List<EPackage> ePackages) { + addAllUsedEPackages(eClass.getEPackage(), ePackages); + for (EClass eSuperClass : eClass.getESuperTypes()) { + // apparently there is a cycle in one of the XSD/XML packages, this prevents this. + if (!ePackages.contains(eSuperClass.getEPackage())) { + addAllUsedEPackages(eSuperClass, ePackages); + } + } + for (EStructuralFeature eFeature : eClass.getEStructuralFeatures()) { + if (!ePackages.contains(eFeature.getEType().getEPackage())) { + addAllUsedEPackages(eFeature.getEType(), ePackages); + } + } + } + + private void addAllUsedEPackages(EDataType eDataType, List<EPackage> ePackages) { + if (eDataType == null) { + return; + } + addAllUsedEPackages(eDataType.getEPackage(), ePackages); + addAllUsedEPackages(ExtendedMetaData.INSTANCE.getBaseType(eDataType), ePackages); + } + + /** + * For each pannotated eattribute find the pannotated edatatype and copy the values of the estructuralfeature if not + * yet set in the eattribute + */ + protected void processEDataTypeAnnotations(PAnnotatedModel pam) { + log.debug("Copying annotations on edatatypes over eattribute annotations!"); + for (PAnnotatedEPackage pep : pam.getPaEPackages()) { + for (PAnnotatedEClass pec : pep.getPaEClasses()) { + for (PAnnotatedEStructuralFeature pef : pec.getPaEStructuralFeatures()) { + if (pef instanceof PAnnotatedEAttribute) { + final PAnnotatedEAttribute pea = (PAnnotatedEAttribute) pef; + final EDataType et = pea.getModelEAttribute().getEAttributeType(); + final PAnnotatedEDataType ped = pam.getPAnnotated(et); + if (ped == null) { + continue; // not an explicit modeled edatatype + } + for (EStructuralFeature esf : ped.eClass().getEAllStructuralFeatures()) { + final EStructuralFeature asf = pea.eClass().getEStructuralFeature(esf.getName()); + if (asf != null && !pea.eIsSet(asf) && ped.eIsSet(esf)) { + log.debug("Copying value for feature " + esf.getName() + " from edatatype " + + et.getName() + " to " + pea.getModelEAttribute().getName()); + + final Object obj = ped.eGet(esf); + if (obj instanceof Collection<?>) { + pea.eSet(asf, EcoreUtil.copyAll((Collection<?>) obj)); + } else if (obj instanceof EObject) { + pea.eSet(asf, EcoreUtil.copy((EObject) obj)); + } else { + throw new StoreAnnotationsException("Class " + obj.getClass().getName() + + " not supported should be eobject or collection"); + } + } + } + } + } + } + } + } + + /** Additional inputstreams for xml mappings */ + protected InputStream[] getAdditionalXMLMappings() { + return new InputStream[0]; + } +}
\ No newline at end of file diff --git a/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/annotations/mapper/SingleAttributeAnnotator.java b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/annotations/mapper/SingleAttributeAnnotator.java new file mode 100755 index 000000000..4979d1e98 --- /dev/null +++ b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/annotations/mapper/SingleAttributeAnnotator.java @@ -0,0 +1,153 @@ +/** + * <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: SingleAttributeAnnotator.java,v 1.12 2009/09/14 21:40:14 mtaal Exp $ + */ + +package org.eclipse.emf.teneo.annotations.mapper; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.eclipse.emf.ecore.EAttribute; +import org.eclipse.emf.ecore.EEnum; +import org.eclipse.emf.teneo.PersistenceOptions; +import org.eclipse.emf.teneo.annotations.pamodel.PAnnotatedEAttribute; +import org.eclipse.emf.teneo.annotations.pannotation.Basic; +import org.eclipse.emf.teneo.annotations.pannotation.EnumType; +import org.eclipse.emf.teneo.annotations.pannotation.Enumerated; +import org.eclipse.emf.teneo.annotations.pannotation.GeneratedValue; +import org.eclipse.emf.teneo.annotations.pannotation.GenerationType; +import org.eclipse.emf.teneo.annotations.pannotation.Id; +import org.eclipse.emf.teneo.annotations.pannotation.TemporalType; +import org.eclipse.emf.teneo.extension.ExtensionPoint; + +/** + * Annotates a single attribute, a primitive type such as a long or int. + * + * @author <a href="mailto:mtaal@elver.org">Martin Taal</a> + * @version $Revision: 1.12 $ + */ + +public class SingleAttributeAnnotator extends BaseEFeatureAnnotator implements ExtensionPoint { + + // The logger + protected static final Log log = LogFactory.getLog(SingleAttributeAnnotator.class); + + private TemporalType optionDefaultTemporal = null; + + /** Process the features of the eclass */ + public void annotate(PAnnotatedEAttribute aAttribute) { + + log.debug(" Adding default annotations for EAttribute " + aAttribute.getModelElement().getName()); + + final EAttribute eAttribute = (EAttribute) aAttribute.getModelElement(); + + // this is done before adding the id because an enumerated can also be + // an id + if (eAttribute.getEType() instanceof EEnum && aAttribute.getEnumerated() == null) { + final Enumerated enumerated = getFactory().createEnumerated(); + enumerated.setValue(EnumType.STRING); + enumerated.setEModelElement(eAttribute); + aAttribute.setEnumerated(enumerated); + } + + if (getPersistenceOptions().isIDFeatureAsPrimaryKey() && eAttribute.isID() && aAttribute.getId() == null) { + // bugzilla 249246 + if (aAttribute.getPaEClass().getPaSuperEntity() != null + && aAttribute.getPaEClass().getPaSuperEntity().getMappedSuperclass() == null) { + log + .warn("The eclass " + + aAttribute.getPaEClass().getModelEClass().getName() + + " has an efeature (" + + aAttribute.getModelEAttribute().getName() + + ")" + + " which has type ID, Teneo will not annotate this efeature with @Id because it is an efeature of a subtype"); + } else { + final Id id = getFactory().createId(); + id.setEModelElement(eAttribute); + aAttribute.setId(id); + addColumnConstraints(aAttribute); + + if (getPersistenceOptions().isSetGeneratedValueOnIDFeature() + && aAttribute.getGeneratedValue() == null + && (Number.class.isAssignableFrom(eAttribute.getEAttributeType().getInstanceClass()) + || eAttribute.getEAttributeType().getInstanceClass() == long.class || eAttribute + .getEAttributeType().getInstanceClass() == int.class)) { + final GeneratedValue gv = getFactory().createGeneratedValue(); + gv.setStrategy(GenerationType.AUTO); + aAttribute.setGeneratedValue(gv); + } + + return; // after id do not add basic + } + } else if (aAttribute.getId() != null) { + addColumnConstraints(aAttribute); + return; // after id do not do basic + } + + if (aAttribute.getTemporal() == null) { + setTemporal(aAttribute, optionDefaultTemporal); + } + + if (aAttribute.getBasic() == null) { + // primitive defaults are set in the model itself + final Basic basic = getFactory().createBasic(); + basic.setEModelElement(eAttribute); + + // NOTE: the ejb3 spec says that for primitivie optional does not + // apply, this is + // confusing why having this then? If this applies then for each + // basic and nullable + // field a column annotation has to be added to force nullability + + // removed unsettable because it is not used to define optional, it + // is used + // to allow distinction between the default value set or a feature + // which has not been + // set, this is used in validation + // basic.setOptional(!eAttribute.isRequired() || + // eAttribute.isUnsettable()); + if (aAttribute.getColumn() != null) { + basic.setOptional(aAttribute.getColumn().isNullable()); + } else { + basic.setOptional(!eAttribute.isRequired() || eAttribute.isUnsettable()); + } + aAttribute.setBasic(basic); + } + + if (aAttribute.getId() != null) { + aAttribute.getBasic().setOptional(false); + if (aAttribute.getColumn() != null && aAttribute.getColumn().isNullable()) { + log.warn("The column of a primary key property is null, this will often result in database errors!"); + } + } + addColumnConstraints(aAttribute); + } + + /* + * (non-Javadoc) + * + * @seeorg.eclipse.emf.teneo.annotations.mapper.AbstractAnnotator# setPersistenceOptions(org.eclipse + * .emf.teneo.PersistenceOptions) + */ + @Override + public void setPersistenceOptions(PersistenceOptions persistenceOptions) { + super.setPersistenceOptions(persistenceOptions); + + optionDefaultTemporal = TemporalType.get(persistenceOptions.getDefaultTemporalValue()); + if (optionDefaultTemporal == null) { + throw new StoreMappingException("Temporal value not found: " + persistenceOptions.getDefaultTemporalValue()); + } + } + +} diff --git a/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/annotations/mapper/StoreMappingException.java b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/annotations/mapper/StoreMappingException.java new file mode 100755 index 000000000..ac7434da2 --- /dev/null +++ b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/annotations/mapper/StoreMappingException.java @@ -0,0 +1,51 @@ +/** + * <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: StoreMappingException.java,v 1.6 2009/03/30 07:53:04 mtaal Exp $ + */ + +package org.eclipse.emf.teneo.annotations.mapper; + +import org.eclipse.emf.teneo.TeneoException; + +/** + * This exception is the base class of all exceptions which occur in the mapping process. This class + * offers automatic logging to commons logging. Note that this class extends RuntimeException, so no + * forced throws and catch statements. Although there are very differing views on this topic but it + * is our experience that to many checked exceptions only distract the programmer and have no added + * value. + * + * @author <a href="mailto:mtaal@elver.org">Martin Taal</a> + * @version $Revision: 1.6 $ + */ + +public class StoreMappingException extends TeneoException { + /** + * Serial id + */ + private static final long serialVersionUID = 4685665979865102829L; + + /** + * The constructor, logs the exception also + */ + public StoreMappingException(String msg, Throwable cause) { + super(msg, cause); + } + + /** + * The constructor, logs the exception also + */ + public StoreMappingException(String msg) { + super(msg); + } +} diff --git a/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/annotations/mapper/UnidirectionalManyToManyAnnotator.java b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/annotations/mapper/UnidirectionalManyToManyAnnotator.java new file mode 100755 index 000000000..ea2611405 --- /dev/null +++ b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/annotations/mapper/UnidirectionalManyToManyAnnotator.java @@ -0,0 +1,91 @@ +/** + * <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: UnidirectionalManyToManyAnnotator.java,v 1.9 2009/03/30 07:53:04 mtaal Exp $ + */ + +package org.eclipse.emf.teneo.annotations.mapper; + +import java.util.List; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.eclipse.emf.ecore.EReference; +import org.eclipse.emf.teneo.annotations.pamodel.PAnnotatedEReference; +import org.eclipse.emf.teneo.annotations.pannotation.JoinTable; +import org.eclipse.emf.teneo.annotations.pannotation.ManyToMany; +import org.eclipse.emf.teneo.extension.ExtensionPoint; + +/** + * Annotates a many-to-many which is handled from one side. + * + * @author <a href="mailto:mtaal@elver.org">Martin Taal</a> + * @version $Revision: 1.9 $ + */ + +public class UnidirectionalManyToManyAnnotator extends BaseEFeatureAnnotator implements ExtensionPoint { + + // The logger + protected static final Log log = LogFactory.getLog(UnidirectionalManyToManyAnnotator.class); + + /** Process the features of the eclass */ + public void annotate(PAnnotatedEReference aReference) { + final String featureLogStr = + aReference.getModelEReference().getName() + "/" + + aReference.getModelEReference().getEContainingClass().getName(); + + if (aReference.getOneToMany() != null || aReference.getOneToOne() != null || aReference.getManyToOne() != null) { + throw new StoreMappingException("The feature/eclass " + featureLogStr + " should be a ManyToMany but " + + "it already has a OneToMany, OneToOne or ManyToOne annotation"); + } + + final EReference eReference = (EReference) aReference.getModelElement(); + + // note that mtm is always present because this case can not be + // discovered by Teneo + final ManyToMany mtm = aReference.getManyToMany(); + log.debug("ManyToMany present check if default information should be added"); + mtm.setEModelElement(eReference); + + if (eReference.isContainment() || getPersistenceOptions().isSetDefaultCascadeOnNonContainment()) { + setCascade(mtm.getCascade(), eReference.isContainment()); + } + + if (mtm.getTargetEntity() == null) { + mtm.setTargetEntity(getEntityName(eReference.getEReferenceType())); + } + + // with a unidirectional mtm the join is always placed here + JoinTable joinTable = aReference.getJoinTable(); + if (joinTable == null) { + joinTable = getFactory().createJoinTable(); + aReference.setJoinTable(joinTable); + } + joinTable.setEModelElement(eReference); + + if (getPersistenceOptions().isSetForeignKeyNames() && aReference.getForeignKey() == null) { + aReference.setForeignKey(createFK(aReference)); + } + + // note that here not the eclass name is used for the opposite side but + // the name of the targetentity + // because that's the one which is known here + if (joinTable.getName() == null) { + joinTable.setName(getSqlNameStrategy().getJoinTableName(aReference)); + } + if (joinTable.getJoinColumns() == null) { + final List<String> names = getSqlNameStrategy().getJoinTableJoinColumns(aReference, false); + joinTable.getJoinColumns().addAll(getJoinColumns(names, false, true, mtm)); + } + } +} diff --git a/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/annotations/parser/AnnotationParser.java b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/annotations/parser/AnnotationParser.java new file mode 100755 index 000000000..bc5cface6 --- /dev/null +++ b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/annotations/parser/AnnotationParser.java @@ -0,0 +1,264 @@ +/** + * <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: AnnotationParser.java,v 1.3 2008/04/06 13:44:04 mtaal Exp $ + */ + +package org.eclipse.emf.teneo.annotations.parser; + +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.emf.ecore.ENamedElement; + +/** + * Parses an annotation and creates a tree of parserNodes. + * + * See AnnotationTokenizer for a short description on the type of parsed tokens. + * + * @author <a href="mailto:mtaal at elver.org">Martin Taal</a> + */ +public class AnnotationParser { + + /** The StringTokenizer being used */ + private AnnotationTokenizer annotationTokenizer; + + /** The list of root nodes */ + private List<NamedParserNode> parserNodes = new ArrayList<NamedParserNode>(); + + private long expectedToken = Long.MAX_VALUE; + + /** Parses the content and returns a list of parsernodes */ + public List<NamedParserNode> parse(ENamedElement eNamedElement, String content) { + annotationTokenizer = new AnnotationTokenizer(eNamedElement, content); + parserNodes.clear(); + int token; + while (annotationTokenizer.getCurrentToken() != AnnotationTokenizer.T_EOF && + (token = annotationTokenizer.nextToken()) != AnnotationTokenizer.T_EOF) { + if (token != AnnotationTokenizer.T_TYPENAME) { + throw new AnnotationParserException("Only typenames are allowed at the root of the " + + "annotation, see _ for the error " + annotationTokenizer.getErrorText()); + } + parseTypeName(null); + } + return parserNodes; + } + + /** Adds a child to the parent */ + private void addToParent(NamedParserNode parent, NamedParserNode child) { + if (parent == null) { + return; + } + if (parent instanceof ComplexNode) { + ((ComplexNode) parent).getChildren().add(child); + } else if (parent instanceof ArrayValueNode) { + ((ArrayValueNode) parent).getChildren().add(child); + } else if (parent instanceof ReferenceValueNode) { + ((ReferenceValueNode) parent).setValue(child); + } + } + + /** Parse a type name (a complex type) */ + private void parseTypeName(NamedParserNode pn) { + final ComplexNode cn = new ComplexNode(); + cn.setName(annotationTokenizer.getLexeme()); + addToParent(pn, cn); + if (pn == null) { + parserNodes.add(cn); + } + + // now parse the next token + final int token = annotationTokenizer.nextToken(); + + switch (token) { + case AnnotationTokenizer.T_EOF: + return; + case AnnotationTokenizer.T_CONTENTSTART: + parseContent(cn); + break; + case AnnotationTokenizer.T_TYPENAME: + parseTypeName(null); // the next one + break; + case AnnotationTokenizer.T_COMMA: // in case of array + if (!(pn instanceof ArrayValueNode)) { + throw new AnnotationParserException( + "Encountered comma but not within an array definition, see _ for error location " + + annotationTokenizer.getErrorText()); + } + return; + default: + throw new AnnotationParserException("Unknown token, see _ for error position: " + + annotationTokenizer.getErrorText()); + } + } + + /** Parse the content of a typeName */ + private void parseContent(NamedParserNode pn) { + // content can either be an array or a set of values + + expectedToken = + AnnotationTokenizer.T_ARRAYSTART + AnnotationTokenizer.T_IDENTIFIER + AnnotationTokenizer.T_VALUE; + + boolean finished = false; + while (!finished) { + final int token = annotationTokenizer.nextToken(); + checkToken(token); + switch (token) { + case AnnotationTokenizer.T_COMMA: + expectedToken = AnnotationTokenizer.T_IDENTIFIER; + break; + case AnnotationTokenizer.T_EOF: + throw new AnnotationParserException("Unexcepted end to annotation string, " + + annotationTokenizer.getErrorText()); + case AnnotationTokenizer.T_CONTENTEND: + return; + case AnnotationTokenizer.T_VALUE: + final String theValue = annotationTokenizer.getLexeme(); + final PrimitiveValueNode valueNode = new PrimitiveValueNode(); + valueNode.setName("value"); + valueNode.setValue(theValue); + addToParent(pn, valueNode); + if (annotationTokenizer.nextToken() != AnnotationTokenizer.T_CONTENTEND) { + throw new AnnotationParserException("After this value a closing ) should follow " + + annotationTokenizer.getErrorText()); + } + return; + case AnnotationTokenizer.T_IDENTIFIER: + final String identifier = annotationTokenizer.getLexeme(); + // next token must be an is + int nextToken = annotationTokenizer.nextToken(); + // in case of simple annotations with just a value member + if (nextToken == AnnotationTokenizer.T_CONTENTEND) { + final PrimitiveValueNode vn = new PrimitiveValueNode(); + vn.setName("value"); + vn.setValue(identifier); + addToParent(pn, vn); + return; + } + if (nextToken != AnnotationTokenizer.T_IS) { + throw new AnnotationParserException( + "No = character after identifier, see _ for error position " + + annotationTokenizer.getErrorText()); + } + nextToken = annotationTokenizer.nextToken(); + // if (nextToken == AnnotationTokenizer.T_VALUE) { + // final String value = annotationTokenizer.getLexeme(); + // final PrimitiveValueNode vn = new PrimitiveValueNode(); + // vn.setName(identifier); + // vn.setValue(value); + // addToParent(pn, vn); + // } + if (nextToken == AnnotationTokenizer.T_VALUE) { + final String value = annotationTokenizer.getLexeme(); + final PrimitiveValueNode vn = new PrimitiveValueNode(); + vn.setName(identifier); + vn.setValue(value); + addToParent(pn, vn); + } else if (nextToken == AnnotationTokenizer.T_IDENTIFIER) { + final String value = annotationTokenizer.getLexeme(); + final PrimitiveValueNode vn = new PrimitiveValueNode(); + vn.setName(identifier); + vn.setValue(value); + addToParent(pn, vn); + } else if (nextToken == AnnotationTokenizer.T_TYPENAME) { + final ReferenceValueNode rvn = new ReferenceValueNode(); + rvn.setName(identifier); + parseTypeName(rvn); + addToParent(pn, rvn); + } else if (nextToken == AnnotationTokenizer.T_ARRAYSTART) { + final ArrayValueNode avn = new ArrayValueNode(); + avn.setName(identifier); + parseArray(avn); + addToParent(pn, avn); + } else if (annotationTokenizer.nextToken() != AnnotationTokenizer.T_VALUE) { + throw new AnnotationParserException("No value token after =, see _ for error position " + + annotationTokenizer.getErrorText()); + } + expectedToken = + AnnotationTokenizer.T_COMMA + AnnotationTokenizer.T_IDENTIFIER + + AnnotationTokenizer.T_CONTENTEND; + break; + case AnnotationTokenizer.T_ARRAYSTART: + // special case in which the main type is just a list of other + // types + // for example SecondaryTables which is just a list of + // SecondaryTable + parseArray(pn); + ((ComplexNode) pn).setList(true); + expectedToken = + AnnotationTokenizer.T_COMMA + AnnotationTokenizer.T_IDENTIFIER + + AnnotationTokenizer.T_CONTENTEND; + break; + } + } + } + + /** Parse an array */ + private void parseArray(NamedParserNode pn) { + // content can either be an array or a set of values + final ArrayValueNode an = new ArrayValueNode(); + addToParent(pn, an); + boolean finished = false; + + expectedToken = AnnotationTokenizer.T_TYPENAME + AnnotationTokenizer.T_VALUE + AnnotationTokenizer.T_IDENTIFIER; + + while (!finished) { + final int token = annotationTokenizer.nextToken(); + checkToken(token); + switch (token) { + case AnnotationTokenizer.T_EOF: + throw new AnnotationParserException("Unexcepted end to annotation string, " + + annotationTokenizer.getErrorText()); + case AnnotationTokenizer.T_TYPENAME: + parseTypeName(an); + + expectedToken = AnnotationTokenizer.T_ARRAYEND + AnnotationTokenizer.T_COMMA; + + break; + case AnnotationTokenizer.T_VALUE: + String value = annotationTokenizer.getLexeme(); + if (value != null && value.length() > 1 && value.charAt(0) == '"' && + value.charAt(value.length() - 1) == '"') { + value = value.substring(1, value.length() - 1); + } + an.getChildren().add(value); + expectedToken = AnnotationTokenizer.T_ARRAYEND + AnnotationTokenizer.T_COMMA; + break; + case AnnotationTokenizer.T_IDENTIFIER: + an.getChildren().add(annotationTokenizer.getLexeme()); + + expectedToken = + AnnotationTokenizer.T_IS + AnnotationTokenizer.T_ARRAYEND + AnnotationTokenizer.T_COMMA; + break; + case AnnotationTokenizer.T_COMMA: + expectedToken = + AnnotationTokenizer.T_TYPENAME + AnnotationTokenizer.T_VALUE + + AnnotationTokenizer.T_IDENTIFIER; + break; + case AnnotationTokenizer.T_ARRAYEND: + expectedToken = Long.MAX_VALUE; + return; + } + } + throw new AnnotationParserException("Unexpected end of array. " + annotationTokenizer.getErrorText()); + } + + protected void checkToken(int currentToken) { + if ((currentToken & expectedToken) == 0) { + final String msg = + "Found " + annotationTokenizer.getCurrentTokenName() + " but expected one of : " + + annotationTokenizer.getTokenNames(expectedToken); + throw new AnnotationParserException(msg + ". " + annotationTokenizer.getErrorText()); + } + } +} diff --git a/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/annotations/parser/AnnotationParserException.java b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/annotations/parser/AnnotationParserException.java new file mode 100755 index 000000000..5477096d7 --- /dev/null +++ b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/annotations/parser/AnnotationParserException.java @@ -0,0 +1,40 @@ +/** + * <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: + * AnnotationParserException.java,v 1.4 2007/02/08 23:12:34 mtaal Exp $ + */ + +package org.eclipse.emf.teneo.annotations.parser; + +import org.eclipse.emf.teneo.TeneoException; + +/** + * Is thrown in the org.eclipse.emf.teneo.annotations.parser package. Takes care of logging the + * cause. + * + * @author <a href="mailto:mtaal@elver.org">Martin Taal</a> + * @version $Revision: 1.2 $ + */ + +public class AnnotationParserException extends TeneoException { + /** + * Serial id + */ + private static final long serialVersionUID = 4685665979865102829L; + + /** + * The constructor, logs the exception also + */ + public AnnotationParserException(String msg, Throwable cause) { + super(msg, cause); + } + + /** + * The constructor, logs the exception also + */ + public AnnotationParserException(String msg) { + super(msg); + } +} diff --git a/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/annotations/parser/AnnotationTokenizer.java b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/annotations/parser/AnnotationTokenizer.java new file mode 100755 index 000000000..744aee878 --- /dev/null +++ b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/annotations/parser/AnnotationTokenizer.java @@ -0,0 +1,357 @@ +/** + * <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: AnnotationTokenizer.java,v 1.12 2009/03/30 07:53:05 mtaal Exp $ + */ + +package org.eclipse.emf.teneo.annotations.parser; + +import java.util.HashMap; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.eclipse.emf.ecore.ENamedElement; +import org.eclipse.emf.teneo.annotations.StoreAnnotationsException; + +/** + * Tokenizes a java annotation. The main tokens are: - TypeName - Identifier - Value - Array + * + * For example the following java annotation + * + * @GenericGenerator(name="hibseq", strategy = "hilo", parameters = { + * @Parameter(name="table", value = "hilo_table"), + * @Parameter(name="column", value="the_hilo_column")} ) + * + * Here GenericGenerator is a TypeName, name and strategy are Identifiers + * and "hilo_table" is a value, the array is the part between the {}. + * + * There is a special case where the typename is actually a list of + * values, e.g. SecondaryTables. These are treated as a special type of + * TypeName which is translated into a ComplexNode with isList=true. This + * is currently only supported at the top level. + * + * @author <a href="mailto:mtaal at elver.org">Martin Taal</a> + */ +class AnnotationTokenizer { + /** Log it */ + private final static Log log = LogFactory.getLog(AnnotationTokenizer.class); + + /** Special Tokens */ + static final int T_EOF = 4096; + + private static final int T_EOL = 8192; + + private static final int T_UNKNOWN = 16384; + + /** + * Annotation tokens + */ + static final int T_TYPENAME = 2; + + static final int T_IDENTIFIER = 4; + + static final int T_ARRAYSTART = 8; + + static final int T_ARRAYEND = 16; + + static final int T_VALUE = 32; + + static final int T_IS = 64; + + static final int T_CONTENTSTART = 128; + + static final int T_CONTENTEND = 256; + + static final int T_COMMA = 512; + + /** Data */ + private char[] data; + + /** Length */ + private int length; + + /** Points to the start of the current token */ + + private int tokBeg; + + /** Ponts to the end of the current token. */ + private int tokEnd; + + /** The last returned token */ + private int currentToken = T_EOF - 1; + + private HashMap<Integer, String> constantToName = new HashMap<Integer, String>(); + + /** + * Constructor + */ + + AnnotationTokenizer(ENamedElement eNamedElement, String source) { + setSource(source.toCharArray()); + constantToName.put(2, "Annotation"); + constantToName.put(4, "Attribute Name"); + constantToName.put(8, "Array Start ({)"); + constantToName.put(16, "Array End (})"); + constantToName.put(32, "Value (e.g. String, int)"); + constantToName.put(64, "= character"); + constantToName.put(128, "Annotation content start ('(')"); + constantToName.put(256, "Annotation content end (')')"); + constantToName.put(512, "Comma (,)"); + + constantToName.put(1024, "Carriage Return"); + constantToName.put(2048, "Line Feed"); + constantToName.put(4096, "EOF"); + constantToName.put(8192, "EOL"); + constantToName.put(16384, "Unknown"); + } + + public String getCurrentTokenName() { + final String name = constantToName.get(currentToken); + if (name == null) { + throw new StoreAnnotationsException("Illegal token " + currentToken); + } + return name; + } + + public String getTokenNames(long tokens) { + final StringBuffer sb = new StringBuffer(); + for (Integer key : constantToName.keySet()) { + + if ((tokens & key.intValue()) > 0) { + if (sb.length() > 0) { + sb.append(", "); + } + sb.append(constantToName.get(key)); + } + } + return sb.toString(); + } + + /** + * Sets the source to be tokenized form a character array. + */ + + private void setSource(char[] iSource) { + length = iSource.length; + // Append three null-characters as sentinel since three + // look-ahead characters are required (e.g. for the '>>>=' token). + data = new char[length + 3]; + System.arraycopy(iSource, 0, data, 0, length); + + data[length] = 0; // Append the sentinel characters. + data[length + 1] = 0; + data[length + 2] = 0; + + tokBeg = 0; + tokEnd = 0; + + log.debug(dump()); + } + + /** + * Returns the next token. + */ + + final int nextToken() { + currentToken = getNextToken(); + return currentToken; + } + + /** Return the curren token */ + final int getCurrentToken() { + return currentToken; + } + + /** + * Returns the next token. + */ + + final int getNextToken() { + int lCur = tokEnd; + + Loop: for (;;) { + char lChar = data[lCur]; // Grab next character. + + switch (lChar) { + case ' ': // Skip leading whitespace! + case '\n': // new line + case '\r': // Carriage Return. + case '\f': // Line Feed. + case '\t': { + lCur++; + continue Loop; // --> Keep on skipping leading whitespace! + } + + case 0: // End of buffer. + { + if (lCur == length) // Guard against embedded nulls in the + // Source. + { + // EOBuf may only occur at the first non whitespace char. + + return T_EOF; // --> End of file. + } + throw new AnnotationParserException("Char is 0 but end not reached " + lCur + " " + length); + } + + // TYPENAME + case '@': { + ++lCur; // get rid of the @ + tokBeg = lCur; // Save starting point of current lexeme. + + do { + lChar = data[++lCur]; + } while (lChar == '-' || lChar == '_' || lChar == '/' || lChar == '@' || + ('0' <= lChar && lChar <= '9') || lChar == ':' || ('a' <= lChar && lChar <= 'z') || + ('A' <= lChar && lChar <= 'Z')); + + tokEnd = lCur; // Save endpoint of current lexeme. + + return T_TYPENAME; // --> Identifier. + } + // VALUE with double quotes + case '"': { + // after the dollar the identifier part needs to be found + tokBeg = lCur; // Save starting point of current lexeme. + + do { + lChar = data[++lCur]; + } while (lChar == ',' || lChar == '-' || lChar == '.' || lChar == ' ' || lChar == '_' || + lChar == '/' || lChar == '`' || lChar == '@' || lChar == ':' || lChar == '=' || + lChar == '(' || lChar == ')' || lChar == '{' || lChar == '}' || lChar == '\'' || + lChar == '#' || lChar == '&' || lChar == '<' || lChar == '>' || lChar == '$' || + lChar == ';' || lChar == '%' || lChar == '*' || lChar == '\'' || + ('0' <= lChar && lChar <= '9') || ('a' <= lChar && lChar <= 'z') || lChar == '?' || + ('A' <= lChar && lChar <= 'Z')); + + if (lChar != '"') { + final AnnotationParserException e = + new AnnotationParserException( + "Value not closed with double quote, see the _ for the location " + getErrorText()); + tokEnd = lCur + 1; // prevent infinite looping + throw e; + } + tokEnd = lCur + 1; + return T_VALUE; + } + case '(': { + tokBeg = lCur; + tokEnd = lCur + 1; + return T_CONTENTSTART; + } + case ')': { + tokBeg = lCur; + tokEnd = lCur + 1; + return T_CONTENTEND; + } + case '{': { + tokBeg = lCur; + tokEnd = lCur + 1; + return T_ARRAYSTART; + } + case '}': { + tokBeg = lCur; + tokEnd = lCur + 1; + return T_ARRAYEND; + } + case ',': { + tokBeg = lCur; + tokEnd = lCur + 1; + return T_COMMA; + } + case '=': { + tokBeg = lCur; + tokEnd = lCur + 1; + return T_IS; + } + default: // the rest must be identifiers + { + // after the dollar the identifier part needs to be found + tokBeg = lCur; // Save starting point of current lexeme. + + do { + lChar = data[++lCur]; + } while (lChar == '.' || lChar == '-' || lChar == '_' || lChar == '/' || lChar == '@' || + ('0' <= lChar && lChar <= '9') || ('a' <= lChar && lChar <= 'z') || + ('A' <= lChar && lChar <= 'Z')); + + tokEnd = lCur; // Save endpoint of current lexeme. + + return T_IDENTIFIER; // --> Identifier. + } + } + } + } + + /** + * Returns the current lexeme. + */ + + final String getLexeme() { + return new String(data, tokBeg, tokEnd - tokBeg); + } + + /** + * Returns an error version of the query with a _ at the error location. + */ + final String getErrorText() { + // final StringBuffer result = new StringBuffer(); + // result.append("E Element: " + eNamedElement.getName() + "\n"); + // result.append("Begin: " + tokBeg + "\n"); + // result.append("End: " + tokEnd + "\n"); + // result.append("Length: " + data.length + "\n"); + // result.append("first part: " + new String(data, 0, tokEnd) + "\n"); + // result.append("Last part: " + new String(data, tokEnd, data.length - + // tokEnd - 2) + "\n"); + + return new String(data, 0, tokEnd) + "_" + new String(data, tokEnd, data.length - tokEnd - 2) + + "\nCurrent lexeme: " + getLexeme(); + } + + /** + * Dumps the tokens. + */ + + final String dump() { + final StringBuffer result = new StringBuffer(); + int oldTokBeg = tokBeg; + int oldTokEnd = tokEnd; + int oldCurrentToken = currentToken; + + // Reset pointers. + tokBeg = 0; + tokEnd = 0; + + boolean lFinished = false; + int lTok = 0; + while (!lFinished) { + try { + lTok = nextToken(); + if (lTok != T_EOL) // Don't log End-of-line tokens. + { + result.append("Tok: " + lTok + ": '" + getLexeme() + "'\n"); + } + } catch (AnnotationParserException e) { + result.append("Tok: " + T_UNKNOWN + ": " + getLexeme() + "'"); + throw e; + } + lFinished = lTok == T_EOF; + } + + // Restore state. + tokBeg = oldTokBeg; + tokEnd = oldTokEnd; + currentToken = oldCurrentToken; + return result.toString(); + } +} diff --git a/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/annotations/parser/ArrayValueNode.java b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/annotations/parser/ArrayValueNode.java new file mode 100755 index 000000000..1cfd3659f --- /dev/null +++ b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/annotations/parser/ArrayValueNode.java @@ -0,0 +1,65 @@ +/** + * <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: ArrayValueNode.java,v 1.3 2009/03/30 07:53:05 mtaal Exp $ + */ + +package org.eclipse.emf.teneo.annotations.parser; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +/** + * An array node contains a list of child values. + * + * @author <a href="mailto:mtaal at elver.org">Martin Taal</a> + */ +class ArrayValueNode extends NamedParserNode { + /** Log it */ + private final static Log log = LogFactory.getLog(ArrayValueNode.class); + + /** The value */ + private List<Object> children = new ArrayList<Object>(); + + /** Returns the list */ + List<Object> getChildren() { + return children; + } + + /** Translate into a list of eobjects */ + List<Object> convert(EClassResolver ecr) { + log.debug("Converting array value node"); + + final ArrayList<Object> result = new ArrayList<Object>(); + for (Object ob : children) { + if (ob instanceof String) { + result.add(ob); + } else if (ob instanceof ComplexNode) { + final ComplexNode cn = (ComplexNode) ob; + result.add(cn.convert(ecr)); + } else if (ob instanceof ReferenceValueNode) { + final ReferenceValueNode rvn = (ReferenceValueNode) ob; + result.add(rvn.convert(ecr)); + } else if (ob instanceof ArrayValueNode) { + final ArrayValueNode avn = (ArrayValueNode) ob; + result.addAll((List<Object>) avn.convert(ecr)); + } else { + throw new AnnotationParserException("Type " + ob.getClass().getName() + " not supported here"); + } + } + return result; + } +} diff --git a/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/annotations/parser/ComplexNode.java b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/annotations/parser/ComplexNode.java new file mode 100755 index 000000000..0f818d71a --- /dev/null +++ b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/annotations/parser/ComplexNode.java @@ -0,0 +1,178 @@ +/** + * <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: ComplexNode.java,v 1.5 2011/02/21 06:40:04 mtaal Exp $ + */ + +package org.eclipse.emf.teneo.annotations.parser; + +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.EClassifier; +import org.eclipse.emf.ecore.EDataType; +import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.ecore.EReference; +import org.eclipse.emf.ecore.EStructuralFeature; +import org.eclipse.emf.ecore.util.EcoreUtil; +import org.eclipse.emf.teneo.annotations.pannotation.PAnnotation; + +/** + * Models a real type (a complex type in xml schema speak), an EClass. + * + * @author <a href="mailto:mtaal at elver.org">Martin Taal</a> + */ +class ComplexNode extends NamedParserNode { + + /** Log it */ + private final static Log log = LogFactory.getLog(ComplexNode.class); + + /** The child nodes */ + private List<NamedParserNode> children = new ArrayList<NamedParserNode>(); + + /** Is set if this is a list */ + private boolean isList = false; + + /** Returns the list of children */ + List<NamedParserNode> getChildren() { + return children; + } + + /** Translate into an eclass */ + @Override + @SuppressWarnings({ "unchecked", "rawtypes" }) + Object convert(EClassResolver ecr) { + log.debug("Converting " + getName() + " to EObject "); + + // special case in which the main type is just a list of other types + // for example SecondaryTables which is just a list of SecondaryTable + // TODO: repair this hard link to a separate type! + final EClass eClass = ecr.getEClass(getName()); + if (isList() && eClass == null) { + assert (children.size() == 1); + assert (children.get(0) instanceof ArrayValueNode); + return ((ArrayValueNode) children.get(0)).convert(ecr); + } + + if (eClass == null) { + throw new AnnotationParserException("No eclass found with name " + + getName()); + } + final EObject eobj = EcoreUtil.create(eClass); + ((PAnnotation) eobj).setGenerated(false); + + for (NamedParserNode child : children) { + final EStructuralFeature efeature = ecr.getEStructuralFeature( + eClass, child.getName()); + if (child instanceof PrimitiveValueNode) { + final PrimitiveValueNode pvn = (PrimitiveValueNode) child; + log.debug("Primitive child: " + pvn.getName() + ": " + + pvn.getValue()); + if (!(efeature instanceof EAttribute)) { + throw new AnnotationParserException("The EFeature " + + efeature.getName() + "/" + eClass.getName() + + " is not an eattribute but a " + + efeature.getClass().getName()); + } + final EClassifier eType = efeature.getEType(); + if (!efeature.isMany()) { + eobj.eSet( + efeature, + ParserUtil.convertValue((EDataType) eType, + pvn.getValue())); + } else { + final String[] sources = pvn.getValue().split("\\s+"); + log.debug("Child is many, splitting content into " + + sources.length + " parts"); + final List<Object> referenced = new ArrayList<Object>( + sources.length); + for (String source : sources) { + referenced.add(ParserUtil.convertValue( + (EDataType) eType, source)); + } + final List currentList = (List) eobj.eGet(efeature); + currentList.addAll(referenced); + } + } else if (child instanceof ArrayValueNode + && efeature instanceof EAttribute) { + final EAttribute eattr = (EAttribute) efeature; + if (!eattr.isMany()) { + throw new AnnotationParserException("The EFeature " + + efeature.getName() + "/" + eClass.getName() + + " is not ismany"); + } + log.debug("Array child with primitive values"); + List<Object> list = ((ArrayValueNode) child).convert(ecr); + List<Object> convertedList = new ArrayList<Object>(); + for (Object object : list) { + final String val = (String) object; + log.debug("Value " + val); + convertedList.add(ParserUtil.convertValue( + (EDataType) eattr.getEType(), val)); + } + final List currentList = (List) eobj.eGet(efeature); + currentList.addAll(convertedList); + } else if (child instanceof ArrayValueNode) { + if (!(efeature instanceof EReference)) { + throw new AnnotationParserException("The EFeature " + + efeature.getName() + "/" + eClass.getName() + + " is not an ereference but a " + + efeature.getClass().getName()); + } + final EReference eref = (EReference) efeature; + if (!eref.isMany()) { + throw new AnnotationParserException("The EFeature " + + efeature.getName() + "/" + eClass.getName() + + " is not ismany"); + } + log.debug("Array child"); + eobj.eSet(eref, ((ArrayValueNode) child).convert(ecr)); + } else if (child instanceof ReferenceValueNode) { + if (!(efeature instanceof EReference)) { + throw new AnnotationParserException("The EFeature " + + efeature.getName() + "/" + eClass.getName() + + " is not an ereference but a " + + efeature.getClass().getName()); + } + final EReference eref = (EReference) efeature; + log.debug("Reference child " + child.getName()); + if (eref.isMany()) { + ((List) eobj.eGet(eref)).add(((ReferenceValueNode) child) + .convert(ecr)); + } else { + eobj.eSet(eref, ((ReferenceValueNode) child).convert(ecr)); + } + } + } + return eobj; + } + + /** + * @return the isList + */ + public boolean isList() { + return isList; + } + + /** + * @param isList + * the isList to set + */ + public void setList(boolean isList) { + this.isList = isList; + } +} diff --git a/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/annotations/parser/EAnnotationParserImporter.java b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/annotations/parser/EAnnotationParserImporter.java new file mode 100755 index 000000000..ad1f05d75 --- /dev/null +++ b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/annotations/parser/EAnnotationParserImporter.java @@ -0,0 +1,244 @@ +/** + * <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: EAnnotationParserImporter.java,v 1.8 2010/02/04 11:02:59 mtaal Exp $ + */ + +package org.eclipse.emf.teneo.annotations.parser; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.eclipse.emf.ecore.EAnnotation; +import org.eclipse.emf.ecore.EClass; +import org.eclipse.emf.ecore.ENamedElement; +import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.ecore.EPackage; +import org.eclipse.emf.ecore.EReference; +import org.eclipse.emf.ecore.EStructuralFeature; +import org.eclipse.emf.teneo.Constants; +import org.eclipse.emf.teneo.PersistenceOptions; +import org.eclipse.emf.teneo.annotations.pamodel.PAnnotatedEClass; +import org.eclipse.emf.teneo.annotations.pamodel.PAnnotatedEDataType; +import org.eclipse.emf.teneo.annotations.pamodel.PAnnotatedEModelElement; +import org.eclipse.emf.teneo.annotations.pamodel.PAnnotatedEPackage; +import org.eclipse.emf.teneo.annotations.pamodel.PAnnotatedEStructuralFeature; +import org.eclipse.emf.teneo.annotations.pamodel.PAnnotatedModel; +import org.eclipse.emf.teneo.annotations.pannotation.PannotationPackage; +import org.eclipse.emf.teneo.extension.ExtensionPoint; + +/** + * Walks over the pamodel and the paepackages and translates eannotations to pannotation types and sets the + * corresponding values in the pamodel. + * + * @author <a href="mailto:mtaal at elver.org">Martin Taal</a> + */ +public class EAnnotationParserImporter implements EClassResolver, ExtensionPoint { + /** Log it */ + private final static Log log = LogFactory.getLog(EAnnotationParserImporter.class); + + /** annotation parser */ + private AnnotationParser annotationParser = new AnnotationParser(); + + /** The prefix to distinguish jpa annotations from hb or jpox annotations */ + private static final String JPA_PREFIX = "jpa:"; + + private String[] extraAnnotationsSources = new String[] {}; + + /** Parse an pamodel */ + public void process(PAnnotatedModel paModel) { + for (PAnnotatedEPackage pap : paModel.getPaEPackages()) { + log.debug("Processing package " + pap.getModelEPackage().getName()); + processAnnotatedModelElement(pap, pap.eClass().getEPackage()); + + // and now the eclasses + process(pap); + } + } + + /** Process package */ + protected void process(PAnnotatedEPackage pap) { + for (PAnnotatedEClass pac : pap.getPaEClasses()) { + processAnnotatedModelElement(pac, pac.getModelEClass().getEPackage()); + process(pac); + } + for (PAnnotatedEDataType pac : pap.getPaEDataTypes()) { + processAnnotatedModelElement(pac, pac.getModelEDataType().getEPackage()); + } + } + + /** Process the efeatures */ + protected void process(PAnnotatedEClass pac) { + log.debug("Processing eclass " + pac.getModelEClass().getName()); + for (PAnnotatedEStructuralFeature paf : pac.getPaEStructuralFeatures()) { + processAnnotatedModelElement(paf, paf.getModelEStructuralFeature().eClass().getEPackage()); + } + } + + /** Process a type with its eannotations */ + @SuppressWarnings("unchecked") + protected void processAnnotatedModelElement(PAnnotatedEModelElement pee, EPackage epack) { + log.debug("Processing " + pee.getModelElement().getName()); + final ArrayList<NamedParserNode> parsedNodes = new ArrayList<NamedParserNode>(); + for (EAnnotation annotation : pee.getModelElement().getEAnnotations()) { + parsedNodes.addAll(process(annotation, pee.getModelElement())); + } + + // now also do the annotations on the edatatype (if any) + /* + * if (pee.getAnnotatedElement() instanceof EAttribute) { final EAttribute eattr = + * (EAttribute)pee.getAnnotatedElement(); final EDataType edt = (EDataType)eattr.getEType(); for (Iterator it = + * edt.getEAnnotations().iterator(); it.hasNext();) { parsedNodes.addAll(process((EAnnotation)it.next(), + * pee.getAnnotatedElement())); } } + */ + + // now the parsed nodes should be translated into features of the + // enamedelement + // this is done multiplelevel + log.debug("Number of parsed typename annotations " + parsedNodes.size()); + for (NamedParserNode namedParserNode : parsedNodes) { + final ComplexNode cn = (ComplexNode) namedParserNode; + if (cn.isList()) { + // find the efeature + final EStructuralFeature ef = getEStructuralFeature(pee.eClass(), cn.getName()); + pee.eSet(ef, cn.convert(this)); + } else { + EObject eobj = (EObject) cn.convert(this); + boolean found = false; + for (EReference eref : pee.eClass().getEAllReferences()) { + if (eref.getEReferenceType().isInstance(eobj)) { + log.debug("Found EReference " + eref.getName() + " for " + eobj.eClass().getName()); + if (eref.isMany()) { + ((List<EObject>) pee.eGet(eref)).add(eobj); + } else { + pee.eSet(eref, eobj); + } + found = true; + break; + } + } + if (!found) { + throw new AnnotationParserException("The eclass: " + pee.eClass().getName() + + " does not have an efeature for " + eobj.eClass().getName()); + } + } + } + + // now for each eobject find which eref stores it! + // log.debug("Find efeature for each created eobject"); + // final ArrayList objects = new ArrayList(); + // for (Iterator it = objects.iterator(); it.hasNext();) { + // EObject eobj = (EObject)it.next(); + // log.debug("EClass " + eobj.eClass().getName()); + // } + } + + /** Processes EAnnotations */ + private ArrayList<NamedParserNode> process(EAnnotation ea, ENamedElement ene) { + final ArrayList<NamedParserNode> result = new ArrayList<NamedParserNode>(); + + if (!isValidSource(ea.getSource())) { + return result; + } + + log.debug("Processing annotations "); + for (Map.Entry<String, String> pAnnotationDetails : ea.getDetails().entrySet()) { + final String fName = pAnnotationDetails.getKey(); + // todo externalize + if (fName.compareToIgnoreCase("appinfo") == 0 || fName.compareToIgnoreCase("value") == 0) { + log.debug("Annotation content: \n " + pAnnotationDetails.getValue()); + final String content = removeCommentLines(pAnnotationDetails.getValue()); + result.addAll(annotationParser.parse(ene, content)); + } + } + return result; + } + + // removes the lines which start with a // + private String removeCommentLines(String content) { + if (content.indexOf("//") == -1) { + return content; + } + final String[] lines = content.split("\n"); + final StringBuilder sb = new StringBuilder(); + for (String line : lines) { + if (line.trim().startsWith("//")) { + continue; + } + if (sb.length() > 0) { + sb.append("\n"); + } + sb.append(line); + } + return sb.toString(); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.emf.teneo.annotations.parser.EClassResolver#getEClass(java .lang.String) + */ + public EClass getEClass(String name) { + if (name.startsWith(JPA_PREFIX)) { + return getEClass(name.substring(JPA_PREFIX.length())); + } + return (EClass) PannotationPackage.eINSTANCE.getEClassifier(name); + } + + /** Is a valid source */ + protected boolean isValidSource(String source) { + if (source == null) { + return false; + } + + if (extraAnnotationsSources.length > 0) { + for (String annotationSource : extraAnnotationsSources) { + if (source.equals(annotationSource)) { + return true; + } + } + } + + return source.startsWith(Constants.ANNOTATION_SOURCE_TENEO_JPA) + || source.startsWith(Constants.ANNOTATION_SOURCE_TENEO_MAPPING); + } + + /** Find the efeature */ + public EStructuralFeature getEStructuralFeature(EClass eClass, String name) { + return ParserUtil.getEStructuralFeature(eClass, name); + } + + public void setExtraAnnotationSources(PersistenceOptions po) { + if (po.getExtraAnnotationSources() != null && po.getExtraAnnotationSources().trim().length() > 0) { + extraAnnotationsSources = po.getExtraAnnotationSources().split(","); + for (int i = 0; i < extraAnnotationsSources.length; i++) { + extraAnnotationsSources[i] = extraAnnotationsSources[i].trim(); + if (extraAnnotationsSources[i].startsWith(Constants.ANNOTATION_SOURCE_TENEO_JPA) + || extraAnnotationsSources[i].startsWith(Constants.ANNOTATION_SOURCE_TENEO_MAPPING)) { + log + .warn("Extra annotation source (" + + extraAnnotationsSources[i] + + ") starts with the default Teneo annotation source: " + + Constants.ANNOTATION_SOURCE_TENEO_JPA + + " or " + + Constants.ANNOTATION_SOURCE_TENEO_MAPPING + + ". Annotations which should sometimes be " + + "ignored or disabled should not start with these values as they are always considered by Teneo"); + } + } + } + } +}
\ No newline at end of file diff --git a/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/annotations/parser/EClassResolver.java b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/annotations/parser/EClassResolver.java new file mode 100755 index 000000000..1e045e59d --- /dev/null +++ b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/annotations/parser/EClassResolver.java @@ -0,0 +1,34 @@ +/** + * <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: EClassResolver.java,v 1.2 2008/02/28 07:08:33 mtaal Exp $ + */ + +package org.eclipse.emf.teneo.annotations.parser; + +import org.eclipse.emf.ecore.EClass; +import org.eclipse.emf.ecore.EStructuralFeature; + +/** + * Finds an eclass using a certain string. + * + * @author <a href="mailto:mtaal at elver.org">Martin Taal</a> + */ +public interface EClassResolver { + + /** Return an eclass, returns null if not found */ + EClass getEClass(String name); + + /** Find the efeature */ + EStructuralFeature getEStructuralFeature(EClass eClass, String name); +} diff --git a/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/annotations/parser/NamedParserNode.java b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/annotations/parser/NamedParserNode.java new file mode 100755 index 000000000..59cd322b4 --- /dev/null +++ b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/annotations/parser/NamedParserNode.java @@ -0,0 +1,46 @@ +/** + * <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: NamedParserNode.java,v 1.2 2008/02/28 07:08:33 mtaal Exp $ + */ + +package org.eclipse.emf.teneo.annotations.parser; + +/** + * Main class of the nodes which are the result of the annotation parser. + * + * @author <a href="mailto:mtaal at elver.org">Martin Taal</a> + */ +abstract class NamedParserNode { + + /** The name parsed */ + private String name = "value"; + + /** + * @return the name + */ + public String getName() { + return name; + } + + /** + * @param name + * the name to set + */ + public void setName(String name) { + this.name = name; + } + + /** Translate to pamodel/pannotation */ + abstract Object convert(EClassResolver ecr); +} diff --git a/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/annotations/parser/ParserUtil.java b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/annotations/parser/ParserUtil.java new file mode 100755 index 000000000..4e4555e85 --- /dev/null +++ b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/annotations/parser/ParserUtil.java @@ -0,0 +1,66 @@ +/** + * <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: ParserUtil.java,v 1.3 2009/03/30 07:53:05 mtaal Exp $ + */ + +package org.eclipse.emf.teneo.annotations.parser; + +import org.eclipse.emf.ecore.EClass; +import org.eclipse.emf.ecore.EDataType; +import org.eclipse.emf.ecore.EStructuralFeature; +import org.eclipse.emf.ecore.util.EcoreUtil; + +/** + * Util class + * + * @author <a href="mailto:mtaal@elver.org">Martin Taal</a> + * @version $Revision: 1.3 $ + */ + +public class ParserUtil { + + /** + * @return Returns the result of converting the String value to the given data type. + * @throws EAnnotationImportException + */ + public static Object convertValue(EDataType eType, String value) { + try { + return EcoreUtil.createFromString(eType, value); + } catch (IllegalArgumentException e) { + // now try without the first dot + if (value != null && value.indexOf('.') != -1) { + try { + return EcoreUtil.createFromString(eType, value.substring(1 + value.indexOf('.'))); + } catch (IllegalArgumentException x) { + throw new AnnotationParserException("Cannot convert '" + value + "' to '" + eType.getName() + + "' type", e); + } + } + throw new AnnotationParserException("Cannot convert '" + value + "' to '" + eType.getName() + "' type", e); + } + } + + /** Get a structuralfeature */ + public static EStructuralFeature getEStructuralFeature(EClass eClass, String name) { + try { + for (EStructuralFeature ef : eClass.getEAllStructuralFeatures()) { + if (ef.getName().compareToIgnoreCase(name) == 0) return ef; + } + throw new AnnotationParserException("No efeature " + name + " for eclass " + eClass.getName()); + } catch (IllegalArgumentException e) { + throw new AnnotationParserException("Cannot convert '" + name + "' to an efeature for eclass " + + eClass.getName()); + } + } +} diff --git a/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/annotations/parser/PrimitiveValueNode.java b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/annotations/parser/PrimitiveValueNode.java new file mode 100755 index 000000000..afa5fd48e --- /dev/null +++ b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/annotations/parser/PrimitiveValueNode.java @@ -0,0 +1,58 @@ +/** + * <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: PrimitiveValueNode.java,v 1.5 2008/06/10 10:19:43 mtaal Exp $ + */ + +package org.eclipse.emf.teneo.annotations.parser; + +/** + * Simple value node. + * + * @author <a href="mailto:mtaal at elver.org">Martin Taal</a> + */ +class PrimitiveValueNode extends NamedParserNode { + + /** The value */ + private String value; + + /** + * @return the value + */ + public String getValue() { + return value; + } + + /** + * @param value + * the value to set + */ + public void setValue(String value) { + value = value.replaceAll(">", ">"); + value = value.replaceAll("<", "<"); + + // correct a small mistake in the tokenizer + if (value != null && value.length() > 1 && value.charAt(0) == '"' && value.charAt(value.length() - 1) == '"') { + this.value = value.substring(1, value.length() - 1); + } else { + this.value = value; + } + } + + /** Translate into an etype */ + @Override + Object convert(EClassResolver ecr) { + return value; + } + +} diff --git a/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/annotations/parser/ReferenceValueNode.java b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/annotations/parser/ReferenceValueNode.java new file mode 100755 index 000000000..66c6d84cd --- /dev/null +++ b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/annotations/parser/ReferenceValueNode.java @@ -0,0 +1,58 @@ +/** + * <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: ReferenceValueNode.java,v 1.3 2009/03/30 07:53:05 mtaal Exp $ + */ + +package org.eclipse.emf.teneo.annotations.parser; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +/** + * Node which has a complex type as its value. + * + * @author <a href="mailto:mtaal at elver.org">Martin Taal</a> + */ +class ReferenceValueNode extends NamedParserNode { + /** Log it */ + private final static Log log = LogFactory.getLog(ArrayValueNode.class); + + /** The value */ + private NamedParserNode value; + + /** + * @return the value + */ + public NamedParserNode getValue() { + return value; + } + + /** + * @param value + * the value to set + */ + public void setValue(NamedParserNode value) { + this.value = value; + } + + /** Translate into a list of eobjects */ + Object convert(EClassResolver ecr) { + log.debug("Converting reference node " + getName()); + if (!(value instanceof ComplexNode)) { + throw new AnnotationParserException("A reference annotation value may only " + "contain a typename"); + } + final ComplexNode cn = (ComplexNode) value; + return cn.convert(ecr); + } +} diff --git a/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/annotations/xml/ParseXMLAnnotationsException.java b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/annotations/xml/ParseXMLAnnotationsException.java new file mode 100755 index 000000000..bb8f19400 --- /dev/null +++ b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/annotations/xml/ParseXMLAnnotationsException.java @@ -0,0 +1,55 @@ +/** + * <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: ParseXMLAnnotationsException.java,v 1.2 2008/02/28 07:08:33 mtaal Exp $ + */ + +package org.eclipse.emf.teneo.annotations.xml; + +import org.eclipse.emf.teneo.annotations.StoreAnnotationsException; + +/** + * Is thrown in the org.eclipse.emf.teneo.annotations.xml package. Takes care of logging the cause. + * + * @author <a href="mailto:mtaal@elver.org">Martin Taal</a> + * @version $Revision: 1.2 $ + */ + +public class ParseXMLAnnotationsException extends StoreAnnotationsException { + + /** + * Serial Version ID + */ + private static final long serialVersionUID = -8670363508437586401L; + + /** + * The constructor, logs the exception also + */ + public ParseXMLAnnotationsException(String msg, Throwable cause) { + super(msg, cause); + } + + /** + * The constructor, logs the exception also + */ + public ParseXMLAnnotationsException(String msg) { + super(msg); + } + + /** + * The constructor, logs the exception also + */ + public ParseXMLAnnotationsException(Throwable t) { + super(t.getMessage(), t); + } +} diff --git a/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/annotations/xml/PersistenceMappingSchemaGenerator.java b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/annotations/xml/PersistenceMappingSchemaGenerator.java new file mode 100755 index 000000000..8015a4ddc --- /dev/null +++ b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/annotations/xml/PersistenceMappingSchemaGenerator.java @@ -0,0 +1,592 @@ +/** + * <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: PersistenceMappingSchemaGenerator.java,v 1.7 2010/02/04 11:03:02 mtaal Exp $ + */ + +package org.eclipse.emf.teneo.annotations.xml; + +import java.io.FileWriter; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.eclipse.emf.ecore.EAnnotation; +import org.eclipse.emf.ecore.EClass; +import org.eclipse.emf.ecore.EClassifier; +import org.eclipse.emf.ecore.EEnum; +import org.eclipse.emf.ecore.EEnumLiteral; +import org.eclipse.emf.ecore.EModelElement; +import org.eclipse.emf.ecore.ENamedElement; +import org.eclipse.emf.ecore.EPackage; +import org.eclipse.emf.ecore.EReference; +import org.eclipse.emf.ecore.EStructuralFeature; +import org.eclipse.emf.teneo.annotations.StoreAnnotationsException; +import org.eclipse.emf.teneo.annotations.pamodel.PamodelPackage; +import org.eclipse.emf.teneo.annotations.pannotation.PannotationPackage; +import org.eclipse.emf.teneo.simpledom.Attribute; +import org.eclipse.emf.teneo.simpledom.Document; +import org.eclipse.emf.teneo.simpledom.Element; + +/** + * Parses the pamodel and pannotation model to generate a xsd. + * + * @author <a href="mailto:mtaal@elver.org">Martin Taal</a> + * @version $Revision: 1.7 $ + */ + +public class PersistenceMappingSchemaGenerator { + + /** The source name used to set to which estructural feature a tag belongs */ + public static final String ESTRUCTURAL_FEATURE_SOURCE_NAME = "teneo/internal/EStructuralFeatureName"; + + /** Used to set efeatures in the ecore model to be ignored */ + public static final String PERSISTENCE_MAPPING_SOURCE = "teneo/internal/PersistenceMapping"; + + /** Is set on efeatures to denote that they are not supported */ + private static final String UNSUPPORTED_SOURCE = "teneo/internal/Unsupported"; + + public static final String XML_SCHEMA_NAMESPACE = "http://www.w3.org/2001/XMLSchema"; + + /** The main method, ugly but effective */ + public static void main(String[] args) { + final PersistenceMappingSchemaGenerator pmsg = new PersistenceMappingSchemaGenerator(); + pmsg.setAnnotationEPackages(new EPackage[] { PannotationPackage.eINSTANCE }); + pmsg.setModelEPackage(PamodelPackage.eINSTANCE); + try { + final FileWriter fw = new FileWriter("/home/mtaal/mytmp/persistence-mapping.xsd"); + fw.write(pmsg.generate()); + fw.close(); + } catch (Exception e) { + throw new StoreAnnotationsException("Exception while generating mapping.xsd", e); + } + } + + /** The pamodel */ + private EPackage modelEPackage; + + /** And the annotations packages */ + private EPackage[] annotationEPackages; + + /** Mapping from ecore simple types to schema simple types */ + private final Map<String, String> schemaTypeNamesByAnnotationType = new HashMap<String, String>(); + + /** Target name space */ + private String nameSpace = "http://www.eclipse.org/emft/teneo"; + + /** Initialize some main things */ + private void initialize() { + schemaTypeNamesByAnnotationType.put("EBoolean", "xsd:boolean"); + schemaTypeNamesByAnnotationType.put("EInt", "xsd:int"); + schemaTypeNamesByAnnotationType.put("ELong", "xsd:long"); + schemaTypeNamesByAnnotationType.put("EString", "xsd:string"); + } + + /** Generate into a string */ + public String generate() { + + initialize(); + + final Document doc = new Document(); + + // The root Element + final Element root = new Element("xsd:schema").addAttribute("targetNamespace", nameSpace).addAttribute( + "elementFormDefault", "qualified").addAttribute("xmlns:xsd", "http://www.w3.org/2001/XMLSchema") + .addAttribute("xmlns", nameSpace); + + root.addElement("xsd:element").addAttribute("name", "persistence-mapping").addAttribute("type", + "PersistenceMapping"); + root.addElement("xsd:complexType").addAttribute("name", "PersistenceMapping").addElement("xsd:sequence") + .addAttribute("minOccurs", "1").addAttribute("maxOccurs", "unbounded").addElement("xsd:element") + .addAttribute("name", "epackage").addAttribute("type", "EPackage"); + + // first determine which types have only one string field, these are handled + // slightly different because this makes the xml easier + for (EPackage annotationEPackage : annotationEPackages) { + final List<EClassifier> eclassifiers = new ArrayList<EClassifier>(annotationEPackage.getEClassifiers()); + for (EClassifier eClassifier : eclassifiers) { + String schemaTypeName = eClassifier.getName(); + if (eClassifier instanceof EClass) { + EClass eClass = (EClass) eClassifier; + + // Annotation types with a single feature are converted to simple type + // references in the schema. + if (oneMappableFeature(eClass)) { + final EStructuralFeature eStructuralFeature = eClass.getEStructuralFeatures().get(0); + final EClassifier eType = eStructuralFeature.getEType(); + schemaTypeName = schemaTypeNamesByAnnotationType.get(eType.getName()); + if (schemaTypeName == null) { + schemaTypeName = eType.getName(); + } + schemaTypeNamesByAnnotationType.put(eClassifier.getName(), schemaTypeName); + continue; + } + } + schemaTypeNamesByAnnotationType.put(eClassifier.getName(), schemaTypeName); + } + } + + // process the annotations first to get the correct typing + final List<Element> annotationList = new ArrayList<Element>(); + for (EPackage annotationEPackage : annotationEPackages) { + annotationList.addAll(processAnnotationEPackage(annotationEPackage)); + } + + root.addElement(createEPackageElement()); + root.addElement(createEClassElement()); + root.addElement(createEAttributeElement()); + root.addElement(createEReferenceElement()); + root.addElement(createPropertyElement()); + root.addElement(createEDataTypeElement()); + root.getChildren().addAll(annotationList); + + doc.setRoot(root); + return doc.emitXML(); + } + + /** process annotation packages */ + private List<Element> processAnnotationEPackage(EPackage epackage) { + final ArrayList<Element> elemList = new ArrayList<Element>(); + final List<EClassifier> eclassifiers = new ArrayList<EClassifier>(epackage.getEClassifiers()); + Collections.sort(eclassifiers, new ENamedElementComparator()); + + for (EClassifier eClassifier : eclassifiers) { + if (isIgnorable(eClassifier) || isUnsupported(eClassifier)) { + continue; + } + + String schemaTypeName = eClassifier.getName(); + if (eClassifier instanceof EClass) { + final EClass eClass = (EClass) eClassifier; + if (eClass.isAbstract()) { + continue; + } + + final List<EStructuralFeature> eStructuralFeatures = eClass.getEAllStructuralFeatures(); + if (eStructuralFeatures.isEmpty()) { + continue; + } + + // Annotation types with a single feature are converted to simple type references in + // the schema. + if (oneMappableFeature(eClass)) { + /* + * final EStructuralFeature eStructuralFeature = (EStructuralFeature) + * eClass.getEStructuralFeatures().get(0); final EClassifier eType = eStructuralFeature.getEType(); + * schemaTypeName = (String) schemaTypeNamesByAnnotationType.get(eType.getName()); if + * (schemaTypeName == null) { schemaTypeName = eType.getName(); } + * schemaTypeNamesByAnnotationType.put(eClassifier.getName(), schemaTypeName); + */ + continue; + } + + final Element complexTypeElement = createSchemaComplexType(eClass.getName()); + elemList.add(complexTypeElement); + + final Element choiceElement = complexTypeElement.addElement("xsd:choice"); + processStructuralFeatures(choiceElement, eStructuralFeatures); + if (choiceElement.getChildren().size() == 0) { + complexTypeElement.getChildren().remove(choiceElement); + } else if (choiceElement.getChildren().size() == 1) { + complexTypeElement.remove(choiceElement); + final Element sequenceElement = complexTypeElement.addElement("xsd:sequence"); + complexTypeElement.remove(sequenceElement); + sequenceElement.add(choiceElement.getChildren().get(0)); + complexTypeElement.add(0, sequenceElement); + } else { + addMinMaxOccurs(choiceElement, "0", "unbounded"); + } + } else if (eClassifier instanceof EEnum) { + elemList.add(processEnum((EEnum) eClassifier)); + } else { + throw new RuntimeException("Unexpected EClassifier: " + eClassifier.eClass().getName()); + } + + schemaTypeNamesByAnnotationType.put(eClassifier.getName(), schemaTypeName); + } + return elemList; + } + + /** If more than one mappable structuralfeature */ + private boolean oneMappableFeature(EClass eclass) { + int cnt = 0; + for (EStructuralFeature ef : eclass.getEStructuralFeatures()) { + if (!isIgnorable(ef) && !isUnsupported(ef)) { + cnt++; + } + } + return cnt == 1; + } + + /** Process an enum */ + private Element processEnum(EEnum eEnum) { + final Element simpleTypeElement = createSchemaSimpleType(eEnum.getName(), null); + final Element restrictionElement = new Element("xsd:restriction"); + restrictionElement.addAttribute(new Attribute("base", "xsd:token")); + simpleTypeElement.addElement(restrictionElement); + final List<EEnumLiteral> literals = eEnum.getELiterals(); + for (EEnumLiteral literal : literals) { + final Element enumerationElement = new Element("xsd:enumeration"); + restrictionElement.addElement(enumerationElement); + enumerationElement.addAttribute(new Attribute("value", literal.getLiteral())); + } + return simpleTypeElement; + } + + /** Do the epackage */ + private Element createEPackageElement() { + final Element epackElement = new Element("xsd:complexType").addAttribute("name", "EPackage"); + final Element choiceElement = epackElement.addElement("xsd:choice"); + processStructuralFeatures(choiceElement, getPAnnotatedEPackage().getEAllStructuralFeatures()); + choiceElement.addElement("xsd:element").addAttribute("name", "eclass").addAttribute("type", "EClass"); + choiceElement.addElement("xsd:element").addAttribute("name", "edatatype").addAttribute("type", "EDataType"); + + addMinMaxOccurs(choiceElement, "0", "unbounded"); + + // add the namespace-uri attribute + epackElement.addElement("xsd:attribute").addAttribute("name", "namespace-uri").addAttribute("type", + "xsd:anyURI").addAttribute("use", "required"); + return epackElement; + } + + /** Do the eClass */ + private Element createEClassElement() { + final Element eclassElement = new Element("xsd:complexType").addAttribute("name", "EClass"); + final Element choiceElement = eclassElement.addElement("xsd:choice"); + processStructuralFeatures(choiceElement, getPAnnotatedEClass().getEAllStructuralFeatures()); + + choiceElement.addElement("xsd:element").addAttribute("name", "eattribute").addAttribute("type", "EAttribute"); + choiceElement.addElement("xsd:element").addAttribute("name", "ereference").addAttribute("type", "EReference"); + choiceElement.addElement("xsd:element").addAttribute("name", "property").addAttribute("type", "Property"); + choiceElement.addElement("xsd:element").addAttribute("name", "edatatype").addAttribute("type", "EDataType"); + + addMinMaxOccurs(choiceElement, "0", "unbounded"); + + eclassElement.addElement("xsd:attribute").addAttribute("name", "name").addAttribute("type", "xsd:token") + .addAttribute("use", "required"); + return eclassElement; + } + + /** Do the eReference element */ + private Element createEReferenceElement() { + final Element erefElement = new Element("xsd:complexType").addAttribute("name", "EReference"); + final Element choiceElement = erefElement.addElement("xsd:choice"); + processStructuralFeatures(choiceElement, getPAnnotatedEReference().getEAllStructuralFeatures()); + addMinMaxOccurs(choiceElement, "0", "unbounded"); + erefElement.addElement("xsd:attribute").addAttribute("name", "name").addAttribute("type", "xsd:token") + .addAttribute("use", "required"); + return erefElement; + } + + /** Do the eAttribute */ + private Element createEAttributeElement() { + final Element eattrElement = new Element("xsd:complexType").addAttribute("name", "EAttribute"); + final Element choiceElement = eattrElement.addElement("xsd:choice"); + processStructuralFeatures(choiceElement, getPAnnotatedEAttribute().getEAllStructuralFeatures()); + addMinMaxOccurs(choiceElement, "0", "unbounded"); + eattrElement.addElement("xsd:attribute").addAttribute("name", "name").addAttribute("type", "xsd:token") + .addAttribute("use", "required"); + return eattrElement; + } + + /** Do the eDataType */ + private Element createEDataTypeElement() { + final Element eattrElement = new Element("xsd:complexType").addAttribute("name", "EDataType"); + final Element choiceElement = eattrElement.addElement("xsd:choice"); + processStructuralFeatures(choiceElement, getPAnnotatedEDataType().getEAllStructuralFeatures()); + addMinMaxOccurs(choiceElement, "0", "unbounded"); + eattrElement.addElement("xsd:attribute").addAttribute("name", "name").addAttribute("type", "xsd:token") + .addAttribute("use", "required"); + return eattrElement; + } + + /** Do the property (comb. of ereference and eattribute */ + private Element createPropertyElement() { + final Element propertyElement = new Element("xsd:complexType").addAttribute("name", "Property"); + final Element choiceElement = propertyElement.addElement("xsd:choice"); + final List<EStructuralFeature> features = new ArrayList<EStructuralFeature>(getPAnnotatedEAttribute() + .getEAllStructuralFeatures()); + features.removeAll(getPAnnotatedEReference().getEAllStructuralFeatures()); + features.addAll(getPAnnotatedEReference().getEAllStructuralFeatures()); + + processStructuralFeatures(choiceElement, features); + addMinMaxOccurs(choiceElement, "0", "unbounded"); + propertyElement.addElement("xsd:attribute").addAttribute("name", "name").addAttribute("type", "xsd:token") + .addAttribute("use", "required"); + return propertyElement; + } + + /** Walk through a pamodel type and add references to each type to the passed element */ + private void processStructuralFeatures(Element mainElement, List<EStructuralFeature> eStructuralFeatures) { + final List<EStructuralFeature> eFeatures = new ArrayList<EStructuralFeature>(eStructuralFeatures); + Collections.sort(eFeatures, new ENamedElementComparator()); + for (EStructuralFeature ef : eFeatures) { + processStructuralFeature(mainElement, ef); + } + } + + /** + * Processes the EStructuralFeatures of a Pamodel EClass. + */ + private void processStructuralFeature(Element parentElement, EStructuralFeature eStructuralFeature) { + final EClassifier eType = eStructuralFeature.getEType(); + + if (isIgnorable(eStructuralFeature) || isIgnorable(eType) || isUnsupported(eType)) { + return; + } + + final int minOccurs = (eStructuralFeature.isRequired() ? 1 : 0); + + // Determine the element name. + final EAnnotation eAnnotation = eStructuralFeature.getEAnnotation(PERSISTENCE_MAPPING_SOURCE); + String elementName = null; + if (eAnnotation != null) { + elementName = eAnnotation.getDetails().get("elementName"); + } + if (elementName == null) { + // No explicit XML element name specified, so derive from the name instead. + elementName = eStructuralFeature.getName(); + if (eStructuralFeature.isMany() && elementName.endsWith("s")) { + elementName = elementName.substring(0, elementName.length() - 1); + } + } + + // check for double occurences, can occur when doing the property tag + // which combines ereference and eattribute features + final String xmlName = convertToXmlName(elementName); + for (Element otherElem : parentElement.getChildren()) { + String name; + if ((name = otherElem.getAttributeValue("name")) != null && name.compareTo(xmlName) == 0) { + return; + } + } + if (parentElement.element(convertToXmlName(elementName)) != null) { + return; + } + + String typeName = schemaTypeNamesByAnnotationType.get(eType.getName()); + if (typeName == null) { + typeName = eType.getName(); + } + + if (eStructuralFeature instanceof EReference) { + // EReferences are represented by child elements. + final Element element = createSchemaElement(elementName, typeName, eStructuralFeature.getName()); + element.addAttribute(new Attribute("minOccurs", String.valueOf(minOccurs))); + if (eStructuralFeature.isMany()) { + element.addAttribute(new Attribute("maxOccurs", "unbounded")); + } + parentElement.addElement(element); + } else { + // EAttributes are represented by attributes and optional child elements in case of many + // multiplicity. + final Element attributeElement = createSchemaAttribute(eStructuralFeature.getName(), typeName, + eStructuralFeature.getName()); + attributeElement.addAttribute(new Attribute("use", (minOccurs == 0 ? "optional" : "required"))); + parentElement.getParent().addElement(attributeElement); + if (eStructuralFeature.isMany()) { + final Element element = createSchemaElement(eStructuralFeature.getName(), typeName, eStructuralFeature + .getName()); + parentElement.addElement(element); + element.addAttribute(new Attribute("minOccurs", "0")); + element.addAttribute(new Attribute("maxOccurs", "unbounded")); + } + } + } + + /** Return the PAnnotatedEClass */ + protected EClass getPAnnotatedEPackage() { + return (EClass) modelEPackage.getEClassifier("PAnnotatedEPackage"); + } + + /** Return the PAnnotatedEClass */ + protected EClass getPAnnotatedEClass() { + return (EClass) modelEPackage.getEClassifier("PAnnotatedEClass"); + } + + /** Return the PAnnotatedEReference */ + protected EClass getPAnnotatedEReference() { + return (EClass) modelEPackage.getEClassifier("PAnnotatedEReference"); + } + + /** Return the PAnnotatedEAttribute */ + protected EClass getPAnnotatedEAttribute() { + return (EClass) modelEPackage.getEClassifier("PAnnotatedEAttribute"); + } + + /** Return the PAnnotatedEDataType */ + protected EClass getPAnnotatedEDataType() { + return (EClass) modelEPackage.getEClassifier("PAnnotatedEDataType"); + } + + /** + * Tests whether an EModelElement can be ignored for persistence mapping. + * + */ + protected static boolean isIgnorable(EModelElement eModelElement) { + final EAnnotation eAnnotation = eModelElement.getEAnnotation(PERSISTENCE_MAPPING_SOURCE); + boolean ignore = false; + if (eAnnotation != null) { + ignore = Boolean.valueOf(eAnnotation.getDetails().get("ignore")).booleanValue(); + } + return ignore; + } + + /** + * Creates an XML Schema element. (<xsd:element>) + */ + private Element createSchemaElement(String name, String type, String eStructuralFeatureName) { + final Element element = new Element("xsd:element"); + element.addAttribute(new Attribute("name", convertToXmlName(name))); + element.addAttribute(new Attribute("type", type)); + if (!name.equals(eStructuralFeatureName)) { + addAppInfoElement(element, eStructuralFeatureName); + } + return element; + } + + /** + * Creates an XML Schema complex type. (<xsd:complexType>) + */ + private Element createSchemaSimpleType(String name, String type) { + final Element element = new Element("xsd:simpleType"); + element.addAttribute(new Attribute("name", name)); + if (type != null) { + element.addAttribute(new Attribute("type", type)); + } + return element; + } + + /** + * Creates an XML Schema attribute element. (<xsd:attribute>) + */ + private Element createSchemaAttribute(String name, String type, String eStructuralFeatureName) { + final Element element = new Element("xsd:attribute"); + element.addAttribute(new Attribute("name", convertToXmlName(name))); + element.addAttribute(new Attribute("type", type)); + if (!name.equals(eStructuralFeatureName)) { + addAppInfoElement(element, eStructuralFeatureName); + } + return element; + } + + private static void addAppInfoElement(final Element element, String eStructuralFeatureName) { + final Element annotationElement = new Element("xsd:annotation"); + element.addElement(annotationElement); + final Element appInfoElement = new Element("xsd:appinfo"); + appInfoElement.addAttribute(new Attribute("source", ESTRUCTURAL_FEATURE_SOURCE_NAME)); + appInfoElement.setText(eStructuralFeatureName); + annotationElement.addElement(appInfoElement); + } + + /** + * Creates an XML Schema complex type. (<xsd:complexType>) + */ + private Element createSchemaComplexType(String name) { + final Element element = new Element("xsd:complexType"); + element.addAttribute(new Attribute("name", name)); + return element; + } + + /** + * Tests whether an EModelElement is unsupported. + * + */ + protected static boolean isUnsupported(EModelElement eModelElement) { + return (eModelElement.getEAnnotation(UNSUPPORTED_SOURCE) != null); + } + + /** Add minOccurs and maxOccurs */ + private void addMinMaxOccurs(Element elem, String min, String max) { + elem.addAttribute("minOccurs", min).addAttribute("maxOccurs", max); + } + + /** + * Converts mixed-case names to XML names. + * <p> + * Example: "generatedValue" -> "generated-value". + * + * @param name + * @return + */ + protected String convertToXmlName(String name) { + StringBuffer sb = new StringBuffer(); + for (int i = 0, n = name.length(); i < n; i++) { + char ch = name.charAt(i); + if (Character.isUpperCase(ch)) { + if (i > 0) { + sb.append('-'); + } + ch = Character.toLowerCase(ch); + } + sb.append(ch); + } + return sb.toString(); + } + + /** EFeature comparator */ + private class ENamedElementComparator implements Comparator<ENamedElement> { + /** Compare features */ + public int compare(ENamedElement e1, ENamedElement e2) { + return e1.getName().compareTo(e2.getName()); + } + } + + /** + * @return the annotationEPackages + */ + public EPackage[] getAnnotationEPackages() { + return annotationEPackages; + } + + /** + * @param annotationEPackages + * the annotationEPackages to set + */ + public void setAnnotationEPackages(EPackage[] annotationEPackages) { + this.annotationEPackages = annotationEPackages; + } + + /** + * @return the modelEPackage + */ + public EPackage getModelEPackage() { + return modelEPackage; + } + + /** + * @param modelEPackage + * the modelEPackage to set + */ + public void setModelEPackage(EPackage modelEPackage) { + this.modelEPackage = modelEPackage; + } + + /** + * @return the nameSpace + */ + public String getNameSpace() { + return nameSpace; + } + + /** + * @param nameSpace + * the nameSpace to set + */ + public void setNameSpace(String nameSpace) { + this.nameSpace = nameSpace; + } +} diff --git a/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/annotations/xml/XmlElementToEStructuralFeatureMapper.java b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/annotations/xml/XmlElementToEStructuralFeatureMapper.java new file mode 100755 index 000000000..0c74259f9 --- /dev/null +++ b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/annotations/xml/XmlElementToEStructuralFeatureMapper.java @@ -0,0 +1,83 @@ +/** + * <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: XmlElementToEStructuralFeatureMapper.java,v 1.4 2008/05/27 07:42:09 mtaal Exp $ + */ + +package org.eclipse.emf.teneo.annotations.xml; + +import java.io.InputStream; +import java.util.HashMap; +import java.util.Map; + +import javax.xml.parsers.SAXParser; +import javax.xml.parsers.SAXParserFactory; + +import org.eclipse.emf.teneo.annotations.StoreAnnotationsException; +import org.eclipse.emf.teneo.extension.ExtensionPoint; +import org.xml.sax.Attributes; +import org.xml.sax.SAXException; +import org.xml.sax.helpers.DefaultHandler; + +/** + * Helper class used internally for mapping XML element names to EStructuralFeature names. + */ +public class XmlElementToEStructuralFeatureMapper implements ExtensionPoint { + private Map<String, String> eStructuralFeatureNamesByXmlElementName = new HashMap<String, String>(); + + private String xmlElementName; + + private boolean appInfoValue; + + public void parseSchema(InputStream schema) { + try { + final SAXParserFactory saxParserFactory = SAXParserFactory.newInstance(); + saxParserFactory.setNamespaceAware(true); + final SAXParser saxParser = saxParserFactory.newSAXParser(); + saxParser.parse(this.getClass().getResourceAsStream("persistence-mapping.xsd"), new XmlContentHandler()); + } catch (Exception e) { + throw new StoreAnnotationsException("Exception while parsing xsd", e); + } + } + + public class XmlContentHandler extends DefaultHandler { + + @Override + public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { + if (localName.equals("attribute") || localName.equals("element")) { + xmlElementName = attributes.getValue("name"); + } else if (localName.equals("appinfo") && + PersistenceMappingSchemaGenerator.ESTRUCTURAL_FEATURE_SOURCE_NAME.equals(attributes + .getValue("source"))) { + appInfoValue = true; + } + } + + @Override + public void characters(char[] ch, int start, int length) throws SAXException { + if (appInfoValue && xmlElementName != null) { + final String eStructuralFeatureName = new String(ch, start, length).trim(); + if (eStructuralFeatureName.length() > 0 && + !eStructuralFeatureNamesByXmlElementName.containsKey(xmlElementName)) { + eStructuralFeatureNamesByXmlElementName.put(xmlElementName, eStructuralFeatureName); + appInfoValue = false; + xmlElementName = null; + } + } + } + } + + public String getEStructuralFeatureName(String xmlElementName) { + return eStructuralFeatureNamesByXmlElementName.get(xmlElementName); + } +} diff --git a/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/annotations/xml/XmlPersistenceContentHandler.java b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/annotations/xml/XmlPersistenceContentHandler.java new file mode 100755 index 000000000..757f47508 --- /dev/null +++ b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/annotations/xml/XmlPersistenceContentHandler.java @@ -0,0 +1,530 @@ +/** + * <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: XmlPersistenceContentHandler.java,v 1.11 2011/04/08 17:47:25 mtaal Exp $ + */ + +package org.eclipse.emf.teneo.annotations.xml; + +import java.io.InputStream; +import java.util.ArrayList; +import java.util.List; +import java.util.Stack; +import java.util.regex.Pattern; + +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.EObject; +import org.eclipse.emf.ecore.EPackage; +import org.eclipse.emf.ecore.EReference; +import org.eclipse.emf.ecore.EStructuralFeature; +import org.eclipse.emf.ecore.util.EcoreUtil; +import org.eclipse.emf.teneo.PackageRegistryProvider; +import org.eclipse.emf.teneo.annotations.pamodel.PAnnotatedEClass; +import org.eclipse.emf.teneo.annotations.pamodel.PAnnotatedEDataType; +import org.eclipse.emf.teneo.annotations.pamodel.PAnnotatedEPackage; +import org.eclipse.emf.teneo.annotations.pamodel.PAnnotatedEStructuralFeature; +import org.eclipse.emf.teneo.annotations.pamodel.PAnnotatedModel; +import org.eclipse.emf.teneo.annotations.pannotation.PAnnotation; +import org.eclipse.emf.teneo.extension.ExtensionManager; +import org.eclipse.emf.teneo.extension.ExtensionManagerAware; +import org.eclipse.emf.teneo.extension.ExtensionPoint; +import org.xml.sax.Attributes; +import org.xml.sax.SAXException; +import org.xml.sax.SAXParseException; +import org.xml.sax.helpers.DefaultHandler; + +/** + * SAX ContentHandler for processing XML persistence mapping. Used internally by + * {@link XmlPersistenceMapper}. + */ +public class XmlPersistenceContentHandler extends DefaultHandler implements + ExtensionPoint, ExtensionManagerAware { + + // Parse states + + // Document root. + private static final int ROOT = 0; + + // <persistence-mapping> + private static final int PERSISTENCE_MAPPING = 1; + + // <epackage> + private static final int EPACKAGE = 2; + + // Annotation element for an <epackage>. + private static final int EPACKAGE_ANNOTATION = 3; + + // <eclass> + private static final int ECLASS = 4; + + // Annotation element for an <eclass>. + private static final int ECLASS_ANNOTATION = 5; + + // <eattribute>, <ereference> or <property>. + private static final int ESTRUCTURALFEATURE = 6; + + // Annotation element for an <eattribute>, <ereference> or <property>. + private static final int ESTRUCTURALFEATURE_ANNOTATION = 7; + + // Annotation element inside another annotation. + private static final int NESTED_ANNOTATION = 8; + + // Value for an annotation element. + private static final int ANNOTATION_ATTRIBUTE = 9; + + // <eclass> + private static final int EDATATYPE = 10; + + // Annotation element for an <eclass>. + private static final int EDATATYPE_ANNOTATION = 11; + + // The pattern to split the XML element names against. + private static Pattern XML_NAME_PATTERN = Pattern.compile("-"); + + private static String convertXmlNameToEStructuralFeatureName(String xmlName) { + final String[] elementNameParts = XML_NAME_PATTERN.split(xmlName); + final StringBuffer featureName = new StringBuffer(); + for (int i = 0; i < elementNameParts.length; i++) { + String part = elementNameParts[i]; + if (i > 0) { + part = part.substring(0, 1).toUpperCase() + part.substring(1); + } + featureName.append(part); + } + return featureName.toString(); + } + + // The PAnnotatedModel that will be populated. + private PAnnotatedModel pAnnotatedModel; + + // The PAnnotatedEPackage to which the XML annotations will be applied. + private PAnnotatedEPackage pAnnotatedEPackage; + + // The current PAnnotatedEClass. + private PAnnotatedEClass pAnnotatedEClass; + + // The current PAnnotatedEDataType. + private PAnnotatedEDataType pAnnotatedEDataType; + + // The current PAnnotatedEStructuralFeature of pAnnotatedEClass. + private PAnnotatedEStructuralFeature pAnnotatedEStructuralFeature; + + // Stack of PAnnotations. + private Stack<PAnnotation> pAnnotations = new Stack<PAnnotation>(); + + // The current EAttribute of the current pAnnotation. Used only for + // EDataTypes. + private EAttribute pAnnotationEAttribute; + + // Stack of parse states. + private Stack<Integer> parseStates = new Stack<Integer>(); + + // prefix for extra efeature parsing + private String prefix; + + // ExtensionManager + private ExtensionManager extensionManager; + + /** The xml element to structural feature mapper */ + private XmlElementToEStructuralFeatureMapper xmlElementToEStructuralFeatureMapper; + + public XmlPersistenceContentHandler() { + parseStates.push(ROOT); + } + + /** Set the schema */ + public void setSchema(InputStream schema) { + xmlElementToEStructuralFeatureMapper = getExtensionManager() + .getExtension(XmlElementToEStructuralFeatureMapper.class); + xmlElementToEStructuralFeatureMapper.parseSchema(schema); + } + + /** + * Returns the current parse state. + */ + protected int getParseState() { + assert (parseStates.size() >= 1) : "Parse state stack must contain at least one element."; + return (parseStates.peek()).intValue(); + } + + protected PAnnotation getPAnnotation() { + return pAnnotations.peek(); + } + + /** + * Applies an annotation on an EObject based on the given XML element name. + * + */ + @SuppressWarnings("unchecked") + protected void applyAnnotation(EObject pAnnotatedEModelElement, + String elementName, Attributes attributes) throws SAXException { + final EStructuralFeature annotationEStructuralFeature = getEStructuralFeature( + pAnnotatedEModelElement, elementName); + if (annotationEStructuralFeature == null) { + throw new SAXException("Cannot handle element <" + elementName + + ">"); + } + + final PAnnotation pAnnotation = (PAnnotation) EcoreUtil + .create((EClass) annotationEStructuralFeature.getEType()); + pAnnotation.setGenerated(false); + pAnnotations.push(pAnnotation); + + if (annotationEStructuralFeature.isMany()) { + ((List<PAnnotation>) pAnnotatedEModelElement + .eGet(annotationEStructuralFeature)).add(pAnnotation); + } else { + pAnnotatedEModelElement.eSet(annotationEStructuralFeature, + pAnnotation); + } + + // Apply attributes to pAnnotation + for (int i = 0, n = attributes.getLength(); i < n; i++) { + final EAttribute eAttribute = (EAttribute) getEStructuralFeature( + pAnnotation, attributes.getLocalName(i)); + final EDataType eDataType = eAttribute.getEAttributeType(); + final Object valueObject = eDataType.getEPackage() + .getEFactoryInstance() + .createFromString(eDataType, attributes.getValue(i)); + if (eAttribute.isMany()) { + ((List<Object>) pAnnotation.eGet(eAttribute)).add(valueObject); + } else { + pAnnotation.eSet(eAttribute, valueObject); + } + } + + } + + /** + * Returns an estructuralfeature on the basis of the name, mainly does + * conversion of the xmlName to the efeaturename, the prefix returned from + * getPrefix is also used. todo: move prefix handling to + * XmlElementToEStructuralFeatureMapper. + */ + protected EStructuralFeature getEStructuralFeature( + EObject pAnnotatedEModelElement, String xmlName) { + String annotationEStructuralFeatureName = convertXmlNameToEStructuralFeatureName(xmlName); + EStructuralFeature annotationEStructuralFeature = pAnnotatedEModelElement + .eClass().getEStructuralFeature( + annotationEStructuralFeatureName); + if (annotationEStructuralFeature == null) { + annotationEStructuralFeatureName = xmlElementToEStructuralFeatureMapper + .getEStructuralFeatureName(xmlName); + annotationEStructuralFeature = pAnnotatedEModelElement.eClass() + .getEStructuralFeature(annotationEStructuralFeatureName); + } + // if still null then try with the prefix + if (annotationEStructuralFeature == null) { + // note if a prefix is added then the first character of the first + // part has to be + // upper-cased + String name = convertXmlNameToEStructuralFeatureName(xmlName); + annotationEStructuralFeatureName = prefix + + name.substring(0, 1).toUpperCase() + name.substring(1); + ; + annotationEStructuralFeature = pAnnotatedEModelElement.eClass() + .getEStructuralFeature(annotationEStructuralFeatureName); + } + return annotationEStructuralFeature; + } + + // -------------------------------------------------------------------- + // Implementation of ContentHandler interface. + // -------------------------------------------------------------------- + @Override + public void startElement(String uri, String localName, String qName, + Attributes attributes) throws SAXException { + // Change parse state. + int newParseState; + switch (getParseState()) { + case ROOT: + newParseState = PERSISTENCE_MAPPING; + break; + case PERSISTENCE_MAPPING: + assert (localName.equals("epackage")); + newParseState = EPACKAGE; + break; + case EPACKAGE: + if (localName.equals("eclass")) { + newParseState = ECLASS; + } else if (localName.equals("edatatype")) { + newParseState = EDATATYPE; + } else { + newParseState = EPACKAGE_ANNOTATION; + } + break; + case ECLASS: + if (localName.equals("eattribute") + || localName.equals("ereference") + || localName.equals("property")) { + newParseState = ESTRUCTURALFEATURE; + } else { + newParseState = ECLASS_ANNOTATION; + } + break; + case ESTRUCTURALFEATURE: + newParseState = ESTRUCTURALFEATURE_ANNOTATION; + break; + case EDATATYPE: + newParseState = EDATATYPE_ANNOTATION; + break; + case EPACKAGE_ANNOTATION: + case ECLASS_ANNOTATION: + case ESTRUCTURALFEATURE_ANNOTATION: + case NESTED_ANNOTATION: { + final EStructuralFeature annotationEStructuralFeature = getEStructuralFeature( + getPAnnotation(), localName); + if (annotationEStructuralFeature.getEType() instanceof EClass) { + newParseState = NESTED_ANNOTATION; + } else { + newParseState = ANNOTATION_ATTRIBUTE; + } + break; + } + default: + throw new ParseXMLAnnotationsException( + "Invalid parse state encountered."); + } + parseStates.push(new Integer(newParseState)); + + // Act upon the new parse state. + switch (getParseState()) { + case EPACKAGE: { + final String namespaceUri = attributes.getValue("namespace-uri"); + final EPackage ePackage = PackageRegistryProvider.getInstance() + .getPackageRegistry().getEPackage(namespaceUri); + if (ePackage == null) { + throw new SAXException("Could not find EPackage \"" + + namespaceUri + "\"."); + } + pAnnotatedEPackage = pAnnotatedModel.getPAnnotated(ePackage); + if (pAnnotatedEPackage == null) { + throw new SAXException("Could not find PAnnotatedEPackage \"" + + namespaceUri + "\"."); + } + break; + } + case ECLASS: { + final String eClassName = attributes.getValue("name"); + final EClassifier eClassifier = pAnnotatedEPackage + .getModelEPackage().getEClassifier(eClassName); + if (eClassifier == null) { + throw new SAXException("Could not find EClass \"" + eClassName + + "\""); + } + if (!(eClassifier instanceof EClass)) { + throw new SAXException("EClassifier \"" + eClassName + + "\" is not an EClass."); + } + pAnnotatedEClass = pAnnotatedModel + .getPAnnotated((EClass) eClassifier); + break; + } + case EDATATYPE: { + final String eDataTypeName = attributes.getValue("name"); + final EDataType et = (EDataType) pAnnotatedEPackage + .getModelEPackage().getEClassifier(eDataTypeName); + if (et == null) { + throw new SAXException("Could not find EClass \"" + + eDataTypeName + "\""); + } + pAnnotatedEDataType = pAnnotatedModel.getPAnnotated(et); + break; + } + case ESTRUCTURALFEATURE: { + final String eStructuralFeatureName = attributes.getValue("name"); + final EClass eClass = pAnnotatedEClass.getModelEClass(); + final EStructuralFeature eStructuralFeature = eClass + .getEStructuralFeature(eStructuralFeatureName); + if (eStructuralFeature == null) { + throw new SAXException("Could not find EStructuralFeature \"" + + eStructuralFeatureName + "\" in EClass \"" + + eClass.getName() + "\"."); + } else if (localName.equals("eattribute") + && !(eStructuralFeature instanceof EAttribute)) { + throw new SAXException("EStructuralFeature \"" + + eStructuralFeatureName + "\" in EClass \"" + + eClass.getName() + "\" is not an EAttribute."); + } else if (localName.equals("ereference") + && !(eStructuralFeature instanceof EReference)) { + throw new SAXException("EStructuralFeature \"" + + eStructuralFeatureName + "\" in EClass \"" + + eClass.getName() + "\" is not an EReference."); + } + pAnnotatedEStructuralFeature = pAnnotatedModel + .getPAnnotated(eStructuralFeature); + break; + } + case EPACKAGE_ANNOTATION: + applyAnnotation(pAnnotatedEPackage, localName, attributes); + break; + case ECLASS_ANNOTATION: + applyAnnotation(pAnnotatedEClass, localName, attributes); + break; + case ESTRUCTURALFEATURE_ANNOTATION: + applyAnnotation(pAnnotatedEStructuralFeature, localName, attributes); + break; + case EDATATYPE_ANNOTATION: + applyAnnotation(pAnnotatedEDataType, localName, attributes); + break; + case NESTED_ANNOTATION: { + // final String eStructuralFeatureName = + // convertElementNameToEStructuralFeatureName(localName); + // final EReference annotationEStructuralFeature = (EReference) + // getPAnnotation().eClass() + // .getEStructuralFeature(eStructuralFeatureName); + applyAnnotation(getPAnnotation(), localName, attributes); + break; + } + case ANNOTATION_ATTRIBUTE: { + final String eStructuralFeatureName = convertXmlNameToEStructuralFeatureName(localName); + pAnnotationEAttribute = (EAttribute) getPAnnotation().eClass() + .getEStructuralFeature(eStructuralFeatureName); + break; + } + } + } + + @Override + @SuppressWarnings("unchecked") + public void characters(char[] ch, int start, int length) + throws SAXException { + final String value = new String(ch, start, length).trim(); + if (value.length() == 0) { + return; + } + switch (getParseState()) { + case EPACKAGE_ANNOTATION: + case ECLASS_ANNOTATION: + case ESTRUCTURALFEATURE_ANNOTATION: + case NESTED_ANNOTATION: { + // If we get here, we are dealing with a PAnnotation that has only + // one EAttribute. + // I.e. there are no + // child elements. Example: + // <discriminator-value>MyObject</discriminator-value> + final PAnnotation pAnnotation = getPAnnotation(); + assert (pAnnotation.eClass().getEStructuralFeatures().size() == 1); + final EAttribute eAttribute = (EAttribute) pAnnotation.eClass() + .getEStructuralFeatures().get(0); + final EDataType eAttributeType = eAttribute.getEAttributeType(); + final Object valueObject = eAttributeType.getEPackage() + .getEFactoryInstance() + .createFromString(eAttributeType, value); + if (eAttribute.isMany() && valueObject instanceof String) { + final String[] vals = ((String) valueObject).split(","); + final List<String> valsList = new ArrayList<String>(); + for (String val : vals) { + valsList.add(val); + } + pAnnotation.eSet(eAttribute, valsList); + } else { + pAnnotation.eSet(eAttribute, valueObject); + } + break; + } + case ANNOTATION_ATTRIBUTE: { + final EDataType eDataType = pAnnotationEAttribute + .getEAttributeType(); + final Object valueObject = eDataType.getEPackage() + .getEFactoryInstance().createFromString(eDataType, value); + if (pAnnotationEAttribute.isMany()) { + ((List<Object>) getPAnnotation().eGet(pAnnotationEAttribute)) + .add(valueObject); + } else { + getPAnnotation().eSet(pAnnotationEAttribute, valueObject); + } + break; + } + } + } + + @Override + public void endElement(String uri, String localName, String qName) + throws SAXException { + switch (getParseState()) { + case EPACKAGE_ANNOTATION: + case ECLASS_ANNOTATION: + case ESTRUCTURALFEATURE_ANNOTATION: + case NESTED_ANNOTATION: + pAnnotations.pop(); + break; + case ANNOTATION_ATTRIBUTE: + pAnnotationEAttribute = null; + break; + } + parseStates.pop(); + } + + // -------------------------------------------------------------------- + // Implementation of ErrorHandler interface. + // -------------------------------------------------------------------- + + @Override + public void error(SAXParseException e) throws SAXException { + throw e; + } + + @Override + public void fatalError(SAXParseException e) throws SAXException { + throw e; + } + + /** + * @return the extensionManager + */ + public ExtensionManager getExtensionManager() { + return extensionManager; + } + + /** + * @param extensionManager + * the extensionManager to set + */ + public void setExtensionManager(ExtensionManager extensionManager) { + this.extensionManager = extensionManager; + } + + /** + * @return the pAnnotatedModel + */ + public PAnnotatedModel getPAnnotatedModel() { + return pAnnotatedModel; + } + + /** + * @param annotatedModel + * the pAnnotatedModel to set + */ + public void setPAnnotatedModel(PAnnotatedModel annotatedModel) { + pAnnotatedModel = annotatedModel; + } + + /** + * @return the prefix + */ + public String getPrefix() { + return prefix; + } + + /** + * @param prefix + * the prefix to set + */ + public void setPrefix(String prefix) { + this.prefix = prefix; + } +}
\ No newline at end of file diff --git a/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/annotations/xml/XmlPersistenceMapper.java b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/annotations/xml/XmlPersistenceMapper.java new file mode 100755 index 000000000..f029ec7f3 --- /dev/null +++ b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/annotations/xml/XmlPersistenceMapper.java @@ -0,0 +1,144 @@ +/** + * <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: XmlPersistenceMapper.java,v 1.5 2008/05/27 07:42:09 mtaal Exp $ + */ + +package org.eclipse.emf.teneo.annotations.xml; + +import java.io.IOException; +import java.io.InputStream; + +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.parsers.SAXParser; +import javax.xml.parsers.SAXParserFactory; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.eclipse.emf.teneo.annotations.pamodel.PAnnotatedModel; +import org.eclipse.emf.teneo.extension.ExtensionManager; +import org.eclipse.emf.teneo.extension.ExtensionManagerAware; +import org.eclipse.emf.teneo.extension.ExtensionPoint; +import org.xml.sax.SAXException; +import org.xml.sax.SAXNotRecognizedException; + +/** + * Populates and configures a PAnnotatedModel using an XML persistence mapping file. + */ +public class XmlPersistenceMapper implements ExtensionPoint, ExtensionManagerAware { + + /** The inputStream containing the xml document */ + private InputStream xmlMapping; + + /** The logger */ + protected static final Log log = LogFactory.getLog(XmlPersistenceMapper.class); + + private ExtensionManager extensionManager; + + /** + * Sets the InputStream containing the XML mapping. + * + * @param xmlMapping + * The InputStream containing the XML persistence mapping. Closed automatically by + * {@link #applyPersistenceMapping(PAnnotatedModel)}. + */ + public void setXmlMapping(InputStream xmlMapping) { + if (xmlMapping == null) { + throw new IllegalArgumentException("XML mapping cannot be null."); + } + this.xmlMapping = xmlMapping; + } + + /** + * Applies the XML persistence mapping to a PAnnotatedModel. + * + * @throws IllegalStateException + * if the XML mapping was not configured. + * @throws RuntimeException + * If there was an error reading or parsing the XML file. + */ + public void applyPersistenceMapping(PAnnotatedModel pAnnotatedModel) { + if (xmlMapping == null) { + throw new IllegalStateException("XML mapping not configured."); + } + + SAXParser saxParser; + try { + final SAXParserFactory saxParserFactory = SAXParserFactory.newInstance(); + saxParserFactory.setNamespaceAware(true); + saxParserFactory.setValidating(true); + + saxParser = saxParserFactory.newSAXParser(); + } catch (ParserConfigurationException e) { + throw new ParseXMLAnnotationsException(e); + } catch (SAXException e) { + throw new ParseXMLAnnotationsException(e); + } + + try { + try { + saxParser.setProperty("http://java.sun.com/xml/jaxp/properties/schemaLanguage", + "http://www.w3.org/2001/XMLSchema"); + saxParser.setProperty("http://java.sun.com/xml/jaxp/properties/schemaSource", this.getClass() + .getResourceAsStream("persistence-mapping.xsd")); + } catch (SAXNotRecognizedException s) { + log.warn("Properties schemaSource and/or schemaLanguage are not supported, setvalidating=false. " + + "Probably running 1.4 with an old crimson sax parser. Ignoring this and continuing with " + + "a non-validating and name-space-aware sax parser"); + final SAXParserFactory saxParserFactory = SAXParserFactory.newInstance(); + saxParserFactory.setNamespaceAware(true); + saxParserFactory.setValidating(false); + saxParser = saxParserFactory.newSAXParser(); + } + + final XmlPersistenceContentHandler xmlContentHandler = + extensionManager.getExtension(XmlPersistenceContentHandler.class); + xmlContentHandler.setPAnnotatedModel(pAnnotatedModel); + xmlContentHandler.setPrefix(getPrefix()); + xmlContentHandler.setSchema(this.getClass().getResourceAsStream("persistence-mapping.xsd")); + saxParser.parse(xmlMapping, xmlContentHandler); + } catch (SAXException e) { + throw new ParseXMLAnnotationsException(e); + } catch (IOException e) { + throw new ParseXMLAnnotationsException(e); + } catch (ParserConfigurationException e) { + throw new ParseXMLAnnotationsException(e); + } finally { + try { + xmlMapping.close(); + } catch (IOException e) { + // ignoring io exception + } + } + } + + /** Return a prefix which are used by a subpackage to make efeatures unique */ + protected String getPrefix() { + return ""; + } + + /** + * @return the extensionManager + */ + public ExtensionManager getExtensionManager() { + return extensionManager; + } + + /** + * @param extensionManager + * the extensionManager to set + */ + public void setExtensionManager(ExtensionManager extensionManager) { + this.extensionManager = extensionManager; + } +} diff --git a/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/annotations/xml/persistence-mapping.xsd b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/annotations/xml/persistence-mapping.xsd new file mode 100755 index 000000000..e0a72dabf --- /dev/null +++ b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/annotations/xml/persistence-mapping.xsd @@ -0,0 +1,433 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<xsd:schema targetNamespace="http://www.eclipse.org/emft/teneo" elementFormDefault="qualified" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://www.eclipse.org/emft/teneo"> + <xsd:element name="persistence-mapping" type="PersistenceMapping"/> + <xsd:complexType name="PersistenceMapping"> + <xsd:sequence minOccurs="1" maxOccurs="unbounded"> + <xsd:element name="epackage" type="EPackage"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="EPackage"> + <xsd:choice minOccurs="0" maxOccurs="unbounded"> + <xsd:element name="sequence-generator" type="SequenceGenerator"> + <xsd:annotation> + <xsd:appinfo source="teneo/internal/EStructuralFeatureName">sequenceGenerators</xsd:appinfo> + </xsd:annotation> + </xsd:element> + <xsd:element name="table-generator" type="TableGenerator"> + <xsd:annotation> + <xsd:appinfo source="teneo/internal/EStructuralFeatureName">tableGenerators</xsd:appinfo> + </xsd:annotation> + </xsd:element> + <xsd:element name="transient" type="Transient"/> + <xsd:element name="eclass" type="EClass"/> + <xsd:element name="edatatype" type="EDataType"/> + </xsd:choice> + <xsd:attribute name="namespace-uri" type="xsd:anyURI" use="required"/> + </xsd:complexType> + <xsd:complexType name="EClass"> + <xsd:choice minOccurs="0" maxOccurs="unbounded"> + <xsd:element name="association-override" type="AssociationOverride"> + <xsd:annotation> + <xsd:appinfo source="teneo/internal/EStructuralFeatureName">associationOverrides</xsd:appinfo> + </xsd:annotation> + </xsd:element> + <xsd:element name="attribute-override" type="AttributeOverride"> + <xsd:annotation> + <xsd:appinfo source="teneo/internal/EStructuralFeatureName">attributeOverrides</xsd:appinfo> + </xsd:annotation> + </xsd:element> + <xsd:element name="discriminator-column" type="DiscriminatorColumn"/> + <xsd:element name="discriminator-value" type="xsd:string"/> + <xsd:element name="embeddable" type="Embeddable"/> + <xsd:element name="entity" type="Entity"/> + <xsd:element name="id-class" type="xsd:string"/> + <xsd:element name="inheritance" type="InheritanceType"/> + <xsd:element name="mapped-superclass" type="MappedSuperclass"/> + <xsd:element name="primary-key-join-column" type="PrimaryKeyJoinColumn"> + <xsd:annotation> + <xsd:appinfo source="teneo/internal/EStructuralFeatureName">primaryKeyJoinColumns</xsd:appinfo> + </xsd:annotation> + </xsd:element> + <xsd:element name="secondary-table" type="SecondaryTable"> + <xsd:annotation> + <xsd:appinfo source="teneo/internal/EStructuralFeatureName">secondaryTables</xsd:appinfo> + </xsd:annotation> + </xsd:element> + <xsd:element name="table" type="Table"/> + <xsd:element name="table-generator" type="TableGenerator"/> + <xsd:element name="transient" type="Transient"/> + <xsd:element name="eattribute" type="EAttribute"/> + <xsd:element name="ereference" type="EReference"/> + <xsd:element name="property" type="Property"/> + <xsd:element name="edatatype" type="EDataType"/> + </xsd:choice> + <xsd:attribute name="name" type="xsd:token" use="required"/> + </xsd:complexType> + <xsd:complexType name="EAttribute"> + <xsd:choice minOccurs="0" maxOccurs="unbounded"> + <xsd:element name="attribute-override" type="AttributeOverride"> + <xsd:annotation> + <xsd:appinfo source="teneo/internal/EStructuralFeatureName">attributeOverrides</xsd:appinfo> + </xsd:annotation> + </xsd:element> + <xsd:element name="basic" type="Basic"/> + <xsd:element name="column" type="Column"/> + <xsd:element name="enumerated" type="EnumType"/> + <xsd:element name="foreign-key" type="xsd:string"/> + <xsd:element name="generated-value" type="GeneratedValue"/> + <xsd:element name="id" type="Id"/> + <xsd:element name="join-column" type="JoinColumn"> + <xsd:annotation> + <xsd:appinfo source="teneo/internal/EStructuralFeatureName">joinColumns</xsd:appinfo> + </xsd:annotation> + </xsd:element> + <xsd:element name="join-table" type="JoinTable"/> + <xsd:element name="lob" type="Lob"/> + <xsd:element name="one-to-many" type="OneToMany"/> + <xsd:element name="sequence-generator" type="SequenceGenerator"/> + <xsd:element name="table-generator" type="TableGenerator"> + <xsd:annotation> + <xsd:appinfo source="teneo/internal/EStructuralFeatureName">tableGenerators</xsd:appinfo> + </xsd:annotation> + </xsd:element> + <xsd:element name="temporal" type="TemporalType"/> + <xsd:element name="transient" type="Transient"/> + <xsd:element name="version" type="Version"/> + </xsd:choice> + <xsd:attribute name="name" type="xsd:token" use="required"/> + </xsd:complexType> + <xsd:complexType name="EReference"> + <xsd:choice minOccurs="0" maxOccurs="unbounded"> + <xsd:element name="attribute-override" type="AttributeOverride"> + <xsd:annotation> + <xsd:appinfo source="teneo/internal/EStructuralFeatureName">attributeOverrides</xsd:appinfo> + </xsd:annotation> + </xsd:element> + <xsd:element name="column" type="Column"/> + <xsd:element name="embedded" type="Embedded"/> + <xsd:element name="embedded-id" type="EmbeddedId"/> + <xsd:element name="foreign-key" type="xsd:string"/> + <xsd:element name="join-column" type="JoinColumn"> + <xsd:annotation> + <xsd:appinfo source="teneo/internal/EStructuralFeatureName">joinColumns</xsd:appinfo> + </xsd:annotation> + </xsd:element> + <xsd:element name="join-table" type="JoinTable"/> + <xsd:element name="many-to-many" type="ManyToMany"/> + <xsd:element name="many-to-one" type="ManyToOne"/> + <xsd:element name="map-key" type="xsd:string"/> + <xsd:element name="one-to-many" type="OneToMany"/> + <xsd:element name="one-to-one" type="OneToOne"/> + <xsd:element name="order-by" type="xsd:string"/> + <xsd:element name="primary-key-join-column" type="PrimaryKeyJoinColumn"> + <xsd:annotation> + <xsd:appinfo source="teneo/internal/EStructuralFeatureName">primaryKeyJoinColumns</xsd:appinfo> + </xsd:annotation> + </xsd:element> + <xsd:element name="sequence-generator" type="SequenceGenerator"/> + <xsd:element name="table-generator" type="TableGenerator"> + <xsd:annotation> + <xsd:appinfo source="teneo/internal/EStructuralFeatureName">tableGenerators</xsd:appinfo> + </xsd:annotation> + </xsd:element> + <xsd:element name="transient" type="Transient"/> + </xsd:choice> + <xsd:attribute name="name" type="xsd:token" use="required"/> + </xsd:complexType> + <xsd:complexType name="Property"> + <xsd:choice minOccurs="0" maxOccurs="unbounded"> + <xsd:element name="attribute-override" type="AttributeOverride"> + <xsd:annotation> + <xsd:appinfo source="teneo/internal/EStructuralFeatureName">attributeOverrides</xsd:appinfo> + </xsd:annotation> + </xsd:element> + <xsd:element name="basic" type="Basic"/> + <xsd:element name="column" type="Column"/> + <xsd:element name="embedded" type="Embedded"/> + <xsd:element name="embedded-id" type="EmbeddedId"/> + <xsd:element name="enumerated" type="EnumType"/> + <xsd:element name="foreign-key" type="xsd:string"/> + <xsd:element name="generated-value" type="GeneratedValue"/> + <xsd:element name="id" type="Id"/> + <xsd:element name="join-column" type="JoinColumn"> + <xsd:annotation> + <xsd:appinfo source="teneo/internal/EStructuralFeatureName">joinColumns</xsd:appinfo> + </xsd:annotation> + </xsd:element> + <xsd:element name="join-table" type="JoinTable"/> + <xsd:element name="lob" type="Lob"/> + <xsd:element name="many-to-many" type="ManyToMany"/> + <xsd:element name="many-to-one" type="ManyToOne"/> + <xsd:element name="map-key" type="xsd:string"/> + <xsd:element name="one-to-many" type="OneToMany"/> + <xsd:element name="one-to-one" type="OneToOne"/> + <xsd:element name="order-by" type="xsd:string"/> + <xsd:element name="primary-key-join-column" type="PrimaryKeyJoinColumn"> + <xsd:annotation> + <xsd:appinfo source="teneo/internal/EStructuralFeatureName">primaryKeyJoinColumns</xsd:appinfo> + </xsd:annotation> + </xsd:element> + <xsd:element name="sequence-generator" type="SequenceGenerator"/> + <xsd:element name="table-generator" type="TableGenerator"> + <xsd:annotation> + <xsd:appinfo source="teneo/internal/EStructuralFeatureName">tableGenerators</xsd:appinfo> + </xsd:annotation> + </xsd:element> + <xsd:element name="temporal" type="TemporalType"/> + <xsd:element name="transient" type="Transient"/> + <xsd:element name="version" type="Version"/> + </xsd:choice> + <xsd:attribute name="name" type="xsd:token" use="required"/> + </xsd:complexType> + <xsd:complexType name="EDataType"> + <xsd:choice minOccurs="0" maxOccurs="unbounded"> + <xsd:element name="basic" type="Basic"/> + <xsd:element name="column" type="Column"/> + <xsd:element name="enumerated" type="EnumType"/> + <xsd:element name="generated-value" type="GeneratedValue"/> + <xsd:element name="id" type="Id"/> + <xsd:element name="lob" type="Lob"/> + <xsd:element name="temporal" type="TemporalType"/> + <xsd:element name="transient" type="Transient"/> + <xsd:element name="version" type="Version"/> + </xsd:choice> + <xsd:attribute name="name" type="xsd:token" use="required"/> + </xsd:complexType> +<xsd:complexType name="AssociationOverride"> + <xsd:choice minOccurs="0" maxOccurs="unbounded"> + <xsd:element name="join-column" type="JoinColumn"> + <xsd:annotation> + <xsd:appinfo source="teneo/internal/EStructuralFeatureName">joinColumns</xsd:appinfo> + </xsd:annotation> + </xsd:element> + </xsd:choice> + <xsd:attribute name="name" type="xsd:string" use="required"/> +</xsd:complexType> +<xsd:complexType name="AttributeOverride"> + <xsd:choice minOccurs="0" maxOccurs="unbounded"> + <xsd:element name="column" type="Column"/> + </xsd:choice> + <xsd:attribute name="name" type="xsd:string" use="required"/> +</xsd:complexType> +<xsd:complexType name="Basic"> + <xsd:attribute name="fetch" type="FetchType" use="optional"/> + <xsd:attribute name="optional" type="xsd:boolean" use="optional"/> +</xsd:complexType> +<xsd:simpleType name="CascadeType"> + <xsd:restriction base="xsd:token"> + <xsd:enumeration value="ALL"/> + <xsd:enumeration value="PERSIST"/> + <xsd:enumeration value="MERGE"/> + <xsd:enumeration value="REMOVE"/> + <xsd:enumeration value="REFRESH"/> + <xsd:enumeration value="NONE"/> + </xsd:restriction> +</xsd:simpleType> +<xsd:complexType name="Column"> + <xsd:attribute name="column-definition" type="xsd:string" use="optional"/> + <xsd:attribute name="insertable" type="xsd:boolean" use="optional"/> + <xsd:attribute name="length" type="xsd:int" use="optional"/> + <xsd:attribute name="name" type="xsd:string" use="optional"/> + <xsd:attribute name="nullable" type="xsd:boolean" use="optional"/> + <xsd:attribute name="precision" type="xsd:int" use="optional"/> + <xsd:attribute name="scale" type="xsd:int" use="optional"/> + <xsd:attribute name="table" type="xsd:string" use="optional"/> + <xsd:attribute name="unique" type="xsd:boolean" use="optional"/> + <xsd:attribute name="updatable" type="xsd:boolean" use="optional"/> +</xsd:complexType> +<xsd:complexType name="DiscriminatorColumn"> + <xsd:attribute name="column-definition" type="xsd:string" use="optional"/> + <xsd:attribute name="discriminator-type" type="DiscriminatorType" use="optional"/> + <xsd:attribute name="length" type="xsd:int" use="optional"/> + <xsd:attribute name="name" type="xsd:string" use="optional"/> +</xsd:complexType> +<xsd:simpleType name="DiscriminatorType"> + <xsd:restriction base="xsd:token"> + <xsd:enumeration value="STRING"/> + <xsd:enumeration value="CHAR"/> + <xsd:enumeration value="INTEGER"/> + </xsd:restriction> +</xsd:simpleType> +<xsd:complexType name="Embeddable"/> +<xsd:complexType name="Embedded"/> +<xsd:complexType name="EmbeddedId"/> +<xsd:complexType name="Entity"> + <xsd:attribute name="extends" type="xsd:string" use="optional"/> + <xsd:attribute name="name" type="xsd:string" use="optional"/> +</xsd:complexType> +<xsd:simpleType name="EnumType"> + <xsd:restriction base="xsd:token"> + <xsd:enumeration value="ORDINAL"/> + <xsd:enumeration value="STRING"/> + </xsd:restriction> +</xsd:simpleType> +<xsd:simpleType name="FetchType"> + <xsd:restriction base="xsd:token"> + <xsd:enumeration value="LAZY"/> + <xsd:enumeration value="EAGER"/> + <xsd:enumeration value="EXTRA"/> + </xsd:restriction> +</xsd:simpleType> +<xsd:complexType name="GeneratedValue"> + <xsd:attribute name="generator" type="xsd:string" use="optional"/> + <xsd:attribute name="strategy" type="GenerationType" use="optional"/> +</xsd:complexType> +<xsd:simpleType name="GenerationType"> + <xsd:restriction base="xsd:token"> + <xsd:enumeration value="TABLE"/> + <xsd:enumeration value="SEQUENCE"/> + <xsd:enumeration value="IDENTITY"/> + <xsd:enumeration value="AUTO"/> + </xsd:restriction> +</xsd:simpleType> +<xsd:complexType name="Id"/> +<xsd:simpleType name="InheritanceType"> + <xsd:restriction base="xsd:token"> + <xsd:enumeration value="SINGLE_TABLE"/> + <xsd:enumeration value="TABLE_PER_CLASS"/> + <xsd:enumeration value="JOINED"/> + </xsd:restriction> +</xsd:simpleType> +<xsd:complexType name="JoinColumn"> + <xsd:attribute name="column-definition" type="xsd:string" use="optional"/> + <xsd:attribute name="insertable" type="xsd:boolean" use="optional"/> + <xsd:attribute name="name" type="xsd:string" use="optional"/> + <xsd:attribute name="nullable" type="xsd:boolean" use="optional"/> + <xsd:attribute name="referenced-column-name" type="xsd:string" use="optional"/> + <xsd:attribute name="table" type="xsd:string" use="optional"/> + <xsd:attribute name="unique" type="xsd:boolean" use="optional"/> + <xsd:attribute name="updatable" type="xsd:boolean" use="optional"/> +</xsd:complexType> +<xsd:complexType name="JoinTable"> + <xsd:choice minOccurs="0" maxOccurs="unbounded"> + <xsd:element name="inverse-join-column" type="JoinColumn"> + <xsd:annotation> + <xsd:appinfo source="teneo/internal/EStructuralFeatureName">inverseJoinColumns</xsd:appinfo> + </xsd:annotation> + </xsd:element> + <xsd:element name="join-column" type="JoinColumn"> + <xsd:annotation> + <xsd:appinfo source="teneo/internal/EStructuralFeatureName">joinColumns</xsd:appinfo> + </xsd:annotation> + </xsd:element> + <xsd:element name="unique-constraint" type="xsd:string"> + <xsd:annotation> + <xsd:appinfo source="teneo/internal/EStructuralFeatureName">uniqueConstraints</xsd:appinfo> + </xsd:annotation> + </xsd:element> + </xsd:choice> + <xsd:attribute name="catalog" type="xsd:string" use="optional"/> + <xsd:attribute name="name" type="xsd:string" use="optional"/> + <xsd:attribute name="schema" type="xsd:string" use="optional"/> +</xsd:complexType> +<xsd:complexType name="Lob"/> +<xsd:complexType name="ManyToMany"> + <xsd:choice minOccurs="0" maxOccurs="unbounded"> + <xsd:element name="cascade" type="CascadeType"/> + </xsd:choice> + <xsd:attribute name="cascade" type="CascadeType" use="optional"/> + <xsd:attribute name="fetch" type="FetchType" use="optional"/> + <xsd:attribute name="indexed" type="xsd:boolean" use="optional"/> + <xsd:attribute name="mapped-by" type="xsd:string" use="optional"/> + <xsd:attribute name="target-entity" type="xsd:string" use="optional"/> +</xsd:complexType> +<xsd:complexType name="ManyToOne"> + <xsd:choice minOccurs="0" maxOccurs="unbounded"> + <xsd:element name="cascade" type="CascadeType"/> + </xsd:choice> + <xsd:attribute name="cascade" type="CascadeType" use="optional"/> + <xsd:attribute name="fetch" type="FetchType" use="optional"/> + <xsd:attribute name="optional" type="xsd:boolean" use="optional"/> + <xsd:attribute name="target-entity" type="xsd:string" use="optional"/> +</xsd:complexType> +<xsd:complexType name="MappedSuperclass"/> +<xsd:complexType name="OneToMany"> + <xsd:choice minOccurs="0" maxOccurs="unbounded"> + <xsd:element name="cascade" type="CascadeType"/> + </xsd:choice> + <xsd:attribute name="cascade" type="CascadeType" use="optional"/> + <xsd:attribute name="fetch" type="FetchType" use="optional"/> + <xsd:attribute name="indexed" type="xsd:boolean" use="optional"/> + <xsd:attribute name="mapped-by" type="xsd:string" use="optional"/> + <xsd:attribute name="target-entity" type="xsd:string" use="optional"/> + <xsd:attribute name="unique" type="xsd:boolean" use="optional"/> +</xsd:complexType> +<xsd:complexType name="OneToOne"> + <xsd:choice minOccurs="0" maxOccurs="unbounded"> + <xsd:element name="cascade" type="CascadeType"/> + </xsd:choice> + <xsd:attribute name="cascade" type="CascadeType" use="optional"/> + <xsd:attribute name="fetch" type="FetchType" use="optional"/> + <xsd:attribute name="mapped-by" type="xsd:string" use="optional"/> + <xsd:attribute name="optional" type="xsd:boolean" use="optional"/> + <xsd:attribute name="target-entity" type="xsd:string" use="optional"/> +</xsd:complexType> +<xsd:complexType name="PrimaryKeyJoinColumn"> + <xsd:attribute name="column-definition" type="xsd:string" use="optional"/> + <xsd:attribute name="name" type="xsd:string" use="optional"/> + <xsd:attribute name="referenced-column-name" type="xsd:string" use="optional"/> +</xsd:complexType> +<xsd:complexType name="SecondaryTable"> + <xsd:choice minOccurs="0" maxOccurs="unbounded"> + <xsd:element name="pk-join-column" type="PrimaryKeyJoinColumn"> + <xsd:annotation> + <xsd:appinfo source="teneo/internal/EStructuralFeatureName">pkJoinColumns</xsd:appinfo> + </xsd:annotation> + </xsd:element> + <xsd:element name="unique-constraint" type="xsd:string"> + <xsd:annotation> + <xsd:appinfo source="teneo/internal/EStructuralFeatureName">uniqueConstraints</xsd:appinfo> + </xsd:annotation> + </xsd:element> + </xsd:choice> + <xsd:attribute name="catalog" type="xsd:string" use="optional"/> + <xsd:attribute name="name" type="xsd:string" use="required"/> + <xsd:attribute name="schema" type="xsd:string" use="optional"/> +</xsd:complexType> +<xsd:complexType name="SequenceGenerator"> + <xsd:attribute name="allocation-size" type="xsd:int" use="optional"/> + <xsd:attribute name="initial-value" type="xsd:int" use="optional"/> + <xsd:attribute name="name" type="xsd:string" use="required"/> + <xsd:attribute name="sequence-name" type="xsd:string" use="optional"/> +</xsd:complexType> +<xsd:complexType name="Table"> + <xsd:choice minOccurs="0" maxOccurs="unbounded"> + <xsd:element name="unique-constraint" type="xsd:string"> + <xsd:annotation> + <xsd:appinfo source="teneo/internal/EStructuralFeatureName">uniqueConstraints</xsd:appinfo> + </xsd:annotation> + </xsd:element> + </xsd:choice> + <xsd:attribute name="catalog" type="xsd:string" use="optional"/> + <xsd:attribute name="name" type="xsd:string" use="optional"/> + <xsd:attribute name="schema" type="xsd:string" use="optional"/> +</xsd:complexType> +<xsd:complexType name="TableGenerator"> + <xsd:choice minOccurs="0" maxOccurs="unbounded"> + <xsd:element name="unique-constraint" type="xsd:string"> + <xsd:annotation> + <xsd:appinfo source="teneo/internal/EStructuralFeatureName">uniqueConstraints</xsd:appinfo> + </xsd:annotation> + </xsd:element> + </xsd:choice> + <xsd:attribute name="allocation-size" type="xsd:int" use="optional"/> + <xsd:attribute name="catalog" type="xsd:string" use="optional"/> + <xsd:attribute name="initial-value" type="xsd:int" use="optional"/> + <xsd:attribute name="name" type="xsd:string" use="required"/> + <xsd:attribute name="pk-column-name" type="xsd:string" use="optional"/> + <xsd:attribute name="pk-column-value" type="xsd:string" use="optional"/> + <xsd:attribute name="schema" type="xsd:string" use="optional"/> + <xsd:attribute name="table" type="xsd:string" use="optional"/> + <xsd:attribute name="value-column-name" type="xsd:string" use="optional"/> +</xsd:complexType> +<xsd:simpleType name="TemporalType"> + <xsd:restriction base="xsd:token"> + <xsd:enumeration value="DATE"/> + <xsd:enumeration value="TIME"/> + <xsd:enumeration value="TIMESTAMP"/> + </xsd:restriction> +</xsd:simpleType> +<xsd:complexType name="Transient"/> +<xsd:complexType name="Version"/> +</xsd:schema>
\ No newline at end of file diff --git a/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/annotations/xml/persistence-mapping_previous.xsd b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/annotations/xml/persistence-mapping_previous.xsd new file mode 100755 index 000000000..36cca8878 --- /dev/null +++ b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/annotations/xml/persistence-mapping_previous.xsd @@ -0,0 +1,399 @@ +<?xml version="1.0" encoding="UTF-8"?> +<xsd:schema targetNamespace="http://www.elver.org/teneo/persistence" +elementFormDefault="qualified" xmlns:xsd="http://www.w3.org/2001/XMLSchema" +xmlns="http://www.elver.org/teneo/persistence"> + <xsd:element name="persistence-mapping" type="PersistenceMapping"> + <xsd:annotation> + <xsd:documentation>The root element of an instance document.</xsd:documentation> + </xsd:annotation> + </xsd:element> + <xsd:complexType name="PersistenceMapping"> + <xsd:sequence minOccurs="1" maxOccurs="unbounded"> + <xsd:element name="epackage" type="EPackage"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="EPackage"> + <xsd:sequence> + <xsd:element name="sequence-generator" type="SequenceGenerator" minOccurs="0"/> + <xsd:element name="table-generator" type="TableGenerator" minOccurs="0"/> + <xsd:element name="eclass" type="EClass" minOccurs="0" maxOccurs="unbounded"/> + </xsd:sequence> + <xsd:attribute name="namespace-uri" type="xsd:anyURI" use="required"/> + </xsd:complexType> + <xsd:complexType name="EClass"> + <xsd:sequence> + <xsd:choice minOccurs="0" maxOccurs="unbounded"> + <xsd:element name="association-override" type="AssociationOverride" minOccurs="0" maxOccurs="unbounded"> + <xsd:annotation> + <xsd:appinfo source="http://annotation.elver.org/internal/EStructuralFeatureName">associationOverrides</xsd:appinfo> + </xsd:annotation> + </xsd:element> + <xsd:element name="attribute-override" type="AttributeOverride" minOccurs="0" maxOccurs="unbounded"> + <xsd:annotation> + <xsd:appinfo source="http://annotation.elver.org/internal/EStructuralFeatureName">attributeOverrides</xsd:appinfo> + </xsd:annotation> + </xsd:element> + <xsd:element name="discriminator-column" type="DiscriminatorColumn" minOccurs="0"/> + <xsd:element name="discriminator-value" type="xsd:string" minOccurs="0"/> + <xsd:element name="embeddable" type="Embeddable" minOccurs="0"/> + <xsd:element name="id-class" type="xsd:string" minOccurs="0"/> + <xsd:element name="inheritance" type="InheritanceType" minOccurs="0"/> + <xsd:element name="mapped-superclass" type="MappedSuperclass" minOccurs="0"/> + <xsd:element name="primary-key-join-column" type="PrimaryKeyJoinColumn" minOccurs="0" maxOccurs="unbounded"> + <xsd:annotation> + <xsd:appinfo source="http://annotation.elver.org/internal/EStructuralFeatureName">primaryKeyJoinColumns</xsd:appinfo> + </xsd:annotation> + </xsd:element> + <xsd:element name="secondary-table" type="SecondaryTable" minOccurs="0" maxOccurs="unbounded"> + <xsd:annotation> + <xsd:appinfo source="http://annotation.elver.org/internal/EStructuralFeatureName">secondaryTables</xsd:appinfo> + </xsd:annotation> + </xsd:element> + <xsd:element name="table" type="Table" minOccurs="0"/> + <xsd:element name="table-generator" type="TableGenerator" minOccurs="0"/> + </xsd:choice> + <xsd:choice minOccurs="0" maxOccurs="unbounded"> + <xsd:element name="eattribute" type="EAttribute" minOccurs="0" maxOccurs="unbounded"/> + <xsd:element name="ereference" type="EReference" minOccurs="0" maxOccurs="unbounded"/> + <xsd:element name="property" type="Property" minOccurs="0" maxOccurs="unbounded"/> + </xsd:choice> + </xsd:sequence> + <xsd:attribute name="name" type="xsd:token" use="required"/> + </xsd:complexType> + <xsd:complexType name="EAttribute"> + <xsd:choice minOccurs="0" maxOccurs="unbounded"> + <xsd:element name="attribute-override" type="AttributeOverride" minOccurs="0" maxOccurs="unbounded"> + <xsd:annotation> + <xsd:appinfo source="http://annotation.elver.org/internal/EStructuralFeatureName">attributeOverrides</xsd:appinfo> + </xsd:annotation> + </xsd:element> + <xsd:element name="basic" type="Basic" minOccurs="0"/> + <xsd:element name="column" type="Column" minOccurs="0"/> + <xsd:element name="enumerated" type="EnumType" minOccurs="0"/> + <xsd:element name="generated-value" type="GeneratedValue" minOccurs="0"/> + <xsd:element name="id" type="Id" minOccurs="0"/> + <xsd:element name="indexed" type="xsd:boolean" minOccurs="0"/> + <xsd:element name="join-column" type="JoinColumn" minOccurs="0" maxOccurs="unbounded"> + <xsd:annotation> + <xsd:appinfo source="http://annotation.elver.org/internal/EStructuralFeatureName">joinColumns</xsd:appinfo> + </xsd:annotation> + </xsd:element> + <xsd:element name="join-table" type="JoinTable" minOccurs="0"/> + <xsd:element name="lob" type="Lob" minOccurs="0"/> + <xsd:element name="one-to-many" type="OneToMany" minOccurs="0"/> + <xsd:element name="sequence-generator" type="SequenceGenerator" minOccurs="0"/> + <xsd:element name="table-generator" type="TableGenerator" minOccurs="0"/> + <xsd:element name="temporal" type="TemporalType" minOccurs="0"/> + <xsd:element name="unique" type="xsd:boolean" minOccurs="0"/> + <xsd:element name="version" type="Version" minOccurs="0"/> + </xsd:choice> + <xsd:attribute name="name" type="xsd:token" use="required"/> + </xsd:complexType> + <xsd:complexType name="EReference"> + <xsd:choice minOccurs="0" maxOccurs="unbounded"> + <xsd:element name="attribute-override" type="AttributeOverride" minOccurs="0" maxOccurs="unbounded"> + <xsd:annotation> + <xsd:appinfo source="http://annotation.elver.org/internal/EStructuralFeatureName">attributeOverrides</xsd:appinfo> + </xsd:annotation> + </xsd:element> + <xsd:element name="column" type="Column" minOccurs="0"/> + <xsd:element name="embedded" type="Embedded" minOccurs="0"/> + <xsd:element name="embedded-id" type="EmbeddedId" minOccurs="0"/> + <xsd:element name="indexed" type="xsd:boolean" minOccurs="0"/> + <xsd:element name="join-column" type="JoinColumn" minOccurs="0" maxOccurs="unbounded"> + <xsd:annotation> + <xsd:appinfo source="http://annotation.elver.org/internal/EStructuralFeatureName">joinColumns</xsd:appinfo> + </xsd:annotation> + </xsd:element> + <xsd:element name="join-table" type="JoinTable" minOccurs="0"/> + <xsd:element name="many-to-many" type="ManyToMany" minOccurs="0"/> + <xsd:element name="many-to-one" type="ManyToOne" minOccurs="0"/> + <xsd:element name="one-to-many" type="OneToMany" minOccurs="0"/> + <xsd:element name="one-to-one" type="OneToOne" minOccurs="0"/> + <xsd:element name="order-by" type="xsd:string" minOccurs="0"/> + <xsd:element name="primary-key-join-column" type="PrimaryKeyJoinColumn" minOccurs="0" maxOccurs="unbounded"> + <xsd:annotation> + <xsd:appinfo source="http://annotation.elver.org/internal/EStructuralFeatureName">primaryKeyJoinColumns</xsd:appinfo> + </xsd:annotation> + </xsd:element> + <xsd:element name="sequence-generator" type="SequenceGenerator" minOccurs="0"/> + <xsd:element name="table-generator" type="TableGenerator" minOccurs="0"/> + <xsd:element name="unique" type="xsd:boolean" minOccurs="0"/> + </xsd:choice> + <xsd:attribute name="name" type="xsd:token" use="required"/> + </xsd:complexType> + <xsd:complexType name="Property"> + <xsd:choice minOccurs="0" maxOccurs="unbounded"> + <xsd:element name="attribute-override" type="AttributeOverride" minOccurs="0" maxOccurs="unbounded"> + <xsd:annotation> + <xsd:appinfo source="http://annotation.elver.org/internal/EStructuralFeatureName">attributeOverrides</xsd:appinfo> + </xsd:annotation> + </xsd:element> + <xsd:element name="basic" type="Basic" minOccurs="0"/> + <xsd:element name="column" type="Column" minOccurs="0"/> + <xsd:element name="embedded" type="Embedded" minOccurs="0"/> + <xsd:element name="embedded-id" type="EmbeddedId" minOccurs="0"/> + <xsd:element name="enumerated" type="EnumType" minOccurs="0"/> + <xsd:element name="generated-value" type="GeneratedValue" minOccurs="0"/> + <xsd:element name="id" type="Id" minOccurs="0"/> + <xsd:element name="indexed" type="xsd:boolean" minOccurs="0"/> + <xsd:element name="join-column" type="JoinColumn" minOccurs="0" maxOccurs="unbounded"> + <xsd:annotation> + <xsd:appinfo source="http://annotation.elver.org/internal/EStructuralFeatureName">joinColumns</xsd:appinfo> + </xsd:annotation> + </xsd:element> + <xsd:element name="join-table" type="JoinTable" minOccurs="0"/> + <xsd:element name="lob" type="Lob" minOccurs="0"/> + <xsd:element name="many-to-many" type="ManyToMany" minOccurs="0"/> + <xsd:element name="many-to-one" type="ManyToOne" minOccurs="0"/> + <xsd:element name="one-to-many" type="OneToMany" minOccurs="0"/> + <xsd:element name="one-to-one" type="OneToOne" minOccurs="0"/> + <xsd:element name="order-by" type="xsd:string" minOccurs="0"/> + <xsd:element name="primary-key-join-column" type="PrimaryKeyJoinColumn" minOccurs="0" maxOccurs="unbounded"> + <xsd:annotation> + <xsd:appinfo source="http://annotation.elver.org/internal/EStructuralFeatureName">primaryKeyJoinColumns</xsd:appinfo> + </xsd:annotation> + </xsd:element> + <xsd:element name="sequence-generator" type="SequenceGenerator" minOccurs="0"/> + <xsd:element name="table-generator" type="TableGenerator" minOccurs="0"/> + <xsd:element name="temporal" type="TemporalType" minOccurs="0"/> + <xsd:element name="unique" type="xsd:boolean" minOccurs="0"/> + <xsd:element name="version" type="Version" minOccurs="0"/> + </xsd:choice> + <xsd:attribute name="name" type="xsd:token" use="required"/> + </xsd:complexType> + <xsd:complexType name="AssociationOverride"> + <xsd:choice minOccurs="0" maxOccurs="unbounded"> + <xsd:element name="join-column" type="JoinColumn" minOccurs="1" maxOccurs="unbounded"> + <xsd:annotation> + <xsd:appinfo source="http://annotation.elver.org/internal/EStructuralFeatureName">joinColumns</xsd:appinfo> + </xsd:annotation> + </xsd:element> + </xsd:choice> + <xsd:attribute name="name" type="xsd:string" use="required"/> + </xsd:complexType> + <xsd:complexType name="AttributeOverride"> + <xsd:choice minOccurs="0" maxOccurs="unbounded"> + <xsd:element name="column" type="Column" minOccurs="1"/> + </xsd:choice> + <xsd:attribute name="name" type="xsd:string" use="required"/> + </xsd:complexType> + <xsd:complexType name="Basic"> + <xsd:choice minOccurs="0" maxOccurs="unbounded"/> + <xsd:attribute name="fetch" type="FetchType" use="optional"/> + <xsd:attribute name="optional" type="xsd:boolean" use="optional"/> + </xsd:complexType> + <xsd:complexType name="Column"> + <xsd:choice minOccurs="0" maxOccurs="unbounded"/> + <xsd:attribute name="column-definition" type="xsd:string" use="optional"/> + <xsd:attribute name="insertable" type="xsd:boolean" use="optional"/> + <xsd:attribute name="length" type="xsd:int" use="optional"/> + <xsd:attribute name="name" type="xsd:string" use="optional"/> + <xsd:attribute name="nullable" type="xsd:boolean" use="optional"/> + <xsd:attribute name="precision" type="xsd:int" use="optional"/> + <xsd:attribute name="scale" type="xsd:int" use="optional"/> + <xsd:attribute name="table" type="xsd:string" use="optional"/> + <xsd:attribute name="unique" type="xsd:boolean" use="optional"/> + <xsd:attribute name="updatable" type="xsd:boolean" use="optional"/> + </xsd:complexType> + <xsd:complexType name="DiscriminatorColumn"> + <xsd:choice minOccurs="0" maxOccurs="unbounded"/> + <xsd:attribute name="column-definition" type="xsd:string" use="optional"/> + <xsd:attribute name="discriminator-type" type="DiscriminatorType" use="optional"/> + <xsd:attribute name="length" type="xsd:int" use="optional"/> + <xsd:attribute name="name" type="xsd:string" use="optional"/> + </xsd:complexType> + <xsd:complexType name="Embeddable"/> + <xsd:complexType name="Embedded"/> + <xsd:complexType name="EmbeddedId"/> + <xsd:complexType name="GeneratedValue"> + <xsd:choice minOccurs="0" maxOccurs="unbounded"/> + <xsd:attribute name="generator" type="xsd:string" use="optional"/> + <xsd:attribute name="strategy" type="GenerationType" use="optional"/> + </xsd:complexType> + <xsd:complexType name="Id"/> + <xsd:complexType name="JoinColumn"> + <xsd:choice minOccurs="0" maxOccurs="unbounded"/> + <xsd:attribute name="column-definition" type="xsd:string" use="optional"/> + <xsd:attribute name="insertable" type="xsd:boolean" use="optional"/> + <xsd:attribute name="name" type="xsd:string" use="optional"/> + <xsd:attribute name="nullable" type="xsd:boolean" use="optional"/> + <xsd:attribute name="referenced-column-name" type="xsd:string" use="optional"/> + <xsd:attribute name="table" type="xsd:string" use="optional"/> + <xsd:attribute name="unique" type="xsd:boolean" use="optional"/> + <xsd:attribute name="updatable" type="xsd:boolean" use="optional"/> + </xsd:complexType> + <xsd:complexType name="JoinTable"> + <xsd:choice minOccurs="0" maxOccurs="unbounded"> + <xsd:element name="inverse-join-column" type="JoinColumn" minOccurs="0" maxOccurs="unbounded"> + <xsd:annotation> + <xsd:appinfo source="http://annotation.elver.org/internal/EStructuralFeatureName">inverseJoinColumns</xsd:appinfo> + </xsd:annotation> + </xsd:element> + <xsd:element name="join-column" type="JoinColumn" minOccurs="0" maxOccurs="unbounded"> + <xsd:annotation> + <xsd:appinfo source="http://annotation.elver.org/internal/EStructuralFeatureName">joinColumns</xsd:appinfo> + </xsd:annotation> + </xsd:element> + <xsd:element name="unique-constraint" type="xsd:string" minOccurs="0" maxOccurs="unbounded"> + <xsd:annotation> + <xsd:appinfo source="http://annotation.elver.org/internal/EStructuralFeatureName">uniqueConstraints</xsd:appinfo> + </xsd:annotation> + </xsd:element> + </xsd:choice> + <xsd:attribute name="catalog" type="xsd:string" use="optional"/> + <xsd:attribute name="name" type="xsd:string" use="optional"/> + <xsd:attribute name="schema" type="xsd:string" use="optional"/> + </xsd:complexType> + <xsd:complexType name="Lob"/> + <xsd:complexType name="ManyToMany"> + <xsd:choice minOccurs="0" maxOccurs="unbounded"> + <xsd:element name="cascade" type="CascadeType" minOccurs="0" maxOccurs="unbounded"/> + </xsd:choice> + <xsd:attribute name="cascade" type="CascadeType" use="optional"/> + <xsd:attribute name="fetch" type="FetchType" use="optional"/> + <xsd:attribute name="mapped-by" type="xsd:string" use="optional"/> + <xsd:attribute name="target-entity" type="xsd:string" use="optional"/> + </xsd:complexType> + <xsd:complexType name="ManyToOne"> + <xsd:choice minOccurs="0" maxOccurs="unbounded"> + <xsd:element name="cascade" type="CascadeType" minOccurs="0" maxOccurs="unbounded"/> + </xsd:choice> + <xsd:attribute name="cascade" type="CascadeType" use="optional"/> + <xsd:attribute name="fetch" type="FetchType" use="optional"/> + <xsd:attribute name="optional" type="xsd:boolean" use="optional"/> + <xsd:attribute name="target-entity" type="xsd:string" use="optional"/> + </xsd:complexType> + <xsd:complexType name="MappedSuperclass"/> + <xsd:complexType name="OneToMany"> + <xsd:choice minOccurs="0" maxOccurs="unbounded"> + <xsd:element name="cascade" type="CascadeType" minOccurs="0" maxOccurs="unbounded"/> + </xsd:choice> + <xsd:attribute name="cascade" type="CascadeType" use="optional"/> + <xsd:attribute name="fetch" type="FetchType" use="optional"/> + <xsd:attribute name="mapped-by" type="xsd:string" use="optional"/> + <xsd:attribute name="target-entity" type="xsd:string" use="optional"/> + </xsd:complexType> + <xsd:complexType name="OneToOne"> + <xsd:choice minOccurs="0" maxOccurs="unbounded"> + <xsd:element name="cascade" type="CascadeType" minOccurs="0" maxOccurs="unbounded"/> + </xsd:choice> + <xsd:attribute name="cascade" type="CascadeType" use="optional"/> + <xsd:attribute name="fetch" type="FetchType" use="optional"/> + <xsd:attribute name="mapped-by" type="xsd:string" use="optional"/> + <xsd:attribute name="optional" type="xsd:boolean" use="optional"/> + <xsd:attribute name="target-entity" type="xsd:string" use="optional"/> + </xsd:complexType> + <xsd:complexType name="PrimaryKeyJoinColumn"> + <xsd:choice minOccurs="0" maxOccurs="unbounded"/> + <xsd:attribute name="column-definition" type="xsd:string" use="optional"/> + <xsd:attribute name="name" type="xsd:string" use="optional"/> + <xsd:attribute name="referenced-column-name" type="xsd:string" use="optional"/> + </xsd:complexType> + <xsd:complexType name="SecondaryTable"> + <xsd:choice minOccurs="0" maxOccurs="unbounded"> + <xsd:element name="pk-join-column" type="PrimaryKeyJoinColumn" minOccurs="0" maxOccurs="unbounded"> + <xsd:annotation> + <xsd:appinfo source="http://annotation.elver.org/internal/EStructuralFeatureName">pkJoinColumns</xsd:appinfo> + </xsd:annotation> + </xsd:element> + <xsd:element name="unique-constraint" type="xsd:string" minOccurs="0" maxOccurs="unbounded"> + <xsd:annotation> + <xsd:appinfo source="http://annotation.elver.org/internal/EStructuralFeatureName">uniqueConstraints</xsd:appinfo> + </xsd:annotation> + </xsd:element> + </xsd:choice> + <xsd:attribute name="catalog" type="xsd:string" use="optional"/> + <xsd:attribute name="name" type="xsd:string" use="required"/> + <xsd:attribute name="schema" type="xsd:string" use="optional"/> + </xsd:complexType> + <xsd:complexType name="SequenceGenerator"> + <xsd:choice minOccurs="0" maxOccurs="unbounded"/> + <xsd:attribute name="allocation-size" type="xsd:int" use="optional"/> + <xsd:attribute name="initial-value" type="xsd:int" use="optional"/> + <xsd:attribute name="name" type="xsd:string" use="required"/> + <xsd:attribute name="sequence-name" type="xsd:string" use="optional"/> + </xsd:complexType> + <xsd:complexType name="Table"> + <xsd:choice minOccurs="0" maxOccurs="unbounded"> + <xsd:element name="unique-constraint" type="xsd:string" minOccurs="0" maxOccurs="unbounded"> + <xsd:annotation> + <xsd:appinfo source="http://annotation.elver.org/internal/EStructuralFeatureName">uniqueConstraints</xsd:appinfo> + </xsd:annotation> + </xsd:element> + </xsd:choice> + <xsd:attribute name="catalog" type="xsd:string" use="optional"/> + <xsd:attribute name="name" type="xsd:string" use="optional"/> + <xsd:attribute name="schema" type="xsd:string" use="optional"/> + </xsd:complexType> + <xsd:complexType name="TableGenerator"> + <xsd:choice minOccurs="0" maxOccurs="unbounded"> + <xsd:element name="unique-constraint" type="xsd:string" minOccurs="0" maxOccurs="unbounded"> + <xsd:annotation> + <xsd:appinfo source="http://annotation.elver.org/internal/EStructuralFeatureName">uniqueConstraints</xsd:appinfo> + </xsd:annotation> + </xsd:element> + </xsd:choice> + <xsd:attribute name="allocation-size" type="xsd:int" use="optional"/> + <xsd:attribute name="catalog" type="xsd:string" use="optional"/> + <xsd:attribute name="initial-value" type="xsd:int" use="optional"/> + <xsd:attribute name="name" type="xsd:string" use="required"/> + <xsd:attribute name="pk-column-name" type="xsd:string" use="optional"/> + <xsd:attribute name="pk-column-value" type="xsd:string" use="optional"/> + <xsd:attribute name="schema" type="xsd:string" use="optional"/> + <xsd:attribute name="table" type="xsd:string" use="optional"/> + <xsd:attribute name="value-column-name" type="xsd:string" use="optional"/> + </xsd:complexType> + <xsd:complexType name="Transient"/> + <xsd:complexType name="Version"/> + <xsd:simpleType name="CascadeType"> + <xsd:restriction base="xsd:token"> + <xsd:enumeration value="ALL"/> + <xsd:enumeration value="PERSIST"/> + <xsd:enumeration value="MERGE"/> + <xsd:enumeration value="REMOVE"/> + <xsd:enumeration value="REFRESH"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="DiscriminatorType"> + <xsd:restriction base="xsd:token"> + <xsd:enumeration value="STRING"/> + <xsd:enumeration value="CHAR"/> + <xsd:enumeration value="INTEGER"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="EnumType"> + <xsd:restriction base="xsd:token"> + <xsd:enumeration value="ORDINAL"/> + <xsd:enumeration value="STRING"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="FetchType"> + <xsd:restriction base="xsd:token"> + <xsd:enumeration value="LAZY"/> + <xsd:enumeration value="EAGER"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="GenerationType"> + <xsd:restriction base="xsd:token"> + <xsd:enumeration value="TABLE"/> + <xsd:enumeration value="SEQUENCE"/> + <xsd:enumeration value="IDENTITY"/> + <xsd:enumeration value="AUTO"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="InheritanceType"> + <xsd:restriction base="xsd:token"> + <xsd:enumeration value="SINGLE_TABLE"/> + <xsd:enumeration value="TABLE_PER_CLASS"/> + <xsd:enumeration value="JOINED"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="TemporalType"> + <xsd:restriction base="xsd:token"> + <xsd:enumeration value="DATE"/> + <xsd:enumeration value="TIME"/> + <xsd:enumeration value="TIMESTAMP"/> + </xsd:restriction> + </xsd:simpleType> +</xsd:schema> |