Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo')
-rwxr-xr-xcore/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/Constants.java94
-rwxr-xr-xcore/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/DataStore.java49
-rwxr-xr-xcore/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/EContainerRepairControl.java379
-rwxr-xr-xcore/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/ERuntime.java425
-rw-r--r--core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/PackageRegistryProvider.java65
-rwxr-xr-xcore/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/PersistenceOptions.java1253
-rwxr-xr-xcore/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/StoreValidationException.java62
-rwxr-xr-xcore/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/TeneoException.java54
-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
-rwxr-xr-xcore/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/classloader/ClassClassLoaderStrategy.java87
-rwxr-xr-xcore/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/classloader/ClassLoaderResolver.java76
-rwxr-xr-xcore/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/classloader/ClassLoaderStrategy.java32
-rwxr-xr-xcore/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/classloader/ContextClassLoaderStrategy.java35
-rwxr-xr-xcore/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/classloader/StoreClassLoadException.java49
-rwxr-xr-xcore/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/ecore/EModelResolver.java107
-rwxr-xr-xcore/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/extension/DatastoreAware.java32
-rwxr-xr-xcore/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/extension/DefaultExtensionManager.java286
-rwxr-xr-xcore/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/extension/Extension.java109
-rwxr-xr-xcore/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/extension/ExtensionInitializable.java31
-rwxr-xr-xcore/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/extension/ExtensionManager.java60
-rwxr-xr-xcore/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/extension/ExtensionManagerAware.java31
-rwxr-xr-xcore/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/extension/ExtensionManagerFactory.java48
-rwxr-xr-xcore/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/extension/ExtensionPoint.java30
-rwxr-xr-xcore/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/extension/ExtensionUtil.java302
-rwxr-xr-xcore/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/extension/PaModelAware.java33
-rwxr-xr-xcore/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/extension/PersistenceOptionsAware.java33
-rwxr-xr-xcore/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/extension/TeneoExtensionException.java48
-rwxr-xr-xcore/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/mapping/elist/MapPersistableEMap.java254
-rwxr-xr-xcore/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/mapping/elist/PersistableDelegateList.java40
-rwxr-xr-xcore/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/mapping/elist/PersistableEList.java621
-rwxr-xr-xcore/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/mapping/elist/PersistableEMap.java617
-rwxr-xr-xcore/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/mapping/elist/PersistableFeatureMap.java539
-rwxr-xr-xcore/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/mapping/strategy/EntityNameStrategy.java64
-rwxr-xr-xcore/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/mapping/strategy/SQLNameStrategy.java135
-rwxr-xr-xcore/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/mapping/strategy/StrategyUtil.java124
-rwxr-xr-xcore/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/mapping/strategy/impl/ClassicEntityNameStrategy.java164
-rwxr-xr-xcore/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/mapping/strategy/impl/ClassicSQLNameStrategy.java611
-rwxr-xr-xcore/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/mapping/strategy/impl/EntityInterfaceNameStrategy.java212
-rwxr-xr-xcore/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/mapping/strategy/impl/EntityResolvingNameStrategy.java222
-rwxr-xr-xcore/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/mapping/strategy/impl/QualifyingEntityNameStrategy.java136
-rw-r--r--core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/mapping/strategy/impl/TeneoNewSQLNameStrategy.java36
-rwxr-xr-xcore/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/mapping/strategy/impl/TeneoSQLNameStrategy.java204
-rwxr-xr-xcore/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/resource/NonLoadingDiagnostician.java56
-rwxr-xr-xcore/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/resource/NonLoadingEContentsEList.java85
-rwxr-xr-xcore/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/resource/StoreResource.java1115
-rwxr-xr-xcore/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/resource/StoreResourceException.java42
-rwxr-xr-xcore/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/simpledom/Attribute.java43
-rwxr-xr-xcore/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/simpledom/Document.java64
-rwxr-xr-xcore/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/simpledom/DocumentHelper.java35
-rwxr-xr-xcore/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/simpledom/Element.java230
-rwxr-xr-xcore/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/simpledom/Node.java64
-rwxr-xr-xcore/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/type/FeatureMapEntry.java467
-rwxr-xr-xcore/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/type/MixedFeatureMapEntry.java80
-rw-r--r--core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/type/PersistentStoreAdapter.java280
-rwxr-xr-xcore/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/util/AssertUtil.java100
-rwxr-xr-xcore/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/util/EcoreDataTypes.java435
-rwxr-xr-xcore/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/util/FieldUtil.java174
-rwxr-xr-xcore/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/util/StoreUtil.java665
94 files changed, 19100 insertions, 0 deletions
diff --git a/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/Constants.java b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/Constants.java
new file mode 100755
index 000000000..1a35d75dd
--- /dev/null
+++ b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/Constants.java
@@ -0,0 +1,94 @@
+/**
+ * <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: Constants.java,v 1.13 2009/11/10 10:06:04 mtaal Exp $
+ */
+
+package org.eclipse.emf.teneo;
+
+import org.eclipse.emf.common.notify.Notification;
+import org.eclipse.emf.ecore.EStructuralFeature;
+import org.eclipse.emf.ecore.xml.type.XMLTypePackage;
+
+/**
+ * AnnotationUtil used when reading a property file is also used by resources.
+ *
+ * @author <a href="mailto:mtaal@elver.org">Martin Taal</a>
+ * @version $Revision: 1.13 $
+ */
+
+public class Constants {
+ /** StructuralFeatures for TEXT content (part of a mixed complex type) */
+ public static final EStructuralFeature TEXT = XMLTypePackage.eINSTANCE.getXMLTypeDocumentRoot_Text();
+
+ /** StructuralFeatures for CDATA content (part of a mixed complex type) */
+ public static final EStructuralFeature CDATA = XMLTypePackage.eINSTANCE.getXMLTypeDocumentRoot_CDATA();
+
+ /** StructuralFeatures for COMMENT content (part of a mixed complex type) */
+ public static final EStructuralFeature COMMENT = XMLTypePackage.eINSTANCE.getXMLTypeDocumentRoot_Comment();
+
+ /**
+ * The name under which this connection (PersistenceManagerFactory) is registered
+ */
+ public static final String PROP_NAME = "name";
+
+ /** The extension used to find the default editor */
+ public static final String PROP_EDITOR_EXTENSTION = "editorextension";
+
+ /** The id used to find the default editor */
+ public static final String PROP_EDITOR_ID = "editorid";
+
+ /**
+ * The NS URI of the epackage handled by this database (can be more than one, then should be a comma delimited list)
+ */
+ public static final String PROP_EPACKAGE_NSURI = "nsuri";
+
+ /** The epackage property */
+ public static final String PROP_EPACKAGE = "epackage";
+
+ /** The database name property */
+ public static final String PROP_DB_NAME = "dbname";
+
+ /** The database user property */
+ public static final String PROP_DB_USER = "dbuser";
+
+ /** The database password property */
+ public static final String PROP_DB_PWD = "dbpassword";
+
+ /** The database driver property */
+ public static final String PROP_DB_DRIVER = "dbdriver";
+
+ /** The database url property */
+ public static final String PROP_DB_URL = "dburl";
+
+ /** The database dialect property */
+ public static final String PROP_DB_DIALECT = "dbdialect";
+
+ /** Denotes the start range from which Elver notifications are derived */
+ public static final int NOTIFICATION_START_EVENT_TYPE_COUNT = Notification.EVENT_TYPE_COUNT + 1000;
+
+ /** Nofitication Used by elver to notify an elist load */
+ public static final int ELIST_LOAD_NOTIFICATION = NOTIFICATION_START_EVENT_TYPE_COUNT + 1;
+
+ public static final String EAV_EOBJECT_ENTITY_NAME = "EAV_EObject";
+
+ public static final String EAV_EOBJECT_VALUES = "values";
+
+ public final static String COLUMN_ECONTAINER_CLASS = "econtainer_class";
+ public final static String COLUMN_ECONTAINER = "e_container";
+ public final static String COLUMN_ECONTAINER_FEATURE_NAME = "e_container_feature_name";
+
+ public final static String ANNOTATION_SOURCE_TENEO_JPA = "teneo.jpa";
+ public final static String ANNOTATION_SOURCE_TENEO_MAPPING = "teneo.mapping";
+}
diff --git a/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/DataStore.java b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/DataStore.java
new file mode 100755
index 000000000..38026098d
--- /dev/null
+++ b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/DataStore.java
@@ -0,0 +1,49 @@
+/**
+ * <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: DataStore.java,v 1.4 2010/11/11 10:28:03 mtaal Exp $
+ */
+
+package org.eclipse.emf.teneo;
+
+import java.util.Properties;
+
+import org.eclipse.emf.ecore.EPackage;
+import org.eclipse.emf.teneo.extension.ExtensionManager;
+
+/**
+ * Generic datastore interface used by hibernate and jpox.
+ *
+ * @author <a href="mailto:mtaal@elver.org">Martin Taal</a>
+ * @version $Revision: 1.4 $
+ */
+
+public interface DataStore {
+
+ /** @return the mapped epackages */
+ EPackage[] getEPackages();
+
+ /**
+ * Note: renamed from getProperties in a previous release.
+ *
+ * @return the properties, the combination of jpox and hibernate properties
+ */
+ Properties getDataStoreProperties();
+
+ /** Return the extension manager */
+ ExtensionManager getExtensionManager();
+
+ /** Return the name */
+ String getName();
+} \ No newline at end of file
diff --git a/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/EContainerRepairControl.java b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/EContainerRepairControl.java
new file mode 100755
index 000000000..4304fe844
--- /dev/null
+++ b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/EContainerRepairControl.java
@@ -0,0 +1,379 @@
+/**
+ * <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: EContainerRepairControl.java,v 1.12 2010/02/04 11:03:01 mtaal Exp $
+ */
+
+package org.eclipse.emf.teneo;
+
+import java.util.ArrayList;
+import java.util.Hashtable;
+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.EObject;
+import org.eclipse.emf.ecore.EReference;
+import org.eclipse.emf.ecore.EStructuralFeature;
+import org.eclipse.emf.ecore.InternalEObject;
+import org.eclipse.emf.ecore.resource.Resource;
+import org.eclipse.emf.teneo.mapping.elist.PersistableDelegateList;
+import org.eclipse.emf.teneo.mapping.elist.PersistableEList;
+import org.eclipse.emf.teneo.mapping.elist.PersistableFeatureMap;
+
+/**
+ * Supports the repair of the eContainer and resource setting of child objects when an object is
+ * loaded from the backing store.
+ *
+ * Repair of the eContainer is required in two distinct cases: 1) 1:1 relation: in this case the
+ * repair is implemented in the caching mechanism. This was the correct location because in jpox an
+ * object is added to the level 1 cache just after it is retrieved from the db and before it is
+ * passed on to the requesting application. 2) 1:n relation: in this case the EListWrapper knows
+ * that a containment relation is being loaded and calls the equivalent methods here.
+ *
+ * Note that both cases need to take into account two-way relatiofns. For two-way relations the
+ * featureid of the opposing ereferencing is used. For one-way relations emf apparently works with
+ * negative featureid's.
+ *
+ * This class also supports caching so that the system can quickly determine if for a certain class
+ * eContainers need to be set in child objects.
+ *
+ * @author <a href="mailto:mtaal@elver.org">Martin Taal</a>
+ * @version $Revision: 1.12 $
+ */
+
+public class EContainerRepairControl {
+ /** The logger */
+ private static Log log = LogFactory.getLog(EContainerRepairControl.class);
+
+ /** Hashmap of classes for which no repair is required */
+ private static final Hashtable<Class<?>, Class<?>> norepairRequired = new Hashtable<Class<?>, Class<?>>();
+
+ /** Hashmap of repair controls for a certain class */
+ private static final Hashtable<Class<?>, List<RepairControl>> repair =
+ new Hashtable<Class<?>, List<RepairControl>>();
+
+ /**
+ * Recursively sets the resource of the object and all its referenced objects, only if the
+ * object has a resource which is not set and does not have a container.
+ */
+ public static void setEResourceToAlLContent(InternalEObject start, Resource res) {
+ for (EStructuralFeature estruct : start.eClass().getEAllStructuralFeatures()) {
+ if (estruct instanceof EReference) {
+ final EReference eref = (EReference) estruct;
+ if (eref.isMany()) {
+ final EList<?> list = (EList<?>) start.eGet(eref);
+ if (list == null) {
+ continue;
+ }
+ if ((list instanceof PersistableEList<?>) && !((PersistableEList<?>) list).isLoaded()) {
+ continue;
+ }
+ if ((list instanceof PersistableFeatureMap) && !((PersistableFeatureMap) list).isLoaded()) {
+ continue;
+ }
+ for (int i = 0; i < list.size(); i++) {
+ final InternalEObject child = (InternalEObject) list.get(i);
+ if (child.eResource() == null) // no container
+ {
+ setResource(child, new ArrayList<EObject>(), (Resource.Internal) res);
+ }
+ }
+ } else {
+ final InternalEObject child = (InternalEObject) start.eGet(eref);
+ if (child != null && child.eResource() == null) {
+ setResource(child, new ArrayList<EObject>(), (Resource.Internal) res);
+ }
+ }
+ }
+ }
+ }
+
+ /** Sets the resource on an object or if it has a container on its container */
+ private static void setResource(InternalEObject eobj, ArrayList<EObject> objs, Resource.Internal res) {
+ // been here go away
+ if (objs.contains(eobj)) {
+ return;
+ }
+
+ // set the resource here or at the container
+ if (eobj.eResource() == null) {
+ if (eobj.eContainer() == null) {
+ eobj.eSetResource(res, null);
+ } else {
+ objs.add(eobj);
+ setResource((InternalEObject) eobj.eContainer(), objs, res);
+ }
+ }
+ }
+
+ /** Method to repair the eContainer of the child object of this object */
+ public static void repair(Object owner) {
+ if (log.isDebugEnabled()) {
+ log.debug("Repairing container relations of children of: " + owner.getClass().getName());
+ }
+
+ if (!(owner instanceof InternalEObject)) {
+ return;
+ }
+
+ if (norepairRequired.get(owner.getClass()) != null) {
+ return;
+ }
+
+ List<RepairControl> repairList = repair.get(owner.getClass());
+
+ if (repairList == null) {
+ repairList = buildRepairList((InternalEObject) owner);
+ }
+
+ if (log.isDebugEnabled() && repairList.size() > 0) {
+ log.debug("Repairing container relations of children of: " + owner.getClass().getName());
+ }
+
+ for (int i = 0; i < repairList.size(); i++) {
+ RepairControl repairControl = repairList.get(i);
+ if (log.isDebugEnabled()) {
+ log.debug("Repairing reference " + repairControl.container.getName() + " to child " +
+ repairControl.childClass.getName());
+ }
+
+ repairControl.repair((InternalEObject) owner);
+ }
+ }
+
+ /**
+ * Convenience method to just set the container directly for an object, this method does not
+ * cascade down. The featureid is the id of the feature of the owner which contains the child.
+ * The feature id is corrected in the method.
+ */
+ public static void setContainer(InternalEObject owner, InternalEObject child, EStructuralFeature estruct) {
+ if (child.eContainer() == owner) {
+ return;
+ }
+
+ final int featureID;
+ if (estruct instanceof EReference && ((EReference) estruct).getEOpposite() != null) {
+ featureID = child.eClass().getFeatureID(((EReference) estruct).getEOpposite());
+ } else {
+
+ featureID = InternalEObject.EOPPOSITE_FEATURE_BASE - owner.eClass().getFeatureID(estruct);
+ }
+ child.eBasicSetContainer(owner, featureID, null);
+ }
+
+ /**
+ * Method to repair the eContainer of the child object of this object. Note the featureid is
+ * internally translated to an econtainer id, nl. subtract from EOPPOSITE_FEATURE_BASE
+ */
+ public static void repair(Object owner, Object child, EStructuralFeature estruct) {
+
+ if (!(owner instanceof InternalEObject)) {
+ return;
+ }
+ if (!(child instanceof InternalEObject)) {
+ return;
+ }
+
+ final int correctedFeatureID;
+ if (estruct instanceof EReference && ((EReference) estruct).getEOpposite() != null) {
+ correctedFeatureID = ((InternalEObject) child).eClass().getFeatureID(((EReference) estruct).getEOpposite());
+ } else {
+ correctedFeatureID =
+ InternalEObject.EOPPOSITE_FEATURE_BASE - ((InternalEObject) owner).eClass().getFeatureID(estruct);
+ }
+
+ if (norepairRequired.get(owner.getClass()) != null) {
+ return;
+ }
+
+ List<RepairControl> repairList = repair.get(owner.getClass());
+
+ if (repairList == null) {
+ repairList = buildRepairList((InternalEObject) owner);
+ }
+
+ if (log.isDebugEnabled() && repairList.size() > 0) {
+ log.debug("Repairing container relations of children of: " + owner.getClass().getName());
+ }
+
+ for (int i = 0; i < repairList.size(); i++) {
+ RepairControl repairControl = repairList.get(i);
+ if (repairControl.getFeatureID() == correctedFeatureID &&
+ ((Class<?>) repairControl.childClass).isAssignableFrom(child.getClass())) {
+ repairControl.repair((InternalEObject) owner, (InternalEObject) child);
+ return;
+ }
+ }
+ }
+
+ /** Builds a repair control list for an object */
+ private static List<RepairControl> buildRepairList(InternalEObject owner) {
+ final ArrayList<RepairControl> result = new ArrayList<RepairControl>();
+ for (EStructuralFeature estruct : owner.eClass().getEAllStructuralFeatures()) {
+ if (estruct instanceof EReference) {
+ final EReference eref = (EReference) estruct;
+ if (eref.isContainment()) {
+ // now check if we are two or not
+ if (eref.getEOpposite() != null) {
+ result.add(new TwoWayContainer(eref, eref.getEOpposite()));
+ } else {
+ result.add(new OneWayContainer(eref));
+ }
+ }
+ }
+ }
+
+ if (result.size() == 0) {
+ norepairRequired.put(owner.getClass(), owner.getClass());
+ } else {
+ repair.put(owner.getClass(), result);
+ }
+ return result;
+ }
+
+ /** Abstract class for repairing containers */
+ private static abstract class RepairControl {
+ /** The ereference of the owner which contains the childs */
+ private final EReference container;
+
+ /** Some shortcuts for spead */
+ private final Class<?> childClass;
+
+ /** Featureid set as container */
+ private final int featureID;
+
+ /** Constructor */
+ RepairControl(EReference containerReference, int myFeatureID) {
+ container = containerReference;
+ childClass = container.getEType().getInstanceClass();
+ featureID = myFeatureID;
+ }
+
+ /** Returns the feature id of this containment relation */
+ public int getFeatureID() {
+ return featureID;
+ }
+
+ /** Repairs all containers of the owner */
+ void repair(InternalEObject owner) {
+ // The container repair of a list is done through the repair(owner,
+ // child) method,
+ // directly in the elist.doLoadFromStore method
+ if (container.isMany()) {
+ return;
+ }
+
+ final Object containedObject = owner.eGet(container);
+ if (containedObject == null) // not set
+ {
+ return;
+ }
+
+ // no list should be caught in the first line
+ assert (!(containedObject instanceof PersistableDelegateList<?>));
+
+ /*
+ * if (containedObject instanceof JPOXEList) { if
+ * (((JPOXEList)containedObject).getOwner() == owner) return;
+ *
+ * throw new StoreJPOXEmfException("Owner of containerobject is different from passed
+ * owner, " + "this should have been solved in the
+ * elist" + containedObject.getClass() + "/" + owner.getClass().getName() + "/" +
+ * container.getName()); }
+ */
+
+ if (!(containedObject instanceof InternalEObject)) {
+ return;
+ }
+
+ final InternalEObject containedEObject = (InternalEObject) containedObject;
+ if (containedEObject.eContainer() == owner) {
+ return; // already set?
+ }
+
+ if (log.isDebugEnabled()) {
+ log.debug("Set container of child " + containedObject.getClass().getName() + " containerfield " +
+ container.getName());
+ }
+
+ // and set it
+ containedEObject.eBasicSetContainer(owner, featureID, null);
+
+ // also repair the resource if applicable!
+ /*
+ * if (containedObject instanceof InternalEObject) { final InternalEObject eobj =
+ * (InternalEObject)containedObject; if (eobj.eResource() != owner.eResource()) {
+ * log.debug("Set resource of eobj " + eobj.getClass().getName() + " to resource " +
+ * owner.eResource().getURI()); eobj.eSetResource((Resource.Internal)owner.eResource(),
+ * null); } }
+ */
+
+ // and also do its children
+ EContainerRepairControl.repair(containedEObject);
+ }
+
+ /** Repairs all specific relation */
+ void repair(InternalEObject owner, InternalEObject child) {
+ if (!childClass.isAssignableFrom(child.getClass())) {
+ return; // not handled by this container
+ }
+
+ if (child.eContainer() == owner) {
+ return; // already set?
+ }
+
+ if (log.isDebugEnabled()) {
+ log.debug("Set container of child " + child.getClass().getName() + " containerfield " +
+ container.getName());
+ }
+
+ // and set it
+ child.eBasicSetContainer(owner, featureID, null);
+
+ // also repair the resource if applicable!
+ /*
+ * if (child instanceof InternalEObject) { final InternalEObject eobj =
+ * (InternalEObject)child; Object ores = owner.eResource(); Object eres =
+ * eobj.eResource(); if (eobj.eResource() != owner.eResource()) { log.debug("Set
+ * resource of eobj " + eobj.getClass().getName() + " to resource " +
+ * owner.eResource().getURI()); eobj.eSetResource((Resource.Internal)owner.eResource(),
+ * null); } }
+ */
+
+ EContainerRepairControl.repair(child);
+ }
+ }
+
+ /**
+ * Class handles a oneway container relation, in this case the eBasicSetContainer is used.
+ */
+ private static class OneWayContainer extends RepairControl {
+ /** Constructor */
+ OneWayContainer(EReference containerReference) {
+ super(containerReference, InternalEObject.EOPPOSITE_FEATURE_BASE - containerReference.getFeatureID());
+ }
+ }
+
+ /**
+ * Class handles a twoway container relation, in this case the eBasicSetContainer is used.
+ */
+ private static class TwoWayContainer extends RepairControl {
+ /** Constructor */
+ TwoWayContainer(EReference containerReference, EReference toContainer) {
+ super(containerReference, toContainer.getFeatureID());
+ }
+ }
+} \ No newline at end of file
diff --git a/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/ERuntime.java b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/ERuntime.java
new file mode 100755
index 000000000..8b4349a01
--- /dev/null
+++ b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/ERuntime.java
@@ -0,0 +1,425 @@
+/**
+ * <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: ERuntime.java,v 1.20 2010/02/04 11:03:02 mtaal Exp $
+ */
+
+package org.eclipse.emf.teneo;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+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.EClass;
+import org.eclipse.emf.ecore.EClassifier;
+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.impl.DynamicEObjectImpl;
+import org.eclipse.emf.ecore.util.EcoreUtil;
+import org.eclipse.emf.ecore.util.ExtendedMetaData;
+import org.eclipse.emf.teneo.classloader.ClassLoaderResolver;
+import org.eclipse.emf.teneo.classloader.StoreClassLoadException;
+import org.eclipse.emf.teneo.ecore.EModelResolver;
+import org.eclipse.emf.teneo.util.StoreUtil;
+
+/**
+ * The ERuntime contains references to EPackages which are persistable, i.e. are persisted.
+ *
+ * It is used to compute information related to concrete class - eclass mapping, interface to
+ * concrete class, references for cross reference computation, contained computations.
+ *
+ * @author <a href="mailto:mtaal@elver.org">Martin Taal</a>
+ * @version $Revision: 1.20 $
+ */
+
+public class ERuntime extends EModelResolver {
+
+ /** The logger */
+ private static Log log = LogFactory.getLog(ERuntime.class);
+
+ /** The singleton instance */
+ public static final ERuntime INSTANCE = new ERuntime();
+
+ /** The list of epackages processed here */
+ private final ArrayList<EPackage> epackages = new ArrayList<EPackage>();
+
+ /** The mapping from concrete classes to eclass and back */
+ private final HashMap<Class<?>, EClass> concreteToEClass = new HashMap<Class<?>, EClass>();
+
+ private final HashMap<Class<?>, EClass> interfaceToEClass = new HashMap<Class<?>, EClass>();
+
+ private final HashMap<EClassifier, Class<?>> eclassifierToConcrete = new HashMap<EClassifier, Class<?>>();
+
+ /** The list of topclasses/interfaces */
+ private final ArrayList<Class<?>> topClasses = new ArrayList<Class<?>>();
+
+ /** The list of contained classes/interfaces */
+ private final ArrayList<Class<?>> containedClasses = new ArrayList<Class<?>>();
+
+ /** Register the epackages */
+ @Override
+ public synchronized void register(EPackage[] epacks) {
+ for (int i = 0; i < epacks.length; i++) {
+
+ if (!epackages.contains(epacks[i])) {
+ epackages.add(epacks[i]);
+ }
+ }
+
+ computeConcreteInstanceMapping();
+ computeContainedClasses();
+ }
+
+ /** Resets the maps/lists */
+ @Override
+ public void clear() {
+ epackages.clear();
+ containedClasses.clear();
+ concreteToEClass.clear();
+ interfaceToEClass.clear();
+ eclassifierToConcrete.clear();
+ topClasses.clear();
+ }
+
+ /**
+ * Computes which classes are contained and which are non-contained. Method must be called after
+ * the computeReferers method!
+ */
+ private void computeContainedClasses() {
+
+ topClasses.clear();
+ containedClasses.clear();
+
+ for (int i = 0; i < epackages.size(); i++) {
+ final EPackage epack = epackages.get(i);
+ if (ignorePackage(epack)) {
+ continue;
+ }
+
+ for (EClassifier eclassifier : epack.getEClassifiers()) {
+ if (!(eclassifier instanceof EClass)) {
+ continue;
+ }
+
+ final EClass eclass = (EClass) eclassifier;
+
+ // bit ugly compare on name, but document root should be ignored
+ // otherwise everything is contained
+ if (ExtendedMetaData.INSTANCE.isDocumentRoot(eclass)) {
+ continue;
+ }
+
+ for (EReference eref : eclass.getEReferences()) {
+ if (!eref.isContainment()) {
+ continue;
+ }
+ final Class<?> toClass = eref.getEType().getInstanceClass();
+ if (!containedClasses.contains(toClass)) {
+ containedClasses.add(toClass);
+ }
+ }
+ }
+ }
+
+ // and then when it is not contained add it to the contained list
+ for (Class<?> clazz : interfaceToEClass.keySet()) {
+ if (containedClasses.contains(clazz)) {
+ continue; // already determined so continue
+ }
+
+ if (isSelfOrSuperContained(clazz, containedClasses)) {
+ containedClasses.add(clazz);
+ } else {
+ final EClass eClass = getEClass(clazz);
+ // remove all the abstract types
+ // see bugzilla 220106
+ if (eClass == null || !eClass.isAbstract()) {
+ topClasses.add(clazz);
+ }
+ }
+ }
+
+ // topclasses are cleaned because they are used to query and otherwise
+ // different queries would return overlapping results (because of
+ // polymor.)
+ cleanList(topClasses);
+ cleanList(containedClasses);
+ }
+
+ /**
+ * Walks through a interface inheritance structure and determines if a superclass is contained
+ * if so then the class is added to the containedclasses
+ */
+ private boolean isSelfOrSuperContained(Class<?> checkClass, ArrayList<Class<?>> containedClasses) {
+ // assert (checkClass.isInterface());
+ if (containedClasses.contains(checkClass)) {
+ return true;
+ }
+ final Class<?>[] interfaces = checkClass.getInterfaces();
+ for (Class<?> element : interfaces) {
+ if (isSelfOrSuperContained(element, containedClasses)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /** Returns the list of topclasses */
+ public Class<?>[] getTopClasses() {
+ return topClasses.toArray(new Class[topClasses.size()]);
+ }
+
+ /** Return the list of interfaces */
+ public Set<Class<?>> getAllInterfaces() {
+ return interfaceToEClass.keySet();
+ }
+
+ /** Returns all concrete classes */
+ public Set<Class<?>> getAllConcreteClasses() {
+ return concreteToEClass.keySet();
+ }
+
+ /**
+ * Retains only the root parent class in a list, so if an entry in the list as a parent in the
+ * same list then the child is deleted from the list
+ */
+ private void cleanList(ArrayList<Class<?>> list) {
+ final ArrayList<Class<?>> toRemove = new ArrayList<Class<?>>();
+ for (Class<?> clazz : list) {
+ if (clazz == null) {
+ continue;
+ }
+ final Class<?>[] supers = clazz.getInterfaces();
+ for (Class<?> element : supers) {
+ if (list.contains(element)) {
+ toRemove.add(clazz);
+ break;
+ }
+ }
+ }
+ list.removeAll(toRemove);
+ }
+
+ /** Determines concrete impl classes for each eclass */
+ private void computeConcreteInstanceMapping() {
+ concreteToEClass.clear();
+ eclassifierToConcrete.clear();
+ interfaceToEClass.clear();
+
+ // walk through all the epackages
+ for (int i = 0; i < epackages.size(); i++) {
+ final EPackage epack = epackages.get(i);
+
+ if (ignorePackage(epack)) {
+ log.debug("Not determining concrete classes for package " + epack.getName());
+ continue;
+ }
+
+ log.debug("Determining concrete classes for package " + epack.getName());
+
+ for (EClassifier eclassifier : epack.getEClassifiers()) {
+ if (!(eclassifier instanceof EClass)) {
+ continue;
+ }
+
+ final Object instance = create((EClass) eclassifier);
+ if (instance != null && !(instance instanceof DynamicEObjectImpl)) {
+ eclassifierToConcrete.put(eclassifier, instance.getClass());
+ concreteToEClass.put(instance.getClass(), (EClass) eclassifier);
+ }
+ if (eclassifier.getInstanceClass() != null) {
+ interfaceToEClass.put(eclassifier.getInstanceClass(), (EClass) eclassifier);
+ }
+ }
+ }
+
+ // packaged in an extra arraylist to prevent concurrent modification
+ // exception.
+ final List<Class<?>> classes = new ArrayList<Class<?>>(concreteToEClass.keySet());
+ for (Class<?> clz : classes) {
+ addAbstractSupers(clz);
+ }
+ }
+
+ /**
+ * Walks up the class hierarchy and adds the superclasses to the concrete-interface mapping
+ * class sets
+ */
+ private void addAbstractSupers(Class<?> clazz) {
+
+ // clazz is null or not an eobject
+ if (clazz == null || !EObject.class.isAssignableFrom(clazz)) {
+ return;
+ }
+
+ // if already been here then go on for the superclasses
+ if (concreteToEClass.get(clazz) != null) {
+ addAbstractSupers(clazz.getSuperclass());
+ return;
+ }
+
+ // new one, find all its interfaces
+ final Class<?>[] interf = clazz.getInterfaces();
+ for (Class<?> element : interf) {
+ if (EObject.class.isAssignableFrom(element)) {
+ final EClass eclass = interfaceToEClass.get(element);
+ concreteToEClass.put(clazz, eclass);
+ eclassifierToConcrete.put(eclass, clazz);
+ }
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.emf.teneo.jpox.emf.IEMFDataStore#getEPackages()
+ */
+ @Override
+ public EPackage[] getEPackages() {
+ return epackages.toArray(new EPackage[epackages.size()]);
+ }
+
+ /** Returns true if the epackage is registered here */
+ @Override
+ public boolean isRegistered(EPackage epackage) {
+ return epackages.contains(epackage);
+ }
+
+ /** Convenience method to easily determine which packages should be ignored */
+ private static boolean ignorePackage(EPackage epack) {
+ return false;
+// }
+// if (epack instanceof XMLTypePackageImpl) {
+// return true; // ignore this
+// }
+// if (epack instanceof EcorePackageImpl) {
+// return true; // ignore this
+// }
+// return false;
+ }
+
+ /** Returns the instanceclass for a passed interface */
+ public Class<?> getInstanceClass(Class<?> interf) {
+ final EClass eclass = interfaceToEClass.get(interf);
+ if (eclass == null) {
+ throw new TeneoException("No eclass for interf " + interf.getName());
+ }
+ return getJavaClass(eclass);
+ }
+
+ /** Returns the instanceclass for a passed eclass */
+ @Override
+ public Class<?> getJavaClass(EClassifier eclassifier) {
+ if (eclassifier instanceof EClass) {
+ final EClass eclass = (EClass) eclassifier;
+ if (eclass.isInterface()) {
+ return eclass.getInstanceClass();
+ }
+ }
+ return eclassifierToConcrete.get(eclassifier);
+ }
+
+ /** Returns the interface class for a passed eclass */
+ @Override
+ public Class<?> getJavaInterfaceClass(EClass eclass) {
+ return eclass.getInstanceClass();
+ }
+
+ /** Returns true if the passed EClass has a javaClass representation. */
+ @Override
+ public boolean hasImplementationClass(EClassifier eclassifier) {
+ return null != getJavaClass(eclassifier);
+ }
+
+ /** Returns null */
+ @Override
+ public Object create(EClass eclass) {
+ // abstract instance classes are added later
+ if (eclass.isAbstract() || eclass.isInterface()) {
+ return null;
+ }
+
+ // Check if the class is persistable
+ try {
+ return EcoreUtil.create(eclass);
+ } catch (Exception e) {
+ // log but do nothing because this happens when we try to create an
+ // object
+ // with an invalid classifier, which is a eclass!
+ log.debug("The classifier: " + eclass.getName() + " is not a valid eclass");
+
+ return null;
+ }
+ }
+
+ /** Get the eclass for a certain class */
+ @Override
+ public EClass getEClass(Class<?> clazz) {
+ if (clazz.isInterface()) {
+ return interfaceToEClass.get(clazz);
+ }
+ return concreteToEClass.get(clazz);
+ }
+
+ /** Get the eclass for a certain class name */
+ public EClass getEClass(String classname) {
+ try {
+ return getEClass(ClassLoaderResolver.classForName(classname));
+ } catch (StoreClassLoadException e) {
+ log.debug("Failed to retreive ECLass for name: " + classname);
+ return null;
+ }
+ }
+
+ /**
+ * Returns the structural feature for a certain field and object comby. Null is returned if
+ * nothing is found
+ */
+ public EStructuralFeature getStructuralFeature(Class<?> clazz, String FieldName) {
+ final EClass eclass = getEClass(clazz);
+ if (eclass == null) {
+ return null;
+ }
+ return StoreUtil.getEStructuralFeature(eclass, FieldName);
+ }
+
+ /**
+ * Returns the list of EMF interfaces which are contained. Only the topmost interface in a class
+ * hierarchy is returned. This can be used to automatically create the econtainer field
+ * mappings.
+ *
+ * Note that multiple classes in one inheritance structure can be present.
+ */
+ public Class<?>[] getContainedInterfaces() {
+ return containedClasses.toArray(new Class[containedClasses.size()]);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.emf.teneo.ecore.EModelResolver#getAllClassesAndInterfaces()
+ */
+ @Override
+ public List<Class<?>> getAllClassesAndInterfaces() {
+ final List<Class<?>> result = new ArrayList<Class<?>>();
+ result.addAll(getAllConcreteClasses());
+ result.addAll(getAllInterfaces());
+ return result;
+ }
+} \ No newline at end of file
diff --git a/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/PackageRegistryProvider.java b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/PackageRegistryProvider.java
new file mode 100644
index 000000000..cb54612fe
--- /dev/null
+++ b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/PackageRegistryProvider.java
@@ -0,0 +1,65 @@
+/**
+ * <copyright>
+ *
+ * Copyright (c) 2009 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: PackageRegistryProvider.java,v 1.2 2009/10/15 20:47:43 mtaal Exp $
+ */
+
+package org.eclipse.emf.teneo;
+
+import org.eclipse.emf.ecore.EPackage;
+
+/**
+ * Provides the package registry to the rest of Teneo. As a default the global Package.Registry is used. There are two
+ * ways to override the behavior in this class by setting a Package.Registry explicitly. Or by replacing the singleton
+ * instance with your own implementation.
+ *
+ * @author <a href="mailto:mtaal@elver.org">Martin Taal</a>
+ * @version $Revision: 1.2 $
+ */
+public class PackageRegistryProvider {
+
+ private static PackageRegistryProvider instance;
+
+ public static PackageRegistryProvider getInstance() {
+ if (instance == null) {
+ instance = new PackageRegistryProvider();
+ }
+ return instance;
+ }
+
+ public static void setInstance(PackageRegistryProvider instance) {
+ PackageRegistryProvider.instance = instance;
+ }
+
+ private EPackage.Registry packageRegistry = EPackage.Registry.INSTANCE;
+
+ // is used to handle the package registry defined in a datastore
+ private ThreadLocal<EPackage.Registry> threadRegistry = new ThreadLocal<EPackage.Registry>();
+
+ public EPackage.Registry getPackageRegistry() {
+ final EPackage.Registry theThreadRegistry = threadRegistry.get();
+ if (theThreadRegistry != null) {
+ return theThreadRegistry;
+ }
+ return packageRegistry;
+ }
+
+ public void setPackageRegistry(EPackage.Registry packageRegistry) {
+ this.packageRegistry = packageRegistry;
+ }
+
+ public void setThreadPackageRegistry(EPackage.Registry thePackageRegistry) {
+ threadRegistry.set(thePackageRegistry);
+ }
+
+} \ No newline at end of file
diff --git a/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/PersistenceOptions.java b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/PersistenceOptions.java
new file mode 100755
index 000000000..514799f02
--- /dev/null
+++ b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/PersistenceOptions.java
@@ -0,0 +1,1253 @@
+/**
+ * <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
+ * Jason Henriksen - Mapping File Path
+ * Jason Henriksen - XSDDate and XSDDateTime constants
+ * </copyright>
+ *
+ * $Id: PersistenceOptions.java,v 1.71 2011/10/29 06:12:48 mtaal Exp $
+ */
+
+package org.eclipse.emf.teneo;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Properties;
+import java.util.regex.Pattern;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.eclipse.emf.teneo.annotations.pannotation.CascadeType;
+import org.eclipse.emf.teneo.extension.ExtensionPoint;
+
+/**
+ * Defines the property names used in the persistence mapping.
+ * <p>
+ * As a convenience, this class offers type-safe property accessor wrappers.
+ *
+ * @author <a href="mailto:mtaal@elver.org">Martin Taal</a>
+ * @version $Revision: 1.71 $
+ */
+public class PersistenceOptions implements ExtensionPoint {
+
+ public static final String DEFAULT_CLASSPATH_FILENAME = "/teneo-persistence.properties";
+
+ public static final String RUNTIME_PREFIX = "teneo.runtime.";
+
+ public static final String MAPPING_PREFIX = "teneo.mapping.";
+
+ public static final String NAMING_PREFIX = "teneo.naming.";
+
+ /** The logger */
+ private static Log log = LogFactory.getLog(PersistenceOptions.class);
+
+ // START: ++++++++++++++++++++++ SQL Naming related Options
+ // ++++++++++++++++++++++++++++++++++++
+
+ /**
+ * DiscriminatorColumn name, default is DTYPE.
+ */
+ public static final String DISCRIMINATOR_COLUMN_NAME = NAMING_PREFIX
+ + "discriminator_column_name";
+
+ /**
+ * Join table naming strategy, two values: ejb3 and unique
+ *
+ * @Deprecated use the extensionManager concept
+ */
+ public static final String JOIN_TABLE_NAMING_STRATEGY = NAMING_PREFIX
+ + "join_table_naming_strategy";
+
+ /**
+ * Deprecated use JOIN_TABLE_NAMING_STRATEGY
+ *
+ * @Deprecated
+ */
+ public static final String JOIN_TABLE_NAMING_STRATEGY_OLD = MAPPING_PREFIX
+ + "join_table_naming_strategy";
+
+ /**
+ * Join column naming strategy, two values: unique and simple. unique is the
+ * default and results in guaranteed unique naming for the join columns
+ * simple will always try to use minimal name lengths and will most of the
+ * time just use the efeaturename.
+ */
+ public static final String JOIN_COLUMN_NAMING_STRATEGY = NAMING_PREFIX
+ + "join_column_naming_strategy";
+
+ /** The column name of the id column in the idbag, default is id */
+ public static final String IDBAG_ID_COLUMN_NAME = NAMING_PREFIX
+ + "idbag_id_column_name";
+
+ /** Name of version column, default value is e_version */
+ public static final String VERSION_COLUMN_NAME = NAMING_PREFIX
+ + "version_column";
+
+ /** Name of id column, default value is e_id */
+ public static final String ID_COLUMN_NAME = NAMING_PREFIX
+ + "default_id_column";
+
+ /**
+ * Truncate the column name if the length is larger than this property. In
+ * case of concatenating property names for foreign keys
+ */
+ public static final String MAXIMUM_SQL_NAME_LENGTH = NAMING_PREFIX
+ + "max_sql_name_length";
+
+ /**
+ * The option which determines the casing of columns and table names,
+ * lowercase will result in lowercase letters, uppercase in uppercase, none
+ * will just work as it did until now
+ */
+ public static final String SQL_CASE_STRATEGY = NAMING_PREFIX + "strategy";
+
+ /**
+ * If set then the system will generate readable foreign key names. The
+ * default is true. Set to false for backward compatibility. Note that
+ * before the default value of this property was false.
+ */
+ public static final String SET_FOREIGN_KEY_NAME = NAMING_PREFIX
+ + "set_foreign_key_name";
+
+ /**
+ * The escape character to use when escaping table and column names.
+ * Standard Hibernate uses the ` (backtick). This is the default value.
+ */
+ public static final String SQL_NAME_ESCAPE_CHARACTER = MAPPING_PREFIX
+ + "sql_name_escape_character";
+
+ /**
+ * The sql name strategy, if not set then the ClassicSQLNameStrategy is
+ * used.
+ *
+ * @Deprecated use the extensionManager concept
+ */
+ public static final String SQL_NAME_STRATEGY = NAMING_PREFIX
+ + "sql_name_strategy";
+
+ /**
+ * The Table name prefix, as a default set to "".
+ */
+ public static final String SQL_TABLE_NAME_PREFIX = NAMING_PREFIX
+ + "sql_table_name_prefix";
+
+ /**
+ * The Column name prefix, as a default set to "".
+ */
+ public static final String SQL_COLUMN_NAME_PREFIX = NAMING_PREFIX
+ + "sql_column_name_prefix";
+
+ /**
+ * The FK name prefix, as a default set to "".
+ */
+ public static final String SQL_FOREIGN_KEY_NAME_PREFIX = NAMING_PREFIX
+ + "sql_fk_name_prefix";
+
+ /**
+ * The Index name prefix, as a default set to "".
+ */
+ public static final String SQL_INDEX_KEY_NAME_PREFIX = NAMING_PREFIX
+ + "sql_index_name_prefix";
+
+ /**
+ * Controls if manually set sql names (table name, column names) should also
+ * be truncated or cased. Default is true for backward compatability.
+ */
+ public static final String AUTO_ADAPT_MANUAL_SET_SQL_NAMES = NAMING_PREFIX
+ + "auto_adapt_manual_set_sql_names";
+
+ // END: ++++++++++++++++++++++ SQL Naming related Options
+ // ++++++++++++++++++++++++++++++++++++
+
+ /**
+ * Controls if non-mutable eclasses should have a discriminator or version
+ * column. Default is false.
+ *
+ * @Deprecated use the extensionManager concept
+ */
+ public static final String SQL_DISCRIMINATOR_VERSION_IMMUTABLE_ECLASS = NAMING_PREFIX
+ + "sql_discriminator_version_immutable_eclass";
+
+ /**
+ * Controls how the econtainer feature id is persisted. There are three
+ * values: featureid or featurename
+ *
+ * @Deprecated use the extensionManager concept
+ */
+ public static final String ECONTAINER_FEATURE_PERSISTENCE_STRATEGY = NAMING_PREFIX
+ + "econtainer_feature_persistence_strategy";
+
+ /**
+ * see bugzilla 227673, option can be used to set the hibernate usertype
+ * used for xsd date and xsd date time fields.
+ */
+ public static final String USER_XSDDATE_TYPE = MAPPING_PREFIX
+ + "UserDateType";
+ public static final String USER_XSDDATETIME_TYPE = MAPPING_PREFIX
+ + "UserDateTimeType";
+ public static final String USER_XSDTIME_TYPE = MAPPING_PREFIX
+ + "UserTimeType";
+
+ /**
+ * This option can be used to control the actual xsd date class used, as a
+ * default the javax.xml.datatype.XMLGregorianCalendar class is used.
+ */
+ public static final String XSDDATE_CLASS = MAPPING_PREFIX + "XSDDateClass";
+
+ /**
+ * The default length of a varchar column. Normally hibernate will choose to
+ * set this to 255.
+ */
+ public static final String DEFAULT_VARCHAR_LENGTH = MAPPING_PREFIX
+ + "default_varchar_length";
+
+ /**
+ * The maximum length of the comments which are copied from the model to the
+ * mapping file. The default is zero which means no comments are copied from
+ * the model to the mapping.
+ */
+ public static final String MAX_COMMENT_LENGTH = MAPPING_PREFIX
+ + "max_comment_length";
+
+ /**
+ * EClass marked with Embeddable is always embedded, default is false. If
+ * this is set to true then it is not required anymore to set a
+ *
+ * @Embedded annotation on an ereference,
+ * @Embeddable on the EClass is then sufficient.
+ */
+ public static final String MAP_EMBEDDABLE_AS_EMBEDDED = MAPPING_PREFIX
+ + "map_embeddable_as_embedded";
+
+ /** Optimistic locking */
+ public static final String OPTIMISTIC = MAPPING_PREFIX
+ + "optimistic_locking";
+
+ /**
+ * Add an index for each foreign key mapping. Some databases do not add an
+ * index for a foreign key automatically. Setting this to true will
+ * automatically add an index field to each foreign key.
+ */
+ public static final String ADD_INDEX_FOR_FOREIGN_KEY = MAPPING_PREFIX
+ + "add_index_for_fk";
+
+ /**
+ * Set or not set the cascade attribute on a mto, mtm or otm non-containment
+ * relation. The backward compatible value is true. The better performing
+ * value is false. The default is false.
+ *
+ * @Deprecated use CASCADE_POLICY_ON_NON_CONTAINMENT
+ */
+ public static final String SET_DEFAULT_CASCADE_ON_NON_CONTAINMENT = MAPPING_PREFIX
+ + "set_default_cascade_on_non_containment";
+
+ /** Inheritance mapping */
+ public static final String INHERITANCE_MAPPING = MAPPING_PREFIX
+ + "inheritance";
+
+ /**
+ * Can be set to force an update of the schema when the application starts.
+ * Note this option is only meaningfull for jpox, for hibernate use the
+ * hibernate property: hibernate.hbm2ddl_auto
+ */
+ public static final String UPDATE_SCHEMA = RUNTIME_PREFIX + "update_schema";
+
+ /** Force all containment relations to be eagerly loaded or not */
+ public static final String FETCH_CONTAINMENT_EAGERLY = MAPPING_PREFIX
+ + "fetch_containment_eagerly";
+
+ /**
+ * Force all associations to be extra lazy loaded See here
+ * http://sites.google
+ * .com/a/pintailconsultingllc.com/java/hibernate-extra-lazy
+ * -collection-fetching for some information.
+ *
+ * Default is false.
+ */
+ public static final String FETCH_ASSOCIATION_EXTRA_LAZY = MAPPING_PREFIX
+ + "fetch_one_to_many_extra_lazy";
+
+ /**
+ * Set cascade all (incl. orphan delete) on containment relation.
+ *
+ * @Deprecated use CASCADE_POLICY_ON_CONTAINMENT
+ */
+ public static final String SET_CASCADE_ALL_ON_CONTAINMENT = MAPPING_PREFIX
+ + "cascade_all_on_containment";
+
+ /**
+ * Can be used to set custom cascade policy for containment : <br>
+ * <code>ALL</code> or a combination of (<code>REMOVE</code>,
+ * <code>REFRESH</code>, <code>PERSIST</code>, <code>MERGE</code>) <br>
+ * e.g. : REMOVE,PERSIST,MERGE <br>
+ * Warning : ALL != REMOVE,REFRESH,PERSIST,MERGE <br>
+ * but ALL == REMOVE with delete Orphan, REFRESH,PERSIST,MERGE
+ */
+ public static final String CASCADE_POLICY_ON_CONTAINMENT = MAPPING_PREFIX
+ + "cascade_policy_on_containment";
+
+ /**
+ * Can be used to set custom cascade policy for non containment : <br>
+ * a combination of (<code>REFRESH</code>,<code>PERSIST</code>,
+ * <code>MERGE</code>) e.g. : PERSIST,MERGE
+ */
+ public static final String CASCADE_POLICY_ON_NON_CONTAINMENT = MAPPING_PREFIX
+ + "cascade_policy_on_non_containment";
+
+ /**
+ * Can be used to control if the entity ann. should be added automatically
+ * to the model elements or that the default annotator should work according
+ * to the ejb3 spec.
+ */
+ public static final String SET_ENTITY_AUTOMATICALLY = MAPPING_PREFIX
+ + "set_entity_automatically";
+
+ /**
+ * Map all lists as a bag to the db (does not map the list index to the db),
+ * default is false
+ */
+ public static final String ALWAYS_MAP_LIST_AS_BAG = MAPPING_PREFIX
+ + "always_map_list_as_bag";
+
+ /**
+ * Map all lists as a hibernate idbag to the db (does not map the list index
+ * to the db), default is false
+ */
+ public static final String MAP_ALL_LISTS_AS_IDBAG = MAPPING_PREFIX
+ + "map_all_lists_as_idbag";
+
+ /** Use static hibernate mapping file */
+ public static final String USE_MAPPING_FILE = MAPPING_PREFIX
+ + "hibernate_mapping_file";
+
+ /**
+ * The complete resource path to the mapping file, can be used instead of
+ * the USE_MAPPING_FILE option
+ */
+ public static final String MAPPING_FILE_PATH = MAPPING_PREFIX
+ + "mapping_file_name";
+
+ /**
+ * Automatically add @Id to ID feature
+ *
+ * @id annotation to ID xsd type
+ */
+ public static final String ID_FEATURE_AS_PRIMARY_KEY = NAMING_PREFIX
+ + "id_feature_as_primary_key";
+
+ /**
+ * Automatically add
+ *
+ * @GeneratedValue to ID feature for which
+ * @Id is added automatically, default is true.
+ */
+ public static final String SET_GENERATED_VALUE_ON_ID_FEATURE = NAMING_PREFIX
+ + "set_generated_value_on_id_feature";
+
+ /**
+ * The name of the id feature if no feature has an id.
+ *
+ * @id annotation
+ */
+ public static final String DEFAULT_ID_FEATURE_NAME = NAMING_PREFIX
+ + "default_id_feature";
+
+ /**
+ * The path of the persistence XML file.
+ */
+ public static final String PERSISTENCE_XML = MAPPING_PREFIX
+ + "persistence_xml";
+
+ /**
+ * Ignore mapping EAnnotations. Primarily meant for test cases that use
+ * Persistence XML mapping, so that they can reuse the same sample models.
+ */
+ public static final String IGNORE_EANNOTATIONS = MAPPING_PREFIX
+ + "ignore_eannotations";
+
+ /**
+ * Map all emaps as true hibernate maps, default is true. In EMF an EMap is
+ * in fact an EList with Map entries. Originally Teneo maps this as a
+ * hibernate list. In the new behavior hibernate can map the emap as a real
+ * map. The default is true.
+ */
+ public static final String EMAP_AS_TRUE_MAP = MAPPING_PREFIX
+ + "emap_as_true_map";
+
+ /**
+ * This option controls if in case of hibernate also a name attribute should
+ * be added to the class/subclass tag. By adding this a class is mapped as
+ * an entity as well as a normal class. Also mapping as a normal class has
+ * the advantage that proxies can be used and that queries can use actual
+ * class names and interface names. This option is really there for backward
+ * compatibility. There are no apparent dis-advantages of adding a name
+ * attribute so the default of this option is true. Note that an eclass must
+ * have an implementation class otherwise this option has no effect.
+ * Interfaces are for example always mapped as an entity.
+ */
+ public static final String ALSO_MAP_AS_CLASS = MAPPING_PREFIX
+ + "also_map_as_class";
+
+ /**
+ * This option controls if as a default all classes should be proxied (for
+ * hibernate). This means that you don't need to add a
+ *
+ * @Proxy annotation to each eclass. As a default Teneo will use the eclass
+ * interface as the proxy class. When this is set to true then the
+ * option ALSO_MAP_AS_CLASS should also be true.
+ */
+ public static final String SET_PROXY = MAPPING_PREFIX + "set_proxy";
+
+ /**
+ * This option forces lazy=true without the proxy attribute in the hibernate
+ * mapping.
+ */
+ public static final String FORCE_LAZY = MAPPING_PREFIX + "force_lazy";
+
+ /**
+ * Disable EContainer mapping.
+ */
+ public static final String DISABLE_ECONTAINER_MAPPING = MAPPING_PREFIX
+ + "disable_econtainer";
+
+ /**
+ * Option to specify that for non-contained one-to-many always a join table
+ * is used, default is true
+ */
+ public static final String JOIN_TABLE_FOR_NON_CONTAINED_ASSOCIATIONS = MAPPING_PREFIX
+ + "join_table_for_non_contained_associations";
+
+ /**
+ * Determines whether to always include a version mapping even if one is not
+ * specified. Defaults to "true"
+ */
+ public static final String ALWAYS_VERSION = MAPPING_PREFIX
+ + "always_version";
+
+ /**
+ * The default cache strategy, can be one of: NONE, READ_ONLY,
+ * NONSTRICT_READ_ONLY, READ_WRITE, TRANSACTIONAl. If different than NONE
+ * (=default) then for Hibernate every class will be second-level cached!
+ */
+ public static final String DEFAULT_CACHE_STRATEGY = MAPPING_PREFIX
+ + "default_cache_strategy";
+
+ /** The default time/date type used */
+ public static final String DEFAULT_TEMPORAL_VALUE = MAPPING_PREFIX
+ + "default_temporal";
+
+ /**
+ * If true then EAttributes which are not set are stored as null in the
+ * database, if false then the default values is stored in the database.
+ */
+ public static final String HANDLE_UNSET_AS_NULL = RUNTIME_PREFIX
+ + "handle_unset_as_null";
+
+ /**
+ * When an unset feature is persisted, the database will get a null value,
+ * default is false.
+ */
+ public static final String CONVERT_UNSET_TO_NULL = RUNTIME_PREFIX
+ + "convert_unset_to_null";
+
+ /**
+ * If set to true then the document root is also mapped.
+ */
+ public static final String MAP_DOCUMENT_ROOT = MAPPING_PREFIX
+ + "map_document_root";
+
+ /**
+ * If set to true then the system will automatically add referenced
+ * epackages
+ */
+ public static final String AUTO_ADD_REFERENCED_EPACKAGES = MAPPING_PREFIX
+ + "auto_add_referenced_epackages";
+
+ /**
+ * If set to true then the system will map all eclasses as an EAV mapping.
+ * See http://www.elver.org/hibernate/eav_mapping.html
+ */
+ public static final String EAV_MAPPING = MAPPING_PREFIX + "eav_mapping";
+
+ /**
+ * If set then the eav mapping file is read from the location defined by
+ * this property.
+ */
+ public static final String EAV_MAPPING_FILE = MAPPING_PREFIX
+ + "eav_location";
+
+ /**
+ * Map the FeatureMap as a component entity
+ */
+ public static final String FEATUREMAP_AS_COMPONENT = MAPPING_PREFIX
+ + "featuremap_as_component";
+
+ /**
+ * Additional sources which are taken into account parsing model
+ * annotations. The value can be a comma delimited list of source values.
+ */
+ public static final String EXTRA_ANNOTATION_SOURCES = MAPPING_PREFIX
+ + "extra_annotation_sources";
+
+ public final static String ECONTAINER_CLASS_COLUMN = "econtainer_class_column";
+ public final static String ECONTAINER_COLUMN = "e_container_column";
+ public final static String ECONTAINER_FEATURE_NAME_COLUMN = "e_container_feature_name_column";
+
+ /** Returns the default properties used in the system */
+ public static Properties getDefaultProperties() {
+ final Properties props = new Properties();
+ props.setProperty(HANDLE_UNSET_AS_NULL, "false");
+ props.setProperty(CONVERT_UNSET_TO_NULL, "false");
+ props.setProperty(JOIN_TABLE_FOR_NON_CONTAINED_ASSOCIATIONS, "true");
+ props.setProperty(USE_MAPPING_FILE, "false");
+ // props.setProperty(MAPPING_FILE_PATH, null); // null is the default
+ // anyway
+ props.setProperty(SET_CASCADE_ALL_ON_CONTAINMENT, "");
+ props.setProperty(CASCADE_POLICY_ON_CONTAINMENT, "ALL");
+ props.setProperty(OPTIMISTIC, "true");
+ props.setProperty(UPDATE_SCHEMA, "false");
+ props.setProperty(FETCH_CONTAINMENT_EAGERLY, "false");
+ props.setProperty(FETCH_ASSOCIATION_EXTRA_LAZY, "false");
+ props.setProperty(SET_ENTITY_AUTOMATICALLY, "true");
+ props.setProperty(VERSION_COLUMN_NAME, "e_version");
+ props.setProperty(SQL_CASE_STRATEGY, "lowercase");
+ props.setProperty(ID_COLUMN_NAME, "e_id");
+ props.setProperty(DISABLE_ECONTAINER_MAPPING, "false");
+ props.setProperty(MAXIMUM_SQL_NAME_LENGTH, "-1");
+ props.setProperty(IGNORE_EANNOTATIONS, "false");
+ props.setProperty(ALWAYS_VERSION, "true");
+ props.setProperty(DEFAULT_CACHE_STRATEGY, "NONE");
+ props.setProperty(DISCRIMINATOR_COLUMN_NAME, "DTYPE");
+ props.setProperty(JOIN_TABLE_NAMING_STRATEGY, "unique");
+ // props.setProperty(JOIN_TABLE_NAMING_STRATEGY_OLD, "unique");
+ props.setProperty(JOIN_COLUMN_NAMING_STRATEGY, "unique");
+ props.setProperty(DEFAULT_TEMPORAL_VALUE, "TIMESTAMP");
+ props.setProperty(DEFAULT_ID_FEATURE_NAME, "e_id");
+ props.setProperty(ID_FEATURE_AS_PRIMARY_KEY, "true");
+ props.setProperty(SET_GENERATED_VALUE_ON_ID_FEATURE, "true");
+ props.setProperty(EMAP_AS_TRUE_MAP, "true");
+ props.setProperty(ALWAYS_MAP_LIST_AS_BAG, "false");
+ props.setProperty(ALSO_MAP_AS_CLASS, "true");
+ props.setProperty(SET_PROXY, "false");
+ props.setProperty(FORCE_LAZY, "false");
+ props.setProperty(MAP_ALL_LISTS_AS_IDBAG, "false");
+ props.setProperty(IDBAG_ID_COLUMN_NAME, "ID");
+ props.setProperty(ADD_INDEX_FOR_FOREIGN_KEY, "false");
+ props.setProperty(SET_DEFAULT_CASCADE_ON_NON_CONTAINMENT, "");
+ props.setProperty(CASCADE_POLICY_ON_NON_CONTAINMENT, "");
+ props.setProperty(SET_FOREIGN_KEY_NAME, "true");
+ props.setProperty(MAP_EMBEDDABLE_AS_EMBEDDED, "false");
+ props.setProperty(MAX_COMMENT_LENGTH, "0");
+ props.setProperty(DEFAULT_VARCHAR_LENGTH, "-1");
+ props.setProperty(SQL_NAME_ESCAPE_CHARACTER, "`");
+ props.setProperty(USER_XSDDATE_TYPE,
+ "org.eclipse.emf.teneo.hibernate.mapping.XSDDate");
+ props.setProperty(USER_XSDDATETIME_TYPE,
+ "org.eclipse.emf.teneo.hibernate.mapping.XSDDateTime");
+ props.setProperty(USER_XSDTIME_TYPE,
+ "org.eclipse.emf.teneo.hibernate.mapping.XSDDateTime");
+ props.setProperty(XSDDATE_CLASS,
+ "javax.xml.datatype.XMLGregorianCalendar");
+ props.setProperty(SQL_DISCRIMINATOR_VERSION_IMMUTABLE_ECLASS, "true");
+ props.setProperty(ECONTAINER_FEATURE_PERSISTENCE_STRATEGY,
+ "FEATURENAME");
+ props.setProperty(SQL_TABLE_NAME_PREFIX, "");
+ props.setProperty(SQL_COLUMN_NAME_PREFIX, "");
+ props.setProperty(SQL_FOREIGN_KEY_NAME_PREFIX, "");
+ props.setProperty(SQL_INDEX_KEY_NAME_PREFIX, "");
+ props.setProperty(MAP_DOCUMENT_ROOT, "false");
+ props.setProperty(EAV_MAPPING, "false");
+ props.setProperty(AUTO_ADD_REFERENCED_EPACKAGES, "false");
+ props.setProperty(ECONTAINER_CLASS_COLUMN,
+ Constants.COLUMN_ECONTAINER_CLASS);
+ props.setProperty(ECONTAINER_COLUMN, Constants.COLUMN_ECONTAINER);
+ props.setProperty(ECONTAINER_FEATURE_NAME_COLUMN,
+ Constants.COLUMN_ECONTAINER_FEATURE_NAME);
+ props.setProperty(FEATUREMAP_AS_COMPONENT, "false");
+ props.setProperty(EXTRA_ANNOTATION_SOURCES, "");
+ props.setProperty(AUTO_ADAPT_MANUAL_SET_SQL_NAMES, "true");
+
+ return props;
+ }
+
+ /**
+ * The wrapped Properties instance.
+ */
+ private final Properties properties;
+
+ /**
+ * @return value of {@link #DISCRIMINATOR_COLUMN_NAME}
+ */
+ public String getDiscriminatorColumnName() {
+ return properties.getProperty(DISCRIMINATOR_COLUMN_NAME);
+ }
+
+ /**
+ * @return value of {@link #EXTRA_ANNOTATION_SOURCES}
+ */
+ public String getExtraAnnotationSources() {
+ return properties.getProperty(EXTRA_ANNOTATION_SOURCES);
+ }
+
+ /**
+ * @return value of {@link #FEATUREMAP_AS_COMPONENT}
+ */
+ public boolean isMapFeatureMapAsComponent() {
+ return Boolean.valueOf(properties.getProperty(FEATUREMAP_AS_COMPONENT))
+ .booleanValue();
+ }
+
+ /**
+ * @return value of {@link AUTO_ADAPT_MANUAL_SET_SQL_NAMES}
+ */
+ public boolean isAutoAdaptManualSQLNames() {
+ return Boolean.valueOf(
+ properties.getProperty(AUTO_ADAPT_MANUAL_SET_SQL_NAMES))
+ .booleanValue();
+ }
+
+ /**
+ * @return value of {@link #ECONTAINER_COLUMN}
+ */
+ public String getEContainerColumn() {
+ return properties.getProperty(ECONTAINER_COLUMN);
+ }
+
+ /**
+ * @return value of {@link #ECONTAINER_CLASS_COLUMN}
+ */
+ public String getEContainerClassColumn() {
+ return properties.getProperty(ECONTAINER_CLASS_COLUMN);
+ }
+
+ /**
+ * @return value of {@link #ECONTAINER_FEATURE_NAME_COLUMN}
+ */
+ public String getEContainerFeatureNameColumn() {
+ return properties.getProperty(ECONTAINER_FEATURE_NAME_COLUMN);
+ }
+
+ /**
+ * @return value of {@link #EAV_MAPPING}
+ */
+ public boolean isEAVMapping() {
+ return Boolean.valueOf(properties.getProperty(EAV_MAPPING))
+ .booleanValue();
+ }
+
+ /**
+ * @return value of {@link #EAV_MAPPING_FILE}
+ */
+ public String getEAVMappingFile() {
+ return properties.getProperty(EAV_MAPPING_FILE);
+ }
+
+ /**
+ * @return value of {@link #AUTO_ADD_REFERENCED_EPACKAGES}
+ */
+ public boolean isAutoAddReferencedEPackages() {
+ return Boolean.valueOf(
+ properties.getProperty(AUTO_ADD_REFERENCED_EPACKAGES))
+ .booleanValue();
+ }
+
+ /**
+ * @return value of {@link #MAP_DOCUMENT_ROOT}
+ */
+ public boolean isMapDocumentRoot() {
+ return Boolean.valueOf(properties.getProperty(MAP_DOCUMENT_ROOT))
+ .booleanValue();
+ }
+
+ /**
+ * @return value of the {@link #HANDLE_UNSET_AS_NULL} option
+ */
+ public boolean getHandleUnsetAsNull() {
+ return Boolean.valueOf(properties.getProperty(HANDLE_UNSET_AS_NULL))
+ .booleanValue();
+ }
+
+ /**
+ * @return value of the {@link #CONVERT_UNSET_TO_NULL} option
+ */
+ public boolean getConvertUnsetToNull() {
+ return Boolean.valueOf(properties.getProperty(CONVERT_UNSET_TO_NULL))
+ .booleanValue();
+ }
+
+ /**
+ * Construct a new instance using Properties.
+ */
+ public PersistenceOptions(Properties properties) {
+ this.properties = getDefaultProperties();
+
+ if (properties != null) {
+ this.properties.putAll(properties);
+ }
+
+ logProperties();
+ }
+
+ /**
+ * Constructs a new instance by loading properties from
+ * "/elver-persistence.properties" at the root of the classpath.
+ */
+ public PersistenceOptions() {
+ this.properties = getDefaultProperties();
+
+ final Properties props = new Properties();
+ InputStream in = null;
+ try {
+ in = this.getClass()
+ .getResourceAsStream(DEFAULT_CLASSPATH_FILENAME);
+ if (in != null) {
+ log.debug("Loading persistence options from classpath \""
+ + DEFAULT_CLASSPATH_FILENAME + "\".");
+ props.load(in);
+ }
+ } catch (IOException e) {
+ throw new RuntimeException("Error loading \""
+ + DEFAULT_CLASSPATH_FILENAME + "\" from classpath:"
+ + e.getMessage(), e);
+ } finally {
+ try {
+ if (in != null) {
+ in.close();
+ }
+ } catch (IOException e) {
+ // Ignore.
+ }
+ }
+ this.properties.putAll(props);
+
+ logProperties();
+ }
+
+ /** Dump the props */
+ public void logProperties() {
+ log.debug("Properties of PersistenceOptions:");
+ for (Object key : properties.keySet()) {
+ log.debug(key + ": " + properties.get(key));
+ }
+ }
+
+ public String getSQLTableNamePrefix() {
+ return properties.getProperty(SQL_TABLE_NAME_PREFIX);
+ }
+
+ public String getSQLColumnNamePrefix() {
+ return properties.getProperty(SQL_COLUMN_NAME_PREFIX);
+ }
+
+ public String getSQLForeignKeyNamePrefix() {
+ return properties.getProperty(SQL_FOREIGN_KEY_NAME_PREFIX);
+ }
+
+ public String getSQLIndexNamePrefix() {
+ return properties.getProperty(SQL_INDEX_KEY_NAME_PREFIX);
+ }
+
+ /** Return the default temporal value */
+ public String getDefaultTemporalValue() {
+ return properties.getProperty(DEFAULT_TEMPORAL_VALUE);
+ }
+
+ /** Return the IDBAG_ID_COLUMN_NAME */
+ public String getIDBagIDColumnName() {
+ return getSQLColumnNamePrefix()
+ + properties.getProperty(IDBAG_ID_COLUMN_NAME);
+ }
+
+ /**
+ * Returns the value of the EMAP_AS_TRUE_MAP option, default is false
+ */
+ public boolean isMapEMapAsTrueMap() {
+ return Boolean.valueOf(properties.getProperty(EMAP_AS_TRUE_MAP))
+ .booleanValue();
+ }
+
+ /**
+ * Returns the value of the SET_DEFAULT_CASCADE_ON_MTO_MTM option, default
+ * is false
+ */
+ public boolean isSetDefaultCascadeOnNonContainment() {
+ String property = properties
+ .getProperty(SET_DEFAULT_CASCADE_ON_NON_CONTAINMENT);
+ if (!property.equals("")) {
+ return Boolean.valueOf(property).booleanValue();
+ }
+ return !properties.getProperty(CASCADE_POLICY_ON_NON_CONTAINMENT)
+ .equals("");
+ }
+
+ public boolean isSetCascadePolicyForNonContainment() {
+ return !properties.getProperty(CASCADE_POLICY_ON_NON_CONTAINMENT)
+ .equals("");
+ }
+
+ public String getCascadePolicyForContainment() {
+ return properties.getProperty(CASCADE_POLICY_ON_CONTAINMENT);
+ }
+
+ public String getCascadePolicyForNonContainment() {
+ return properties.getProperty(CASCADE_POLICY_ON_NON_CONTAINMENT);
+ }
+
+ /**
+ * Returns true if the CASCADE_POLICY_ON_NON_CONTAINMENT property contains
+ * the merge cascade type
+ */
+ public boolean isSetCascadeMergeOnNonContainment() {
+ return isSetCascadeOnNonContainement(CascadeType.MERGE.getName());
+ }
+
+ /**
+ * Returns true if the CASCADE_POLICY_ON_NON_CONTAINMENT property contains
+ * the persist cascade type
+ */
+ public boolean isSetCascadePersistOnNonContainment() {
+ return isSetCascadeOnNonContainement(CascadeType.PERSIST.getName());
+ }
+
+ /**
+ * Returns true if the CASCADE_POLICY_ON_NON_CONTAINMENT property contains
+ * the refresh cascade type
+ */
+ public boolean isSetCascadeRefreshOnNonContainment() {
+ return isSetCascadeOnNonContainement(CascadeType.REFRESH.getName());
+ }
+
+ /**
+ * Returns true if the CASCADE_POLICY_ON_NON_CONTAINMENT property contains
+ * the given cascade type
+ */
+ private boolean isSetCascadeOnNonContainement(String cascadeType) {
+ return isSetCascade(
+ properties.getProperty(CASCADE_POLICY_ON_NON_CONTAINMENT),
+ cascadeType);
+ }
+
+ /**
+ * Returns the value of the SET_FOREIGN_KEY_NAME option, default is true
+ */
+ public boolean isSetForeignKeyNames() {
+ return Boolean.valueOf(properties.getProperty(SET_FOREIGN_KEY_NAME))
+ .booleanValue();
+ }
+
+ /**
+ * Returns the value of the ALSO_MAP_AS_CLASS option, default is false
+ */
+ public boolean isAlsoMapAsClass() {
+ return Boolean.valueOf(properties.getProperty(ALSO_MAP_AS_CLASS))
+ .booleanValue();
+ }
+
+ /**
+ * Returns the value of the MAP_EMBEDDABLE_AS_EMBEDDED option, default is
+ * false
+ */
+ public boolean isMapEmbeddableAsEmbedded() {
+ return Boolean.valueOf(
+ properties.getProperty(MAP_EMBEDDABLE_AS_EMBEDDED))
+ .booleanValue();
+ }
+
+ /**
+ * Returns true if the proxy annotation should be added automatically
+ */
+ public boolean isSetProxy() {
+ return Boolean.valueOf(properties.getProperty(SET_PROXY))
+ .booleanValue();
+ }
+
+ /**
+ * Returns true if the lazy attribute should be forced to true in the hbm
+ * mapping.
+ */
+ public boolean isForceLazy() {
+ return Boolean.valueOf(properties.getProperty(FORCE_LAZY))
+ .booleanValue();
+ }
+
+ /**
+ * Returns the value of the ALWAYS_MAP_LIST_AS_BAG option, default is false
+ */
+ public boolean alwaysMapListAsBag() {
+ return Boolean.valueOf(properties.getProperty(ALWAYS_MAP_LIST_AS_BAG))
+ .booleanValue();
+ }
+
+ /**
+ * Returns the value of the MAP_ALL_LISTS_AS_IDBAG option, default is false
+ */
+ public boolean alwaysMapListAsIdBag() {
+ return Boolean.valueOf(properties.getProperty(MAP_ALL_LISTS_AS_IDBAG))
+ .booleanValue();
+ }
+
+ /** Returns the value of the ADD_INDEX_FOR_FOREIGN_KEY option */
+ public boolean isAddIndexForForeignKey() {
+ return Boolean.valueOf(
+ properties.getProperty(ADD_INDEX_FOR_FOREIGN_KEY))
+ .booleanValue();
+ }
+
+ /**
+ * Returns the value of the UseJoinTableForNonContainedAssociations option,
+ * default is false
+ */
+ public boolean isJoinTableForNonContainedAssociations() {
+ return Boolean
+ .valueOf(
+ properties
+ .getProperty(JOIN_TABLE_FOR_NON_CONTAINED_ASSOCIATIONS))
+ .booleanValue();
+ }
+
+ /** Returns the value of the UseMappingFile option, default is false */
+ public boolean isUseMappingFile() {
+ return Boolean.valueOf(properties.getProperty(USE_MAPPING_FILE))
+ .booleanValue();
+ }
+
+ /** Returns the value of the MAPPING_FILE_PATH option, default is "" */
+ public String getMappingFilePath() {
+ return properties.getProperty(MAPPING_FILE_PATH);
+ }
+
+ /** Returns the value of the id feature as primary key */
+ public boolean isIDFeatureAsPrimaryKey() {
+ return Boolean.valueOf(
+ properties.getProperty(ID_FEATURE_AS_PRIMARY_KEY))
+ .booleanValue();
+ }
+
+ /** Returns the value of the SET_GENERATED_VALUE_ON_ID_FEATURE option */
+ public boolean isSetGeneratedValueOnIDFeature() {
+ return Boolean.valueOf(
+ properties.getProperty(SET_GENERATED_VALUE_ON_ID_FEATURE))
+ .booleanValue();
+ }
+
+ /** Returns the value of the orphan delete on containment, default is true */
+ public boolean isSetCascadeAllOnContainment() {
+ if (!properties.getProperty(SET_CASCADE_ALL_ON_CONTAINMENT).equals("")) {
+ return Boolean.valueOf(
+ properties.getProperty(SET_CASCADE_ALL_ON_CONTAINMENT))
+ .booleanValue();
+ }
+ return isSetCascadeOnContainement(CascadeType.ALL.getName());
+ }
+
+ /**
+ * Returns true if CASCADE_POLICY_ON_CONTAINMENT property contains the MERGE
+ * cascade type
+ */
+ public boolean isSetCascadeMergeOnContainment() {
+ return isSetCascadeOnContainement(CascadeType.MERGE.getName());
+ }
+
+ /**
+ * Returns true if CASCADE_POLICY_ON_CONTAINMENT property contains the
+ * PERSIST cascade type
+ */
+ public boolean isSetCascadePersistOnContainment() {
+ return isSetCascadeOnContainement(CascadeType.PERSIST.getName());
+ }
+
+ /**
+ * Returns true if CASCADE_POLICY_ON_CONTAINMENT property contains the
+ * REMOVE cascade type
+ */
+ public boolean isSetCascadeRemoveOnContainment() {
+ return isSetCascadeOnContainement(CascadeType.REMOVE.getName());
+ }
+
+ /**
+ * Returns true if CASCADE_POLICY_ON_CONTAINMENT property contains the
+ * REFRESH cascade type
+ */
+ public boolean isSetCascadeRefreshOnContainment() {
+ return isSetCascadeOnContainement(CascadeType.REFRESH.getName());
+ }
+
+ /**
+ * Returns true if CASCADE_POLICY_ON_CONTAINMENT property contains the given
+ * cascade type
+ */
+ private boolean isSetCascadeOnContainement(String cascadeType) {
+ return isSetCascade(
+ properties.getProperty(CASCADE_POLICY_ON_CONTAINMENT),
+ cascadeType);
+ }
+
+ /** Returns true if property contains the given cascade type */
+ private boolean isSetCascade(String property, String cascadeType) {
+ return Pattern.matches(".*\\b" + cascadeType.toUpperCase() + "\\b.*",
+ property.toUpperCase());
+ }
+
+ /** Returns the value of the Optimistic option, default is true */
+ public boolean isUseOptimisticLocking() {
+ return Boolean.valueOf(properties.getProperty(OPTIMISTIC))
+ .booleanValue();
+ }
+
+ /** Returns the value of the UpdateSchema option, default is true */
+ public boolean isUpdateSchema() {
+ return Boolean.valueOf(properties.getProperty(UPDATE_SCHEMA))
+ .booleanValue();
+ }
+
+ /** Returns the value of the fetch containment eagerly, default is false */
+ public boolean isFetchContainmentEagerly() {
+ return Boolean.valueOf(
+ properties.getProperty(FETCH_CONTAINMENT_EAGERLY))
+ .booleanValue();
+ }
+
+ /** Returns the value of the fetch extra lazy option, default is false */
+ public boolean isFetchAssociationExtraLazy() {
+ return Boolean.valueOf(
+ properties.getProperty(FETCH_ASSOCIATION_EXTRA_LAZY))
+ .booleanValue();
+ }
+
+ /** Is set entity automatically, default is true */
+ public boolean isSetEntityAutomatically() {
+ return Boolean
+ .valueOf(properties.getProperty(SET_ENTITY_AUTOMATICALLY))
+ .booleanValue();
+ }
+
+ /** Returns the inheritance mapping strategy, can be null */
+ public String getInheritanceMapping() {
+ return properties.getProperty(INHERITANCE_MAPPING);
+ }
+
+ /** Returns the value of the version column option, returns null if not set */
+ public String getVersionColumnName() {
+ return getSQLColumnNamePrefix()
+ + properties.getProperty(VERSION_COLUMN_NAME);
+ }
+
+ /** Returns the value of the naming strategy, default is lower case */
+ public String getSQLCaseStrategy() {
+ return properties.getProperty(SQL_CASE_STRATEGY);
+ }
+
+ /** Returns the value of the id column option, returns null if not set */
+ public String getIdColumnName() {
+ return getSQLColumnNamePrefix()
+ + properties.getProperty(ID_COLUMN_NAME);
+ }
+
+ /** Returns the value of the default id property */
+ public String getDefaultIDFeatureName() {
+ return properties.getProperty(DEFAULT_ID_FEATURE_NAME);
+ }
+
+ /** Return the sql escape character, default is ` */
+ public String getSqlNameEscapeCharacter() {
+ return properties.getProperty(SQL_NAME_ESCAPE_CHARACTER);
+ }
+
+ /** Returns the value of the join table naming strategy */
+ public String getJoinTableNamingStrategy() {
+ if (properties.get(JOIN_TABLE_NAMING_STRATEGY_OLD) != null) {
+ log.warn("The option " + JOIN_TABLE_NAMING_STRATEGY_OLD
+ + " is deprecated, please use: "
+ + JOIN_TABLE_NAMING_STRATEGY);
+ return properties.getProperty(JOIN_TABLE_NAMING_STRATEGY);
+ }
+ return properties.getProperty(JOIN_TABLE_NAMING_STRATEGY);
+ }
+
+ /** Returns the value of the join column naming strategy */
+ public String getJoinColumnNamingStrategy() {
+ return properties.getProperty(JOIN_COLUMN_NAMING_STRATEGY);
+ }
+
+ /**
+ * Returns the default second level caching strategy, default value is NONE
+ * (no second level caching).
+ */
+ public String getDefaultCacheStrategy() {
+ return properties.getProperty(DEFAULT_CACHE_STRATEGY);
+ }
+
+ /** Return the default varchar length */
+ public int getDefaultVarCharLength() {
+ return Integer.parseInt(properties.getProperty(DEFAULT_VARCHAR_LENGTH));
+ }
+
+ /** Are econtainer mappings (hibernate) disabled */
+ public boolean isDisableEContainerMapping() {
+ return Boolean.valueOf(
+ properties.getProperty(DISABLE_ECONTAINER_MAPPING))
+ .booleanValue();
+ }
+
+ /** Return the value of the MAX_COMMENT_LENGTH */
+ public int getMaximumCommentLength() {
+ final String colLength = properties.getProperty(MAX_COMMENT_LENGTH);
+ try {
+ final int maxLength = Integer.parseInt(colLength);
+ return maxLength;
+ } catch (NumberFormatException e) {
+ log.error("Property " + MAXIMUM_SQL_NAME_LENGTH
+ + " as a non-integer value: " + colLength
+ + " value is ignored");
+ return 0;
+ }
+ }
+
+ /** Return the max. sql name length, or -1 if not set or illegal */
+ public int getMaximumSqlNameLength() {
+ final String colLength = properties
+ .getProperty(MAXIMUM_SQL_NAME_LENGTH);
+ try {
+ final int maxLength = Integer.parseInt(colLength);
+ if (maxLength == 0) {
+ throw new TeneoException(
+ "The option MAXIMUM_SQL_NAME_LENGTH has a value of zero. "
+ + "This will result in empty column and table names in the mapping! "
+ + "Please change this option to a more usable value.");
+ }
+ if (maxLength < 4 && maxLength > -1) {
+ log.warn("The option MAXIMUM_SQL_NAME_LENGTH has a low value: "
+ + maxLength + ". Are you sure this is correct?");
+ }
+ return maxLength;
+ } catch (NumberFormatException e) {
+ log.error("Property " + MAXIMUM_SQL_NAME_LENGTH
+ + " as a non-integer value: " + colLength
+ + " value is ignored");
+ return -1;
+ }
+ }
+
+ /**
+ * Returns the value of the SQL_DISCRIMINATOR_VERSION_IMMUTABLE_ECLASS
+ * option.
+ */
+ public Boolean isDiscriminatorVersionOnImmutableEClass() {
+ return Boolean
+ .valueOf(
+ properties
+ .getProperty(SQL_DISCRIMINATOR_VERSION_IMMUTABLE_ECLASS))
+ .booleanValue();
+ }
+
+ /**
+ * Returns the path of the XML persistence mapping file or null if the
+ * property has not been defined.
+ */
+ public String getPersistenceXmlPath() {
+ return properties.getProperty(PERSISTENCE_XML);
+ }
+
+ /**
+ * Returns a boolean indication whether to ignore mapping EAnnotations.
+ */
+ public boolean isIgnoreEAnnotations() {
+ return Boolean.valueOf(properties.getProperty(IGNORE_EANNOTATIONS))
+ .booleanValue();
+ }
+
+ /**
+ * Returns an array of all String constants.
+ *
+ * @return
+ */
+ public static String[] propertyNames() {
+ final List<String> names = new ArrayList<String>();
+ for (Field field : PersistenceOptions.class.getFields()) {
+ try {
+ if ((field.getModifiers() & Modifier.STATIC) > 0
+ & field.getType().equals(String.class)) {
+ final String value = (String) field.get(null);
+ if (value.startsWith("teneo.")) {
+ names.add(value);
+ }
+ }
+ } catch (IllegalAccessException e) {
+ }
+ }
+ Collections.sort(names);
+ return names.toArray(new String[names.size()]);
+ }
+
+ public boolean getAlwaysVersion() {
+ return Boolean.valueOf(properties.getProperty(ALWAYS_VERSION))
+ .booleanValue();
+ }
+
+ /**
+ * @return the properties
+ */
+ public Properties getProperties() {
+ return properties;
+ }
+
+ /**
+ * Creates the correct sql name strategy based on the String setting.
+ *
+ * @Deprecated use the SQLNameStrategy and extensionManager concept
+ */
+ public String getSQLNameStrategy() {
+ return properties.getProperty(SQL_NAME_STRATEGY);
+ }
+
+ public String getUserXSDDateType() {
+ return properties.getProperty(USER_XSDDATE_TYPE);
+ }
+
+ public String getUserXSDTime() {
+ return properties.getProperty(USER_XSDTIME_TYPE);
+ }
+
+ public String getUserXSDDateTime() {
+ return properties.getProperty(USER_XSDDATETIME_TYPE);
+ }
+
+ public String getXSDDateClass() {
+ return properties.getProperty(XSDDATE_CLASS);
+ }
+
+ public EContainerFeaturePersistenceStrategy getEContainerFeaturePersistenceStrategy() {
+ String strategy = properties
+ .getProperty(ECONTAINER_FEATURE_PERSISTENCE_STRATEGY);
+ if (strategy == null) {
+ throw new TeneoException(
+ "Option ECONTAINER_FEATURE_PERSISTENCE_STRATEGY not set, please set it to one of: featureid, featurename, both");
+ }
+ EContainerFeaturePersistenceStrategy result = EContainerFeaturePersistenceStrategy
+ .valueOf(strategy.toUpperCase());
+ if (result == null) {
+ throw new TeneoException(
+ "Option ECONTAINER_FEATURE_PERSISTENCE_STRATEGY not set correctly ("
+ + strategy
+ + "), please set it to one of: featureid, featurename, both");
+ }
+ return result;
+ }
+
+ public enum EContainerFeaturePersistenceStrategy {
+ FEATURENAME, FEATUREID, BOTH
+ }
+} \ No newline at end of file
diff --git a/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/StoreValidationException.java b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/StoreValidationException.java
new file mode 100755
index 000000000..9e83087a2
--- /dev/null
+++ b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/StoreValidationException.java
@@ -0,0 +1,62 @@
+/**
+ * <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: StoreValidationException.java,v 1.4 2007/02/08 23:14:41 mtaal
+ * Exp $
+ */
+
+package org.eclipse.emf.teneo;
+
+import org.eclipse.emf.common.util.Diagnostic;
+
+/**
+ * Is used to contain a list of Diagnostics which contain error messages found during the save of a
+ * resource.
+ *
+ * @author <a href="mailto:mtaal@elver.org">Martin Taal</a>
+ * @version $Revision: 1.8 $
+ */
+
+public class StoreValidationException extends TeneoException {
+ /**
+ * Serializable id
+ */
+ private static final long serialVersionUID = 7433341056815136417L;
+
+ /** Creates the message */
+ private static String createMessage(Diagnostic[] diagnostics) {
+ final StringBuffer result = new StringBuffer();
+ for (int i = 0; i < diagnostics.length; i++) {
+ if (i > 0) {
+ result.append("\n");
+ }
+ result.append(diagnostics[i].getMessage());
+
+ for (Diagnostic childDiagnostic : diagnostics[i].getChildren()) {
+ switch (childDiagnostic.getSeverity()) {
+ case Diagnostic.ERROR:
+ result.append("\n\t" + childDiagnostic.getMessage());
+ }
+ }
+ }
+ return result.toString();
+ }
+
+ /** The list of diagnostics */
+ private final Diagnostic[] diagnostics;
+
+ /**
+ * The constructor, logs the exception also
+ */
+ public StoreValidationException(Diagnostic[] diags) {
+ super(createMessage(diags));
+ diagnostics = diags;
+ }
+
+ /** Returns the list of diagnostics of this exception */
+ public Diagnostic[] getDiagnostics() {
+ return diagnostics;
+ }
+}
diff --git a/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/TeneoException.java b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/TeneoException.java
new file mode 100755
index 000000000..8a3a17dc6
--- /dev/null
+++ b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/TeneoException.java
@@ -0,0 +1,54 @@
+/**
+ * <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: TeneoException.java,v 1.4 2009/03/30 07:53:05 mtaal Exp $
+ */
+
+package org.eclipse.emf.teneo;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * Is used to throw runtime store exceptions. 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.4 $
+ */
+
+public class TeneoException extends RuntimeException {
+ /**
+ * Serializable id
+ */
+ private static final long serialVersionUID = 7433341056815136417L;
+
+ /**
+ * The constructor, logs the exception also
+ */
+ public TeneoException(String msg, Throwable cause) {
+ super(msg, cause);
+
+ // and log it
+ getLogger().error(msg, cause);
+ }
+
+ /**
+ * The constructor, logs the exception also
+ */
+ public TeneoException(String msg) {
+ super(msg);
+
+ // and log it
+ getLogger().error(msg, this);
+ }
+
+ /** Get the class specific logger */
+ private Log getLogger() {
+ return LogFactory.getLog(this.getClass());
+ }
+}
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>
diff --git a/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/classloader/ClassClassLoaderStrategy.java b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/classloader/ClassClassLoaderStrategy.java
new file mode 100755
index 000000000..c2e620180
--- /dev/null
+++ b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/classloader/ClassClassLoaderStrategy.java
@@ -0,0 +1,87 @@
+/**
+ * <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: ClassClassLoaderStrategy.java,v 1.6 2009/03/30 07:53:05 mtaal Exp $
+ */
+
+package org.eclipse.emf.teneo.classloader;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * Just returns the passed class loader.
+ *
+ * @author <a href="mailto:mtaal@elver.org">Martin Taal</a>
+ * @version $Revision: 1.6 $
+ */
+
+public class ClassClassLoaderStrategy implements ClassLoaderStrategy {
+ /** The logger */
+ private static Log log = LogFactory.getLog(ClassClassLoaderStrategy.class);
+
+ /** The caller resolver */
+ private static CallerResolver callerResolver;
+
+ // Robust way of creating of the caller resolver
+ static {
+ try {
+ // This can fail if the current SecurityManager does not allow
+ // RuntimePermission ("createSecurityManager"):
+ callerResolver = new CallerResolver();
+ } catch (SecurityException se) {
+ // set callerResolver to null and log
+ log.error("Class class loader resolver could not be created because of SecurityException " +
+ " just using the class loader of the classclassloader class, error msg: " + se.getMessage(), se);
+ callerResolver = null;
+ }
+ }
+
+ /**
+ * Indexes into the current method call context with a given offset.
+ */
+ private static Class<?> getCallerClass(int callerOffset) {
+ if (callerResolver == null) {
+ return ClassClassLoaderStrategy.class;
+ }
+ return callerResolver.getClassContext()[callerOffset];
+ }
+
+ /**
+ * Based on examples in
+ * http://www.javaworld.com/javaworld/javaqa/2003-06/01-qa-0606-load-p2.html
+ *
+ * A helper class to get the call context. It subclasses SecurityManager to make
+ * getClassContext() accessible. An instance of CallerResolver only needs to be created, not
+ * installed as an actual security manager.
+ */
+ private static final class CallerResolver extends SecurityManager {
+ protected Class<?>[] getClassContext() {
+ final Class<?>[] clsContext = super.getClassContext();
+ return clsContext;
+ }
+ }
+
+ /**
+ * Just returns the classClassLoader
+ */
+ public ClassLoader getClassLoader() {
+ /*
+ * 0: SecurityManager.getClassContext 1: getClassContext 2: getCallerClass 3: getClassLoader
+ * 4: ClassLoaderResolver.getClassLoader 5: app class
+ */
+ final Class<?> clazz = getCallerClass(5);
+ return clazz.getClassLoader();
+ }
+}
diff --git a/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/classloader/ClassLoaderResolver.java b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/classloader/ClassLoaderResolver.java
new file mode 100755
index 000000000..26e48f475
--- /dev/null
+++ b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/classloader/ClassLoaderResolver.java
@@ -0,0 +1,76 @@
+/**
+ * <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: ClassLoaderResolver.java,v 1.6 2009/03/30 07:53:04 mtaal Exp $
+ */
+
+package org.eclipse.emf.teneo.classloader;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.eclipse.emf.teneo.TeneoException;
+
+/**
+ * Is responsible for determining which class loader to use.
+ *
+ * @author <a href="mailto:mtaal@elver.org">Martin Taal</a>
+ * @version $Revision: 1.6 $
+ */
+
+public class ClassLoaderResolver {
+ /** The logger */
+ private static Log log = LogFactory.getLog(ClassClassLoaderStrategy.class);
+
+ /** The classloader strategy used */
+ private static ClassLoaderStrategy classLoaderStrategy;
+
+ /** Static initializer */
+ static {
+ try {
+ setClassLoaderStrategy(new ContextClassLoaderStrategy());
+ } catch (Exception e) {
+ throw new TeneoException("Exception when setting default class loader strategy", e);
+ }
+ }
+
+ /** Returns a class based on the name */
+ public static Class<?> classForName(String name) {
+ try {
+ return Class.forName(name, true, getClassLoader());
+ } catch (Exception e) {
+ throw new StoreClassLoadException("Class for name exception ", e);
+ }
+ }
+
+ /** Return a classloader */
+ public static ClassLoader getClassLoader() {
+ return classLoaderStrategy.getClassLoader();
+ }
+
+ /**
+ * @return Returns the classLoaderStrategy.
+ */
+ public static ClassLoaderStrategy getClassLoaderStrategy() {
+ return classLoaderStrategy;
+ }
+
+ /**
+ * @param classLoaderStrategy
+ * The classLoaderStrategy to set.
+ */
+ public static void setClassLoaderStrategy(ClassLoaderStrategy classLoaderStrategy) {
+ ClassLoaderResolver.classLoaderStrategy = classLoaderStrategy;
+ log.info("Class loader strategy set to: " + classLoaderStrategy.getClass().getName());
+ }
+}
diff --git a/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/classloader/ClassLoaderStrategy.java b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/classloader/ClassLoaderStrategy.java
new file mode 100755
index 000000000..85850f54e
--- /dev/null
+++ b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/classloader/ClassLoaderStrategy.java
@@ -0,0 +1,32 @@
+/**
+ * <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: ClassLoaderStrategy.java,v 1.6 2009/03/30 06:41:00 mtaal Exp $
+ */
+
+package org.eclipse.emf.teneo.classloader;
+
+/**
+ * Interface for classes which determine which classloader to use.
+ *
+ * @author <a href="mailto:mtaal@elver.org">Martin Taal</a>
+ * @version $Revision: 1.6 $
+ */
+
+public interface ClassLoaderStrategy {
+ /**
+ * Return the classloader
+ */
+ public ClassLoader getClassLoader();
+}
diff --git a/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/classloader/ContextClassLoaderStrategy.java b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/classloader/ContextClassLoaderStrategy.java
new file mode 100755
index 000000000..98393ed34
--- /dev/null
+++ b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/classloader/ContextClassLoaderStrategy.java
@@ -0,0 +1,35 @@
+/**
+ * <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: ContextClassLoaderStrategy.java,v 1.3 2008/02/28 07:08:33 mtaal Exp $
+ */
+
+package org.eclipse.emf.teneo.classloader;
+
+/**
+ * Returns the context class loader.
+ *
+ * @author <a href="mailto:mtaal@elver.org">Martin Taal</a>
+ * @version $Revision: 1.3 $
+ */
+
+public class ContextClassLoaderStrategy implements ClassLoaderStrategy {
+ /**
+ * Returns the context class loader
+ */
+ public ClassLoader getClassLoader() {
+ return Thread.currentThread().getContextClassLoader();
+ }
+
+}
diff --git a/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/classloader/StoreClassLoadException.java b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/classloader/StoreClassLoadException.java
new file mode 100755
index 000000000..9b8e6f753
--- /dev/null
+++ b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/classloader/StoreClassLoadException.java
@@ -0,0 +1,49 @@
+/**
+ * <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: StoreClassLoadException.java,v 1.5 2008/02/28 07:08:33 mtaal Exp $
+ */
+
+package org.eclipse.emf.teneo.classloader;
+
+import org.eclipse.emf.teneo.TeneoException;
+
+/**
+ * Is used to throw exception when getting a class in the classloader
+ *
+ * @author <a href="mailto:mtaal@elver.org">Martin Taal</a>
+ * @version $Revision: 1.5 $
+ */
+
+public class StoreClassLoadException extends TeneoException {
+
+ /**
+ * Serial ID
+ */
+ private static final long serialVersionUID = -952752250000575101L;
+
+ /**
+ * The constructor, logs the exception also
+ */
+ public StoreClassLoadException(String msg, Throwable cause) {
+ super(msg, cause);
+ }
+
+ /**
+ * The constructor, logs the exception also
+ */
+ public StoreClassLoadException(String msg) {
+ super(msg);
+ }
+}
diff --git a/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/ecore/EModelResolver.java b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/ecore/EModelResolver.java
new file mode 100755
index 000000000..3ca0eebfe
--- /dev/null
+++ b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/ecore/EModelResolver.java
@@ -0,0 +1,107 @@
+/**
+ * <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: EModelResolver.java,v 1.9 2009/03/30 07:53:05 mtaal Exp $
+ */
+
+package org.eclipse.emf.teneo.ecore;
+
+import java.util.List;
+
+import org.eclipse.emf.ecore.EClass;
+import org.eclipse.emf.ecore.EClassifier;
+import org.eclipse.emf.ecore.EPackage;
+import org.eclipse.emf.teneo.ERuntime;
+
+/**
+ * The EModelResolver allows pluggable access to the underlying ecore model. It maps from
+ * eclass/efeature names to java member names or to real eclass names. This default implementation
+ * only returns null.
+ *
+ * @author <a href="mtaal@elver.org">Martin Taal</a>
+ */
+public abstract class EModelResolver {
+
+ /** The default instance of an EcoreResolver */
+ private static EModelResolver instance = null;
+
+ /** Return the current ecore resolver */
+ public static EModelResolver instance() {
+ if (instance == null) {
+ instance = ERuntime.INSTANCE;
+ }
+ return instance;
+ }
+
+ /** Set an EcoreResolver */
+ public static void setInstance(EModelResolver modelResolver) {
+ instance = modelResolver;
+ }
+
+ /** Clear all internal datastructures */
+ public abstract void clear();
+
+ /**
+ * @return the EClass for a java class, if not found then the superclass of the javaclass is
+ * tried
+ */
+ public abstract EClass getEClass(Class<?> javaClass);
+
+ /** Is the epackage registered */
+ public abstract boolean isRegistered(EPackage epackage);
+
+ /** Register the epackages */
+ public abstract void register(EPackage[] epacks);
+
+ /** @return all java classes and interfaces */
+ public abstract List<Class<?>> getAllClassesAndInterfaces();
+
+ /** @return the java implementation class for an EClass */
+ public abstract Class<?> getJavaClass(EClassifier eclassifier);
+
+ /** @return the java interface class for an EClass */
+ public abstract Class<?> getJavaInterfaceClass(EClass eclass);
+
+ /** Returns true if the passed EClass has a javaClass representation. */
+ public abstract boolean hasImplementationClass(EClassifier eclassifier);
+
+ /** Returns the currently registered epackages */
+ public abstract EPackage[] getEPackages();
+
+ /** Returns null */
+ public abstract Object create(EClass eclass);
+
+ /** Returns a java instance of an EClass defined by name */
+ public Object create(EPackage epackage, String eclassName) {
+ final EClass eclass = (EClass) epackage.getEClassifier(eclassName);
+ if (eclass == null) {
+ throw new IllegalArgumentException("No EClass " + eclassName + " found in epackage " + epackage.getName());
+ }
+ return create(eclass);
+ }
+
+ /**
+ * Returns a java instance of an EClass defined by name, all epackages are searched for this
+ * eclass.
+ */
+ public Object create(String eclassName) {
+ for (EPackage epackage : getEPackages()) {
+ final EClass eclass = (EClass) epackage.getEClassifier(eclassName);
+ if (eclass != null) {
+ return create(eclass);
+ }
+ }
+ throw new IllegalArgumentException("No EClass " + eclassName + " found.");
+ }
+} \ No newline at end of file
diff --git a/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/extension/DatastoreAware.java b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/extension/DatastoreAware.java
new file mode 100755
index 000000000..e83eb2e4c
--- /dev/null
+++ b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/extension/DatastoreAware.java
@@ -0,0 +1,32 @@
+/**
+ * <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: DatastoreAware.java,v 1.4 2009/03/30 07:53:04 mtaal Exp $
+ */
+
+package org.eclipse.emf.teneo.extension;
+
+import org.eclipse.emf.teneo.DataStore;
+
+/**
+ * An extension implementing this interface will be able to 'receive' an instance of a Pamodel.
+ *
+ * @author <a href="mailto:mtaal@elver.org">Martin Taal</a>
+ * @version $Revision: 1.4 $
+ */
+
+public interface DatastoreAware {
+ /** Set the relevant pamodel */
+ void setDatastore(DataStore dataStore);
+} \ No newline at end of file
diff --git a/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/extension/DefaultExtensionManager.java b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/extension/DefaultExtensionManager.java
new file mode 100755
index 000000000..e92bf87aa
--- /dev/null
+++ b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/extension/DefaultExtensionManager.java
@@ -0,0 +1,286 @@
+/**
+ * <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: DefaultExtensionManager.java,v 1.9 2009/05/22 21:35:10 mtaal Exp $
+ */
+
+package org.eclipse.emf.teneo.extension;
+
+import java.lang.reflect.Constructor;
+import java.util.concurrent.ConcurrentHashMap;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.eclipse.emf.teneo.classloader.ClassLoaderResolver;
+
+/**
+ * Manages a set of extensions. Currently for each extension point there will always be only one extension instance.
+ *
+ * @author <a href="mailto:mtaal@elver.org">Martin Taal</a>
+ * @version $Revision: 1.9 $
+ */
+
+public class DefaultExtensionManager implements ExtensionManager {
+
+ private static Log log = LogFactory.getLog(DefaultExtensionManager.class);
+
+ // Uses the default for now
+ private ConcurrentHashMap<String, Extension> extensionRegistry = new ConcurrentHashMap<String, Extension>();
+
+ // The instances of the extensions
+ private ConcurrentHashMap<String, ExtensionPoint> extensionInstances = new ConcurrentHashMap<String, ExtensionPoint>();
+
+ // The constructor cache
+ private ConcurrentHashMap<String, Constructor<?>> constructorCache = new ConcurrentHashMap<String, Constructor<?>>();
+
+ public DefaultExtensionManager() {
+ ExtensionUtil.registerDefaultExtensions(this);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.emf.teneo.extension.ExtensionManager#registerExtension(org
+ * .eclipse.emf.teneo.extension.Extension)
+ */
+ public void registerExtension(Extension extension) {
+ // check if there is already a non-default plugin registered with the
+ // same name
+ if (extension.isDefaultExtension()) {
+ final Extension currentExtension = extensionRegistry.get(extension.getPoint());
+ if (currentExtension != null && !currentExtension.isDefaultExtension()) {
+ log.debug("Not registering extension " + extension);
+ log.debug("There is already a user plugin defined: " + currentExtension);
+ return;
+ }
+ }
+ if (extension.getPoint() == null) {
+ throw new TeneoExtensionException("Point of extension may not be null");
+ }
+ if (extension.getClassName() == null) {
+ throw new TeneoExtensionException("Classname of extension: " + extension.getPoint() + " may not be null");
+ }
+ log.debug("Registering " + extension);
+ extensionRegistry.put(extension.getPoint(), extension);
+
+ // remove any instances for this extension
+ extensionInstances.remove(extension.getPoint());
+ }
+
+ public void registerExtension(String point, String className) {
+ final Extension currentExtension = extensionRegistry.get(point);
+ if (currentExtension == null) {
+ throw new TeneoExtensionException("No default extension found using point: " + point
+ + " is the point value correct?");
+ }
+ final Extension newExtension = new Extension();
+ newExtension.setPoint(point);
+ newExtension.setClassName(className);
+ newExtension.setDefaultExtension(false);
+ newExtension.setSingleton(currentExtension.isSingleton());
+ registerExtension(newExtension);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.emf.teneo.extension.ExtensionManager#getExtension(java.lang .String)
+ */
+ public ExtensionPoint getExtension(String point, Object[] initArgs) {
+ log.debug("Searching extension " + point);
+ final Extension extension = extensionRegistry.get(point);
+ if (extension == null) {
+ throw new TeneoExtensionException("Extension point " + point + " not registered");
+ }
+
+ if (extension.isSingleton()) {
+ final ExtensionPoint extensionInstance = extensionInstances.get(point);
+ if (extensionInstance != null) {
+ log.debug("Found instance " + extensionInstance.getClass().getClass());
+ return extensionInstance;
+ }
+ }
+
+ // get the clz
+ // note that before the classloader was retrieved as an extension
+ // however this is not logical, always use the classloaderresolver for
+ // this
+ final Class<?> clz = ClassLoaderResolver.classForName(extension.getClassName());
+
+ // check if this class indeed implements ExtensionPoint
+ if (!(ExtensionPoint.class.isAssignableFrom(clz))) {
+ throw new TeneoExtensionException("The requested extension " + clz.getName()
+ + " does not implement the interface " + ExtensionPoint.class.getName());
+ }
+
+ try {
+ final boolean constructorUsed;
+ final ExtensionPoint extensionInstance;
+ if (initArgs == null || initArgs.length == 0) { // use default
+ // constructor
+ constructorUsed = false;
+ extensionInstance = (ExtensionPoint) clz.newInstance();
+ } else {
+ log.debug("Initargs passed, using constructor for class " + clz.getName());
+ constructorUsed = true;
+ final Constructor<?> constructor = getConstructor(clz, initArgs);
+ extensionInstance = (ExtensionPoint) constructor.newInstance(initArgs);
+ }
+ log.debug("Created extensionPoint instance: " + extensionInstance.getClass().getName());
+
+ if (extensionInstance instanceof ExtensionManagerAware) {
+ ((ExtensionManagerAware) extensionInstance).setExtensionManager(this);
+ }
+
+ if (extensionInstance instanceof ExtensionInitializable) {
+ log.debug("Initializing extension " + extensionInstance.getClass().getName());
+ ((ExtensionInitializable) extensionInstance).initializeExtension();
+ }
+
+ // note if a constructor is used instances are never cached because
+ // we assume
+ // that instances always differ
+ if (extension.isSingleton() && !constructorUsed) {
+ log.debug("Caching extension instance as singleton " + extension);
+ extensionInstances.put(point, extensionInstance);
+
+ // now see if the extensioninstance also implements other
+ // extensionpoints
+ registerForAllExtensionPoints(extensionInstance.getClass(), extensionInstance);
+ }
+ if (extension.isSingleton() && constructorUsed) {
+ // disabled as it is not so meaningfull
+ // log.warn("The extension: " + extension.getPoint() +
+ // " is declared as a singleton but this getInstance call " +
+ // " passed initialization parameters so it is not cached, " + clz.getName());
+ }
+
+ return extensionInstance;
+ } catch (Exception e) {
+ throw new TeneoExtensionException("Exception while instantiating: " + extension.getClassName(), e);
+ }
+ }
+
+ /** Return the constructor for a class and initialization arguments */
+ protected Constructor<?> getConstructor(Class<?> clz, Object[] initArgs) throws NoSuchMethodException {
+ Constructor<?> result = null;
+ final Class<?>[] initTypes = new Class<?>[initArgs.length];
+ int i = 0;
+ final StringBuffer keyStr = new StringBuffer();
+ for (Object o : initArgs) {
+ if (keyStr.length() > 0) {
+ keyStr.append(",");
+ }
+ if (o == null) {
+ initTypes[i++] = null;
+ keyStr.append("null");
+ } else {
+ initTypes[i++] = o.getClass();
+ keyStr.append(o.getClass().getName());
+ }
+ }
+
+ final String key = clz.getName() + keyStr;
+
+ if ((result = constructorCache.get(key)) != null) {
+ return result;
+ }
+
+ for (Constructor<?> constructor : clz.getConstructors()) {
+ if (constructor.getParameterTypes().length != initTypes.length) {
+ continue;
+ }
+ int j = 0;
+ boolean found = true;
+ for (Class<?> paramType : constructor.getParameterTypes()) {
+ final Class<?> argumentType = initTypes[j++];
+ if (argumentType == null && !Object.class.isAssignableFrom(paramType)) {
+ found = false;
+ break;
+ } else if (argumentType == null && Object.class.isAssignableFrom(paramType)) {
+ // just continue
+ } else if (!paramType.isAssignableFrom(argumentType)) {
+ found = false;
+ break;
+ }
+ }
+ if (found) {
+ result = constructor;
+ constructorCache.put(key, result);
+ break;
+ }
+ }
+ if (result == null) {
+ throw new TeneoExtensionException("No constructor found for : " + clz.getName()
+ + " and constructor argument types: " + keyStr);
+ }
+ return result;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.emf.teneo.extension.ExtensionManager#getExtension(java.lang .Class)
+ */
+ @SuppressWarnings("unchecked")
+ public <T> T getExtension(Class<T> clz) {
+ return (T) getExtension(clz.getName(), null);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.emf.teneo.extension.ExtensionManager#getExtension(java.lang .Class)
+ */
+ @SuppressWarnings("unchecked")
+ public <T> T getExtension(Class<T> clz, Object[] initArgs) {
+ return (T) getExtension(clz.getName(), initArgs);
+ }
+
+ /**
+ * Registers an instance for all other extensionpoints it implements if no other instance was already registered for
+ * it.
+ */
+ private void registerForAllExtensionPoints(Class<?> cls, ExtensionPoint extensionInstance) {
+ if (cls == null) {
+ return;
+ }
+
+ // for its interfaces
+ for (Class<?> interf : cls.getInterfaces()) {
+ checkRegister(extensionRegistry.get(interf.getName()), extensionInstance);
+ }
+
+ // and for the class itself
+ checkRegister(extensionRegistry.get(cls.getName()), extensionInstance);
+
+ // and not the superclass, the check for null is done in the method
+ // itself
+ registerForAllExtensionPoints(cls.getSuperclass(), extensionInstance);
+ }
+
+ // register the passed instance if it implements the extension and its class
+ // is registered for that extension
+ private void checkRegister(Extension extension, ExtensionPoint extensionInstance) {
+ if (extension == null) {
+ return;
+ }
+ if (extension.getClassName().compareTo(extensionInstance.getClass().getName()) == 0 && extension.isSingleton()
+ && extensionInstances.get(extension.getPoint()) == null) {
+ log.debug("Also registering extensioninstance: " + extensionInstance.getClass().getName()
+ + " for extension " + extension.getPoint());
+ extensionInstances.put(extension.getPoint(), extensionInstance);
+ }
+ }
+} \ No newline at end of file
diff --git a/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/extension/Extension.java b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/extension/Extension.java
new file mode 100755
index 000000000..8f85e3e6c
--- /dev/null
+++ b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/extension/Extension.java
@@ -0,0 +1,109 @@
+/**
+ * <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: Extension.java,v 1.4 2009/03/30 07:53:04 mtaal Exp $
+ */
+
+package org.eclipse.emf.teneo.extension;
+
+/**
+ * An Extension sets a certain ExtensionPoint in Teneo. Teneo will register default Extensions which
+ * can be overridden by a user.
+ *
+ * @author <a href="mailto:mtaal@elver.org">Martin Taal</a>
+ * @version $Revision: 1.4 $
+ */
+
+public class Extension {
+
+ // the extension point id, normally a classname of an ExtensionPoint
+ private String point;
+
+ // the classname of the extensionpoint implementor
+ private String className;
+
+ // Is this a default extension registered by Teneo or a user plugin
+ private boolean defaultExtension = false;
+
+ // Is this a singleton within one ExtensionManager, default is true
+ private boolean singleton = true;
+
+ /**
+ * @return the point
+ */
+ public String getPoint() {
+ return point;
+ }
+
+ /**
+ * @param point
+ * the point to set
+ */
+ public void setPoint(String point) {
+ this.point = point;
+ }
+
+ /**
+ * @return the className
+ */
+ public String getClassName() {
+ return className;
+ }
+
+ /**
+ * @param className
+ * the className to set
+ */
+ public void setClassName(String className) {
+ this.className = className;
+ }
+
+ /**
+ * @return the defaultExtension
+ */
+ public boolean isDefaultExtension() {
+ return defaultExtension;
+ }
+
+ /**
+ * Default is false, this is the correct value for extensions created by users of Teneo. So
+ * normally this method does not need to be called.
+ *
+ * @param defaultExtension
+ * the defaultExtension to set
+ */
+ public void setDefaultExtension(boolean defaultExtension) {
+ this.defaultExtension = defaultExtension;
+ }
+
+ @Override
+ public String toString() {
+ return " point: " + getPoint() + " classname: " + getClassName() + " default: " + isDefaultExtension();
+ }
+
+ /**
+ * @return the singleton
+ */
+ public boolean isSingleton() {
+ return singleton;
+ }
+
+ /**
+ * @param singleton
+ * the singleton to set
+ */
+ public void setSingleton(boolean singleton) {
+ this.singleton = singleton;
+ }
+} \ No newline at end of file
diff --git a/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/extension/ExtensionInitializable.java b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/extension/ExtensionInitializable.java
new file mode 100755
index 000000000..94d0b76a4
--- /dev/null
+++ b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/extension/ExtensionInitializable.java
@@ -0,0 +1,31 @@
+/**
+ * <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: ExtensionInitializable.java,v 1.4 2009/03/30 07:53:04 mtaal Exp $
+ */
+
+package org.eclipse.emf.teneo.extension;
+
+/**
+ * Defines an initialize method which is called after creating the object and after setting the
+ * extensionmanager (if the object is ExtensionManagerAware).
+ *
+ * @author <a href="mailto:mtaal@elver.org">Martin Taal</a>
+ * @version $Revision: 1.4 $
+ */
+
+public interface ExtensionInitializable {
+ /** Initialize the object */
+ void initializeExtension();
+} \ No newline at end of file
diff --git a/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/extension/ExtensionManager.java b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/extension/ExtensionManager.java
new file mode 100755
index 000000000..a8357a779
--- /dev/null
+++ b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/extension/ExtensionManager.java
@@ -0,0 +1,60 @@
+/**
+ * <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: ExtensionManager.java,v 1.6 2009/03/30 07:53:04 mtaal Exp $
+ */
+
+package org.eclipse.emf.teneo.extension;
+
+/**
+ * Manages a set of extensions. Currently for each extension point there will always be only one
+ * extension instance.
+ *
+ * @author <a href="mailto:mtaal@elver.org">Martin Taal</a>
+ * @version $Revision: 1.6 $
+ */
+public interface ExtensionManager {
+
+ /**
+ * Register an extension. If there is already a non-default extension registered then it is not
+ * overwritten.
+ */
+ public abstract void registerExtension(Extension extension);
+
+ /**
+ * Return an instance of an extension, pass null if no constructor arguments are required for
+ * this extension
+ */
+ public abstract ExtensionPoint getExtension(String point, Object[] initArgs);
+
+ /**
+ * Convenience method which also performs the casting and uses the classname of the class
+ * parameter to search for the plugin.
+ */
+ public abstract <T> T getExtension(Class<T> clz);
+
+ /**
+ * Convenience method which also performs the casting and uses the classname of the class
+ * parameter to search for the plugin.
+ */
+ public abstract <T> T getExtension(Class<T> clz, Object[] initArgs);
+
+ /**
+ * Convenience method to register a user extension overriding a current extension. It will
+ * search for an existing extension using the point. If not found then an exception is thrown.
+ * In case a completely new extension is to be registered then use the registerExtension method.
+ * The singleton value from the existing extension is used. value is used from that extension.
+ */
+ public void registerExtension(String point, String className);
+} \ No newline at end of file
diff --git a/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/extension/ExtensionManagerAware.java b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/extension/ExtensionManagerAware.java
new file mode 100755
index 000000000..abab306e4
--- /dev/null
+++ b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/extension/ExtensionManagerAware.java
@@ -0,0 +1,31 @@
+/**
+ * <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: ExtensionManagerAware.java,v 1.4 2009/03/30 07:53:04 mtaal Exp $
+ */
+
+package org.eclipse.emf.teneo.extension;
+
+/**
+ * An extension implementing this interface will be able to 'receive' an instance of the
+ * ExtensionManager which created it.
+ *
+ * @author <a href="mailto:mtaal@elver.org">Martin Taal</a>
+ * @version $Revision: 1.4 $
+ */
+
+public interface ExtensionManagerAware {
+ /** Set the extensionManager */
+ void setExtensionManager(ExtensionManager extensionManager);
+} \ No newline at end of file
diff --git a/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/extension/ExtensionManagerFactory.java b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/extension/ExtensionManagerFactory.java
new file mode 100755
index 000000000..04675124b
--- /dev/null
+++ b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/extension/ExtensionManagerFactory.java
@@ -0,0 +1,48 @@
+/**
+ * <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: ExtensionManagerFactory.java,v 1.4 2009/03/30 07:53:04 mtaal Exp $
+ */
+
+package org.eclipse.emf.teneo.extension;
+
+/**
+ * Factory which creates ExtensionManagers. A customer factory can be set by calling setInstance().
+ *
+ * @author <a href="mailto:mtaal@elver.org">Martin Taal</a>
+ * @version $Revision: 1.4 $
+ */
+public class ExtensionManagerFactory {
+
+ private static ExtensionManagerFactory instance = new ExtensionManagerFactory();
+
+ /**
+ * @return the instance
+ */
+ public static ExtensionManagerFactory getInstance() {
+ return instance;
+ }
+
+ /**
+ * @param instance
+ * the instance to set
+ */
+ public static void setInstance(ExtensionManagerFactory instance) {
+ ExtensionManagerFactory.instance = instance;
+ }
+
+ public ExtensionManager create() {
+ return new DefaultExtensionManager();
+ }
+} \ No newline at end of file
diff --git a/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/extension/ExtensionPoint.java b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/extension/ExtensionPoint.java
new file mode 100755
index 000000000..29ed16a3d
--- /dev/null
+++ b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/extension/ExtensionPoint.java
@@ -0,0 +1,30 @@
+/**
+ * <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: ExtensionPoint.java,v 1.4 2009/03/30 07:53:04 mtaal Exp $
+ */
+
+package org.eclipse.emf.teneo.extension;
+
+/**
+ * Is a marker interface to mark a class to be replacable by a user extension. The classname or
+ * interface implementing this interface is also the name of the ExtensionPoint (the value of the
+ * point attribute in the extension).
+ *
+ * @author <a href="mailto:mtaal@elver.org">Martin Taal</a>
+ * @version $Revision: 1.4 $
+ */
+
+public interface ExtensionPoint {
+} \ No newline at end of file
diff --git a/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/extension/ExtensionUtil.java b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/extension/ExtensionUtil.java
new file mode 100755
index 000000000..315ad62d8
--- /dev/null
+++ b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/extension/ExtensionUtil.java
@@ -0,0 +1,302 @@
+/**
+ * <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: ExtensionUtil.java,v 1.17 2011/10/29 06:12:49 mtaal Exp $
+ */
+
+package org.eclipse.emf.teneo.extension;
+
+import org.eclipse.emf.teneo.PersistenceOptions;
+import org.eclipse.emf.teneo.annotations.mapper.AnnotationGenerator;
+import org.eclipse.emf.teneo.annotations.mapper.BasicPamodelBuilder;
+import org.eclipse.emf.teneo.annotations.mapper.BidirectionalManyToManyAnnotator;
+import org.eclipse.emf.teneo.annotations.mapper.EClassAnnotator;
+import org.eclipse.emf.teneo.annotations.mapper.EDataTypeAnnotator;
+import org.eclipse.emf.teneo.annotations.mapper.EFeatureAnnotator;
+import org.eclipse.emf.teneo.annotations.mapper.ManyToOneReferenceAnnotator;
+import org.eclipse.emf.teneo.annotations.mapper.OneToManyAttributeAnnotator;
+import org.eclipse.emf.teneo.annotations.mapper.OneToManyReferenceAnnotator;
+import org.eclipse.emf.teneo.annotations.mapper.OneToOneReferenceAnnotator;
+import org.eclipse.emf.teneo.annotations.mapper.PersistenceFileProvider;
+import org.eclipse.emf.teneo.annotations.mapper.PersistenceMappingBuilder;
+import org.eclipse.emf.teneo.annotations.mapper.SingleAttributeAnnotator;
+import org.eclipse.emf.teneo.annotations.mapper.UnidirectionalManyToManyAnnotator;
+import org.eclipse.emf.teneo.annotations.parser.EAnnotationParserImporter;
+import org.eclipse.emf.teneo.annotations.xml.XmlElementToEStructuralFeatureMapper;
+import org.eclipse.emf.teneo.annotations.xml.XmlPersistenceContentHandler;
+import org.eclipse.emf.teneo.annotations.xml.XmlPersistenceMapper;
+import org.eclipse.emf.teneo.mapping.strategy.EntityNameStrategy;
+import org.eclipse.emf.teneo.mapping.strategy.SQLNameStrategy;
+import org.eclipse.emf.teneo.mapping.strategy.impl.EntityResolvingNameStrategy;
+import org.eclipse.emf.teneo.mapping.strategy.impl.TeneoSQLNameStrategy;
+
+/**
+ * Contains simple utility methods.
+ *
+ * @author <a href="mailto:mtaal@elver.org">Martin Taal</a>
+ * @version $Revision: 1.17 $
+ */
+
+public class ExtensionUtil {
+
+ /** Creates a default extension */
+ public static Extension createExtension(Class<?> extensionPoint,
+ Class<?> clz) {
+ return createExtension(extensionPoint, clz, true);
+ }
+
+ public static Extension createExtension(Class<?> extensionPoint,
+ Class<?> clz, boolean defaultExtension) {
+ final Extension extension = new Extension();
+ extension.setPoint(extensionPoint.getName());
+ extension.setClassName(clz.getName());
+ extension.setDefaultExtension(defaultExtension);
+ return extension;
+ }
+
+ public static Extension createExtension(String pointClassName,
+ boolean singleton) {
+ final Extension extension = new Extension();
+ extension.setPoint(pointClassName);
+ extension.setClassName(pointClassName);
+ extension.setDefaultExtension(true);
+ extension.setSingleton(singleton);
+ return extension;
+ }
+
+ public static Extension createExtension(String pointClassName,
+ String className, boolean singleton) {
+ final Extension extension = new Extension();
+ extension.setPoint(pointClassName);
+ extension.setClassName(className);
+ extension.setDefaultExtension(true);
+ extension.setSingleton(singleton);
+ return extension;
+ }
+
+ /** Register a number of default Extensions */
+ public static void registerDefaultExtensions(ExtensionManager em) {
+
+ // the ones coming from this plugin
+ em.registerExtension(createExtension(BasicPamodelBuilder.class,
+ BasicPamodelBuilder.class));
+ em.registerExtension(createExtension(AnnotationGenerator.class,
+ AnnotationGenerator.class));
+ em.registerExtension(createExtension(EAnnotationParserImporter.class,
+ EAnnotationParserImporter.class));
+ em.registerExtension(createExtension(PersistenceMappingBuilder.class,
+ PersistenceMappingBuilder.class));
+ em.registerExtension(createExtension(XmlPersistenceMapper.class,
+ XmlPersistenceMapper.class));
+
+ em.registerExtension(createExtension(PersistenceFileProvider.class,
+ PersistenceFileProvider.class));
+
+ // from now on always use the classloader
+ // em.registerExtension(createExtension(ClassLoaderStrategy.class,
+ // ContextClassLoaderStrategy.class));
+ em.registerExtension(createExtension(EntityNameStrategy.class,
+ EntityResolvingNameStrategy.class));
+ em.registerExtension(createExtension(SQLNameStrategy.class,
+ TeneoSQLNameStrategy.class));
+ em.registerExtension(createExtension(
+ XmlPersistenceContentHandler.class,
+ XmlPersistenceContentHandler.class));
+ em.registerExtension(createExtension(
+ XmlElementToEStructuralFeatureMapper.class,
+ XmlElementToEStructuralFeatureMapper.class));
+ em.registerExtension(createExtension(PersistenceOptions.class,
+ PersistenceOptions.class));
+
+ // annotator related
+ em.registerExtension(createExtension(EClassAnnotator.class,
+ EClassAnnotator.class));
+ em.registerExtension(createExtension(EFeatureAnnotator.class,
+ EFeatureAnnotator.class));
+ em.registerExtension(createExtension(OneToManyAttributeAnnotator.class,
+ OneToManyAttributeAnnotator.class));
+ em.registerExtension(createExtension(SingleAttributeAnnotator.class,
+ SingleAttributeAnnotator.class));
+ em.registerExtension(createExtension(
+ BidirectionalManyToManyAnnotator.class,
+ BidirectionalManyToManyAnnotator.class));
+ em.registerExtension(createExtension(
+ UnidirectionalManyToManyAnnotator.class,
+ UnidirectionalManyToManyAnnotator.class));
+ em.registerExtension(createExtension(EDataTypeAnnotator.class,
+ EDataTypeAnnotator.class));
+ em.registerExtension(createExtension(OneToManyReferenceAnnotator.class,
+ OneToManyReferenceAnnotator.class));
+ em.registerExtension(createExtension(OneToOneReferenceAnnotator.class,
+ OneToOneReferenceAnnotator.class));
+ em.registerExtension(createExtension(ManyToOneReferenceAnnotator.class,
+ ManyToOneReferenceAnnotator.class));
+
+ // from the hibernate plugin
+ em.registerExtension(createExtension(
+ "org.eclipse.emf.teneo.hibernate.HbContext", true));
+ em.registerExtension(createExtension(
+ "org.eclipse.emf.teneo.hibernate.mapping.econtainer.EContainerAccessor",
+ false));
+ em.registerExtension(createExtension(
+ "org.eclipse.emf.teneo.hibernate.mapping.econtainer.EContainerFeatureIDAccessor",
+ false));
+ em.registerExtension(createExtension(
+ "org.eclipse.emf.teneo.hibernate.mapping.econtainer.EContainerFeatureIDPropertyHandler",
+ false));
+ em.registerExtension(createExtension(
+ "org.eclipse.emf.teneo.hibernate.mapping.econtainer.EContainerPropertyHandler",
+ false));
+
+ em.registerExtension(createExtension(
+ "org.eclipse.emf.teneo.hibernate.mapping.property.EListPropertyHandler",
+ false));
+ em.registerExtension(createExtension(
+ "org.eclipse.emf.teneo.hibernate.mapping.property.EReferencePropertyHandler",
+ false));
+ em.registerExtension(createExtension(
+ "org.eclipse.emf.teneo.hibernate.mapping.property.FeatureMapEntryFeatureURIPropertyHandler",
+ false));
+ em.registerExtension(createExtension(
+ "org.eclipse.emf.teneo.hibernate.mapping.property.WildCardAttributePropertyHandler",
+ false));
+ em.registerExtension(createExtension(
+ "org.eclipse.emf.teneo.hibernate.mapping.property.WildCardReferencePropertyHandler",
+ false));
+
+ em.registerExtension(createExtension(
+ "org.eclipse.emf.teneo.hibernate.mapping.econtainer.NewEContainerFeatureIDPropertyHandler",
+ false));
+
+ em.registerExtension(createExtension(
+ "org.eclipse.emf.teneo.hibernate.mapping.property.FeatureMapEntryPropertyHandler",
+ false));
+ em.registerExtension(createExtension(
+ "org.eclipse.emf.teneo.hibernate.mapping.property.FeatureMapPropertyHandler",
+ false));
+ em.registerExtension(createExtension(
+ "org.eclipse.emf.teneo.hibernate.mapping.property.VersionPropertyHandler",
+ false));
+ em.registerExtension(createExtension(
+ "org.eclipse.emf.teneo.hibernate.EMFInterceptor", false));
+
+ em.registerExtension(createExtension(
+ "org.eclipse.emf.teneo.hibernate.tuplizer.EMFEntityNameResolver",
+ false));
+
+ em.registerExtension(createExtension(
+ "org.eclipse.emf.teneo.hibernate.mapping.elist.HibernatePersistableEList",
+ false));
+ em.registerExtension(createExtension(
+ "org.eclipse.emf.teneo.hibernate.mapping.elist.HibernatePersistableEMap",
+ false));
+ em.registerExtension(createExtension(
+ "org.eclipse.emf.teneo.hibernate.mapping.elist.HibernatePersistableFeatureMap",
+ false));
+ em.registerExtension(createExtension(
+ "org.eclipse.emf.teneo.hibernate.mapping.elist.HbExtraLazyPersistableEList",
+ false));
+ em.registerExtension(createExtension(
+ "org.eclipse.emf.teneo.hibernate.mapping.elist.HbExtraLazyPersistableEMap",
+ false));
+ em.registerExtension(createExtension(
+ "org.eclipse.emf.teneo.hibernate.mapping.elist.MapHibernatePersistableEMap",
+ false));
+
+ // hibernate mapper
+ em.registerExtension(createExtension(
+ "org.eclipse.emf.teneo.hibernate.mapper.HibernateMappingGenerator",
+ false));
+ em.registerExtension(createExtension(
+ "org.eclipse.emf.teneo.hibernate.mapper.MappingContext", false));
+ em.registerExtension(createExtension(
+ "org.eclipse.emf.teneo.hibernate.mapper.BasicMapper", false));
+ em.registerExtension(createExtension(
+ "org.eclipse.emf.teneo.hibernate.mapper.EmbeddedMapper", false));
+ em.registerExtension(createExtension(
+ "org.eclipse.emf.teneo.hibernate.mapper.EntityMapper", false));
+ em.registerExtension(createExtension(
+ "org.eclipse.emf.teneo.hibernate.mapper.FeatureMapper", false));
+ em.registerExtension(createExtension(
+ "org.eclipse.emf.teneo.hibernate.mapper.IdMapper", false));
+ em.registerExtension(createExtension(
+ "org.eclipse.emf.teneo.hibernate.mapper.ManyAttributeMapper",
+ false));
+ em.registerExtension(createExtension(
+ "org.eclipse.emf.teneo.hibernate.mapper.ManyToManyMapper",
+ false));
+ em.registerExtension(createExtension(
+ "org.eclipse.emf.teneo.hibernate.mapper.ManyToOneMapper", false));
+ em.registerExtension(createExtension(
+ "org.eclipse.emf.teneo.hibernate.mapper.MappingContext", false));
+ em.registerExtension(createExtension(
+ "org.eclipse.emf.teneo.hibernate.mapper.OneToManyMapper", false));
+ em.registerExtension(createExtension(
+ "org.eclipse.emf.teneo.hibernate.mapper.OneToOneMapper", false));
+ em.registerExtension(createExtension(
+ "org.eclipse.emf.teneo.hibernate.mapper.ManyExternalReferenceMapper",
+ false));
+ em.registerExtension(createExtension(
+ "org.eclipse.emf.teneo.hibernate.mapping.EMFInitializeCollectionEventListener",
+ false));
+ em.registerExtension(createExtension(
+ "org.eclipse.emf.teneo.hibernate.mapping.eav.EAVMergeEventListener",
+ false));
+
+ // jpox mapping
+ em.registerExtension(createExtension(
+ "org.eclipse.emf.teneo.jpox.mapper.association.EmbeddedMapper",
+ false));
+ em.registerExtension(createExtension(
+ "org.eclipse.emf.teneo.jpox.mapper.association.ManyToManyMapper",
+ false));
+ em.registerExtension(createExtension(
+ "org.eclipse.emf.teneo.jpox.mapper.association.ManyToOneMapper",
+ false));
+ em.registerExtension(createExtension(
+ "org.eclipse.emf.teneo.jpox.mapper.association.OneToManyMapper",
+ false));
+ em.registerExtension(createExtension(
+ "org.eclipse.emf.teneo.jpox.mapper.association.OneToOneMapper",
+ false));
+ em.registerExtension(createExtension(
+ "org.eclipse.emf.teneo.jpox.mapper.property.BasicMapper", false));
+ em.registerExtension(createExtension(
+ "org.eclipse.emf.teneo.jpox.mapper.property.ColumnMapper",
+ false));
+ em.registerExtension(createExtension(
+ "org.eclipse.emf.teneo.jpox.mapper.property.EClassFeatureMapper",
+ false));
+ em.registerExtension(createExtension(
+ "org.eclipse.emf.teneo.jpox.mapper.property.IdMapper", false));
+ em.registerExtension(createExtension(
+ "org.eclipse.emf.teneo.jpox.mapper.property.InheritanceMapper",
+ false));
+ em.registerExtension(createExtension(
+ "org.eclipse.emf.teneo.jpox.mapper.property.JoinColumnMapper",
+ false));
+ em.registerExtension(createExtension(
+ "org.eclipse.emf.teneo.jpox.mapper.property.ManyBasicMapper",
+ false));
+ em.registerExtension(createExtension(
+ "org.eclipse.emf.teneo.jpox.mapper.property.TableMapper", false));
+ em.registerExtension(createExtension(
+ "org.eclipse.emf.teneo.jpox.mapper.JPOXMappingGenerator", false));
+ em.registerExtension(createExtension(
+ "org.eclipse.emf.teneo.jpox.mapper.MappingContext", false));
+ em.registerExtension(createExtension(
+ "org.eclipse.emf.teneo.jpox.mapper.NamingHandler", false));
+
+ }
+} \ No newline at end of file
diff --git a/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/extension/PaModelAware.java b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/extension/PaModelAware.java
new file mode 100755
index 000000000..11da02622
--- /dev/null
+++ b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/extension/PaModelAware.java
@@ -0,0 +1,33 @@
+/**
+ * <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: PaModelAware.java,v 1.4 2009/03/30 07:53:04 mtaal Exp $
+ */
+
+package org.eclipse.emf.teneo.extension;
+
+import org.eclipse.emf.teneo.annotations.pamodel.PAnnotatedModel;
+
+/**
+ * A extension implementing this interface will be able to 'receive' an instance of a
+ * PAnnotatedModel.
+ *
+ * @author <a href="mailto:mtaal@elver.org">Martin Taal</a>
+ * @version $Revision: 1.4 $
+ */
+
+public interface PaModelAware {
+ /** Set the relevant pamodel */
+ void setPaModel(PAnnotatedModel paModel);
+} \ No newline at end of file
diff --git a/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/extension/PersistenceOptionsAware.java b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/extension/PersistenceOptionsAware.java
new file mode 100755
index 000000000..c5ff6cd53
--- /dev/null
+++ b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/extension/PersistenceOptionsAware.java
@@ -0,0 +1,33 @@
+/**
+ * <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: PersistenceOptionsAware.java,v 1.4 2009/03/30 07:53:04 mtaal Exp $
+ */
+
+package org.eclipse.emf.teneo.extension;
+
+import org.eclipse.emf.teneo.PersistenceOptions;
+
+/**
+ * An extension implementing this interface will be able to 'receive' an instance of the
+ * PersistenceOptions.
+ *
+ * @author <a href="mailto:mtaal@elver.org">Martin Taal</a>
+ * @version $Revision: 1.4 $
+ */
+
+public interface PersistenceOptionsAware {
+ /** Set the relevant pamodel */
+ void setPersistenceOptions(PersistenceOptions persistenceOptions);
+} \ No newline at end of file
diff --git a/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/extension/TeneoExtensionException.java b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/extension/TeneoExtensionException.java
new file mode 100755
index 000000000..a9217b87d
--- /dev/null
+++ b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/extension/TeneoExtensionException.java
@@ -0,0 +1,48 @@
+/**
+ * <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: TeneoExtensionException.java,v 1.2 2008/02/28 07:08:33 mtaal Exp $
+ */
+
+package org.eclipse.emf.teneo.extension;
+
+import org.eclipse.emf.teneo.TeneoException;
+
+/**
+ * Is thrown in case of an illegal situation in handling extensions.
+ *
+ * @author <a href="mailto:mtaal@elver.org">Martin Taal</a>
+ * @version $Revision: 1.2 $
+ */
+
+public class TeneoExtensionException extends TeneoException {
+ /**
+ * Serializable id
+ */
+ private static final long serialVersionUID = 7433341056815136417L;
+
+ /**
+ * The constructor, logs the exception also
+ */
+ public TeneoExtensionException(String msg, Throwable cause) {
+ super(msg, cause);
+ }
+
+ /**
+ * The constructor, logs the exception also
+ */
+ public TeneoExtensionException(String msg) {
+ super(msg);
+ }
+}
diff --git a/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/mapping/elist/MapPersistableEMap.java b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/mapping/elist/MapPersistableEMap.java
new file mode 100755
index 000000000..80cfff2e3
--- /dev/null
+++ b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/mapping/elist/MapPersistableEMap.java
@@ -0,0 +1,254 @@
+/**
+ * <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:
+ * Douglas Bitting
+ * Martin Taal
+ *
+ * </copyright>
+ *
+ * $Id: MapPersistableEMap.java,v 1.6 2009/03/30 07:53:04 mtaal Exp $
+ */
+package org.eclipse.emf.teneo.mapping.elist;
+
+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.common.util.BasicEMap;
+import org.eclipse.emf.common.util.EList;
+import org.eclipse.emf.ecore.EAttribute;
+import org.eclipse.emf.ecore.EClass;
+import org.eclipse.emf.ecore.EStructuralFeature;
+import org.eclipse.emf.ecore.InternalEObject;
+
+/**
+ * A persistable emap which is mapped as a real map to the db. It differs from its parent class
+ * (PersistableEMap) because that class assumes that the EMap is mapped to the db as a list.
+ *
+ * @author <a href="mailto:mtaal@elver.org">Martin Taal</a>
+ * @author <a href="mailto:jdboudreault@gmail.com">Jean-Denis Boudreault</a>
+ *
+ * @version $Revision: 1.6 $
+ */
+public abstract class MapPersistableEMap<K, V> extends PersistableEMap<K, V> implements
+ PersistableDelegateList<BasicEMap.Entry<K, V>> {
+
+ private static final long serialVersionUID = 1L;
+
+ /** The logger */
+ private static Log log = LogFactory.getLog(MapPersistableEMap.class);
+
+ /**
+ * The persisted map handled by the orm layer. This delegate is the map we receive from the
+ * database provider. It is kept all the time, any changes to the PersistableEMap are replicated
+ * to the ormMap.
+ *
+ * This field will be null unless there is a map waiting to be lazy loaded
+ */
+ protected Map<K, V> ormMapDelegate = null;
+
+ // Is this a map with primitives
+ private final boolean mapValueIsEAttribute;
+
+ /** Not supported constructor */
+ public MapPersistableEMap(EClass entryEClass, EList<BasicEMap.Entry<K, V>> delegateEList) {
+ super(entryEClass, delegateEList);
+ throw new UnsupportedOperationException("Explicitly passing delegate list is not supported!");
+ }
+
+ /** Constructor */
+ public MapPersistableEMap(EClass entryEClass, Class<?> entryClass, InternalEObject owner, EStructuralFeature feature) {
+ // invoke constructor with no lazyLoadMapDelegate
+ this(entryEClass, owner, feature, (java.util.Map<K, V>) null);
+ }
+
+ /**
+ * This version will set the lazyLoadMapDelegate if it is set. This version will prepare lazy
+ * lading if available
+ *
+ * @param entryEClass
+ * @param entryClass
+ * @param owner
+ * @param featureID
+ * @param lazyLoadDelegate
+ * a java.util.map that is a proxy collection taht will be used when lazy load is
+ * invoked. if it is null, then the map is considered as loaded
+ */
+ public MapPersistableEMap(EClass entryEClass, InternalEObject owner, EStructuralFeature feature,
+ Map<K, V> ormMapDelegate) {
+ super(entryEClass, owner, feature, new ArrayList<Entry<K, V>>());
+
+ setORMMapDelegate(ormMapDelegate);
+
+ // create our list as empty for now
+ setDelegateEList(owner, feature, this.newList());
+
+ if (isInitialized()) {
+ // perform eager loading if the underlying list has been pre-loaded
+ setLoaded();
+
+ // sets the size of this map, depending on its load status
+ size();
+ }
+
+ log.debug("Created persistable emap for entry eclass " + entryEClass.getName());
+ mapValueIsEAttribute = entryEClass.getEStructuralFeature("value") instanceof EAttribute;
+ }
+
+ /**
+ * This version will create the lsit completely, there is no lazy lading from this constructor
+ *
+ * @param entryEClass
+ * @param entryClass
+ * @param owner
+ * @param featureID
+ * @param ormMapDelegate
+ * a java.util.map that is a proxy collection taht will be used when lazy load is
+ * invoked. if it is null, then the map is considered as loaded
+ */
+ public MapPersistableEMap(EClass entryEClass, InternalEObject owner, EStructuralFeature feature,
+ List<BasicEMap.Entry<K, V>> list) {
+ super(entryEClass, owner, feature, list);
+ this.setORMMapDelegate(null);
+
+ // this should do nothing but set us as already loaded
+ setLoaded();
+
+ // sets the size of this map
+ size();
+
+ log.debug("Created persistable emap for entry eclass " + entryEClass.getName());
+
+ mapValueIsEAttribute = entryEClass.getEStructuralFeature("value") instanceof EAttribute;
+ }
+
+ /** Does nothing here */
+ @Override
+ protected void setDelegateEList(InternalEObject owner, EStructuralFeature feature,
+ List<BasicEMap.Entry<K, V>> delegateORMList) {
+ }
+
+ /** Needs to be implemented by concrete subclass, does nothing here */
+ @Override
+ protected EList<BasicEMap.Entry<K, V>> createDelegateEList(InternalEObject owner, EStructuralFeature feature,
+ List<BasicEMap.Entry<K, V>> delegateORMList) {
+ throw new UnsupportedOperationException("This method should not be called!");
+ }
+
+ /**
+ * Override this method to determine if the ormmapdelegate colelction has been eagerly loaded or
+ * not
+ *
+ * @return
+ */
+ protected abstract boolean isORMMapDelegateLoaded();
+
+ /**
+ * this method will check the status of the lazy loaded delegate and if ti is eager lodaed,
+ * perform our loading too.
+ */
+ protected void setLoaded() {
+ // now, we do a check to see if the lazyLoadedDelegate was eager loaded.
+ // it was, this method will wrap its data and set ourselves as loaded
+ if (this.getORMMapDelegate() == null) {
+ this.setLoaded(true);
+ } else if (this.getORMMapDelegate() != null && isORMMapDelegateLoaded()) {
+ this.load();
+ } else {
+ this.setLoaded(false);
+ }
+ }
+
+ /** Return the delegate list without doing a load */
+ @Override
+ public Object getDelegate() {
+ // if there is a delegate then return that one
+ // this ensures that hibernate always sees its map back
+ if (getORMMapDelegate() != null) {
+ return getORMMapDelegate();
+ }
+ // todo: throw error here?
+ return map();
+ }
+
+ /** Replace the delegate */
+ @Override
+ @SuppressWarnings("unchecked")
+ public void replaceDelegate(Object newDelegate) {
+ // set the ormmapdelegate to null to handle the clear action
+ setORMMapDelegate(null);
+ doClear();
+
+ // now set the new value in there
+ setORMMapDelegate((Map<K, V>) newDelegate);
+ setLoaded(false);
+ }
+
+ /** Returns the ormMapDelegate */
+ public Map<K, V> getORMMapDelegate() {
+ return ormMapDelegate;
+ }
+
+ /**
+ * This method sets the ormMapDelegate
+ */
+ protected void setORMMapDelegate(Map<K, V> ormMapDelegate) {
+ this.ormMapDelegate = ormMapDelegate;
+ }
+
+ /**
+ * @return the mapValueIsEAttribute
+ */
+ public boolean isMapValueIsEAttribute() {
+ return mapValueIsEAttribute;
+ }
+
+ /**
+ * Updates orm map
+ *
+ * @see org.eclipse.emf.common.util.BasicEMap#didAdd(org.eclipse.emf.common.util.BasicEMap.Entry)
+ */
+ @Override
+ protected void didAdd(org.eclipse.emf.common.util.BasicEMap.Entry<K, V> entry) {
+ if (getORMMapDelegate() != null) {
+ getORMMapDelegate().put(entry.getKey(), entry.getValue());
+ }
+ super.didAdd(entry);
+ }
+
+ /**
+ * Sets the new value using the key in the orm map.
+ *
+ * @see org.eclipse.emf.common.util.BasicEMap#didModify(org.eclipse.emf.common.util.BasicEMap.Entry,
+ * java.lang.Object)
+ */
+ @Override
+ protected void didModify(org.eclipse.emf.common.util.BasicEMap.Entry<K, V> entry, V oldValue) {
+ if (getORMMapDelegate() != null) {
+ getORMMapDelegate().put(entry.getKey(), entry.getValue());
+ }
+ super.didModify(entry, oldValue);
+ }
+
+ /**
+ * Removes the entry from the orm map
+ *
+ * @see org.eclipse.emf.common.util.BasicEMap#didRemove(org.eclipse.emf.common.util.BasicEMap.Entry)
+ */
+ @Override
+ protected void didRemove(org.eclipse.emf.common.util.BasicEMap.Entry<K, V> entry) {
+ if (getORMMapDelegate() != null) {
+ getORMMapDelegate().remove(entry.getKey());
+ }
+ super.didRemove(entry);
+ }
+} \ No newline at end of file
diff --git a/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/mapping/elist/PersistableDelegateList.java b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/mapping/elist/PersistableDelegateList.java
new file mode 100755
index 000000000..a8bd4be8c
--- /dev/null
+++ b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/mapping/elist/PersistableDelegateList.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 - Initial API and implementation
+ *
+ * </copyright>
+ *
+ * $Id: PersistableDelegateList.java,v 1.9 2010/03/25 00:12:45 mtaal Exp $
+ */
+
+package org.eclipse.emf.teneo.mapping.elist;
+
+import org.eclipse.emf.ecore.EStructuralFeature;
+
+/**
+ * A tag which signals that a list is either a persistable map, featuremap or elist.
+ *
+ * @author <a href="mailto:mtaal@elver.org">Martin Taal</a>
+ * @version $Revision: 1.9 $
+ */
+
+public interface PersistableDelegateList<E> {
+ /** Return the delegate list/map without doing a load */
+ public Object getDelegate();
+
+ /** Returns true if the elist is loaded */
+ public boolean isLoaded();
+
+ /** If the delegate has been initialized */
+ public boolean isInitialized();
+
+ public EStructuralFeature getEStructuralFeature();
+} \ No newline at end of file
diff --git a/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/mapping/elist/PersistableEList.java b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/mapping/elist/PersistableEList.java
new file mode 100755
index 000000000..717e070b4
--- /dev/null
+++ b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/mapping/elist/PersistableEList.java
@@ -0,0 +1,621 @@
+/**
+ * <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: PersistableEList.java,v 1.26 2010/02/06 20:51:42 mtaal Exp $
+ */
+
+package org.eclipse.emf.teneo.mapping.elist;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+import java.util.ListIterator;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.eclipse.emf.common.notify.Notification;
+import org.eclipse.emf.common.notify.NotifyingList;
+import org.eclipse.emf.common.util.EList;
+import org.eclipse.emf.ecore.EStructuralFeature;
+import org.eclipse.emf.ecore.InternalEObject;
+import org.eclipse.emf.ecore.util.DelegatingEcoreEList;
+import org.eclipse.emf.teneo.util.StoreUtil;
+
+/**
+ * A persistable elist which can be used by different or mappers. This persistable elist works around the idea that the
+ * persisted list (e.g. PersistentList in Hibernate) is the delegate for this elist.
+ *
+ * @author <a href="mailto:mtaal@elver.org">Martin Taal</a>
+ * @version $Revision: 1.26 $
+ */
+
+public abstract class PersistableEList<E> extends DelegatingEcoreEList<E> implements PersistableDelegateList<E> {
+ private static final long serialVersionUID = 1L;
+
+ /** The logger */
+ private static Log log = LogFactory.getLog(PersistableEList.class);
+
+ /**
+ * The actual list, must never be an elist as notifications etc. are done by this list
+ */
+ protected List<E> delegate;
+
+ /** The structural feature modeled by this list */
+ private EStructuralFeature estructuralFeature;
+
+ /** The unique path to the efeature, used to support serializaion */
+ private String eFeaturePath = "";
+
+ /** Is loaded from backend */
+ private boolean isLoaded = false;
+
+ /** Is being loaded from backend */
+ private boolean isLoading = false;
+
+ /** The string used for logging */
+ protected final String logString;
+
+ protected Boolean isThisListWrapped;
+
+ /** Constructor */
+ public PersistableEList(InternalEObject owner, EStructuralFeature feature, List<E> list) {
+ super(owner);
+ estructuralFeature = feature;
+ if (list == null) {
+ delegate = new ArrayList<E>();
+ isLoaded = true;
+ } else if (list instanceof EList<?>) {
+ delegate = new ArrayList<E>(list);
+ isLoaded = true;
+ } else if (list instanceof ArrayList<?>) { // already loaded lists are
+ // packaged in an elist
+ delegate = list;
+ isLoaded = list.size() > 0;
+ } else {
+ delegate = list;
+ }
+
+ logString = "EList of type: " + this.getClass().getName() + " of member " + estructuralFeature.getName()
+ + " owned by " + owner.getClass().getName() + " with delegate list " + delegate.getClass().getName();
+
+ log.debug("Created persistable list " + logString);
+ }
+
+ /** Takes care of serializing the efeature */
+ private void writeObject(java.io.ObjectOutputStream out) throws IOException {
+ EStructuralFeature estructuralFeatureOld = estructuralFeature;
+ eFeaturePath = StoreUtil.structuralFeatureToString(estructuralFeature);
+ // Commented to fix the bug due to which the attribute structuralFeature
+ // was getting chnaged to null
+ estructuralFeature = null;
+ additionalWriteObject();
+ out.defaultWriteObject();
+ estructuralFeature = estructuralFeatureOld;
+ }
+
+ /** Do your subclass thing for serialization */
+ protected void additionalWriteObject() {
+ }
+
+ /** Takes care of deserializing the efeature */
+ private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException {
+ in.defaultReadObject();
+ estructuralFeature = StoreUtil.stringToStructureFeature(eFeaturePath);
+ }
+
+ /*
+ * Get the underlying efeature
+ *
+ * @see org.eclipse.emf.ecore.util.DelegatingEcoreEList#getEStructuralFeature()
+ */
+ @Override
+ public EStructuralFeature getEStructuralFeature() {
+ return estructuralFeature;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.emf.ecore.util.DelegatingEcoreEList#getFeature()
+ */
+ @Override
+ public Object getFeature() {
+ return estructuralFeature;
+ }
+
+ /** Return the isunique value of the efeature */
+ @Override
+ public boolean isUnique() {
+ return estructuralFeature.isUnique();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.emf.ecore.util.DelegatingEcoreEList#getFeatureID()
+ */
+ @Override
+ // todo: get rid of the override when the issue with the
+ // delegatingecorelist.getFeatureId is
+ // solved.
+ public int getFeatureID() {
+ return owner.eClass().getFeatureID(estructuralFeature);
+ }
+
+ /** Return the delegate list without doing a load */
+ public List<E> getDelegate() {
+ return delegate;
+ }
+
+ /** Returns the underlying elist */
+ @Override
+ protected List<E> delegateList() {
+ load();
+
+ return delegate;
+ }
+
+ /**
+ * If this instance is again wrapped by a NotifyingList then assume that the wrapper will be smart enough to do all
+ * the inverse things.... Note that the check if a list is wrapped is done once and then the result is cached. So
+ * this assumes that a list will not be re-wrapped.
+ *
+ * @return false if the list is wrapped, otherwise the super hasInverse is called.
+ */
+ @Override
+ protected boolean hasInverse() {
+ if (isWrapped()) {
+ return false;
+ }
+
+ return super.hasInverse();
+ }
+
+ @Override
+ protected void dispatchNotification(Notification notification) {
+ // don't notify anyone as the wrapper should do that
+ if (isWrapped()) {
+ return;
+ }
+ super.dispatchNotification(notification);
+ }
+
+ private boolean isWrapped() {
+ if (isThisListWrapped == null) {
+ final Object value = getEObject().eGet(getEStructuralFeature());
+ isThisListWrapped = value != this && value instanceof NotifyingList<?>;
+ }
+ return isThisListWrapped;
+ }
+
+ /** Replace the delegating list and set isLoaded = false */
+ public void replaceDelegate(List<E> newDelegate) {
+ // disabled this assertion because in case of a session refresh it is
+ // possible
+ // that the list is replaced by a persistent list
+ // AssertUtil.assertTrue("This elist " + logString +
+ // " already wraps an or specific list",
+ // !isPersistencyWrapped());
+ delegate = newDelegate;
+ isLoaded = false;
+ }
+
+ /** Returns a string which can be used to log for this elist */
+ public String getLogString() {
+ return logString;
+ }
+
+ /**
+ * Performs the load action if not yet oaded and sends out the load notification.
+ */
+ protected void load() {
+ if (isLoaded) {
+ return;
+ }
+
+ // When we are loading we should not be reloaded!
+ // this can happen in the jpox elist impl. when detaching
+ if (isLoading) {
+ return;
+ }
+
+ isLoading = true;
+ log.debug("Loading " + getLogString());
+
+ // prevent notifications to be sent out
+ boolean eDeliver = owner.eDeliver();
+ boolean setDeliver = false;
+ try {
+ // only set to false if it was true
+ if (eDeliver) {
+ log.debug("Owner " + owner.getClass() + " set eDeliver to false");
+ owner.eSetDeliver(false);
+ setDeliver = true;
+ }
+ } catch (UnsupportedOperationException e) {
+ // in this case the eSetDeliver was not overridden from the
+ // baseclass
+ // ignore
+ }
+ try {
+ doLoad();
+ } finally {
+ isLoaded = true;
+ isLoading = false;
+ if (setDeliver) {
+ owner.eSetDeliver(eDeliver);
+ }
+ }
+ // StoreUtil.dispatchEListLoadNotification(owner, this,
+ // getEStructuralFeature());
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.emf.ecore.util.EcoreEList#isNotificationRequired()
+ */
+ @Override
+ protected boolean isNotificationRequired() {
+ if (!isLoaded() || isLoading()) {
+ return false; // not yet loaded so no notifications, prevents
+ // infinite looping
+ }
+ return super.isNotificationRequired();
+ }
+
+ /** Is loaded */
+ public boolean isLoaded() {
+ return isLoaded;
+ }
+
+ /** Is loaded */
+ public void setIsLoaded(boolean isLoaded) {
+ this.isLoaded = isLoaded;
+ }
+
+ /** Is loading */
+ public void setIsLoading(boolean isLoading) {
+ this.isLoading = isLoading;
+ }
+
+ /** Returns true if the load action is running and false otherwise */
+ public boolean isLoading() {
+ return isLoading;
+ }
+
+ /**
+ * The load method which should be overridden by the subclass to add lazyloading
+ */
+ protected abstract void doLoad();
+
+ /** Returns true if the wrapped list is a persistency layer specific list */
+ public abstract boolean isPersistencyWrapped();
+
+ // ---------------------------- Overloaded delegate methods
+ // --------------------------
+ // These methods have been overridden to a load action before the backing
+ // list is
+ // accessed.
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.emf.common.util.DelegatingEList#delegateAdd(int, java.lang.Object)
+ */
+ @Override
+ protected void delegateAdd(int index, E object) {
+ load();
+ super.delegateAdd(index, object);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.emf.common.util.DelegatingEList#delegateAdd(java.lang.Object)
+ */
+ @Override
+ protected void delegateAdd(E object) {
+ load();
+ super.delegateAdd(object);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.emf.common.util.DelegatingEList#delegateBasicList()
+ */
+ @Override
+ protected List<E> delegateBasicList() {
+ load();
+ return super.delegateBasicList();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.emf.common.util.DelegatingEList#delegateClear()
+ */
+ @Override
+ protected void delegateClear() {
+ load();
+ super.delegateClear();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.emf.common.util.DelegatingEList#delegateContains(java.lang .Object)
+ */
+ @Override
+ protected boolean delegateContains(Object object) {
+ load();
+ return super.delegateContains(object);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.emf.common.util.DelegatingEList#delegateContainsAll(java. util.Collection)
+ */
+ @Override
+ protected boolean delegateContainsAll(Collection<?> collection) {
+ load();
+ return super.delegateContainsAll(collection);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.emf.common.util.DelegatingEList#delegateEquals(java.lang. Object)
+ */
+ @Override
+ protected boolean delegateEquals(Object object) {
+ load();
+ return super.delegateEquals(object);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.emf.common.util.DelegatingEList#delegateGet(int)
+ */
+ @Override
+ protected E delegateGet(int index) {
+ load();
+ return super.delegateGet(index);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.emf.common.util.DelegatingEList#delegateHashCode()
+ */
+ @Override
+ protected int delegateHashCode() {
+ load();
+ return super.delegateHashCode();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.emf.common.util.DelegatingEList#delegateIndexOf(java.lang .Object)
+ */
+ @Override
+ protected int delegateIndexOf(Object object) {
+ load();
+ return super.delegateIndexOf(object);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.emf.common.util.DelegatingEList#delegateIsEmpty()
+ */
+ @Override
+ protected boolean delegateIsEmpty() {
+ load();
+ return super.delegateIsEmpty();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.emf.common.util.DelegatingEList#delegateIterator()
+ */
+ @Override
+ protected Iterator<E> delegateIterator() {
+ load();
+ return super.delegateIterator();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.emf.common.util.DelegatingEList#delegateLastIndexOf(java. lang.Object)
+ */
+ @Override
+ protected int delegateLastIndexOf(Object object) {
+ load();
+ return super.delegateLastIndexOf(object);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.emf.common.util.DelegatingEList#delegateListIterator()
+ */
+ @Override
+ protected ListIterator<E> delegateListIterator() {
+ return super.delegateListIterator();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.emf.common.util.DelegatingEList#delegateRemove(int)
+ */
+ @Override
+ protected E delegateRemove(int index) {
+ load();
+ return super.delegateRemove(index);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.emf.common.util.DelegatingEList#delegateSet(int, java.lang.Object)
+ */
+ @Override
+ protected E delegateSet(int index, E object) {
+ load();
+ return super.delegateSet(index, object);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.emf.common.util.DelegatingEList#delegateSize()
+ */
+ @Override
+ protected int delegateSize() {
+ load();
+ return super.delegateSize();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.emf.common.util.DelegatingEList#delegateToArray()
+ */
+ @Override
+ protected Object[] delegateToArray() {
+ load();
+ return super.delegateToArray();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.emf.common.util.DelegatingEList#delegateToArray(java.lang .Object[])
+ */
+ @Override
+ protected <T> T[] delegateToArray(T[] array) {
+ load();
+ return super.delegateToArray(array);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.emf.common.util.DelegatingEList#delegateToString()
+ */
+ @Override
+ protected String delegateToString() {
+ load();
+ return super.delegateToString();
+ }
+
+ /** If not loaded then basicIterator will always return a false for hasNext */
+ @SuppressWarnings("deprecation")
+ @Override
+ public Iterator<E> basicIterator() {
+ if (!isLoaded()) {
+ return new NonResolvingEIterator<E>() {
+ /** Always returns false */
+ @Override
+ public boolean hasNext() {
+ return false;
+ }
+ };
+ }
+
+ return super.basicIterator();
+ }
+
+ /**
+ * If not loaded then basicIterator will always return a false for hasNext/hasPrevious
+ */
+ @Override
+ @SuppressWarnings("deprecation")
+ public ListIterator<E> basicListIterator() {
+ if (!isLoaded()) {
+ return new NonResolvingEListIterator<E>() {
+ /** Always returns false */
+ @Override
+ public boolean hasNext() {
+ return false;
+ }
+
+ /** Always returns false */
+ @Override
+ public boolean hasPrevious() {
+ return false;
+ }
+ };
+ }
+
+ return super.basicListIterator();
+ }
+
+ /**
+ * If not loaded then basicIterator will always return a false for hasNext/hasPrevious
+ */
+ @Override
+ @SuppressWarnings("deprecation")
+ public ListIterator<E> basicListIterator(int index) {
+ if (!isLoaded()) {
+ // note no size check on index as this would load this thing
+ return new NonResolvingEListIterator<E>() {
+ /** Always returns false */
+ @Override
+ public boolean hasNext() {
+ return false;
+ }
+
+ /** Always returns false */
+ @Override
+ public boolean hasPrevious() {
+ return false;
+ }
+ };
+ }
+
+ return super.basicListIterator(index);
+ }
+
+ /**
+ * Is overridden because it can't use delegates for equality because the delegate (a hibernate or jpox list) will
+ * try to be equal with this persistable elist.
+ *
+ * This method does jvm instance equality because doing a full-fledge equal would result in a load of the list.
+ */
+ @Override
+ public boolean equals(Object object) {
+ return this == object;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see java.lang.Object#clone()
+ */
+ @Override
+ protected Object clone() throws CloneNotSupportedException {
+ return super.clone();
+ }
+} \ No newline at end of file
diff --git a/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/mapping/elist/PersistableEMap.java b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/mapping/elist/PersistableEMap.java
new file mode 100755
index 000000000..f2bdfe5fa
--- /dev/null
+++ b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/mapping/elist/PersistableEMap.java
@@ -0,0 +1,617 @@
+/**
+ * <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:
+ * Douglas Bitting
+ * Martin Taal
+ *
+ * </copyright>
+ *
+ * $Id: PersistableEMap.java,v 1.17 2010/04/03 12:55:21 mtaal Exp $
+ */
+package org.eclipse.emf.teneo.mapping.elist;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+import java.util.ListIterator;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.eclipse.emf.common.notify.NotificationChain;
+import org.eclipse.emf.common.util.BasicEMap;
+import org.eclipse.emf.common.util.EList;
+import org.eclipse.emf.common.util.EMap;
+import org.eclipse.emf.ecore.EClass;
+import org.eclipse.emf.ecore.EStructuralFeature;
+import org.eclipse.emf.ecore.InternalEObject;
+import org.eclipse.emf.ecore.util.EcoreEMap;
+
+/**
+ * A persistable emap which uses the PersistableEList as its delegate. Note that this implementation is based on the
+ * implementation of the superclass. The superclass makes use of a delegate list to store its content. This
+ * implementation puts a persistent list in this member.
+ *
+ * @author <a href="mailto:mtaal@elver.org">Martin Taal</a>
+ * @author <a href="mailto:jdboudreault@gmail.com">Jean-Denis Boudreault</a>
+ *
+ * @version $Revision: 1.17 $
+ */
+public abstract class PersistableEMap<K, V> extends EcoreEMap<K, V> implements
+ PersistableDelegateList<BasicEMap.Entry<K, V>> {
+
+ private static final long serialVersionUID = 1L;
+
+ /** The logger */
+ private static Log log = LogFactory.getLog(PersistableEMap.class);
+
+ /** The logstring */
+ protected String logString;
+
+ /** Used for assertion */
+ private final int featureID;
+
+ /** Is loaded from backend */
+ private boolean isLoaded = false;
+
+ /** Is being loaded from backend */
+ private boolean isLoading = false;
+
+ /**
+ * The owner of the objet. we must keep a copy since emap does not have one and the delegate EList does not expose
+ * this field publicly
+ */
+ private InternalEObject owner;
+
+ /** Not supported constructor */
+ public PersistableEMap(EClass entryEClass, EList<BasicEMap.Entry<K, V>> delegateEList) {
+ super(entryEClass, BasicEMap.Entry.class, delegateEList);
+ throw new UnsupportedOperationException("Explicitly passing delegate list is not supported!");
+ }
+
+ /** Constructor */
+ public PersistableEMap(EClass entryEClass, Class<?> entryClass, InternalEObject owner, EStructuralFeature feature) {
+ // invoke constructor with no lazyLoadMapDelegate
+ super(entryEClass, BasicEMap.Entry.class, owner, owner.eClass().getFeatureID(feature));
+
+ setDelegateEList(owner, feature, new ArrayList<Entry<K, V>>());
+
+ this.owner = owner;
+ this.featureID = owner.eClass().getFeatureID(feature);
+ log.debug("Created persistable emap for entry eclass " + entryEClass.getName());
+ }
+
+ /**
+ * This version will create the lsit completely, there is no lazy lading from this constructor
+ *
+ * @param entryEClass
+ * @param entryClass
+ * @param owner
+ * @param featureID
+ */
+ public PersistableEMap(EClass entryEClass, InternalEObject owner, EStructuralFeature feature,
+ List<BasicEMap.Entry<K, V>> list) {
+ super(entryEClass, BasicEMap.Entry.class, owner, owner.eClass().getFeatureID(feature));
+
+ this.owner = owner;
+ this.featureID = owner.eClass().getFeatureID(feature);
+
+ // create our list
+ setDelegateEList(owner, feature, list);
+
+ // sets the size of this map
+ // size();
+
+ log.debug("Created persistable emap for entry eclass " + entryEClass.getName());
+ }
+
+ /** Sets the delegatelist to a persistablelist */
+ protected void setDelegateEList(InternalEObject owner, EStructuralFeature feature,
+ List<BasicEMap.Entry<K, V>> delegateORMList) {
+ assert (owner.eClass().getFeatureID(feature) == featureID);
+
+ // NOTE BEWARE: the delegateEList is a member of the superclass!
+ delegateEList = createDelegateEList(owner, feature, delegateORMList);
+
+ logString = "EMap with entry eclass: " + entryEClass.getName() + " of member " + feature.getName()
+ + " owned by " + owner.getClass().getName() + " with delegate list "
+ + delegateORMList.getClass().getName();
+
+ log.debug("Created/reset elist " + logString);
+
+ if (delegateORMList instanceof EList<?>) {
+ setLoaded(true);
+ } else if (delegateORMList instanceof ArrayList<?>) { // already loaded
+ // lists are
+ // packaged in
+ // an elist
+ setLoaded(delegateORMList.size() > 0);
+ }
+ if (isLoaded) {
+ // force the map to be computed, this sets the internal entrydata/size member
+ get(null);
+ }
+ }
+
+ /** Needs to be implemented by concrete subclass */
+ protected abstract EList<BasicEMap.Entry<K, V>> createDelegateEList(InternalEObject owner,
+ EStructuralFeature feature, List<BasicEMap.Entry<K, V>> delegateORMList);
+
+ /** Replace the delegate */
+ @SuppressWarnings("unchecked")
+ public void replaceDelegate(Object newDelegate) {
+ setDelegateEList(owner, getEStructuralFeature(), (List<BasicEMap.Entry<K, V>>) newDelegate);
+ setLoaded(false);
+ }
+
+ /**
+ * Performs the load action if not yet oaded and sends out the load notification.
+ */
+ protected void load() {
+ if (isLoaded) {
+ // reset the size
+ size = delegateEList.size();
+ return;
+ }
+
+ // When we are loading we should not be reloaded!
+ // this can happen in the jpox elist impl. when detaching
+ if (isLoading) {
+ return;
+ }
+
+ isLoading = true;
+ log.debug("Loading " + getLogString());
+
+ // set the size
+ size = this.size();
+
+ // prevent notifications to be sent out
+ boolean eDeliver = this.getOwner().eDeliver();
+ boolean setDeliver = false;
+ try {
+ // only set to false if it was true
+ if (eDeliver) {
+ log.debug("Owner " + getOwner().getClass() + " set eDeliver to false");
+ getOwner().eSetDeliver(false);
+ setDeliver = true;
+ }
+ } catch (UnsupportedOperationException e) {
+ // in this case the eSetDeliver was not overridden from the
+ // baseclass
+ // ignore
+ }
+ try {
+ doLoad();
+
+ // force the map to be computed, this sets the internal entrydata/size member
+ get(null);
+
+ // set the size
+ size = this.size();
+ } finally {
+ isLoaded = true;
+ isLoading = false;
+ if (setDeliver) {
+ owner.eSetDeliver(eDeliver);
+ }
+ }
+ }
+
+ /**
+ * The load method which should be overridden by the subclass to add lazyloading
+ */
+ protected abstract void doLoad();
+
+ //
+ // /**
+ // * Overridden to prevent the super
+ // */
+ // @Override
+ // public void initializeDelegateEList() {
+ // this.isLoaded = false;
+ // this.size = 0;
+ // this.delegateEList = null;
+ // }
+
+ /** Return ourselves, this class assumes that the emap is mapped as a list */
+ public Object getDelegate() {
+ return this;
+ }
+
+ /** Returns true if the elist is loaded */
+ public boolean isLoaded() {
+ return isLoaded;
+ }
+
+ /**
+ * Overridden for access to size member
+ */
+ @Override
+ protected void ensureEntryDataExists() {
+ load();
+ super.ensureEntryDataExists();
+ }
+
+ /**
+ * Overridden because of access to size attribute
+ */
+ @Override
+ public int size() {
+ // the subclass can override the size to perform smart size
+ // determination
+ if (!this.isLoaded()) {
+ load();
+ }
+ size = delegateEList.size();
+ return super.size();
+ }
+
+ /**
+ * Overridden because of access to size attribute
+ */
+ @Override
+ public boolean isEmpty() {
+ size();
+ if (!this.isLoaded()) {
+ return (this.size == 0);
+ }
+
+ return super.isEmpty();
+ }
+
+ /*
+ * Javadoc copied from interface. Overridden because of access to size attribute
+ */
+ @Override
+ public boolean containsKey(Object key) {
+ load();
+ return super.containsKey(key);
+ }
+
+ /*
+ * Javadoc copied from interface. Overridden because of access to size attribute
+ */
+ @Override
+ public Set<K> keySet() {
+ load();
+ return super.keySet();
+ }
+
+ /*
+ * Javadoc copied from interface. Overridden because of access to size attribute
+ */
+ @Override
+ public Collection<V> values() {
+ load();
+ return super.values();
+ }
+
+ /*
+ * Javadoc copied from interface. Overridden because of access to size attribute
+ */
+ @Override
+ public Set<Map.Entry<K, V>> entrySet() {
+ load();
+ return super.entrySet();
+ }
+
+ /*
+ * Javadoc copied from interface. Overridden because of access to size attribute
+ */
+ @Override
+ public boolean containsValue(Object value) {
+ load();
+ return super.containsValue(value);
+ }
+
+ /*
+ * Javadoc copied from interface. Overridden because of access to size attribute
+ */
+ @Override
+ public V get(Object key) {
+ load();
+ return super.get(key);
+ }
+
+ @Override
+ public Map<K, V> map() {
+ load();
+ if (view == null) {
+ view = new View<K, V>();
+ }
+ if (view.map == null) {
+ view.map = new PersistableDelegatingMap();
+ }
+
+ return view.map;
+ }
+
+ /** Used to tag the returned map class and give access to the owner */
+ public class PersistableDelegatingMap extends DelegatingMap {
+
+ /** Return my owner */
+ public PersistableEMap<K, V> getOwner() {
+ return PersistableEMap.this;
+ }
+
+ }
+
+ /** Set the delegate again */
+
+ protected boolean isLoading() {
+ return isLoading;
+ }
+
+ protected void setLoading(boolean isLoading) {
+ this.isLoading = isLoading;
+ }
+
+ protected void setLoaded(boolean isLoaded) {
+ this.isLoaded = isLoaded;
+ log.debug("Isloaded is " + isLoaded);
+ }
+
+ protected String getLogString() {
+ return logString;
+ }
+
+ protected InternalEObject getOwner() {
+ return owner;
+ }
+
+ @Override
+ public NotificationChain basicAdd(java.util.Map.Entry<K, V> object, NotificationChain notifications) {
+ load();
+ return super.basicAdd(object, notifications);
+ }
+
+ @Override
+ public org.eclipse.emf.common.util.BasicEMap.Entry<K, V> basicGet(int index) {
+ load();
+ return super.basicGet(index);
+ }
+
+ @Override
+ public Iterator<java.util.Map.Entry<K, V>> basicIterator() {
+ load();
+ return super.basicIterator();
+ }
+
+ @Override
+ public List<java.util.Map.Entry<K, V>> basicList() {
+ load();
+ return super.basicList();
+ }
+
+ @Override
+ public ListIterator<java.util.Map.Entry<K, V>> basicListIterator() {
+ load();
+ return super.basicListIterator();
+ }
+
+ @Override
+ public ListIterator<java.util.Map.Entry<K, V>> basicListIterator(int index) {
+ load();
+ return super.basicListIterator(index);
+ }
+
+ @Override
+ public NotificationChain basicRemove(Object object, NotificationChain notifications) {
+ load();
+ return super.basicRemove(object, notifications);
+ }
+
+ @Override
+ public void addUnique(java.util.Map.Entry<K, V> object) {
+ load();
+ super.addUnique(object);
+ }
+
+ @Override
+ public void addUnique(int index, java.util.Map.Entry<K, V> object) {
+ load();
+ super.addUnique(index, object);
+ }
+
+ @Override
+ public java.util.Map.Entry<K, V> setUnique(int index, java.util.Map.Entry<K, V> object) {
+ load();
+ return super.setUnique(index, object);
+ }
+
+ @Override
+ public boolean add(java.util.Map.Entry<K, V> object) {
+ load();
+ return super.add(object);
+ }
+
+ @Override
+ public void add(int index, java.util.Map.Entry<K, V> object) {
+ load();
+ super.add(index, object);
+ }
+
+ @Override
+ public boolean addAll(Collection<? extends java.util.Map.Entry<K, V>> collection) {
+ load();
+ return super.addAll(collection);
+ }
+
+ @Override
+ public boolean addAll(int index, Collection<? extends java.util.Map.Entry<K, V>> collection) {
+ load();
+ return super.addAll(index, collection);
+ }
+
+ @Override
+ public void clear() {
+ this.isLoaded = false;
+ super.clear();
+ }
+
+ @Override
+ public org.eclipse.emf.common.util.BasicEMap.Entry<K, V> get(int index) {
+ load();
+ return super.get(index);
+ }
+
+ @Override
+ protected int indexOf(int hash) {
+ load();
+ return super.indexOf(hash);
+ }
+
+ @Override
+ public int indexOf(Object object) {
+ load();
+ return super.indexOf(object);
+ }
+
+ @Override
+ public int indexOfKey(Object key) {
+ load();
+ return super.indexOfKey(key);
+ }
+
+ @Override
+ public Iterator<java.util.Map.Entry<K, V>> iterator() {
+ load();
+ return super.iterator();
+ }
+
+ @Override
+ public int lastIndexOf(Object object) {
+ load();
+ return super.lastIndexOf(object);
+ }
+
+ @Override
+ public ListIterator<java.util.Map.Entry<K, V>> listIterator() {
+ load();
+ return super.listIterator();
+ }
+
+ @Override
+ public ListIterator<java.util.Map.Entry<K, V>> listIterator(int index) {
+ load();
+ return super.listIterator(index);
+ }
+
+ @Override
+ public void move(int index, java.util.Map.Entry<K, V> object) {
+ load();
+ super.move(index, object);
+ }
+
+ @Override
+ public java.util.Map.Entry<K, V> move(int targetIndex, int sourceIndex) {
+ load();
+ return super.move(targetIndex, sourceIndex);
+ }
+
+ @Override
+ public V put(K key, V value) {
+ load();
+ return super.put(key, value);
+ }
+
+ @Override
+ public void putAll(EMap<? extends K, ? extends V> map) {
+ load();
+ super.putAll(map);
+ }
+
+ @Override
+ public void putAll(Map<? extends K, ? extends V> map) {
+ load();
+ super.putAll(map);
+ }
+
+ @Override
+ protected V putEntry(org.eclipse.emf.common.util.BasicEMap.Entry<K, V> entry, V value) {
+ return super.putEntry(entry, value);
+ }
+
+ @Override
+ public java.util.Map.Entry<K, V> remove(int index) {
+ load();
+ return super.remove(index);
+ }
+
+ @Override
+ public boolean remove(Object object) {
+
+ load();
+ return super.remove(object);
+ }
+
+ @Override
+ public boolean removeAll(Collection<?> collection) {
+ load();
+ return super.removeAll(collection);
+ }
+
+ @Override
+ protected V removeEntry(int index, int entryIndex) {
+ load();
+ return super.removeEntry(index, entryIndex);
+ }
+
+ @Override
+ public V removeKey(Object key) {
+ load();
+ return super.removeKey(key);
+ }
+
+ @Override
+ protected V resolve(K key, V value) {
+ load();
+ return super.resolve(key, value);
+ }
+
+ @Override
+ public boolean retainAll(Collection<?> collection) {
+ load();
+ return super.retainAll(collection);
+ }
+
+ @Override
+ public java.util.Map.Entry<K, V> set(int index, java.util.Map.Entry<K, V> object) {
+ load();
+ return super.set(index, object);
+ }
+
+ @Override
+ public List<java.util.Map.Entry<K, V>> subList(int start, int end) {
+ load();
+ return super.subList(start, end);
+ }
+
+ @Override
+ public Object[] toArray() {
+ load();
+ return super.toArray();
+ }
+
+ @Override
+ public <T> T[] toArray(T[] array) {
+ load();
+ return super.toArray(array);
+ }
+
+ @Override
+ public void set(Object value) {
+ load();
+ super.set(value);
+ }
+} \ No newline at end of file
diff --git a/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/mapping/elist/PersistableFeatureMap.java b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/mapping/elist/PersistableFeatureMap.java
new file mode 100755
index 000000000..04e9ba693
--- /dev/null
+++ b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/mapping/elist/PersistableFeatureMap.java
@@ -0,0 +1,539 @@
+/**
+ * <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: PersistableFeatureMap.java,v 1.15 2010/02/04 11:03:00 mtaal Exp $
+ */
+
+package org.eclipse.emf.teneo.mapping.elist;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+import java.util.ListIterator;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.eclipse.emf.common.util.EList;
+import org.eclipse.emf.ecore.EStructuralFeature;
+import org.eclipse.emf.ecore.InternalEObject;
+import org.eclipse.emf.ecore.util.DelegatingFeatureMap;
+import org.eclipse.emf.ecore.util.FeatureMap;
+import org.eclipse.emf.teneo.TeneoException;
+import org.eclipse.emf.teneo.type.FeatureMapEntry;
+import org.eclipse.emf.teneo.util.AssertUtil;
+
+/**
+ * A persistable elist which can be used by different or mappers. This persistable elist works around the idea that the
+ * persisted list (e.g. PersistentList in Hibernate) is the delegate for this elist.
+ *
+ * Note the delegate**() methods are overridden to force a load before anything else happens with the delegated list.
+ * The addUnique. addSet methods are overridden to ensure that the featuremap entries of the right type are passed to
+ * the persistent store.
+ *
+ * @author <a href="mailto:mtaal@elver.org">Martin Taal</a>
+ * @version $Revision: 1.15 $
+ */
+
+public abstract class PersistableFeatureMap extends DelegatingFeatureMap implements
+ PersistableDelegateList<FeatureMap.Entry> {
+
+ private static final long serialVersionUID = 1L;
+
+ /** The logger */
+ private static Log log = LogFactory.getLog(PersistableFeatureMap.class);
+
+ /**
+ * The actual list, must never be an elist as notifications etc. are done by this list
+ */
+ protected List<FeatureMap.Entry> delegate;
+
+ /** Is loaded from backend */
+ private boolean isLoaded = false;
+
+ /** Is being loaded from backend */
+ private boolean isLoading = false;
+
+ /** The string used for logging */
+ protected final String logString;
+
+ /** The type of the elements in this list */
+ private final Class<? extends FeatureMap.Entry> elementType;
+
+ /** Constructor */
+ public PersistableFeatureMap(InternalEObject owner, EStructuralFeature feature, List<FeatureMap.Entry> list) {
+ super(owner, feature);
+ elementType = determineElementType();
+
+ if (list == null) {
+ delegate = new ArrayList<FeatureMap.Entry>();
+ isLoaded = true;
+ } else if (list instanceof EList<?>) {
+ AssertUtil.assertTrue("The passed elist is not a featuremap but a : " + list.getClass().getName()
+ + ". Error in featureMap: " + getLogString(), list instanceof FeatureMap);
+
+ delegate = replaceEntryAll(list);
+ isLoaded = true;
+ } else {
+ delegate = list;
+ isLoaded = list.size() > 0;
+ }
+
+ logString = "FeatureMap of member " + getEStructuralFeature().getName() + " owned by "
+ + owner.getClass().getName() + " with delegate list " + delegate.getClass().getName();
+
+ log.debug("Created persistable featuremap " + logString);
+ }
+
+ /** Returns the element type to be used */
+ protected abstract Class<? extends FeatureMap.Entry> determineElementType();
+
+ /** Returns the element type */
+ public Class<? extends FeatureMap.Entry> getElementType() {
+ return elementType;
+ }
+
+ /** Shortcut to replace entries */
+ protected FeatureMap.Entry replaceEntry(FeatureMap.Entry entry) {
+ if (entry instanceof FeatureMapEntry && ((FeatureMapEntry) entry).belongsToFeatureMap(this)) {
+ return entry;
+ }
+
+ final FeatureMap.Entry emfEntry = entry;
+ return createEntry(emfEntry.getEStructuralFeature(), emfEntry.getValue());
+ }
+
+ /** Convenience to replace all */
+ private List<FeatureMap.Entry> replaceEntryAll(Collection<? extends FeatureMap.Entry> coll) {
+ final ArrayList<FeatureMap.Entry> result = new ArrayList<FeatureMap.Entry>();
+ for (FeatureMap.Entry fe : coll) {
+ result.add(replaceEntry(fe));
+ }
+ return result;
+ }
+
+ /** Creates an exception with the logID added, without a cause */
+ protected TeneoException createException(String msg) {
+ return new TeneoException(msg + "\n" + getLogString());
+ }
+
+ /** Creates an exception with the logID added, without a cause */
+ protected TeneoException createException(String msg, Throwable t) {
+ return new TeneoException(msg + "\n" + getLogString(), t);
+ }
+
+ /** Return the delegate list without doing a load */
+ public List<FeatureMap.Entry> getDelegate() {
+ return delegate;
+ }
+
+ /** Returns the underlying elist */
+ @Override
+ protected List<FeatureMap.Entry> delegateList() {
+ load();
+
+ return delegate;
+ }
+
+ /** Replace the delegating list */
+ public void replaceDelegate(List<FeatureMap.Entry> newDelegate) {
+ AssertUtil.assertTrue("This featuremap " + logString + " already wraps an or specific featuremap",
+ !isPersistencyWrapped());
+
+ delegate = newDelegate;
+ isLoaded = false;
+ }
+
+ /** Returns a string which can be used to log for this elist */
+ public String getLogString() {
+ return logString;
+ }
+
+ /**
+ * Performs the load action if not yet loaded and sends out the load notification
+ */
+ protected void load() {
+ if (isLoaded) {
+ return;
+ }
+
+ // When we are loading we should not be reloaded!
+ // this can happen in the jpox fm impl. when detaching
+ if (isLoading) {
+ return;
+ }
+
+ isLoading = true;
+ doLoad();
+ isLoaded = true;
+ isLoading = false;
+ // StoreUtil.dispatchEListLoadNotification(owner, this,
+ // getEStructuralFeature());
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.emf.ecore.util.EcoreEList#isNotificationRequired()
+ */
+ @Override
+ protected boolean isNotificationRequired() {
+ if (!isLoaded() || isLoading()) {
+ return false; // not yet loaded so no notifications, prevents
+ // infinite looping
+ }
+ return super.isNotificationRequired();
+ }
+
+ /** Is loaded */
+ public boolean isLoaded() {
+ return isLoaded;
+ }
+
+ /** Is loaded */
+ public void setIsLoaded(boolean isLoaded) {
+ this.isLoaded = isLoaded;
+ }
+
+ /** Is loading */
+ public void setIsLoading(boolean isLoading) {
+ this.isLoading = isLoading;
+ }
+
+ /** Returns true if the load action is running and false otherwise */
+ public boolean isLoading() {
+ return isLoading;
+ }
+
+ /**
+ * The load method which should be overridden by the subclass to add lazyloading
+ */
+ protected abstract void doLoad();
+
+ /** Returns true if the wrapped list is a persistency layer specific list */
+ public abstract boolean isPersistencyWrapped();
+
+ /** Override the didadd to enable opposite setting */
+ // MT not necessary anymore in new EMF versions
+ // @Override
+ // protected void didAdd(int index, FeatureMap.Entry obj) {
+ // final NotificationChain nc = inverseAdd(obj, null);
+ // if (nc != null && isNotificationRequired()) {
+ // nc.dispatch();
+ // }
+ // super.didAdd(index, obj);
+ // }
+ /* Override the didremove to enable opposite setting */
+ // @Override
+ // protected void didRemove(int index, FeatureMap.Entry obj) {
+ // final NotificationChain nc = inverseRemove(obj, null);
+ // if (nc != null && isNotificationRequired()) {
+ // nc.dispatch();
+ // }
+ // super.didRemove(index, obj);
+ // }
+ // ---------------------------- Overloaded delegate methods
+ // --------------------------
+ // These methods have been overridden to a load action before the backing
+ // list is
+ // accessed.
+ /** OVerridden to create the correct featuremap entry */
+ @Override
+ protected abstract FeatureMap.Entry createEntry(EStructuralFeature eStructuralFeature, Object value);
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.emf.common.util.DelegatingEList#delegateAdd(int, java.lang.Object)
+ */
+ @Override
+ protected void delegateAdd(int index, FeatureMap.Entry object) {
+ load();
+ super.delegateAdd(index, object);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.emf.common.util.DelegatingEList#delegateAdd(java.lang.Object)
+ */
+ @Override
+ protected void delegateAdd(FeatureMap.Entry object) {
+ load();
+ super.delegateAdd(object);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.emf.common.notify.impl.DelegatingNotifyingListImpl#addAllUnique (java.util.Collection )
+ */
+ @Override
+ public boolean addAllUnique(Collection<? extends FeatureMap.Entry> collection) {
+ return super.addAllUnique(replaceEntryAll(collection));
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.emf.common.notify.impl.DelegatingNotifyingListImpl#addAllUnique (int, java.util.Collection)
+ */
+ @Override
+ public boolean addAllUnique(int index, Collection<? extends FeatureMap.Entry> collection) {
+ return super.addAllUnique(index, replaceEntryAll(collection));
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.emf.common.notify.impl.DelegatingNotifyingListImpl#addUnique (int, java.lang.Object)
+ */
+ @Override
+ public void addUnique(int index, FeatureMap.Entry object) {
+ super.addUnique(index, replaceEntry(object));
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.emf.common.notify.impl.DelegatingNotifyingListImpl#addUnique (java.lang.Object)
+ */
+ @Override
+ public void addUnique(FeatureMap.Entry object) {
+ super.addUnique(replaceEntry(object));
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.emf.common.notify.impl.DelegatingNotifyingListImpl#setUnique (int, java.lang.Object)
+ */
+ @Override
+ public FeatureMap.Entry setUnique(int index, FeatureMap.Entry object) {
+ return super.setUnique(index, replaceEntry(object));
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.emf.common.util.DelegatingEList#delegateBasicList()
+ */
+ @Override
+ protected List<FeatureMap.Entry> delegateBasicList() {
+ load();
+ return super.delegateBasicList();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.emf.common.util.DelegatingEList#delegateClear()
+ */
+ @Override
+ protected void delegateClear() {
+ load();
+ super.delegateClear();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.emf.common.util.DelegatingEList#delegateContains(java.lang .Object)
+ */
+ @Override
+ protected boolean delegateContains(Object object) {
+ load();
+ return super.delegateContains(object);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.emf.common.util.DelegatingEList#delegateContainsAll(java. util.Collection)
+ */
+ @Override
+ protected boolean delegateContainsAll(Collection<?> collection) {
+ load();
+ return super.delegateContainsAll(collection);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.emf.common.util.DelegatingEList#delegateEquals(java.lang. Object)
+ */
+ @Override
+ protected boolean delegateEquals(Object object) {
+ load();
+ return super.delegateEquals(object);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.emf.common.util.DelegatingEList#delegateGet(int)
+ */
+ @Override
+ protected FeatureMap.Entry delegateGet(int index) {
+ load();
+ return super.delegateGet(index);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.emf.common.util.DelegatingEList#delegateHashCode()
+ */
+ @Override
+ protected int delegateHashCode() {
+ load();
+ return super.delegateHashCode();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.emf.common.util.DelegatingEList#delegateIndexOf(java.lang .Object)
+ */
+ @Override
+ protected int delegateIndexOf(Object object) {
+ load();
+ return super.delegateIndexOf(object);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.emf.common.util.DelegatingEList#delegateIsEmpty()
+ */
+ @Override
+ protected boolean delegateIsEmpty() {
+ load();
+ return super.delegateIsEmpty();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.emf.common.util.DelegatingEList#delegateIterator()
+ */
+ @Override
+ protected Iterator<FeatureMap.Entry> delegateIterator() {
+ load();
+ return super.delegateIterator();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.emf.common.util.DelegatingEList#delegateLastIndexOf(java. lang.Object)
+ */
+ @Override
+ protected int delegateLastIndexOf(Object object) {
+ load();
+ return super.delegateLastIndexOf(object);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.emf.common.util.DelegatingEList#delegateListIterator()
+ */
+ @Override
+ protected ListIterator<FeatureMap.Entry> delegateListIterator() {
+ // TODO Auto-generated method stub
+ return super.delegateListIterator();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.emf.common.util.DelegatingEList#delegateRemove(int)
+ */
+ @Override
+ protected FeatureMap.Entry delegateRemove(int index) {
+ load();
+ return super.delegateRemove(index);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.emf.common.util.DelegatingEList#delegateSet(int, java.lang.Object)
+ */
+ @Override
+ protected FeatureMap.Entry delegateSet(int index, FeatureMap.Entry object) {
+ load();
+ // do the delegate set in two steps so that cascade delete works
+ // for featuremap as a component
+ final FeatureMap.Entry old = delegateRemove(index);
+ delegateAdd(index, object);
+ return old;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.emf.common.util.DelegatingEList#delegateSize()
+ */
+ @Override
+ protected int delegateSize() {
+ load();
+ return super.delegateSize();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.emf.common.util.DelegatingEList#delegateToArray()
+ */
+ @Override
+ protected Object[] delegateToArray() {
+ load();
+ return super.delegateToArray();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.emf.common.util.DelegatingEList#delegateToArray(java.lang .Object[])
+ */
+ @Override
+ protected <T> T[] delegateToArray(T[] array) {
+ load();
+ return super.delegateToArray(array);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.emf.common.util.DelegatingEList#delegateToString()
+ */
+ @Override
+ protected String delegateToString() {
+ load();
+ return super.delegateToString();
+ }
+
+ /**
+ * Is overridden because it can't use delegates for equality because the delegate (a hibernate or jpox list) will
+ * try to be equal with this persistable elist.
+ *
+ * This method does jvm instance equality because doing a full-fledge equal would result in a load of the list.
+ */
+ @Override
+ public boolean equals(Object object) {
+ return this == object;
+ }
+} \ No newline at end of file
diff --git a/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/mapping/strategy/EntityNameStrategy.java b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/mapping/strategy/EntityNameStrategy.java
new file mode 100755
index 000000000..049353296
--- /dev/null
+++ b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/mapping/strategy/EntityNameStrategy.java
@@ -0,0 +1,64 @@
+/**
+ * <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: EntityNameStrategy.java,v 1.7 2010/02/06 18:25:46 mtaal Exp $
+ */
+
+package org.eclipse.emf.teneo.mapping.strategy;
+
+import org.eclipse.emf.ecore.EClass;
+import org.eclipse.emf.ecore.EcorePackage;
+import org.eclipse.emf.teneo.annotations.pamodel.PAnnotatedModel;
+import org.eclipse.emf.teneo.extension.ExtensionManagerAware;
+import org.eclipse.emf.teneo.extension.ExtensionPoint;
+
+/**
+ * Converter from entityname to and from an eclass. The entityname is used in
+ * the hql, etc.
+ *
+ * @author <a href="mtaal@elver.org">Martin Taal</a>
+ * @version $Revision: 1.7 $
+ */
+public interface EntityNameStrategy extends ExtensionPoint,
+ ExtensionManagerAware {
+
+ /** The EObject eclass */
+ public static EClass EOBJECT_ECLASS = (EClass) EcorePackage.eINSTANCE
+ .getEClassifier("EObject");
+
+ /** The EObject eclass name */
+ public static String EOBJECT_ECLASS_NAME = EcorePackage.eINSTANCE.getName()
+ + "_" + EOBJECT_ECLASS.getName();
+
+ /**
+ * Determines the name for a given EClass. This name can be used in jsf
+ * pages and queries.
+ *
+ * Note if the eClass is the EObject eclass then the string
+ * EOBJECT_ECLASS_NAME must be returned.
+ */
+ public String toEntityName(EClass eClass);
+
+ /**
+ * Return the EClass for a certain name, searches in the array of epackages
+ */
+ public EClass toEClass(String eClassName);
+
+ /**
+ * @param paModel
+ * the paModel to set
+ */
+ public void setPaModel(PAnnotatedModel paModel);
+
+} \ No newline at end of file
diff --git a/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/mapping/strategy/SQLNameStrategy.java b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/mapping/strategy/SQLNameStrategy.java
new file mode 100755
index 000000000..9799ac757
--- /dev/null
+++ b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/mapping/strategy/SQLNameStrategy.java
@@ -0,0 +1,135 @@
+/**
+ * <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: SQLNameStrategy.java,v 1.11 2011/10/29 06:12:48 mtaal Exp $
+ */
+
+package org.eclipse.emf.teneo.mapping.strategy;
+
+import java.util.List;
+
+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.extension.ExtensionPoint;
+
+/**
+ * Takes care of creating correct names for sql artifacts such as tables,
+ * columns, foreign keys, etc.
+ *
+ * Note that strategies are normally created once for each instance of
+ * persistenceoptions.
+ *
+ * @author <a href="mtaal@elver.org">Martin Taal</a>
+ * @version $Revision: 1.11 $
+ */
+public interface SQLNameStrategy extends ExtensionPoint {
+
+ /**
+ * Converts the name to the required sql setting (length and case). If the
+ * name is too long (see option maximum sql name length) then the prefix is
+ * trunced away.
+ */
+ public abstract String convert(String name);
+
+ /**
+ * Converts the name to the required sql setting (length and case). If the
+ * name is too long (see the option maximum sql name length) then: if
+ * truncPrefix = false then the part after the _ is trunced. if truncPrefix
+ * = true then the part before the _ is trunced. An underscore often occurs
+ * in the name of a join table.
+ */
+ public String convert(String name, boolean truncPrefix);
+
+ /**
+ * The join column name used to join a joined-subclass table with its parent
+ * table
+ */
+ public abstract String getPrimaryKeyJoinColumnName(
+ PAnnotatedEClass aSuperClass, String idFeature);
+
+ /** The join colum name for the secondary table */
+ public abstract String getSecondaryTablePrimaryKeyJoinColumnName(
+ PAnnotatedEStructuralFeature iddef);
+
+ /** Returns the table name for a passed AnnotatedEClass */
+ public abstract String getTableName(PAnnotatedEClass aClass);
+
+ /** Simple column name with optional prefix */
+ public abstract String getColumnName(
+ PAnnotatedEStructuralFeature aStructuralFeature, String prefix);
+
+ /**
+ * Return the name of the foreign key used for this aReference. If null is
+ * returned then the name of the foreign key is not set. Returns the
+ * concatenation of the entityname of the aclass to which the areference
+ * belongs.
+ *
+ * This method is normally called when the PersistenceOption
+ * CREATE_READABLE_FOREIGN_KEY_NAMES is true.
+ */
+ public abstract String getForeignKeyName(
+ PAnnotatedEStructuralFeature aFeature);
+
+ /** Return joincolumn names for many-to-one */
+ public abstract List<String> getManyToOneJoinColumnNames(
+ PAnnotatedEReference aReference);
+
+ /** Return a list of join columns for a many is eAttribute */
+ public abstract List<String> getOneToManyEAttributeJoinColumns(
+ PAnnotatedEAttribute aAttribute);
+
+ /** Return a list of join columns for a many is eReference */
+ public abstract List<String> getOneToManyEReferenceJoinColumns(
+ PAnnotatedEReference aReference);
+
+ /**
+ * Return a list of join columns for a join table for a many to many
+ */
+ public abstract List<String> getJoinTableJoinColumns(
+ PAnnotatedEReference aReference, boolean inverse);
+
+ /** Return the name of the join table in case of a list of simpletypes */
+ public abstract String getJoinTableName(PAnnotatedEAttribute aAttribute);
+
+ /** Return the name of the join table */
+ public abstract String getJoinTableName(PAnnotatedEReference aReference);
+
+ /**
+ * @see PersistenceOptions#DISCRIMINATOR_COLUMN_NAME
+ */
+ public abstract String getDiscriminatorColumnName();
+
+ /**
+ * Return the name of the version column used.
+ */
+ public abstract String getVersionColumnName();
+
+ /**
+ * Return the column name for the id column of the idbag join table.
+ */
+ public abstract String getIdBagIDColumn();
+
+ /** Return the column name for the synthetic ID column */
+ public abstract String getSyntheticIDColumnName();
+
+ /**
+ * Sets the PersistenceOptions used. This is mainly to support backward
+ * compatibility with older version in which the naming strategy was
+ * controlled by options.
+ */
+ public abstract void setPersistenceOptions(PersistenceOptions po);
+} \ No newline at end of file
diff --git a/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/mapping/strategy/StrategyUtil.java b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/mapping/strategy/StrategyUtil.java
new file mode 100755
index 000000000..cc26d2dde
--- /dev/null
+++ b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/mapping/strategy/StrategyUtil.java
@@ -0,0 +1,124 @@
+/**
+ * <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: StrategyUtil.java,v 1.7 2009/03/30 06:41:00 mtaal Exp $
+ */
+
+package org.eclipse.emf.teneo.mapping.strategy;
+
+import java.util.ArrayList;
+import java.util.List;
+
+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.PersistenceOptions;
+import org.eclipse.emf.teneo.annotations.pamodel.PAnnotatedEAttribute;
+import org.eclipse.emf.teneo.annotations.pamodel.PAnnotatedEClass;
+import org.eclipse.emf.teneo.annotations.pamodel.PAnnotatedEStructuralFeature;
+import org.eclipse.emf.teneo.annotations.pamodel.PAnnotatedModel;
+import org.eclipse.emf.teneo.util.StoreUtil;
+
+/**
+ * Contains different util methods related to strategies.
+ *
+ * @author <a href="mailto:mtaal@elver.org">Martin Taal</a>
+ * @version $Revision: 1.7 $
+ */
+
+public class StrategyUtil {
+
+ /** Returns the entity name based on a specific logic */
+ public static String getEntityName(EntityNameStrategy ens,
+ PersistenceOptions po, PAnnotatedModel paModel, EClass eclass) {
+ if (eclass == null) {
+ throw new IllegalArgumentException(
+ "Passed eclass is null."
+ + "This can occur if epackages which refer to eachother are placed in different ecore/xsd files "
+ + "and they are not read using one resource set. The reference from one epackage to another must be "
+ + "resolvable by EMF.");
+ }
+
+ // ok, here we figure out if it is an EMap. if so, we return the
+ // destination child name, not the keyToValueEntry wrapper
+ final PAnnotatedEClass aclass = (paModel != null ? paModel
+ .getPAnnotated(eclass) : null);
+ if (aclass == null && paModel != null) { // happens when the eclass is
+ // EObject itself
+ return ens.toEntityName(eclass);
+ }
+ if (po.isMapEMapAsTrueMap() && StoreUtil.isMapEntry(eclass)) {
+ // ok, it is an EMAp, get the annotaetd class of the child
+ EStructuralFeature feature = eclass.getEStructuralFeature("value");
+ if (feature instanceof EReference) {
+ return getEntityName(ens, po, paModel, ((EReference) feature)
+ .getEReferenceType());
+ }
+ return ((EAttribute) feature).getEType().getInstanceClassName();
+ }
+ //
+ // if (aclass != null && aclass.getEntity() != null &&
+ // aclass.getEntity().getName() != null) {
+ // return aclass.getEntity().getName();
+ // }
+ return ens.toEntityName(eclass);
+ }
+
+ /**
+ * Returns the list of names of id props of the eclass, walks the
+ * inheritance tree to find the id feature, if none is found then the
+ */
+ public static List<String> getIDFeaturesNames(PAnnotatedEClass aClass,
+ String optionDefaultIDFeatureName) {
+ final List<String> list = getIDFeaturesNamesRecurse(aClass);
+ // See, 172756
+ if (list.isEmpty()) {
+ list.add(optionDefaultIDFeatureName);
+ }
+ return list;
+ }
+
+ /** Internal will walk the inheritance tree to find the id feature */
+ private static List<String> getIDFeaturesNamesRecurse(
+ PAnnotatedEClass aClass) {
+ final ArrayList<String> list = new ArrayList<String>();
+ for (EStructuralFeature feature : aClass.getModelEClass()
+ .getEStructuralFeatures()) {
+ final PAnnotatedEStructuralFeature aStructuralFeature = aClass
+ .getPaModel().getPAnnotated(feature);
+ if (aStructuralFeature instanceof PAnnotatedEAttribute) {
+ final PAnnotatedEAttribute aAttribute = (PAnnotatedEAttribute) aStructuralFeature;
+ final String attrName = aAttribute.getModelEAttribute()
+ .getName();
+ if (aAttribute.getId() != null && !list.contains(attrName)) {
+ list.add(attrName);
+ }
+ }
+ }
+
+ if (list.isEmpty()
+ && aClass.getModelEClass().getESuperTypes().size() > 0) {
+ for (EClass eClass : aClass.getModelEClass().getESuperTypes()) {
+ final PAnnotatedEClass aSuperClass = aClass.getPaModel()
+ .getPAnnotated(eClass);
+ if (aSuperClass != null) {
+ final List<String> superList = getIDFeaturesNamesRecurse(aSuperClass);
+ list.removeAll(superList);
+ list.addAll(superList);
+ }
+ if (!list.isEmpty()) {
+ return list;
+ }
+ }
+ if (!list.isEmpty()) {
+ return list;
+ }
+ // fall through
+ }
+ return list;
+ }
+
+} \ No newline at end of file
diff --git a/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/mapping/strategy/impl/ClassicEntityNameStrategy.java b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/mapping/strategy/impl/ClassicEntityNameStrategy.java
new file mode 100755
index 000000000..c62ea9625
--- /dev/null
+++ b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/mapping/strategy/impl/ClassicEntityNameStrategy.java
@@ -0,0 +1,164 @@
+/**
+ * <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: ClassicEntityNameStrategy.java,v 1.7 2009/07/28 03:39:44 mtaal Exp $
+ */
+
+package org.eclipse.emf.teneo.mapping.strategy.impl;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.eclipse.emf.ecore.EClass;
+import org.eclipse.emf.ecore.EcorePackage;
+import org.eclipse.emf.teneo.annotations.pamodel.PAnnotatedEClass;
+import org.eclipse.emf.teneo.annotations.pamodel.PAnnotatedEPackage;
+import org.eclipse.emf.teneo.annotations.pamodel.PAnnotatedModel;
+import org.eclipse.emf.teneo.classloader.ClassLoaderResolver;
+import org.eclipse.emf.teneo.classloader.StoreClassLoadException;
+import org.eclipse.emf.teneo.ecore.EModelResolver;
+import org.eclipse.emf.teneo.extension.ExtensionManager;
+import org.eclipse.emf.teneo.mapping.strategy.EntityNameStrategy;
+
+/**
+ * This implementation assumes that EClass names are unique. It will (de)Resolve using the EClass name.
+ *
+ * @author <a href="mtaal@elver.org">Martin Taal</a>
+ * @version $Revision: 1.7 $
+ */
+public class ClassicEntityNameStrategy implements EntityNameStrategy {
+
+ /** The logger */
+ private static Log log = LogFactory.getLog(ClassicEntityNameStrategy.class);
+
+ /** The singleton instance as it is thread safe */
+ public static final ClassicEntityNameStrategy INSTANCE = new ClassicEntityNameStrategy();
+
+ // The pamodel for which this is done
+ private PAnnotatedModel paModel;
+
+ private ExtensionManager extensionManager;
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.elver.ecore.spring.EClassResolver#deResolve(org.eclipse.emf.ecore .EClass)
+ */
+ public String toEntityName(EClass eClass) {
+ if (eClass == EOBJECT_ECLASS) {
+ return EOBJECT_ECLASS_NAME;
+ }
+
+ if (eClass == null) {
+ throw new IllegalArgumentException(
+ "Passed eclass is null."
+ + "This can occur if epackages which refer to eachother are placed in different ecore/xsd files "
+ + "and they are not read using one resource set. The reference from one epackage to another must be "
+ + "resolvable by EMF.");
+ }
+
+ if (eClass.getName() == null) {
+ throw new IllegalArgumentException(
+ "EClass "
+ + eClass.toString()
+ + " has a null name."
+ + "This can occur if epackages which refer to eachother are placed in different ecore/xsd files "
+ + "and they are not read using one resource set. The reference from one epackage to another must be "
+ + "resolvable by EMF.");
+ }
+
+ return eClass.getName();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.elver.ecore.spring.EClassResolver#resolve(java.lang.String)
+ */
+ public EClass toEClass(String eClassName) {
+ if (eClassName == null) {
+ throw new IllegalArgumentException("eClassName may not be null");
+ }
+
+ if (eClassName.compareTo(EOBJECT_ECLASS_NAME) == 0) {
+ return EcorePackage.eINSTANCE.getEObject();
+ }
+
+ // now try all epackages
+ EClass eClass = null;
+ for (final PAnnotatedEPackage aPackage : getPaModel().getPaEPackages()) {
+ for (final PAnnotatedEClass aClass : aPackage.getPaEClasses()) {
+ final EClass checkEClass = aClass.getModelEClass();
+ if (checkEClass.getName().compareTo(eClassName) == 0) {
+ if (eClass != null) {
+ // doubly entry! Actually require different resolver
+ throw new IllegalArgumentException("There is more than one EClass with the same name ("
+ + eClassName + " in EPackage " + eClass.getEPackage().getName() + " and "
+ + aPackage.getModelEPackage().getName()
+ + ". A different EClassResolver should be used.");
+ }
+ }
+ eClass = checkEClass;
+ }
+ }
+
+ // we didn'y find it, perhaps it is fully qualified, lets try by full
+ // class name
+ if (eClass == null) {
+ try {
+ final Class<?> cls = ClassLoaderResolver.classForName(eClassName);
+ eClass = EModelResolver.instance().getEClass(cls);
+ } catch (StoreClassLoadException e) {
+ log.debug("Failed to retreive ECLass for name: " + eClassName
+ + ". This is no problem if this is a featuremap.");
+ }
+ }
+
+ if (eClass == null) {
+ throw new IllegalArgumentException("No EClass found using " + eClassName);
+ }
+ return eClass;
+ }
+
+ /**
+ * @return the paModel
+ */
+ public PAnnotatedModel getPaModel() {
+ return paModel;
+ }
+
+ /**
+ * @param paModel
+ * the paModel to set
+ */
+ public void setPaModel(PAnnotatedModel paModel) {
+ this.paModel = paModel;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.emf.teneo.extension.ExtensionManagerAware#setExtensionManager
+ * (org.eclipse.emf.teneo.extension.ExtensionManager)
+ */
+ public void setExtensionManager(ExtensionManager extensionManager) {
+ this.extensionManager = extensionManager;
+ }
+
+ /**
+ * @return the extensionManager
+ */
+ public ExtensionManager getExtensionManager() {
+ return extensionManager;
+ }
+}
diff --git a/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/mapping/strategy/impl/ClassicSQLNameStrategy.java b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/mapping/strategy/impl/ClassicSQLNameStrategy.java
new file mode 100755
index 000000000..2a412a014
--- /dev/null
+++ b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/mapping/strategy/impl/ClassicSQLNameStrategy.java
@@ -0,0 +1,611 @@
+/**
+ * <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: ClassicSQLNameStrategy.java,v 1.20 2011/10/29 06:12:49 mtaal Exp $
+ */
+
+package org.eclipse.emf.teneo.mapping.strategy.impl;
+
+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.EClass;
+import org.eclipse.emf.ecore.EReference;
+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.pamodel.PAnnotatedModel;
+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;
+import org.eclipse.emf.teneo.util.AssertUtil;
+
+/**
+ * Implements the sql naming strategy of older versions of Teneo. This
+ * implementation is driven by the options set in the PersistenceOptions.
+ *
+ * @author <a href="mtaal@elver.org">Martin Taal</a>
+ * @version $Revision: 1.20 $
+ */
+public class ClassicSQLNameStrategy implements SQLNameStrategy,
+ ExtensionManagerAware {
+
+ // The logger
+ protected static final Log log = LogFactory
+ .getLog(ClassicSQLNameStrategy.class);
+
+ // The local members for several options
+ protected String optionJoinTableNamingStrategy;
+ protected String optionJoinColumnNamingStrategy;
+ protected int optionMaximumSqlLength;
+ protected EntityNameStrategy entityNameStrategy;
+ protected PersistenceOptions persistenceOptions;
+ protected boolean optionSQLUpperCase = false;
+ protected boolean optionSQLLowerCase = false;
+ protected String optionTableNamePrefix = "";
+ protected String optionColumnNamePrefix = "";
+ protected String optionForeignKeyNamePrefix = "";
+ protected String optionSQLNameColumnPrefix = "";
+
+ private ExtensionManager extensionManager;
+
+ /*
+ * (non-Javadoc)
+ *
+ * @seeorg.eclipse.emf.teneo.mapping.strategy.SqlNameStrategy#
+ * getPrimaryKeyJoinColumnName
+ * (org.eclipse.emf.teneo.annotations.pamodel.PAnnotatedEClass,
+ * java.lang.String)
+ */
+ public String getPrimaryKeyJoinColumnName(PAnnotatedEClass aSuperClass,
+ String idFeature) {
+ return optionColumnNamePrefix
+ + convert(
+ getEntityName(aSuperClass.getPaModel(),
+ aSuperClass.getModelEClass())
+ + "_" + idFeature, true);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @seeorg.eclipse.emf.teneo.mapping.strategy.SqlNameStrategy#
+ * getSecondaryTablePrimaryKeyJoinColumnName
+ * (org.eclipse.emf.teneo.annotations.pamodel.PAnnotatedEStructuralFeature)
+ */
+ public String getSecondaryTablePrimaryKeyJoinColumnName(
+ PAnnotatedEStructuralFeature iddef) {
+ return optionColumnNamePrefix
+ + convert(iddef.getModelEStructuralFeature().getName());
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * org.eclipse.emf.teneo.mapping.strategy.SqlNameStrategy#getTableName(org
+ * .eclipse.emf.teneo.annotations.pamodel.PAnnotatedEClass)
+ */
+ public String getTableName(PAnnotatedEClass aClass) {
+ return optionTableNamePrefix
+ + convert(getEntityName(aClass.getPaModel(),
+ aClass.getModelEClass()));
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * org.eclipse.emf.teneo.mapping.strategy.SqlNameStrategy#getColumnName(
+ * org.eclipse.emf.teneo.annotations.pamodel.PAnnotatedEStructuralFeature)
+ */
+ public String getColumnName(
+ PAnnotatedEStructuralFeature aStructuralFeature, String prefix) {
+ if (prefix != null) {
+ return convert(prefix + "_"
+ + aStructuralFeature.getModelEStructuralFeature().getName());
+ }
+ return optionColumnNamePrefix
+ + convert(aStructuralFeature.getModelEStructuralFeature()
+ .getName());
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * org.eclipse.emf.teneo.mapping.strategy.SqlNameStrategy#getForeignKeyName
+ * (org.eclipse.emf.teneo.annotations.pamodel.PAnnotatedEStructuralFeature)
+ */
+ public String getForeignKeyName(PAnnotatedEStructuralFeature aFeature) {
+ final PAnnotatedEClass aClass = aFeature.getPaEClass();
+ return optionForeignKeyNamePrefix
+ + convert(
+ getEntityName(aClass.getPaModel(),
+ aClass.getModelEClass())
+ + "_"
+ + aFeature.getModelEStructuralFeature()
+ .getName(), true);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @seeorg.eclipse.emf.teneo.mapping.strategy.SqlNameStrategy#
+ * getManyToOneJoinColumnNames
+ * (org.eclipse.emf.teneo.annotations.pamodel.PAnnotatedEReference)
+ */
+ public List<String> getManyToOneJoinColumnNames(
+ PAnnotatedEReference aReference) {
+ final EReference eref = aReference.getModelEReference();
+
+ // isTransient occurs for computed featuremap features, these are
+ // ignored
+ // later on
+ assert (eref.isTransient() || !eref.isMany()); // otherwise this should
+ // have been a mtm
+
+ // in case of many-to-one to qualify use the name of the class to which
+ // is refered
+ // this is just there for backward compatibility, see the case of
+ // the manytoone and onetoone below.
+ final PAnnotatedEClass aClass;
+ if (eref.getEOpposite() == null) {
+ aClass = aReference.getAReferenceType();
+ } else {
+ // the aclass is just the class of the structuralfeature itself.
+ // this is the most common case the name of the join column reflects
+ // the owner of the one-to-many
+ aClass = aReference.getPaEClass();
+ }
+ final String typeName = getMappingName(aClass);
+ final String featureName = eref.getName();
+
+ final List<String> result = new ArrayList<String>();
+ final List<String> names = StrategyUtil.getIDFeaturesNames(aClass,
+ persistenceOptions.getDefaultIDFeatureName());
+ final boolean simpleNaming = optionJoinColumnNamingStrategy
+ .compareTo("simple") == 0;
+ for (String name : names) {
+ final String postFix;
+ if (names.size() == 1 && simpleNaming) {
+ postFix = "";
+ } else {
+ postFix = "_" + name;
+ }
+
+ final String jcName;
+ if (simpleNaming) {
+ jcName = featureName + postFix;
+ } else { // backward compatibility
+ jcName = typeName + "_" + featureName + postFix;
+ }
+ result.add(optionColumnNamePrefix + convert(jcName, true));
+ }
+ return result;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @seeorg.eclipse.emf.teneo.mapping.strategy.SqlNameStrategy#
+ * getOneToManyEAttributeJoinColumns
+ * (org.eclipse.emf.teneo.annotations.pamodel.PAnnotatedEAttribute)
+ */
+ public List<String> getOneToManyEAttributeJoinColumns(
+ PAnnotatedEAttribute aAttribute) {
+ final PAnnotatedEClass aClass = aAttribute.getPaEClass();
+ final String typeName = getMappingName(aClass);
+ final String featureName = aAttribute.getModelEAttribute().getName();
+
+ final List<String> result = new ArrayList<String>();
+ final List<String> names = StrategyUtil.getIDFeaturesNames(aClass,
+ persistenceOptions.getDefaultIDFeatureName());
+ final boolean simpleNaming = optionJoinColumnNamingStrategy
+ .compareTo("simple") == 0;
+ for (String name : names) {
+ final String postFix;
+ if (names.size() == 1 && simpleNaming) {
+ postFix = "";
+ } else {
+ postFix = "_" + name;
+ }
+
+ final String jcName = typeName + "_" + featureName + postFix;
+ result.add(optionColumnNamePrefix + convert(jcName, true));
+ }
+ return result;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @seeorg.eclipse.emf.teneo.mapping.strategy.SqlNameStrategy#
+ * getOneToManyEReferenceJoinColumns
+ * (org.eclipse.emf.teneo.annotations.pamodel.PAnnotatedEReference)
+ */
+ public List<String> getOneToManyEReferenceJoinColumns(
+ PAnnotatedEReference aReference) {
+ final PAnnotatedEClass aClass = aReference.getPaEClass();
+ final String typeName;
+ final String featureName;
+ // for backwards compatibility if the other side is there then use the
+ // name
+ // of the other side for the typeName and featureName. The many-to-one
+ // determines
+ // the naming
+ if (aReference.getModelEReference().getEOpposite() != null) {
+ typeName = getMappingName(aReference.getAReferenceType());
+ featureName = aReference.getModelEReference().getEOpposite()
+ .getName();
+ } else {
+ typeName = getMappingName(aClass);
+ featureName = aReference.getModelEReference().getName();
+ }
+
+ final List<String> result = new ArrayList<String>();
+ final List<String> names = StrategyUtil.getIDFeaturesNames(aClass,
+ persistenceOptions.getDefaultIDFeatureName());
+ final boolean simpleNaming = optionJoinColumnNamingStrategy
+ .compareTo("simple") == 0;
+ for (String name : names) {
+ final String postFix;
+ if (names.size() == 1 && simpleNaming) {
+ postFix = "";
+ } else {
+ postFix = "_" + name;
+ }
+
+ final String jcName = typeName + "_" + featureName + postFix;
+ result.add(optionColumnNamePrefix + convert(jcName, true));
+ }
+ return result;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @seeorg.eclipse.emf.teneo.mapping.strategy.SqlNameStrategy#
+ * getJoinTableJoinColumns
+ * (org.eclipse.emf.teneo.annotations.pamodel.PAnnotatedEReference, boolean)
+ */
+ public List<String> getJoinTableJoinColumns(
+ PAnnotatedEReference aReference, boolean inverse) {
+ final PAnnotatedEClass aClass;
+ final String typeName;
+ String featureName;
+ if (inverse) {
+ aClass = aReference.getAReferenceType();
+ if (aReference.getModelEReference().getEOpposite() != null) {
+ typeName = getMappingName(aReference.getAReferenceType());
+ featureName = "_"
+ + aReference.getModelEReference().getEOpposite()
+ .getName();
+ } else {
+ typeName = getMappingName(aReference.getAReferenceType());
+ featureName = "";
+ }
+ } else {
+ aClass = aReference.getPaEClass();
+ typeName = getMappingName(aClass);
+ featureName = "_" + aReference.getModelEReference().getName();
+ }
+ // for backward compatibility, only use featurename if the reference is
+ // to itself
+ if (aReference.getAReferenceType() != aReference.getPaEClass()) {
+ featureName = "";
+ }
+
+ final List<String> result = new ArrayList<String>();
+ final List<String> names = StrategyUtil.getIDFeaturesNames(aClass,
+ persistenceOptions.getDefaultIDFeatureName());
+ final boolean simpleNaming = optionJoinColumnNamingStrategy
+ .compareTo("simple") == 0;
+ for (String name : names) {
+ final String postFix;
+ if (names.size() == 1 && simpleNaming) {
+ postFix = "";
+ } else {
+ postFix = "_" + name;
+ }
+
+ final String jcName = typeName + featureName + postFix;
+ result.add(optionColumnNamePrefix + convert(jcName, true));
+ }
+ return result;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * org.eclipse.emf.teneo.mapping.strategy.SqlNameStrategy#getJoinTableName
+ * (org.eclipse.emf.teneo.annotations.pamodel.PAnnotatedEAttribute)
+ */
+ public String getJoinTableName(PAnnotatedEAttribute aAttribute) {
+ // note for array the isMany is false, so disable this check
+ // assert (aAttribute.getModelEAttribute().isMany());
+ final PAnnotatedEClass aClass = aAttribute.getPaEClass();
+ String truncedName = getEntityName(aClass.getPaModel(),
+ aClass.getModelEClass())
+ + "_" + aAttribute.getModelEAttribute().getName();
+ return optionTableNamePrefix + convert(truncedName, true);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * org.eclipse.emf.teneo.mapping.strategy.SqlNameStrategy#getJoinTableName
+ * (org.eclipse.emf.teneo.annotations.pamodel.PAnnotatedEReference)
+ */
+ public String getJoinTableName(PAnnotatedEReference aReference) {
+ final EReference eReference = aReference.getModelEReference();
+ final boolean isEObject = eReference.getEType() == ClassicEntityNameStrategy.EOBJECT_ECLASS;
+ final String jTableName;
+
+ EReference eOpposite = eReference.getEOpposite();
+ if (aReference.getManyToMany() != null
+ && aReference.getManyToMany().isIndexed()) {
+ // In case the reference is not indexed then one join table can be
+ // used for both sides
+ // If indexed then separate join tables should be used.
+ eOpposite = null; // trick to force a specific naming
+ }
+
+ if (!isEObject
+ && optionJoinTableNamingStrategy.compareToIgnoreCase("ejb3") == 0) {
+ // table name is the entityname of the eclass of the reference and
+ // entityname of
+ // the eclass of the refered to
+ final String thisEntityName = getEntityName(
+ aReference.getPaModel(), eReference.getEContainingClass());
+ final String thatEntityName = getEntityName(
+ aReference.getPaModel(), eReference.getEReferenceType());
+
+ if (eOpposite != null && eOpposite.isMany()
+ && compareNames(eReference, eOpposite)) {
+ jTableName = thatEntityName + "_" + thisEntityName;
+ } else {
+ jTableName = thisEntityName + "_" + thatEntityName;
+ }
+ } else {
+ AssertUtil.assertTrue(
+ "option optionJoinTableNamingStrategy "
+ + optionJoinTableNamingStrategy + " not supported",
+ isEObject
+ || optionJoinTableNamingStrategy
+ .compareToIgnoreCase("unique") == 0);
+ if (eOpposite != null && eOpposite.isMany()
+ && compareNames(eReference, eOpposite)) {
+ final String thatEntityName = getEntityName(
+ aReference.getPaModel(),
+ eOpposite.getEContainingClass());
+ jTableName = thatEntityName + "_" + eOpposite.getName();
+ } else {
+ final String thisEntityName = getEntityName(
+ aReference.getPaModel(),
+ eReference.getEContainingClass());
+ jTableName = thisEntityName + "_" + eReference.getName();
+ }
+ }
+ return optionTableNamePrefix + convert(jTableName);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.emf.teneo.mapping.strategy.SqlNameStrategy#
+ * getDiscriminatorColumnName()
+ */
+ public String getDiscriminatorColumnName() {
+ return optionColumnNamePrefix
+ + convert(persistenceOptions.getDiscriminatorColumnName());
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * org.eclipse.emf.teneo.mapping.strategy.SqlNameStrategy#getVersionColumnName
+ * ()
+ */
+ public String getVersionColumnName() {
+ return optionColumnNamePrefix
+ + convert(persistenceOptions.getVersionColumnName());
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * org.eclipse.emf.teneo.mapping.strategy.SqlNameStrategy#getIdBagIDColumn()
+ */
+ public String getIdBagIDColumn() {
+ return optionColumnNamePrefix
+ + convert(persistenceOptions.getIDBagIDColumnName());
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @seeorg.eclipse.emf.teneo.mapping.strategy.SqlNameStrategy#
+ * getSyntheticIDColumnName()
+ */
+ public String getSyntheticIDColumnName() {
+ return optionColumnNamePrefix
+ + convert(persistenceOptions.getIdColumnName());
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * org.eclipse.emf.teneo.mapping.strategy.SqlNameStrategy#setPersistenceOptions
+ * (org.eclipse.emf.teneo.PersistenceOptions)
+ */
+ public void setPersistenceOptions(PersistenceOptions po) {
+ optionMaximumSqlLength = po.getMaximumSqlNameLength();
+ optionJoinTableNamingStrategy = po.getJoinTableNamingStrategy();
+ optionJoinColumnNamingStrategy = po.getJoinColumnNamingStrategy();
+
+ final String optionSQLCaseStrategy = po.getSQLCaseStrategy();
+ if (optionSQLCaseStrategy.toLowerCase().compareTo("lowercase") == 0) {
+ optionSQLLowerCase = true;
+ } else if (optionSQLCaseStrategy.toLowerCase().compareTo("uppercase") == 0) {
+ optionSQLUpperCase = true;
+ }
+ optionTableNamePrefix = po.getSQLTableNamePrefix();
+ optionColumnNamePrefix = po.getSQLColumnNamePrefix();
+ optionForeignKeyNamePrefix = po.getSQLForeignKeyNamePrefix();
+ optionSQLNameColumnPrefix = po.getSQLColumnNamePrefix();
+ persistenceOptions = po;
+ }
+
+ // Returns the entityname of the refered to entity
+ protected String getEntityName(PAnnotatedModel paModel, EClass eClass) {
+ return StrategyUtil.getEntityName(getEntityNameStrategy(),
+ persistenceOptions, paModel, eClass);
+ }
+
+ // Returns the entityname of the refered to entity
+ protected String getMappingName(PAnnotatedEClass aClass) {
+ return aClass.getModelEClass().getName();
+ // return StrategyUtil.getEntityName(getEntityNameStrategy(),
+ // persistenceOptions, aClass.getPaModel(), aClass
+ // .getModelEClass());
+ }
+
+ public String getIndexColumnName(PAnnotatedEStructuralFeature aFeature) {
+ return optionSQLNameColumnPrefix
+ + (getMappingName(aFeature.getPaEClass()) + "_"
+ + aFeature.getModelEStructuralFeature().getName() + "_IDX")
+ .toUpperCase();
+
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * org.eclipse.emf.teneo.mapping.strategy.SqlNameStrategy#convert(java.lang
+ * .String)
+ */
+ public String convert(String name) {
+ return convert(name, false);
+ }
+
+ public String convert(String name, boolean truncPrefix) {
+ final String result = trunc(optionMaximumSqlLength, name, truncPrefix);
+ if (optionSQLLowerCase) {
+ return result.toLowerCase();
+ } else if (optionSQLUpperCase) {
+ return result.toUpperCase();
+ } else {
+ return result;
+ }
+ }
+
+ /**
+ * 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.getEContainingClass().getName()
+ + here.getName();
+ final String nameThere = there.getEContainingClass().getName()
+ + there.getName();
+ assert (nameHere.compareTo(nameThere) != 0);
+ return nameHere.compareTo(nameThere) > 0;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * org.eclipse.emf.teneo.mapping.strategy.SqlNameStrategy#getExtensionManager
+ * ()
+ */
+ public ExtensionManager getExtensionManager() {
+ return extensionManager;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * org.eclipse.emf.teneo.mapping.strategy.SqlNameStrategy#setExtensionManager
+ * (org.eclipse.emf.teneo.extension.ExtensionManager)
+ */
+ public void setExtensionManager(ExtensionManager extensionManager) {
+ this.extensionManager = extensionManager;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * org.eclipse.emf.teneo.mapping.strategy.SqlNameStrategy#getEntityNameStrategy
+ * ()
+ */
+ public EntityNameStrategy getEntityNameStrategy() {
+ if (entityNameStrategy == null) {
+ entityNameStrategy = getExtensionManager().getExtension(
+ EntityNameStrategy.class);
+ }
+ return entityNameStrategy;
+ }
+
+ /**
+ * Utility method to truncate a column/table name, the truncPrefix
+ * determines if the part before the _ (the prefix) or after the _ (the
+ * suffix) is truncated. A _ often occurs in a jointable name.
+ */
+ protected String trunc(int optionMaximumSqlLength, String truncName,
+ boolean truncPrefix) {
+ final String correctedName = truncName.replace('.', '_');
+
+ if (optionMaximumSqlLength == -1) {
+ return correctedName;
+ }
+ if (correctedName.length() < optionMaximumSqlLength) {
+ return correctedName;
+ }
+
+ if (!truncPrefix) { // this truncs away the suffix
+ return correctedName.substring(0, optionMaximumSqlLength);
+ }
+
+ // truncate the part before the last _ because this is often the suffix
+ final int underscore = correctedName.lastIndexOf('_');
+ if (underscore != -1 && underscore > 0) {
+ final String usStr = correctedName.substring(underscore);
+ if ((optionMaximumSqlLength - usStr.length()) < 0) {
+ return correctedName;
+ }
+ return correctedName.substring(0,
+ optionMaximumSqlLength - usStr.length())
+ + usStr;
+ }
+
+ return correctedName.substring(0, optionMaximumSqlLength);
+ }
+
+} \ No newline at end of file
diff --git a/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/mapping/strategy/impl/EntityInterfaceNameStrategy.java b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/mapping/strategy/impl/EntityInterfaceNameStrategy.java
new file mode 100755
index 000000000..68e26af4c
--- /dev/null
+++ b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/mapping/strategy/impl/EntityInterfaceNameStrategy.java
@@ -0,0 +1,212 @@
+/**
+ * <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: EntityInterfaceNameStrategy.java,v 1.3 2009/03/30 07:53:04 mtaal Exp $
+ */
+
+package org.eclipse.emf.teneo.mapping.strategy.impl;
+
+import java.util.concurrent.ConcurrentHashMap;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.eclipse.emf.ecore.EClass;
+import org.eclipse.emf.ecore.EcorePackage;
+import org.eclipse.emf.teneo.annotations.pamodel.PAnnotatedEClass;
+import org.eclipse.emf.teneo.annotations.pamodel.PAnnotatedEPackage;
+import org.eclipse.emf.teneo.annotations.pamodel.PAnnotatedModel;
+import org.eclipse.emf.teneo.extension.ExtensionManager;
+import org.eclipse.emf.teneo.util.StoreUtil;
+
+/**
+ * This implementation will first use the name of the entity annotation and then the interface name
+ *
+ * @author <a href="mtaal@elver.org">Martin Taal</a>
+ * @version $Revision: 1.3 $
+ */
+public class EntityInterfaceNameStrategy extends EntityResolvingNameStrategy {
+
+ /** The logger */
+ private static Log log = LogFactory.getLog(EntityInterfaceNameStrategy.class);
+
+ /** The singleton instance as it is thread safe */
+ public static final EntityInterfaceNameStrategy INSTANCE = new EntityInterfaceNameStrategy();
+
+ // The pamodel for which this is done
+ private PAnnotatedModel paModel;
+
+ // Internal cache name from name to eclass
+ private ConcurrentHashMap<String, EClass> entityNameToEClass = new ConcurrentHashMap<String, EClass>();
+
+ private ExtensionManager extensionManager;
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.elver.ecore.spring.EClassResolver#deResolve(org.eclipse.emf.ecore .EClass)
+ */
+ @Override
+ public String toEntityName(EClass eClass) {
+ if (eClass == EOBJECT_ECLASS) {
+ return EOBJECT_ECLASS_NAME;
+ }
+
+ if (eClass == null) {
+ throw new IllegalArgumentException(
+ "Passed eclass is null."
+ + "This can occur if epackages which refer to eachother are placed in different ecore/xsd files "
+ + "and they are not read using one resource set. The reference from one epackage to another must be "
+ + "resolvable by EMF.");
+ }
+
+ if (eClass.getName() == null) {
+ throw new IllegalArgumentException(
+ "EClass " +
+ eClass.toString() +
+ " has a null name." +
+ "This can occur if epackages which refer to eachother are placed in different ecore/xsd files " +
+ "and they are not read using one resource set. The reference from one epackage to another must be " +
+ "resolvable by EMF.");
+ }
+
+ // check if there is an entity annotation on the eclass with a name set
+ final PAnnotatedEClass aClass = getPaModel().getPAnnotated(eClass);
+ if (aClass != null && aClass.getEntity() != null && aClass.getEntity().getName() != null) {
+ return aClass.getEntity().getName();
+ }
+
+ if (eClass.getInstanceClassName() != null) {
+ return eClass.getInstanceClassName();
+ }
+ return eClass.getName();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.elver.ecore.spring.EClassResolver#resolve(java.lang.String)
+ */
+ @Override
+ public EClass toEClass(String eClassName) {
+ if (eClassName == null) {
+ throw new IllegalArgumentException("eClassName may not be null");
+ }
+
+ if (eClassName.compareTo(EOBJECT_ECLASS_NAME) == 0) {
+ return EcorePackage.eINSTANCE.getEObject();
+ }
+
+ EClass eClass = null;
+ if ((eClass = entityNameToEClass.get(eClassName)) != null) {
+ return eClass;
+ }
+
+ // first try the entityname
+ for (final PAnnotatedEPackage aPackage : getPaModel().getPaEPackages()) {
+ for (final PAnnotatedEClass aClass : aPackage.getPaEClasses()) {
+ if (aClass.getEntity() != null && aClass.getEntity().getName() != null &&
+ aClass.getEntity().getName().compareTo(eClassName) == 0 &&
+ !StoreUtil.isMapEntry(aClass.getModelEClass())) { // map
+ // entries
+ // are
+ // ignored
+ if (eClass != null) {
+ // doubly entry! Actually require different resolver
+ throw new IllegalArgumentException("There is more than one EClass with the same name (" +
+ eClassName + " in EPackage " + eClass.getEPackage().getName() + " and " +
+ aPackage.getModelEPackage().getName() + ". A different EClassResolver should be used.");
+ }
+ eClass = aClass.getModelEClass();
+ }
+ }
+ }
+ if (eClass != null) {
+ entityNameToEClass.put(eClassName, eClass);
+ return eClass;
+ }
+ // now try the eclassname itself
+ for (final PAnnotatedEPackage aPackage : getPaModel().getPaEPackages()) {
+ for (PAnnotatedEClass aClass : aPackage.getPaEClasses()) {
+ if (aClass.getEntity() != null && aClass.getEntity().getName() != null &&
+ aClass.getEntity().getName().compareTo(eClassName) == 0) {
+ if (eClass != null) {
+ // doubly entry! Actually require different resolver
+ throw new IllegalArgumentException("There is more than one EClass with the same name (" +
+ eClassName + " in EPackage " + eClass.getEPackage().getName() + " and " +
+ aPackage.getModelEPackage().getName() + ". A different EClassResolver should be used.");
+ }
+ eClass = aClass.getModelEClass();
+ }
+ }
+ }
+
+ // we didn'y find it, perhaps it is fully qualified, lets try by full
+ // class name
+ // if (eClass == null) {
+ // try {
+ // final Class<?> cls = ClassLoaderResolver.classForName(eClassName);
+ // eClass = EModelResolver.instance().getEClass(cls);
+ // } catch (StoreClassLoadException e) {
+ // log.debug("Failed to retreive EClass for name: " + eClassName +
+ // ". This is no problem if this is a featuremap.");
+ // }
+ // }
+
+ if (eClass == null) {
+ log.debug("Failed to retreive EClass for name: " + eClassName +
+ ". This is no problem if this is a featuremap.");
+ return null;
+ // throw new IllegalArgumentException("No EClass found using " +
+ // eClassName);
+ }
+ entityNameToEClass.put(eClassName, eClass);
+ return eClass;
+ }
+
+ /**
+ * @return the paModel
+ */
+ @Override
+ public PAnnotatedModel getPaModel() {
+ return paModel;
+ }
+
+ /**
+ * @param paModel
+ * the paModel to set
+ */
+ @Override
+ public void setPaModel(PAnnotatedModel paModel) {
+ this.paModel = paModel;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.emf.teneo.extension.ExtensionManagerAware#setExtensionManager
+ * (org.eclipse.emf .teneo.extension.ExtensionManager)
+ */
+ @Override
+ public void setExtensionManager(ExtensionManager extensionManager) {
+ this.extensionManager = extensionManager;
+ }
+
+ /**
+ * @return the extensionManager
+ */
+ @Override
+ public ExtensionManager getExtensionManager() {
+ return extensionManager;
+ }
+}
diff --git a/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/mapping/strategy/impl/EntityResolvingNameStrategy.java b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/mapping/strategy/impl/EntityResolvingNameStrategy.java
new file mode 100755
index 000000000..2519a2dee
--- /dev/null
+++ b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/mapping/strategy/impl/EntityResolvingNameStrategy.java
@@ -0,0 +1,222 @@
+/**
+ * <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: EntityResolvingNameStrategy.java,v 1.12 2009/12/04 15:06:37 mtaal Exp $
+ */
+
+package org.eclipse.emf.teneo.mapping.strategy.impl;
+
+import java.util.concurrent.ConcurrentHashMap;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.eclipse.emf.ecore.EClass;
+import org.eclipse.emf.ecore.EcorePackage;
+import org.eclipse.emf.ecore.util.ExtendedMetaData;
+import org.eclipse.emf.teneo.annotations.pamodel.PAnnotatedEClass;
+import org.eclipse.emf.teneo.annotations.pamodel.PAnnotatedEPackage;
+import org.eclipse.emf.teneo.annotations.pamodel.PAnnotatedModel;
+import org.eclipse.emf.teneo.extension.ExtensionManager;
+import org.eclipse.emf.teneo.mapping.strategy.EntityNameStrategy;
+import org.eclipse.emf.teneo.util.StoreUtil;
+
+/**
+ * This implementation will first use the name of the entity annotation and then the EClass name. For the DocumentRoot
+ * the EClass name is always prefixed with the EPackage namespace.
+ *
+ * @author <a href="mtaal@elver.org">Martin Taal</a>
+ * @version $Revision: 1.12 $
+ */
+public class EntityResolvingNameStrategy implements EntityNameStrategy {
+
+ /** The logger */
+ private static Log log = LogFactory.getLog(EntityResolvingNameStrategy.class);
+
+ /** The singleton instance as it is thread safe */
+ public static final EntityResolvingNameStrategy INSTANCE = new EntityResolvingNameStrategy();
+
+ // The pamodel for which this is done
+ private PAnnotatedModel paModel;
+
+ // Internal cache name from name to eclass
+ private ConcurrentHashMap<String, EClass> entityNameToEClass = new ConcurrentHashMap<String, EClass>();
+
+ private ExtensionManager extensionManager;
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.elver.ecore.spring.EClassResolver#deResolve(org.eclipse.emf.ecore .EClass)
+ */
+ public String toEntityName(EClass eClass) {
+ if (eClass == EOBJECT_ECLASS) {
+ return EOBJECT_ECLASS_NAME;
+ }
+
+ if (eClass == null) {
+ throw new IllegalArgumentException(
+ "Passed eclass is null."
+ + "This can occur if epackages which refer to eachother are placed in different ecore/xsd files "
+ + "and they are not read using one resource set. The reference from one epackage to another must be "
+ + "resolvable by EMF.");
+ }
+
+ if (eClass.getName() == null) {
+ throw new IllegalArgumentException(
+ "EClass "
+ + eClass.toString()
+ + " has a null name."
+ + "This can occur if epackages which refer to eachother are placed in different ecore/xsd files "
+ + "and they are not read using one resource set. The reference from one epackage to another must be "
+ + "resolvable by EMF.");
+ }
+
+ // check if there is an entity annotation on the eclass with a name set
+ final PAnnotatedEClass aClass = getPaModel().getPAnnotated(eClass);
+ if (aClass == null) {
+ return createEClassEntityName(eClass);
+ }
+ if (aClass.getEntity() != null && aClass.getEntity().getName() != null) {
+ return aClass.getEntity().getName();
+ }
+
+ return createEClassEntityName(eClass);
+ }
+
+ // always prefix DocumentRoot
+ protected String createEClassEntityName(EClass eClass) {
+ if (ExtendedMetaData.INSTANCE.isDocumentRoot(eClass)) {
+ return eClass.getEPackage().getNsPrefix() + "." + eClass.getName();
+ }
+ return eClass.getName();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.elver.ecore.spring.EClassResolver#resolve(java.lang.String)
+ */
+ public EClass toEClass(String eClassName) {
+ if (eClassName == null) {
+ throw new IllegalArgumentException("eClassName may not be null");
+ }
+
+ if (eClassName.compareTo(EOBJECT_ECLASS_NAME) == 0) {
+ return EcorePackage.eINSTANCE.getEObject();
+ }
+
+ EClass eClass = null;
+ if ((eClass = entityNameToEClass.get(eClassName)) != null) {
+ return eClass;
+ }
+
+ // first try the entityname
+ for (final PAnnotatedEPackage aPackage : getPaModel().getPaEPackages()) {
+ for (final PAnnotatedEClass aClass : aPackage.getPaEClasses()) {
+ if (aClass.getEntity() != null && aClass.getEntity().getName() != null
+ && aClass.getEntity().getName().compareTo(eClassName) == 0
+ && !StoreUtil.isMapEntry(aClass.getModelEClass())) { // map
+ // entries
+ // are
+ // ignored
+ if (eClass != null) {
+ // doubly entry! Actually require different resolver
+ throw new IllegalArgumentException("There is more than one EClass with the same name ("
+ + eClassName + " in EPackage " + eClass.getEPackage().getName() + " and "
+ + aPackage.getModelEPackage().getName()
+ + ". A different EClassResolver should be used.");
+ }
+ eClass = aClass.getModelEClass();
+ }
+ }
+ }
+ if (eClass != null) {
+ entityNameToEClass.put(eClassName, eClass);
+ return eClass;
+ }
+ // now try the eclassname itself
+ for (final PAnnotatedEPackage aPackage : getPaModel().getPaEPackages()) {
+ for (PAnnotatedEClass aClass : aPackage.getPaEClasses()) {
+ final EClass compareToEClass = aClass.getModelEClass();
+ // convert the EClass to a name using the standard approach
+ // also handle documentroot
+ final String compareToName = createEClassEntityName(compareToEClass);
+ if (compareToName.compareTo(eClassName) == 0) {
+ if (eClass != null) {
+ // doubly entry! Actually require different resolver
+ throw new IllegalArgumentException("There is more than one EClass with the same name ("
+ + eClassName + " in EPackage " + eClass.getEPackage().getName() + " and "
+ + aPackage.getModelEPackage().getName()
+ + ". A different EClassResolver should be used.");
+ }
+ eClass = compareToEClass;
+ }
+ }
+ }
+
+ // we didn'y find it, perhaps it is fully qualified, lets try by full
+ // class name
+ // if (eClass == null) {
+ // try {
+ // final Class<?> cls = ClassLoaderResolver.classForName(eClassName);
+ // eClass = EModelResolver.instance().getEClass(cls);
+ // } catch (StoreClassLoadException e) {
+ // log.debug("Failed to retreive EClass for name: " + eClassName +
+ // ". This is no problem if this is a featuremap.");
+ // }
+ // }
+
+ if (eClass == null) {
+ log.debug("Failed to retreive EClass for name: " + eClassName
+ + ". This is no problem if this is a featuremap.");
+ return null;
+ // throw new IllegalArgumentException("No EClass found using " +
+ // eClassName);
+ }
+ entityNameToEClass.put(eClassName, eClass);
+ return eClass;
+ }
+
+ /**
+ * @return the paModel
+ */
+ public PAnnotatedModel getPaModel() {
+ return paModel;
+ }
+
+ /**
+ * @param paModel
+ * the paModel to set
+ */
+ public void setPaModel(PAnnotatedModel paModel) {
+ this.paModel = paModel;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.emf.teneo.extension.ExtensionManagerAware#setExtensionManager (org.eclipse.emf
+ * .teneo.extension.ExtensionManager)
+ */
+ public void setExtensionManager(ExtensionManager extensionManager) {
+ this.extensionManager = extensionManager;
+ }
+
+ /**
+ * @return the extensionManager
+ */
+ public ExtensionManager getExtensionManager() {
+ return extensionManager;
+ }
+}
diff --git a/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/mapping/strategy/impl/QualifyingEntityNameStrategy.java b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/mapping/strategy/impl/QualifyingEntityNameStrategy.java
new file mode 100755
index 000000000..3ac9cf33a
--- /dev/null
+++ b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/mapping/strategy/impl/QualifyingEntityNameStrategy.java
@@ -0,0 +1,136 @@
+/**
+ * <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: QualifyingEntityNameStrategy.java,v 1.8 2009/07/28 03:39:44 mtaal Exp $
+ */
+
+package org.eclipse.emf.teneo.mapping.strategy.impl;
+
+import org.eclipse.emf.ecore.EClass;
+import org.eclipse.emf.ecore.EPackage;
+import org.eclipse.emf.ecore.EcorePackage;
+import org.eclipse.emf.teneo.annotations.pamodel.PAnnotatedEClass;
+import org.eclipse.emf.teneo.annotations.pamodel.PAnnotatedEPackage;
+import org.eclipse.emf.teneo.annotations.pamodel.PAnnotatedModel;
+import org.eclipse.emf.teneo.extension.ExtensionManager;
+import org.eclipse.emf.teneo.mapping.strategy.EntityNameStrategy;
+
+/**
+ * This implementation prefixes the eclass names with the epackage nsprefix. This makes it less likely that name clashes
+ * occur of eclasses in different packages.
+ *
+ * @author <a href="mtaal@elver.org">Martin Taal</a>
+ * @version $Revision: 1.8 $
+ */
+public class QualifyingEntityNameStrategy implements EntityNameStrategy {
+
+ // The pamodel for which this is done
+ private PAnnotatedModel paModel;
+
+ public static final QualifyingEntityNameStrategy INSTANCE = new QualifyingEntityNameStrategy();
+
+ private ExtensionManager extensionManager;
+
+ public String toEntityName(EClass eClass) {
+ if (eClass == null) {
+ throw new IllegalArgumentException("EClass cannot be null.");
+ }
+ if (eClass == EOBJECT_ECLASS) {
+ return EOBJECT_ECLASS_NAME;
+ }
+ String nsPrefix = eClass.getEPackage().getNsPrefix();
+ if (nsPrefix == null) {
+ nsPrefix = eClass.getEPackage().getName();
+ }
+ return nsPrefix + "." + eClass.getName();
+ }
+
+ public EClass toEClass(String eClassStr) {
+ if (eClassStr == null) {
+ throw new IllegalArgumentException("eClassStr may not be null");
+ }
+
+ if (eClassStr.compareTo(EOBJECT_ECLASS_NAME) == 0) {
+ return EcorePackage.eINSTANCE.getEObject();
+ }
+
+ // get prefix or name
+ final int index = eClassStr.lastIndexOf(".");
+ if (index == -1) {
+ throw new IllegalArgumentException(
+ "Illegal eClassStr for this resolver (no dot separating the epackage nsprefix and name): "
+ + eClassStr);
+ }
+ final String nsPrefix = eClassStr.substring(0, index);
+ final String eClassName = eClassStr.substring(index + 1);
+
+ // now try all epackages
+ EClass eClass = null;
+ for (final PAnnotatedEPackage aPackage : getPaModel().getPaEPackages()) {
+ final EPackage ePackage = aPackage.getModelEPackage();
+ if (ePackage.getNsPrefix().compareTo(nsPrefix) != 0 && ePackage.getName().compareTo(nsPrefix) != 0) {
+ continue;
+ }
+ for (final PAnnotatedEClass aClass : aPackage.getPaEClasses()) {
+ final EClass checkEClass = aClass.getModelEClass();
+ if (checkEClass.getName().compareTo(eClassName) == 0) {
+ if (eClass != null) {
+ // doubly entry! Actually require different resolver
+ throw new IllegalArgumentException(
+ "There is more than one EClass with the same identifying String (" + eClassStr
+ + " in EPackage " + eClass.getEPackage().getName() + " and "
+ + ePackage.getName() + ". A different EClassResolver should be used.");
+ }
+ eClass = checkEClass;
+ }
+ }
+ }
+ if (eClass == null) {
+ throw new IllegalArgumentException("No EClass found using " + eClassStr);
+ }
+ return eClass;
+ }
+
+ /**
+ * @return the paModel
+ */
+ public PAnnotatedModel getPaModel() {
+ return paModel;
+ }
+
+ /**
+ * @param paModel
+ * the paModel to set
+ */
+ public void setPaModel(PAnnotatedModel paModel) {
+ this.paModel = paModel;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.emf.teneo.extension.ExtensionManagerAware#setExtensionManager
+ * (org.eclipse.emf.teneo.extension.ExtensionManager)
+ */
+ public void setExtensionManager(ExtensionManager extensionManager) {
+ this.extensionManager = extensionManager;
+ }
+
+ /**
+ * @return the extensionManager
+ */
+ public ExtensionManager getExtensionManager() {
+ return extensionManager;
+ }
+} \ No newline at end of file
diff --git a/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/mapping/strategy/impl/TeneoNewSQLNameStrategy.java b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/mapping/strategy/impl/TeneoNewSQLNameStrategy.java
new file mode 100644
index 000000000..c59c01f51
--- /dev/null
+++ b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/mapping/strategy/impl/TeneoNewSQLNameStrategy.java
@@ -0,0 +1,36 @@
+/**
+ * <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: TeneoNewSQLNameStrategy.java,v 1.1 2009/10/02 07:23:23 mtaal Exp $
+ */
+
+package org.eclipse.emf.teneo.mapping.strategy.impl;
+
+import org.eclipse.emf.teneo.annotations.pamodel.PAnnotatedEClass;
+import org.eclipse.emf.teneo.mapping.strategy.StrategyUtil;
+
+/**
+ * Mapping strategy which uses the EClass entity name.
+ *
+ * @author <a href="mtaal@elver.org">Martin Taal</a>
+ * @version $Revision: 1.1 $
+ */
+public class TeneoNewSQLNameStrategy extends TeneoSQLNameStrategy {
+
+ // Returns the entityname of the refered to entity
+ protected String getMappingName(PAnnotatedEClass aClass) {
+ return StrategyUtil.getEntityName(getEntityNameStrategy(), persistenceOptions, aClass.getPaModel(), aClass
+ .getModelEClass());
+ }
+} \ No newline at end of file
diff --git a/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/mapping/strategy/impl/TeneoSQLNameStrategy.java b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/mapping/strategy/impl/TeneoSQLNameStrategy.java
new file mode 100755
index 000000000..b57b0b9f7
--- /dev/null
+++ b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/mapping/strategy/impl/TeneoSQLNameStrategy.java
@@ -0,0 +1,204 @@
+/**
+ * <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: TeneoSQLNameStrategy.java,v 1.10 2010/01/26 20:09:42 mtaal Exp $
+ */
+
+package org.eclipse.emf.teneo.mapping.strategy.impl;
+
+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.EReference;
+import org.eclipse.emf.teneo.annotations.pamodel.PAnnotatedEClass;
+import org.eclipse.emf.teneo.annotations.pamodel.PAnnotatedEReference;
+import org.eclipse.emf.teneo.mapping.strategy.StrategyUtil;
+
+/**
+ * Differences between this implementation and the ClassicSQLNameStrategy is the way truncation is done if a name is
+ * longer than the sql name length constraint. To truncate a name this class will first remove vowels (in the order: u,
+ * o, a, e, i) and if that is not enough it will truncate the different parts of a name (separated by _).
+ *
+ * @author <a href="mtaal@elver.org">Martin Taal</a>
+ * @version $Revision: 1.10 $
+ */
+public class TeneoSQLNameStrategy extends ClassicSQLNameStrategy {
+
+ // The logger
+ protected static final Log log = LogFactory.getLog(TeneoSQLNameStrategy.class);
+
+ private static String[] removables = new String[] { "u", "o", "a", "e", "i" };
+
+ /*
+ * (non-Javadoc)
+ *
+ * @seeorg.eclipse.emf.teneo.mapping.strategy.SqlNameStrategy# getManyToOneJoinColumnNames
+ * (org.eclipse.emf.teneo.annotations.pamodel.PAnnotatedEReference)
+ */
+ @Override
+ public List<String> getManyToOneJoinColumnNames(PAnnotatedEReference aReference) {
+ final EReference eref = aReference.getModelEReference();
+
+ // isTransient occurs for computed featuremap features, these are
+ // ignored
+ // later on
+ assert (eref.isTransient() || !eref.isMany()); // otherwise this should
+ // have been a mtm
+
+ // in case of many-to-one to qualify use the name of the class to which
+ // is refered
+ // this is only used in case of non-simple naming (simple naming is
+ // better readable)!
+ final PAnnotatedEClass aClass;
+ if (eref.getEOpposite() == null) {
+ aClass = aReference.getAReferenceType();
+ } else {
+ // the aclass is just the class of the structuralfeature itself.
+ // This is done so that both sides of the relationship use the same
+ // columns
+ aClass = aReference.getPaEClass();
+ }
+ final String typeName = getMappingName(aClass);
+ final String featureName = eref.getName();
+
+ final List<String> result = new ArrayList<String>();
+ final List<String> names = StrategyUtil.getIDFeaturesNames(aReference.getAReferenceType(), persistenceOptions
+ .getDefaultIDFeatureName());
+ final boolean simpleNaming = optionJoinColumnNamingStrategy.compareTo("simple") == 0;
+ for (String name : names) {
+ final String postFix;
+ if (names.size() == 1 && simpleNaming) {
+ postFix = "";
+ } else {
+ postFix = "_" + name;
+ }
+
+ final String jcName;
+ if (simpleNaming) {
+ jcName = featureName + postFix;
+ } else { // backward compatibility
+ jcName = typeName + "_" + featureName + postFix;
+ }
+ result.add(optionColumnNamePrefix + convert(jcName, true));
+ }
+ return result;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.emf.teneo.mapping.strategy.impl.ClassicSQLNameStrategy#trunc (int, java.lang.String, boolean)
+ */
+ @Override
+ public String trunc(int maxSqlLength, String truncName, boolean truncPrefix) {
+ String correctedName = truncName.replace('.', '_');
+ if (maxSqlLength == -1) {
+ return correctedName;
+ }
+ if (correctedName.length() <= maxSqlLength) {
+ return correctedName;
+ }
+
+ correctedName = correctedName.replaceAll("__", "_");
+ if (correctedName.startsWith("_")) {
+ correctedName = correctedName.substring(1);
+ }
+
+ if (correctedName.length() <= maxSqlLength) {
+ return correctedName;
+ }
+
+ // first do some standard things
+ // truncate the standard e_id
+ correctedName = correctedName.replaceAll("e_id", "id");
+ if (correctedName.length() <= maxSqlLength) {
+ return correctedName;
+ }
+
+ // now do vowel truncation preserving the first character
+ char correctedNameFirstChar = correctedName.charAt(0);
+ String correctedNameTail = correctedName.substring(1);
+ for (String vowel : getRemovableCharacters()) {
+ while (correctedNameTail.indexOf(vowel) != -1 || correctedNameTail.indexOf(vowel.toUpperCase()) != -1) {
+ if (correctedNameTail.indexOf(vowel) != -1) {
+ correctedNameTail = correctedNameTail.replaceFirst(vowel, "");
+ } else {
+ correctedNameTail = correctedNameTail.replaceFirst(vowel.toUpperCase(), "");
+ }
+ correctedNameTail = correctedNameTail.replaceAll("__", "_");
+ if ((correctedNameTail.length() + 1) <= maxSqlLength) {
+ return correctedNameFirstChar + correctedNameTail;
+ }
+ }
+ }
+
+ // still failed do length truncation
+ return doLengthTruncation(maxSqlLength, correctedNameFirstChar + correctedNameTail);
+ }
+
+ protected String doLengthTruncation(int maxSqlLength, String correctedName) {
+ // failed do length truncation with the remainder
+ final int underscore = correctedName.lastIndexOf('_');
+ if (underscore == -1) {
+ return correctedName.substring(0, maxSqlLength);
+ }
+
+ // now do the complex logic to truncate different parts
+ final String[] parts = correctedName.split("_");
+ int maxLength = -1;
+ for (String part : parts) {
+ if (part.length() > maxLength && part.length() > 0) {
+ maxLength = part.length();
+ }
+ }
+
+ // can this ever happen
+ int totalLength = correctedName.length();
+ while (maxLength > 1 && totalLength > maxSqlLength) {
+ totalLength = 0;
+ int newMax = 0;
+ for (int i = 0; i < parts.length; i++) {
+ if (parts[i].length() == maxLength) {
+ parts[i] = parts[i].substring(0, maxLength - 1);
+ }
+ if (parts[i].length() > newMax) {
+ newMax = parts[i].length();
+ }
+ totalLength += parts[i].length();
+ }
+ totalLength += parts.length - 1; // count the underscores
+ maxLength = newMax;
+ }
+
+ final StringBuffer result = new StringBuffer();
+ for (String part : parts) {
+ if (result.length() > 0) {
+ result.append("_");
+ }
+ result.append(part);
+ }
+
+ return result.toString();
+ }
+
+ /**
+ * Return the characters to remove, the character removal is done in order of the returned array. This method is
+ * provided to be overridden to pass a custom set of removable characters.
+ */
+ protected String[] getRemovableCharacters() {
+ return removables;
+ }
+} \ No newline at end of file
diff --git a/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/resource/NonLoadingDiagnostician.java b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/resource/NonLoadingDiagnostician.java
new file mode 100755
index 000000000..68b07ada7
--- /dev/null
+++ b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/resource/NonLoadingDiagnostician.java
@@ -0,0 +1,56 @@
+/**
+ * <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: NonLoadingDiagnostician.java,v 1.7 2009/03/30 07:53:04 mtaal Exp $
+ */
+
+package org.eclipse.emf.teneo.resource;
+
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.emf.common.util.DiagnosticChain;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.util.Diagnostician;
+
+/**
+ * Extends the default EMF Diagnostican to prevent the validation to load unloaded lists.
+ *
+ * @author <a href="mailto:mtaal@elver.org">Martin Taal</a>
+ * @version $Revision: 1.7 $
+ */
+
+public class NonLoadingDiagnostician extends Diagnostician {
+
+ /** The instance */
+ public static NonLoadingDiagnostician INSTANCE = new NonLoadingDiagnostician();
+
+ /** Overriden to prevent loading of complete content */
+ @Override
+ protected boolean doValidateContents(EObject eObject, DiagnosticChain diagnostics, Map<Object, Object> context) {
+ List<EObject> eContents = NonLoadingEContentsEList.create(eObject, true);
+ if (!eContents.isEmpty()) {
+ Iterator<EObject> i = eContents.iterator();
+ EObject child = i.next();
+ boolean result = validate(child, diagnostics, context);
+ while (i.hasNext() && (result || diagnostics != null)) {
+ child = i.next();
+ result &= validate(child, diagnostics, context);
+ }
+ return result;
+ }
+ return true;
+ }
+}
diff --git a/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/resource/NonLoadingEContentsEList.java b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/resource/NonLoadingEContentsEList.java
new file mode 100755
index 000000000..060628144
--- /dev/null
+++ b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/resource/NonLoadingEContentsEList.java
@@ -0,0 +1,85 @@
+/**
+ * <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: NonLoadingEContentsEList.java,v 1.8 2010/02/04 11:03:00 mtaal Exp $
+ */
+
+package org.eclipse.emf.teneo.resource;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.EReference;
+import org.eclipse.emf.ecore.EStructuralFeature;
+import org.eclipse.emf.ecore.InternalEObject;
+import org.eclipse.emf.ecore.InternalEObject.EStore;
+import org.eclipse.emf.ecore.util.EContentsEList;
+import org.eclipse.emf.teneo.mapping.elist.PersistableEList;
+import org.eclipse.emf.teneo.mapping.elist.PersistableEMap;
+import org.eclipse.emf.teneo.mapping.elist.PersistableFeatureMap;
+import org.eclipse.emf.teneo.util.StoreUtil;
+
+/**
+ * Is a contents elist which will only iterate over loaded efeatures.
+ *
+ * @author <a href="mailto:mtaal@elver.org">Martin Taal</a>
+ * @version $Revision: 1.8 $
+ */
+
+public class NonLoadingEContentsEList<E> extends EContentsEList<E> {
+
+ /** Creates an instance of a NonResolvingEContentsEList for the EObject */
+ public static EContentsEList<EObject> create(EObject eObject, boolean forValidation) {
+ final ArrayList<EStructuralFeature> result = new ArrayList<EStructuralFeature>();
+ for (EReference eref : eObject.eClass().getEAllReferences()) {
+ if (!eref.isContainment()) {
+ continue;
+ }
+ if (eref.isMany()) {
+ List<?> list = (List<?>) eObject.eGet(eref);
+
+ // in case of an estore the list has to be retrieved in a
+ // special
+ // way
+ if (StoreUtil.isEStoreList(list)) {
+ final EStore eStore = ((InternalEObject) eObject).eStore();
+ list = (List<?>) eStore.get((InternalEObject) eObject, eref, EStore.NO_INDEX);
+ }
+
+ if ((list instanceof PersistableEList<?>) && ((PersistableEList<?>) list).isLoaded()) {
+ result.add(eref);
+ } else if ((list instanceof PersistableEMap<?,?>) && ((PersistableEMap<?, ?>) list).isLoaded()) {
+ result.add(eref);
+ } else if ((list instanceof PersistableFeatureMap) && ((PersistableFeatureMap) list).isLoaded()) {
+ result.add(eref);
+ } else if (eref.getLowerBound() > 0 && forValidation) {
+ result.add(eref);
+ }
+ if (!(list instanceof PersistableEList<?>) && !(list instanceof PersistableFeatureMap) &&
+ !(list instanceof PersistableEMap<?,?>)) {
+ result.add(eref);
+ }
+
+ } else {
+ result.add(eref);
+ }
+ }
+ return new NonLoadingEContentsEList<EObject>(eObject, result);
+ }
+
+ private NonLoadingEContentsEList(EObject eObject, List<? extends EStructuralFeature> eStructuralFeatures) {
+ super(eObject, eStructuralFeatures);
+ }
+}
diff --git a/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/resource/StoreResource.java b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/resource/StoreResource.java
new file mode 100755
index 000000000..d50f11dd1
--- /dev/null
+++ b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/resource/StoreResource.java
@@ -0,0 +1,1115 @@
+/**
+ * <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
+ * Benjamin Cabé - See bugzilla 176356
+ *
+ * </copyright>
+ *
+ * $Id: StoreResource.java,v 1.44 2011/07/03 11:16:06 mtaal Exp $
+ */
+
+package org.eclipse.emf.teneo.resource;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.TreeMap;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.eclipse.emf.common.notify.Adapter;
+import org.eclipse.emf.common.notify.Notification;
+import org.eclipse.emf.common.notify.NotificationChain;
+import org.eclipse.emf.common.notify.impl.AdapterImpl;
+import org.eclipse.emf.common.notify.impl.NotificationImpl;
+import org.eclipse.emf.common.util.AbstractTreeIterator;
+import org.eclipse.emf.common.util.BasicEMap;
+import org.eclipse.emf.common.util.EList;
+import org.eclipse.emf.common.util.TreeIterator;
+import org.eclipse.emf.common.util.URI;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.EReference;
+import org.eclipse.emf.ecore.InternalEObject;
+import org.eclipse.emf.ecore.impl.BasicEObjectImpl;
+import org.eclipse.emf.ecore.resource.Resource;
+import org.eclipse.emf.ecore.resource.impl.ResourceImpl;
+import org.eclipse.emf.ecore.util.EContentsEList;
+import org.eclipse.emf.ecore.util.EcoreUtil;
+import org.eclipse.emf.ecore.util.InternalEList;
+import org.eclipse.emf.ecore.xmi.XMIResource;
+import org.eclipse.emf.ecore.xmi.XMLResource;
+import org.eclipse.emf.teneo.EContainerRepairControl;
+import org.eclipse.emf.teneo.StoreValidationException;
+import org.eclipse.emf.teneo.util.FieldUtil;
+
+/**
+ * General part of Store Resources. Main feature is that it keeps track of
+ * changes to the resource content and that settrackingmodification will not
+ * load unloaded elists.
+ *
+ * @author <a href="mailto:mtaal@elver.org">Martin Taal</a>
+ * @version $Revision: 1.44 $
+ */
+
+public abstract class StoreResource extends ResourceImpl {
+
+ /** The name of the parameter used for the datastore name */
+ public static final String DS_NAME_PARAM = "dsname";
+
+ /**
+ * Prefix to use when specifying query parameters in the uri or in the
+ * property file
+ */
+ public static final String QUERY_PREFIX = "query";
+
+ /** Load strategy */
+ public static final String LOAD_STRATEGY_PARAM = "loadStrategy";
+
+ /** The default strategy */
+ public static final String ADD_TO_CONTENTS = "addToContents";
+
+ /** The just set eResource */
+ public static final String SET_ERESOURCE = "setEResource";
+
+ /**
+ * Don't do anything, risk of dangling_references but is better if objects
+ * get added to other resources anyway.
+ */
+ public static final String NOT_SET_ERESOURCE = "notSetEResource";
+
+ /** The logger */
+ private static Log log = LogFactory.getLog(StoreResource.class);
+
+ /**
+ * The list of objects which will be deleted at commit time. Needs to be a
+ * list because of the order of deletion.
+ */
+ protected List<EObject> removedEObjects = new ArrayList<EObject>();
+
+ /**
+ * The set of objects loaded from the backend. objects which have been
+ * removed are still part of this list. This is to prevent them from being
+ * added to the newEObjects set.
+ */
+ protected HashSet<EObject> loadedEObjects = new HashSet<EObject>();
+ // is used for more efficient access
+ protected HashSet<EObject> loadedEObjectSet = new HashSet<EObject>();
+
+ /**
+ * The set of new objects new EObjects are never part of the loadedEObjects,
+ * when a newEObject is removed it is just removed from this set and not
+ * added to the removed EObjects. new eobjects are never part of the
+ * modifiedEObjects set.
+ */
+ protected List<EObject> newEObjects = new ArrayList<EObject>();
+ // is used for more efficient access
+ protected HashSet<EObject> newEObjectSet = new HashSet<EObject>();
+
+ /**
+ * The set of changed objects, this contains the loadedEObjects which have
+ * changed new EObjects are never part of this set
+ */
+ protected HashSet<EObject> modifiedEObjects = new HashSet<EObject>();
+
+ /**
+ * Apparently the super EMF resource classes have a different idea of loaded
+ * During the unload action they again start loading from the db, this
+ * should be prevented.
+ */
+ protected boolean isUnLoading = false;
+
+ /** The list of topclasses */
+ protected String[] topClassNames;
+
+ /**
+ * The list of queries if they are defined for this resource. If not set
+ * (length is 0) then the resource will as default behavior read the
+ * topclasses of the database.
+ */
+ private String[] definedQueries = new String[0];
+
+ /** Send notifications under load */
+ private boolean sendNotificationsOnLoad = true;
+
+ /** Is send notification set by parameter */
+ private boolean sendNotificationSetByParam = false;
+
+ /** The load strategy */
+ private String loadStrategy = SET_ERESOURCE;
+
+ /**
+ * The constructor, gets an uri and retrieves the backing OJBStore
+ */
+ public StoreResource(URI uri) {
+ super(uri);
+
+ final Map<String, String> params = decodeQueryString(uri.query());
+ if (params.get(LOAD_STRATEGY_PARAM) != null) {
+ loadStrategy = params.get(LOAD_STRATEGY_PARAM);
+ }
+
+ if (log.isDebugEnabled()) {
+ log.debug("Created " + this.getClass().getName() + " using uri: "
+ + uri.toString());
+ }
+
+ if (params.get(XMLResource.OPTION_DISABLE_NOTIFY) != null) {
+ sendNotificationSetByParam = true;
+ sendNotificationsOnLoad = "false".compareToIgnoreCase(params
+ .get(XMLResource.OPTION_DISABLE_NOTIFY)) == 0;
+ } else if (params.get(XMIResource.OPTION_DISABLE_NOTIFY) != null) {
+ sendNotificationSetByParam = true;
+ sendNotificationsOnLoad = "false".compareToIgnoreCase(params
+ .get(XMIResource.OPTION_DISABLE_NOTIFY)) == 0;
+ }
+
+ setLoaded(false);
+
+ // note this ugly statement is required because in this class
+ // it is required to have direct access to the contents member
+ // the call to getSuperContents will initialize it
+ if (getContents().size() == 0) {
+ log.debug("Initialized contents member");
+ }
+
+ // set the intrinsicmap
+ setIntrinsicIDToEObjectMap(new HashMap<String, EObject>());
+ }
+
+ /** Sets topclasses */
+ protected void init(String[] topClasses) {
+ topClassNames = topClasses;
+ }
+
+ public void setIsLoading(boolean loading) {
+ isLoading = loading;
+ }
+
+ // ----------------------------------- Defined Queries
+ // ----------------------------------
+
+ /** Sets the defined queries */
+ public void setDefinedQueries(String[] qrys) {
+ log.debug("Setting defined queries of resource " + getURI().toString()
+ + "/" + this.getClass().getName());
+ for (String element : qrys) {
+ log.debug("Adding query: " + element);
+ }
+
+ definedQueries = qrys;
+ }
+
+ /** Returns true if there are defined queries */
+ public boolean definedQueriesPresent() {
+ return definedQueries.length > 0;
+ }
+
+ /**
+ * Returns the current array of defined queries. Note if there are no
+ * definedQueries then an array of length 0 is returned.
+ */
+ public String[] getDefinedQueries() {
+ return definedQueries;
+ }
+
+ /** Returns a list of queries if they are passed as parameters */
+ protected String[] getQueries(Map<?, ?> params) {
+ final ArrayList<String> queries = new ArrayList<String>();
+ for (Object key : params.keySet()) {
+ if (((String) key).startsWith(QUERY_PREFIX)) {
+ queries.add((String) params.get(key));
+ }
+ }
+ return queries.toArray(new String[queries.size()]);
+ }
+
+ /** Get the parameter from the hashmap, if not found then throw an exception */
+ protected String getParam(Map<String, String> params, String paramName,
+ String report) {
+ final String param = params.get(paramName);
+ if (param == null) {
+ throw new StoreResourceException("Parameter " + paramName
+ + " missing in querystring: " + report);
+ }
+ return param;
+ }
+
+ /** Decode the query string in a hashmap */
+ protected Map<String, String> decodeQueryString(String qryStr) {
+ final TreeMap<String, String> result = new TreeMap<String, String>();
+
+ if (qryStr == null) {
+ return result;
+ }
+
+ final String[] qryParts = qryStr.split("&");
+ for (final String qryPart : qryParts) {
+ final String fieldName = qryPart.substring(0, qryPart.indexOf('='));
+ final String fieldValue = URI.decode(qryPart.substring(qryPart
+ .indexOf('=') + 1));
+ result.put(fieldName, fieldValue);
+ }
+ return result;
+ }
+
+ // ------------------------------ Subclass methods
+ // ---------------------------------
+
+ /**
+ * Returns an array of EObjects which refer to a certain EObject, note if
+ * the array is of length zero then no refering EObjects where found.
+ */
+ public abstract Object[] getCrossReferencers(EObject referedTo);
+
+ /** Load implemented by subclass */
+ protected abstract List<EObject> loadResource(Map<?, ?> options);
+
+ /** Save implemented by subclass */
+ protected abstract void saveResource(Map<?, ?> options);
+
+ // ------------------------------------ Load
+ // ------------------------------------------
+
+ /** Returns true if the resource is unloading */
+ public boolean isUnLoading() {
+ return isUnLoading;
+ }
+
+ /** Loads the resource */
+ @Override
+ public void load(Map<?, ?> options) {
+ if (isUnLoading) {
+ return;
+ }
+ if (isLoaded()) {
+ return;
+ }
+ if (isLoading()) {
+ return;
+ }
+
+ String option;
+ if (options != null
+ && (option = (String) options
+ .get(XMLResource.OPTION_DISABLE_NOTIFY)) != null) {
+ sendNotificationsOnLoad = "false".compareToIgnoreCase(option) == 0;
+ } else if (options != null
+ && (option = (String) options
+ .get(XMIResource.OPTION_DISABLE_NOTIFY)) != null) {
+ sendNotificationsOnLoad = "false".compareToIgnoreCase(option) == 0;
+ } else if (!sendNotificationSetByParam) {
+ sendNotificationsOnLoad = true;
+ }
+
+ if (options != null && options.get(LOAD_STRATEGY_PARAM) != null) {
+ loadStrategy = (String) options.get(LOAD_STRATEGY_PARAM);
+ }
+
+ isLoading = true;
+ Notification notification = setLoaded(true);
+ try {
+ clearChangeTrackerArrays();
+ List<EObject> list = loadResource(options);
+ for (EObject eObject : list) {
+ addToContent((InternalEObject) eObject);
+ }
+ } finally {
+ if (notification != null) {
+ eNotify(notification);
+ }
+
+ setModified(false);
+ isLoading = false;
+ }
+ }
+
+ /** Add to this resource */
+ protected void addToContent(InternalEObject eObject) {
+ // note direct access to super member
+ if (!getLocalContents().contains(eObject)) {
+ final NotificationChain notifications = getLocalContents()
+ .basicAdd(eObject, null);
+ if (notifications != null && sendNotificationsOnLoad) {
+ notifications.dispatch();
+ }
+ setEResource(eObject, true);
+ attached(eObject);
+ }
+ }
+
+ protected void addUsingContainmentStructure(InternalEObject eObject) {
+ final boolean oldLoading = isLoading();
+ try {
+ setIsLoading(true);
+ // find the topcontainer
+ InternalEObject currentEObject = eObject;
+ while (currentEObject.eContainer() != null
+ && !currentEObject.eContainmentFeature().isResolveProxies()) {
+ currentEObject = (InternalEObject) currentEObject.eContainer();
+ }
+ // if the topcontainer is not yet part of the resource then add it
+ if (!loadedEObjectSet.contains(currentEObject)) {
+ final NotificationChain notifications = getLocalContents()
+ .basicAdd(eObject, null);
+ if (notifications != null && sendNotificationsOnLoad) {
+ notifications.dispatch();
+ }
+ setEResource(eObject, true);
+ // attached will also call the children
+ attached(currentEObject);
+ } else if (!loadedEObjectSet.contains(eObject)) {
+ // container is already part of the resource
+ // just add the current object to the loaded eobjects
+ attached(eObject);
+ }
+ } finally {
+ setIsLoading(oldLoading);
+ }
+ }
+
+ // This method is called when ereferences are resolved.
+ public void addToContentOrAttach(InternalEObject eObject,
+ EReference eReference) {
+ final boolean oldLoading = isLoading();
+ try {
+ if (loadStrategy.compareTo(ADD_TO_CONTENTS) == 0) {
+ if (eObject.eResource() != null && eObject.eResource() != this) {
+ return;
+ }
+ // always add to the resource, this will change
+ // the contents of the resource
+ addUsingContainmentStructure(eObject);
+ } else if (eReference.isContainment()) {
+ // if resolve proxies then it is allowed to have child objects
+ // in other
+ // resources
+ if (eReference.isResolveProxies()
+ && eObject.eResource() != null
+ && eObject.eResource() != this) {
+ return;
+ }
+ // only add if contained, just add to the loaded eobjects lists
+ assert (eObject.eContainer().eResource() == this);
+ attached(eObject);
+ } else if (loadStrategy.compareTo(SET_ERESOURCE) == 0) {
+ // this is not the nicest solution because everyone is added to
+ // the top of the
+ // resource.
+ // but it prevents dangling references
+ // when objects are not added explicitly to a resource
+ setEResource(eObject, false);
+ attached(eObject);
+ }
+ } finally {
+ setIsLoading(oldLoading);
+ }
+ }
+
+ /**
+ * Called by subclass
+ *
+ * /** Saves the resource
+ */
+ @Override
+ public void save(Map<?, ?> options) {
+ boolean err = true;
+ try {
+ setAllowNotifications(false);
+ validateContents();
+ saveResource(options);
+ err = false;
+ } catch (Throwable t) {
+ throw new IllegalStateException(t);
+ } finally {
+ // now clear the changed eobjects and move the new objects
+ // to the loaded eobjects
+ setAllowNotifications(true);
+ if (!err) {
+ modifiedEObjects.clear();
+ removedEObjects.clear();
+ loadedEObjects.addAll(newEObjects);
+ loadedEObjectSet.addAll(newEObjects);
+ newEObjects.clear();
+ newEObjectSet.clear();
+ setModified(false);
+ }
+
+ }
+ }
+
+ /**
+ * Clears different lists to start with an empty resource again.
+ */
+ @Override
+ protected void doUnload() {
+ isUnLoading = true;
+ super.doUnload();
+ clearChangeTrackerArrays();
+ isUnLoading = false;
+ }
+
+ /*
+ * Javadoc copied from interface.
+ */
+ @Override
+ public EList<EObject> getContents() {
+ if (contents == null) {
+ contents = new LocalContentsEList();
+ }
+ return contents;
+ }
+
+ protected LocalContentsEList getLocalContents() {
+ return (LocalContentsEList) getContents();
+ }
+
+ // this specific ContentsElist overrides inverseremove to handle the
+ // following case
+ // using queries it is possible to load a parent and child both in the root
+ // of the
+ // resource. During unload of the resource the child is removed from the
+ // parent
+ // see the BasicEObjectImpl.eSetResource implementation. This is undesirable
+ // therefore
+ // the inverseRemove method is overridden.
+ // See bugzilla 227500
+ protected class LocalContentsEList extends ContentsEList<EObject> {
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ public NotificationChain inverseRemove(EObject object,
+ NotificationChain notifications) {
+ if (!isUnLoading()) {
+ return super.inverseRemove(object, notifications);
+ }
+ if (!unloadingContents.contains(object)) {
+ return super.inverseRemove(object, notifications);
+ }
+
+ final InternalEObject eObject = (InternalEObject) object;
+ final InternalEObject eContainer = eObject.eInternalContainer();
+ if (eContainer == null) {
+ return super.inverseRemove(object, notifications);
+ }
+
+ // specific case which works fine as in this case the
+ // object is not removed from its container
+ if (eObject.eContainmentFeature().isResolveProxies()) {
+ return super.inverseRemove(object, notifications);
+ }
+
+ // can this ever happen?
+ if (!(eObject instanceof BasicEObjectImpl)) {
+ return super.inverseRemove(object, notifications);
+ }
+
+ // now the only thing remaining is mimick the inverseRemove without
+ // removal
+ // from the container
+ // this is the invariant:
+ // eDirectResource() != null && eContainer != null
+ // in this case the directresource has to be set, using java
+ // reflection to handle that
+ final Resource oldResource = eObject.eDirectResource();
+ if (oldResource != null) {
+ notifications = ((InternalEList<?>) oldResource.getContents())
+ .basicRemove(this, notifications);
+ }
+ FieldUtil.callMethod(eObject, "eSetDirectResource",
+ new Object[] { null });
+
+ return notifications;
+ }
+
+ // reimplement the contains because the super class does something
+ // strange with checking
+ // the eresource of the object, this implementation needs to check the
+ // actual content
+ public boolean contains(Object object) {
+ if (useEquals() && object != null) {
+ for (int i = 0; i < size; ++i) {
+ if (object.equals(data[i])) {
+ return true;
+ }
+ }
+ } else {
+ for (int i = 0; i < size; ++i) {
+ if (data[i] == object) {
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
+
+ }
+
+ /**
+ * Validate the contents of the resource, only the changed/new EObjects are
+ * checked
+ */
+ protected void validateContents() throws StoreValidationException {
+ // get the changed or new eobjects
+ final ArrayList<EObject> newOrChangedObjects = new ArrayList<EObject>(
+ newEObjects);
+ newOrChangedObjects.addAll(modifiedEObjects);
+
+ log.debug("Validating contents of resource " + uri + " approx. "
+ + newOrChangedObjects.size() + " will be checked");
+
+ final ArrayList<org.eclipse.emf.common.util.Diagnostic> diags = new ArrayList<org.eclipse.emf.common.util.Diagnostic>();
+ for (int i = 0; i < newOrChangedObjects.size(); i++) {
+ final InternalEObject obj = (InternalEObject) newOrChangedObjects
+ .get(i);
+
+ // ensure that the resource is set correctly before validating
+ if (obj.eResource() != this) {
+ assert (obj.eResource() == this);
+ }
+ EContainerRepairControl.setEResourceToAlLContent(obj, this);
+
+ if (newOrChangedObjects.contains(obj.eContainer())) {
+ continue; // they will be checked as part of their container
+ }
+
+ final org.eclipse.emf.common.util.Diagnostic diag = validateObject(newOrChangedObjects
+ .get(i));
+ if (diag != null) {
+ diags.add(diag);
+ }
+ }
+ log.debug("Found " + diags.size() + " errors ");
+ if (diags.size() > 0) {
+ throw new StoreValidationException(
+ diags.toArray(new org.eclipse.emf.common.util.Diagnostic[diags
+ .size()]));
+ }
+ }
+
+ /** Copied from IBM tutorial, validates one eobject */
+ public org.eclipse.emf.common.util.Diagnostic validateObject(EObject eObject) {
+ org.eclipse.emf.common.util.Diagnostic diagnostic = NonLoadingDiagnostician.INSTANCE
+ .validate(eObject);
+ if (diagnostic.getSeverity() == org.eclipse.emf.common.util.Diagnostic.ERROR) {
+ return diagnostic;
+ }
+ return null;
+ }
+
+ // -------------------------- Content Iteration
+ // -----------------------------------
+
+ // /**
+ // * Override load to force a load when getContents is called without a
+ // previous load call.
+ // */
+ // @Override
+ // public EList<EObject> getContents() {
+ // // the getContents should not load but should return an
+ // // empty string if not yet loaded.
+ // // if (!isLoaded() && !isLoading) {
+ // // load(null);
+ // // }
+ // //
+ // // and then do our thing!
+ // return super.getContents();
+ // }
+ //
+ // /**
+ // * Extra method to allow subclasses to easily reach the contents of the
+ // superclass of this class
+ // */
+ // protected EList<EObject> getSuperContents() {
+ // return super.getContents();
+ // }
+
+ // -------------------------------- Change Tracker
+ // ----------------------------------
+
+ /** Clears the change tracker arrays */
+ public void clearChangeTrackerArrays() {
+ removedEObjects.clear();
+ newEObjects.clear();
+ newEObjectSet.clear();
+ loadedEObjects.clear();
+ loadedEObjectSet.clear();
+ modifiedEObjects.clear();
+ }
+
+ /**
+ * Keeps track of changed objects, CHECK: currently if a tree of objects has
+ * been added to this resource and afterwards a child in the tree is changed
+ * then the child is added to the modifiedEObjects list while its containing
+ * parent is part of the addedEObjects list. This should maybe be prevented
+ * here but this can come at some cost as it means that the complete
+ * container path has to be loaded for each modification.
+ */
+ public void modifiedEObject(EObject eObject) {
+ // if (addedEObjects.contains(eObject)) return; // see remark above, if
+ // childs are added to the modified list
+ // then childs also
+
+ if (loadedEObjectSet.contains(eObject)
+ && !modifiedEObjects.contains(eObject)) {
+ assert (!newEObjectSet.contains(eObject));
+ modifiedEObjects.add(eObject);
+ }
+ }
+
+ /** Keeps track of new objects */
+ public void addedEObject(EObject eObject) {
+ if (isLoading()) {
+ if (removedEObjects.contains(eObject)) {
+ // special case an eobject was removed from the resource but is
+ // readded during load of an elist
+ // the remove will be done at save
+ return;
+ }
+ // assert (!removedEObjects.contains(eObject));
+ assert (!loadedEObjectSet.contains(eObject));
+ loadedEObjects.add(eObject);
+ loadedEObjectSet.add(eObject);
+ } else {
+ // assert (!removedEObjects.contains(eObject));
+ assert (!newEObjectSet.contains(eObject));
+ if (removedEObjects.remove(eObject)) {
+ modifiedEObjects.add(eObject);
+ } else {
+ newEObjects.add(eObject);
+ newEObjectSet.add(eObject);
+ }
+ }
+ }
+
+ /** Keeps track of removed objects */
+ public void removedEObject(EObject eObject) {
+ assert (!removedEObjects.contains(eObject));
+
+ if (newEObjectSet.contains(eObject)) {
+ assert (newEObjects.contains(eObject));
+ newEObjects.remove(eObject); // just remove from this list
+ newEObjectSet.remove(eObject);
+ return;
+ }
+
+ if (!loadedEObjectSet.contains(eObject)) {
+ assert (!loadedEObjects.contains(eObject));
+ }
+ assert (!removedEObjects.contains(eObject));
+
+ if (!(eObject instanceof BasicEMap.Entry<?, ?>)) {
+ removedEObjects.add(eObject);
+ }
+
+ loadedEObjects.remove(eObject);
+ loadedEObjectSet.remove(eObject);
+ modifiedEObjects.remove(eObject);
+ }
+
+ /** Object is attached, is overridden to use non-resolving iterator */
+ @Override
+ public void attached(EObject eObject) {
+ attachedHelper(eObject);
+ for (Iterator<EObject> tree = getNonResolvingContent(eObject)
+ .basicIterator(); tree.hasNext();) {
+ final Object obj = tree.next();
+ // before this called:
+ // attachedHelper((EObject) obj);
+ // however this resulted in child elements (which were loaded) not
+ // being
+ // added to the internal id map
+ attached((EObject) obj);
+ }
+ }
+
+ /** Detached means deleted from resource */
+ @Override
+ public void detached(EObject eObject) {
+ detachedHelper(eObject);
+ for (EObject object : getNonResolvingContent(eObject)) {
+ detachedHelper(object);
+ }
+ }
+
+ /**
+ * Attached the object to this resource, This object will be stored at the
+ * next save action. Also handles the specific id generation used for
+ * different resource impl.
+ *
+ * Note that this method does not add the object to the
+ * resource.getContents(). It just adds the object to the internal lists of
+ * this resource.
+ */
+ // 20 April 2008: cleaned up side-effects of this method, add to contents,
+ // setting
+ // eresource has been disabled, this should be done in calling methods
+ @Override
+ protected void attachedHelper(EObject eObject) {
+ // also attach the container
+ // if (eObject.eContainer() != null && eObject.eContainer().eResource()
+ // == null &&
+ // !eObject.eContainmentFeature().isResolveProxies()) {
+ // attached(eObject.eContainer());
+ // }
+
+ // a bit strange as an object can only be contained once but this can
+ // happen if someone
+ // adds an object to a resource directly and then later add this same
+ // object as a child
+ // to a container
+ if (newEObjectSet.contains(eObject)
+ || loadedEObjectSet.contains(eObject)) {
+ return;
+ }
+
+ // Already belongs to another resource
+ if (eObject.eResource() != null && eObject.eResource() != this) {
+ return;
+ }
+
+ addedEObject(eObject);
+
+ // if (eObject instanceof InternalEObject && eObject.eResource() ==
+ // null) {
+ // setEResource((InternalEObject) eObject, false);
+ // }
+
+ // NOTE: should this really happen here? My feel is that this should
+ // be cleaned up and be done outside of this method
+ // This is required here because the attached method is called
+ // recursively for the container, see the first if in this method
+ // only add an eobject to contents if it does not have a container or if
+ // the container
+ // relation allows resolve proxies (container and contained can be in
+ // different resources)
+ // and the load strategy is correct
+ // if ((eObject.eContainer() == null || eObject.eContainmentFeature() ==
+ // null ||
+ // eObject.eContainmentFeature()
+ // .isResolveProxies()) &&
+ // !getContents().contains(eObject) &&
+ // loadStrategy.compareTo(ADD_TO_CONTENTS) == 0) {
+ // // note direct access to super contents
+ // final NotificationChain notifications = contents.basicAdd(eObject,
+ // null);
+ // if (notifications != null && sendNotificationsOnLoad) {
+ // notifications.dispatch();
+ // }
+ // }
+
+ if (isTrackingModification()) {
+ eObject.eAdapters().add(modificationTrackingAdapter);
+ }
+
+ Map<String, EObject> map = getIntrinsicIDToEObjectMap();
+ if (map != null) {
+ String id = EcoreUtil.getID(eObject);
+ if (id != null) {
+ map.put(id, eObject);
+ } else {
+ id = getURIFragment(eObject);
+ if (id != null) {
+ map.put(id, eObject);
+ }
+ }
+ }
+
+ // now also attach all ereferences with single values which are
+ // contained
+ for (EReference eref : eObject.eClass().getEAllReferences()) {
+ if (!eref.isMany() && eObject.eGet(eref, false) != null) { // the
+ // ismanies
+ // are handled
+ // differently
+ final Resource res = ((EObject) eObject.eGet(eref)).eResource();
+ if (res == null) { // attach it to this resource because it has
+ // no other
+ final InternalEObject referedTo = (InternalEObject) eObject
+ .eGet(eref);
+ addToContentOrAttach(referedTo, eref);
+ }
+ }
+ }
+ }
+
+ /**
+ * Add to the contents of this resource and dispatch if send notification.
+ * It also takes care of attaching this object and its contained children to
+ * the internal lists and setting the eResource.
+ *
+ * Approaches: - Set eResource and add to contents (if no econtainer) - Just
+ * set eResource and add to contents if it does not have a container public
+ * void addToResource(InternalEObject eObject, boolean forceAddToContents) {
+ * // if it has an econtainer then also add the econtainer if
+ * (eObject.eContainer() != null && eObject.eContainer().eResource() ==
+ * null) { addToResource((InternalEObject)eObject.eContainer(), false); } //
+ * if the econtainer is already part of this resource then just attach if
+ * (!forceAddToContents && eObject.eContainer() != null &&
+ * eObject.eContainer().eResource() == this) { attached(eObject); return; }
+ * // probably lazy load action of non-containment, already part of this
+ * just return if (!forceAddToContents && eObject.eResource() == this &&
+ * !loadedEObjects.contains(eObject) && !removedEObjects.contains(eObject)
+ * && !newEObjects.contains(eObject)) { attached(eObject); return; } //
+ * already part of another resource if (!forceAddToContents &&
+ * eObject.eResource() != null) { return; }
+ *
+ * final ContentsEList elist = (ContentsEList) super.getContents(); if
+ * (elist.contains(eObject)) { // can happen because of extends,
+ * polymorphism return; } // fill in the resource, do not use the normal add
+ * method because it // is possible that a child of a container is loaded,
+ * in that case // the normal add will remove the container of the object
+ * when the // resource is set in the child object, this issue can happen
+ * with // direct reads using queries. NotificationChain notification =
+ * null; if (loadStrategy.compareToIgnoreCase(ADD_TO_CONTENTS) == 0 ||
+ * forceAddToContents) { notification = elist.basicAdd(eObject, null); } if
+ * (eObject.eResource() == null || (forceAddToContents &&
+ * eObject.eResource() != this)) { setEResource(eObject,
+ * forceAddToContents); } // attached(eObject); if (sendNotificationsOnLoad
+ * && notification != null) { notification.dispatch(); } }
+ */
+
+ /**
+ * Sets the eresource by walking up the containment structure and finding
+ * the highest parent. There the resource is set.If the resource is already
+ * set nothing is done.
+ */
+ public void setEResource(InternalEObject eobj, boolean force) {
+ if (eobj.eResource() != null && eobj.eResource() != this && !force) {
+ return;
+ }
+
+ final Resource prevResource = eobj.eResource();
+
+ InternalEObject currentEObject = eobj;
+ final List<EObject> toMove = new ArrayList<EObject>();
+ while (currentEObject.eContainer() != null
+ && !currentEObject.eContainmentFeature().isResolveProxies()) {
+ toMove.add(currentEObject);
+ currentEObject = (InternalEObject) currentEObject.eContainer();
+ }
+ if (currentEObject.eResource() != this) {
+ currentEObject.eSetResource(this, null);
+ attached(currentEObject);
+ }
+
+ // the original object can be loaded in the root of the old resource
+ // it is not removed automatically in this approach, do that now
+ for (EObject toMoveEObject : toMove) {
+ if (prevResource != null
+ && toMoveEObject.eResource() != prevResource) {
+ ((ContentsEList<?>) prevResource.getContents()).basicRemove(
+ toMoveEObject, null);
+ }
+ }
+
+ }
+
+ /**
+ * Overridden to also support persistence specific id instead of single emf
+ * id
+ */
+ @Override
+ protected void detachedHelper(EObject eObject) {
+
+ // support move to other resource
+ if (eObject.eResource() != this) {
+ removedEObjects.remove(eObject);
+ modifiedEObjects.remove(eObject);
+ loadedEObjects.remove(eObject);
+ loadedEObjectSet.remove(eObject);
+ newEObjects.remove(eObject);
+ newEObjectSet.remove(eObject);
+ return;
+ }
+
+ removedEObject(eObject);
+
+ Map<String, EObject> map = getIntrinsicIDToEObjectMap();
+ if (map != null) {
+ String id = EcoreUtil.getID(eObject);
+ if (id != null) {
+ map.remove(id);
+ } else {
+ id = getURIFragment(eObject);
+ if (id != null) {
+ map.remove(id);
+ }
+ }
+ }
+
+ if (isTrackingModification()) {
+ eObject.eAdapters().remove(modificationTrackingAdapter);
+ }
+ }
+
+ /** Returns the added objects */
+ public List<EObject> getNewEObjects() {
+ return newEObjects;
+ }
+
+ public HashSet<EObject> getNewEObjectSet() {
+ return newEObjectSet;
+ }
+
+ /** Return the new eobjects */
+ public HashSet<EObject> getModifiedEObjects() {
+ return modifiedEObjects;
+ }
+
+ /** Return the new eobjects */
+ public List<EObject> getRemovedEObjects() {
+ return removedEObjects;
+ }
+
+ /**
+ * Overridden to make it non resolving for not loaded elists and proxy
+ * eobjects
+ */
+ @Override
+ public void setTrackingModification(boolean isTrackingModification) {
+ boolean oldIsTrackingModification = modificationTrackingAdapter != null;
+
+ if (oldIsTrackingModification != isTrackingModification) {
+ if (isTrackingModification) {
+
+ // note the global modification adapter is set after the for
+ // loop
+ // because in the for loop extra objects can be added to the
+ // resource
+ // these objects would get two adapters, once in the
+ // attachedHelper method
+ // and once here, btw can also prevent this by adding a contains
+ // check within
+ // for loop
+ final Adapter adapter = createModificationTrackingAdapter();
+ for (Iterator<EObject> i = getNonResolvingAllContents(); i
+ .hasNext();) {
+ EObject eObject = i.next();
+ assert (!eObject.eAdapters().contains(adapter));
+ eObject.eAdapters().add(adapter);
+ }
+ modificationTrackingAdapter = adapter;
+ } else {
+ Adapter oldModificationTrackingAdapter = modificationTrackingAdapter;
+
+ for (Iterator<EObject> i = getNonResolvingAllContents(); i
+ .hasNext();) {
+ EObject eObject = i.next();
+ assert (eObject.eAdapters()
+ .contains(modificationTrackingAdapter));
+ eObject.eAdapters().remove(oldModificationTrackingAdapter);
+ }
+ modificationTrackingAdapter = null;
+ }
+ }
+
+ if (eNotificationRequired()) {
+ Notification notification = new NotificationImpl(Notification.SET,
+ oldIsTrackingModification, isTrackingModification) {
+ @Override
+ public Object getNotifier() {
+ return StoreResource.this;
+ }
+
+ @Override
+ public int getFeatureID(Class<?> expectedClass) {
+ return RESOURCE__IS_TRACKING_MODIFICATION;
+ }
+ };
+ eNotify(notification);
+ }
+ }
+
+ /**
+ * Always returns a non-resolving iterator because resolving is defined on
+ * model level and the resource should adhere to that
+ */
+ @SuppressWarnings("serial")
+ protected TreeIterator<EObject> getNonResolvingAllContents() {
+ return new AbstractTreeIterator<EObject>(this, false) {
+ @Override
+ public Iterator<EObject> getChildren(Object object) {
+ return object == StoreResource.this ? getLocalContents()
+ .basicIterator() : getNonResolvingContent(
+ (EObject) object).basicIterator();
+ }
+ };
+ }
+
+ @Override
+ // Method is called at unload, only loaded content should be iterated
+ protected TreeIterator<EObject> getAllProperContents(List<EObject> contents) {
+ return getNonResolvingAllContents();
+ }
+
+ /** Returns a non-resolving contents elist for an eobject */
+ protected EContentsEList<EObject> getNonResolvingContent(EObject eObject) {
+ return NonLoadingEContentsEList.create(eObject, false);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @seeorg.eclipse.emf.ecore.resource.impl.ResourceImpl#
+ * createModificationTrackingAdapter()
+ */
+ @Override
+ protected Adapter createModificationTrackingAdapter() {
+ return new StoreModificationTrackingAdapter();
+ }
+
+ // Enable or disable notifications for the current content
+ protected void setAllowNotifications(boolean allow) {
+ for (Iterator<?> i = getNonResolvingAllContents(); i.hasNext();) {
+ EObject eObject = (EObject) i.next();
+ eObject.eSetDeliver(allow);
+ }
+ }
+
+ /**
+ * An adapter implementation for tracking resource modification, registers
+ * changed objects
+ */
+ protected class StoreModificationTrackingAdapter extends AdapterImpl {
+ @Override
+ public void notifyChanged(Notification notification) {
+ switch (notification.getEventType()) {
+ case Notification.SET:
+ case Notification.UNSET:
+ case Notification.MOVE: {
+ if (!notification.isTouch()) {
+ setModified(true);
+ modifiedEObject((EObject) notification.getNotifier());
+ }
+ break;
+ }
+ case Notification.ADD:
+ case Notification.REMOVE:
+ case Notification.ADD_MANY:
+ case Notification.REMOVE_MANY: {
+ setModified(true);
+ break;
+ }
+ }
+ }
+ }
+
+ /**
+ * @return the sendNotificationsOnLoad
+ */
+ public boolean isSendNotificationsOnLoad() {
+ return sendNotificationsOnLoad;
+ }
+} \ No newline at end of file
diff --git a/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/resource/StoreResourceException.java b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/resource/StoreResourceException.java
new file mode 100755
index 000000000..86bc3cfec
--- /dev/null
+++ b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/resource/StoreResourceException.java
@@ -0,0 +1,42 @@
+/**
+ * <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: StoreResourceException.java,v 1.8 2009/03/30 07:53:04 mtaal Exp $
+ */
+
+package org.eclipse.emf.teneo.resource;
+
+import org.eclipse.emf.teneo.TeneoException;
+
+/**
+ * Is used to throw runtime store exceptions. 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.8 $
+ */
+
+public class StoreResourceException extends TeneoException {
+ /**
+ * Serializable id
+ */
+ private static final long serialVersionUID = 7433341056815136417L;
+
+ /**
+ * The constructor, logs the exception also
+ */
+ public StoreResourceException(String msg, Throwable cause) {
+ super(msg, cause);
+ }
+
+ /**
+ * The constructor, logs the exception also
+ */
+ public StoreResourceException(String msg) {
+ super(msg);
+ }
+}
diff --git a/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/simpledom/Attribute.java b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/simpledom/Attribute.java
new file mode 100755
index 000000000..3f0f250b5
--- /dev/null
+++ b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/simpledom/Attribute.java
@@ -0,0 +1,43 @@
+/**
+ * <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: Attribute.java,v 1.6 2008/02/28 07:08:33 mtaal Exp $
+ */
+
+package org.eclipse.emf.teneo.simpledom;
+
+/**
+ * This simple class is part of the replacement of dom4j.
+ *
+ * @author <a href="mailto:mtaal@elver.org">Martin Taal</a>
+ * @version $Revision: 1.6 $
+ */
+public class Attribute extends Node {
+
+ /** Constructor */
+ public Attribute() {
+ super();
+ }
+
+ /** Constructor */
+ public Attribute(String name, String text) {
+ setName(name);
+ setText(text);
+ }
+
+ /** emit me */
+ String emitXML() {
+ return getName() + "=\"" + getText() + "\"";
+ }
+} \ No newline at end of file
diff --git a/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/simpledom/Document.java b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/simpledom/Document.java
new file mode 100755
index 000000000..dfedab415
--- /dev/null
+++ b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/simpledom/Document.java
@@ -0,0 +1,64 @@
+/**
+ * <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: Document.java,v 1.9 2009/03/30 07:53:04 mtaal Exp $
+ */
+
+package org.eclipse.emf.teneo.simpledom;
+
+/**
+ * This simple class is part of the replacement of dom4j.
+ *
+ * @author <a href="mailto:mtaal@elver.org">Martin Taal</a>
+ * @version $Revision: 1.9 $
+ */
+
+public class Document {
+
+ /** The doctype */
+ private String docType = "";
+
+ /** Root element */
+ private Element root = null;
+
+ /** Set the docType */
+ public void setDocType(String docType) {
+ this.docType = docType;
+ }
+
+ /** Set the root */
+ public Element setRoot(Element root) {
+ this.root = root;
+ return root;
+ }
+
+ /** Return the root */
+ public Element getRoot() {
+ return root;
+ }
+
+ /** Emit ourselve as a XML string */
+ public String emitXML() {
+ final StringBuffer result = new StringBuffer("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
+ if (docType.length() > 0) {
+ result.append(docType + "\n");
+ }
+ // removed the following line because then comparison between different
+ // versions
+ // of hbm files is easier.
+ // result.append("<!--\tGenerated by Teneo on " + new Date() + " -->");
+ result.append(root.emitXML());
+ return result.toString();
+ }
+} \ No newline at end of file
diff --git a/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/simpledom/DocumentHelper.java b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/simpledom/DocumentHelper.java
new file mode 100755
index 000000000..6fbd99288
--- /dev/null
+++ b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/simpledom/DocumentHelper.java
@@ -0,0 +1,35 @@
+/**
+ * <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: DocumentHelper.java,v 1.4 2008/02/28 07:08:33 mtaal Exp $
+ */
+
+package org.eclipse.emf.teneo.simpledom;
+
+/**
+ * This simple class is part of the replacement of dom4j.
+ *
+ * @author <a href="mailto:mtaal@elver.org">Martin Taal</a>
+ * @version $Revision: 1.4 $
+ */
+
+public class DocumentHelper {
+
+ /** Create an element */
+ public static Element createElement(String name) {
+ final Element element = new Element();
+ element.setName(name);
+ return element;
+ }
+} \ No newline at end of file
diff --git a/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/simpledom/Element.java b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/simpledom/Element.java
new file mode 100755
index 000000000..0e4135e9b
--- /dev/null
+++ b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/simpledom/Element.java
@@ -0,0 +1,230 @@
+/**
+ * <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: Element.java,v 1.11 2010/07/15 07:46:44 mtaal Exp $
+ */
+
+package org.eclipse.emf.teneo.simpledom;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * This simple class is part of the replacement of dom4j.
+ *
+ * @author <a href="mailto:mtaal@elver.org">Martin Taal</a>
+ * @version $Revision: 1.11 $
+ */
+
+public class Element extends Node {
+
+ /** The children */
+ private List<Element> children = new ArrayList<Element>();
+
+ /** The attributes */
+ private List<Attribute> attributes = new ArrayList<Attribute>();
+
+ /** The parent element */
+ private Element parent = null;
+
+ /** Constructor */
+ public Element() {
+ }
+
+ /** Constructor */
+ public Element(String name) {
+ setName(name);
+ }
+
+ /** Method to add attribute */
+ public Element addAttribute(String name, String text) {
+ // check if already present
+ for (Attribute attr : attributes) {
+ if (attr.getName().compareTo(name) == 0) {
+ attr.setText(text);
+ return this;
+ }
+ }
+
+ final Attribute attr = new Attribute(name, text);
+ attributes.add(attr);
+ return this;
+ }
+
+ /**
+ * Return the value of an attribute the attribute name, if not found then null is returned
+ */
+ public String getAttributeValue(String name) {
+ for (Attribute attr : attributes) {
+ if (attr.getName().compareTo(name) == 0) {
+ return attr.getText();
+ }
+ }
+ return null;
+ }
+
+ /** Remove the attribute using a specific name */
+ public void removeAttribute(String name) {
+ Attribute toRemove = null;
+ for (Attribute attr : attributes) {
+ if (attr.getName().compareTo(name) == 0) {
+ toRemove = attr;
+ }
+ }
+ if (toRemove != null) {
+ attributes.remove(toRemove);
+ }
+ }
+
+ /** Method to add attribute */
+ public Element addAttribute(Attribute attr) {
+ attributes.add(attr);
+ return this;
+ }
+
+ /** Method to add Element */
+ public Element addElement(String name) {
+ final Element element = new Element();
+ element.setName(name);
+ children.add(element);
+ element.setParent(this);
+ return element;
+ }
+
+ /** Method to add Element */
+ public Element addElement(Element element) {
+ children.add(element);
+ element.setParent(this);
+ return element;
+ }
+
+ /**
+ * @param text
+ * the text to set
+ */
+ public void addText(String text) {
+ setText(getText() + text);
+ }
+
+ /** Add */
+ public Element add(Element element) {
+ children.add(element);
+ element.setParent(this);
+ return element;
+ }
+
+ /** Add */
+ public Element add(int index, Element element) {
+ children.add(index, element);
+ element.setParent(this);
+ return element;
+ }
+
+ /** Find a child element */
+ public Element element(String name) {
+ for (Element elem : children) {
+ if (elem.getName().compareTo(name) == 0) {
+ return elem;
+ }
+ }
+ return null;
+ }
+
+ /** The indexof */
+ public int indexOf(Element element) {
+ return children.indexOf(element);
+ }
+
+ /** The remove */
+ public boolean remove(Element element) {
+ return children.remove(element);
+ }
+
+ /**
+ * @return the parent
+ */
+ public Element getParent() {
+ return parent;
+ }
+
+ /**
+ * @param parent
+ * the parent to set
+ */
+ public void setParent(Element parent) {
+ this.parent = parent;
+ }
+
+ /** Emit ourselves */
+ String emitXML() {
+ final StringBuffer result = new StringBuffer("\n");
+ int level = getLevel();
+ for (int i = 0; i < level; i++) {
+ result.append("\t");
+ }
+
+ result.append("<" + getName());
+ for (int i = 0; i < attributes.size(); i++) {
+ result.append(" ");
+ final Attribute attr = attributes.get(i);
+ result.append(attr.emitXML());
+ }
+ if (children.size() == 0 && (getText() == null || getText().length() == 0)) {
+ result.append("/>");
+ return result.toString();
+ }
+ result.append(">");
+ if (children.size() == 0) {
+ result.append(getText());
+ result.append("</" + getName() + ">");
+ return result.toString();
+ }
+
+ for (int i = 0; i < children.size(); i++) {
+ final Element element = children.get(i);
+ result.append(element.emitXML());
+ }
+ result.append("\n");
+ for (int i = 0; i < level; i++) {
+ result.append("\t");
+ }
+ result.append("</" + getName() + ">");
+ return result.toString();
+ }
+
+ /* Return the level */
+ int getLevel() {
+ if (getParent() != null) {
+ return 1 + getParent().getLevel();
+ }
+ return 0;
+ }
+
+ /** Return the children */
+ public List<Element> getChildren() {
+ return children;
+ }
+
+ /** Clone */
+ @Override
+ public Object clone() {
+ final Element element = new Element();
+ element.setName(getName());
+ element.setText(getText());
+ element.children.addAll(children);
+ element.attributes.addAll(attributes);
+ element.setParent(getParent());
+ return element;
+ }
+} \ No newline at end of file
diff --git a/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/simpledom/Node.java b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/simpledom/Node.java
new file mode 100755
index 000000000..d58bfb6d6
--- /dev/null
+++ b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/simpledom/Node.java
@@ -0,0 +1,64 @@
+/**
+ * <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: Node.java,v 1.6 2008/02/28 07:08:33 mtaal Exp $
+ */
+
+package org.eclipse.emf.teneo.simpledom;
+
+/**
+ * This simple class is part of the replacement of dom4j.
+ *
+ * @author <a href="mailto:mtaal@elver.org">Martin Taal</a>
+ * @version $Revision: 1.6 $
+ */
+
+public abstract class Node {
+
+ /** The element name */
+ private String name;
+
+ /** The content, only text is supported */
+ private String text = "";
+
+ /**
+ * @return the name
+ */
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * @param name
+ * the name to set
+ */
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ /**
+ * @return the text
+ */
+ public String getText() {
+ return text;
+ }
+
+ /**
+ * @param text
+ * the text to set
+ */
+ public void setText(String text) {
+ this.text = text;
+ }
+} \ No newline at end of file
diff --git a/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/type/FeatureMapEntry.java b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/type/FeatureMapEntry.java
new file mode 100755
index 000000000..b55b19acb
--- /dev/null
+++ b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/type/FeatureMapEntry.java
@@ -0,0 +1,467 @@
+/**
+ * <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: FeatureMapEntry.java,v 1.10 2010/02/04 11:03:02 mtaal Exp $
+ */
+
+package org.eclipse.emf.teneo.type;
+
+import java.io.IOException;
+import java.io.Serializable;
+
+import org.eclipse.emf.common.notify.NotificationChain;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.EReference;
+import org.eclipse.emf.ecore.EStructuralFeature;
+import org.eclipse.emf.ecore.InternalEObject;
+import org.eclipse.emf.ecore.util.ExtendedMetaData;
+import org.eclipse.emf.ecore.util.FeatureMap;
+import org.eclipse.emf.teneo.EContainerRepairControl;
+import org.eclipse.emf.teneo.util.StoreUtil;
+
+/**
+ * Is used to replace the EMF feature map entry with an entry which can be handled by the or layer.
+ *
+ * The FeatureMap.Entry.Internal methods are handled through a delegate. Based on the efeature the
+ * correct delegate is created.
+ *
+ * @author <a href="mailto:mtaal@elver.org">Martin Taal</a>
+ * @version $Revision: 1.10 $
+ */
+
+public abstract class FeatureMapEntry implements FeatureMap.Entry.Internal, Serializable {
+ private static final long serialVersionUID = 1L;
+
+ /** The structural feature which defines which element this is */
+ private EStructuralFeature eStructuralFeature;
+
+ /** Path to the efeature for serialization support */
+ private String eFeaturePath;
+
+ /** And its value */
+ private Object value;
+
+ /** Keeps track if the class was initialized */
+ private boolean initialized = false;
+
+ /** The delegate which implements the inverse action */
+ private InverseAction inverseAction;
+
+ /**
+ * The featuremap to which we are connected. Is used to determine if entries have been added to
+ * another featuremap. This happens in copy actions.
+ */
+ private FeatureMap.Internal owningMap;
+
+ /**
+ * Constructor called by the storage layer, fields need to be set by calls to subclass
+ */
+ public FeatureMapEntry() {
+ }
+
+ /**
+ * Constructor called by the storage layer, fields need to be set by calls to subclass
+ */
+ public FeatureMapEntry(EStructuralFeature feature, Object val) {
+ eStructuralFeature = feature;
+ value = val;
+ initialized = true;
+ initializeSpecificImplementation();
+ setInverseAction();
+ }
+
+ /** Takes care of serializing the efeature */
+ private void writeObject(java.io.ObjectOutputStream out) throws IOException {
+ eFeaturePath = StoreUtil.structuralFeatureToString(eStructuralFeature);
+ eStructuralFeature = null;
+ out.defaultWriteObject();
+ }
+
+ /** Takes care of deserializing the efeature */
+ private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException {
+ in.defaultReadObject();
+ eStructuralFeature = StoreUtil.stringToStructureFeature(eFeaturePath);
+ }
+
+ /** Set the inverseaction delegate, must be called after the efeature is set */
+ private void setInverseAction() {
+ if (eStructuralFeature instanceof EReference) {
+ final EReference eref = (EReference) eStructuralFeature;
+ if (eref.getEOpposite() != null) {
+ inverseAction = new BidirectionalInverseAction();
+ } else if (eref.isContainment()) {
+ inverseAction = new ContainmentInverseAction();
+ } else {
+ inverseAction = new InverseAction();
+ }
+ } else {
+ inverseAction = new InverseAction();
+ }
+ }
+
+ /** Sets the featuremap, is done when an entry is added to the featuremap */
+ public void setFeatureMap(FeatureMap.Internal featureMap) {
+ owningMap = featureMap;
+
+ /*
+ * if (value != null && value instanceof InternalEObject && eStructuralFeature instanceof
+ * EReference && ((EReference)eStructuralFeature).isContainment()) { ((InternalEObject)
+ * value).eSetResource((Resource.Internal)owningMap.getEObject ().eResource(), null); }
+ */
+ }
+
+ /** Unsets the featuremap, is done when an entry is removed */
+ public void unsetFeatureMap() {
+ owningMap = null;
+ }
+
+ /** Is true if this featureMap already belongs to a Map */
+ public boolean isFeatureMapSet() {
+ return owningMap != null;
+ }
+
+ /** Is true if this featureMap already belongs to the passed map */
+ public boolean belongsToFeatureMap(FeatureMap.Internal fm) {
+ return owningMap == fm; // object equality!
+ }
+
+ /** Set the value from a previous entry */
+ public void setEntry(FeatureMap.Entry entry) {
+ eStructuralFeature = entry.getEStructuralFeature();
+ value = entry.getValue();
+ initialized = true; // needs to be set before the call to the subclass,
+ // otherwise infinite
+ // looping
+ initializeSpecificImplementation();
+ setInverseAction();
+ }
+
+ /** Initializes this class from the values in the subclass */
+ public void initialize() {
+ eStructuralFeature = retrieveStructuralFeature(getStructuralFeatureDBID());
+ value = getValueFromSpecificImplementation(eStructuralFeature);
+ initialized = true;
+ setInverseAction();
+ }
+
+ /**
+ * Needs to be implemented by the subclass, returns the value based on one of the fields set
+ * through the db
+ */
+ protected abstract Object getValueFromSpecificImplementation(EStructuralFeature eFeature);
+
+ /**
+ * Needs to be implemented by the subclass, returns the database id of the structural feature
+ */
+ protected abstract String getStructuralFeatureDBID();
+
+ /**
+ * Is called by the super class to notify the subclass that it needs to set its fields based on
+ * the structural feature
+ */
+ protected abstract void initializeSpecificImplementation();
+
+ /**
+ * Method which needs to be called by the subclass to set the superclass members
+ */
+ public void setFields(EStructuralFeature structuralFeature, Object structuralValue) {
+ eStructuralFeature = structuralFeature;
+ value = structuralValue;
+ initialized = true; // do this before the call to the subclass
+ // initialize the subclass so that the fields are stored in the db
+ initializeSpecificImplementation();
+ setInverseAction();
+ }
+
+ /** Returns structural feature */
+ public EStructuralFeature getEStructuralFeature() {
+ if (!initialized) {
+ initialize();
+ }
+
+ return eStructuralFeature;
+ }
+
+ /** Returns the value */
+ public Object getValue() {
+ if (!initialized) {
+ initialize();
+ }
+
+ return value;
+ }
+
+ /**
+ * Returns the string which is used to store the unique identification of this structuralfeature
+ * in the db
+ */
+ protected String createStructuralFeatureDBID() {
+ return StoreUtil.structuralFeatureToString(getEStructuralFeature());
+ }
+
+ /** Gets a structuralfeature on the basis of the passed id */
+ protected EStructuralFeature retrieveStructuralFeature(String dbid) {
+ return StoreUtil.stringToStructureFeature(dbid);
+ }
+
+ /**
+ * Checks if a certain feature has a certain name or that its group (if present) has this name,
+ * in which case it is also set to true.
+ */
+ protected boolean featureForField(String name) {
+ if (eStructuralFeature.getName().compareTo(name) == 0) {
+ return true;
+ }
+
+ // check the group feature
+ final EStructuralFeature groupFeature = ExtendedMetaData.INSTANCE.getGroup(eStructuralFeature);
+ if (groupFeature != null && groupFeature.getName().compareTo(name) == 0) {
+ return true;
+ }
+
+ final EStructuralFeature affiliatedFeature = ExtendedMetaData.INSTANCE.getAffiliation(eStructuralFeature);
+ if (affiliatedFeature != null && affiliatedFeature.getName().compareTo(name) == 0) {
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Sets the container property of the value if the value is an EObject and the feature is a
+ * containment feature.
+ */
+ public void setContainer(InternalEObject owner) {
+ if (!initialized) {
+ initialize();
+ }
+
+ if (value != null && value instanceof InternalEObject && eStructuralFeature instanceof EReference &&
+ ((EReference) eStructuralFeature).isContainment()) {
+ EContainerRepairControl.setContainer(owner, (InternalEObject) value, eStructuralFeature);
+ }
+ }
+
+ /** Code copied from FeatureMapUtil.EntryImpl */
+ @Override
+ public boolean equals(Object that) {
+ if (!initialized) {
+ initialize();
+ }
+
+ if (this == that) {
+ return true;
+ } else if (!(that instanceof FeatureMap.Entry)) {
+ return false;
+ } else {
+ FeatureMap.Entry entry = (FeatureMap.Entry) that;
+ return entry.getEStructuralFeature() == eStructuralFeature &&
+ (value == null ? entry.getValue() == null : value.equals(entry.getValue()));
+ }
+ }
+
+ /** Code copied from FeatureMapUtil.EntryImpl */
+ @Override
+ public int hashCode() {
+ /*
+ * Used to create a hashcode which maps all instances of one class to the same hashcode Is
+ * required because the normal hashcode method (see commented out part below) resulted in
+ * null-pointer exceptions in hibernate because the content of the entry was used for
+ * determining the hashcode while the object was not initialized from the db
+ */
+ return this.getClass().hashCode();
+ /*
+ * if (!initialized) initialize();
+ *
+ * return eStructuralFeature.hashCode() ^ (value == null ? 0 : value.hashCode());
+ */
+ }
+
+ /** Code copied from FeatureMapUtil.EntryImpl */
+ @Override
+ public String toString() {
+ if (!initialized) {
+ initialize();
+ }
+
+ String prefix = eStructuralFeature.getEContainingClass().getEPackage().getNsPrefix();
+ eStructuralFeature.getName();
+ return (prefix != null && prefix.length() != 0 ? prefix + ":" + eStructuralFeature.getName()
+ : eStructuralFeature.getName()) +
+ "=" + value;
+ }
+
+ /** Create copy with same feature and different value */
+ public Internal createEntry(InternalEObject value) {
+ return createEntry((Object) value);
+ }
+
+ /** Create copy with same feature and different value */
+ public abstract Internal createEntry(Object value);
+
+ /** Do inverse action */
+ public NotificationChain inverseAdd(InternalEObject owner, int featureID, NotificationChain notifications) {
+ return inverseAction.inverseAdd(owner, featureID, notifications);
+ }
+
+ /** Do inverse action */
+ public NotificationChain inverseAdd(InternalEObject owner, Object otherEnd, int featureID,
+ NotificationChain notifications) {
+ return inverseAction.inverseAdd(owner, otherEnd, featureID, notifications);
+ }
+
+ /** Do inverse action */
+ public NotificationChain inverseRemove(InternalEObject owner, int featureID, NotificationChain notifications) {
+ return inverseAction.inverseRemove(owner, featureID, notifications);
+ }
+
+ /** Do inverse action */
+ public NotificationChain inverseRemove(InternalEObject owner, Object otherEnd, int featureID,
+ NotificationChain notifications) {
+ return inverseAction.inverseRemove(owner, otherEnd, featureID, notifications);
+ }
+
+ /** Validate type of object against the type of the efeature */
+ public void validate(Object value) {
+ if (value != null && !eStructuralFeature.getEType().isInstance(value)) {
+ String valueClass =
+ value instanceof EObject ? ((EObject) value).eClass().getName() : value.getClass().getName();
+ throw new ClassCastException("The feature '" + eStructuralFeature.getName() + "'s type '" +
+ eStructuralFeature.getEType().getName() + "' does not permit a value of type '" + valueClass + "'");
+ }
+ }
+
+ /** Internal class to handle inverse actions */
+ private class InverseAction {
+
+ /** Handles inverse action, differs on the basis of the feature type */
+ public NotificationChain inverseAdd(InternalEObject owner, int featureID, NotificationChain notifications) {
+ return inverseAdd(owner, value, featureID, notifications);
+ }
+
+ /** Handles inverse action, differs on the basis of the feature type */
+ public NotificationChain inverseRemove(InternalEObject owner, int featureID, NotificationChain notifications) {
+ return inverseRemove(owner, value, featureID, notifications);
+ }
+
+ /** Handles inverse action, differs on the basis of the feature type */
+ public NotificationChain inverseAdd(InternalEObject owner, Object otherEnd, int featureID,
+ NotificationChain notifications) {
+ return notifications;
+ }
+
+ /** Handles inverse action, differs on the basis of the feature type */
+ public NotificationChain inverseRemove(InternalEObject owner, Object otherEnd, int featureID,
+ NotificationChain notifications) {
+ return notifications;
+ }
+//
+// /**
+// * validate the type of the value with the type expected by the efeature
+// */
+// public void validate(Object value) {
+// if (value != null && !eStructuralFeature.getEType().isInstance(value)) {
+// String valueClass =
+// value instanceof EObject ? ((EObject) value).eClass().getName() : value.getClass().getName();
+// throw new ClassCastException("The feature '" + eStructuralFeature.getName() + "'s type '" +
+// eStructuralFeature.getEType().getName() + "' does not permit a value of type '" + valueClass +
+// "'");
+// }
+// }
+ }
+
+ /** Containment Inverse Action */
+ private class ContainmentInverseAction extends InverseAction {
+
+ /** Handles inverse action, differs on the basis of the feature type */
+ @Override
+ public NotificationChain inverseAdd(InternalEObject owner, Object otherEnd, int featureID,
+ NotificationChain notifications) {
+ return inverseAdd(owner, (InternalEObject) value, featureID, notifications);
+ }
+
+ /** Handles inverse action, differs on the basis of the feature type */
+ @Override
+ public NotificationChain inverseRemove(InternalEObject owner, Object otherEnd, int featureID,
+ NotificationChain notifications) {
+ return inverseRemove(owner, (InternalEObject) value, featureID, notifications);
+ }
+
+ /** Does inverse action on other end */
+ private NotificationChain inverseAdd(InternalEObject owner, InternalEObject otherEnd, int featureID,
+ NotificationChain notifications) {
+ if (otherEnd != null) {
+ int containmentFeatureID = owner.eClass().getFeatureID(eStructuralFeature);
+ notifications =
+ otherEnd.eInverseAdd(owner, InternalEObject.EOPPOSITE_FEATURE_BASE -
+ (containmentFeatureID == -1 ? featureID : containmentFeatureID), null, notifications);
+ }
+
+ return notifications;
+ }
+
+ /** Does inverse action on other end */
+ private NotificationChain inverseRemove(InternalEObject owner, InternalEObject otherEnd, int featureID,
+ NotificationChain notifications) {
+ if (otherEnd != null) {
+ int containmentFeatureID = owner.eClass().getFeatureID(eStructuralFeature);
+ notifications =
+ otherEnd.eInverseRemove(owner, InternalEObject.EOPPOSITE_FEATURE_BASE -
+ (containmentFeatureID == -1 ? featureID : containmentFeatureID), null, notifications);
+ }
+
+ return notifications;
+ }
+ }
+
+ /** Bidirectional feature value */
+ private class BidirectionalInverseAction extends InverseAction {
+
+ /** Handles inverse action, differs on the basis of the feature type */
+ @Override
+ public NotificationChain inverseAdd(InternalEObject owner, Object otherEnd, int featureID,
+ NotificationChain notifications) {
+ return inverseAdd(owner, (InternalEObject) value, featureID, notifications);
+ }
+
+ /** Handles inverse action, differs on the basis of the feature type */
+ @Override
+ public NotificationChain inverseRemove(InternalEObject owner, Object otherEnd, int featureID,
+ NotificationChain notifications) {
+ return inverseRemove(owner, (InternalEObject) value, featureID, notifications);
+ }
+
+ /** Does inverse action on other end */
+ private final NotificationChain inverseAdd(InternalEObject owner, InternalEObject otherEnd, int featureID,
+ NotificationChain notifications) {
+ if (otherEnd != null) {
+ notifications =
+ otherEnd.eInverseAdd(owner, otherEnd.eClass().getFeatureID(
+ ((EReference) eStructuralFeature).getEOpposite()), null, notifications);
+ }
+
+ return notifications;
+ }
+
+ /** Does inverse action on other end */
+ private final NotificationChain inverseRemove(InternalEObject owner, InternalEObject otherEnd, int featureID,
+ NotificationChain notifications) {
+ if (otherEnd != null) {
+ notifications =
+ otherEnd.eInverseRemove(owner, otherEnd.eClass().getFeatureID(
+ ((EReference) eStructuralFeature).getEOpposite()), null, notifications);
+ }
+ return notifications;
+ }
+ }
+} \ No newline at end of file
diff --git a/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/type/MixedFeatureMapEntry.java b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/type/MixedFeatureMapEntry.java
new file mode 100755
index 000000000..b35b99eb8
--- /dev/null
+++ b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/type/MixedFeatureMapEntry.java
@@ -0,0 +1,80 @@
+/**
+ * <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: MixedFeatureMapEntry.java,v 1.7 2009/03/30 07:53:05 mtaal Exp $
+ */
+
+package org.eclipse.emf.teneo.type;
+
+import org.eclipse.emf.ecore.EStructuralFeature;
+import org.eclipse.emf.teneo.Constants;
+
+/**
+ * Is a specific EMF feature map for handling mixed content. Mixed content is content which consists
+ * of normal nodes and other content. The other content supported here is text, cdata and comment.
+ *
+ * @author <a href="mailto:mtaal@elver.org">Martin Taal</a>
+ * @version $Revision: 1.7 $
+ */
+
+public abstract class MixedFeatureMapEntry extends FeatureMapEntry {
+ private static final long serialVersionUID = 1L;
+
+ /** Constant used to encode the TEXT feature in the db. */
+ static final String TEXT_FEATURE_DBID = "TEXT";
+
+ /** Constant used to encode the CDATA feature in the db. */
+ static final String CDATA_FEATURE_DBID = "CDATA";
+
+ /** Constant used to encode the COMMENT feature in the db. */
+ static final String COMMENT_FEATURE_DBID = "COMMENT";
+
+ /** Overridden to encode the TEXT, CDATA or COMMENT structural features */
+ @Override
+ protected String createStructuralFeatureDBID() {
+ final EStructuralFeature structuralFeature = getEStructuralFeature();
+
+ if (structuralFeature == Constants.TEXT) {
+ return TEXT_FEATURE_DBID;
+ } else if (structuralFeature == Constants.CDATA) {
+ return CDATA_FEATURE_DBID;
+ } else if (structuralFeature == Constants.COMMENT) {
+ return COMMENT_FEATURE_DBID;
+ }
+ return super.createStructuralFeatureDBID();
+ }
+
+ /** Gets a structuralfeature on the basis of the passed id */
+ @Override
+ protected EStructuralFeature retrieveStructuralFeature(String dbid) {
+ if (TEXT_FEATURE_DBID.compareTo(dbid) == 0) {
+ return Constants.TEXT;
+ }
+ if (CDATA_FEATURE_DBID.compareTo(dbid) == 0) {
+ return Constants.CDATA;
+ }
+ if (COMMENT_FEATURE_DBID.compareTo(dbid) == 0) {
+ return Constants.COMMENT;
+ }
+
+ return super.retrieveStructuralFeature(dbid);
+ }
+
+ /** Returns true if the feature is a TEXT, CDATA or COMMENT */
+ protected boolean isMixedFeature() {
+ final EStructuralFeature structuralFeature = getEStructuralFeature();
+ return structuralFeature == Constants.TEXT || structuralFeature == Constants.CDATA ||
+ structuralFeature == Constants.COMMENT;
+ }
+} \ No newline at end of file
diff --git a/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/type/PersistentStoreAdapter.java b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/type/PersistentStoreAdapter.java
new file mode 100644
index 000000000..2c8525cc3
--- /dev/null
+++ b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/type/PersistentStoreAdapter.java
@@ -0,0 +1,280 @@
+/**
+ * <copyright>
+ *
+ * Copyright (c) 2009 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: PersistentStoreAdapter.java,v 1.15 2011/02/21 04:43:18 mtaal Exp $
+ */
+
+package org.eclipse.emf.teneo.type;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.emf.common.notify.Adapter;
+import org.eclipse.emf.common.notify.Notification;
+import org.eclipse.emf.common.notify.Notifier;
+import org.eclipse.emf.ecore.EReference;
+import org.eclipse.emf.ecore.EStructuralFeature;
+import org.eclipse.emf.teneo.util.StoreUtil;
+
+/**
+ * Keeps a list of PersistentLists by efeature. Is used when a new object is
+ * persisted and the OR-layer wants to replace the list implementation.
+ *
+ * This adapter keeps the PersistentList and ensures that any updates in the
+ * original list are also done in the persistent store.
+ *
+ * This adapter only operates in case the target object is not read from the
+ * persistent store but is persisted there for the first time.
+ *
+ * @author <a href="mailto:mtaal@elver.org">Martin Taal</a>
+ * @version $Revision: 1.15 $
+ */
+
+public class PersistentStoreAdapter implements Adapter {
+ private static final long serialVersionUID = 1L;
+
+ private Notifier target;
+ private boolean targetCreatedByORM;
+
+ private Map<EStructuralFeature, Object> storeCollections = new HashMap<EStructuralFeature, Object>();
+
+ private Map<String, Object> syntheticProperties = new HashMap<String, Object>();
+
+ public void addStoreCollection(EStructuralFeature eFeature,
+ Object storeCollection) {
+ // note that when refresh is called on a persisted object
+ // then this call replaces the current collection
+ storeCollections.put(eFeature, storeCollection);
+ }
+
+ public Object getStoreCollection(EStructuralFeature eFeature) {
+ return storeCollections.get(eFeature);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.emf.common.notify.Adapter#getTarget()
+ */
+ public Notifier getTarget() {
+ return target;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * org.eclipse.emf.common.notify.Adapter#isAdapterForType(java.lang.Object)
+ */
+ public boolean isAdapterForType(Object type) {
+ return false;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * org.eclipse.emf.common.notify.Adapter#notifyChanged(org.eclipse.emf.common
+ * .notify.Notification)
+ */
+ @SuppressWarnings("unchecked")
+ public void notifyChanged(Notification notification) {
+ final EStructuralFeature eFeature = (EStructuralFeature) notification
+ .getFeature();
+
+ final Object collectionObject = storeCollections.get(eFeature);
+ if (collectionObject == null) {
+ return;
+ }
+
+ final List<Object> list = (collectionObject instanceof List ? (List<Object>) collectionObject
+ : null);
+ final Map<Object, Object> map = (collectionObject instanceof Map<?, ?> ? (Map<Object, Object>) collectionObject
+ : null);
+
+ final boolean isEReference = eFeature instanceof EReference;
+ int changedPosition = -1;
+ switch (notification.getEventType()) {
+ case Notification.ADD:
+ if (list != null) {
+ if (notification.getPosition() != Notification.NO_INDEX) {
+ changedPosition = notification.getPosition();
+ list.add(notification.getPosition(),
+ replaceValue(notification.getNewValue(), eFeature));
+ } else {
+ changedPosition = list.size();
+ list.add(replaceValue(notification.getNewValue(), eFeature));
+ }
+ }
+ if (map != null) {
+ final Map.Entry<?, ?> entry = (Map.Entry<?, ?>) notification
+ .getNewValue();
+ map.put(entry.getKey(), entry.getValue());
+ }
+ break;
+ case Notification.ADD_MANY:
+ if (list != null) {
+ if (notification.getPosition() != Notification.NO_INDEX) {
+ changedPosition = notification.getPosition();
+ list.addAll(
+ notification.getPosition(),
+ replaceValues(
+ (List<Object>) notification.getNewValue(),
+ eFeature));
+
+ } else {
+ changedPosition = list.size();
+ list.addAll(replaceValues(
+ (List<Object>) notification.getNewValue(), eFeature));
+ }
+ }
+ if (map != null) {
+ for (Object o : (List<?>) notification.getNewValue()) {
+ final Map.Entry<?, ?> entry = (Map.Entry<?, ?>) o;
+ map.put(entry.getKey(), entry.getValue());
+ }
+ }
+ break;
+ case Notification.REMOVE:
+ if (list != null) {
+ final Object removed;
+ if (notification.getPosition() != Notification.NO_INDEX) {
+ removed = list.remove(notification.getPosition());
+ } else {
+ removed = replaceValue(notification.getOldValue(), eFeature);
+ list.remove(removed);
+ }
+ // recompute them all
+ changedPosition = 0;
+ if (isEReference) {
+ StoreUtil.resetSyntheticListInfo(eFeature, removed);
+ }
+ }
+ if (map != null) {
+ final Map.Entry<?, ?> entry = (Map.Entry<?, ?>) notification
+ .getOldValue();
+ map.remove(entry.getKey());
+ }
+ break;
+ case Notification.REMOVE_MANY:
+ if (list != null) {
+ final List<?> removed = replaceValues(
+ (List<Object>) notification.getOldValue(), eFeature);
+ list.removeAll(removed);
+ if (isEReference) {
+ for (Object removedObject : removed) {
+ StoreUtil.resetSyntheticListInfo(eFeature,
+ removedObject);
+ }
+ }
+ changedPosition = 0;
+ }
+ if (map != null) {
+ for (Object o : (List<?>) notification.getOldValue()) {
+ final Map.Entry<?, ?> entry = (Map.Entry<?, ?>) o;
+ map.remove(entry.getKey());
+ }
+ }
+ break;
+ case Notification.MOVE:
+ if (list != null) {
+ final int oldPosition = (Integer) notification.getOldValue();
+ final int newPosition = notification.getPosition();
+ final Object o = list.remove(oldPosition);
+ if (o != notification.getNewValue()) {
+ throw new IllegalStateException(
+ "Persistent list and EList are out of sync");
+ }
+ list.add(newPosition, o);
+ if (newPosition < oldPosition) {
+ changedPosition = newPosition;
+ } else {
+ changedPosition = oldPosition;
+ }
+ }
+ break;
+ case Notification.SET:
+ if (list != null) {
+ final int position = notification.getPosition();
+ Object removed = list.set(position,
+ replaceValue(notification.getNewValue(), eFeature));
+ changedPosition = position;
+ if (isEReference) {
+ StoreUtil.resetSyntheticListInfo(eFeature, removed);
+ }
+ }
+ break;
+ }
+
+ if (changedPosition > -1 && isEReference) {
+ int newIndex = changedPosition;
+ for (Object element : list.subList(changedPosition, list.size())) {
+ StoreUtil.setSyntheticListOwner(eFeature, element,
+ notification.getNotifier());
+ StoreUtil.setSyntheticListIndex(eFeature, element, newIndex++);
+ }
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * org.eclipse.emf.common.notify.Adapter#setTarget(org.eclipse.emf.common
+ * .notify.Notifier)
+ */
+ public void setTarget(Notifier newTarget) {
+ target = newTarget;
+ }
+
+ /**
+ * @return the targetCreatedByORM
+ */
+ public boolean isTargetCreatedByORM() {
+ return targetCreatedByORM;
+ }
+
+ /**
+ * @param targetCreatedByORM
+ * the targetCreatedByORM to set
+ */
+ public void setTargetCreatedByORM(boolean targetCreatedByORM) {
+ this.targetCreatedByORM = targetCreatedByORM;
+ }
+
+ /**
+ * @return the storeCollections
+ */
+ public Map<EStructuralFeature, Object> getStoreCollections() {
+ return storeCollections;
+ }
+
+ protected Object replaceValue(Object value, EStructuralFeature eFeature) {
+ return value;
+ }
+
+ protected List<Object> replaceValues(List<Object> values,
+ EStructuralFeature eFeature) {
+ return values;
+ }
+
+ public Object getSyntheticProperty(String property) {
+ return syntheticProperties.get(property);
+ }
+
+ public void setSyntheticProperty(String property, Object value) {
+ syntheticProperties.put(property, value);
+ }
+} \ No newline at end of file
diff --git a/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/util/AssertUtil.java b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/util/AssertUtil.java
new file mode 100755
index 000000000..0fc384050
--- /dev/null
+++ b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/util/AssertUtil.java
@@ -0,0 +1,100 @@
+/**
+ * <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: AssertUtil.java,v 1.7 2009/03/30 07:53:04 mtaal Exp $
+ */
+
+package org.eclipse.emf.teneo.util;
+
+import org.eclipse.emf.ecore.EObject;
+
+/**
+ * Contains utility methods for assertions
+ *
+ * @author <a href="mailto:mtaal@elver.org">Martin Taal</a>
+ * @version $Revision: 1.7 $
+ */
+
+public class AssertUtil {
+ /** AssertTrue with message */
+ public static void assertTrue(String msg, boolean value) {
+ if (!value) {
+ throw new AssertionError(msg);
+ }
+ }
+
+ /** Same resource check */
+ public static void assertResource(EObject obj1, EObject obj2) {
+ if (obj1.eResource() == null && ((EObject) obj2).eResource() == null) return;
+ if (obj1.eResource() != ((EObject) obj2).eResource()) {
+ throw new AssertionError("The resources are different: " + obj1.getClass().getName() + "/" +
+ obj2.getClass().getName());
+ }
+ }
+
+ /** Checks for correct container relations */
+ public static void assertContainer(EObject parent, EObject child) {
+ if (parent != child.eContainer()) {
+ throw new AssertionError("The child's container is incorrect! parent/child: " +
+ parent.getClass().getName() + "/" + child.getClass().getName());
+ }
+ }
+
+ /** Asserts that the passed entry is null */
+ public static void assertIsNull(Object obj) {
+ if (obj != null) {
+ throw new AssertionError("Passed object: " + obj.getClass().getName() +
+ " is not null while this was expected");
+ }
+ }
+
+ /**
+ * Checks if the passed object is of the class specified, null values are ignored
+ */
+ public static void assertInstanceOf(Object obj, Class<?> expClass) {
+ if (obj == null) return;
+ if (!(expClass.isAssignableFrom(obj.getClass()))) {
+ throw new AssertionError("Expected class: " + expClass.getName() + " but object has class: " +
+ obj.getClass().getName());
+ }
+ }
+
+ /**
+ * Checks if the passed object is of the class specified, null values throw an exception
+ */
+ public static void assertInstanceOfNotNull(Object obj, Class<?> expClass) {
+ if (obj == null) {
+ throw new AssertionError("Checking instanceof but object is null, expecting class: " + expClass.getName());
+ }
+ if (!(expClass.isAssignableFrom(obj.getClass()))) {
+ throw new AssertionError("Expected class: " + expClass.getName() + " but object has class: " +
+ obj.getClass().getName());
+ }
+ }
+
+ /** Checks object memory equality */
+ public static void assertSameObject(Object obj1, Object obj2) {
+ if (obj1 != obj2) {
+ throw new AssertionError("Objects are not the same");
+ }
+ }
+
+ /** Checks object memory inequality */
+ public static void assertNotSameObject(Object obj1, Object obj2) {
+ if (obj1 == obj2) {
+ throw new AssertionError("Objects are the same");
+ }
+ }
+
+} \ No newline at end of file
diff --git a/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/util/EcoreDataTypes.java b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/util/EcoreDataTypes.java
new file mode 100755
index 000000000..69e5ae6d2
--- /dev/null
+++ b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/util/EcoreDataTypes.java
@@ -0,0 +1,435 @@
+/**
+ * <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
+ * Brian Vetter (bugzilla 175909)
+ * Alexandros Karypidis (bugzilla 207799)
+ * </copyright>
+ *
+ * $Id: EcoreDataTypes.java,v 1.17 2011/03/17 09:21:31 mtaal Exp $
+ */
+
+package org.eclipse.emf.teneo.util;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Calendar;
+import java.util.Collections;
+import java.util.Date;
+import java.util.List;
+
+import javax.xml.datatype.DatatypeConfigurationException;
+import javax.xml.datatype.DatatypeFactory;
+import javax.xml.datatype.XMLGregorianCalendar;
+
+import org.eclipse.emf.ecore.EAnnotation;
+import org.eclipse.emf.ecore.EAttribute;
+import org.eclipse.emf.ecore.EClassifier;
+import org.eclipse.emf.ecore.EDataType;
+import org.eclipse.emf.ecore.EEnum;
+import org.eclipse.emf.ecore.EModelElement;
+import org.eclipse.emf.ecore.EPackage;
+import org.eclipse.emf.ecore.EcorePackage;
+import org.eclipse.emf.ecore.xml.type.XMLTypePackage;
+import org.eclipse.emf.teneo.PersistenceOptions;
+import org.eclipse.emf.teneo.TeneoException;
+import org.eclipse.emf.teneo.annotations.pamodel.PAnnotatedEAttribute;
+
+/**
+ * Utility class to classify Ecore datatypes.
+ *
+ * @author <a href="mailto:marchign at elver.org">Davide Marchignoli</a>
+ */
+public class EcoreDataTypes {
+
+ // The xml types
+ private static XMLTypePackage xmlTypePackage = XMLTypePackage.eINSTANCE;
+ private static EDataType xmlDateEDataType = xmlTypePackage.getDate();
+ private static EDataType xmlDateTimeEDataType = xmlTypePackage
+ .getDateTime();
+ private static EDataType xmlTimeEDataType = xmlTypePackage.getTime();
+
+ // The source of the annotations of extended metadata used by emf
+ private static final String ANNOTATION_SOURCE_METADATA = "http:///org/eclipse/emf/ecore/util/ExtendedMetaData";
+
+ // XML datatype factory instance
+ private final DatatypeFactory dataTypeFactory;
+
+ private static final List<EDataType> PRIMITIVES_ETYPES_LIST = Collections
+ .unmodifiableList(Arrays.asList(new EDataType[] {
+ EcorePackage.eINSTANCE.getEBoolean(),
+ EcorePackage.eINSTANCE.getEByte(),
+ EcorePackage.eINSTANCE.getEChar(),
+ EcorePackage.eINSTANCE.getEDouble(),
+ EcorePackage.eINSTANCE.getEFloat(),
+ EcorePackage.eINSTANCE.getEInt(),
+ EcorePackage.eINSTANCE.getELong(),
+ EcorePackage.eINSTANCE.getEShort(), }));
+
+ private static final List<Class<?>> PRIMITIVE_OBJECT_TYPE_LIST = Collections
+ .unmodifiableList(Arrays.asList(new Class<?>[] {
+ java.lang.Boolean.class, java.lang.Byte.class,
+ java.lang.Double.class, java.lang.Float.class,
+ java.lang.Integer.class, java.lang.Long.class,
+ java.math.BigDecimal.class, java.math.BigInteger.class }));
+
+ private static final List<EDataType> WRAPPERS_ETYPES_LIST = Collections
+ .unmodifiableList(Arrays.asList(new EDataType[] {
+ EcorePackage.eINSTANCE.getEBooleanObject(),
+ EcorePackage.eINSTANCE.getEByteObject(),
+ EcorePackage.eINSTANCE.getECharacterObject(),
+ EcorePackage.eINSTANCE.getEDoubleObject(),
+ EcorePackage.eINSTANCE.getEFloatObject(),
+ EcorePackage.eINSTANCE.getEIntegerObject(),
+ EcorePackage.eINSTANCE.getELongObject(),
+ EcorePackage.eINSTANCE.getEShortObject(), }));
+
+ public static EcoreDataTypes INSTANCE = new EcoreDataTypes();
+
+ private EcoreDataTypes() {
+ try {
+ dataTypeFactory = DatatypeFactory.newInstance();
+ } catch (DatatypeConfigurationException e) {
+ throw new TeneoException("Exception ", e);
+ }
+ }
+
+ /** Returns the type name of a many attribute */
+ public String getTargetTypeName(PAnnotatedEAttribute aAttribute) {
+ final EAttribute eAttribute = aAttribute.getModelEAttribute();
+ // check on equality on object.class is used for listunion simpleunions
+ final Class<?> instanceClass = eAttribute.getEAttributeType()
+ .getInstanceClass();
+ if (instanceClass != null && !Object.class.equals(instanceClass)
+ && !List.class.equals(instanceClass)) {
+ if (instanceClass.isArray()) {
+ // get rid of the [] at the end
+ return eAttribute
+ .getEType()
+ .getInstanceClassName()
+ .substring(
+ 0,
+ eAttribute.getEType().getInstanceClassName()
+ .length() - 2);
+ }
+ return instanceClass.getName();
+ }
+ // the type is hidden somewhere deep get it
+ // the edatatype is the java.util.list
+ // it has an itemType which is the name of the element edatatype
+ // which contains the instanceclass
+ // takes also into account inheritance between datatypes
+ // NOTE the otm.targetentity can consist of a comma delimited list
+ // of target
+ // entities this is required for listunion types but is not
+ // according to the ejb3 spec!
+ ArrayList<EClassifier> eclassifiers = getItemTypes((EDataType) eAttribute
+ .getEType());
+ if (eclassifiers.size() > 0) {
+ StringBuffer result = new StringBuffer();
+ for (int i = 0; i < eclassifiers.size(); i++) {
+ final EClassifier eclassifier = eclassifiers.get(i);
+ if (i > 0) {
+ result.append(",");
+ }
+ result.append(eclassifier.getInstanceClassName());
+ }
+ return result.toString();
+ }
+ return Object.class.getName();
+ }
+
+ /** Walks up a edatatype inheritance structure to find the itemType */
+ public ArrayList<EClassifier> getItemTypes(EDataType eDataType) {
+ final ArrayList<EClassifier> result = new ArrayList<EClassifier>();
+ if (eDataType == null) {
+ return result;
+ }
+ final String itemType = getEAnnotationValue(eDataType,
+ ANNOTATION_SOURCE_METADATA, "itemType");
+ if (itemType != null) {
+ final EClassifier eClassifier = getEClassifier(
+ eDataType.getEPackage(), itemType);
+ if (eClassifier != null) {
+ result.add(eClassifier);
+ }
+
+ return result;
+ }
+
+ final String memberTypes = getEAnnotationValue(eDataType,
+ ANNOTATION_SOURCE_METADATA, "memberTypes");
+ if (memberTypes != null) {
+ String[] mtypes = memberTypes.split(" ");
+ for (String element : mtypes) {
+ final EClassifier eclassifier = getEClassifier(
+ eDataType.getEPackage(), element);
+ if (eclassifier != null) {
+ result.addAll(getItemTypes((EDataType) eclassifier));
+ }
+ }
+ return result;
+ }
+
+ final String baseType = getEAnnotationValue(eDataType,
+ ANNOTATION_SOURCE_METADATA, "baseType");
+ if (baseType != null) {
+ final EClassifier eClassifier = getEClassifier(
+ eDataType.getEPackage(), baseType);
+ if (eClassifier != null) {
+ final ArrayList<EClassifier> tmpResult = getItemTypes((EDataType) eClassifier);
+ if (tmpResult.size() > 0) {
+ result.addAll(tmpResult);
+ return result;
+ }
+ }
+ }
+ if (!Object.class.equals(eDataType.getInstanceClass())) {
+ result.add(eDataType);
+ }
+ return result;
+ }
+
+ /**
+ * Returns the eclassifier using either the name of the eclassifier or the
+ * name element
+ */
+ public EClassifier getEClassifier(EPackage epackage, String searchName) {
+ for (EClassifier eclassifier : epackage.getEClassifiers()) {
+ if (eclassifier.getName().compareTo(searchName) == 0) {
+ return eclassifier;
+ }
+ String nameAnnotation = getEAnnotationValue(eclassifier,
+ ANNOTATION_SOURCE_METADATA, "name");
+ if (nameAnnotation != null
+ && searchName.compareTo(nameAnnotation) == 0) {
+ return eclassifier;
+ }
+ }
+ return null;
+ }
+
+ /** Returns the value of an annotation with a certain key */
+ public String getEAnnotationValue(EModelElement eModelElement,
+ String source, String key) {
+ final EAnnotation eAnnotation = eModelElement.getEAnnotation(source);
+ if (eAnnotation == null) {
+ return null;
+ }
+ return eAnnotation.getDetails().get(key);
+ }
+
+ // TODO: Make all utility methods static.
+
+ /** Return a XMLGregorianCalendar on the basis of the date */
+ public XMLGregorianCalendar getXMLGregorianCalendar(Date date) {
+ final XMLGregorianCalendar gregCalendar = dataTypeFactory
+ .newXMLGregorianCalendar();
+ final Calendar calendar = Calendar.getInstance();
+ calendar.setTime(date);
+ gregCalendar.setYear(calendar.get(Calendar.YEAR));
+ gregCalendar.setMonth(calendar.get(Calendar.MONTH) + 1); // note the
+ // correction
+ // with 1
+ gregCalendar.setDay(calendar.get(Calendar.DAY_OF_MONTH));
+ return gregCalendar;
+ }
+
+ /** Return a XMLGregorianCalendar on datetime level (milliseconds) */
+ public XMLGregorianCalendar getXMLGregorianCalendarDateTime(Date date) {
+ final XMLGregorianCalendar gregCalendar = dataTypeFactory
+ .newXMLGregorianCalendar();
+ final Calendar calendar = Calendar.getInstance();
+ calendar.setTime(date);
+ gregCalendar.setYear(calendar.get(Calendar.YEAR));
+ gregCalendar.setMonth(calendar.get(Calendar.MONTH) + 1); // correct with
+ // 1 on
+ // purpose
+ gregCalendar.setDay(calendar.get(Calendar.DAY_OF_MONTH));
+ gregCalendar.setHour(calendar.get(Calendar.HOUR_OF_DAY));
+ gregCalendar.setMinute(calendar.get(Calendar.MINUTE));
+ gregCalendar.setSecond(calendar.get(Calendar.SECOND));
+ gregCalendar.setMillisecond(calendar.get(Calendar.MILLISECOND));
+ return gregCalendar;
+ }
+
+ /**
+ * @return Returns an immutable list of the Ecore EDataType for java
+ * primitives.
+ */
+ public List<EDataType> getEPrimitives() {
+ return PRIMITIVES_ETYPES_LIST;
+ }
+
+ /**
+ * @return Returns true if and only if the the given eDataType is the Ecore
+ * EDataType for a primitive type.
+ */
+ public boolean isEPrimitive(EDataType eDataType) {
+ return eDataType != null && isPrimitive(eDataType.getInstanceClass());
+ }
+
+ public boolean isPrimitive(Class<?> clz) {
+ if (clz == null) {
+ return false;
+ }
+ return clz.isPrimitive() || PRIMITIVE_OBJECT_TYPE_LIST.contains(clz);
+ }
+
+ /**
+ * @return Returns an immutable list of the Ecore EDataType for java
+ * primitive wrapper classes.
+ */
+ public List<EDataType> getEWrappers() {
+ return WRAPPERS_ETYPES_LIST;
+ }
+
+ /**
+ * @return Returns true if and only if the the given eDataType is the Ecore
+ * EDataType for a primitive wrapper class.
+ */
+ public boolean isEWrapper(EDataType eDataType) {
+ return WRAPPERS_ETYPES_LIST.contains(eDataType);
+ }
+
+ /**
+ * @return true if and only if the given dataType is a string datatype.
+ */
+ public boolean isEString(EDataType eDataType) {
+ // should be eDataType == EString but does not work due to XML type
+ // implementations
+ return String.class == eDataType.getInstanceClass();
+ }
+
+ public boolean isEDuration(EDataType eDataType) {
+ String className = null;
+ if (eDataType.getInstanceClassName() != null) {
+ className = eDataType.getInstanceClassName();
+ } else if (eDataType.getInstanceClass() != null) {
+ className = eDataType.getInstanceClass().getName();
+ } else {
+ return false;
+ }
+ return className.compareTo("javax.xml.datatype.Duration") == 0;
+ }
+
+ /**
+ * - *
+ *
+ * @return true if and only if the given dataType is a date datatype.
+ */
+ public boolean isEDate(EDataType eDataType, PersistenceOptions po) {
+ if (eDataType.equals(xmlDateEDataType)) {
+ return true;
+ }
+ /*
+ * There is some ambiguity around the Java Date class since it can also
+ * hold time - a conflict with the DateTime class
+ */
+ Class<?> ic = eDataType.getInstanceClass();
+ // do a string comparison to prevent another dependency for this teneo
+ // library.
+ if (eDataType.getInstanceClassName() != null
+ && eDataType.getInstanceClassName().compareTo(
+ po.getXSDDateClass()) == 0) {
+ return true;
+ }
+ return java.util.Date.class == ic || java.util.Calendar.class == ic
+ || java.sql.Date.class == ic;
+ }
+
+ /**
+ * @return true if and only if the given dataType is a datetime/timestamp
+ * datatype.
+ */
+ public boolean isETime(EDataType eDataType) {
+ if (eDataType.equals(xmlTimeEDataType)) {
+ return true;
+ }
+ /*
+ * the InstanceClass for date type can be "Object" for XSD types. I'm
+ * not sure about ecore itself so I have kept the original check against
+ * the java classes.
+ */
+ Class<?> ic = eDataType.getInstanceClass();
+ // already handled through the first if
+ // if (ic == Object.class) {
+ // // could be an XML date type
+ // return eDataType.equals(xmlDateTimeEDataType);
+ // }
+ return java.sql.Timestamp.class == ic || Date.class == ic;
+ }
+
+ /**
+ * @return true if and only if the given dataType is a datetime/timestamp
+ * datatype.
+ */
+ public boolean isEDateTime(EDataType eDataType) {
+ if (eDataType.equals(xmlDateTimeEDataType)) {
+ return true;
+ }
+ /*
+ * the InstanceClass for date type can be "Object" for XSD types. I'm
+ * not sure about ecore itself so I have kept the original check against
+ * the java classes.
+ */
+ Class<?> ic = eDataType.getInstanceClass();
+ // already handled through the first if
+ // if (ic == Object.class) {
+ // // could be an XML date type
+ // return eDataType.equals(xmlDateTimeEDataType);
+ // }
+ return java.sql.Timestamp.class == ic || Date.class == ic;
+ }
+
+ /**
+ * @return Returns true if and only if the given type is either a primitive
+ * or a wrapper or string or a date.
+ */
+ public boolean isSimpleType(EDataType eType, PersistenceOptions po) {
+ // TODO move elsewhere
+ return isEPrimitive(eType) || isEWrapper(eType) || isEString(eType)
+ || isEDate(eType, po) || isEDateTime(eType);
+ }
+
+ /**
+ * EJB3-SPEC 9.1.16
+ *
+ * @return Returns true if the given eDataType is a Basic type
+ */
+ public boolean isBasicType(EDataType eDataType, PersistenceOptions po) {
+ // TODO consider also BigInteger, BigDecimal, java.util.Calendar,
+ // java.sql.Date
+ // java.sql.Time, java.sql.Timestamp, byte[], Byte[], char[],
+ // Character[]
+ // and any other type that implements Serializable
+ return isSimpleType(eDataType, po) || isEnum(eDataType);
+ }
+
+ /**
+ * @return Returns true if the given EDataType is an Ecore enumerated type.
+ */
+ public boolean isEnum(EClassifier eClassifier) {
+ return (eClassifier instanceof EEnum);
+ }
+
+ /**
+ * @return true if the eType is a byte array.
+ */
+ public boolean isByteArray(EDataType eType) {
+ final Class<?> clazz = eType.getInstanceClass();
+ if (clazz != null) {
+ return (clazz.isArray() && clazz.getComponentType().equals(
+ Byte.TYPE));
+ }
+ return false;
+ }
+}
diff --git a/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/util/FieldUtil.java b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/util/FieldUtil.java
new file mode 100755
index 000000000..f4e2e1fbf
--- /dev/null
+++ b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/util/FieldUtil.java
@@ -0,0 +1,174 @@
+/**
+ * <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: FieldUtil.java,v 1.18 2009/07/31 00:38:16 mtaal Exp $
+ */
+
+package org.eclipse.emf.teneo.util;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.util.Hashtable;
+
+import org.eclipse.emf.teneo.TeneoException;
+
+/**
+ * Contains different util methods.
+ *
+ * @author <a href="mailto:mtaal@elver.org">Martin Taal</a>
+ * @version $Revision: 1.18 $
+ */
+
+public class FieldUtil {
+ /** The hashtable caches clazz field name combinations */
+ private static final Hashtable<String, Object> fieldMethodCache = new Hashtable<String, Object>();
+
+ /** Sets a field and wraps the exceptions */
+ public static Object callMethod(Object obj, String methodName, Object[] params) {
+ Method method = (Method) fieldMethodCache.get(obj.getClass().getName() + "." + methodName);
+
+ try {
+ if (method == null) {
+ method = getMethodInternal(obj.getClass(), methodName, (params == null ? 0 : params.length));
+ }
+ if (method != null) {
+ fieldMethodCache.put(obj.getClass().getName() + "." + methodName + "."
+ + (params == null ? 0 : params.length), method);
+ } else {
+ throw new TeneoException("Method does not exist " + obj.getClass().getName() + " method; ");
+ }
+
+ return method.invoke(obj, params);
+ } catch (Exception e) {
+ final StringBuffer paramStr = new StringBuffer();
+ if (params != null) {
+ for (Object param : params) {
+ paramStr.append(" - " + param + " (" + param.getClass().getName() + ")");
+ }
+ }
+
+ throw new TeneoException("Exception " + obj.getClass().getName() + " method; " + methodName
+ + " with parameters: " + paramStr.toString(), e);
+ }
+ }
+
+ /** Sets a field and wraps the exceptions */
+ public static void setField(Field field, Object obj, Object value) {
+ try {
+ field.set(obj, value);
+ } catch (IllegalAccessException e) {
+ throw new TeneoException("IllegalAccessException " + obj.getClass().getName() + " field; "
+ + field.getName());
+ }
+ }
+
+ /**
+ * Get the value for a field, first the field is accessed directly if not found then the getter is called.
+ */
+ public static Object callGetter(Object target, String fieldName) {
+ try {
+ Method method = getMethodInternal(target.getClass(), "get" + fieldName, 0);
+ if (method == null) {
+ method = getMethodInternal(target.getClass(), "is" + fieldName, 0);
+ }
+ if (method == null) {
+ final Field field = getField(target.getClass(), fieldName);
+ return field.get(target);
+ }
+ return callMethod(target, method.getName(), new Object[0]);
+ } catch (Exception e) {
+ throw new TeneoException("Exception getting " + fieldName + " from " + target.getClass().getName(), e);
+ }
+ }
+
+ /** Set the field directly or through the set method */
+ public static void callSetter(Object target, String fieldName, Object value) {
+ try {
+ final Method method = getMethodInternal(target.getClass(), "get" + fieldName, 1);
+ if (method != null) {
+ callMethod(target, "set" + fieldName, new Object[] { value });
+ return;
+ }
+ final Field field = getField(target.getClass(), fieldName);
+ field.set(target, value);
+ } catch (Exception e) {
+ throw new TeneoException("Exception setting " + fieldName + " from " + target.getClass().getName()
+ + " to value " + value + " of type " + (value != null ? value.getClass().getName() : ""), e);
+ }
+ }
+
+ /**
+ * Returns a field using a certain name, walks up the class hierarchy to find the field, will make the field
+ * accessible also. Is a bit rough because it does a case insensitive search. Note if the field is not found an
+ * exception is thrown.
+ */
+ public static Field getField(Class<?> clazz, String fieldName) {
+ Field field = (Field) fieldMethodCache.get(clazz.getName() + "." + fieldName);
+
+ if (field != null) {
+ return field;
+ }
+
+ try {
+ field = getFieldInternal(clazz, fieldName);
+ if (field == null) {
+ field = getFieldInternal(clazz, fieldName + "_"); // the way
+ // emf
+ // escapes
+ // fields
+ }
+ } catch (Exception e) // todo replace with specific exception
+ {
+ throw new TeneoException("Field " + fieldName + " not accessible for class: " + clazz.getName(), e);
+ }
+ if (field == null) {
+ return null;
+ }
+
+ fieldMethodCache.put(clazz.getName() + "." + fieldName, field);
+ field.setAccessible(true);
+ return field;
+ }
+
+ /** Does the actual search for the field */
+ private static Field getFieldInternal(Class<?> clazz, String fieldName) throws Exception {
+ if (clazz == null) {
+ return null;
+ }
+
+ final Field[] fields = clazz.getDeclaredFields();
+ for (Field element : fields) {
+ if (element.getName().compareToIgnoreCase(fieldName) == 0) {
+ element.setAccessible(true);
+ return element;
+ }
+ }
+
+ return getFieldInternal(clazz.getSuperclass(), fieldName);
+ }
+
+ /** Does the actual search for the method */
+ private static Method getMethodInternal(Class<?> clazz, String methodName, int numOfParams) throws Exception {
+ if (clazz == null) {
+ return null;
+ }
+
+ final Method method = (Method) fieldMethodCache.get(clazz.getName() + "." + methodName);
+ if (method != null) {
+ return method;
+ }
+ final Method[] methods = clazz.getDeclaredMethods();
+ for (Method element : methods) {
+ if (element.getName().compareToIgnoreCase(methodName) == 0
+ && element.getParameterTypes().length == numOfParams) {
+ element.setAccessible(true);
+ fieldMethodCache.put(clazz.getName() + "." + methodName + "." + numOfParams, element);
+ return element;
+ }
+ }
+
+ return getMethodInternal(clazz.getSuperclass(), methodName, numOfParams);
+ }
+} \ No newline at end of file
diff --git a/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/util/StoreUtil.java b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/util/StoreUtil.java
new file mode 100755
index 000000000..3020b34da
--- /dev/null
+++ b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/util/StoreUtil.java
@@ -0,0 +1,665 @@
+/**
+ * <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: StoreUtil.java,v 1.31 2010/03/28 09:20:26 mtaal Exp $
+ */
+
+package org.eclipse.emf.teneo.util;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.lang.reflect.Field;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.eclipse.emf.common.notify.Adapter;
+import org.eclipse.emf.common.notify.impl.NotificationImpl;
+import org.eclipse.emf.common.util.EList;
+import org.eclipse.emf.common.util.EMap;
+import org.eclipse.emf.common.util.URI;
+import org.eclipse.emf.ecore.EAnnotation;
+import org.eclipse.emf.ecore.EAttribute;
+import org.eclipse.emf.ecore.EClass;
+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.impl.EStoreEObjectImpl;
+import org.eclipse.emf.ecore.impl.EStoreEObjectImpl.EStoreEList;
+import org.eclipse.emf.ecore.resource.Resource;
+import org.eclipse.emf.ecore.resource.ResourceSet;
+import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl;
+import org.eclipse.emf.ecore.util.ExtendedMetaData;
+import org.eclipse.emf.ecore.util.FeatureMapUtil;
+import org.eclipse.emf.ecore.xmi.impl.EcoreResourceFactoryImpl;
+import org.eclipse.emf.ecore.xml.type.XMLTypePackage;
+import org.eclipse.emf.teneo.Constants;
+import org.eclipse.emf.teneo.PackageRegistryProvider;
+import org.eclipse.emf.teneo.TeneoException;
+import org.eclipse.emf.teneo.ecore.EModelResolver;
+import org.eclipse.emf.teneo.type.PersistentStoreAdapter;
+
+/**
+ * Contains different util methods.
+ *
+ * @author <a href="mailto:mtaal@elver.org">Martin Taal</a>
+ * @version $Revision: 1.31 $
+ */
+
+public class StoreUtil {
+
+ /** The logger */
+ private static Log log = LogFactory.getLog(StoreUtil.class);
+
+ /** Separator between package and the extension */
+ public static final char EXTENSION_SEPARATOR = '.';
+
+ /** Separator in package names */
+ private static final char PACKAGE_SEPARATOR = '.';
+
+ /**
+ * Separator between segments of an identifying strucuralfeature or edatatype path
+ */
+ public static final char PATH_SEPARATOR = '/';
+
+ /** The Annotation source name */
+ public static final String ANNOTATION_SOURCE = "http:///org/eclipse/emf/ecore/util/ExtendedMetaData";
+
+ public static void resetSyntheticListInfo(EStructuralFeature eFeature,
+ Object target) {
+ if (target == null || eFeature instanceof EAttribute) {
+ return;
+ }
+ PersistentStoreAdapter persistentStoreAdapter = StoreUtil
+ .getPersistentStoreAdapter((EObject) target);
+ persistentStoreAdapter.setSyntheticProperty(StoreUtil
+ .getExtraLazyInverseIndexPropertyName(eFeature), null);
+ persistentStoreAdapter.setSyntheticProperty(StoreUtil
+ .getExtraLazyInversePropertyName(eFeature), null);
+ }
+
+ public static void setSyntheticListIndex(EStructuralFeature eFeature,
+ Object target, Integer value) {
+ if (eFeature instanceof EAttribute) {
+ return;
+ }
+ PersistentStoreAdapter persistentStoreAdapter = StoreUtil
+ .getPersistentStoreAdapter((EObject) target);
+ persistentStoreAdapter.setSyntheticProperty(StoreUtil
+ .getExtraLazyInverseIndexPropertyName(eFeature), value);
+ }
+
+ public static void setSyntheticListOwner(EStructuralFeature eFeature,
+ Object target, Object owner) {
+ if (eFeature instanceof EAttribute) {
+ return;
+ }
+ PersistentStoreAdapter persistentStoreAdapter = StoreUtil
+ .getPersistentStoreAdapter((EObject) target);
+ persistentStoreAdapter.setSyntheticProperty(StoreUtil
+ .getExtraLazyInversePropertyName(eFeature), owner);
+ }
+
+ public static String getExtraLazyInversePropertyName(
+ EStructuralFeature eFeature) {
+ return eFeature.getEContainingClass().getName()
+ + eFeature.getName();
+ }
+
+ public static String getExtraLazyInverseIndexPropertyName(
+ EStructuralFeature eFeature) {
+ return getExtraLazyInversePropertyName(eFeature) + "idx";
+ }
+
+ /** Returns true if the passed EAttribute is a qname */
+ public static boolean isQName(EAttribute eAttribute) {
+ final EDataType eDataType = eAttribute.getEAttributeType();
+ return eDataType == XMLTypePackage.eINSTANCE.getQName();
+ }
+
+ /** Reads the epackages present in the passed ecore files. */
+ public static List<EPackage> readEPackages(String[] ecoreFiles) {
+ final ResourceSet resourceSet = new ResourceSetImpl();
+ resourceSet.getResourceFactoryRegistry().getExtensionToFactoryMap().put("*", new EcoreResourceFactoryImpl());
+ final ArrayList<EPackage> epackages = new ArrayList<EPackage>();
+ for (String element : ecoreFiles) {
+
+ log.debug("Reading ecore file: " + element);
+
+ Resource res = resourceSet.getResource(URI.createFileURI(element), true);
+
+ Iterator<EObject> it = res.getAllContents();
+ while (it.hasNext()) {
+ final EObject obj = it.next();
+ if (obj instanceof EPackage) {
+ final EPackage epack = (EPackage) obj;
+ final EPackage currentEPackage = PackageRegistryProvider.getInstance().getPackageRegistry()
+ .getEPackage(epack.getNsURI());
+ if (currentEPackage != null) { // use the existing epackage
+ if (!epackages.contains(currentEPackage)) {
+ epackages.add(currentEPackage);
+ }
+ } else {
+ PackageRegistryProvider.getInstance().getPackageRegistry().put(epack.getNsURI(), epack);
+ epackages.add(epack);
+ }
+ }
+ }
+ }
+ return epackages;
+ }
+
+ /**
+ * Returns true if the passed EStructuralFeature represents a map. Note that the method also handles EAttribute
+ * (returns false) for convenience reasons.
+ */
+ public static boolean isMap(EStructuralFeature eStructuralFeature) {
+ if (eStructuralFeature instanceof EAttribute) {
+ return false;
+ }
+ final EReference eref = (EReference) eStructuralFeature;
+ return isMapEntry(eref.getEReferenceType());
+ }
+
+ /** Same method only for an eclass */
+ public static boolean isMapEntry(EClass eclass) {
+ return eclass != null && eclass.getInstanceClass() != null
+ && Map.Entry.class.isAssignableFrom(eclass.getInstanceClass())
+ && eclass.getEStructuralFeatures().size() == 2 && eclass.getEStructuralFeature("key") != null
+ && eclass.getEStructuralFeature("value") != null;
+ }
+
+ public static boolean isEStoreList(Object o) {
+ if (o == null) {
+ return false;
+ }
+ if (o instanceof EStoreEList<?>) {
+ return true;
+ }
+ if (o instanceof EStoreEObjectImpl.BasicEStoreEList<?>) {
+ return true;
+ }
+ return false;
+ }
+
+ /** The nsprefix, eclass separator */
+ // private static final String NSPREFIX_ECLASS_SEPARATOR = ".";
+ /** Returns the name of the entity used for this feature map entry */
+ public static String getEntityName(EStructuralFeature feature) {
+ assert (FeatureMapUtil.isFeatureMap(feature));
+ return feature.getEContainingClass().getName() + "_" + feature.getName();
+ }
+
+ /** Returns a loggable string for a efeature */
+ public static String toString(EStructuralFeature efeature) {
+ if (efeature == null) {
+ return "NULL"; // possibly throw error
+ }
+ return efeature.getEContainingClass().getName() + "/" + efeature.getName();
+ }
+
+ /**
+ * Translates an ECLass to a string representation public static String getEClassURI(EClass eclass, String qualify)
+ * { if (eclass == EOBJECT_ECLASS) { return EOBJECT_ECLASS_URI; } if (qualify == null ||
+ * qualify.compareTo(PersistenceOptions.QUALIFY_ENTITY_NAME_NO) == 0) { return eclass.getName(); } else if
+ * (qualify.compareTo(PersistenceOptions.QUALIFY_ENTITY_NAME_NSPREFIX) == 0) { return
+ * eclass.getEPackage().getNsPrefix() + "." + eclass.getName(); } throw new StoreException("Qualify type " + qualify
+ * + " unknown"); } /** Returns an estructuralfeature on the basis of the name of the eclass and the name of the
+ * feature itself. public static EStructuralFeature getEStructuralFeature(String eclassURI, String featureName,
+ * EPackage[] epackages) { EClass eclass = getEClassFromURI(eclassURI, epackages); if (eclass == null) return null;
+ * return eclass.getEStructuralFeature(featureName); } /* /** Translates an eclass uri back to an eclass / public
+ * static EClass getEClassFromURI(String theEClassURI) { final Registry packageRegistry = Registry.INSTANCE; final
+ * EPackage[] epacks = new EPackage[packageRegistry.size()]; int cnt = 0; for (Iterator it =
+ * packageRegistry.values().iterator(); it.hasNext();) { final EPackage epack = (EPackage) it.next(); epacks[cnt++]
+ * = epack; } return getEClassFromURI(theEClassURI, epacks); } /** Translates an eclass uri back to an eclass /
+ * public static EClass getEClassFromURI(String theEClassURI, EPackage[] epackages, EClassNameStrategy nameStrategy)
+ * { if (theEClassURI.compareTo(EOBJECT_ECLASS_URI) == 0) { return EcorePackage.eINSTANCE.getEObject(); } String
+ * nsPrefix = null; String eClassName = theEClassURI; if (eClassName.indexOf(NSPREFIX_ECLASS_SEPARATOR) != -1) {
+ * nsPrefix = theEClassURI.substring(0, eClassName.lastIndexOf(NSPREFIX_ECLASS_SEPARATOR)); eClassName =
+ * theEClassURI.substring(1 + eClassName.lastIndexOf(NSPREFIX_ECLASS_SEPARATOR)); } ArrayList eclasses = new
+ * ArrayList(); for (int i = 0; i < epackages.length; i++) { EPackage epack = epackages[i]; if (nsPrefix != null &&
+ * epack.getNsPrefix() != null && epack.getNsPrefix().compareTo(nsPrefix) != 0) { continue; } EClassifier
+ * eclassifier = epack.getEClassifier(eClassName); if (eclassifier instanceof EClass) { eclasses.add(eclassifier); }
+ * } if (eclasses.size() == 1) { return (EClass) eclasses.get(0); } else if (eclasses.size() == 0) { return null; //
+ * throw new StoreException("The uri " + eclassURI + " can not be translated to an eclass"); } else { StringBuffer
+ * eclassList = new StringBuffer(); for (Iterator it = eclasses.iterator(); it.hasNext();) { EClass eclass =
+ * (EClass) it.next(); eclassList.append(eclass.getEPackage().getNsURI() + "/" + eclass.getName()); } throw new
+ * StoreException("The uri " + eClassName + " maps to multiple eclasses: " + eclassList.toString()); } /* int
+ * lastIndex = eclassURI.lastIndexOf(PATH_SEPARATOR); if (lastIndex == -1) { throw new
+ * StoreAnnotationsException("The uri: " + eclassURI + " has an illegal format, it can not parsed to an eclass."); }
+ * final String nsuri = eclassURI.substring(0, lastIndex); final String name = eclassURI.substring(lastIndex + 1);
+ * final EPackage epack = PackageRegistryProvider.getInstance().getPackageRegistry().getEPackage(nsuri); if (epack
+ * == null) { throw new StoreAnnotationsException("No package found for the nsuri: " + nsuri +
+ * " using the eclassURI " + eclassURI); } final EClass eclass = (EClass)epack.getEClassifier(name); if (eclass ==
+ * null) { throw new StoreAnnotationsException("The nsuri " + nsuri + " and eclassname: " + name +
+ * " does not resolve to an EClass"); } return eclass; / }
+ */
+ /** Sends out a notification of an elist load */
+ public static void dispatchEListLoadNotification(final EObject notifier, final EList<? extends EObject> elist,
+ final EStructuralFeature feature) {
+ notifier.eNotify(new NotificationImpl(Constants.ELIST_LOAD_NOTIFICATION, null, elist) {
+ @Override
+ public Object getNotifier() {
+ return notifier;
+ }
+
+ @Override
+ public Object getFeature() {
+ return feature;
+ }
+
+ @Override
+ public int getFeatureID(Class<?> expectedClass) {
+ return feature.getFeatureID();
+ }
+ });
+ }
+
+ /**
+ * Returns the string which is used to store the unique identification of this structuralfeature in the db
+ */
+ public static String structuralFeatureToString(EStructuralFeature structuralFeature) {
+ // the unique id will consist of three part: 1) package NSURI, 2) EClass
+ // Name, 3) StructuralFeature Name
+ final String nsuri = structuralFeature.getEContainingClass().getEPackage().getNsURI();
+ final String eclassName = structuralFeature.getEContainingClass().getName();
+ final String featureName = structuralFeature.getName();
+
+ return nsuri + PATH_SEPARATOR + eclassName + PATH_SEPARATOR + featureName;
+ }
+
+ /** Returns true if the passed feature is a wildcard feature */
+ public static boolean isWildCard(EStructuralFeature feature) {
+ EAnnotation eAnnotation = feature.getEAnnotation("http:///org/eclipse/emf/ecore/util/ExtendedMetaData");
+ if (eAnnotation == null) {
+ return false;
+ }
+ final String kind = eAnnotation.getDetails().get("kind");
+ final String wildcards = eAnnotation.getDetails().get("wildcards");
+ return kind != null && kind.compareTo("elementWildcard") == 0 && wildcards != null;
+ /*
+ * // todo optimise this with a cache final EAnnotation eannotation = feature
+ * .getEAnnotation("http:///org/eclipse/emf/ecore/util/ExtendedMetaData" ); if (eannotation != null) { final
+ * String kind = (String)eannotation.getDetails().get("kind"); final String wildcards =
+ * (String)eannotation.getDetails().get("wildcards"); if (wildcards != null && kind != null &&
+ * "elementWildcard".compareTo(kind) == 0) { return true; } } return false;
+ */
+ }
+
+ /** Returns true if the passed feature is a wildcard feature */
+ public static boolean isMixed(EStructuralFeature feature) {
+ EAnnotation eAnnotation = feature.getEAnnotation("http:///org/eclipse/emf/ecore/util/ExtendedMetaData");
+ if (eAnnotation == null) {
+ return false;
+ }
+ final String kind = eAnnotation.getDetails().get("kind");
+ final String name = eAnnotation.getDetails().get("name");
+ return kind != null && kind.compareTo("elementWildcard") == 0 && name != null && name.compareTo(":mixed") == 0;
+ /*
+ * // todo optimise this with a cache final EAnnotation eannotation = feature
+ * .getEAnnotation("http:///org/eclipse/emf/ecore/util/ExtendedMetaData" ); if (eannotation != null) { final
+ * String kind = (String)eannotation.getDetails().get("kind"); final String wildcards =
+ * (String)eannotation.getDetails().get("wildcards"); if (wildcards != null && kind != null &&
+ * "elementWildcard".compareTo(kind) == 0) { return true; } } return false;
+ */
+ }
+
+ /** Translates a string to a structural feature */
+ public static EStructuralFeature stringToStructureFeature(String strid) {
+ // this method expects a dbid consisting of three parts separated by /
+ int lastIndex = strid.lastIndexOf(PATH_SEPARATOR);
+ int beforeLastIndex = strid.lastIndexOf(PATH_SEPARATOR, lastIndex - 1);
+
+ if (lastIndex == -1 || beforeLastIndex == -1) {
+ throw new TeneoException(
+ "The database id stored for a structuralfeature used in a featuremap entry is invalid, dbid: "
+ + strid);
+ }
+
+ final String nsuri = strid.substring(0, beforeLastIndex);
+ final String eclassName = strid.substring(beforeLastIndex + 1, lastIndex);
+ final String featureName = strid.substring(lastIndex + 1);
+
+ final EPackage epack = PackageRegistryProvider.getInstance().getPackageRegistry().getEPackage(nsuri);
+ if (epack == null) {
+ throw new TeneoException("The dbid " + strid + " and nsuri: " + nsuri + " does not resolve to an epackage");
+ }
+
+ final EClass eclass = (EClass) epack.getEClassifier(eclassName);
+ if (eclass == null) {
+ throw new TeneoException("The dbid " + strid + " and eclassname: " + eclassName
+ + " does not resolve to an eclass");
+ }
+
+ final EStructuralFeature structFeature = eclass.getEStructuralFeature(featureName);
+ if (structFeature == null) {
+ throw new TeneoException("The dbid " + strid + " and featurename: " + featureName
+ + " does not resolve to a structural feature");
+ }
+
+ return structFeature;
+ }
+
+ /**
+ * Returns the string which is used to store the unique identification of the passed edatatype
+ */
+ public static String edatatypeToString(EDataType edatatype) {
+ // the unique id will consist of two part: 1) package NSURI, 2) Name
+ final String nsuri = edatatype.getEPackage().getNsURI();
+ final String name = edatatype.getName();
+ return nsuri + PATH_SEPARATOR + name;
+ }
+
+ /** Translates a string to an edatatype */
+ public static EDataType stringToEDataType(String strid) {
+ // this method expects a dbid consisting of three parts separated by /
+ int lastIndex = strid.lastIndexOf(PATH_SEPARATOR);
+
+ if (lastIndex == -1) {
+ throw new TeneoException("The database id stored for a datatype is invalid, dbid: " + strid);
+ }
+
+ final String nsuri = strid.substring(0, lastIndex);
+ final String name = strid.substring(lastIndex + 1);
+
+ final EPackage epack = PackageRegistryProvider.getInstance().getPackageRegistry().getEPackage(nsuri);
+ if (epack == null) {
+ throw new TeneoException("The dbid " + strid + " and nsuri: " + nsuri + " does not resolve to an epackage");
+ }
+
+ final EDataType edatatype = (EDataType) epack.getEClassifier(name);
+ if (edatatype == null) {
+ throw new TeneoException("The dbid " + strid + " and eclassname: " + name
+ + " does not resolve to an EDataType");
+ }
+ return edatatype;
+ }
+
+ /**
+ * Based on the eobject and the fieldname returns the structural feature. Caching should be added here.
+ */
+ public static EStructuralFeature getEStructuralFeature(EObject emfObj, String fieldName) {
+ return getEStructuralFeature(emfObj.eClass(), fieldName);
+ }
+
+ /**
+ * Returns all the direct content based on the eclass of the object, null content is not returned
+ */
+ public static Object[] getObjectContent(EObject eo) {
+ final ArrayList<Object> result = new ArrayList<Object>();
+ for (EStructuralFeature estruct : eo.eClass().getEAllStructuralFeatures()) {
+ final Object val = eo.eGet(estruct);
+ if (val != null) {
+ result.add(val);
+ }
+ }
+ return result.toArray(new Object[result.size()]);
+ }
+
+ /**
+ * Based on the eclass and the fieldname returns the structural feature. Caching should be added here.
+ */
+ public static EStructuralFeature getEStructuralFeature(EClass eclass, String fieldName) {
+ EStructuralFeature reserve = null;
+ for (EStructuralFeature estruct : eclass.getEAllStructuralFeatures()) {
+ String name = estruct.getName();
+ if (name.compareTo(fieldName) == 0) {
+ return estruct;
+ }
+ if (name.compareToIgnoreCase(fieldName) == 0) {
+ reserve = estruct; // use this if all else fails
+ } else if ((name + "_").compareToIgnoreCase(fieldName) == 0) { // reserved
+ // word
+ reserve = estruct; // use this if all else fails
+ }
+ }
+
+ if (reserve != null) {
+ return reserve;
+ }
+
+ return null;
+
+ // throw new StoreException("The fieldname " + fieldName + " is not
+ // present as a ereference type in the class: "
+ // + eclass.getName());
+ }
+
+ /**
+ * Returns a list of all ereferences with many of the emfObj. TODO add caching
+ */
+ public static EReference[] getManyGroupEReferences(EObject emfObj) {
+ final ArrayList<EReference> manyRefs = new ArrayList<EReference>();
+ for (EStructuralFeature estruct : emfObj.eClass().getEAllStructuralFeatures()) {
+ if (estruct instanceof EReference
+ && (((EReference) estruct).isMany() || isGroupFeature(estruct) || isWildCard(estruct))) {
+ manyRefs.add((EReference) estruct);
+ }
+ }
+ return manyRefs.toArray(new EReference[manyRefs.size()]);
+ }
+
+ /** Checks if a structural feature is a group feature */
+ public static boolean isGroupFeature(EStructuralFeature estruct) {
+ final EAnnotation annotation = estruct.getEAnnotation(ANNOTATION_SOURCE);
+
+ if (annotation == null) {
+ return false;
+ }
+
+ final EMap<String, String> map = annotation.getDetails();
+ for (String key : map.keySet()) {
+ final String value = map.get(key);
+ if ("kind".compareTo(key) == 0 && "group".compareTo(value) == 0) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Returns the name used for the group feature, if the feature is not a group then null is returned
+ */
+ public static String getGroupName(EStructuralFeature estruct) {
+ final EAnnotation annotation = estruct.getEAnnotation(ANNOTATION_SOURCE);
+
+ if (annotation == null) {
+ return null;
+ }
+
+ boolean isGroup = false;
+ String name = null;
+
+ final EMap<String, String> map = annotation.getDetails();
+ for (String key : map.keySet()) {
+ final String value = map.get(key);
+ if ("kind".compareTo(key) == 0 && "group".compareTo(value) == 0) {
+ // can not return here because we also need to get the name
+ isGroup = true;
+ }
+ if ("name".compareTo(key) == 0) {
+ name = value;
+ }
+ }
+
+ if (isGroup) {
+ assert (name != null);
+ return name;
+ }
+
+ return null;
+ }
+
+ /** Checks if a feature is an element of the passed group */
+ public static boolean isElementOfGroup(EStructuralFeature estruct, EStructuralFeature groupFeature) {
+ final EStructuralFeature ef = ExtendedMetaData.INSTANCE.getGroup(estruct);
+ return ef == groupFeature;
+ /*
+ * final EAnnotation annotation = estruct.getEAnnotation(ANNOTATION_SOURCE); if (annotation == null) return
+ * false; final EMap map = annotation.getDetails(); final Iterator keys = map.keySet().iterator(); while
+ * (keys.hasNext()) { final String key = (String)keys.next(); final String value = (String)map.get(key); // for
+ * a choice the groupName in the group element starts with # for substitution it // doesn't therefore the
+ * endsWith if ("group".compareTo(key) == 0 && value != null && groupName.endsWith(value)) { return true; } }
+ * return false;
+ */
+ }
+
+ /** Checks if a feature is an element of a group */
+ public static boolean isElementOfAGroup(EStructuralFeature estruct) {
+ final EStructuralFeature ef = ExtendedMetaData.INSTANCE.getGroup(estruct);
+ return ef != null;
+ /*
+ * // group elements are always transient if (!estruct.isTransient()) return false; final EAnnotation annotation
+ * = estruct.getEAnnotation(ANNOTATION_SOURCE); if (annotation == null) return false; final EMap map =
+ * annotation.getDetails(); final Iterator keys = map.keySet().iterator(); while (keys.hasNext()) { final String
+ * key = (String)keys.next(); final String value = (String)map.get(key); if ("group".compareTo(key) == 0 &&
+ * value != null) return true; } return false;
+ */
+ }
+
+ /**
+ * Returns the list of estructuralfeatures which belong to a certain feature map entry
+ */
+ public static List<EStructuralFeature> getFeaturesOfGroup(EAttribute eattr) {
+ final ArrayList<EStructuralFeature> result = new ArrayList<EStructuralFeature>();
+ for (EStructuralFeature efeature : eattr.getEContainingClass().getEStructuralFeatures()) {
+ if (StoreUtil.isElementOfGroup(efeature, eattr)) {
+ result.add(efeature);
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Returns an array of epackages on the basis of a string with comma separated epackage ns uris
+ */
+ public static EPackage[] getEPackages(String nsuris) {
+ final String[] epacknsuris = nsuris.split(",");
+ final EPackage[] epacks = new EPackage[epacknsuris.length];
+ for (int i = 0; i < epacknsuris.length; i++) {
+ final EPackage epack = PackageRegistryProvider.getInstance().getPackageRegistry().getEPackage(
+ epacknsuris[i]);
+ if (epack == null) {
+ throw new TeneoException("EPackage with nsuri: " + epacknsuris[i] + " can not be found,");
+ }
+ epacks[i] = epack;
+ }
+ return epacks;
+ }
+
+ /** Sets a field and wraps the exceptions */
+ public static void setField(Field field, Object obj, Object value) {
+ try {
+ field.set(obj, value);
+ } catch (IllegalAccessException e) {
+ throw new TeneoException("IllegalAccessException " + obj.getClass().getName() + " field; "
+ + field.getName());
+ }
+ }
+
+ /**
+ * Determines the list of available mapping files on the basis of the suffix
+ */
+ public static String[] getFileList(String fileName, String additionalLocation) {
+ final ArrayList<String> result = new ArrayList<String>();
+ log.debug(">>>> Building or descriptor file List");
+
+ if (additionalLocation != null) {
+ result.add(additionalLocation);
+ }
+
+ final String[] packagelist = buildPackagelist();
+ for (final String packagePath : packagelist) {
+ final String filePath = packagePath + fileName;
+
+ log.debug("Try path: " + filePath);
+
+ final URL url = StoreUtil.class.getResource(filePath);
+ if (url != null) // file exists
+ {
+ log.debug("!!Found!!");
+ result.add(filePath);
+ }
+ }
+ return result.toArray(new String[result.size()]);
+ }
+
+ /** Build list of possible or descriptor file paths */
+ private static String[] buildPackagelist() {
+ // walk through all the classnames
+ final ArrayList<String> newPackagePathList = new ArrayList<String>();
+ newPackagePathList.add(File.pathSeparator); // add the root package
+
+ // TODO: move this to the EModelResolver!
+ for (Class<?> clazz : EModelResolver.instance().getAllClassesAndInterfaces()) {
+ final String className = clazz.getName();
+ final int classNameIndex = className.lastIndexOf(PACKAGE_SEPARATOR);
+ final String trunkClassName = className.substring(0, classNameIndex);
+ final String startPath = PATH_SEPARATOR + trunkClassName.replace(PACKAGE_SEPARATOR, PATH_SEPARATOR);
+
+ buildPackagePathFromClassName(startPath, newPackagePathList);
+ }
+ return newPackagePathList.toArray(new String[newPackagePathList.size()]);
+ }
+
+ /** Take care of one class */
+ private static void buildPackagePathFromClassName(String path, ArrayList<String> newPackagePathList) {
+ if (newPackagePathList.contains(path + PATH_SEPARATOR)) {
+ return;
+ }
+ newPackagePathList.add(path + PATH_SEPARATOR);
+
+ final int sepIndex = path.lastIndexOf(PATH_SEPARATOR);
+ if (sepIndex == -1) {
+ return;
+ }
+ buildPackagePathFromClassName(path.substring(0, sepIndex), newPackagePathList);
+ }
+
+ /** Copies a file */
+ public static void copyFile(File src, File dst) {
+ try {
+ log.debug("Copy file from " + src.getAbsolutePath() + " to " + dst.getAbsolutePath());
+ InputStream in = new FileInputStream(src);
+ OutputStream out = new FileOutputStream(dst);
+
+ // Transfer bytes from in to out
+ byte[] buf = new byte[1024];
+ int len;
+ while ((len = in.read(buf)) > 0) {
+ out.write(buf, 0, len);
+ }
+ in.close();
+ out.close();
+ } catch (Exception e) {
+ throw new TeneoException("Exception while copying from/to " + src.getAbsolutePath() + "/"
+ + dst.getAbsolutePath(), e);
+ }
+ }
+
+ /**
+ * Checks if an object has a HibernatePersistentStoreAdapter and if it doesn't creates one and returns it.
+ */
+ public static PersistentStoreAdapter getPersistentStoreAdapter(EObject eObject) {
+ for (Adapter adapter : eObject.eAdapters()) {
+ if (PersistentStoreAdapter.class.isAssignableFrom(adapter.getClass())) {
+ return (PersistentStoreAdapter) adapter;
+ }
+ }
+ final PersistentStoreAdapter adapter = new PersistentStoreAdapter();
+ eObject.eAdapters().add(adapter);
+ return adapter;
+ }
+
+} \ No newline at end of file

Back to the top