Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/annotations')
-rwxr-xr-xcore/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/annotations/StoreAnnotationsException.java39
-rwxr-xr-xcore/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/annotations/mapper/AbstractAnnotator.java170
-rwxr-xr-xcore/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/annotations/mapper/AbstractProcessingContext.java364
-rwxr-xr-xcore/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/annotations/mapper/AnnotationGenerator.java180
-rwxr-xr-xcore/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/annotations/mapper/BaseEFeatureAnnotator.java336
-rwxr-xr-xcore/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/annotations/mapper/BasicPamodelBuilder.java363
-rwxr-xr-xcore/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/annotations/mapper/BidirectionalManyToManyAnnotator.java133
-rwxr-xr-xcore/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/annotations/mapper/EClassAnnotator.java414
-rwxr-xr-xcore/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/annotations/mapper/EDataTypeAnnotator.java39
-rwxr-xr-xcore/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/annotations/mapper/EFeatureAnnotator.java272
-rwxr-xr-xcore/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/annotations/mapper/ManyToOneReferenceAnnotator.java155
-rwxr-xr-xcore/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/annotations/mapper/OneToManyAttributeAnnotator.java153
-rwxr-xr-xcore/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/annotations/mapper/OneToManyReferenceAnnotator.java348
-rwxr-xr-xcore/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/annotations/mapper/OneToOneReferenceAnnotator.java123
-rw-r--r--core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/annotations/mapper/PersistenceFileProvider.java50
-rwxr-xr-xcore/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/annotations/mapper/PersistenceMappingBuilder.java296
-rwxr-xr-xcore/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/annotations/mapper/SingleAttributeAnnotator.java153
-rwxr-xr-xcore/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/annotations/mapper/StoreMappingException.java51
-rwxr-xr-xcore/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/annotations/mapper/UnidirectionalManyToManyAnnotator.java91
-rwxr-xr-xcore/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/annotations/parser/AnnotationParser.java264
-rwxr-xr-xcore/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/annotations/parser/AnnotationParserException.java40
-rwxr-xr-xcore/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/annotations/parser/AnnotationTokenizer.java357
-rwxr-xr-xcore/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/annotations/parser/ArrayValueNode.java65
-rwxr-xr-xcore/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/annotations/parser/ComplexNode.java178
-rwxr-xr-xcore/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/annotations/parser/EAnnotationParserImporter.java244
-rwxr-xr-xcore/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/annotations/parser/EClassResolver.java34
-rwxr-xr-xcore/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/annotations/parser/NamedParserNode.java46
-rwxr-xr-xcore/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/annotations/parser/ParserUtil.java66
-rwxr-xr-xcore/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/annotations/parser/PrimitiveValueNode.java58
-rwxr-xr-xcore/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/annotations/parser/ReferenceValueNode.java58
-rwxr-xr-xcore/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/annotations/xml/ParseXMLAnnotationsException.java55
-rwxr-xr-xcore/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/annotations/xml/PersistenceMappingSchemaGenerator.java592
-rwxr-xr-xcore/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/annotations/xml/XmlElementToEStructuralFeatureMapper.java83
-rwxr-xr-xcore/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/annotations/xml/XmlPersistenceContentHandler.java530
-rwxr-xr-xcore/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/annotations/xml/XmlPersistenceMapper.java144
-rwxr-xr-xcore/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/annotations/xml/persistence-mapping.xsd433
-rwxr-xr-xcore/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/annotations/xml/persistence-mapping_previous.xsd399
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("&gt;", ">");
+ value = value.replaceAll("&lt;", "<");
+
+ // 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. (&lt;xsd:element&gt;)
+ */
+ 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. (&lt;xsd:complexType&gt;)
+ */
+ 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. (&lt;xsd:attribute&gt;)
+ */
+ 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. (&lt;xsd:complexType&gt;)
+ */
+ 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>

Back to the top