summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStefan Winkler2010-10-01 04:42:09 (EDT)
committerStefan Winkler2010-10-01 04:42:09 (EDT)
commit4f1a1b7e87529058446bd90ea4d544faa8c9cda5 (patch)
treecbd0d873e3b499f61fa93397a9d136129f4c51d2
parentd88c799ad852ae2a966baee0d9aa90684dc46ecd (diff)
downloadcdo-4f1a1b7e87529058446bd90ea4d544faa8c9cda5.zip
cdo-4f1a1b7e87529058446bd90ea4d544faa8c9cda5.tar.gz
cdo-4f1a1b7e87529058446bd90ea4d544faa8c9cda5.tar.bz2
[285426] [DB] Implement user-defined typeMapping support
https://bugs.eclipse.org/bugs/show_bug.cgi?id=285426
-rw-r--r--plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/mapping/AbstractTypeMapping.java287
-rw-r--r--plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/mapping/AbstractTypeMappingFactory.java43
-rw-r--r--plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/mapping/ITypeMapping.java126
-rw-r--r--plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/DBAnnotation.java4
-rw-r--r--plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/bundle/OM.java1
-rw-r--r--plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/AbstractMappingStrategy.java9
-rw-r--r--plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/CoreTypeMappings.java771
-rw-r--r--plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/TypeMapping.java701
-rw-r--r--plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/TypeMappingDescriptor.java65
-rw-r--r--plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/TypeMappingFactory.java349
-rw-r--r--plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/TypeMappingRegistry.java430
-rw-r--r--plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/TypeMappingUtil.java113
-rw-r--r--plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/AbstractFeatureMapTableMapping.java13
-rw-r--r--plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/AuditFeatureMapTableMappingWithRanges.java10
-rw-r--r--plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/messages/messages.properties14
-rw-r--r--plugins/org.eclipse.emf.cdo.tests.db/src/org/eclipse/emf/cdo/tests/db/CustomTypeMappingTest.java148
-rw-r--r--plugins/org.eclipse.emf.cdo.tests.db/src/org/eclipse/emf/cdo/tests/db/DBAnnotationsTest.java22
-rw-r--r--plugins/org.eclipse.emf.cdo.tests.db/src/org/eclipse/emf/cdo/tests/db/DBConfigs.java2
18 files changed, 2047 insertions, 1061 deletions
diff --git a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/mapping/AbstractTypeMapping.java b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/mapping/AbstractTypeMapping.java
new file mode 100644
index 0000000..ff1ebb1
--- /dev/null
+++ b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/mapping/AbstractTypeMapping.java
@@ -0,0 +1,287 @@
+/**
+ * Copyright (c) 2004 - 2010 Eike Stepper (Berlin, Germany) 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:
+ * Eike Stepper - initial API and implementation
+ * Stefan Winkler - bug 271444: [DB] Multiple refactorings
+ * Stefan Winkler - bug 275303: [DB] DBStore does not handle BIG_INTEGER and BIG_DECIMAL
+ * Kai Schlamp - bug 282976: [DB] Influence Mappings through EAnnotations
+ * Stefan Winkler - bug 282976: [DB] Influence Mappings through EAnnotations
+ * Stefan Winkler - bug 285270: [DB] Support XSD based models
+ * Stefan Winkler - Bug 285426: [DB] Implement user-defined typeMapping support
+ */
+package org.eclipse.emf.cdo.server.db.mapping;
+
+import org.eclipse.emf.cdo.common.revision.CDORevisionData;
+import org.eclipse.emf.cdo.server.internal.db.DBAnnotation;
+import org.eclipse.emf.cdo.server.internal.db.MetaDataManager;
+import org.eclipse.emf.cdo.server.internal.db.bundle.OM;
+import org.eclipse.emf.cdo.server.internal.db.mapping.TypeMappingRegistry;
+import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevision;
+
+import org.eclipse.net4j.db.DBType;
+import org.eclipse.net4j.db.ddl.IDBField;
+import org.eclipse.net4j.db.ddl.IDBTable;
+import org.eclipse.net4j.util.container.IManagedContainer;
+import org.eclipse.net4j.util.om.trace.ContextTracer;
+
+import org.eclipse.emf.ecore.EStructuralFeature;
+
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+
+/**
+ * This is a default implementation for the {@link ITypeMapping} interface which provides default behavor for all common
+ * types. Implementors should provide a constructor which the factory (see below) can use and implement
+ * {@link #getResultSetValue(ResultSet)}. If needed, {@link #doSetValue(PreparedStatement, int, Object)} can also be
+ * overridden as a counterpart to {@link #getResultSetValue(ResultSet)}. Finally, an implementor should also implement a
+ * suitable factory for the {@link TypeMappingRegistry} and register it either manually using
+ * {@link IManagedContainer#registerFactory(org.eclipse.net4j.util.factory.IFactory)} or using the Net4j Extension Point
+ * <code>factories</code>.
+ *
+ * @author Eike Stepper
+ * @author Stefan Winkler
+ * @since 4.0
+ */
+public abstract class AbstractTypeMapping implements ITypeMapping
+{
+ private static final ContextTracer TRACER = new ContextTracer(OM.DEBUG, AbstractTypeMapping.class);
+
+ private IMappingStrategy mappingStrategy;
+
+ private EStructuralFeature feature;
+
+ private IDBField field;
+
+ private DBType dbType;
+
+ /**
+ * Create a new type mapping
+ */
+ public AbstractTypeMapping()
+ {
+ super();
+ }
+
+ public final void setMappingStrategy(IMappingStrategy mappingStrategy)
+ {
+ this.mappingStrategy = mappingStrategy;
+ }
+
+ public final IMappingStrategy getMappingStrategy()
+ {
+ return mappingStrategy;
+ }
+
+ public final void setFeature(EStructuralFeature feature)
+ {
+ this.feature = feature;
+ }
+
+ public final EStructuralFeature getFeature()
+ {
+ return feature;
+ }
+
+ public final void setValueFromRevision(PreparedStatement stmt, int index, InternalCDORevision revision)
+ throws SQLException
+ {
+ setValue(stmt, index, getRevisionValue(revision));
+ }
+
+ public void setDefaultValue(PreparedStatement stmt, int index) throws SQLException
+ {
+ setValue(stmt, index, getDefaultValue());
+ }
+
+ public final void setValue(PreparedStatement stmt, int index, Object value) throws SQLException
+ {
+ if (value == CDORevisionData.NIL)
+ {
+ if (TRACER.isEnabled())
+ {
+ TRACER.format("TypeMapping for {0}: converting Revision.NIL to DB-null", feature.getName()); //$NON-NLS-1$
+ }
+
+ stmt.setNull(index, getSqlType());
+ }
+ else if (value == null)
+ {
+ if (feature.isMany() || getDefaultValue() == null)
+ {
+ if (TRACER.isEnabled())
+ {
+ TRACER.format("TypeMapping for {0}: writing Revision.null as DB.null", feature.getName()); //$NON-NLS-1$
+ }
+
+ stmt.setNull(index, getSqlType());
+ }
+ else
+ {
+ if (TRACER.isEnabled())
+ {
+ TRACER.format("TypeMapping for {0}: converting Revision.null to default value", feature.getName()); //$NON-NLS-1$
+ }
+
+ setDefaultValue(stmt, index);
+ }
+ }
+ else
+ {
+ doSetValue(stmt, index, value);
+ }
+ }
+
+ public final void createDBField(IDBTable table)
+ {
+ createDBField(table, mappingStrategy.getFieldName(feature));
+ }
+
+ public final void createDBField(IDBTable table, String fieldName)
+ {
+ DBType fieldType = getDBType();
+ int fieldLength = getDBLength(fieldType);
+ field = table.addField(fieldName, fieldType, fieldLength);
+ }
+
+ public final void setDBField(IDBTable table, String fieldName)
+ {
+ field = table.getField(fieldName);
+ }
+
+ public final IDBField getField()
+ {
+ return field;
+ }
+
+ public final void readValueToRevision(ResultSet resultSet, InternalCDORevision revision) throws SQLException
+ {
+ Object value = readValue(resultSet);
+ revision.setValue(getFeature(), value);
+ }
+
+ public final Object readValue(ResultSet resultSet) throws SQLException
+ {
+ Object value = getResultSetValue(resultSet);
+ if (resultSet.wasNull())
+ {
+ if (feature.isMany())
+ {
+ if (TRACER.isEnabled())
+ {
+ TRACER.format("TypeMapping for {0}: read db.null - setting Revision.null", feature.getName()); //$NON-NLS-1$
+ }
+
+ value = null;
+ }
+ else
+ {
+ if (getDefaultValue() == null)
+ {
+ if (TRACER.isEnabled())
+ {
+ TRACER.format(
+ "TypeMapping for {0}: read db.null - setting Revision.null, because of default", feature.getName()); //$NON-NLS-1$
+ }
+
+ value = null;
+ }
+ else
+ {
+ if (TRACER.isEnabled())
+ {
+ TRACER.format("TypeMapping for {0}: read db.null - setting Revision.NIL", feature.getName()); //$NON-NLS-1$
+ }
+
+ value = CDORevisionData.NIL;
+ }
+ }
+ }
+
+ return value;
+ }
+
+ protected Object getDefaultValue()
+ {
+ return feature.getDefaultValue();
+ }
+
+ protected final Object getRevisionValue(InternalCDORevision revision)
+ {
+ return revision.getValue(getFeature());
+ }
+
+ /**
+ * Implementors could override this method to convert a given value to the database representation and set it to the
+ * prepared statement.
+ *
+ * @param stmt
+ * the {@link PreparedStatement} which is used for DB access
+ * @param index
+ * the parameter index in the statement which should be set
+ * @param value
+ * the value of the feature which should be written into the DB
+ */
+ protected void doSetValue(PreparedStatement stmt, int index, Object value) throws SQLException
+ {
+ stmt.setObject(index, value, getSqlType());
+ }
+
+ /**
+ * Returns the SQL type of this TypeMapping. The default implementation considers the type map hold by the meta-data
+ * manager (@see {@link MetaDataManager#getDBType(org.eclipse.emf.ecore.EClassifier)} Subclasses may override.
+ *
+ * @return The sql type of this TypeMapping.
+ */
+ protected int getSqlType()
+ {
+ return getDBType().getCode();
+ }
+
+ public final void setDBType(DBType dbType)
+ {
+ this.dbType = dbType;
+ }
+
+ public DBType getDBType()
+ {
+ return dbType;
+ }
+
+ protected int getDBLength(DBType type)
+ {
+ String value = DBAnnotation.COLUMN_LENGTH.getValue(feature);
+ if (value != null)
+ {
+ try
+ {
+ return Integer.parseInt(value);
+ }
+ catch (NumberFormatException e)
+ {
+ OM.LOG.error("Illegal columnLength annotation of feature " + feature.getName());
+ }
+ }
+
+ // TODO: implement DBAdapter.getDBLength
+ // mappingStrategy.getStore().getDBAdapter().getDBLength(type);
+ // which should then return the correct default field length for the db type
+ return type == DBType.VARCHAR ? 32672 : IDBField.DEFAULT;
+ }
+
+ /**
+ * Subclasses should implement this method to read the value from the result set. Typical implementations should look
+ * similar to this one: <code>resultSet.getString(getField().getName())</code>
+ *
+ * @param resultSet
+ * the result set to read from
+ * @return the result value read (this has to be compatible with the {@link #feature}.
+ */
+ protected abstract Object getResultSetValue(ResultSet resultSet) throws SQLException;
+
+}
diff --git a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/mapping/AbstractTypeMappingFactory.java b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/mapping/AbstractTypeMappingFactory.java
new file mode 100644
index 0000000..e57477d
--- /dev/null
+++ b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/mapping/AbstractTypeMappingFactory.java
@@ -0,0 +1,43 @@
+/**
+ * Copyright (c) 2004 - 2010 Eike Stepper (Berlin, Germany) 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:
+ * Eike Stepper - initial API and implementation
+ */
+package org.eclipse.emf.cdo.server.db.mapping;
+
+import org.eclipse.emf.cdo.server.db.mapping.ITypeMapping.Descriptor;
+
+import org.eclipse.net4j.util.factory.Factory;
+import org.eclipse.net4j.util.factory.ProductCreationException;
+
+/**
+ * Abstract implementation for {@link ITypeMapping.Factory}. Implementors should implement their custom
+ * {@link #create(String)} method and construct the factory using their custom descriptor. Subclasses must have a
+ * default constructor!
+ *
+ * @author Stefan Winkler
+ * @since 4.0
+ */
+public abstract class AbstractTypeMappingFactory extends Factory implements
+ org.eclipse.emf.cdo.server.db.mapping.ITypeMapping.Factory
+{
+ private ITypeMapping.Descriptor descriptor;
+
+ public AbstractTypeMappingFactory(Descriptor descriptor)
+ {
+ super(PRODUCT_GROUP, descriptor.getFactoryType());
+ this.descriptor = descriptor;
+ }
+
+ public abstract ITypeMapping create(String description) throws ProductCreationException;
+
+ public final Descriptor getDescriptor()
+ {
+ return descriptor;
+ }
+}
diff --git a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/mapping/ITypeMapping.java b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/mapping/ITypeMapping.java
index d309b11..fe24069 100644
--- a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/mapping/ITypeMapping.java
+++ b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/mapping/ITypeMapping.java
@@ -12,17 +12,22 @@
*/
package org.eclipse.emf.cdo.server.db.mapping;
+import org.eclipse.emf.cdo.server.internal.db.mapping.TypeMappingRegistry;
+import org.eclipse.emf.cdo.server.internal.db.mapping.TypeMappingUtil;
import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevision;
import org.eclipse.net4j.db.DBType;
import org.eclipse.net4j.db.ddl.IDBField;
import org.eclipse.net4j.db.ddl.IDBTable;
+import org.eclipse.net4j.util.factory.IFactory;
+import org.eclipse.emf.ecore.EClassifier;
import org.eclipse.emf.ecore.EStructuralFeature;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
+import java.util.Collection;
/**
* Mapping of single values to and from the database.
@@ -50,6 +55,21 @@ public interface ITypeMapping
public DBType getDBType();
/**
+ * @since 4.0
+ */
+ public void setMappingStrategy(IMappingStrategy mappingStrategy);
+
+ /**
+ * @since 4.0
+ */
+ public void setFeature(EStructuralFeature feature);
+
+ /**
+ * @since 4.0
+ */
+ public void setDBType(DBType dbType);
+
+ /**
* Creates the DBField and adds it to the given table. The name of the DBField is derived from the feature.
*
* @param table
@@ -149,4 +169,110 @@ public interface ITypeMapping
* @since 3.0
*/
public void readValueToRevision(ResultSet resultSet, InternalCDORevision revision) throws SQLException;
+
+ /**
+ * A descriptor which describes one type mapping class. The descriptor is encoded in the factoryType which is used as
+ * a string description for the extension point mechanism. Translations and instantiations can be done using the
+ * methods in {@link TypeMappingUtil}.
+ *
+ * @author Stefan Winkler
+ * @since 4.0
+ */
+ public interface Descriptor
+ {
+ /**
+ * The factoryType of the factory which can create the type mapping
+ */
+ public String getFactoryType();
+
+ /**
+ * The ID of the described type mapping.
+ */
+ public String getID();
+
+ /**
+ * The source (i.e., model) type that can be mapped by the type mapping.
+ */
+ public EClassifier getEClassifier();
+
+ /**
+ * The target (i.e., db) type that can be mapped by the type mapping.
+ */
+ public DBType getDBType();
+
+ }
+
+ /**
+ * A global (singleton) registry which collects all available type mappings which are either available in the CDO
+ * core, as declared extensions, or registered manually.
+ *
+ * @author Stefan Winkler
+ * @since 4.0
+ */
+ public interface Registry
+ {
+ /**
+ * The one global (singleton) registry instance.
+ */
+ public static Registry INSTANCE = new TypeMappingRegistry();
+
+ /**
+ * Register a type mapping by descriptor.
+ */
+ public void registerTypeMapping(ITypeMapping.Descriptor descriptor);
+
+ /**
+ * Provides a list of all DBTypes for which type mappings exist in the registry. This is used in feature map tables
+ * to create columns for all of these types.
+ */
+ public Collection<DBType> getDefaultFeatureMapDBTypes();
+ }
+
+ /**
+ * A provider for type mapping information. This provider is used by the {@link TypeMappingRegistry} to create an
+ * {@link ITypeMapping} instance suitable for a given feature and DB field. Usually, one factory is responsible for
+ * one type mapping.
+ *
+ * @author Stefan Winkler
+ * @since 4.0
+ */
+ public interface Provider
+ {
+ /**
+ * The one global (singleton) provider instance.
+ */
+ public static Provider INSTANCE = (Provider)Registry.INSTANCE;
+
+ /**
+ * Create an {@link ITypeMapping} implementation.
+ *
+ * @param mappingStrategy
+ * the mapping strategy
+ * @param feature
+ * the feature the new type mapping shall be responsible for
+ * @return the newly created {@link ITypeMapping} instance
+ */
+ public ITypeMapping createTypeMapping(IMappingStrategy mappingStrategy, EStructuralFeature feature);
+ }
+
+ /**
+ * A factory for typeMappings. This is a regular Net4j factory registered by the respective extension point. It
+ * enhances the regular factory using a descriptor which is translated from and to the factoryType by the methods in
+ * {@link TypeMappingUtil}.
+ *
+ * @author Stefan Winkler
+ * @since 4.0
+ */
+ public interface Factory extends IFactory
+ {
+ /**
+ * The Net4j factory product group for type mappings
+ */
+ public static final String PRODUCT_GROUP = "org.eclipse.emf.cdo.server.db.typeMappings";
+
+ /**
+ * Return the descriptor of the kind of type mapping created by this factory.
+ */
+ public ITypeMapping.Descriptor getDescriptor();
+ }
}
diff --git a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/DBAnnotation.java b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/DBAnnotation.java
index 64f5997..f7825fa 100644
--- a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/DBAnnotation.java
+++ b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/DBAnnotation.java
@@ -10,6 +10,7 @@
* Eike Stepper - maintenance
* Kai Schlamp - Bug 284680 - [DB] Provide annotation to bypass ClassMapping
* Stefan Winkler - maintenance
+ * Stefan Winkler - Bug 285426: [DB] Implement user-defined typeMapping support
*/
package org.eclipse.emf.cdo.server.internal.db;
@@ -25,7 +26,8 @@ public enum DBAnnotation
TABLE_NAME("tableName"), //
COLUMN_NAME("columnName"), //
COLUMN_TYPE("columnType"), //
- COLUMN_LENGTH("columnLength");
+ COLUMN_LENGTH("columnLength"), //
+ TYPE_MAPPING("typeMapping");
public final static String SOURCE_URI = "http://www.eclipse.org/CDO/DBStore";
diff --git a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/bundle/OM.java b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/bundle/OM.java
index 1e7de67..39a3852 100644
--- a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/bundle/OM.java
+++ b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/bundle/OM.java
@@ -7,6 +7,7 @@
*
* Contributors:
* Eike Stepper - initial API and implementation
+ * Stefan Winkler - Bug 285426: [DB] Implement user-defined typeMapping support
*/
package org.eclipse.emf.cdo.server.internal.db.bundle;
diff --git a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/AbstractMappingStrategy.java b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/AbstractMappingStrategy.java
index f7b4cb4..b20e07b 100644
--- a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/AbstractMappingStrategy.java
+++ b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/AbstractMappingStrategy.java
@@ -12,6 +12,7 @@
* Stefan Winkler - Bug 282976: [DB] Influence Mappings through EAnnotations
* Kai Schlamp - Bug 284680 - [DB] Provide annotation to bypass ClassMapping
* Stefan Winkler - maintenance
+ * Stefan Winkler - Bug 285426: [DB] Implement user-defined typeMapping support
*/
package org.eclipse.emf.cdo.server.internal.db.mapping;
@@ -550,7 +551,13 @@ public abstract class AbstractMappingStrategy extends Lifecycle implements IMapp
public ITypeMapping createValueMapping(EStructuralFeature feature)
{
- return TypeMappingFactory.createTypeMapping(this, feature);
+ ITypeMapping.Provider provider = getTypeMappingProvider();
+ return provider.createTypeMapping(this, feature);
+ }
+
+ protected ITypeMapping.Provider getTypeMappingProvider()
+ {
+ return ITypeMapping.Provider.INSTANCE;
}
public final IListMapping createListMapping(EClass containingClass, EStructuralFeature feature)
diff --git a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/CoreTypeMappings.java b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/CoreTypeMappings.java
new file mode 100644
index 0000000..78887af
--- /dev/null
+++ b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/CoreTypeMappings.java
@@ -0,0 +1,771 @@
+/**
+ * Copyright (c) 2004 - 2010 Eike Stepper (Berlin, Germany) 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:
+ * Eike Stepper - initial API and implementation
+ * Stefan Winkler - bug 271444: [DB] Multiple refactorings
+ * Stefan Winkler - bug 275303: [DB] DBStore does not handle BIG_INTEGER and BIG_DECIMAL
+ * Kai Schlamp - bug 282976: [DB] Influence Mappings through EAnnotations
+ * Stefan Winkler - bug 282976: [DB] Influence Mappings through EAnnotations
+ * Stefan Winkler - bug 285270: [DB] Support XSD based models
+ * Stefan Winkler - Bug 285426: [DB] Implement user-defined typeMapping support
+ */
+package org.eclipse.emf.cdo.server.internal.db.mapping;
+
+import org.eclipse.emf.cdo.common.id.CDOID;
+import org.eclipse.emf.cdo.common.revision.CDORevisionData;
+import org.eclipse.emf.cdo.server.IStoreAccessor;
+import org.eclipse.emf.cdo.server.IStoreAccessor.CommitContext;
+import org.eclipse.emf.cdo.server.StoreThreadLocal;
+import org.eclipse.emf.cdo.server.db.CDODBUtil;
+import org.eclipse.emf.cdo.server.db.IDBStore;
+import org.eclipse.emf.cdo.server.db.IDBStoreAccessor;
+import org.eclipse.emf.cdo.server.db.IExternalReferenceManager;
+import org.eclipse.emf.cdo.server.db.mapping.AbstractTypeMapping;
+import org.eclipse.emf.cdo.server.db.mapping.AbstractTypeMappingFactory;
+import org.eclipse.emf.cdo.server.db.mapping.ITypeMapping;
+
+import org.eclipse.net4j.db.DBType;
+import org.eclipse.net4j.util.factory.ProductCreationException;
+
+import org.eclipse.emf.common.util.Enumerator;
+import org.eclipse.emf.ecore.EEnum;
+import org.eclipse.emf.ecore.EEnumLiteral;
+import org.eclipse.emf.ecore.EcorePackage;
+
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Timestamp;
+import java.util.Calendar;
+import java.util.Date;
+
+/**
+ * This is a default implementation for the {@link ITypeMapping} interface which provides default behavor for all common
+ * types.
+ *
+ * @author Eike Stepper
+ */
+public class CoreTypeMappings
+{
+ public static final String ID_PREFIX = "org.eclipse.emf.cdo.server.db.CoreTypeMappings";
+
+ /**
+ * @author Eike Stepper
+ */
+ public static class TMEnum extends AbstractTypeMapping
+ {
+ public static final String ID = ID_PREFIX + ".Enum";
+
+ public static final Factory FACTORY = new Factory(TypeMappingUtil.createDescriptor(ID,
+ EcorePackage.eINSTANCE.getEEnum(), DBType.INTEGER));
+
+ public static class Factory extends AbstractTypeMappingFactory
+ {
+ public Factory(Descriptor descriptor)
+ {
+ super(descriptor);
+ }
+
+ @Override
+ public ITypeMapping create(String description) throws ProductCreationException
+ {
+ return new TMEnum();
+ }
+ }
+
+ @Override
+ public Object getResultSetValue(ResultSet resultSet) throws SQLException
+ {
+ // see Bug 271941
+ return resultSet.getInt(getField().getName());
+ // EEnum type = (EEnum)getFeature().getEType();
+ // int value = resultSet.getInt(column);
+ // return type.getEEnumLiteral(value);
+ }
+
+ @Override
+ protected Object getDefaultValue()
+ {
+ EEnum eenum = (EEnum)getFeature().getEType();
+
+ String defaultValueLiteral = getFeature().getDefaultValueLiteral();
+ if (defaultValueLiteral != null)
+ {
+ EEnumLiteral literal = eenum.getEEnumLiteralByLiteral(defaultValueLiteral);
+ return literal.getValue();
+ }
+
+ Enumerator enumerator = (Enumerator)eenum.getDefaultValue();
+ return enumerator.getValue();
+ }
+ }
+
+ /**
+ * @author Eike Stepper
+ */
+ public static class TMString extends AbstractTypeMapping
+ {
+ public static final String ID_VARCHAR = ID_PREFIX + ".StringVarchar";
+
+ public static final Factory FACTORY_VARCHAR = new Factory(TypeMappingUtil.createDescriptor(ID_VARCHAR,
+ EcorePackage.eINSTANCE.getEString(), DBType.VARCHAR));
+
+ public static final String ID_CLOB = ID_PREFIX + ".StringClob";
+
+ public static final Factory FACTORY_CLOB = new Factory(TypeMappingUtil.createDescriptor(ID_CLOB,
+ EcorePackage.eINSTANCE.getEString(), DBType.CLOB));
+
+ public static class Factory extends AbstractTypeMappingFactory
+ {
+ public Factory(Descriptor descriptor)
+ {
+ super(descriptor);
+ }
+
+ @Override
+ public ITypeMapping create(String description) throws ProductCreationException
+ {
+ return new TMString();
+ }
+ }
+
+ @Override
+ public Object getResultSetValue(ResultSet resultSet) throws SQLException
+ {
+ return resultSet.getString(getField().getName());
+ }
+ }
+
+ /**
+ * @author Eike Stepper
+ */
+ public static class TMShort extends AbstractTypeMapping
+ {
+ public static final String ID = ID_PREFIX + ".Short";
+
+ public static final Factory FACTORY = new Factory(TypeMappingUtil.createDescriptor(ID,
+ EcorePackage.eINSTANCE.getEShort(), DBType.SMALLINT));
+
+ public static final String ID_OBJECT = ID_PREFIX + ".ShortObject";
+
+ public static final Factory FACTORY_OBJECT = new Factory(TypeMappingUtil.createDescriptor(ID_OBJECT,
+ EcorePackage.eINSTANCE.getEShortObject(), DBType.SMALLINT));
+
+ public static class Factory extends AbstractTypeMappingFactory
+ {
+ public Factory(Descriptor descriptor)
+ {
+ super(descriptor);
+ }
+
+ @Override
+ public ITypeMapping create(String description) throws ProductCreationException
+ {
+ return new TMShort();
+ }
+ }
+
+ @Override
+ public Object getResultSetValue(ResultSet resultSet) throws SQLException
+ {
+ return resultSet.getShort(getField().getName());
+ }
+ }
+
+ /**
+ * @author Eike Stepper <br>
+ */
+ public static class TMObject extends AbstractTypeMapping
+ {
+ public static final String ID = ID_PREFIX + ".Object";
+
+ public static final Factory FACTORY = new Factory(TypeMappingUtil.createDescriptor(ID,
+ EcorePackage.eINSTANCE.getEClass(), DBType.BIGINT));
+
+ public static class Factory extends AbstractTypeMappingFactory
+ {
+ public Factory(Descriptor descriptor)
+ {
+ super(descriptor);
+ }
+
+ @Override
+ public ITypeMapping create(String description) throws ProductCreationException
+ {
+ return new TMObject();
+ }
+ }
+
+ @Override
+ public Object getResultSetValue(ResultSet resultSet) throws SQLException
+ {
+ long id = resultSet.getLong(getField().getName());
+ if (resultSet.wasNull())
+ {
+ return getFeature().isUnsettable() ? CDORevisionData.NIL : null;
+ }
+
+ IExternalReferenceManager externalRefs = getMappingStrategy().getStore().getExternalReferenceManager();
+ return CDODBUtil.convertLongToCDOID(externalRefs, getAccessor(), id);
+ }
+
+ @Override
+ protected void doSetValue(PreparedStatement stmt, int index, Object value) throws SQLException
+ {
+ IDBStore store = getMappingStrategy().getStore();
+ IExternalReferenceManager externalReferenceManager = store.getExternalReferenceManager();
+ CommitContext commitContext = StoreThreadLocal.getCommitContext();
+ long commitTime = commitContext.getBranchPoint().getTimeStamp();
+ long id = CDODBUtil.convertCDOIDToLong(externalReferenceManager, getAccessor(), (CDOID)value, commitTime);
+ super.doSetValue(stmt, index, id);
+ }
+
+ private IDBStoreAccessor getAccessor()
+ {
+ IStoreAccessor accessor = StoreThreadLocal.getAccessor();
+ if (accessor == null)
+ {
+ throw new IllegalStateException("Can only be called from within a valid IDBStoreAccessor context");
+ }
+
+ return (IDBStoreAccessor)accessor;
+ }
+ }
+
+ /**
+ * @author Eike Stepper
+ */
+ public static class TMLong extends AbstractTypeMapping
+ {
+ public static final String ID = ID_PREFIX + ".Long";
+
+ public static final Factory FACTORY = new Factory(TypeMappingUtil.createDescriptor(ID,
+ EcorePackage.eINSTANCE.getELong(), DBType.BIGINT));
+
+ public static final String ID_OBJECT = ID_PREFIX + ".LongObject";
+
+ public static final Factory FACTORY_OBJECT = new Factory(TypeMappingUtil.createDescriptor(ID_OBJECT,
+ EcorePackage.eINSTANCE.getELongObject(), DBType.BIGINT));
+
+ public static class Factory extends AbstractTypeMappingFactory
+ {
+ public Factory(Descriptor descriptor)
+ {
+ super(descriptor);
+ }
+
+ @Override
+ public ITypeMapping create(String description) throws ProductCreationException
+ {
+ return new TMLong();
+ }
+ }
+
+ @Override
+ public Object getResultSetValue(ResultSet resultSet) throws SQLException
+ {
+ return resultSet.getLong(getField().getName());
+ }
+ }
+
+ /**
+ * @author Eike Stepper
+ */
+ public static class TMInteger extends AbstractTypeMapping
+ {
+ public static final String ID = ID_PREFIX + ".Integer";
+
+ public static final Factory FACTORY = new Factory(TypeMappingUtil.createDescriptor(ID,
+ EcorePackage.eINSTANCE.getEInt(), DBType.INTEGER));
+
+ public static final String ID_OBJECT = ID_PREFIX + ".IntegerObject";
+
+ public static final Factory FACTORY_OBJECT = new Factory(TypeMappingUtil.createDescriptor(ID_OBJECT,
+ EcorePackage.eINSTANCE.getEIntegerObject(), DBType.INTEGER));
+
+ public static class Factory extends AbstractTypeMappingFactory
+ {
+ public Factory(Descriptor descriptor)
+ {
+ super(descriptor);
+ }
+
+ @Override
+ public ITypeMapping create(String description) throws ProductCreationException
+ {
+ return new TMInteger();
+ }
+ }
+
+ @Override
+ public Object getResultSetValue(ResultSet resultSet) throws SQLException
+ {
+ return resultSet.getInt(getField().getName());
+ }
+ }
+
+ /**
+ * @author Eike Stepper
+ */
+ public static class TMFloat extends AbstractTypeMapping
+ {
+ public static final String ID = ID_PREFIX + ".Float";
+
+ public static final Factory FACTORY = new Factory(TypeMappingUtil.createDescriptor(ID,
+ EcorePackage.eINSTANCE.getEFloat(), DBType.FLOAT));
+
+ public static final String ID_OBJECT = ID_PREFIX + ".FloatObject";
+
+ public static final Factory FACTORY_OBJECT = new Factory(TypeMappingUtil.createDescriptor(ID_OBJECT,
+ EcorePackage.eINSTANCE.getEFloatObject(), DBType.FLOAT));
+
+ public static class Factory extends AbstractTypeMappingFactory
+ {
+ public Factory(Descriptor descriptor)
+ {
+ super(descriptor);
+ }
+
+ @Override
+ public ITypeMapping create(String description) throws ProductCreationException
+ {
+ return new TMFloat();
+ }
+ }
+
+ @Override
+ public Object getResultSetValue(ResultSet resultSet) throws SQLException
+ {
+ return resultSet.getFloat(getField().getName());
+ }
+ }
+
+ /**
+ * @author Eike Stepper
+ */
+ public static class TMDouble extends AbstractTypeMapping
+ {
+ public static final String ID = ID_PREFIX + ".Double";
+
+ public static final Factory FACTORY = new Factory(TypeMappingUtil.createDescriptor(ID,
+ EcorePackage.eINSTANCE.getEDouble(), DBType.DOUBLE));
+
+ public static final String ID_OBJECT = ID_PREFIX + ".DoubleObject";
+
+ public static final Factory FACTORY_OBJECT = new Factory(TypeMappingUtil.createDescriptor(ID_OBJECT,
+ EcorePackage.eINSTANCE.getEDoubleObject(), DBType.DOUBLE));
+
+ public static class Factory extends AbstractTypeMappingFactory
+ {
+ public Factory(Descriptor descriptor)
+ {
+ super(descriptor);
+ }
+
+ @Override
+ public ITypeMapping create(String description) throws ProductCreationException
+ {
+ return new TMDouble();
+ }
+ }
+
+ @Override
+ public Object getResultSetValue(ResultSet resultSet) throws SQLException
+ {
+ return resultSet.getDouble(getField().getName());
+ }
+ }
+
+ /**
+ * @author Eike Stepper
+ */
+ public static class TMDate2Timestamp extends AbstractTypeMapping
+ {
+ public static final String ID = ID_PREFIX + ".Timestamp";
+
+ public static final Factory FACTORY = new Factory(TypeMappingUtil.createDescriptor(ID,
+ EcorePackage.eINSTANCE.getEDate(), DBType.TIMESTAMP));
+
+ public static class Factory extends AbstractTypeMappingFactory
+ {
+ public Factory(Descriptor descriptor)
+ {
+ super(descriptor);
+ }
+
+ @Override
+ public ITypeMapping create(String description) throws ProductCreationException
+ {
+ return new TMDate2Timestamp();
+ }
+ }
+
+ @Override
+ public Object getResultSetValue(ResultSet resultSet) throws SQLException
+ {
+ return resultSet.getTimestamp(getField().getName());
+ }
+
+ @Override
+ protected void doSetValue(PreparedStatement stmt, int index, Object value) throws SQLException
+ {
+ stmt.setTimestamp(index, new Timestamp(((Date)value).getTime()));
+ }
+ }
+
+ /**
+ * @author Heiko Ahlig
+ */
+ public static class TMDate2Date extends AbstractTypeMapping
+ {
+ public static final String ID = ID_PREFIX + ".Date";
+
+ public static final Factory FACTORY = new Factory(TypeMappingUtil.createDescriptor(ID,
+ EcorePackage.eINSTANCE.getEDate(), DBType.DATE));
+
+ public static class Factory extends AbstractTypeMappingFactory
+ {
+ public Factory(Descriptor descriptor)
+ {
+ super(descriptor);
+ }
+
+ @Override
+ public ITypeMapping create(String description) throws ProductCreationException
+ {
+ return new TMDate2Date();
+ }
+ }
+
+ @Override
+ public Object getResultSetValue(ResultSet resultSet) throws SQLException
+ {
+ return resultSet.getDate(getField().getName(), Calendar.getInstance());
+ }
+ }
+
+ /**
+ * @author Heiko Ahlig
+ */
+ public static class TMDate2Time extends AbstractTypeMapping
+ {
+ public static final String ID = ID_PREFIX + ".Time";
+
+ public static final Factory FACTORY = new Factory(TypeMappingUtil.createDescriptor(ID,
+ EcorePackage.eINSTANCE.getEDate(), DBType.TIME));
+
+ public static class Factory extends AbstractTypeMappingFactory
+ {
+ public Factory(Descriptor descriptor)
+ {
+ super(descriptor);
+ }
+
+ @Override
+ public ITypeMapping create(String description) throws ProductCreationException
+ {
+ return new TMDate2Time();
+ }
+ }
+
+ @Override
+ public Object getResultSetValue(ResultSet resultSet) throws SQLException
+ {
+ return resultSet.getTime(getField().getName(), Calendar.getInstance());
+ }
+ }
+
+ /**
+ * @author Eike Stepper
+ */
+ public static class TMCharacter extends AbstractTypeMapping
+ {
+ public static final String ID = ID_PREFIX + ".Character";
+
+ public static final Factory FACTORY = new Factory(TypeMappingUtil.createDescriptor(ID,
+ EcorePackage.eINSTANCE.getEChar(), DBType.CHAR));
+
+ public static final String ID_OBJECT = ID_PREFIX + ".CharacterObject";
+
+ public static final Factory FACTORY_OBJECT = new Factory(TypeMappingUtil.createDescriptor(ID_OBJECT,
+ EcorePackage.eINSTANCE.getECharacterObject(), DBType.CHAR));
+
+ public static class Factory extends AbstractTypeMappingFactory
+ {
+ public Factory(Descriptor descriptor)
+ {
+ super(descriptor);
+ }
+
+ @Override
+ public ITypeMapping create(String description) throws ProductCreationException
+ {
+ return new TMCharacter();
+ }
+ }
+
+ @Override
+ public Object getResultSetValue(ResultSet resultSet) throws SQLException
+ {
+ String str = resultSet.getString(getField().getName());
+ if (resultSet.wasNull())
+ {
+ return getFeature().isUnsettable() ? CDORevisionData.NIL : null;
+ }
+
+ return str.charAt(0);
+ }
+
+ @Override
+ protected void doSetValue(PreparedStatement stmt, int index, Object value) throws SQLException
+ {
+ stmt.setString(index, ((Character)value).toString());
+ }
+ }
+
+ /**
+ * @author Eike Stepper
+ */
+ public static class TMByte extends AbstractTypeMapping
+ {
+ public static final String ID = ID_PREFIX + ".Byte";
+
+ public static final Factory FACTORY = new Factory(TypeMappingUtil.createDescriptor(ID,
+ EcorePackage.eINSTANCE.getEByte(), DBType.SMALLINT));
+
+ public static final String ID_OBJECT = ID_PREFIX + ".ByteObject";
+
+ public static final Factory FACTORY_OBJECT = new Factory(TypeMappingUtil.createDescriptor(ID_OBJECT,
+ EcorePackage.eINSTANCE.getEByteObject(), DBType.SMALLINT));
+
+ public static class Factory extends AbstractTypeMappingFactory
+ {
+ public Factory(Descriptor descriptor)
+ {
+ super(descriptor);
+ }
+
+ @Override
+ public ITypeMapping create(String description) throws ProductCreationException
+ {
+ return new TMByte();
+ }
+ }
+
+ @Override
+ public Object getResultSetValue(ResultSet resultSet) throws SQLException
+ {
+ return resultSet.getByte(getField().getName());
+ }
+ }
+
+ /**
+ * @author Eike Stepper
+ */
+ public static class TMBytes extends AbstractTypeMapping
+ {
+ public static final String ID = ID_PREFIX + ".ByteArray";
+
+ public static final Factory FACTORY = new Factory(TypeMappingUtil.createDescriptor(ID,
+ EcorePackage.eINSTANCE.getEByteArray(), DBType.BLOB));
+
+ public static class Factory extends AbstractTypeMappingFactory
+ {
+ public Factory(Descriptor descriptor)
+ {
+ super(descriptor);
+ }
+
+ @Override
+ public ITypeMapping create(String description) throws ProductCreationException
+ {
+ return new TMBytes();
+ }
+ }
+
+ @Override
+ public Object getResultSetValue(ResultSet resultSet) throws SQLException
+ {
+ return resultSet.getBytes(getField().getName());
+ }
+ }
+
+ /**
+ * @author Eike Stepper
+ */
+ public static class TMBoolean extends AbstractTypeMapping
+ {
+ public static final String ID = ID_PREFIX + ".Boolean";
+
+ public static final Factory FACTORY = new Factory(TypeMappingUtil.createDescriptor(ID,
+ EcorePackage.eINSTANCE.getEBoolean(), DBType.BOOLEAN));
+
+ public static final String ID_OBJECT = ID_PREFIX + ".BooleanObject";
+
+ public static final Factory FACTORY_OBJECT = new Factory(TypeMappingUtil.createDescriptor(ID_OBJECT,
+ EcorePackage.eINSTANCE.getEBooleanObject(), DBType.BOOLEAN));
+
+ public static class Factory extends AbstractTypeMappingFactory
+ {
+ public Factory(Descriptor descriptor)
+ {
+ super(descriptor);
+ }
+
+ @Override
+ public ITypeMapping create(String description) throws ProductCreationException
+ {
+ return new TMBoolean();
+ }
+ }
+
+ @Override
+ public Object getResultSetValue(ResultSet resultSet) throws SQLException
+ {
+ return resultSet.getBoolean(getField().getName());
+ }
+ }
+
+ /**
+ * @author Stefan Winkler
+ */
+ public static class TMBigInteger extends AbstractTypeMapping
+ {
+ public static final String ID = ID_PREFIX + ".BigInteger";
+
+ public static final Factory FACTORY = new Factory(TypeMappingUtil.createDescriptor(ID,
+ EcorePackage.eINSTANCE.getEBigInteger(), DBType.VARCHAR));
+
+ public static class Factory extends AbstractTypeMappingFactory
+ {
+ public Factory(Descriptor descriptor)
+ {
+ super(descriptor);
+ }
+
+ @Override
+ public ITypeMapping create(String description) throws ProductCreationException
+ {
+ return new TMBigInteger();
+ }
+ }
+
+ @Override
+ protected Object getResultSetValue(ResultSet resultSet) throws SQLException
+ {
+ String val = resultSet.getString(getField().getName());
+
+ if (resultSet.wasNull())
+ {
+ return getFeature().isUnsettable() ? CDORevisionData.NIL : null;
+ }
+
+ return new BigInteger(val);
+ }
+
+ @Override
+ protected void doSetValue(PreparedStatement stmt, int index, Object value) throws SQLException
+ {
+ stmt.setString(index, ((BigInteger)value).toString());
+ }
+ }
+
+ /**
+ * @author Stefan Winkler
+ */
+ public static class TMBigDecimal extends AbstractTypeMapping
+ {
+ public static final String ID = ID_PREFIX + ".BigDecimal";
+
+ public static final Factory FACTORY = new Factory(TypeMappingUtil.createDescriptor(ID,
+ EcorePackage.eINSTANCE.getEBigDecimal(), DBType.VARCHAR));
+
+ public static class Factory extends AbstractTypeMappingFactory
+ {
+ public Factory(Descriptor descriptor)
+ {
+ super(descriptor);
+ }
+
+ @Override
+ public ITypeMapping create(String description) throws ProductCreationException
+ {
+ return new TMBigDecimal();
+ }
+ }
+
+ @Override
+ protected Object getResultSetValue(ResultSet resultSet) throws SQLException
+ {
+ String val = resultSet.getString(getField().getName());
+
+ if (resultSet.wasNull())
+ {
+ return getFeature().isUnsettable() ? CDORevisionData.NIL : null;
+ }
+
+ return new BigDecimal(val);
+ }
+
+ @Override
+ protected void doSetValue(PreparedStatement stmt, int index, Object value) throws SQLException
+ {
+ stmt.setString(index, ((BigDecimal)value).toPlainString());
+ }
+ }
+
+ /**
+ * @author Stefan Winkler
+ */
+ public static class TMCustom extends AbstractTypeMapping
+ {
+ public static final String ID_VARCHAR = ID_PREFIX + ".CustomVarchar";
+
+ public static final Factory FACTORY_VARCHAR = new Factory(TypeMappingUtil.createDescriptor(ID_VARCHAR,
+ EcorePackage.eINSTANCE.getEDataType(), DBType.VARCHAR));
+
+ public static final String ID_CLOB = ID_PREFIX + ".CustomClob";
+
+ public static final Factory FACTORY_CLOB = new Factory(TypeMappingUtil.createDescriptor(ID_CLOB,
+ EcorePackage.eINSTANCE.getEDataType(), DBType.CLOB));
+
+ public static class Factory extends AbstractTypeMappingFactory
+ {
+ public Factory(Descriptor descriptor)
+ {
+ super(descriptor);
+ }
+
+ @Override
+ public ITypeMapping create(String description) throws ProductCreationException
+ {
+ return new TMCustom();
+ }
+ }
+
+ @Override
+ protected Object getResultSetValue(ResultSet resultSet) throws SQLException
+ {
+ String val = resultSet.getString(getField().getName());
+ if (resultSet.wasNull())
+ {
+ return getFeature().isUnsettable() ? CDORevisionData.NIL : null;
+ }
+
+ return val;
+ }
+
+ @Override
+ public void setDefaultValue(PreparedStatement stmt, int index) throws SQLException
+ {
+ setValue(stmt, index, getFeature().getDefaultValueLiteral());
+ }
+ }
+}
diff --git a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/TypeMapping.java b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/TypeMapping.java
deleted file mode 100644
index cbcfbc6..0000000
--- a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/TypeMapping.java
+++ /dev/null
@@ -1,701 +0,0 @@
-/**
- * Copyright (c) 2004 - 2010 Eike Stepper (Berlin, Germany) 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:
- * Eike Stepper - initial API and implementation
- * Stefan Winkler - bug 271444: [DB] Multiple refactorings
- * Stefan Winkler - bug 275303: [DB] DBStore does not handle BIG_INTEGER and BIG_DECIMAL
- * Kai Schlamp - bug 282976: [DB] Influence Mappings through EAnnotations
- * Stefan Winkler - bug 282976: [DB] Influence Mappings through EAnnotations
- * Stefan Winkler - bug 285270: [DB] Support XSD based models
- * Heiko Ahlig - bug 309461
- */
-package org.eclipse.emf.cdo.server.internal.db.mapping;
-
-import org.eclipse.emf.cdo.common.id.CDOID;
-import org.eclipse.emf.cdo.common.revision.CDORevisionData;
-import org.eclipse.emf.cdo.server.IStoreAccessor;
-import org.eclipse.emf.cdo.server.IStoreAccessor.CommitContext;
-import org.eclipse.emf.cdo.server.StoreThreadLocal;
-import org.eclipse.emf.cdo.server.db.CDODBUtil;
-import org.eclipse.emf.cdo.server.db.IDBStore;
-import org.eclipse.emf.cdo.server.db.IDBStoreAccessor;
-import org.eclipse.emf.cdo.server.db.IExternalReferenceManager;
-import org.eclipse.emf.cdo.server.db.mapping.IMappingStrategy;
-import org.eclipse.emf.cdo.server.db.mapping.ITypeMapping;
-import org.eclipse.emf.cdo.server.internal.db.DBAnnotation;
-import org.eclipse.emf.cdo.server.internal.db.MetaDataManager;
-import org.eclipse.emf.cdo.server.internal.db.bundle.OM;
-import org.eclipse.emf.cdo.server.internal.db.messages.Messages;
-import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevision;
-
-import org.eclipse.net4j.db.DBType;
-import org.eclipse.net4j.db.ddl.IDBField;
-import org.eclipse.net4j.db.ddl.IDBTable;
-import org.eclipse.net4j.util.om.trace.ContextTracer;
-
-import org.eclipse.emf.common.util.Enumerator;
-import org.eclipse.emf.ecore.EEnum;
-import org.eclipse.emf.ecore.EEnumLiteral;
-import org.eclipse.emf.ecore.EStructuralFeature;
-
-import java.math.BigDecimal;
-import java.math.BigInteger;
-import java.sql.PreparedStatement;
-import java.sql.ResultSet;
-import java.sql.SQLException;
-import java.sql.Time;
-import java.sql.Timestamp;
-import java.text.MessageFormat;
-import java.util.Calendar;
-import java.util.Date;
-
-/**
- * This is a default implementation for the {@link ITypeMapping} interface which provides default behavor for all common
- * types.
- *
- * @author Eike Stepper
- */
-public abstract class TypeMapping implements ITypeMapping
-{
- private static final ContextTracer TRACER = new ContextTracer(OM.DEBUG, TypeMapping.class);
-
- private IMappingStrategy mappingStrategy;
-
- private EStructuralFeature feature;
-
- private IDBField field;
-
- private DBType dbType;
-
- /**
- * Create a new type mapping
- *
- * @param mappingStrategy
- * the associated mapping strategy.
- * @param feature
- * the feature to be mapped.
- */
- protected TypeMapping(IMappingStrategy mappingStrategy, EStructuralFeature feature, DBType type)
- {
- this.mappingStrategy = mappingStrategy;
- this.feature = feature;
- dbType = type;
- }
-
- public final IMappingStrategy getMappingStrategy()
- {
- return mappingStrategy;
- }
-
- public final EStructuralFeature getFeature()
- {
- return feature;
- }
-
- public final void setValueFromRevision(PreparedStatement stmt, int index, InternalCDORevision revision)
- throws SQLException
- {
- setValue(stmt, index, getRevisionValue(revision));
- }
-
- public void setDefaultValue(PreparedStatement stmt, int index) throws SQLException
- {
- setValue(stmt, index, getDefaultValue());
- }
-
- public final void setValue(PreparedStatement stmt, int index, Object value) throws SQLException
- {
- if (value == CDORevisionData.NIL)
- {
- if (TRACER.isEnabled())
- {
- TRACER.format("TypeMapping for {0}: converting Revision.NIL to DB-null", feature.getName()); //$NON-NLS-1$
- }
-
- stmt.setNull(index, getSQLType());
- }
- else if (value == null)
- {
- if (feature.isMany() || getDefaultValue() == null)
- {
- if (TRACER.isEnabled())
- {
- TRACER.format("TypeMapping for {0}: writing Revision.null as DB.null", feature.getName()); //$NON-NLS-1$
- }
-
- stmt.setNull(index, getSQLType());
- }
- else
- {
- if (TRACER.isEnabled())
- {
- TRACER.format("TypeMapping for {0}: converting Revision.null to default value", feature.getName()); //$NON-NLS-1$
- }
-
- setDefaultValue(stmt, index);
- }
- }
- else
- {
- doSetValue(stmt, index, value);
- }
- }
-
- public final void createDBField(IDBTable table)
- {
- createDBField(table, mappingStrategy.getFieldName(feature));
- }
-
- public final void createDBField(IDBTable table, String fieldName)
- {
- DBType fieldType = getDBType();
- int fieldLength = getDBLength(fieldType);
- field = table.addField(fieldName, fieldType, fieldLength);
- }
-
- public final void setDBField(IDBTable table, String fieldName)
- {
- field = table.getField(fieldName);
- }
-
- public final IDBField getField()
- {
- return field;
- }
-
- public final void readValueToRevision(ResultSet resultSet, InternalCDORevision revision) throws SQLException
- {
- Object value = readValue(resultSet);
- revision.setValue(getFeature(), value);
- }
-
- public final Object readValue(ResultSet resultSet) throws SQLException
- {
- Object value = getResultSetValue(resultSet);
- if (resultSet.wasNull())
- {
- if (feature.isMany())
- {
- if (TRACER.isEnabled())
- {
- TRACER.format("TypeMapping for {0}: read db.null - setting Revision.null", feature.getName()); //$NON-NLS-1$
- }
-
- value = null;
- }
- else
- {
- if (getDefaultValue() == null)
- {
- if (TRACER.isEnabled())
- {
- TRACER.format(
- "TypeMapping for {0}: read db.null - setting Revision.null, because of default", feature.getName()); //$NON-NLS-1$
- }
-
- value = null;
- }
- else
- {
- if (TRACER.isEnabled())
- {
- TRACER.format("TypeMapping for {0}: read db.null - setting Revision.NIL", feature.getName()); //$NON-NLS-1$
- }
-
- value = CDORevisionData.NIL;
- }
- }
- }
-
- return value;
- }
-
- protected Object getDefaultValue()
- {
- return feature.getDefaultValue();
- }
-
- protected final Object getRevisionValue(InternalCDORevision revision)
- {
- return revision.getValue(getFeature());
- }
-
- protected void doSetValue(PreparedStatement stmt, int index, Object value) throws SQLException
- {
- stmt.setObject(index, value, getSQLType());
- }
-
- /**
- * Returns the SQL type of this TypeMapping. The default implementation considers the type map hold by the meta-data
- * manager (@see {@link MetaDataManager#getDBType(org.eclipse.emf.ecore.EClassifier)} Subclasses may override.
- *
- * @return The sql type of this TypeMapping.
- */
- protected int getSQLType()
- {
- return getDBType().getCode();
- }
-
- public DBType getDBType()
- {
- return dbType;
- }
-
- protected int getDBLength(DBType type)
- {
- String value = DBAnnotation.COLUMN_LENGTH.getValue(feature);
- if (value != null)
- {
- try
- {
- return Integer.parseInt(value);
- }
- catch (NumberFormatException e)
- {
- OM.LOG.error("Illegal columnLength annotation of feature " + feature.getName());
- }
- }
-
- // TODO: implement DBAdapter.getDBLength
- // mappingStrategy.getStore().getDBAdapter().getDBLength(type);
- // which should then return the correct default field length for the db type
- return type == DBType.VARCHAR ? 32672 : IDBField.DEFAULT;
- }
-
- protected abstract Object getResultSetValue(ResultSet resultSet) throws SQLException;
-
- /**
- * @author Eike Stepper
- */
- public static class TMEnum extends TypeMapping
- {
- public TMEnum(IMappingStrategy strategy, EStructuralFeature feature, DBType type)
- {
- super(strategy, feature, type);
- }
-
- @Override
- public Object getResultSetValue(ResultSet resultSet) throws SQLException
- {
- // see Bug 271941
- return resultSet.getInt(getField().getName());
- // EEnum type = (EEnum)getFeature().getEType();
- // int value = resultSet.getInt(column);
- // return type.getEEnumLiteral(value);
- }
-
- @Override
- protected Object getDefaultValue()
- {
- EEnum eenum = (EEnum)getFeature().getEType();
-
- String defaultValueLiteral = getFeature().getDefaultValueLiteral();
- if (defaultValueLiteral != null)
- {
- EEnumLiteral literal = eenum.getEEnumLiteralByLiteral(defaultValueLiteral);
- if (literal == null)
- {
- OM.LOG.warn(MessageFormat.format(
- Messages.getString("DBStore.13"), getFeature().getDefaultValueLiteral(), getFeature())); //$NON-NLS-1$
- literal = (EEnumLiteral)eenum.getDefaultValue();
- }
-
- return literal.getValue();
- }
-
- Enumerator enumerator = (Enumerator)eenum.getDefaultValue();
- return enumerator.getValue();
- }
- }
-
- /**
- * @author Eike Stepper
- */
- public static class TMString extends TypeMapping
- {
- public TMString(IMappingStrategy strategy, EStructuralFeature feature, DBType type)
- {
- super(strategy, feature, type);
- }
-
- @Override
- public Object getResultSetValue(ResultSet resultSet) throws SQLException
- {
- return resultSet.getString(getField().getName());
- }
- }
-
- /**
- * @author Eike Stepper
- */
- public static class TMShort extends TypeMapping
- {
- public TMShort(IMappingStrategy strategy, EStructuralFeature feature, DBType type)
- {
- super(strategy, feature, type);
- }
-
- @Override
- public Object getResultSetValue(ResultSet resultSet) throws SQLException
- {
- return resultSet.getShort(getField().getName());
- }
- }
-
- /**
- * @author Eike Stepper <br>
- */
- public static class TMObject extends TypeMapping
- {
- public TMObject(IMappingStrategy strategy, EStructuralFeature feature, DBType type)
- {
- super(strategy, feature, type);
- }
-
- @Override
- public Object getResultSetValue(ResultSet resultSet) throws SQLException
- {
- long id = resultSet.getLong(getField().getName());
- if (resultSet.wasNull())
- {
- return getFeature().isUnsettable() ? CDORevisionData.NIL : null;
- }
-
- IExternalReferenceManager externalRefs = getMappingStrategy().getStore().getExternalReferenceManager();
- return CDODBUtil.convertLongToCDOID(externalRefs, getAccessor(), id);
- }
-
- @Override
- protected void doSetValue(PreparedStatement stmt, int index, Object value) throws SQLException
- {
- IDBStore store = getMappingStrategy().getStore();
- IExternalReferenceManager externalReferenceManager = store.getExternalReferenceManager();
- CommitContext commitContext = StoreThreadLocal.getCommitContext();
- long commitTime = commitContext.getBranchPoint().getTimeStamp();
- long id = CDODBUtil.convertCDOIDToLong(externalReferenceManager, getAccessor(), (CDOID)value, commitTime);
- super.doSetValue(stmt, index, id);
- }
-
- private IDBStoreAccessor getAccessor()
- {
- IStoreAccessor accessor = StoreThreadLocal.getAccessor();
- if (accessor == null)
- {
- throw new IllegalStateException("Can only be called from within a valid IDBStoreAccessor context");
- }
-
- return (IDBStoreAccessor)accessor;
- }
- }
-
- /**
- * @author Eike Stepper
- */
- public static class TMLong extends TypeMapping
- {
- public TMLong(IMappingStrategy strategy, EStructuralFeature feature, DBType type)
- {
- super(strategy, feature, type);
- }
-
- @Override
- public Object getResultSetValue(ResultSet resultSet) throws SQLException
- {
- return resultSet.getLong(getField().getName());
- }
- }
-
- /**
- * @author Eike Stepper
- */
- public static class TMInteger extends TypeMapping
- {
- public TMInteger(IMappingStrategy strategy, EStructuralFeature feature, DBType type)
- {
- super(strategy, feature, type);
- }
-
- @Override
- public Object getResultSetValue(ResultSet resultSet) throws SQLException
- {
- return resultSet.getInt(getField().getName());
- }
- }
-
- /**
- * @author Eike Stepper
- */
- public static class TMFloat extends TypeMapping
- {
- public TMFloat(IMappingStrategy strategy, EStructuralFeature feature, DBType type)
- {
- super(strategy, feature, type);
- }
-
- @Override
- public Object getResultSetValue(ResultSet resultSet) throws SQLException
- {
- return resultSet.getFloat(getField().getName());
- }
- }
-
- /**
- * @author Eike Stepper
- */
- public static class TMDouble extends TypeMapping
- {
- public TMDouble(IMappingStrategy strategy, EStructuralFeature feature, DBType type)
- {
- super(strategy, feature, type);
- }
-
- @Override
- public Object getResultSetValue(ResultSet resultSet) throws SQLException
- {
- return resultSet.getDouble(getField().getName());
- }
- }
-
- /**
- * @author Eike Stepper
- */
- public static class TMDate2Timestamp extends TypeMapping
- {
- public TMDate2Timestamp(IMappingStrategy strategy, EStructuralFeature feature, DBType type)
- {
- super(strategy, feature, type);
- }
-
- @Override
- public Object getResultSetValue(ResultSet resultSet) throws SQLException
- {
- return resultSet.getTimestamp(getField().getName());
- }
-
- @Override
- protected void doSetValue(PreparedStatement stmt, int index, Object value) throws SQLException
- {
- stmt.setTimestamp(index, new Timestamp(((Date)value).getTime()));
- }
- }
-
- /**
- * @author Heiko Ahlig
- */
- public static class TMDate2Date extends TypeMapping
- {
- public TMDate2Date(IMappingStrategy strategy, EStructuralFeature feature, DBType type)
- {
- super(strategy, feature, type);
- }
-
- @Override
- public Object getResultSetValue(ResultSet resultSet) throws SQLException
- {
- return resultSet.getDate(getField().getName(), Calendar.getInstance());
- }
-
- @Override
- protected void doSetValue(PreparedStatement stmt, int index, Object value) throws SQLException
- {
- stmt.setDate(index, new java.sql.Date(((Date)value).getTime()), Calendar.getInstance());
- }
- }
-
- /**
- * @author Heiko Ahlig
- */
- public static class TMDate2Time extends TypeMapping
- {
- public TMDate2Time(IMappingStrategy strategy, EStructuralFeature feature, DBType type)
- {
- super(strategy, feature, type);
- }
-
- @Override
- public Object getResultSetValue(ResultSet resultSet) throws SQLException
- {
- return resultSet.getTime(getField().getName(), Calendar.getInstance());
- }
-
- @Override
- protected void doSetValue(PreparedStatement stmt, int index, Object value) throws SQLException
- {
- stmt.setTime(index, new Time(((Date)value).getTime()), Calendar.getInstance());
- }
- }
-
- /**
- * @author Eike Stepper
- */
- public static class TMCharacter extends TypeMapping
- {
- public TMCharacter(IMappingStrategy strategy, EStructuralFeature feature, DBType type)
- {
- super(strategy, feature, type);
- }
-
- @Override
- public Object getResultSetValue(ResultSet resultSet) throws SQLException
- {
- String str = resultSet.getString(getField().getName());
- if (resultSet.wasNull())
- {
- return getFeature().isUnsettable() ? CDORevisionData.NIL : null;
- }
-
- return str.charAt(0);
- }
-
- @Override
- protected void doSetValue(PreparedStatement stmt, int index, Object value) throws SQLException
- {
- stmt.setString(index, ((Character)value).toString());
- }
- }
-
- /**
- * @author Eike Stepper
- */
- public static class TMByte extends TypeMapping
- {
- public TMByte(IMappingStrategy strategy, EStructuralFeature feature, DBType type)
- {
- super(strategy, feature, type);
- }
-
- @Override
- public Object getResultSetValue(ResultSet resultSet) throws SQLException
- {
- return resultSet.getByte(getField().getName());
- }
- }
-
- /**
- * @author Eike Stepper
- */
- public static class TMBytes extends TypeMapping
- {
- public TMBytes(IMappingStrategy strategy, EStructuralFeature feature, DBType type)
- {
- super(strategy, feature, type);
- }
-
- @Override
- public Object getResultSetValue(ResultSet resultSet) throws SQLException
- {
- return resultSet.getBytes(getField().getName());
- }
- }
-
- /**
- * @author Eike Stepper
- */
- public static class TMBoolean extends TypeMapping
- {
- public TMBoolean(IMappingStrategy strategy, EStructuralFeature feature, DBType type)
- {
- super(strategy, feature, type);
- }
-
- @Override
- public Object getResultSetValue(ResultSet resultSet) throws SQLException
- {
- return resultSet.getBoolean(getField().getName());
- }
- }
-
- /**
- * @author Stefan Winkler
- */
- public static class TMBigInteger extends TypeMapping
- {
- public TMBigInteger(IMappingStrategy strategy, EStructuralFeature feature, DBType type)
- {
- super(strategy, feature, type);
- }
-
- @Override
- protected Object getResultSetValue(ResultSet resultSet) throws SQLException
- {
- String val = resultSet.getString(getField().getName());
-
- if (resultSet.wasNull())
- {
- return getFeature().isUnsettable() ? CDORevisionData.NIL : null;
- }
-
- return new BigInteger(val);
- }
-
- @Override
- protected void doSetValue(PreparedStatement stmt, int index, Object value) throws SQLException
- {
- stmt.setString(index, ((BigInteger)value).toString());
- }
- }
-
- /**
- * @author Stefan Winkler
- */
- public static class TMBigDecimal extends TypeMapping
- {
- public TMBigDecimal(IMappingStrategy strategy, EStructuralFeature feature, DBType type)
- {
- super(strategy, feature, type);
- }
-
- @Override
- protected Object getResultSetValue(ResultSet resultSet) throws SQLException
- {
- String val = resultSet.getString(getField().getName());
-
- if (resultSet.wasNull())
- {
- return getFeature().isUnsettable() ? CDORevisionData.NIL : null;
- }
-
- return new BigDecimal(val);
- }
-
- @Override
- protected void doSetValue(PreparedStatement stmt, int index, Object value) throws SQLException
- {
- stmt.setString(index, ((BigDecimal)value).toPlainString());
- }
- }
-
- /**
- * @author Stefan Winkler
- */
- public static class TMCustom extends TypeMapping
- {
- public TMCustom(IMappingStrategy mappingStrategy, EStructuralFeature feature, DBType type)
- {
- super(mappingStrategy, feature, type);
- }
-
- @Override
- protected Object getResultSetValue(ResultSet resultSet) throws SQLException
- {
- String val = resultSet.getString(getField().getName());
- if (resultSet.wasNull())
- {
- return getFeature().isUnsettable() ? CDORevisionData.NIL : null;
- }
-
- return val;
- }
-
- @Override
- public void setDefaultValue(PreparedStatement stmt, int index) throws SQLException
- {
- setValue(stmt, index, getFeature().getDefaultValueLiteral());
- }
- }
-}
diff --git a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/TypeMappingDescriptor.java b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/TypeMappingDescriptor.java
new file mode 100644
index 0000000..77574b8
--- /dev/null
+++ b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/TypeMappingDescriptor.java
@@ -0,0 +1,65 @@
+/**
+ * Copyright (c) 2004 - 2010 Eike Stepper (Berlin, Germany) 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:
+ * Stefan Winkler - initial API and implementation
+ */
+package org.eclipse.emf.cdo.server.internal.db.mapping;
+
+import org.eclipse.emf.cdo.server.db.mapping.ITypeMapping;
+
+import org.eclipse.net4j.db.DBType;
+
+import org.eclipse.emf.ecore.EClassifier;
+
+/**
+ * @author Stefan Winkler
+ */
+public class TypeMappingDescriptor implements ITypeMapping.Descriptor
+{
+ private String id;
+
+ private String factoryType;
+
+ private EClassifier eClassifier;
+
+ private DBType dbType;
+
+ public TypeMappingDescriptor(String id, String factoryType, EClassifier eClassifier, DBType dbType)
+ {
+ this.id = id;
+ this.factoryType = factoryType;
+ this.eClassifier = eClassifier;
+ this.dbType = dbType;
+ }
+
+ public String getID()
+ {
+ return id;
+ }
+
+ public String getFactoryType()
+ {
+ return factoryType;
+ }
+
+ public EClassifier getEClassifier()
+ {
+ return eClassifier;
+ }
+
+ public DBType getDBType()
+ {
+ return dbType;
+ }
+
+ @Override
+ public String toString()
+ {
+ return "TypeMappingDescriptor [" + factoryType + "]";
+ }
+}
diff --git a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/TypeMappingFactory.java b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/TypeMappingFactory.java
deleted file mode 100644
index ed79245..0000000
--- a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/TypeMappingFactory.java
+++ /dev/null
@@ -1,349 +0,0 @@
-/**
- * Copyright (c) 2004 - 2010 Eike Stepper (Berlin, Germany) 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:
- * Stefan Winkler - initial API and implementation
- * Eike Stepper - maintenance
- * Stefan Winkler - bug 285270: [DB] Support XSD based models
- * Stefan Winkler - Bug 289445
- * Heiko Ahlig - bug 309461
- */
-package org.eclipse.emf.cdo.server.internal.db.mapping;
-
-import org.eclipse.emf.cdo.common.model.CDOModelUtil;
-import org.eclipse.emf.cdo.common.model.CDOType;
-import org.eclipse.emf.cdo.server.db.mapping.IMappingStrategy;
-import org.eclipse.emf.cdo.server.db.mapping.ITypeMapping;
-import org.eclipse.emf.cdo.server.internal.db.DBAnnotation;
-
-import org.eclipse.net4j.db.DBType;
-import org.eclipse.net4j.db.IDBAdapter;
-import org.eclipse.net4j.util.collection.Pair;
-
-import org.eclipse.emf.ecore.EClass;
-import org.eclipse.emf.ecore.EClassifier;
-import org.eclipse.emf.ecore.EEnum;
-import org.eclipse.emf.ecore.EStructuralFeature;
-import org.eclipse.emf.ecore.EcorePackage;
-
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
-
-/**
- * @author Stefan Winkler
- */
-public enum TypeMappingFactory
-{
- BOOLEAN_MAPPING
- {
- @Override
- public ITypeMapping doCreateTypeMapping(IMappingStrategy mappingStrategy, EStructuralFeature feature, DBType type)
- {
- return new TypeMapping.TMBoolean(mappingStrategy, feature, type);
- }
- },
-
- BYTE_MAPPING
- {
- @Override
- public ITypeMapping doCreateTypeMapping(IMappingStrategy mappingStrategy, EStructuralFeature feature, DBType type)
- {
- return new TypeMapping.TMByte(mappingStrategy, feature, type);
- }
- },
-
- CHARACTER_MAPPING
- {
- @Override
- public ITypeMapping doCreateTypeMapping(IMappingStrategy mappingStrategy, EStructuralFeature feature, DBType type)
- {
- return new TypeMapping.TMCharacter(mappingStrategy, feature, type);
- }
- },
-
- DATE2TIMESTAMP_MAPPING
- {
- @Override
- public ITypeMapping doCreateTypeMapping(IMappingStrategy mappingStrategy, EStructuralFeature feature, DBType type)
- {
- return new TypeMapping.TMDate2Timestamp(mappingStrategy, feature, type);
- }
- },
-
- DATE2DATE_MAPPING
- {
- @Override
- public ITypeMapping doCreateTypeMapping(IMappingStrategy mappingStrategy, EStructuralFeature feature, DBType type)
- {
- return new TypeMapping.TMDate2Date(mappingStrategy, feature, type);
- }
- },
-
- DATE2TIME_MAPPING
- {
- @Override
- public ITypeMapping doCreateTypeMapping(IMappingStrategy mappingStrategy, EStructuralFeature feature, DBType type)
- {
- return new TypeMapping.TMDate2Time(mappingStrategy, feature, type);
- }
- },
-
- DOUBLE_MAPPING
- {
- @Override
- public ITypeMapping doCreateTypeMapping(IMappingStrategy mappingStrategy, EStructuralFeature feature, DBType type)
- {
- return new TypeMapping.TMDouble(mappingStrategy, feature, type);
- }
- },
-
- FLOAT_MAPPING
- {
- @Override
- public ITypeMapping doCreateTypeMapping(IMappingStrategy mappingStrategy, EStructuralFeature feature, DBType type)
- {
- return new TypeMapping.TMFloat(mappingStrategy, feature, type);
- }
- },
-
- INT_MAPPING
- {
- @Override
- public ITypeMapping doCreateTypeMapping(IMappingStrategy mappingStrategy, EStructuralFeature feature, DBType type)
- {
- return new TypeMapping.TMInteger(mappingStrategy, feature, type);
- }
- },
-
- LONG_MAPPING
- {
- @Override
- public ITypeMapping doCreateTypeMapping(IMappingStrategy mappingStrategy, EStructuralFeature feature, DBType type)
- {
- return new TypeMapping.TMLong(mappingStrategy, feature, type);
- }
- },
-
- OBJECT_MAPPING
- {
- @Override
- public ITypeMapping doCreateTypeMapping(IMappingStrategy mappingStrategy, EStructuralFeature feature, DBType type)
- {
- return new TypeMapping.TMObject(mappingStrategy, feature, type);
- }
- },
-
- SHORT_MAPPING
- {
- @Override
- public ITypeMapping doCreateTypeMapping(IMappingStrategy mappingStrategy, EStructuralFeature feature, DBType type)
- {
- return new TypeMapping.TMShort(mappingStrategy, feature, type);
- }
- },
-
- ENUM_MAPPING
- {
- @Override
- public ITypeMapping doCreateTypeMapping(IMappingStrategy mappingStrategy, EStructuralFeature feature, DBType type)
- {
- return new TypeMapping.TMEnum(mappingStrategy, feature, type);
- }
- },
-
- STRING_MAPPING
- {
- @Override
- public ITypeMapping doCreateTypeMapping(IMappingStrategy mappingStrategy, EStructuralFeature feature, DBType type)
- {
- return new TypeMapping.TMString(mappingStrategy, feature, type);
- }
- },
-
- BIG_INT_MAPPING
- {
- @Override
- public ITypeMapping doCreateTypeMapping(IMappingStrategy mappingStrategy, EStructuralFeature feature, DBType type)
- {
- return new TypeMapping.TMBigInteger(mappingStrategy, feature, type);
- }
- },
-
- BIG_DECIMAL_MAPPING
- {
- @Override
- public ITypeMapping doCreateTypeMapping(IMappingStrategy mappingStrategy, EStructuralFeature feature, DBType type)
- {
- return new TypeMapping.TMBigDecimal(mappingStrategy, feature, type);
- }
- },
-
- BYTES_MAPPING
- {
- @Override
- public ITypeMapping doCreateTypeMapping(IMappingStrategy mappingStrategy, EStructuralFeature feature, DBType type)
- {
- return new TypeMapping.TMBytes(mappingStrategy, feature, type);
- }
- },
-
- CUSTOM_MAPPING
- {
- @Override
- public ITypeMapping doCreateTypeMapping(IMappingStrategy mappingStrategy, EStructuralFeature feature, DBType type)
- {
- return new TypeMapping.TMCustom(mappingStrategy, feature, type);
- }
- };
-
- private static Map<EClassifier, DBType> defaultTypeMap = new HashMap<EClassifier, DBType>();
-
- private static Map<Pair<CDOType, DBType>, TypeMappingFactory> mappingTable = new HashMap<Pair<CDOType, DBType>, TypeMappingFactory>();
-
- private static Set<DBType> defaultFeatureMapDBTypes;
-
- static
- {
- /* --- initialize default types --- */
- defaultTypeMap.put(EcorePackage.eINSTANCE.getEDate(), DBType.TIMESTAMP);
- defaultTypeMap.put(EcorePackage.eINSTANCE.getEString(), DBType.VARCHAR);
- defaultTypeMap.put(EcorePackage.eINSTANCE.getEByteArray(), DBType.BLOB);
-
- defaultTypeMap.put(EcorePackage.eINSTANCE.getEBoolean(), DBType.BOOLEAN);
- defaultTypeMap.put(EcorePackage.eINSTANCE.getEByte(), DBType.SMALLINT);
- defaultTypeMap.put(EcorePackage.eINSTANCE.getEChar(), DBType.CHAR);
- defaultTypeMap.put(EcorePackage.eINSTANCE.getEDouble(), DBType.DOUBLE);
- defaultTypeMap.put(EcorePackage.eINSTANCE.getEFloat(), DBType.FLOAT);
- defaultTypeMap.put(EcorePackage.eINSTANCE.getEInt(), DBType.INTEGER);
- defaultTypeMap.put(EcorePackage.eINSTANCE.getELong(), DBType.BIGINT);
- defaultTypeMap.put(EcorePackage.eINSTANCE.getEShort(), DBType.SMALLINT);
-
- defaultTypeMap.put(EcorePackage.eINSTANCE.getEBooleanObject(), DBType.BOOLEAN);
- defaultTypeMap.put(EcorePackage.eINSTANCE.getEByteObject(), DBType.SMALLINT);
- defaultTypeMap.put(EcorePackage.eINSTANCE.getECharacterObject(), DBType.CHAR);
- defaultTypeMap.put(EcorePackage.eINSTANCE.getEDoubleObject(), DBType.DOUBLE);
- defaultTypeMap.put(EcorePackage.eINSTANCE.getEFloatObject(), DBType.FLOAT);
- defaultTypeMap.put(EcorePackage.eINSTANCE.getEIntegerObject(), DBType.INTEGER);
- defaultTypeMap.put(EcorePackage.eINSTANCE.getELongObject(), DBType.BIGINT);
- defaultTypeMap.put(EcorePackage.eINSTANCE.getEShortObject(), DBType.SMALLINT);
-
- /* --- register type mappings --- */
- mappingTable.put(new Pair<CDOType, DBType>(CDOType.BIG_INTEGER, DBType.VARCHAR), BIG_INT_MAPPING);
- mappingTable.put(new Pair<CDOType, DBType>(CDOType.BIG_DECIMAL, DBType.VARCHAR), BIG_DECIMAL_MAPPING);
-
- mappingTable.put(new Pair<CDOType, DBType>(CDOType.BOOLEAN, DBType.BOOLEAN), BOOLEAN_MAPPING);
- mappingTable.put(new Pair<CDOType, DBType>(CDOType.BOOLEAN_OBJECT, DBType.BOOLEAN), BOOLEAN_MAPPING);
-
- mappingTable.put(new Pair<CDOType, DBType>(CDOType.BYTE, DBType.SMALLINT), BYTE_MAPPING);
- mappingTable.put(new Pair<CDOType, DBType>(CDOType.BYTE_OBJECT, DBType.SMALLINT), BYTE_MAPPING);
-
- mappingTable.put(new Pair<CDOType, DBType>(CDOType.BYTE_ARRAY, DBType.BLOB), BYTES_MAPPING);
-
- mappingTable.put(new Pair<CDOType, DBType>(CDOType.CHAR, DBType.CHAR), CHARACTER_MAPPING);
- mappingTable.put(new Pair<CDOType, DBType>(CDOType.CHARACTER_OBJECT, DBType.CHAR), CHARACTER_MAPPING);
-
- mappingTable.put(new Pair<CDOType, DBType>(CDOType.DATE, DBType.TIMESTAMP), DATE2TIMESTAMP_MAPPING);
- mappingTable.put(new Pair<CDOType, DBType>(CDOType.DATE, DBType.DATE), DATE2DATE_MAPPING);
- mappingTable.put(new Pair<CDOType, DBType>(CDOType.DATE, DBType.TIME), DATE2TIME_MAPPING);
-
- mappingTable.put(new Pair<CDOType, DBType>(CDOType.DOUBLE, DBType.DOUBLE), DOUBLE_MAPPING);
- mappingTable.put(new Pair<CDOType, DBType>(CDOType.DOUBLE_OBJECT, DBType.DOUBLE), DOUBLE_MAPPING);
-
- mappingTable.put(new Pair<CDOType, DBType>(CDOType.ENUM_ORDINAL, DBType.INTEGER), ENUM_MAPPING);
-
- mappingTable.put(new Pair<CDOType, DBType>(CDOType.FLOAT, DBType.FLOAT), FLOAT_MAPPING);
- mappingTable.put(new Pair<CDOType, DBType>(CDOType.FLOAT_OBJECT, DBType.FLOAT), FLOAT_MAPPING);
-
- mappingTable.put(new Pair<CDOType, DBType>(CDOType.INT, DBType.INTEGER), INT_MAPPING);
- mappingTable.put(new Pair<CDOType, DBType>(CDOType.INTEGER_OBJECT, DBType.INTEGER), INT_MAPPING);
-
- mappingTable.put(new Pair<CDOType, DBType>(CDOType.LONG, DBType.BIGINT), LONG_MAPPING);
- mappingTable.put(new Pair<CDOType, DBType>(CDOType.LONG_OBJECT, DBType.BIGINT), LONG_MAPPING);
-
- mappingTable.put(new Pair<CDOType, DBType>(CDOType.OBJECT, DBType.BIGINT), OBJECT_MAPPING);
-
- mappingTable.put(new Pair<CDOType, DBType>(CDOType.SHORT, DBType.SMALLINT), SHORT_MAPPING);
- mappingTable.put(new Pair<CDOType, DBType>(CDOType.SHORT_OBJECT, DBType.SMALLINT), SHORT_MAPPING);
-
- mappingTable.put(new Pair<CDOType, DBType>(CDOType.STRING, DBType.VARCHAR), STRING_MAPPING);
- mappingTable.put(new Pair<CDOType, DBType>(CDOType.STRING, DBType.CLOB), STRING_MAPPING);
-
- mappingTable.put(new Pair<CDOType, DBType>(CDOType.CUSTOM, DBType.VARCHAR), CUSTOM_MAPPING);
- mappingTable.put(new Pair<CDOType, DBType>(CDOType.CUSTOM, DBType.CLOB), CUSTOM_MAPPING);
-
- defaultFeatureMapDBTypes = new HashSet<DBType>(defaultTypeMap.values());
- }
-
- protected abstract ITypeMapping doCreateTypeMapping(IMappingStrategy mappingStrategy, EStructuralFeature feature,
- DBType type);
-
- public static ITypeMapping createTypeMapping(IMappingStrategy mappingStrategy, EStructuralFeature feature)
- {
- CDOType cdoType = CDOModelUtil.getType(feature);
- DBType dbType = getDBType(feature, mappingStrategy.getStore().getDBAdapter());
-
- TypeMappingFactory concreteFactory = mappingTable.get(new Pair<CDOType, DBType>(cdoType, dbType));
- if (concreteFactory == null)
- {
- throw new IllegalArgumentException("No suitable mapping found from EMF type " + cdoType.getName()
- + " to DB type " + dbType.getClass().getSimpleName());
- }
-
- return concreteFactory.doCreateTypeMapping(mappingStrategy, feature, dbType);
- }
-
- private static DBType getDBType(EStructuralFeature feature, IDBAdapter dbAdapter)
- {
- String typeKeyword = DBAnnotation.COLUMN_TYPE.getValue(feature);
- if (typeKeyword != null)
- {
- DBType dbType = DBType.getTypeByKeyword(typeKeyword);
- if (dbType == null)
- {
- throw new IllegalArgumentException("Unsupported columnType (" + typeKeyword + ") annotation of feature "
- + feature.getName());
- }
-
- return dbType;
- }
-
- // No annotation present - lookup default DB type.
- return getDefaultDBType(feature.getEType(), dbAdapter);
- }
-
- private static DBType getDefaultDBType(EClassifier type, IDBAdapter dbAdapter)
- {
- // Fallback (e.g., for CUSTOM types)
- DBType result = DBType.VARCHAR;
- if (type instanceof EClass)
- {
- result = DBType.BIGINT;
- }
-
- if (type instanceof EEnum)
- {
- result = DBType.INTEGER;
- }
-
- DBType dbType = defaultTypeMap.get(type);
- if (dbType != null)
- {
- result = dbType;
- }
-
- // Give the DBAdapter a chance to override the default type, if it's not supported
- return dbAdapter.adaptType(result);
- }
-
- public static Collection<DBType> getDefaultFeatureMapDBTypes()
- {
- return defaultFeatureMapDBTypes;
- }
-}
diff --git a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/TypeMappingRegistry.java b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/TypeMappingRegistry.java
new file mode 100644
index 0000000..9b5eb75
--- /dev/null
+++ b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/TypeMappingRegistry.java
@@ -0,0 +1,430 @@
+/**
+ * Copyright (c) 2004 - 2010 Eike Stepper (Berlin, Germany) 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:
+ * Stefan Winkler - initial API and implementation
+ * Stefan Winkler - Bug 285426: [DB] Implement user-defined typeMapping support
+ */
+package org.eclipse.emf.cdo.server.internal.db.mapping;
+
+import org.eclipse.emf.cdo.common.model.CDOModelUtil;
+import org.eclipse.emf.cdo.server.db.mapping.IMappingStrategy;
+import org.eclipse.emf.cdo.server.db.mapping.ITypeMapping;
+import org.eclipse.emf.cdo.server.internal.db.DBAnnotation;
+import org.eclipse.emf.cdo.server.internal.db.bundle.OM;
+import org.eclipse.emf.cdo.server.internal.db.mapping.TypeMappingUtil.FactoryTypeParserException;
+import org.eclipse.emf.cdo.server.internal.db.messages.Messages;
+
+import org.eclipse.net4j.db.DBType;
+import org.eclipse.net4j.db.IDBAdapter;
+import org.eclipse.net4j.util.collection.Pair;
+import org.eclipse.net4j.util.container.ContainerEvent;
+import org.eclipse.net4j.util.container.IContainerDelta;
+import org.eclipse.net4j.util.container.IContainerDelta.Kind;
+import org.eclipse.net4j.util.container.IManagedContainer;
+import org.eclipse.net4j.util.container.IPluginContainer;
+import org.eclipse.net4j.util.event.IEvent;
+import org.eclipse.net4j.util.event.IListener;
+import org.eclipse.net4j.util.factory.IFactory;
+import org.eclipse.net4j.util.factory.IFactoryKey;
+import org.eclipse.net4j.util.om.trace.ContextTracer;
+
+import org.eclipse.emf.ecore.EClass;
+import org.eclipse.emf.ecore.EClassifier;
+import org.eclipse.emf.ecore.EEnum;
+import org.eclipse.emf.ecore.EStructuralFeature;
+import org.eclipse.emf.ecore.EcorePackage;
+
+import java.text.MessageFormat;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+
+/**
+ * An implementation of both the Registry and Provider interfaces for type mappings. This class is a singleton which
+ * keeps itself in sync with the global factory registry. It reads the available factoryTypes for the type mappings
+ * product type and populates indexes which make it easier to determine and look up the correct factories for a needed
+ * type mapping.
+ *
+ * @author Stefan Winkler
+ */
+public class TypeMappingRegistry implements ITypeMapping.Registry, ITypeMapping.Provider
+{
+ private static final ContextTracer TRACER = new ContextTracer(OM.DEBUG, TypeMappingRegistry.class);
+
+ /**
+ * Contains a map from model types to db types which represent default mappings. (I.e., if a model element without db
+ * type annotation is encountered, this map is consulted to retrieve the default type mapping. This map is populated
+ * on a come-first basis. The first mapping for a particular {@link EClassifier} is set as default.
+ */
+ private Map<EClassifier, DBType> classifierDefaultMapping;
+
+ /**
+ * The main TypeMapping index. For any known pair of model and db types the {@link ITypeMapping.Descriptor} is
+ * registered here.
+ */
+ private Map<Pair<EClassifier, DBType>, ITypeMapping.Descriptor> typeMappingByTypes;
+
+ /**
+ * ID-based index. Can be used to lookup an {@link ITypeMapping.Descriptor} for a given ID.
+ */
+ private Map<String, ITypeMapping.Descriptor> typeMappingsById;
+
+ /**
+ * A set of all known mapped DBTypes. This is needed for the feature map mappings.
+ */
+ private Set<DBType> defaultFeatureMapDBTypes;
+
+ /**
+ * A populator which is used to keep the registry in sync with the registered factories of the
+ * {@link IManagedContainer}.
+ */
+ private RegistryPopulator populator = null;
+
+ public TypeMappingRegistry()
+ {
+ defaultFeatureMapDBTypes = new HashSet<DBType>();
+ typeMappingsById = new HashMap<String, ITypeMapping.Descriptor>();
+ typeMappingByTypes = new HashMap<Pair<EClassifier, DBType>, ITypeMapping.Descriptor>();
+ classifierDefaultMapping = new HashMap<EClassifier, DBType>();
+
+ registerCoreTypeMappings();
+
+ // connect to extension registry
+ populator = new RegistryPopulator();
+ populator.connect();
+ }
+
+ /**
+ * Register builtin type mapping factories
+ */
+ private void registerCoreTypeMappings()
+ {
+ // initialize default source and target type pairs
+ IManagedContainer container = IPluginContainer.INSTANCE;
+
+ classifierDefaultMapping.put(EcorePackage.eINSTANCE.getEBigDecimal(), DBType.VARCHAR);
+ container.registerFactory(CoreTypeMappings.TMBigDecimal.FACTORY);
+
+ classifierDefaultMapping.put(EcorePackage.eINSTANCE.getEBigInteger(), DBType.VARCHAR);
+ container.registerFactory(CoreTypeMappings.TMBigInteger.FACTORY);
+
+ classifierDefaultMapping.put(EcorePackage.eINSTANCE.getEBoolean(), DBType.BOOLEAN);
+ container.registerFactory(CoreTypeMappings.TMBoolean.FACTORY);
+
+ classifierDefaultMapping.put(EcorePackage.eINSTANCE.getEBooleanObject(), DBType.BOOLEAN);
+ container.registerFactory(CoreTypeMappings.TMBoolean.FACTORY_OBJECT);
+
+ classifierDefaultMapping.put(EcorePackage.eINSTANCE.getEByte(), DBType.SMALLINT);
+ container.registerFactory(CoreTypeMappings.TMByte.FACTORY);
+
+ classifierDefaultMapping.put(EcorePackage.eINSTANCE.getEByteObject(), DBType.SMALLINT);
+ container.registerFactory(CoreTypeMappings.TMByte.FACTORY_OBJECT);
+
+ classifierDefaultMapping.put(EcorePackage.eINSTANCE.getEByteArray(), DBType.BLOB);
+ container.registerFactory(CoreTypeMappings.TMBytes.FACTORY);
+
+ classifierDefaultMapping.put(EcorePackage.eINSTANCE.getEChar(), DBType.CHAR);
+ container.registerFactory(CoreTypeMappings.TMCharacter.FACTORY);
+
+ classifierDefaultMapping.put(EcorePackage.eINSTANCE.getECharacterObject(), DBType.CHAR);
+ container.registerFactory(CoreTypeMappings.TMCharacter.FACTORY_OBJECT);
+
+ classifierDefaultMapping.put(EcorePackage.eINSTANCE.getEDataType(), DBType.VARCHAR);
+ container.registerFactory(CoreTypeMappings.TMCustom.FACTORY_VARCHAR);
+ container.registerFactory(CoreTypeMappings.TMCustom.FACTORY_CLOB);
+
+ classifierDefaultMapping.put(EcorePackage.eINSTANCE.getEDate(), DBType.TIMESTAMP);
+ container.registerFactory(CoreTypeMappings.TMDate2Date.FACTORY);
+ container.registerFactory(CoreTypeMappings.TMDate2Time.FACTORY);
+ container.registerFactory(CoreTypeMappings.TMDate2Timestamp.FACTORY);
+
+ classifierDefaultMapping.put(EcorePackage.eINSTANCE.getEDouble(), DBType.DOUBLE);
+ container.registerFactory(CoreTypeMappings.TMDouble.FACTORY);
+
+ classifierDefaultMapping.put(EcorePackage.eINSTANCE.getEDoubleObject(), DBType.DOUBLE);
+ container.registerFactory(CoreTypeMappings.TMDouble.FACTORY_OBJECT);
+
+ classifierDefaultMapping.put(EcorePackage.eINSTANCE.getEEnum(), DBType.INTEGER);
+ container.registerFactory(CoreTypeMappings.TMEnum.FACTORY);
+
+ classifierDefaultMapping.put(EcorePackage.eINSTANCE.getEFloat(), DBType.FLOAT);
+ container.registerFactory(CoreTypeMappings.TMFloat.FACTORY);
+
+ classifierDefaultMapping.put(EcorePackage.eINSTANCE.getEFloatObject(), DBType.FLOAT);
+ container.registerFactory(CoreTypeMappings.TMFloat.FACTORY_OBJECT);
+
+ classifierDefaultMapping.put(EcorePackage.eINSTANCE.getEInt(), DBType.INTEGER);
+ container.registerFactory(CoreTypeMappings.TMInteger.FACTORY);
+
+ classifierDefaultMapping.put(EcorePackage.eINSTANCE.getEIntegerObject(), DBType.INTEGER);
+ container.registerFactory(CoreTypeMappings.TMInteger.FACTORY_OBJECT);
+
+ classifierDefaultMapping.put(EcorePackage.eINSTANCE.getELong(), DBType.BIGINT);
+ container.registerFactory(CoreTypeMappings.TMLong.FACTORY);
+
+ classifierDefaultMapping.put(EcorePackage.eINSTANCE.getELongObject(), DBType.BIGINT);
+ container.registerFactory(CoreTypeMappings.TMLong.FACTORY_OBJECT);
+
+ classifierDefaultMapping.put(EcorePackage.eINSTANCE.getEClass(), DBType.BIGINT);
+ container.registerFactory(CoreTypeMappings.TMObject.FACTORY);
+
+ classifierDefaultMapping.put(EcorePackage.eINSTANCE.getEShort(), DBType.SMALLINT);
+ container.registerFactory(CoreTypeMappings.TMShort.FACTORY);
+
+ classifierDefaultMapping.put(EcorePackage.eINSTANCE.getEShortObject(), DBType.SMALLINT);
+ container.registerFactory(CoreTypeMappings.TMShort.FACTORY_OBJECT);
+
+ classifierDefaultMapping.put(EcorePackage.eINSTANCE.getEString(), DBType.VARCHAR);
+ container.registerFactory(CoreTypeMappings.TMString.FACTORY_VARCHAR);
+ container.registerFactory(CoreTypeMappings.TMString.FACTORY_CLOB);
+ }
+
+ public void registerTypeMapping(ITypeMapping.Descriptor descriptor)
+ {
+ if (TRACER.isEnabled())
+ {
+ TRACER.format("Registering {0}", descriptor);
+ }
+
+ EClassifier eClassifier = descriptor.getEClassifier();
+ DBType dbType = descriptor.getDBType();
+ Pair<EClassifier, DBType> sourceTargetPair = new Pair<EClassifier, DBType>(eClassifier, dbType);
+
+ // currently we do not support more than one typeMapping per source-target type pair
+ if (typeMappingByTypes.containsKey(sourceTargetPair))
+ {
+ OM.LOG.error(Messages.getString("TypeMappingRegistry.4"));
+ return;
+ }
+
+ if (typeMappingsById.containsKey(descriptor.getID()))
+ {
+ OM.LOG.error(MessageFormat.format(Messages.getString("TypeMappingRegistry.5"), descriptor.getID()));
+ return;
+ }
+
+ typeMappingsById.put(descriptor.getID(), descriptor);
+
+ // register first dbType for classifier as default
+ if (!classifierDefaultMapping.containsKey(eClassifier))
+ {
+ classifierDefaultMapping.put(eClassifier, dbType);
+ }
+
+ defaultFeatureMapDBTypes.add(dbType);
+
+ typeMappingByTypes.put(sourceTargetPair, descriptor);
+ }
+
+ public ITypeMapping createTypeMapping(IMappingStrategy mappingStrategy, EStructuralFeature feature)
+ {
+ EClassifier classifier = getEClassifier(feature);
+ DBType dbType = getDBType(feature, mappingStrategy.getStore().getDBAdapter());
+
+ String typeMappingID = DBAnnotation.TYPE_MAPPING.getValue(feature);
+
+ ITypeMapping.Descriptor descriptor = null;
+
+ if (typeMappingID != null)
+ {
+ // lookup annotated mapping
+ descriptor = typeMappingsById.get(typeMappingID);
+
+ if (descriptor == null)
+ {
+ OM.LOG.warn(MessageFormat.format(Messages.getString("TypeMappingRegistry.2"), //
+ typeMappingID, feature.toString()));
+ }
+ }
+
+ if (descriptor == null)
+ {
+ // try to find suitable mapping by type
+ descriptor = getMappingByType(feature, dbType);
+ }
+
+ if (descriptor == null)
+ {
+ throw new IllegalStateException(MessageFormat.format(Messages.getString("TypeMappingRegistry.1"),
+ feature.getName(), classifier.getName(), dbType.getKeyword()));
+ }
+
+ IFactory factory = getManagedContainer()
+ .getFactory(ITypeMapping.Factory.PRODUCT_GROUP, descriptor.getFactoryType());
+ ITypeMapping typeMapping = (ITypeMapping)factory.create(null);
+ typeMapping.setMappingStrategy(mappingStrategy);
+ typeMapping.setFeature(feature);
+ typeMapping.setDBType(dbType);
+ return typeMapping;
+ }
+
+ private IManagedContainer getManagedContainer()
+ {
+ return IPluginContainer.INSTANCE;
+ }
+
+ private EClassifier getEClassifier(EStructuralFeature feature)
+ {
+ EClassifier classifier = feature.getEType();
+ if (classifier instanceof EEnum)
+ {
+ return EcorePackage.eINSTANCE.getEEnum();
+ }
+
+ if (classifier instanceof EClass)
+ {
+ return EcorePackage.eINSTANCE.getEClass();
+ }
+
+ if (!CDOModelUtil.isCorePackage(classifier.getEPackage()))
+ {
+ return EcorePackage.eINSTANCE.getEDataType();
+ }
+
+ return classifier;
+ }
+
+ private DBType getDBType(EStructuralFeature feature, IDBAdapter dbAdapter)
+ {
+ String typeKeyword = DBAnnotation.COLUMN_TYPE.getValue(feature);
+ if (typeKeyword != null)
+ {
+ DBType dbType = DBType.getTypeByKeyword(typeKeyword);
+ if (dbType == null)
+ {
+ throw new IllegalArgumentException("Unsupported columnType (" + typeKeyword + ") annotation of feature "
+ + feature.getName());
+ }
+
+ return dbType;
+ }
+
+ // No annotation present - lookup default DB type.
+ return getDefaultDBType(getEClassifier(feature), dbAdapter);
+ }
+
+ private DBType getDefaultDBType(EClassifier type, IDBAdapter dbAdapter)
+ {
+ DBType result = classifierDefaultMapping.get(type);
+
+ if (result == null)
+ {
+ result = DBType.VARCHAR;
+ }
+
+ // Give the DBAdapter a chance to override the default type, if it's not supported
+ return dbAdapter.adaptType(result);
+ }
+
+ private ITypeMapping.Descriptor getMappingByType(EStructuralFeature feature, DBType dbType)
+ {
+ // First try: lookup specific mapping for the immediate type.
+ ITypeMapping.Descriptor descriptor = typeMappingByTypes.get(new Pair<EClassifier, DBType>(feature.getEType(),
+ dbType));
+
+ if (descriptor == null)
+ {
+ // Second try: lookup general mapping
+ descriptor = typeMappingByTypes.get(new Pair<EClassifier, DBType>(getEClassifier(feature), dbType));
+ if (descriptor == null)
+ {
+ // Lookup failed. Give up
+ return null;
+ }
+ }
+
+ return descriptor;
+ }
+
+ public Collection<DBType> getDefaultFeatureMapDBTypes()
+ {
+ return defaultFeatureMapDBTypes;
+ }
+
+ /**
+ * Keeps the {@link TypeMappingRegistry} in sync with {@link IManagedContainer#getFactoryRegistry()}.
+ *
+ * @author Stefan Winkler
+ */
+ private class RegistryPopulator implements IListener
+ {
+ private IManagedContainer container;
+
+ public RegistryPopulator()
+ {
+ }
+
+ /**
+ * Connect to the factory registry.
+ */
+ public void connect()
+ {
+ container = getManagedContainer();
+ populateTypeMappingRegistry();
+ container.getFactoryRegistry().addListener(this);
+ }
+
+ private void populateTypeMappingRegistry()
+ {
+ // get available factory types
+ Set<String> factoryTypes = container.getFactoryTypes(ITypeMapping.Factory.PRODUCT_GROUP);
+
+ // parse the descriptor of each factory type
+ for (String factoryType : factoryTypes)
+ {
+ registerFactoryType(factoryType);
+ }
+ }
+
+ private void registerFactoryType(String factoryType)
+ {
+ ITypeMapping.Descriptor desc;
+
+ try
+ {
+ desc = TypeMappingUtil.descriptorFromFactoryType(factoryType);
+ registerTypeMapping(desc);
+ }
+ catch (FactoryTypeParserException ex)
+ {
+ OM.LOG.warn(ex);
+ }
+ }
+
+ public void notifyEvent(IEvent event)
+ {
+ if (event instanceof ContainerEvent<?>)
+ {
+ @SuppressWarnings("unchecked")
+ ContainerEvent<Map.Entry<IFactoryKey, IFactory>> ev = (ContainerEvent<Entry<IFactoryKey, IFactory>>)event;
+
+ for (IContainerDelta<Map.Entry<IFactoryKey, IFactory>> delta : ev.getDeltas())
+ {
+ IFactoryKey key = delta.getElement().getKey();
+ if (key.getProductGroup().equals(ITypeMapping.Factory.PRODUCT_GROUP))
+ {
+ if (delta.getKind() == Kind.ADDED)
+ {
+ String factoryType = delta.getElement().getKey().getType();
+ registerFactoryType(factoryType);
+ }
+ else
+ // delta.getKind() == Kind.REMOVED
+ {
+ // XXX Runtime removal of typeMappingFactories removal of type mappings is currently not supported.
+ OM.LOG.warn(Messages.getString("TypeMappingRegistry.3"));
+ }
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/TypeMappingUtil.java b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/TypeMappingUtil.java
new file mode 100644
index 0000000..32240c6
--- /dev/null
+++ b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/TypeMappingUtil.java
@@ -0,0 +1,113 @@
+/**
+ * Copyright (c) 2004 - 2010 Eike Stepper (Berlin, Germany) 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:
+ * Eike Stepper - initial API and implementation
+ */
+package org.eclipse.emf.cdo.server.internal.db.mapping;
+
+import org.eclipse.emf.cdo.server.db.mapping.ITypeMapping;
+import org.eclipse.emf.cdo.server.internal.db.messages.Messages;
+
+import org.eclipse.net4j.db.DBType;
+
+import org.eclipse.emf.ecore.EClassifier;
+import org.eclipse.emf.ecore.EPackage;
+
+import java.text.MessageFormat;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * @author Stefan Winkler
+ */
+public class TypeMappingUtil
+{
+ private static final Pattern FACTORY_DESCRIPTOR_PATTERN = Pattern.compile("(.+);(.+)#(.+)->(.+)");
+
+ /**
+ * Utility class - no instantiation.
+ */
+ private TypeMappingUtil()
+ {
+ }
+
+ public static ITypeMapping.Descriptor createDescriptor(String id, EClassifier eClassifier, DBType dbType)
+ {
+ String factoryType = createFactoryType(id, eClassifier, dbType);
+ return new TypeMappingDescriptor(id, factoryType, eClassifier, dbType);
+ }
+
+ public static String createFactoryType(String id, EClassifier eClassifier, DBType dbType)
+ {
+ StringBuilder builder = new StringBuilder();
+
+ // id
+ builder.append(id);
+ builder.append(";");
+
+ // classifier
+ builder.append(eClassifier.getEPackage().getNsURI());
+ builder.append("#");
+ builder.append(eClassifier.getName());
+ builder.append("->");
+
+ // dbtype
+ builder.append(dbType.getKeyword());
+
+ return builder.toString();
+ }
+
+ public static ITypeMapping.Descriptor descriptorFromFactoryType(String factoryType) throws FactoryTypeParserException
+ {
+ Matcher matcher = FACTORY_DESCRIPTOR_PATTERN.matcher(factoryType);
+
+ if (!matcher.matches())
+ {
+ throw new FactoryTypeParserException(MessageFormat.format(Messages.getString("FactoryTypeParserException.1"),
+ factoryType));
+ }
+
+ String id = matcher.group(1);
+ String packageUri = matcher.group(2);
+ String classifierName = matcher.group(3);
+ String typeKeyword = matcher.group(4);
+
+ EPackage ePackage = EPackage.Registry.INSTANCE.getEPackage(packageUri);
+ if (ePackage == null)
+ {
+ throw new FactoryTypeParserException(MessageFormat.format(Messages.getString("FactoryTypeParserException.2"),
+ packageUri, factoryType));
+ }
+
+ EClassifier eClassifier = ePackage.getEClassifier(classifierName);
+ if (eClassifier == null)
+ {
+ throw new FactoryTypeParserException(MessageFormat.format(Messages.getString("FactoryTypeParserException.3"),
+ classifierName, factoryType));
+ }
+
+ DBType dbType = DBType.getTypeByKeyword(typeKeyword);
+ if (dbType == null)
+ {
+ throw new FactoryTypeParserException(MessageFormat.format(Messages.getString("FactoryTypeParserException.4"),
+ dbType, factoryType));
+ }
+
+ return new TypeMappingDescriptor(id, factoryType, eClassifier, dbType);
+ }
+
+ public static class FactoryTypeParserException extends Exception
+ {
+ private static final long serialVersionUID = 1L;
+
+ public FactoryTypeParserException(String desc)
+ {
+ super(desc);
+ }
+ }
+}
diff --git a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/AbstractFeatureMapTableMapping.java b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/AbstractFeatureMapTableMapping.java
index adfbf9d..8ccc649 100644
--- a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/AbstractFeatureMapTableMapping.java
+++ b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/AbstractFeatureMapTableMapping.java
@@ -10,6 +10,7 @@
* Stefan Winkler - 271444: [DB] Multiple refactorings bug 271444
* Christopher Albert - 254455: [DB] Support FeatureMaps bug 254455
* Victor Roldan Betancort - Bug 283998: [DB] Chunk reading for multiple chunks fails
+ * Stefan Winkler - Bug 285426: [DB] Implement user-defined typeMapping support
*/
package org.eclipse.emf.cdo.server.internal.db.mapping.horizontal;
@@ -27,8 +28,6 @@ import org.eclipse.emf.cdo.server.db.mapping.IMappingStrategy;
import org.eclipse.emf.cdo.server.db.mapping.ITypeMapping;
import org.eclipse.emf.cdo.server.internal.db.CDODBSchema;
import org.eclipse.emf.cdo.server.internal.db.bundle.OM;
-import org.eclipse.emf.cdo.server.internal.db.mapping.TypeMapping;
-import org.eclipse.emf.cdo.server.internal.db.mapping.TypeMappingFactory;
import org.eclipse.emf.cdo.spi.common.revision.InternalCDOList;
import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevision;
@@ -109,7 +108,13 @@ public abstract class AbstractFeatureMapTableMapping extends BasicAbstractListTa
private void initDBTypes()
{
// TODO add annotation processing here ...
- dbTypes = new ArrayList<DBType>(TypeMappingFactory.getDefaultFeatureMapDBTypes());
+ ITypeMapping.Registry registry = getTypeMappingRegistry();
+ dbTypes = new ArrayList<DBType>(registry.getDefaultFeatureMapDBTypes());
+ }
+
+ protected ITypeMapping.Registry getTypeMappingRegistry()
+ {
+ return ITypeMapping.Registry.INSTANCE;
}
private void initTable()
@@ -369,7 +374,7 @@ public abstract class AbstractFeatureMapTableMapping extends BasicAbstractListTa
{
EStructuralFeature modelFeature = getFeatureByTag(tag);
- TypeMapping typeMapping = (TypeMapping)getMappingStrategy().createValueMapping(modelFeature);
+ ITypeMapping typeMapping = getMappingStrategy().createValueMapping(modelFeature);
String column = CDODBSchema.FEATUREMAP_VALUE + "_" + typeMapping.getDBType();
tagMap.put(tag, column);
diff --git a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/AuditFeatureMapTableMappingWithRanges.java b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/AuditFeatureMapTableMappingWithRanges.java
index 5ed0878..5fd72fe 100644
--- a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/AuditFeatureMapTableMappingWithRanges.java
+++ b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/AuditFeatureMapTableMappingWithRanges.java
@@ -11,7 +11,8 @@
* Christopher Albert - Bug 254455: [DB] Support FeatureMaps bug 254455
* Victor Roldan Betancort - Bug 283998: [DB] Chunk reading for multiple chunks fails
* Lothar Werzinger - Bug 296440: [DB] Change RDB schema to improve scalability of to-many references in audit mode
- * Stefan Winkler - cleanup, merge and maintenance *
+ * Stefan Winkler - cleanup, merge and maintenance
+ * Stefan Winkler - Bug 285426: [DB] Implement user-defined typeMapping support
*/
package org.eclipse.emf.cdo.server.internal.db.mapping.horizontal;
@@ -44,8 +45,6 @@ import org.eclipse.emf.cdo.server.db.mapping.IMappingStrategy;
import org.eclipse.emf.cdo.server.db.mapping.ITypeMapping;
import org.eclipse.emf.cdo.server.internal.db.CDODBSchema;
import org.eclipse.emf.cdo.server.internal.db.bundle.OM;
-import org.eclipse.emf.cdo.server.internal.db.mapping.TypeMapping;
-import org.eclipse.emf.cdo.server.internal.db.mapping.TypeMappingFactory;
import org.eclipse.emf.cdo.spi.common.revision.InternalCDOList;
import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevision;
@@ -153,7 +152,8 @@ public class AuditFeatureMapTableMappingWithRanges extends BasicAbstractListTabl
private void initDBTypes()
{
// TODO add annotation processing here ...
- dbTypes = new ArrayList<DBType>(TypeMappingFactory.getDefaultFeatureMapDBTypes());
+ ITypeMapping.Registry registry = ITypeMapping.Registry.INSTANCE;
+ dbTypes = new ArrayList<DBType>(registry.getDefaultFeatureMapDBTypes());
}
private void initTable()
@@ -488,7 +488,7 @@ public class AuditFeatureMapTableMappingWithRanges extends BasicAbstractListTabl
{
EStructuralFeature modelFeature = getFeatureByTag(tag);
- TypeMapping typeMapping = (TypeMapping)getMappingStrategy().createValueMapping(modelFeature);
+ ITypeMapping typeMapping = getMappingStrategy().createValueMapping(modelFeature);
String column = CDODBSchema.FEATUREMAP_VALUE + "_" + typeMapping.getDBType(); //$NON-NLS-1$
tagMap.put(tag, column);
diff --git a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/messages/messages.properties b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/messages/messages.properties
index 5b9baba..c6768b4 100644
--- a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/messages/messages.properties
+++ b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/messages/messages.properties
@@ -7,6 +7,7 @@
# Contributors:
# Victor Roldan Betancort - initial API and implementation
# Eike Stepper - maintenance
+# Stefan Winkler - Bug 285426: [DB] Implement user-defined typeMapping support
DBStore.0=dbConnectionProvider is null
DBStore.1=dbAdapter is null
@@ -18,3 +19,16 @@ DBStore.9=Detected crash
DBStore.11=BranchingSupport of MappingStrategy and Store do not match. Please check configuration.
DBStore.12=Repairing after crash failed.
DBStore.13=Invalid EENum default literal {0} for model element {1}. Falling back to EENum default value.
+
+
+TypeMappingRegistry.1=No type mapping factory found for feature {0} (type {1}, DB type {2})
+TypeMappingRegistry.2=TypeMapping {0} annotated at feature {1} could not be found in registry.
+TypeMappingRegistry.3=Runtime removal of ITypeMapping.Factory extensions is currently not supported.
+TypeMappingRegistry.4=Duplicate source:target typeMapping pairs are currently not supported!
+TypeMappingRegistry.5=Duplicate typeMapping ID: {0}
+
+FactoryTypeParserException.1=Invalid format for typeMapping factoryType {0}
+FactoryTypeParserException.2=EPackage {0} could not be resolved while registering typeMapping factoryType {1}
+FactoryTypeParserException.3=EClassifier {0} could not be resolved while registering typeMapping factoryType {1}
+FactoryTypeParserException.4=DBType {0} could not be resolved while registering typeMapping factoryType {1}
+ \ No newline at end of file
diff --git a/plugins/org.eclipse.emf.cdo.tests.db/src/org/eclipse/emf/cdo/tests/db/CustomTypeMappingTest.java b/plugins/org.eclipse.emf.cdo.tests.db/src/org/eclipse/emf/cdo/tests/db/CustomTypeMappingTest.java
new file mode 100644
index 0000000..18a07b3
--- /dev/null
+++ b/plugins/org.eclipse.emf.cdo.tests.db/src/org/eclipse/emf/cdo/tests/db/CustomTypeMappingTest.java
@@ -0,0 +1,148 @@
+/**
+ * Copyright (c) 2004 - 2010 Eike Stepper (Berlin, Germany) 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:
+ * Stefan Winkler - initial API and implementation
+ * Stefan Winkler - Bug 285426: [DB] Implement user-defined typeMapping support
+ */
+package org.eclipse.emf.cdo.tests.db;
+
+import org.eclipse.emf.cdo.common.model.EMFUtil;
+import org.eclipse.emf.cdo.eresource.CDOResource;
+import org.eclipse.emf.cdo.server.db.mapping.AbstractTypeMapping;
+import org.eclipse.emf.cdo.server.db.mapping.AbstractTypeMappingFactory;
+import org.eclipse.emf.cdo.server.db.mapping.ITypeMapping;
+import org.eclipse.emf.cdo.server.internal.db.mapping.TypeMappingUtil;
+import org.eclipse.emf.cdo.session.CDOSession;
+import org.eclipse.emf.cdo.tests.AbstractCDOTest;
+import org.eclipse.emf.cdo.tests.db.verifier.DBStoreVerifier;
+import org.eclipse.emf.cdo.transaction.CDOTransaction;
+import org.eclipse.emf.cdo.util.CDOUtil;
+import org.eclipse.emf.cdo.util.CommitException;
+
+import org.eclipse.net4j.db.DBType;
+import org.eclipse.net4j.db.DBUtil;
+import org.eclipse.net4j.util.container.IPluginContainer;
+
+import org.eclipse.emf.ecore.EAnnotation;
+import org.eclipse.emf.ecore.EAttribute;
+import org.eclipse.emf.ecore.EClass;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.EPackage;
+import org.eclipse.emf.ecore.EcoreFactory;
+import org.eclipse.emf.ecore.EcorePackage;
+import org.eclipse.emf.ecore.util.EcoreUtil;
+
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+
+/**
+ * @author Stefan Winkler
+ */
+public class CustomTypeMappingTest extends AbstractCDOTest
+{
+
+ public void testCustomTypeMapping() throws CommitException
+ {
+ // manually register type mapping
+ IPluginContainer.INSTANCE.registerFactory(new MyIntToVarcharTypeMapping.Factory());
+
+ EPackage pkg = EMFUtil.createEPackage("underscoreTest", "uct", "http://cdo.eclipse.org/tests/underscoreTest.ecore");
+ EClass cls = EMFUtil.createEClass(pkg, "foo", false, false);
+ EAttribute att = EMFUtil.createEAttribute(cls, "bar", EcorePackage.eINSTANCE.getEInt());
+
+ // annotate type mapping and column type
+ EAnnotation annotation = EcoreFactory.eINSTANCE.createEAnnotation();
+ annotation.setSource("http://www.eclipse.org/CDO/DBStore");
+ annotation.getDetails().put("typeMapping", "org.eclipse.emf.cdo.tests.db.EIntToVarchar");
+ annotation.getDetails().put("columnType", DBType.VARCHAR.getKeyword());
+ att.getEAnnotations().add(annotation);
+
+ if (!isConfig(LEGACY))
+ {
+ CDOUtil.prepareDynamicEPackage(pkg);
+ }
+
+ CDOSession session = openSession();
+ CDOTransaction transaction = session.openTransaction();
+ CDOResource resource = transaction.createResource("/test");
+
+ EObject obj = EcoreUtil.create(cls);
+ obj.eSet(att, 42);
+
+ resource.getContents().add(obj);
+ transaction.commit();
+ transaction.close();
+ session.close();
+
+ msg("Check if type was mapped to string...");
+ new DBStoreVerifier(getRepository())
+ {
+ @Override
+ protected void doVerify() throws Exception
+ {
+ Statement stmt = null;
+ ResultSet rset = null;
+ try
+ {
+ stmt = getStatement();
+ rset = stmt.executeQuery("SELECT bar FROM foo");
+ assertEquals("java.lang.String", rset.getMetaData().getColumnClassName(1));
+
+ rset.next();
+ assertEquals("2a", rset.getString(1));
+ }
+ finally
+ {
+ DBUtil.close(rset);
+ DBUtil.close(stmt);
+ }
+ }
+ }.verify();
+ }
+
+ public static class MyIntToVarcharTypeMapping extends AbstractTypeMapping
+ {
+ public static final ITypeMapping.Descriptor DESCRIPTOR = TypeMappingUtil.createDescriptor(
+ "org.eclipse.emf.cdo.tests.db.EIntToVarchar", EcorePackage.eINSTANCE.getEInt(), DBType.VARCHAR);
+
+ public static class Factory extends AbstractTypeMappingFactory
+ {
+ public Factory()
+ {
+ super(DESCRIPTOR);
+ }
+
+ @Override
+ public ITypeMapping create(String description)
+ {
+ return new MyIntToVarcharTypeMapping();
+ }
+ }
+
+ public MyIntToVarcharTypeMapping()
+ {
+ super();
+ }
+
+ @Override
+ protected void doSetValue(PreparedStatement stmt, int index, Object value) throws SQLException
+ {
+ Integer val = (Integer)value;
+ stmt.setString(index, Integer.toHexString(val));
+ }
+
+ @Override
+ protected Object getResultSetValue(ResultSet resultSet) throws SQLException
+ {
+ String stringVal = resultSet.getString(getField().getName());
+ return Integer.parseInt(stringVal, 16);
+ }
+ }
+}
diff --git a/plugins/org.eclipse.emf.cdo.tests.db/src/org/eclipse/emf/cdo/tests/db/DBAnnotationsTest.java b/plugins/org.eclipse.emf.cdo.tests.db/src/org/eclipse/emf/cdo/tests/db/DBAnnotationsTest.java
index 095de03..f15c79c 100644
--- a/plugins/org.eclipse.emf.cdo.tests.db/src/org/eclipse/emf/cdo/tests/db/DBAnnotationsTest.java
+++ b/plugins/org.eclipse.emf.cdo.tests.db/src/org/eclipse/emf/cdo/tests/db/DBAnnotationsTest.java
@@ -8,6 +8,7 @@
* Contributors:
* Kai Schlamp - initial API and implementation
* Eike Stepper - maintenance
+ * Stefan Winkler - Bug 285426: [DB] Implement user-defined typeMapping support
*/
package org.eclipse.emf.cdo.tests.db;
@@ -58,6 +59,8 @@ public class DBAnnotationsTest extends AbstractCDOTest
resource.getContents().add(product);
transaction.commit();
+ transaction.close();
+ session.close();
}
public void testLengthAnnotationNegative() throws Exception
@@ -96,6 +99,11 @@ public class DBAnnotationsTest extends AbstractCDOTest
catch (Exception success)
{
}
+ finally
+ {
+ transaction.close();
+ session.close();
+ }
}
public void testLengthAnnotationByMetaData() throws CommitException
@@ -122,6 +130,8 @@ public class DBAnnotationsTest extends AbstractCDOTest
resource.getContents().add(product);
transaction.commit();
+ transaction.close();
+ session.close();
msg("Check if column size was correctly set.");
new DBStoreVerifier(getRepository())
@@ -164,6 +174,8 @@ public class DBAnnotationsTest extends AbstractCDOTest
resource.getContents().add(category);
transaction.commit();
+ transaction.close();
+ session.close();
msg("Check if column type was correctly set.");
new DBStoreVerifier(getRepository())
@@ -202,6 +214,8 @@ public class DBAnnotationsTest extends AbstractCDOTest
resource.getContents().add(category);
transaction.commit();
+ transaction.close();
+ session.close();
msg("Check if table name was correctly set.");
new DBStoreVerifier(getRepository())
@@ -240,6 +254,8 @@ public class DBAnnotationsTest extends AbstractCDOTest
resource.getContents().add(category);
transaction.commit();
+ transaction.close();
+ session.close();
msg("Check if table name was correctly set.");
new DBStoreVerifier(getRepository())
@@ -282,6 +298,8 @@ public class DBAnnotationsTest extends AbstractCDOTest
resource.getContents().add(category);
transaction.commit();
+ transaction.close();
+ session.close();
msg("Check if table name was correctly set.");
new DBStoreVerifier(getRepository())
@@ -319,6 +337,7 @@ public class DBAnnotationsTest extends AbstractCDOTest
resource.getContents().add(category);
transaction.commit();
transaction.close();
+ session.close();
msg("Check if table name was correctly set.");
new DBStoreVerifier(getRepository())
@@ -425,6 +444,9 @@ public class DBAnnotationsTest extends AbstractCDOTest
EAnnotation annotation = EcoreFactory.eINSTANCE.createEAnnotation();
annotation.setSource("http://www.eclipse.org/CDO/DBStore");
annotation.getDetails().put("tableMapping", "NONE");
+
+ // ID is defined in plugin.xml
+ annotation.getDetails().put("typeMapping", "org.eclipse.emf.cdo.tests.db.EIntToVarchar");
EClass orderDetail = (EClass)model1.getEClassifier(unmappedTable);
orderDetail.getEAnnotations().add(annotation);
diff --git a/plugins/org.eclipse.emf.cdo.tests.db/src/org/eclipse/emf/cdo/tests/db/DBConfigs.java b/plugins/org.eclipse.emf.cdo.tests.db/src/org/eclipse/emf/cdo/tests/db/DBConfigs.java
index 5b9ca96..7e2f1bc 100644
--- a/plugins/org.eclipse.emf.cdo.tests.db/src/org/eclipse/emf/cdo/tests/db/DBConfigs.java
+++ b/plugins/org.eclipse.emf.cdo.tests.db/src/org/eclipse/emf/cdo/tests/db/DBConfigs.java
@@ -7,6 +7,7 @@
*
* Contributors:
* Eike Stepper - initial API and implementation
+ * Stefan Winkler - Bug 285426: [DB] Implement user-defined typeMapping support
*/
package org.eclipse.emf.cdo.tests.db;
@@ -40,6 +41,7 @@ public abstract class DBConfigs extends AllConfigs
testClasses.add(Net4jDBTest.class);
testClasses.add(DBAnnotationsTest.class);
testClasses.add(DBStoreTest.class);
+ testClasses.add(CustomTypeMappingTest.class);
testClasses.add(SQLQueryTest.class);
super.initTestClasses(testClasses);