diff --git a/org.eclipse.emf.cdo.server.db/.classpath b/org.eclipse.emf.cdo.server.db/.classpath
new file mode 100644
index 0000000..64c5e31
--- /dev/null
+++ b/org.eclipse.emf.cdo.server.db/.classpath
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/J2SE-1.5"/>
+	<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
+	<classpathentry kind="src" path="src"/>
+	<classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/org.eclipse.emf.cdo.server.db/.options b/org.eclipse.emf.cdo.server.db/.options
new file mode 100644
index 0000000..f4f74f8
--- /dev/null
+++ b/org.eclipse.emf.cdo.server.db/.options
@@ -0,0 +1,3 @@
+# Debugging and tracing options
+
+org.eclipse.emf.cdo.server.db/debug = true
diff --git a/org.eclipse.emf.cdo.server.db/.project b/org.eclipse.emf.cdo.server.db/.project
new file mode 100644
index 0000000..4bb79d4
--- /dev/null
+++ b/org.eclipse.emf.cdo.server.db/.project
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+	<name>org.eclipse.emf.cdo.server.db</name>
+	<comment></comment>
+	<projects>
+	</projects>
+	<buildSpec>
+		<buildCommand>
+			<name>org.eclipse.jdt.core.javabuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+		<buildCommand>
+			<name>org.eclipse.pde.ManifestBuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+		<buildCommand>
+			<name>org.eclipse.pde.SchemaBuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+		<buildCommand>
+			<name>org.eclipse.pde.api.tools.apiAnalysisBuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+		<buildCommand>
+			<name>org.eclipse.emf.cdo.releng.version.VersionBuilder</name>
+			<arguments>
+				<dictionary>
+					<key>release.path</key>
+					<value>/org.eclipse.emf.cdo.releng/release.xml</value>
+				</dictionary>
+			</arguments>
+		</buildCommand>
+	</buildSpec>
+	<natures>
+		<nature>org.eclipse.pde.PluginNature</nature>
+		<nature>org.eclipse.jdt.core.javanature</nature>
+		<nature>org.eclipse.pde.api.tools.apiAnalysisNature</nature>
+		<nature>org.eclipse.emf.cdo.releng.version.VersionNature</nature>
+	</natures>
+</projectDescription>
diff --git a/org.eclipse.emf.cdo.server.db/.settings/.api_filters b/org.eclipse.emf.cdo.server.db/.settings/.api_filters
new file mode 100644
index 0000000..475cf59
--- /dev/null
+++ b/org.eclipse.emf.cdo.server.db/.settings/.api_filters
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>

+<component id="org.eclipse.emf.cdo.server.db" version="2">

+    <resource path="src/org/eclipse/emf/cdo/server/internal/db/DBStoreAccessor.java" type="org.eclipse.emf.cdo.server.internal.db.DBStoreAccessor">

+        <filter id="574660632">

+            <message_arguments>

+                <message_argument value="DurableLocking"/>

+                <message_argument value="IDurableLockingManager"/>

+                <message_argument value="DBStoreAccessor"/>

+            </message_arguments>

+        </filter>

+    </resource>

+</component>

diff --git a/org.eclipse.emf.cdo.server.db/.settings/org.eclipse.core.resources.prefs b/org.eclipse.emf.cdo.server.db/.settings/org.eclipse.core.resources.prefs
new file mode 100644
index 0000000..eca460f
--- /dev/null
+++ b/org.eclipse.emf.cdo.server.db/.settings/org.eclipse.core.resources.prefs
@@ -0,0 +1,3 @@
+#Mon Jul 04 13:01:28 CEST 2011

+eclipse.preferences.version=1

+encoding//model/org.eclipse.emf.cdo.defs.ecorediag=UTF-8

diff --git a/org.eclipse.emf.cdo.server.db/.settings/org.eclipse.jdt.core.prefs b/org.eclipse.emf.cdo.server.db/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 0000000..611d1a9
--- /dev/null
+++ b/org.eclipse.emf.cdo.server.db/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,373 @@
+#Fri Sep 02 05:40:11 CEST 2011

+eclipse.preferences.version=1

+org.eclipse.jdt.core.builder.cleanOutputFolder=clean

+org.eclipse.jdt.core.builder.duplicateResourceTask=warning

+org.eclipse.jdt.core.builder.invalidClasspath=abort

+org.eclipse.jdt.core.builder.recreateModifiedClassFileInOutputFolder=ignore

+org.eclipse.jdt.core.builder.resourceCopyExclusionFilter=*.launch,*.ucls,doc-files/,package.html,package-info.java

+org.eclipse.jdt.core.circularClasspath=error

+org.eclipse.jdt.core.classpath.exclusionPatterns=enabled

+org.eclipse.jdt.core.classpath.multipleOutputLocations=enabled

+org.eclipse.jdt.core.codeComplete.argumentPrefixes=

+org.eclipse.jdt.core.codeComplete.argumentSuffixes=

+org.eclipse.jdt.core.codeComplete.fieldPrefixes=

+org.eclipse.jdt.core.codeComplete.fieldSuffixes=

+org.eclipse.jdt.core.codeComplete.localPrefixes=

+org.eclipse.jdt.core.codeComplete.localSuffixes=

+org.eclipse.jdt.core.codeComplete.staticFieldPrefixes=

+org.eclipse.jdt.core.codeComplete.staticFieldSuffixes=

+org.eclipse.jdt.core.codeComplete.staticFinalFieldPrefixes=

+org.eclipse.jdt.core.codeComplete.staticFinalFieldSuffixes=

+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled

+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.5

+org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve

+org.eclipse.jdt.core.compiler.compliance=1.5

+org.eclipse.jdt.core.compiler.debug.lineNumber=generate

+org.eclipse.jdt.core.compiler.debug.localVariable=generate

+org.eclipse.jdt.core.compiler.debug.sourceFile=generate

+org.eclipse.jdt.core.compiler.doc.comment.support=enabled

+org.eclipse.jdt.core.compiler.maxProblemPerUnit=100

+org.eclipse.jdt.core.compiler.problem.annotationSuperInterface=warning

+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error

+org.eclipse.jdt.core.compiler.problem.autoboxing=ignore

+org.eclipse.jdt.core.compiler.problem.comparingIdentical=warning

+org.eclipse.jdt.core.compiler.problem.deadCode=warning

+org.eclipse.jdt.core.compiler.problem.deprecation=warning

+org.eclipse.jdt.core.compiler.problem.deprecationInDeprecatedCode=disabled

+org.eclipse.jdt.core.compiler.problem.deprecationWhenOverridingDeprecatedMethod=enabled

+org.eclipse.jdt.core.compiler.problem.discouragedReference=warning

+org.eclipse.jdt.core.compiler.problem.emptyStatement=warning

+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error

+org.eclipse.jdt.core.compiler.problem.fallthroughCase=warning

+org.eclipse.jdt.core.compiler.problem.fatalOptionalError=disabled

+org.eclipse.jdt.core.compiler.problem.fieldHiding=ignore

+org.eclipse.jdt.core.compiler.problem.finalParameterBound=warning

+org.eclipse.jdt.core.compiler.problem.finallyBlockNotCompletingNormally=warning

+org.eclipse.jdt.core.compiler.problem.forbiddenReference=error

+org.eclipse.jdt.core.compiler.problem.hiddenCatchBlock=warning

+org.eclipse.jdt.core.compiler.problem.includeNullInfoFromAsserts=disabled

+org.eclipse.jdt.core.compiler.problem.incompatibleNonInheritedInterfaceMethod=warning

+org.eclipse.jdt.core.compiler.problem.incompleteEnumSwitch=ignore

+org.eclipse.jdt.core.compiler.problem.indirectStaticAccess=ignore

+org.eclipse.jdt.core.compiler.problem.invalidJavadoc=warning

+org.eclipse.jdt.core.compiler.problem.invalidJavadocTags=enabled

+org.eclipse.jdt.core.compiler.problem.invalidJavadocTagsDeprecatedRef=disabled

+org.eclipse.jdt.core.compiler.problem.invalidJavadocTagsNotVisibleRef=disabled

+org.eclipse.jdt.core.compiler.problem.invalidJavadocTagsVisibility=public

+org.eclipse.jdt.core.compiler.problem.localVariableHiding=ignore

+org.eclipse.jdt.core.compiler.problem.methodWithConstructorName=warning

+org.eclipse.jdt.core.compiler.problem.missingDeprecatedAnnotation=warning

+org.eclipse.jdt.core.compiler.problem.missingHashCodeMethod=warning

+org.eclipse.jdt.core.compiler.problem.missingJavadocComments=ignore

+org.eclipse.jdt.core.compiler.problem.missingJavadocCommentsOverriding=disabled

+org.eclipse.jdt.core.compiler.problem.missingJavadocCommentsVisibility=public

+org.eclipse.jdt.core.compiler.problem.missingJavadocTagDescription=return_tag

+org.eclipse.jdt.core.compiler.problem.missingJavadocTags=ignore

+org.eclipse.jdt.core.compiler.problem.missingJavadocTagsOverriding=disabled

+org.eclipse.jdt.core.compiler.problem.missingJavadocTagsVisibility=public

+org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotation=warning

+org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotationForInterfaceMethodImplementation=enabled

+org.eclipse.jdt.core.compiler.problem.missingSerialVersion=warning

+org.eclipse.jdt.core.compiler.problem.missingSynchronizedOnInheritedMethod=warning

+org.eclipse.jdt.core.compiler.problem.noEffectAssignment=warning

+org.eclipse.jdt.core.compiler.problem.noImplicitStringConversion=warning

+org.eclipse.jdt.core.compiler.problem.nonExternalizedStringLiteral=ignore

+org.eclipse.jdt.core.compiler.problem.nullReference=warning

+org.eclipse.jdt.core.compiler.problem.overridingPackageDefaultMethod=warning

+org.eclipse.jdt.core.compiler.problem.parameterAssignment=ignore

+org.eclipse.jdt.core.compiler.problem.possibleAccidentalBooleanAssignment=warning

+org.eclipse.jdt.core.compiler.problem.potentialNullReference=ignore

+org.eclipse.jdt.core.compiler.problem.rawTypeReference=warning

+org.eclipse.jdt.core.compiler.problem.redundantNullCheck=warning

+org.eclipse.jdt.core.compiler.problem.redundantSuperinterface=warning

+org.eclipse.jdt.core.compiler.problem.specialParameterHidingField=disabled

+org.eclipse.jdt.core.compiler.problem.staticAccessReceiver=warning

+org.eclipse.jdt.core.compiler.problem.suppressOptionalErrors=disabled

+org.eclipse.jdt.core.compiler.problem.suppressWarnings=enabled

+org.eclipse.jdt.core.compiler.problem.syntheticAccessEmulation=ignore

+org.eclipse.jdt.core.compiler.problem.typeParameterHiding=warning

+org.eclipse.jdt.core.compiler.problem.uncheckedTypeOperation=warning

+org.eclipse.jdt.core.compiler.problem.undocumentedEmptyBlock=ignore

+org.eclipse.jdt.core.compiler.problem.unhandledWarningToken=warning

+org.eclipse.jdt.core.compiler.problem.unnecessaryElse=warning

+org.eclipse.jdt.core.compiler.problem.unnecessaryTypeCheck=warning

+org.eclipse.jdt.core.compiler.problem.unqualifiedFieldAccess=ignore

+org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownException=ignore

+org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionExemptExceptionAndThrowable=enabled

+org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionIncludeDocCommentReference=enabled

+org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionWhenOverriding=disabled

+org.eclipse.jdt.core.compiler.problem.unusedImport=warning

+org.eclipse.jdt.core.compiler.problem.unusedLabel=warning

+org.eclipse.jdt.core.compiler.problem.unusedLocal=warning

+org.eclipse.jdt.core.compiler.problem.unusedObjectAllocation=ignore

+org.eclipse.jdt.core.compiler.problem.unusedParameter=ignore

+org.eclipse.jdt.core.compiler.problem.unusedParameterIncludeDocCommentReference=enabled

+org.eclipse.jdt.core.compiler.problem.unusedParameterWhenImplementingAbstract=disabled

+org.eclipse.jdt.core.compiler.problem.unusedParameterWhenOverridingConcrete=disabled

+org.eclipse.jdt.core.compiler.problem.unusedPrivateMember=warning

+org.eclipse.jdt.core.compiler.problem.unusedWarningToken=warning

+org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=warning

+org.eclipse.jdt.core.compiler.source=1.5

+org.eclipse.jdt.core.compiler.taskCaseSensitive=enabled

+org.eclipse.jdt.core.compiler.taskPriorities=NORMAL,HIGH,HIGH,LOW,LOW,LOW,LOW,LOW

+org.eclipse.jdt.core.compiler.taskTags=TODO,FIXME,XXX,PERF,MEM,POLISH,@generated NOT,@ADDED

+org.eclipse.jdt.core.formatter.align_type_members_on_columns=false

+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=16

+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=16

+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call=16

+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation=16

+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression=16

+org.eclipse.jdt.core.formatter.alignment_for_assignment=0

+org.eclipse.jdt.core.formatter.alignment_for_binary_expression=16

+org.eclipse.jdt.core.formatter.alignment_for_compact_if=16

+org.eclipse.jdt.core.formatter.alignment_for_conditional_expression=80

+org.eclipse.jdt.core.formatter.alignment_for_enum_constants=0

+org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer=16

+org.eclipse.jdt.core.formatter.alignment_for_multiple_fields=16

+org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration=16

+org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration=16

+org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation=16

+org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration=16

+org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration=16

+org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration=16

+org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration=16

+org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration=16

+org.eclipse.jdt.core.formatter.blank_lines_after_imports=1

+org.eclipse.jdt.core.formatter.blank_lines_after_package=1

+org.eclipse.jdt.core.formatter.blank_lines_before_field=1

+org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration=0

+org.eclipse.jdt.core.formatter.blank_lines_before_imports=1

+org.eclipse.jdt.core.formatter.blank_lines_before_member_type=1

+org.eclipse.jdt.core.formatter.blank_lines_before_method=1

+org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk=1

+org.eclipse.jdt.core.formatter.blank_lines_before_package=0

+org.eclipse.jdt.core.formatter.blank_lines_between_import_groups=1

+org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations=1

+org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration=next_line

+org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration=next_line

+org.eclipse.jdt.core.formatter.brace_position_for_array_initializer=end_of_line

+org.eclipse.jdt.core.formatter.brace_position_for_block=next_line

+org.eclipse.jdt.core.formatter.brace_position_for_block_in_case=next_line

+org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration=next_line

+org.eclipse.jdt.core.formatter.brace_position_for_enum_constant=next_line

+org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration=next_line

+org.eclipse.jdt.core.formatter.brace_position_for_method_declaration=next_line

+org.eclipse.jdt.core.formatter.brace_position_for_switch=next_line

+org.eclipse.jdt.core.formatter.brace_position_for_type_declaration=next_line

+org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment=true

+org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment=true

+org.eclipse.jdt.core.formatter.comment.format_block_comments=true

+org.eclipse.jdt.core.formatter.comment.format_header=false

+org.eclipse.jdt.core.formatter.comment.format_html=true

+org.eclipse.jdt.core.formatter.comment.format_javadoc_comments=true

+org.eclipse.jdt.core.formatter.comment.format_line_comments=true

+org.eclipse.jdt.core.formatter.comment.format_source_code=true

+org.eclipse.jdt.core.formatter.comment.indent_parameter_description=true

+org.eclipse.jdt.core.formatter.comment.indent_root_tags=true

+org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags=insert

+org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter=insert

+org.eclipse.jdt.core.formatter.comment.line_length=120

+org.eclipse.jdt.core.formatter.compact_else_if=true

+org.eclipse.jdt.core.formatter.continuation_indentation=2

+org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer=2

+org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line=false

+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header=true

+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header=true

+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header=true

+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header=true

+org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases=true

+org.eclipse.jdt.core.formatter.indent_empty_lines=false

+org.eclipse.jdt.core.formatter.indent_statements_compare_to_block=true

+org.eclipse.jdt.core.formatter.indent_statements_compare_to_body=true

+org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases=true

+org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch=false

+org.eclipse.jdt.core.formatter.indentation.size=2

+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable=insert

+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_member=insert

+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter=do not insert

+org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer=do not insert

+org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing=insert

+org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement=insert

+org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer=do not insert

+org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement=insert

+org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement=insert

+org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement=do not insert

+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_annotation_declaration=insert

+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_anonymous_type_declaration=insert

+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_block=insert

+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_constant=insert

+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_declaration=insert

+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_method_body=insert

+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_type_declaration=insert

+org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter=insert

+org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator=insert

+org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation=do not insert

+org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration=do not insert

+org.eclipse.jdt.core.formatter.insert_space_after_binary_operator=insert

+org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments=insert

+org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters=insert

+org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block=insert

+org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast=do not insert

+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert=insert

+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case=insert

+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional=insert

+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for=insert

+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement=insert

+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression=insert

+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation=insert

+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer=insert

+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters=insert

+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws=insert

+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments=insert

+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations=insert

+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments=insert

+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments=insert

+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits=insert

+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters=insert

+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws=insert

+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments=insert

+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations=insert

+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations=insert

+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference=insert

+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces=insert

+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments=insert

+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters=insert

+org.eclipse.jdt.core.formatter.insert_space_after_ellipsis=insert

+org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference=do not insert

+org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments=do not insert

+org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters=do not insert

+org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer=insert

+org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression=do not insert

+org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference=do not insert

+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation=do not insert

+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast=do not insert

+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch=do not insert

+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration=do not insert

+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant=do not insert

+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for=do not insert

+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if=do not insert

+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration=do not insert

+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation=do not insert

+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression=do not insert

+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch=do not insert

+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized=do not insert

+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while=do not insert

+org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator=do not insert

+org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator=do not insert

+org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional=insert

+org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard=do not insert

+org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for=insert

+org.eclipse.jdt.core.formatter.insert_space_after_unary_operator=do not insert

+org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter=insert

+org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator=insert

+org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration=insert

+org.eclipse.jdt.core.formatter.insert_space_before_binary_operator=insert

+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference=do not insert

+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments=do not insert

+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters=do not insert

+org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer=insert

+org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression=do not insert

+org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference=do not insert

+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation=do not insert

+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast=do not insert

+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch=do not insert

+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration=do not insert

+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant=do not insert

+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for=do not insert

+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if=do not insert

+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration=do not insert

+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation=do not insert

+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression=do not insert

+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch=do not insert

+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized=do not insert

+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while=do not insert

+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert=insert

+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case=do not insert

+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional=insert

+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default=do not insert

+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for=insert

+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement=do not insert

+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression=do not insert

+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation=do not insert

+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer=do not insert

+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters=do not insert

+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws=do not insert

+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments=do not insert

+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations=do not insert

+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments=do not insert

+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments=do not insert

+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits=do not insert

+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters=do not insert

+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws=do not insert

+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments=do not insert

+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations=do not insert

+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations=do not insert

+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference=do not insert

+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces=do not insert

+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments=do not insert

+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters=do not insert

+org.eclipse.jdt.core.formatter.insert_space_before_ellipsis=do not insert

+org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference=do not insert

+org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments=do not insert

+org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters=do not insert

+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration=insert

+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration=insert

+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer=insert

+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block=insert

+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration=insert

+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant=insert

+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration=insert

+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration=insert

+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch=insert

+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration=insert

+org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression=do not insert

+org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference=do not insert

+org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference=do not insert

+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation=do not insert

+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration=do not insert

+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch=insert

+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration=do not insert

+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant=do not insert

+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for=insert

+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if=insert

+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration=do not insert

+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation=do not insert

+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression=do not insert

+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch=insert

+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized=insert

+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while=insert

+org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return=insert

+org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw=insert

+org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator=do not insert

+org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator=do not insert

+org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional=insert

+org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard=do not insert

+org.eclipse.jdt.core.formatter.insert_space_before_semicolon=do not insert

+org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for=do not insert

+org.eclipse.jdt.core.formatter.insert_space_before_unary_operator=do not insert

+org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference=do not insert

+org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer=do not insert

+org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression=do not insert

+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration=do not insert

+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration=do not insert

+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant=do not insert

+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration=do not insert

+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation=do not insert

+org.eclipse.jdt.core.formatter.join_lines_in_comments=true

+org.eclipse.jdt.core.formatter.join_wrapped_lines=true

+org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line=false

+org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line=false

+org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line=false

+org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line=false

+org.eclipse.jdt.core.formatter.lineSplit=120

+org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column=false

+org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column=false

+org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body=0

+org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve=1

+org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line=true

+org.eclipse.jdt.core.formatter.tabulation.char=space

+org.eclipse.jdt.core.formatter.tabulation.size=2

+org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations=false

+org.eclipse.jdt.core.formatter.wrap_before_binary_operator=true

+org.eclipse.jdt.core.incompatibleJDKLevel=ignore

+org.eclipse.jdt.core.incompleteClasspath=error

diff --git a/org.eclipse.emf.cdo.server.db/.settings/org.eclipse.jdt.launching.prefs b/org.eclipse.emf.cdo.server.db/.settings/org.eclipse.jdt.launching.prefs
new file mode 100644
index 0000000..4658ec1
--- /dev/null
+++ b/org.eclipse.emf.cdo.server.db/.settings/org.eclipse.jdt.launching.prefs
@@ -0,0 +1,3 @@
+#Fri Sep 02 05:38:34 CEST 2011

+eclipse.preferences.version=1

+org.eclipse.jdt.launching.PREF_STRICTLY_COMPATIBLE_JRE_NOT_AVAILABLE=ignore

diff --git a/org.eclipse.emf.cdo.server.db/.settings/org.eclipse.jdt.ui.prefs b/org.eclipse.emf.cdo.server.db/.settings/org.eclipse.jdt.ui.prefs
new file mode 100644
index 0000000..4277817
--- /dev/null
+++ b/org.eclipse.emf.cdo.server.db/.settings/org.eclipse.jdt.ui.prefs
@@ -0,0 +1,120 @@
+#Thu Feb 04 09:44:24 CET 2010
+cleanup.add_default_serial_version_id=true
+cleanup.add_generated_serial_version_id=false
+cleanup.add_missing_annotations=true
+cleanup.add_missing_deprecated_annotations=true
+cleanup.add_missing_methods=false
+cleanup.add_missing_nls_tags=false
+cleanup.add_missing_override_annotations=true
+cleanup.add_missing_override_annotations_interface_methods=true
+cleanup.add_serial_version_id=true
+cleanup.always_use_blocks=true
+cleanup.always_use_parentheses_in_expressions=false
+cleanup.always_use_this_for_non_static_field_access=false
+cleanup.always_use_this_for_non_static_method_access=false
+cleanup.convert_to_enhanced_for_loop=false
+cleanup.correct_indentation=true
+cleanup.format_source_code=true
+cleanup.format_source_code_changes_only=false
+cleanup.make_local_variable_final=true
+cleanup.make_parameters_final=false
+cleanup.make_private_fields_final=true
+cleanup.make_type_abstract_if_missing_method=false
+cleanup.make_variable_declarations_final=false
+cleanup.never_use_blocks=false
+cleanup.never_use_parentheses_in_expressions=true
+cleanup.organize_imports=true
+cleanup.qualify_static_field_accesses_with_declaring_class=false
+cleanup.qualify_static_member_accesses_through_instances_with_declaring_class=true
+cleanup.qualify_static_member_accesses_through_subtypes_with_declaring_class=true
+cleanup.qualify_static_member_accesses_with_declaring_class=false
+cleanup.qualify_static_method_accesses_with_declaring_class=false
+cleanup.remove_private_constructors=true
+cleanup.remove_trailing_whitespaces=true
+cleanup.remove_trailing_whitespaces_all=true
+cleanup.remove_trailing_whitespaces_ignore_empty=false
+cleanup.remove_unnecessary_casts=true
+cleanup.remove_unnecessary_nls_tags=true
+cleanup.remove_unused_imports=true
+cleanup.remove_unused_local_variables=false
+cleanup.remove_unused_private_fields=true
+cleanup.remove_unused_private_members=false
+cleanup.remove_unused_private_methods=true
+cleanup.remove_unused_private_types=true
+cleanup.sort_members=false
+cleanup.sort_members_all=false
+cleanup.use_blocks=true
+cleanup.use_blocks_only_for_return_and_throw=false
+cleanup.use_parentheses_in_expressions=true
+cleanup.use_this_for_non_static_field_access=true
+cleanup.use_this_for_non_static_field_access_only_if_necessary=true
+cleanup.use_this_for_non_static_method_access=true
+cleanup.use_this_for_non_static_method_access_only_if_necessary=true
+cleanup_profile=_EMFT
+cleanup_settings_version=2
+eclipse.preferences.version=1
+editor_save_participant_org.eclipse.jdt.ui.postsavelistener.cleanup=true
+formatter_profile=_EMFT
+formatter_settings_version=11
+org.eclipse.jdt.ui.exception.name=ex
+org.eclipse.jdt.ui.gettersetter.use.is=true
+org.eclipse.jdt.ui.ignorelowercasenames=true
+org.eclipse.jdt.ui.importorder=org.eclipse.emf.cdo;org.eclipse.emf.internal.cdo;org.eclipse.net4j;org.eclipse.internal.net4j;org.eclipse.emf;org.eclipse;com;org;javax;java;
+org.eclipse.jdt.ui.javadoc=true
+org.eclipse.jdt.ui.keywordthis=false
+org.eclipse.jdt.ui.ondemandthreshold=99
+org.eclipse.jdt.ui.overrideannotation=true
+org.eclipse.jdt.ui.staticondemandthreshold=99
+org.eclipse.jdt.ui.text.custom_code_templates=<?xml version\="1.0" encoding\="UTF-8" standalone\="no"?><templates><template autoinsert\="false" context\="gettercomment_context" deleted\="false" description\="Comment for getter method" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.gettercomment" name\="gettercomment"/><template autoinsert\="false" context\="settercomment_context" deleted\="false" description\="Comment for setter method" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.settercomment" name\="settercomment"/><template autoinsert\="false" context\="constructorcomment_context" deleted\="false" description\="Comment for created constructors" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.constructorcomment" name\="constructorcomment"/><template autoinsert\="false" context\="filecomment_context" deleted\="false" description\="Comment for created Java files" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.filecomment" name\="filecomment">/**\r\n * Copyright (c) 2004 - 2011 Eike Stepper (Berlin, Germany) and others.\r\n * All rights reserved. This program and the accompanying materials\r\n * are made available under the terms of the Eclipse Public License v1.0\r\n * which accompanies this distribution, and is available at\r\n * http\://www.eclipse.org/legal/epl-v10.html\r\n * \r\n * Contributors\:\r\n *    Eike Stepper - initial API and implementation\r\n */</template><template autoinsert\="false" context\="typecomment_context" deleted\="false" description\="Comment for created types" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.typecomment" name\="typecomment">/**\r\n * @author Eike Stepper\r\n */</template><template autoinsert\="false" context\="fieldcomment_context" deleted\="false" description\="Comment for fields" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.fieldcomment" name\="fieldcomment"/><template autoinsert\="false" context\="methodcomment_context" deleted\="false" description\="Comment for non-overriding methods" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.methodcomment" name\="methodcomment"/><template autoinsert\="false" context\="overridecomment_context" deleted\="false" description\="Comment for overriding methods" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.overridecomment" name\="overridecomment"/><template autoinsert\="false" context\="delegatecomment_context" deleted\="false" description\="Comment for delegate methods" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.delegatecomment" name\="delegatecomment"/><template autoinsert\="true" context\="newtype_context" deleted\="false" description\="Newly created files" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.newtype" name\="newtype">${filecomment}\r\n${package_declaration}\r\n\r\n${typecomment}\r\n${type_declaration}</template><template autoinsert\="true" context\="classbody_context" deleted\="false" description\="Code in new class type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.classbody" name\="classbody">\r\n</template><template autoinsert\="true" context\="interfacebody_context" deleted\="false" description\="Code in new interface type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.interfacebody" name\="interfacebody">\r\n</template><template autoinsert\="true" context\="enumbody_context" deleted\="false" description\="Code in new enum type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.enumbody" name\="enumbody">\r\n</template><template autoinsert\="true" context\="annotationbody_context" deleted\="false" description\="Code in new annotation type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.annotationbody" name\="annotationbody">\r\n</template><template autoinsert\="false" context\="catchblock_context" deleted\="false" description\="Code in new catch blocks" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.catchblock" name\="catchblock">${exception_var}.printStackTrace();</template><template autoinsert\="false" context\="methodbody_context" deleted\="false" description\="Code in created method stubs" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.methodbody" name\="methodbody">${body_statement}</template><template autoinsert\="false" context\="constructorbody_context" deleted\="false" description\="Code in created constructor stubs" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.constructorbody" name\="constructorbody">${body_statement}</template><template autoinsert\="true" context\="getterbody_context" deleted\="false" description\="Code in created getters" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.getterbody" name\="getterbody">return ${field};</template><template autoinsert\="true" context\="setterbody_context" deleted\="false" description\="Code in created setters" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.setterbody" name\="setterbody">${field} \= ${param};</template></templates>
+sp_cleanup.add_default_serial_version_id=true
+sp_cleanup.add_generated_serial_version_id=false
+sp_cleanup.add_missing_annotations=true
+sp_cleanup.add_missing_deprecated_annotations=true
+sp_cleanup.add_missing_methods=false
+sp_cleanup.add_missing_nls_tags=false
+sp_cleanup.add_missing_override_annotations=true
+sp_cleanup.add_missing_override_annotations_interface_methods=false
+sp_cleanup.add_serial_version_id=false
+sp_cleanup.always_use_blocks=true
+sp_cleanup.always_use_parentheses_in_expressions=false
+sp_cleanup.always_use_this_for_non_static_field_access=false
+sp_cleanup.always_use_this_for_non_static_method_access=false
+sp_cleanup.convert_to_enhanced_for_loop=false
+sp_cleanup.correct_indentation=true
+sp_cleanup.format_source_code=true
+sp_cleanup.format_source_code_changes_only=false
+sp_cleanup.make_local_variable_final=false
+sp_cleanup.make_parameters_final=false
+sp_cleanup.make_private_fields_final=true
+sp_cleanup.make_type_abstract_if_missing_method=false
+sp_cleanup.make_variable_declarations_final=false
+sp_cleanup.never_use_blocks=false
+sp_cleanup.never_use_parentheses_in_expressions=true
+sp_cleanup.on_save_use_additional_actions=true
+sp_cleanup.organize_imports=true
+sp_cleanup.qualify_static_field_accesses_with_declaring_class=false
+sp_cleanup.qualify_static_member_accesses_through_instances_with_declaring_class=true
+sp_cleanup.qualify_static_member_accesses_through_subtypes_with_declaring_class=true
+sp_cleanup.qualify_static_member_accesses_with_declaring_class=false
+sp_cleanup.qualify_static_method_accesses_with_declaring_class=false
+sp_cleanup.remove_private_constructors=true
+sp_cleanup.remove_trailing_whitespaces=true
+sp_cleanup.remove_trailing_whitespaces_all=true
+sp_cleanup.remove_trailing_whitespaces_ignore_empty=false
+sp_cleanup.remove_unnecessary_casts=true
+sp_cleanup.remove_unnecessary_nls_tags=true
+sp_cleanup.remove_unused_imports=true
+sp_cleanup.remove_unused_local_variables=false
+sp_cleanup.remove_unused_private_fields=true
+sp_cleanup.remove_unused_private_members=false
+sp_cleanup.remove_unused_private_methods=true
+sp_cleanup.remove_unused_private_types=true
+sp_cleanup.sort_members=false
+sp_cleanup.sort_members_all=false
+sp_cleanup.use_blocks=true
+sp_cleanup.use_blocks_only_for_return_and_throw=false
+sp_cleanup.use_parentheses_in_expressions=true
+sp_cleanup.use_this_for_non_static_field_access=true
+sp_cleanup.use_this_for_non_static_field_access_only_if_necessary=true
+sp_cleanup.use_this_for_non_static_method_access=true
+sp_cleanup.use_this_for_non_static_method_access_only_if_necessary=true
diff --git a/org.eclipse.emf.cdo.server.db/.settings/org.eclipse.ltk.core.refactoring.prefs b/org.eclipse.emf.cdo.server.db/.settings/org.eclipse.ltk.core.refactoring.prefs
new file mode 100644
index 0000000..864e30f
--- /dev/null
+++ b/org.eclipse.emf.cdo.server.db/.settings/org.eclipse.ltk.core.refactoring.prefs
@@ -0,0 +1,3 @@
+#Thu Feb 04 09:44:24 CET 2010
+eclipse.preferences.version=1
+org.eclipse.ltk.core.refactoring.enable.project.refactoring.history=false
diff --git a/org.eclipse.emf.cdo.server.db/.settings/org.eclipse.mylyn.tasks.ui.prefs b/org.eclipse.emf.cdo.server.db/.settings/org.eclipse.mylyn.tasks.ui.prefs
new file mode 100644
index 0000000..b050639
--- /dev/null
+++ b/org.eclipse.emf.cdo.server.db/.settings/org.eclipse.mylyn.tasks.ui.prefs
@@ -0,0 +1,4 @@
+#Thu Feb 04 09:44:24 CET 2010
+eclipse.preferences.version=1
+project.repository.kind=bugzilla
+project.repository.url=https\://bugs.eclipse.org/bugs
diff --git a/org.eclipse.emf.cdo.server.db/.settings/org.eclipse.mylyn.team.ui.prefs b/org.eclipse.emf.cdo.server.db/.settings/org.eclipse.mylyn.team.ui.prefs
new file mode 100644
index 0000000..2f50f36
--- /dev/null
+++ b/org.eclipse.emf.cdo.server.db/.settings/org.eclipse.mylyn.team.ui.prefs
@@ -0,0 +1,3 @@
+#Thu Feb 04 09:44:24 CET 2010
+commit.comment.template=[${task.id}] ${task.description} \r\n${task.url}
+eclipse.preferences.version=1
diff --git a/org.eclipse.emf.cdo.server.db/.settings/org.eclipse.pde.api.tools.prefs b/org.eclipse.emf.cdo.server.db/.settings/org.eclipse.pde.api.tools.prefs
new file mode 100644
index 0000000..f8d0a06
--- /dev/null
+++ b/org.eclipse.emf.cdo.server.db/.settings/org.eclipse.pde.api.tools.prefs
@@ -0,0 +1,94 @@
+#Thu Feb 04 09:44:24 CET 2010
+ANNOTATION_ELEMENT_TYPE_ADDED_METHOD_WITHOUT_DEFAULT_VALUE=Error
+ANNOTATION_ELEMENT_TYPE_CHANGED_TYPE_CONVERSION=Error
+ANNOTATION_ELEMENT_TYPE_REMOVED_FIELD=Error
+ANNOTATION_ELEMENT_TYPE_REMOVED_METHOD=Error
+ANNOTATION_ELEMENT_TYPE_REMOVED_TYPE_MEMBER=Error
+API_COMPONENT_ELEMENT_TYPE_REMOVED_API_TYPE=Error
+API_COMPONENT_ELEMENT_TYPE_REMOVED_REEXPORTED_API_TYPE=Error
+API_COMPONENT_ELEMENT_TYPE_REMOVED_REEXPORTED_TYPE=Error
+API_COMPONENT_ELEMENT_TYPE_REMOVED_TYPE=Error
+CLASS_ELEMENT_TYPE_ADDED_METHOD=Error
+CLASS_ELEMENT_TYPE_ADDED_RESTRICTIONS=Error
+CLASS_ELEMENT_TYPE_ADDED_TYPE_PARAMETER=Error
+CLASS_ELEMENT_TYPE_CHANGED_CONTRACTED_SUPERINTERFACES_SET=Error
+CLASS_ELEMENT_TYPE_CHANGED_DECREASE_ACCESS=Error
+CLASS_ELEMENT_TYPE_CHANGED_NON_ABSTRACT_TO_ABSTRACT=Error
+CLASS_ELEMENT_TYPE_CHANGED_NON_FINAL_TO_FINAL=Error
+CLASS_ELEMENT_TYPE_CHANGED_TYPE_CONVERSION=Error
+CLASS_ELEMENT_TYPE_REMOVED_CONSTRUCTOR=Error
+CLASS_ELEMENT_TYPE_REMOVED_FIELD=Error
+CLASS_ELEMENT_TYPE_REMOVED_METHOD=Error
+CLASS_ELEMENT_TYPE_REMOVED_SUPERCLASS=Error
+CLASS_ELEMENT_TYPE_REMOVED_TYPE_MEMBER=Error
+CLASS_ELEMENT_TYPE_REMOVED_TYPE_PARAMETER=Error
+CONSTRUCTOR_ELEMENT_TYPE_ADDED_TYPE_PARAMETER=Error
+CONSTRUCTOR_ELEMENT_TYPE_CHANGED_DECREASE_ACCESS=Error
+CONSTRUCTOR_ELEMENT_TYPE_CHANGED_VARARGS_TO_ARRAY=Error
+CONSTRUCTOR_ELEMENT_TYPE_REMOVED_TYPE_PARAMETER=Error
+ENUM_ELEMENT_TYPE_CHANGED_CONTRACTED_SUPERINTERFACES_SET=Error
+ENUM_ELEMENT_TYPE_CHANGED_TYPE_CONVERSION=Error
+ENUM_ELEMENT_TYPE_REMOVED_ENUM_CONSTANT=Error
+ENUM_ELEMENT_TYPE_REMOVED_FIELD=Error
+ENUM_ELEMENT_TYPE_REMOVED_METHOD=Error
+ENUM_ELEMENT_TYPE_REMOVED_TYPE_MEMBER=Error
+FIELD_ELEMENT_TYPE_ADDED_VALUE=Error
+FIELD_ELEMENT_TYPE_CHANGED_DECREASE_ACCESS=Error
+FIELD_ELEMENT_TYPE_CHANGED_FINAL_TO_NON_FINAL_STATIC_CONSTANT=Error
+FIELD_ELEMENT_TYPE_CHANGED_NON_FINAL_TO_FINAL=Error
+FIELD_ELEMENT_TYPE_CHANGED_NON_STATIC_TO_STATIC=Error
+FIELD_ELEMENT_TYPE_CHANGED_STATIC_TO_NON_STATIC=Error
+FIELD_ELEMENT_TYPE_CHANGED_TYPE=Error
+FIELD_ELEMENT_TYPE_CHANGED_VALUE=Error
+FIELD_ELEMENT_TYPE_REMOVED_TYPE_ARGUMENT=Error
+FIELD_ELEMENT_TYPE_REMOVED_VALUE=Error
+ILLEGAL_EXTEND=Warning
+ILLEGAL_IMPLEMENT=Warning
+ILLEGAL_INSTANTIATE=Warning
+ILLEGAL_OVERRIDE=Warning
+ILLEGAL_REFERENCE=Warning
+INTERFACE_ELEMENT_TYPE_ADDED_FIELD=Error
+INTERFACE_ELEMENT_TYPE_ADDED_METHOD=Error
+INTERFACE_ELEMENT_TYPE_ADDED_RESTRICTIONS=Error
+INTERFACE_ELEMENT_TYPE_ADDED_SUPER_INTERFACE_WITH_METHODS=Error
+INTERFACE_ELEMENT_TYPE_ADDED_TYPE_PARAMETER=Error
+INTERFACE_ELEMENT_TYPE_CHANGED_CONTRACTED_SUPERINTERFACES_SET=Error
+INTERFACE_ELEMENT_TYPE_CHANGED_TYPE_CONVERSION=Error
+INTERFACE_ELEMENT_TYPE_REMOVED_FIELD=Error
+INTERFACE_ELEMENT_TYPE_REMOVED_METHOD=Error
+INTERFACE_ELEMENT_TYPE_REMOVED_TYPE_MEMBER=Error
+INTERFACE_ELEMENT_TYPE_REMOVED_TYPE_PARAMETER=Error
+INVALID_JAVADOC_TAG=Ignore
+INVALID_REFERENCE_IN_SYSTEM_LIBRARIES=Ignore
+LEAK_EXTEND=Warning
+LEAK_FIELD_DECL=Warning
+LEAK_IMPLEMENT=Warning
+LEAK_METHOD_PARAM=Warning
+LEAK_METHOD_RETURN_TYPE=Warning
+METHOD_ELEMENT_TYPE_ADDED_RESTRICTIONS=Error
+METHOD_ELEMENT_TYPE_ADDED_TYPE_PARAMETER=Error
+METHOD_ELEMENT_TYPE_CHANGED_DECREASE_ACCESS=Error
+METHOD_ELEMENT_TYPE_CHANGED_NON_ABSTRACT_TO_ABSTRACT=Error
+METHOD_ELEMENT_TYPE_CHANGED_NON_FINAL_TO_FINAL=Error
+METHOD_ELEMENT_TYPE_CHANGED_NON_STATIC_TO_STATIC=Error
+METHOD_ELEMENT_TYPE_CHANGED_STATIC_TO_NON_STATIC=Error
+METHOD_ELEMENT_TYPE_CHANGED_VARARGS_TO_ARRAY=Error
+METHOD_ELEMENT_TYPE_REMOVED_ANNOTATION_DEFAULT_VALUE=Error
+METHOD_ELEMENT_TYPE_REMOVED_TYPE_PARAMETER=Error
+TYPE_PARAMETER_ELEMENT_TYPE_ADDED_CLASS_BOUND=Error
+TYPE_PARAMETER_ELEMENT_TYPE_ADDED_INTERFACE_BOUND=Error
+TYPE_PARAMETER_ELEMENT_TYPE_CHANGED_CLASS_BOUND=Error
+TYPE_PARAMETER_ELEMENT_TYPE_CHANGED_INTERFACE_BOUND=Error
+TYPE_PARAMETER_ELEMENT_TYPE_REMOVED_CLASS_BOUND=Error
+TYPE_PARAMETER_ELEMENT_TYPE_REMOVED_INTERFACE_BOUND=Error
+UNUSED_PROBLEM_FILTERS=Ignore
+automatically_removed_unused_problem_filters=Disabled
+eclipse.preferences.version=1
+incompatible_api_component_version=Error
+incompatible_api_component_version_include_major_without_breaking_change=Disabled
+incompatible_api_component_version_include_minor_without_api_change=Disabled
+invalid_since_tag_version=Error
+malformed_since_tag=Error
+missing_since_tag=Error
+report_api_breakage_when_major_version_incremented=Disabled
+report_resolution_errors_api_component=Warning
diff --git a/org.eclipse.emf.cdo.server.db/.settings/org.eclipse.pde.prefs b/org.eclipse.emf.cdo.server.db/.settings/org.eclipse.pde.prefs
new file mode 100644
index 0000000..c6b96bb
--- /dev/null
+++ b/org.eclipse.emf.cdo.server.db/.settings/org.eclipse.pde.prefs
@@ -0,0 +1,31 @@
+#Thu Feb 04 09:44:24 CET 2010
+compilers.f.unresolved-features=1
+compilers.f.unresolved-plugins=1
+compilers.incompatible-environment=1
+compilers.p.build=1
+compilers.p.build.bin.includes=1
+compilers.p.build.java.compliance=1
+compilers.p.build.missing.output=2
+compilers.p.build.output.library=1
+compilers.p.build.source.library=1
+compilers.p.build.src.includes=1
+compilers.p.deprecated=1
+compilers.p.discouraged-class=1
+compilers.p.internal=1
+compilers.p.missing-packages=1
+compilers.p.missing-version-export-package=1
+compilers.p.missing-version-import-package=1
+compilers.p.missing-version-require-bundle=1
+compilers.p.no-required-att=0
+compilers.p.not-externalized-att=2
+compilers.p.unknown-attribute=1
+compilers.p.unknown-class=1
+compilers.p.unknown-element=1
+compilers.p.unknown-identifier=1
+compilers.p.unknown-resource=1
+compilers.p.unresolved-ex-points=0
+compilers.p.unresolved-import=0
+compilers.s.create-docs=false
+compilers.s.doc-folder=doc
+compilers.s.open-tags=1
+eclipse.preferences.version=1
diff --git a/org.eclipse.emf.cdo.server.db/META-INF/MANIFEST.MF b/org.eclipse.emf.cdo.server.db/META-INF/MANIFEST.MF
new file mode 100644
index 0000000..b3af040
--- /dev/null
+++ b/org.eclipse.emf.cdo.server.db/META-INF/MANIFEST.MF
@@ -0,0 +1,22 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-SymbolicName: org.eclipse.emf.cdo.server.db;singleton:=true
+Bundle-Version: 4.1.0.qualifier
+Bundle-Name: %pluginName
+Bundle-Vendor: %providerName
+Bundle-Localization: plugin
+Bundle-ActivationPolicy: lazy
+Bundle-Activator: org.eclipse.emf.cdo.server.internal.db.bundle.OM$Activator
+Bundle-RequiredExecutionEnvironment: J2SE-1.5
+Bundle-ClassPath: .
+Require-Bundle: org.eclipse.core.runtime;bundle-version="[3.4.0,4.0.0)",
+ org.eclipse.net4j.db;bundle-version="[4.0.0,5.0.0)";visibility:=reexport,
+ org.eclipse.emf.cdo.server;bundle-version="[4.0.0,5.0.0)";visibility:=reexport
+Export-Package: org.eclipse.emf.cdo.server.db;version="4.1.0",
+ org.eclipse.emf.cdo.server.db.mapping;version="4.1.0",
+ org.eclipse.emf.cdo.server.internal.db;version="4.1.0";x-friends:="org.eclipse.emf.cdo.tests,org.eclipse.emf.cdo.tests.db",
+ org.eclipse.emf.cdo.server.internal.db.bundle;version="4.1.0";x-internal:=true,
+ org.eclipse.emf.cdo.server.internal.db.jdbc;version="4.1.0";x-friends:="org.eclipse.emf.cdo.tests,org.eclipse.emf.cdo.tests.db",
+ org.eclipse.emf.cdo.server.internal.db.mapping;version="4.1.0";x-friends:="org.eclipse.emf.cdo.tests,org.eclipse.emf.cdo.tests.db",
+ org.eclipse.emf.cdo.server.internal.db.mapping.horizontal;version="4.1.0";x-friends:="org.eclipse.emf.cdo.tests,org.eclipse.emf.cdo.tests.db",
+ org.eclipse.emf.cdo.server.internal.db.messages;version="4.1.0";x-internal:=true
diff --git a/org.eclipse.emf.cdo.server.db/about.html b/org.eclipse.emf.cdo.server.db/about.html
new file mode 100644
index 0000000..d35d5ae
--- /dev/null
+++ b/org.eclipse.emf.cdo.server.db/about.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"/>
+<title>About</title>
+</head>
+<body lang="EN-US">
+<h2>About This Content</h2>
+ 
+<p>June 5, 2007</p>	
+<h3>License</h3>
+
+<p>The Eclipse Foundation makes available all content in this plug-in (&quot;Content&quot;).  Unless otherwise 
+indicated below, the Content is provided to you under the terms and conditions of the
+Eclipse Public License Version 1.0 (&quot;EPL&quot;).  A copy of the EPL is available 
+at <a href="http://www.eclipse.org/legal/epl-v10.html">http://www.eclipse.org/legal/epl-v10.html</a>.
+For purposes of the EPL, &quot;Program&quot; will mean the Content.</p>
+
+<p>If you did not receive this Content directly from the Eclipse Foundation, the Content is 
+being redistributed by another party (&quot;Redistributor&quot;) and different terms and conditions may
+apply to your use of any object code in the Content.  Check the Redistributor's license that was 
+provided with the Content.  If no such license exists, contact the Redistributor.  Unless otherwise
+indicated below, the terms and conditions of the EPL still apply to any source code in the Content
+and such source code may be obtained at <a href="http://www.eclipse.org/">http://www.eclipse.org</a>.</p>
+
+</body>
+</html>
diff --git a/org.eclipse.emf.cdo.server.db/about.ini b/org.eclipse.emf.cdo.server.db/about.ini
new file mode 100644
index 0000000..32006ae
--- /dev/null
+++ b/org.eclipse.emf.cdo.server.db/about.ini
@@ -0,0 +1,15 @@
+# about.ini
+# contains information about a feature
+# java.io.Properties file (ISO 8859-1 with "\" escapes)
+# "%key" are externalized strings defined in about.properties
+# This file does not need to be translated.
+
+# Property "aboutText" contains blurb for "About" dialog (translated)
+aboutText=%featureText 
+
+# Property "featureImage" contains path to feature image (32x32)
+featureImage=modeling32.png
+
+# Property "appName" contains name of the application (translated)
+appName=%featureName
+
diff --git a/org.eclipse.emf.cdo.server.db/about.mappings b/org.eclipse.emf.cdo.server.db/about.mappings
new file mode 100644
index 0000000..bddaab4
--- /dev/null
+++ b/org.eclipse.emf.cdo.server.db/about.mappings
@@ -0,0 +1,6 @@
+# about.mappings
+# contains fill-ins for about.properties
+# java.io.Properties file (ISO 8859-1 with "\" escapes)
+# This file does not need to be translated.
+
+0=@build@
\ No newline at end of file
diff --git a/org.eclipse.emf.cdo.server.db/about.properties b/org.eclipse.emf.cdo.server.db/about.properties
new file mode 100644
index 0000000..949ccad
--- /dev/null
+++ b/org.eclipse.emf.cdo.server.db/about.properties
@@ -0,0 +1,31 @@
+# Copyright (c) 2004 - 2011 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
+
+# NLS_MESSAGEFORMAT_VAR
+
+# ==============================================================================
+# Do not change the properties between this line and the last line containing:
+# %%% END OF TRANSLATED PROPERTIES %%%
+# Instead, either redefine an existing property, or create a new property,
+# append it to the end of the file, and change the code to use the new name.
+# ==============================================================================
+
+featureName = CDO Model Repository Server DB
+featureText = CDO Model Repository Server DB\n\
+Version: {featureVersion}\n\
+Build id: {0}\n\
+\n\
+Copyright (c) 2004 - 2011 Eike Stepper (Berlin, Germany) and others. All rights reserved.\n\
+\n\
+Visit http://www.eclipse.org/cdo
+
+# ==============================================================================
+# %%% END OF TRANSLATED PROPERTIES %%%
+# The above properties have been shipped for translation.
+# ==============================================================================
diff --git a/org.eclipse.emf.cdo.server.db/build.properties b/org.eclipse.emf.cdo.server.db/build.properties
new file mode 100644
index 0000000..7962001
--- /dev/null
+++ b/org.eclipse.emf.cdo.server.db/build.properties
@@ -0,0 +1,29 @@
+# Copyright (c) 2004 - 2011 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
+
+# NLS_MESSAGEFORMAT_VAR
+
+source.. = src/
+output.. = bin/
+bin.includes = META-INF/,\
+               .,\
+               .options,\
+               about.html,\
+               copyright.txt,\
+               plugin.xml,\
+               schema/,\
+               plugin.properties,\
+               about.ini,\
+               about.mappings,\
+               about.properties,\
+               modeling32.png
+src.includes = about.html,\
+               copyright.txt
+
+org.eclipse.emf.cdo.releng.javadoc.project = org.eclipse.emf.cdo.doc
diff --git a/org.eclipse.emf.cdo.server.db/copyright.txt b/org.eclipse.emf.cdo.server.db/copyright.txt
new file mode 100644
index 0000000..e921242
--- /dev/null
+++ b/org.eclipse.emf.cdo.server.db/copyright.txt
@@ -0,0 +1,8 @@
+Copyright (c) 2004 - 2011 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
\ No newline at end of file
diff --git a/org.eclipse.emf.cdo.server.db/modeling32.png b/org.eclipse.emf.cdo.server.db/modeling32.png
new file mode 100644
index 0000000..6b08de2
--- /dev/null
+++ b/org.eclipse.emf.cdo.server.db/modeling32.png
Binary files differ
diff --git a/org.eclipse.emf.cdo.server.db/plugin.properties b/org.eclipse.emf.cdo.server.db/plugin.properties
new file mode 100644
index 0000000..ade0c88
--- /dev/null
+++ b/org.eclipse.emf.cdo.server.db/plugin.properties
@@ -0,0 +1,13 @@
+# Copyright (c) 2004 - 2011 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
+
+pluginName = CDO Model Repository Server DB
+providerName = Eclipse Modeling Project
+
+extension-point.name = CDO Mapping Strategies
\ No newline at end of file
diff --git a/org.eclipse.emf.cdo.server.db/plugin.xml b/org.eclipse.emf.cdo.server.db/plugin.xml
new file mode 100644
index 0000000..6abb1a8
--- /dev/null
+++ b/org.eclipse.emf.cdo.server.db/plugin.xml
@@ -0,0 +1,57 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<?eclipse version="3.4"?>
+<!--
+	Copyright (c) 2004 - 2011 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
+-->
+
+<plugin>
+
+   <extension-point id="mappingStrategies" name="%extension-point.name" schema="schema/mappingStrategies.exsd"/>
+   
+   <extension
+         point="org.eclipse.net4j.util.factories">
+      <factory
+            class="org.eclipse.emf.cdo.server.internal.db.DBBrowserPage$Factory"
+            productGroup="org.eclipse.emf.cdo.server.browserPages"
+            type="db">
+      </factory>
+   </extension>
+
+   <extension
+         point="org.eclipse.emf.cdo.server.storeFactories">
+      <storeFactory
+            class="org.eclipse.emf.cdo.server.internal.db.DBStoreFactory"
+            storeType="db">
+      </storeFactory>
+   </extension>
+
+   <extension
+         point="org.eclipse.emf.cdo.server.db.mappingStrategies">
+      <mappingStrategy
+            class="org.eclipse.emf.cdo.server.internal.db.mapping.horizontal.HorizontalMappingStrategy"
+            type="horizontal"/>
+      <mappingStrategy
+            class="org.eclipse.emf.cdo.server.internal.db.mapping.horizontal.HorizontalNonAuditMappingStrategy"
+            type="horizontalNonAuditing"/>
+      <mappingStrategy
+            class="org.eclipse.emf.cdo.server.internal.db.mapping.horizontal.HorizontalAuditMappingStrategy"
+            type="horizontalAuditing"/>
+      <mappingStrategy
+            class="org.eclipse.emf.cdo.server.internal.db.mapping.horizontal.HorizontalBranchingMappingStrategy"
+            type="horizontalBranching"/>
+      <mappingStrategy
+            class="org.eclipse.emf.cdo.server.internal.db.mapping.horizontal.HorizontalAuditMappingStrategyWithRanges"
+            type="horizontalAuditingWithRanges"/>
+      <mappingStrategy
+            class="org.eclipse.emf.cdo.server.internal.db.mapping.horizontal.HorizontalBranchingMappingStrategyWithRanges"
+            type="horizontalBranchingWithRanges"/>
+   </extension>
+   
+</plugin>
diff --git a/org.eclipse.emf.cdo.server.db/schema/mappingStrategies.exsd b/org.eclipse.emf.cdo.server.db/schema/mappingStrategies.exsd
new file mode 100644
index 0000000..c708d55
--- /dev/null
+++ b/org.eclipse.emf.cdo.server.db/schema/mappingStrategies.exsd
@@ -0,0 +1,113 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<!-- Schema file written by PDE -->
+<schema targetNamespace="org.eclipse.emf.cdo.server.db">
+<annotation>
+      <appInfo>
+         <meta.schema plugin="org.eclipse.emf.cdo.server.db" id="mappingStrategies" name="CDO Mapping Strategies"/>
+      </appInfo>
+      <documentation>
+         [Enter description of this extension point.]
+      </documentation>
+   </annotation>
+
+   <element name="extension">
+      <complexType>
+         <sequence>
+            <element ref="mappingStrategy" minOccurs="1" maxOccurs="unbounded"/>
+         </sequence>
+         <attribute name="point" type="string" use="required">
+            <annotation>
+               <documentation>
+
+               </documentation>
+            </annotation>
+         </attribute>
+         <attribute name="id" type="string">
+            <annotation>
+               <documentation>
+
+               </documentation>
+            </annotation>
+         </attribute>
+         <attribute name="name" type="string">
+            <annotation>
+               <documentation>
+
+               </documentation>
+               <appInfo>
+                  <meta.attribute translatable="true"/>
+               </appInfo>
+            </annotation>
+         </attribute>
+      </complexType>
+   </element>
+
+   <element name="mappingStrategy">
+      <complexType>
+         <attribute name="type" type="string" use="required">
+            <annotation>
+               <documentation>
+
+               </documentation>
+            </annotation>
+         </attribute>
+         <attribute name="class" type="string" use="required">
+            <annotation>
+               <documentation>
+
+               </documentation>
+               <appInfo>
+                  <meta.attribute kind="java" basedOn=":org.eclipse.emf.cdo.server.db.IMappingStrategy"/>
+               </appInfo>
+            </annotation>
+         </attribute>
+      </complexType>
+   </element>
+
+   <annotation>
+      <appInfo>
+         <meta.section type="since"/>
+      </appInfo>
+      <documentation>
+         [Enter the first release in which this extension point appears.]
+      </documentation>
+   </annotation>
+
+   <annotation>
+      <appInfo>
+         <meta.section type="examples"/>
+      </appInfo>
+      <documentation>
+         [Enter extension point usage example here.]
+      </documentation>
+   </annotation>
+
+   <annotation>
+      <appInfo>
+         <meta.section type="apiInfo"/>
+      </appInfo>
+      <documentation>
+         [Enter API information here.]
+      </documentation>
+   </annotation>
+
+   <annotation>
+      <appInfo>
+         <meta.section type="implementation"/>
+      </appInfo>
+      <documentation>
+         [Enter information about supplied implementation of this extension point.]
+      </documentation>
+   </annotation>
+
+   <annotation>
+      <appinfo>
+         <meta.section type="copyright"/>
+      </appinfo>
+      <documentation>
+         Copyright (c) 2004 - 2011 Eike Stepper (Berlin, Germany) and others.&lt;br&gt;
+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 &lt;a href=&quot;http://www.eclipse.org/legal/epl-v10.html&quot;&gt;http://www.eclipse.org/legal/epl-v10.html&lt;/a&gt;
+      </documentation>
+   </annotation>
+
+</schema>
diff --git a/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/CDODBUtil.java b/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/CDODBUtil.java
new file mode 100644
index 0000000..b5cb29a
--- /dev/null
+++ b/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/CDODBUtil.java
@@ -0,0 +1,202 @@
+/**
+ * Copyright (c) 2004 - 2011 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 - 271444: [DB] Multiple refactorings
+ *    Stefan Winkler - 249610: [DB] Support external references (Implementation)
+ */
+package org.eclipse.emf.cdo.server.db;
+
+import org.eclipse.emf.cdo.server.db.mapping.IMappingStrategy;
+import org.eclipse.emf.cdo.server.internal.db.DBBrowserPage;
+import org.eclipse.emf.cdo.server.internal.db.DBStore;
+import org.eclipse.emf.cdo.server.internal.db.SmartPreparedStatementCache;
+import org.eclipse.emf.cdo.server.internal.db.bundle.OM;
+import org.eclipse.emf.cdo.server.internal.db.mapping.horizontal.HorizontalAuditMappingStrategy;
+import org.eclipse.emf.cdo.server.internal.db.mapping.horizontal.HorizontalAuditMappingStrategyWithRanges;
+import org.eclipse.emf.cdo.server.internal.db.mapping.horizontal.HorizontalBranchingMappingStrategy;
+import org.eclipse.emf.cdo.server.internal.db.mapping.horizontal.HorizontalBranchingMappingStrategyWithRanges;
+import org.eclipse.emf.cdo.server.internal.db.mapping.horizontal.HorizontalMappingStrategy;
+import org.eclipse.emf.cdo.server.internal.db.mapping.horizontal.HorizontalNonAuditMappingStrategy;
+
+import org.eclipse.net4j.db.IDBAdapter;
+import org.eclipse.net4j.db.IDBConnectionProvider;
+import org.eclipse.net4j.util.ObjectUtil;
+import org.eclipse.net4j.util.WrappedException;
+import org.eclipse.net4j.util.container.IManagedContainer;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IExtensionRegistry;
+import org.eclipse.core.runtime.Platform;
+
+/**
+ * @author Eike Stepper
+ */
+public final class CDODBUtil
+{
+  /**
+   * @since 2.0
+   */
+  public static final int DEFAULT_STATEMENT_CACHE_CAPACITY = 200;
+
+  /**
+   * @since 2.0
+   */
+  public static final String EXT_POINT_MAPPING_STRATEGIES = "mappingStrategies"; //$NON-NLS-1$
+
+  /**
+   * @since 4.1
+   */
+  public static final String PROP_WITH_RANGES = "withRanges";
+
+  /**
+   * @since 4.1
+   */
+  public static final String PROP_COPY_ON_BRANCH = "copyOnBranch";
+
+  private CDODBUtil()
+  {
+  }
+
+  /**
+   * @since 4.0
+   */
+  public static void prepareContainer(IManagedContainer container)
+  {
+    container.registerFactory(new DBBrowserPage.Factory());
+  }
+
+  /**
+   * @since 2.0
+   */
+  public static IDBStore createStore(IMappingStrategy mappingStrategy, IDBAdapter dbAdapter,
+      IDBConnectionProvider dbConnectionProvider)
+  {
+    DBStore store = new DBStore();
+    store.setMappingStrategy(mappingStrategy);
+    store.setDBAdapter(dbAdapter);
+    store.setDbConnectionProvider(dbConnectionProvider);
+    return store;
+  }
+
+  /**
+   * @since 2.0
+   */
+  public static IMappingStrategy createHorizontalMappingStrategy(boolean auditing)
+  {
+    return createHorizontalMappingStrategy(auditing, false, false);
+  }
+
+  /**
+   * @since 3.0
+   */
+  public static IMappingStrategy createHorizontalMappingStrategy(boolean auditing, boolean branching)
+  {
+    return createHorizontalMappingStrategy(auditing, branching, false);
+  }
+
+  /**
+   * @since 4.1
+   */
+  public static IMappingStrategy createHorizontalMappingStrategy(boolean auditing, boolean branching, boolean withRanges)
+  {
+    if (branching)
+    {
+      if (auditing)
+      {
+        if (withRanges)
+        {
+          return new HorizontalBranchingMappingStrategyWithRanges();
+        }
+
+        return new HorizontalBranchingMappingStrategy();
+      }
+
+      throw new IllegalArgumentException("Misconfiguration: Branching requires Auditing!");
+    }
+
+    if (auditing)
+    {
+      if (withRanges)
+      {
+        return new HorizontalAuditMappingStrategyWithRanges();
+      }
+
+      return new HorizontalAuditMappingStrategy();
+    }
+
+    return new HorizontalNonAuditMappingStrategy();
+  }
+
+  /**
+   * Creates a horizontal {@link IMappingStrategy mapping strategy} that supports all valid combinations of auditing and
+   * branching.
+   * 
+   * @since 4.1
+   */
+  public static IMappingStrategy createHorizontalMappingStrategy()
+  {
+    return new HorizontalMappingStrategy();
+  }
+
+  /**
+   * Can only be used when Eclipse is running. In standalone scenarios create the mapping strategy instance by directly
+   * calling the constructor of the mapping strategy class.
+   * 
+   * @see #createHorizontalMappingStrategy(boolean)
+   * @see #createHorizontalMappingStrategy(boolean, boolean)
+   * @since 2.0
+   */
+  public static IMappingStrategy createMappingStrategy(String type)
+  {
+    IExtensionRegistry registry = Platform.getExtensionRegistry();
+    IConfigurationElement[] elements = registry.getConfigurationElementsFor(OM.BUNDLE_ID, EXT_POINT_MAPPING_STRATEGIES);
+    for (final IConfigurationElement element : elements)
+    {
+      if ("mappingStrategy".equals(element.getName())) //$NON-NLS-1$
+      {
+        String typeAttr = element.getAttribute("type"); //$NON-NLS-1$
+        if (ObjectUtil.equals(typeAttr, type))
+        {
+          try
+          {
+            return (IMappingStrategy)element.createExecutableExtension("class"); //$NON-NLS-1$
+          }
+          catch (CoreException ex)
+          {
+            throw WrappedException.wrap(ex);
+          }
+        }
+      }
+    }
+
+    return null;
+  }
+
+  /**
+   * Creates a prepared statement cache with the {@link CDODBUtil#DEFAULT_STATEMENT_CACHE_CAPACITY default capacity}.
+   * 
+   * @since 2.0
+   * @see CDODBUtil#createStatementCache(int)
+   */
+  public static IPreparedStatementCache createStatementCache()
+  {
+    return createStatementCache(DEFAULT_STATEMENT_CACHE_CAPACITY);
+  }
+
+  /**
+   * Creates a prepared statement cache with the given capacity.
+   * 
+   * @since 2.0
+   */
+  public static IPreparedStatementCache createStatementCache(int capacity)
+  {
+    return new SmartPreparedStatementCache(capacity);
+  }
+}
diff --git a/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/IDBStore.java b/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/IDBStore.java
new file mode 100644
index 0000000..c1c6d23
--- /dev/null
+++ b/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/IDBStore.java
@@ -0,0 +1,70 @@
+/**
+ * Copyright (c) 2004 - 2011 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 - 271444: [DB] Multiple refactorings
+ *    Stefan Winkler - 249610: [DB] Support external references (Implementation)
+ */
+package org.eclipse.emf.cdo.server.db;
+
+import org.eclipse.emf.cdo.server.ISession;
+import org.eclipse.emf.cdo.server.IStore;
+import org.eclipse.emf.cdo.server.IStore.CanHandleClientAssignedIDs;
+import org.eclipse.emf.cdo.server.ITransaction;
+import org.eclipse.emf.cdo.server.db.mapping.IMappingStrategy;
+
+import org.eclipse.net4j.db.IDBAdapter;
+import org.eclipse.net4j.db.IDBConnectionProvider;
+import org.eclipse.net4j.db.ddl.IDBSchema;
+
+/**
+ * @author Eike Stepper
+ * @noextend This interface is not intended to be extended by clients.
+ * @noimplement This interface is not intended to be implemented by clients.
+ */
+public interface IDBStore extends IStore, IDBConnectionProvider, CanHandleClientAssignedIDs
+{
+  /**
+   * @since 2.0
+   */
+  public IMappingStrategy getMappingStrategy();
+
+  /**
+   * @since 4.0
+   */
+  public IIDHandler getIDHandler();
+
+  public IDBAdapter getDBAdapter();
+
+  public IDBSchema getDBSchema();
+
+  /**
+   * Get the meta data manager associated with this DBStore.
+   * 
+   * @since 2.0
+   */
+  public IMetaDataManager getMetaDataManager();
+
+  /**
+   * @since 2.0
+   */
+  public IDBStoreAccessor getReader(ISession session);
+
+  /**
+   * @since 2.0
+   */
+  public IDBStoreAccessor getWriter(ITransaction transaction);
+
+  /**
+   * @since 4.0
+   */
+  public interface Props
+  {
+    public static final String CONNECTION_KEEPALIVE_PERIOD = "connectionKeepAlivePeriod"; //$NON-NLS-1$
+  }
+}
diff --git a/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/IDBStoreAccessor.java b/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/IDBStoreAccessor.java
new file mode 100644
index 0000000..2d50794
--- /dev/null
+++ b/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/IDBStoreAccessor.java
@@ -0,0 +1,32 @@
+/**
+ * Copyright (c) 2004 - 2011 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;
+
+import org.eclipse.emf.cdo.server.IStoreAccessor;
+
+import java.sql.Connection;
+
+/**
+ * @author Eike Stepper
+ * @noextend This interface is not intended to be extended by clients.
+ * @noimplement This interface is not intended to be implemented by clients.
+ */
+public interface IDBStoreAccessor extends IStoreAccessor.Raw
+{
+  public IDBStore getStore();
+
+  public Connection getConnection();
+
+  /**
+   * @since 2.0
+   */
+  public IPreparedStatementCache getStatementCache();
+}
diff --git a/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/IDBStoreChunkReader.java b/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/IDBStoreChunkReader.java
new file mode 100644
index 0000000..67f9bea
--- /dev/null
+++ b/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/IDBStoreChunkReader.java
@@ -0,0 +1,26 @@
+/**
+ * Copyright (c) 2004 - 2011 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;
+
+import org.eclipse.emf.cdo.server.IStoreChunkReader;
+
+/**
+ * @author Eike Stepper
+ * @noextend This interface is not intended to be extended by clients.
+ * @noimplement This interface is not intended to be implemented by clients.
+ */
+public interface IDBStoreChunkReader extends IStoreChunkReader
+{
+  /**
+   * @since 2.0
+   */
+  public IDBStoreAccessor getAccessor();
+}
diff --git a/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/IIDHandler.java b/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/IIDHandler.java
new file mode 100644
index 0000000..0bbee5d
--- /dev/null
+++ b/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/IIDHandler.java
@@ -0,0 +1,89 @@
+/**

+ * Copyright (c) 2004 - 2011 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;

+

+import org.eclipse.emf.cdo.common.id.CDOID;

+import org.eclipse.emf.cdo.common.id.CDOID.ObjectType;

+import org.eclipse.emf.cdo.common.protocol.CDODataInput;

+import org.eclipse.emf.cdo.common.protocol.CDODataOutput;

+import org.eclipse.emf.cdo.common.revision.CDORevision;

+import org.eclipse.emf.cdo.server.db.mapping.ITypeMapping;

+

+import org.eclipse.net4j.db.DBType;

+import org.eclipse.net4j.util.om.monitor.OMMonitor;

+

+import java.io.IOException;

+import java.sql.Connection;

+import java.sql.PreparedStatement;

+import java.sql.ResultSet;

+import java.sql.SQLException;

+import java.util.Comparator;

+import java.util.Set;

+

+/**

+ * @author Eike Stepper

+ * @since 4.0

+ * @noextend This interface is not intended to be extended by clients.

+ * @noimplement This interface is not intended to be implemented by clients.

+ */

+public interface IIDHandler extends Comparator<CDOID>

+{

+  public IDBStore getStore();

+

+  public DBType getDBType();

+

+  public Set<ObjectType> getObjectIDTypes();

+

+  public ITypeMapping getObjectTypeMapping();

+

+  public CDOID createCDOID(String val);

+

+  public boolean isLocalCDOID(CDOID id);

+

+  public CDOID getLastObjectID();

+

+  public void setLastObjectID(CDOID lastObjectID);

+

+  /**

+   * @since 4.1

+   */

+  public void adjustLastObjectID(CDOID maxID);

+

+  public CDOID getNextLocalObjectID();

+

+  public void setNextLocalObjectID(CDOID nextLocalObjectID);

+

+  public CDOID getNextCDOID(CDORevision revision);

+

+  public void appendCDOID(StringBuilder builder, CDOID id);

+

+  public void setCDOID(PreparedStatement stmt, int column, CDOID id) throws SQLException;

+

+  public void setCDOID(PreparedStatement stmt, int column, CDOID id, long commitTime) throws SQLException;

+

+  public CDOID getCDOID(ResultSet resultSet, int column) throws SQLException;

+

+  public CDOID getCDOID(ResultSet resultSet, String name) throws SQLException;

+

+  public CDOID getMinCDOID();

+

+  public CDOID getMaxCDOID();

+

+  public CDOID mapURI(IDBStoreAccessor accessor, String uri, long commitTime);

+

+  public String unmapURI(IDBStoreAccessor accessor, CDOID id);

+

+  public void rawExport(Connection connection, CDODataOutput out, long fromCommitTime, long toCommitTime)

+      throws IOException;

+

+  public void rawImport(Connection connection, CDODataInput in, long fromCommitTime, long toCommitTime, OMMonitor fork)

+      throws IOException;

+}

diff --git a/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/IMetaDataManager.java b/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/IMetaDataManager.java
new file mode 100644
index 0000000..972d735
--- /dev/null
+++ b/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/IMetaDataManager.java
@@ -0,0 +1,110 @@
+/**
+ * Copyright (c) 2004 - 2011 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
+ *    Kai Schlamp - bug 282976: [DB] Influence Mappings through EAnnotations
+ *    Stefan Winkler - bug 282976: [DB] Influence Mappings through EAnnotations
+ */
+package org.eclipse.emf.cdo.server.db;
+
+import org.eclipse.emf.cdo.common.id.CDOID;
+import org.eclipse.emf.cdo.common.protocol.CDODataInput;
+import org.eclipse.emf.cdo.common.protocol.CDODataOutput;
+import org.eclipse.emf.cdo.spi.common.model.InternalCDOPackageUnit;
+
+import org.eclipse.net4j.util.om.monitor.OMMonitor;
+
+import org.eclipse.emf.ecore.EModelElement;
+import org.eclipse.emf.ecore.EPackage;
+
+import java.io.IOException;
+import java.sql.Connection;
+import java.util.Collection;
+
+/**
+ * @author Eike Stepper
+ * @since 2.0
+ * @noextend This interface is not intended to be extended by clients.
+ * @noimplement This interface is not intended to be implemented by clients.
+ */
+public interface IMetaDataManager
+{
+  /**
+   * Returns the meta ID of the given {@link EModelElement}. <code> getMetaID(getMetaInstance(x))</code> yields
+   * <code>x</code>
+   * 
+   * @param modelElement
+   *          the element
+   * @return the corresponding ID
+   * @since 4.0
+   */
+  public CDOID getMetaID(EModelElement modelElement, long commitTime);
+
+  /**
+   * Returns the {@link EModelElement} referred to by the given ID. <code> getMetaInstance(getMetaID(m))</code> yields
+   * <code>m</code>
+   * 
+   * @since 4.0
+   */
+  public EModelElement getMetaInstance(CDOID id);
+
+  /**
+   * Loads a package unit from the database.
+   * 
+   * @param connection
+   *          the DB connection to read from.
+   * @param packageUnit
+   *          the package unit to load.
+   * @return the loaded package unit.
+   * @since 2.0
+   */
+  public EPackage[] loadPackageUnit(Connection connection, InternalCDOPackageUnit packageUnit);
+
+  /**
+   * @since 4.0
+   */
+  public void clearMetaIDMappings();
+
+  /**
+   * Reads information about package units present in the database.
+   * 
+   * @param connection
+   *          the DB connection to read from.
+   * @return a collection of package unit information records which can be passed to
+   *         {@link IMetaDataManager#loadPackageUnit(Connection, InternalCDOPackageUnit)} in order to read the EPackage.
+   * @since 2.0
+   */
+  public Collection<InternalCDOPackageUnit> readPackageUnits(Connection connection);
+
+  /**
+   * Write package units to the database.
+   * 
+   * @param connection
+   *          the DB connection to write to.
+   * @param packageUnits
+   *          the package units to write.
+   * @param monitor
+   *          the monitor to indicate progress.
+   * @since 2.0
+   */
+  public void writePackageUnits(Connection connection, InternalCDOPackageUnit[] packageUnits, OMMonitor monitor);
+
+  /**
+   * @since 3.0
+   */
+  public void rawExport(Connection connection, CDODataOutput out, long fromCommitTime, long toCommitTime)
+      throws IOException;
+
+  /**
+   * @since 4.0
+   */
+  public Collection<InternalCDOPackageUnit> rawImport(Connection connection, CDODataInput in, long fromCommitTime,
+      long toCommitTime, OMMonitor monitor) throws IOException;
+
+}
diff --git a/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/IPreparedStatementCache.java b/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/IPreparedStatementCache.java
new file mode 100644
index 0000000..4c81edc
--- /dev/null
+++ b/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/IPreparedStatementCache.java
@@ -0,0 +1,52 @@
+/**
+ * Copyright (c) 2004 - 2011 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 - 271444: [DB] Multiple refactorings bug 271444
+ */
+package org.eclipse.emf.cdo.server.db;
+
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+
+/**
+ * @author Stefan Winkler
+ * @since 2.0
+ * @noextend This interface is not intended to be extended by clients.
+ * @noimplement This interface is not intended to be implemented by clients.
+ */
+public interface IPreparedStatementCache
+{
+  public void setConnection(Connection connection);
+
+  public PreparedStatement getPreparedStatement(String sql, ReuseProbability reuseProbability);
+
+  public void releasePreparedStatement(PreparedStatement ps);
+
+  /**
+   * An enum for the degree of probability to which a prepared statement is reused later on. This is used for managing
+   * the cache of prepared statements so that statements which are more likely reused are kept in the cache longer. Rule
+   * of thumb:
+   * <ul>
+   * <li>For global statements which are used regularly (such as lookup object in cdo_objects) use
+   * {@link ReuseProbability#MAX MAX}.
+   * <li>For constant object-specific statements which are used regularly use {@link ReuseProbability#HIGH HIGH}.
+   * <li>For object-specific statements which are assembled from constants which are used regularly use
+   * {@link ReuseProbability#MEDIUM MEDIUM}.
+   * <li>For all other dynamic statements, like queries, use {@link ReuseProbability#LOW LOW}
+   * </ul>
+   * 
+   * @author Stefan Winkler
+   * @since 2.0
+   * @noextend This interface is not intended to be extended by clients.
+   */
+  public static enum ReuseProbability
+  {
+    MAX, HIGH, MEDIUM, LOW;
+  }
+}
diff --git a/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/mapping/AbstractTypeMapping.java b/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/mapping/AbstractTypeMapping.java
new file mode 100644
index 0000000..745e96e
--- /dev/null
+++ b/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/mapping/AbstractTypeMapping.java
@@ -0,0 +1,287 @@
+/**
+ * Copyright (c) 2004 - 2011 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 final 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 held by the
+   * {@link MetaDataManager meta-data manager}. 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/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/mapping/AbstractTypeMappingFactory.java b/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/mapping/AbstractTypeMappingFactory.java
new file mode 100644
index 0000000..4170dbf
--- /dev/null
+++ b/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/mapping/AbstractTypeMappingFactory.java
@@ -0,0 +1,43 @@
+/**
+ * Copyright (c) 2004 - 2011 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/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/mapping/IClassMapping.java b/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/mapping/IClassMapping.java
new file mode 100644
index 0000000..9775d42
--- /dev/null
+++ b/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/mapping/IClassMapping.java
@@ -0,0 +1,201 @@
+/**
+ * Copyright (c) 2004 - 2011 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 - 271444: [DB] Multiple refactorings bug 271444
+ */
+package org.eclipse.emf.cdo.server.db.mapping;
+
+import org.eclipse.emf.cdo.common.branch.CDOBranch;
+import org.eclipse.emf.cdo.common.branch.CDOBranchPoint;
+import org.eclipse.emf.cdo.common.id.CDOID;
+import org.eclipse.emf.cdo.common.revision.CDORevision;
+import org.eclipse.emf.cdo.common.revision.CDORevisionHandler;
+import org.eclipse.emf.cdo.server.IStoreAccessor;
+import org.eclipse.emf.cdo.server.IStoreAccessor.QueryXRefsContext;
+import org.eclipse.emf.cdo.server.db.IDBStoreAccessor;
+import org.eclipse.emf.cdo.spi.common.commit.CDOChangeSetSegment;
+import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevision;
+
+import org.eclipse.net4j.db.ddl.IDBTable;
+import org.eclipse.net4j.util.ImplementationError;
+import org.eclipse.net4j.util.om.monitor.OMMonitor;
+
+import org.eclipse.emf.ecore.EClass;
+import org.eclipse.emf.ecore.EStructuralFeature;
+
+import java.sql.PreparedStatement;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * Basic interface for class mappings.
+ * 
+ * @author Eike Stepper
+ * @author Stefan Winkler
+ * @since 2.0
+ */
+public interface IClassMapping
+{
+  /**
+   * @since 3.0
+   */
+  public EClass getEClass();
+
+  /**
+   * Returns all DB tables which are used by this class and all its contained features.
+   * 
+   * @return a collection of all tables of this class and all its contained features.
+   * @since 3.0
+   */
+  public List<IDBTable> getDBTables();
+
+  /**
+   * Get the mapping of the many-valued feature.
+   * 
+   * @param feature
+   *          the feature for which the mapping should be returned. <code>feature.isMany()</code> has to be
+   *          <code>true</code>.
+   * @return the list mapping corresponding to the feature.
+   */
+  public IListMapping getListMapping(EStructuralFeature feature);
+
+  /**
+   * @since 3.0
+   */
+  public List<IListMapping> getListMappings();
+
+  /**
+   * @since 4.0
+   */
+  public List<ITypeMapping> getValueMappings();
+
+  /**
+   * Read a revision. The branch and timestamp to be read are derived from the branchPoint which is set to the Revision.
+   * Note that non-audit stores only support {@link CDOBranchPoint#UNSPECIFIED_DATE} and non-branching stores only
+   * support the main branch.
+   * 
+   * @param accessor
+   *          the accessor to use.
+   * @param revision
+   *          the revision object into which the data should be read. The revision has to be have its ID set to the
+   *          requested object's ID. The version is ignored, as the version parameter is used to determine the version
+   *          to be read.
+   * @param listChunk
+   *          the chunk size to read attribute lists.
+   * @return <code>true</code>, if the revision has been found and read correctly. <code>false</code> if the revision
+   *         could not be found. In this case, the content of <code>revision</code> is undefined.
+   */
+  public boolean readRevision(IDBStoreAccessor accessor, InternalCDORevision revision, int listChunk);
+
+  /**
+   * Write the revision data to the database.
+   * 
+   * @param accessor
+   *          the accessor to use.
+   * @param revision
+   *          the revision to write.
+   * @param mapType
+   *          <code>true</code> if the type of the object is supposed to be mapped, <code>false</code> otherwise.
+   * @param revise
+   *          <code>true</code> if the previous revision is supposed to be revised, <code>false</code> otherwise.
+   * @param monitor
+   *          the monitor to indicate progress.
+   * @since 4.0
+   */
+  public void writeRevision(IDBStoreAccessor accessor, InternalCDORevision revision, boolean mapType, boolean revise,
+      OMMonitor monitor);
+
+  /**
+   * Detaches (deletes) a CDO object leaving a "ghost" revision behind.
+   * 
+   * @param accessor
+   *          the accessor to use.
+   * @param id
+   *          the id to revise.
+   * @param version
+   *          the last valid version.
+   * @param timeStamp
+   *          the timestamp of detach.
+   * @param monitor
+   *          the monitor to indicate progress.
+   * @since 3.0
+   */
+  public void detachObject(IDBStoreAccessor accessor, CDOID id, int version, CDOBranch branch, long timeStamp,
+      OMMonitor monitor);
+
+  /**
+   * Create a prepared statement which returns all IDs of instances of the corresponding class.
+   * 
+   * @param accessor
+   *          the accessor to use to create the statement
+   * @return the prepared statement ready to be executed using <code>result.executeQuery()</code>.
+   * @since 3.0
+   */
+  public PreparedStatement createObjectIDStatement(IDBStoreAccessor accessor);
+
+  /**
+   * Create a prepared statement which returns all IDs of instances of the corresponding class.
+   * 
+   * @param accessor
+   *          the accessor to use to create the statement
+   * @param folderId
+   *          the ID of the containing folder. <code>0</code> means none.
+   * @param name
+   *          the name of the resource node to look up
+   * @param exactMatch
+   *          if <code>true</code>, <code>name</code> must match exactly, otherwise all resource nodes starting with
+   *          <code>name</code> are returned.
+   * @param branchPoint
+   *          a branchPoint (branch and timestamp). A timestamp in the past if past versions should be looked up. In
+   *          case of no audit support, this must be {@link CDORevision#UNSPECIFIED_DATE}. In case of non branching
+   *          support the branch id must be equal to {@link CDOBranch#MAIN_BRANCH_ID}.
+   * @return the prepared statement ready to be executed using <code>result.executeQuery()</code>.
+   * @throws ImplementationError
+   *           if called on a mapping which does not map an <code>EClass instanceof CDOResourceNode</code>.
+   * @since 3.0
+   */
+  public PreparedStatement createResourceQueryStatement(IDBStoreAccessor accessor, CDOID folderId, String name,
+      boolean exactMatch, CDOBranchPoint branchPoint);
+
+  /**
+   * Passes all revisions of the store to the {@link CDORevisionHandler handler} if <b>all</b> of the following
+   * conditions are met:
+   * <ul>
+   * <li>The <code>branch</code> parameter is <code>null</code> or equal to <code>revision.getBranch()</code>.
+   * <li>The <code>timeStamp</code> parameter is {@link CDOBranchPoint#UNSPECIFIED_DATE} or equal to
+   * <code>revision.getTimeStamp()</code>.
+   * </ul>
+   * 
+   * @see IMappingStrategy#handleRevisions(IDBStoreAccessor, org.eclipse.emf.ecore.EClass, CDOBranch, long, boolean,
+   *      CDORevisionHandler)
+   * @since 4.0
+   */
+  public void handleRevisions(IDBStoreAccessor accessor, CDOBranch branch, long timeStamp, boolean exactTime,
+      CDORevisionHandler handler);
+
+  /**
+   * Returns a set of CDOIDs that have at least one revision in any of the passed branches and time ranges.
+   * DetachedCDORevisions must also be considered!
+   * 
+   * @see IStoreAccessor#readChangeSet(OMMonitor, CDOChangeSetSegment...)
+   * @since 3.0
+   */
+  public Set<CDOID> readChangeSet(IDBStoreAccessor accessor, CDOChangeSetSegment[] segments);
+
+  /**
+   * Retrieve cross-references from DB
+   * 
+   * @param idString
+   *          a string of the form "(id1, id2, id3, ...)" which can be used directly in SQL to form the where-part
+   *          "SELECT * FROM foobar WHERE foobar.target IN [idString]".
+   * @see IStoreAccessor#queryXRefs(QueryXRefsContext)
+   * @since 4.0
+   */
+  public boolean queryXRefs(IDBStoreAccessor accessor, QueryXRefsContext context, String idString);
+}
diff --git a/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/mapping/IClassMappingAuditSupport.java b/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/mapping/IClassMappingAuditSupport.java
new file mode 100644
index 0000000..5a1b13f
--- /dev/null
+++ b/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/mapping/IClassMappingAuditSupport.java
@@ -0,0 +1,44 @@
+/**
+ * Copyright (c) 2004 - 2011 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 - 271444: [DB] Multiple refactorings bug 271444
+ */
+package org.eclipse.emf.cdo.server.db.mapping;
+
+import org.eclipse.emf.cdo.server.db.IDBStoreAccessor;
+import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevision;
+
+/**
+ * Interface which complements {@link IClassMapping} with methods to facilitate audit support.
+ * 
+ * @see IMappingStrategy#hasAuditSupport()
+ * @author Eike Stepper
+ * @author Stefan Winkler
+ * @since 2.0
+ */
+public interface IClassMappingAuditSupport
+{
+  /**
+   * Read a specific version of a revision. If this method returns <code>true</code> it is guaranteed that
+   * <code>revision.getVersion() == version</code>
+   * 
+   * @param storeAccessor
+   *          the accessor to use.
+   * @param revision
+   *          the revision object into which the data should be read. The revision has to be have its ID set to the
+   *          requested object's ID. The version is ignored, as the version parameter is used to determine the version
+   *          to be read.
+   * @param listChunk
+   *          the chunk size to read attribute lists.
+   * @return <code>true</code>, if the revision has been found and read correctly. <code>false</code> if the revision
+   *         could not be found. In this case, the content of <code>revision</code> is undefined.
+   * @since 3.0
+   */
+  public boolean readRevisionByVersion(IDBStoreAccessor storeAccessor, InternalCDORevision revision, int listChunk);
+}
diff --git a/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/mapping/IClassMappingDeltaSupport.java b/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/mapping/IClassMappingDeltaSupport.java
new file mode 100644
index 0000000..86bf12e
--- /dev/null
+++ b/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/mapping/IClassMappingDeltaSupport.java
@@ -0,0 +1,43 @@
+/**
+ * Copyright (c) 2004 - 2011 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 - 271444: [DB] Multiple refactorings bug 271444
+ */
+package org.eclipse.emf.cdo.server.db.mapping;
+
+import org.eclipse.emf.cdo.server.db.IDBStoreAccessor;
+import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevisionDelta;
+
+import org.eclipse.net4j.util.om.monitor.OMMonitor;
+
+/**
+ * Interface which complements {@link IClassMapping} with methods to facilitate revision delta support.
+ * 
+ * @see IMappingStrategy#hasDeltaSupport()
+ * @author Eike Stepper
+ * @author Stefan Winkler
+ * @since 2.0
+ */
+public interface IClassMappingDeltaSupport
+{
+  /**
+   * Write a revision delta.
+   * 
+   * @param accessor
+   *          the accessor to use.
+   * @param delta
+   *          the delta to write.
+   * @param created
+   *          the creation timestamp of the new version
+   * @param monitor
+   *          the monitor to report progress.
+   */
+  public void writeRevisionDelta(IDBStoreAccessor accessor, InternalCDORevisionDelta delta, long created,
+      OMMonitor monitor);
+}
diff --git a/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/mapping/IListMapping.java b/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/mapping/IListMapping.java
new file mode 100644
index 0000000..bb09fa2
--- /dev/null
+++ b/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/mapping/IListMapping.java
@@ -0,0 +1,113 @@
+/**
+ * Copyright (c) 2004 - 2011 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 - major refactoring
+ */
+package org.eclipse.emf.cdo.server.db.mapping;
+
+import org.eclipse.emf.cdo.common.id.CDOID;
+import org.eclipse.emf.cdo.common.revision.CDORevision;
+import org.eclipse.emf.cdo.server.IStoreAccessor;
+import org.eclipse.emf.cdo.server.IStoreAccessor.QueryXRefsContext;
+import org.eclipse.emf.cdo.server.IStoreChunkReader.Chunk;
+import org.eclipse.emf.cdo.server.db.IDBStoreAccessor;
+import org.eclipse.emf.cdo.server.db.IDBStoreChunkReader;
+import org.eclipse.emf.cdo.spi.common.revision.InternalCDOList;
+import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevision;
+
+import org.eclipse.net4j.db.ddl.IDBTable;
+
+import org.eclipse.emf.ecore.EStructuralFeature;
+
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * Interface for mapping features with <code>isMany() == true</code>.
+ * 
+ * @author Eike Stepper
+ * @author Stefan Winkler
+ * @since 2.0
+ */
+public interface IListMapping
+{
+  /**
+   * Return the mapped feature.
+   * 
+   * @return the mapped feature.
+   */
+  public EStructuralFeature getFeature();
+
+  /**
+   * Returns all DB tables which are used by this feature.
+   * 
+   * @return a collection of all tables of this feature.
+   */
+  public Collection<IDBTable> getDBTables();
+
+  /**
+   * Write a complete list of values to the database.
+   * 
+   * @param accessor
+   *          the accessor to use.
+   * @param revision
+   *          the revision containing the list to be written.
+   */
+  public void writeValues(IDBStoreAccessor accessor, InternalCDORevision revision);
+
+  /**
+   * Read the list size and the complete list or the first part of it.
+   * 
+   * @param accessor
+   *          the accessor to use.
+   * @param revision
+   *          the revision into which the list values should be read.
+   * @param listChunk
+   *          indicating the lazy loading behavior: {@link CDORevision#UNCHUNKED} means that the whole list should be
+   *          read. Else, if <code>listChunk >= 0</code>, the list is filled with {@link InternalCDOList#UNINITIALIZED}
+   *          and only the first <code>listChunk</code> values are read.
+   */
+  public void readValues(IDBStoreAccessor accessor, InternalCDORevision revision, int listChunk);
+
+  /**
+   * Used to load-on-demand chunks of a list.
+   * 
+   * @param dbStoreChunkReader
+   *          the chunkReader to use
+   * @param chunks
+   *          the chunks to read
+   * @param where
+   *          the where-clause to use in order to read the chunks.
+   */
+  public void readChunks(IDBStoreChunkReader dbStoreChunkReader, List<Chunk> chunks, String where);
+
+  /**
+   * Hook with which a list mapping is notified that a containing object has been revised. Can be implemented in order
+   * to clean up lists of revised objects.
+   * 
+   * @param accessor
+   *          the accessor to use.
+   * @param id
+   *          the ID of the object which has been revised.
+   * @param revised
+   *          the timestamp at which the object was revised.
+   * @since 3.0
+   */
+  public void objectDetached(IDBStoreAccessor accessor, CDOID id, long revised);
+
+  /**
+   * Retrieve cross-references from DB.
+   * 
+   * @see IClassMapping#queryXRefs(IDBStoreAccessor, IStoreAccessor.QueryXRefsContext, String)
+   * @see IStoreAccessor#queryXRefs(IStoreAccessor.QueryXRefsContext)
+   * @since 4.0
+   */
+  public boolean queryXRefs(IDBStoreAccessor accessor, String mainTableName, String mainTableWhere,
+      QueryXRefsContext context, String idString);
+}
diff --git a/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/mapping/IListMappingDeltaSupport.java b/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/mapping/IListMappingDeltaSupport.java
new file mode 100644
index 0000000..5ed5698
--- /dev/null
+++ b/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/mapping/IListMappingDeltaSupport.java
@@ -0,0 +1,47 @@
+/**
+ * Copyright (c) 2004 - 2011 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 - 271444: [DB] Multiple refactorings bug 271444
+ *    Stefan Winkler - Bug 329025: [DB] Support branching for range-based mapping strategy
+ */
+package org.eclipse.emf.cdo.server.db.mapping;
+
+import org.eclipse.emf.cdo.common.id.CDOID;
+import org.eclipse.emf.cdo.common.revision.delta.CDOListFeatureDelta;
+import org.eclipse.emf.cdo.server.db.IDBStoreAccessor;
+
+/**
+ * Interface to complement {@link IListMapping} in order to provide list delta processing support.
+ * 
+ * @author Eike Stepper
+ * @author Stefan Winkler
+ * @since 2.0
+ */
+public interface IListMappingDeltaSupport
+{
+  /**
+   * Process a set of CDOFeatureDeltas for a many-valued feature.
+   * 
+   * @param accessor
+   *          the accessor to use
+   * @param id
+   *          the ID of the revision affected
+   * @param oldVersion
+   *          the original version of the revision
+   * @param newVersion
+   *          the new revision of the revision (after the change)
+   * @param created
+   *          the creation date for the new revision
+   * @param delta
+   *          the {@link CDOListFeatureDelta} which contains the list deltas.
+   * @since 4.0
+   */
+  public void processDelta(IDBStoreAccessor accessor, CDOID id, int branchId, int oldVersion, int newVersion,
+      long created, CDOListFeatureDelta delta);
+}
diff --git a/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/mapping/IMappingStrategy.java b/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/mapping/IMappingStrategy.java
new file mode 100644
index 0000000..90c6516
--- /dev/null
+++ b/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/mapping/IMappingStrategy.java
@@ -0,0 +1,348 @@
+/**
+ * Copyright (c) 2004 - 2011 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 - 271444: [DB] Multiple refactorings bug 271444
+ */
+package org.eclipse.emf.cdo.server.db.mapping;
+
+import org.eclipse.emf.cdo.common.branch.CDOBranch;
+import org.eclipse.emf.cdo.common.branch.CDOBranchPoint;
+import org.eclipse.emf.cdo.common.id.CDOID;
+import org.eclipse.emf.cdo.common.model.CDOClassifierRef;
+import org.eclipse.emf.cdo.common.protocol.CDODataInput;
+import org.eclipse.emf.cdo.common.protocol.CDODataOutput;
+import org.eclipse.emf.cdo.common.revision.CDORevisionHandler;
+import org.eclipse.emf.cdo.server.IStoreAccessor;
+import org.eclipse.emf.cdo.server.IStoreAccessor.QueryResourcesContext;
+import org.eclipse.emf.cdo.server.IStoreAccessor.QueryXRefsContext;
+import org.eclipse.emf.cdo.server.db.IDBStore;
+import org.eclipse.emf.cdo.server.db.IDBStoreAccessor;
+import org.eclipse.emf.cdo.server.internal.db.DBStore;
+import org.eclipse.emf.cdo.spi.common.commit.CDOChangeSetSegment;
+import org.eclipse.emf.cdo.spi.common.model.InternalCDOPackageUnit;
+
+import org.eclipse.net4j.db.IDBAdapter;
+import org.eclipse.net4j.util.collection.CloseableIterator;
+import org.eclipse.net4j.util.om.monitor.OMMonitor;
+
+import org.eclipse.emf.ecore.EClass;
+import org.eclipse.emf.ecore.ENamedElement;
+import org.eclipse.emf.ecore.EStructuralFeature;
+
+import java.io.IOException;
+import java.sql.Connection;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * The mapping strategy acts as a connection between the DBStore and the database management (and OR-mapping) classes.
+ * The {@link DBStore} uses methods of this interface to create and lookup mappings (or mappers, as they could also be
+ * named as such) and to get properties and informations about the mappings used. The mapping classes (e.g., instances
+ * of IClassMapping and IListMapping) also use this class as a central point of information and as a resource of common
+ * functionalities.
+ * 
+ * @author Eike Stepper
+ * @author Stefan Winkler
+ * @since 2.0
+ */
+public interface IMappingStrategy
+{
+  /**
+   * Name of the integer property that configures the maximum length for table names. A value of zero indicates the
+   * value of the {@link IDBAdapter#getMaxTableNameLength() db adapter} to be used.
+   */
+  public static final String PROP_MAX_TABLE_NAME_LENGTH = "maxTableNameLength"; //$NON-NLS-1$
+
+  /**
+   * Name of the integer property that configures the maximum length for column names. A value of zero indicates the
+   * value of the {@link IDBAdapter#getMaxFieldNameLength() db adapter} to be used.
+   */
+  public static final String PROP_MAX_FIELD_NAME_LENGTH = "maxFieldNameLength"; //$NON-NLS-1$
+
+  /**
+   * Name of the String property that specifies a common prefix for table names.
+   */
+  public static final String PROP_TABLE_NAME_PREFIX = "tableNamePrefix"; //$NON-NLS-1$
+
+  /**
+   * Name of the boolean property that configures whether the table names are made of simple class names or of qualified
+   * class names.
+   */
+  public static final String PROP_QUALIFIED_NAMES = "qualifiedNames"; //$NON-NLS-1$
+
+  /**
+   * Name of the boolean property that configures whether table names and column names are always suffixed with the
+   * internal DBID or only in cases where generated names violate the naming constraints of the underlying backend.
+   */
+  public static final String PROP_FORCE_NAMES_WITH_ID = "forceNamesWithID"; //$NON-NLS-1$
+
+  /**
+   * Name of the integer property that configures the size of the object type in-memory cache. Possible configuration
+   * values are:
+   * <ul>
+   * <li>0 (zero). Don't use memory caching.
+   * <li>&gt;0. Use memory caching with the cache size given.
+   * </ul>
+   * Default is a memory cache size of 10,000,000.
+   * <p>
+   * 
+   * @since 4.0
+   */
+  public static final String PROP_OBJECT_TYPE_CACHE_SIZE = "objectTypeCacheSize"; //$NON-NLS-1$
+
+  /**
+   * @return the store, this MappingStrategy instance belongs to.
+   */
+  public IDBStore getStore();
+
+  /**
+   * Set the store to which this MappingStrategy instance belongs. Should only be called by the {@link DBStore}, and
+   * only once to initialize the connection between {@link DBStore} and mapping strategy.
+   * 
+   * @param dbStore
+   *          the DBStore instance to which this MappingStrategy instance belongs.
+   */
+  public void setStore(IDBStore dbStore);
+
+  /**
+   * Factory for value mappings of single-valued attributes.
+   * 
+   * @param feature
+   *          the feature for which a mapping should be created. It must hold <code>feature.isMany() == false</code>.
+   * @return the mapping created.
+   */
+  public ITypeMapping createValueMapping(EStructuralFeature feature);
+
+  /**
+   * Factory for value mappings of multi-valued-attributes.
+   * 
+   * @param containingClass
+   *          the class containing the feature.
+   * @param feature
+   *          the feature for which a mapping should be created. It must hold <code>feature.isMany() == true</code>.
+   */
+  public IListMapping createListMapping(EClass containingClass, EStructuralFeature feature);
+
+  /**
+   * Create a suitable table name which can be used to map the given element. Should only be called by mapping classes.
+   * 
+   * @param element
+   *          the element for which the name should be created. It must hold:
+   *          <code>element instanceof EClass || element instanceof EPackage</code>.
+   * @return the created table name. It is guaranteed that the table name is compatible with the chosen database.
+   */
+  public String getTableName(ENamedElement element);
+
+  /**
+   * Create a suitable table name which can be used to map the given element. Should only be called by mapping classes.
+   * Should only be called by mapping classes.
+   * 
+   * @param containingClass
+   *          the class containeng the feature.
+   * @param feature
+   *          the feature for which the table name should be created.
+   * @return the created table name. It is guaranteed that the table name is compatible with the chosen database.
+   */
+  public String getTableName(EClass containingClass, EStructuralFeature feature);
+
+  /**
+   * Create a suitable column name which can be used to map the given element. Should only be called by mapping classes.
+   * 
+   * @param feature
+   *          the feature for which the column name should be created.
+   * @return the created column name. It is guaranteed that the name is compatible with the chosen database.
+   */
+  public String getFieldName(EStructuralFeature feature);
+
+  /**
+   * Create and initialize the mapping infrastructure for the given packages. Should be called from the DBStore or the
+   * DBStoreAccessor.
+   * 
+   * @param connection
+   *          the connection to use.
+   * @param packageUnits
+   *          the packages whose elements should be mapped.
+   * @param monitor
+   *          the monitor to report progress.
+   */
+  public void createMapping(Connection connection, InternalCDOPackageUnit[] packageUnits, OMMonitor monitor);
+
+  /**
+   * Remove the mapping infrastructure for the given packages. Should be called from the DBStore or the DBStoreAccessor.
+   * 
+   * @param connection
+   *          the connection to use.
+   * @param packageUnits
+   *          the packages for which the mappings should be removed
+   * @since 4.0
+   */
+  // Bugzilla 298632
+  public void removeMapping(Connection connection, InternalCDOPackageUnit[] packageUnits);
+
+  /**
+   * Look up an existing class mapping for the given class. Before this method is called, the class mapping must have
+   * been initialized by calling {@link #createMapping(Connection, InternalCDOPackageUnit[], OMMonitor)} on its
+   * containing package.
+   * 
+   * @param eClass
+   *          the class to look up.
+   * @return the class mapping.
+   */
+  public IClassMapping getClassMapping(EClass eClass);
+
+  /**
+   * Returns all class mappings of this strategy.
+   * 
+   * @since 4.0
+   */
+  public Map<EClass, IClassMapping> getClassMappings();
+
+  /**
+   * Returns all class mappings of this strategy.
+   * 
+   * @since 4.0
+   */
+  public Map<EClass, IClassMapping> getClassMappings(boolean createOnDemand);
+
+  /**
+   * Query if this mapping supports revision deltas. <br>
+   * If this method returns <code>true</code>, it is guaranteed that all class mappings returned by
+   * {@link #getClassMapping(EClass)} implement {@link IClassMappingDeltaSupport}.
+   * 
+   * @return <code>true</code> if revision deltas are supported, <code>false</code> else.
+   */
+  public boolean hasDeltaSupport();
+
+  /**
+   * Query if this mapping supports audits. <br>
+   * If this method returns <code>true</code>, it is guaranteed that all class mappings returned by
+   * {@link #getClassMapping(EClass)} implement {@link IClassMappingAuditSupport}.
+   * 
+   * @return <code>true</code> if audits are supported, <code>false</code> else.
+   */
+  public boolean hasAuditSupport();
+
+  /**
+   * Query if this mapping supports branches. <br>
+   * 
+   * @return <code>true</code> if branches are supported, <code>false</code> else.
+   * @since 3.0
+   */
+  public boolean hasBranchingSupport();
+
+  /**
+   * Executes a resource query.
+   * 
+   * @param accessor
+   *          the accessor to use.
+   * @param context
+   *          the context from which the query parameters are read and to which the result is written.
+   */
+  public void queryResources(IDBStoreAccessor accessor, QueryResourcesContext context);
+
+  /**
+   * Executes a cross reference query.
+   * 
+   * @param accessor
+   *          the accessor to use.
+   * @param context
+   *          the context from which the query parameters are read and to which the result is written.
+   * @since 3.0
+   */
+  public void queryXRefs(IDBStoreAccessor accessor, QueryXRefsContext context);
+
+  /**
+   * Read the type (i.e. class) of the object referred to by a given ID.
+   * 
+   * @param accessor
+   *          the accessor to use to look up the type.
+   * @param id
+   *          the ID of the object for which the type is to be determined.
+   * @return the type of the object.
+   */
+  public CDOClassifierRef readObjectType(IDBStoreAccessor accessor, CDOID id);
+
+  /**
+   * Get an iterator over all instances of objects in the store.
+   * 
+   * @param accessor
+   *          the accessor to use.
+   * @return the iterator.
+   */
+  public CloseableIterator<CDOID> readObjectIDs(IDBStoreAccessor accessor);
+
+  /**
+   * Return the maximum object id used in the store. This is used by the DBStore if a previous crash is discovered
+   * during the startup process. Should only be called by the DBStore and only during startup.
+   * 
+   * @param dbAdapter
+   *          the dbAdapter to use to access the database
+   * @param connection
+   *          the connection to use to access the database
+   * @since 4.0
+   */
+  public void repairAfterCrash(IDBAdapter dbAdapter, Connection connection);
+
+  /**
+   * Returns the configuration properties of this mapping strategy.
+   * 
+   * @since 4.0
+   */
+  public Map<String, String> getProperties();
+
+  /**
+   * Set configuration properties for this mapping strategy. Should only be called by the factory creating the mapping
+   * strategy instance.
+   * 
+   * @param properties
+   *          the configuration properties to set.
+   */
+  public void setProperties(Map<String, String> properties);
+
+  /**
+   * Passes all revisions of the store to the {@link CDORevisionHandler handler} if <b>all</b> of the following
+   * conditions are met:
+   * <ul>
+   * <li>The <code>eClass</code> parameter is <code>null</code> or equal to <code>revision.getEClass()</code>.
+   * <li>The <code>branch</code> parameter is <code>null</code> or equal to <code>revision.getBranch()</code>.
+   * <li>The <code>timeStamp</code> parameter is {@link CDOBranchPoint#UNSPECIFIED_DATE} or equal to
+   * <code>revision.getTimeStamp()</code>.
+   * </ul>
+   * 
+   * @since 4.0
+   */
+  public void handleRevisions(IDBStoreAccessor accessor, EClass eClass, CDOBranch branch, long timeStamp,
+      boolean exactTime, CDORevisionHandler handler);
+
+  /**
+   * Returns a set of CDOIDs that have at least one revision in any of the passed branches and time ranges.
+   * DetachedCDORevisions must also be considered!
+   * 
+   * @see IStoreAccessor#readChangeSet(OMMonitor, CDOChangeSetSegment...)
+   * @since 4.0
+   */
+  public Set<CDOID> readChangeSet(IDBStoreAccessor accessor, OMMonitor monitor, CDOChangeSetSegment[] segments);
+
+  /**
+   * @since 3.0
+   */
+  public void rawExport(IDBStoreAccessor accessor, CDODataOutput out, int lastReplicatedBranchID, int lastBranchID,
+      long lastReplicatedCommitTime, long lastCommitTime) throws IOException;
+
+  /**
+   * @since 4.0
+   */
+  public void rawImport(IDBStoreAccessor accessor, CDODataInput in, long fromCommitTime, long toCommitTime,
+      OMMonitor monitor) throws IOException;
+
+  /**
+   * @since 4.0
+   */
+  public String getListJoin(String attrTable, String listTable);
+}
diff --git a/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/mapping/ITypeMapping.java b/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/mapping/ITypeMapping.java
new file mode 100644
index 0000000..c6d463c
--- /dev/null
+++ b/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/mapping/ITypeMapping.java
@@ -0,0 +1,278 @@
+/**
+ * Copyright (c) 2004 - 2011 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 - major refactoring
+ *    Christopher Albert - 254455: [DB] Support FeatureMaps bug 254455
+ */
+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.
+ * 
+ * @author Eike Stepper
+ * @author Stefan Winkler
+ * @since 2.0
+ */
+public interface ITypeMapping
+{
+  /**
+   * @return The feature which is associated with this mapping.
+   */
+  public EStructuralFeature getFeature();
+
+  /**
+   * @return The db field which is associated with this mapping.
+   */
+  public IDBField getField();
+
+  /**
+   * @return The db type which is associated with this mapping.
+   * @since 3.0
+   */
+  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
+   *          the table to add this field to.
+   */
+  public void createDBField(IDBTable table);
+
+  /**
+   * Creates the DBField and adds it to the given table. The name of the DBField is explicitly determined by the
+   * corresponding parameter.
+   * 
+   * @param table
+   *          the table to add this field to.
+   * @param fieldName
+   *          the name for the DBField.
+   */
+  public void createDBField(IDBTable table, String fieldName);
+
+  /**
+   * Sets the DBField. The name of the DBField is explicitly determined by the corresponding parameter.
+   * 
+   * @param table
+   *          the table to add this field to.
+   * @param fieldName
+   *          the name for the DBField.
+   * @since 3.0
+   */
+  public void setDBField(IDBTable table, String fieldName);
+
+  /**
+   * Set the given value to the JDBC {@link PreparedStatement} using an appropriate <code>setXxx</code> method.
+   * 
+   * @param stmt
+   *          the prepared statement to set the value
+   * @param index
+   *          the index to use for the <code>setXxx</code> method.
+   * @param value
+   *          the value to set.
+   * @throws SQLException
+   *           if the <code>setXxx</code> throws it.
+   */
+  public void setValue(PreparedStatement stmt, int index, Object value) throws SQLException;
+
+  /**
+   * Set the feature's default value to the JDBC {@link PreparedStatement} using an appropriate <code>setXxx</code>
+   * method.
+   * 
+   * @param stmt
+   *          the prepared statement to set the value
+   * @param index
+   *          the index to use for the <code>setXxx</code> method.
+   * @throws SQLException
+   *           if the <code>setXxx</code> throws it.
+   * @since 3.0
+   */
+  public void setDefaultValue(PreparedStatement stmt, int index) throws SQLException;
+
+  /**
+   * Set a value of the given revision to the JDBC {@link PreparedStatement} using an appropriate <code>setXxx</code>
+   * method. The feature from which the value is taken is determined by {@link #getFeature()}.
+   * 
+   * @param stmt
+   *          the prepared statement to set the value
+   * @param index
+   *          the index to use for the <code>setXxx</code> method.
+   * @param value
+   *          the revision to get the value to set from.
+   * @throws SQLException
+   *           if the <code>setXxx</code> throws it.
+   */
+  public void setValueFromRevision(PreparedStatement stmt, int index, InternalCDORevision value) throws SQLException;
+
+  /**
+   * Read the value from a {@link ResultSet} and convert it from the DB to the CDO representation. The resultSet field
+   * to read from is determined automatically by the internal {@link #getField()} name.
+   * 
+   * @param resultSet
+   *          the result set to read from
+   * @return the read value
+   * @throws SQLException
+   *           if reading the value throws an SQLException
+   * @since 3.0
+   */
+  public Object readValue(ResultSet resultSet) throws SQLException;
+
+  /**
+   * Read a value from a {@link ResultSet}, convert it from the DB to the CDO representation and set it to the feature
+   * of the revision. The feature is determined by getFeature() The resultSet field to read from is determined
+   * automatically by the internal {@link #getField()} name.
+   * 
+   * @param resultSet
+   *          the result set to read from
+   * @param revision
+   *          the revision to which the value should be set.
+   * @throws SQLException
+   *           if reading the value throws an SQLException
+   * @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/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/mapping/package-info.java b/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/mapping/package-info.java
new file mode 100644
index 0000000..cec7a93
--- /dev/null
+++ b/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/mapping/package-info.java
@@ -0,0 +1,15 @@
+/*

+ * Copyright (c) 2004 - 2011 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

+ */

+

+/**

+ * Server concepts for dealing with mapping strategies and mappings for classes, lists and types.

+ */

+package org.eclipse.emf.cdo.server.db.mapping;

diff --git a/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/package-info.java b/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/package-info.java
new file mode 100644
index 0000000..53e5399
--- /dev/null
+++ b/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/package-info.java
@@ -0,0 +1,15 @@
+/*

+ * Copyright (c) 2004 - 2011 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

+ */

+

+/**

+ * Server concepts for dealing with DB stores and accessors.

+ */

+package org.eclipse.emf.cdo.server.db;

diff --git a/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/AbstractPreparedStatementCache.java b/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/AbstractPreparedStatementCache.java
new file mode 100644
index 0000000..2ffd031
--- /dev/null
+++ b/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/AbstractPreparedStatementCache.java
@@ -0,0 +1,47 @@
+/**
+ * Copyright (c) 2004 - 2011 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;
+
+import org.eclipse.emf.cdo.server.db.IPreparedStatementCache;
+
+import org.eclipse.net4j.util.lifecycle.Lifecycle;
+
+import java.sql.Connection;
+
+/**
+ * @author Stefan Winkler
+ * @since 2.0
+ */
+public abstract class AbstractPreparedStatementCache extends Lifecycle implements IPreparedStatementCache
+{
+  private Connection connection;
+
+  public AbstractPreparedStatementCache()
+  {
+  }
+
+  public final Connection getConnection()
+  {
+    return connection;
+  }
+
+  public final void setConnection(Connection connection)
+  {
+    checkInactive();
+    this.connection = connection;
+  }
+
+  @Override
+  protected void doBeforeActivate()
+  {
+    checkState(connection, "Must have valid connection to start"); //$NON-NLS-1$
+  }
+}
diff --git a/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/CDODBSchema.java b/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/CDODBSchema.java
new file mode 100644
index 0000000..dc3e19b
--- /dev/null
+++ b/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/CDODBSchema.java
@@ -0,0 +1,267 @@
+/**
+ * Copyright (c) 2004 - 2011 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 - 271444: [DB] Multiple refactorings bug 271444
+ *    Stefan Winkler - 249610: [DB] Support external references (Implementation)
+ *    Andre Dietisheim - bug 256649
+ *
+ */
+package org.eclipse.emf.cdo.server.internal.db;
+
+import org.eclipse.net4j.db.DBType;
+import org.eclipse.net4j.db.ddl.IDBField;
+import org.eclipse.net4j.db.ddl.IDBIndex;
+import org.eclipse.net4j.db.ddl.IDBTable;
+import org.eclipse.net4j.spi.db.DBSchema;
+
+/**
+ * @author Eike Stepper
+ */
+public class CDODBSchema extends DBSchema
+{
+  public static final CDODBSchema INSTANCE = new CDODBSchema();
+
+  /**
+   * DBTable cdo_properties
+   */
+  public static final IDBTable PROPERTIES = INSTANCE.addTable("cdo_properties"); //$NON-NLS-1$
+
+  public static final IDBField PROPERTIES_NAME = //
+  PROPERTIES.addField("name", DBType.VARCHAR, 255); //$NON-NLS-1$
+
+  public static final IDBField PROPERTIES_VALUE = //
+  PROPERTIES.addField("value", DBType.LONGVARCHAR); //$NON-NLS-1$
+
+  public static final IDBIndex INDEX_PROPERTIES_PK = //
+  PROPERTIES.addIndex(IDBIndex.Type.PRIMARY_KEY, PROPERTIES_NAME);
+
+  public static final String SQL_DELETE_PROPERTIES = "DELETE FROM " + PROPERTIES + " WHERE " + PROPERTIES_NAME + "=?"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+
+  public static final String SQL_INSERT_PROPERTIES = "INSERT INTO " + PROPERTIES + " (" + PROPERTIES_NAME + ", " //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+      + PROPERTIES_VALUE + ") VALUES (?, ?)"; //$NON-NLS-1$
+
+  public static final String SQL_SELECT_PROPERTIES = "SELECT " + PROPERTIES_VALUE + " FROM " + PROPERTIES + " WHERE " //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+      + PROPERTIES_NAME + "=?"; //$NON-NLS-1$
+
+  public static final String SQL_SELECT_ALL_PROPERTIES = "SELECT " + PROPERTIES_NAME + ", " + PROPERTIES_VALUE //$NON-NLS-1$ //$NON-NLS-2$
+      + " FROM " + PROPERTIES; //$NON-NLS-1$
+
+  /**
+   * DBTable cdo_package_units
+   */
+  public static final IDBTable PACKAGE_UNITS = INSTANCE.addTable("cdo_package_units"); //$NON-NLS-1$
+
+  public static final IDBField PACKAGE_UNITS_ID = //
+  PACKAGE_UNITS.addField("id", DBType.VARCHAR, 255); //$NON-NLS-1$
+
+  public static final IDBField PACKAGE_UNITS_ORIGINAL_TYPE = //
+  PACKAGE_UNITS.addField("original_type", DBType.INTEGER); //$NON-NLS-1$
+
+  public static final IDBField PACKAGE_UNITS_TIME_STAMP = //
+  PACKAGE_UNITS.addField("time_stamp", DBType.BIGINT); //$NON-NLS-1$
+
+  public static final IDBField PACKAGE_UNITS_PACKAGE_DATA = //
+  PACKAGE_UNITS.addField("package_data", DBType.BLOB); //$NON-NLS-1$
+
+  public static final IDBIndex INDEX_PACKAGE_UNITS_PK = //
+  PACKAGE_UNITS.addIndex(IDBIndex.Type.PRIMARY_KEY, PACKAGE_UNITS_ID);
+
+  /**
+   * DBTable cdo_packages
+   */
+  public static final IDBTable PACKAGE_INFOS = INSTANCE.addTable("cdo_package_infos"); //$NON-NLS-1$
+
+  public static final IDBField PACKAGE_INFOS_URI = //
+  PACKAGE_INFOS.addField("uri", DBType.VARCHAR, 255); //$NON-NLS-1$
+
+  public static final IDBField PACKAGE_INFOS_PARENT = //
+  PACKAGE_INFOS.addField("parent", DBType.VARCHAR, 255); //$NON-NLS-1$
+
+  public static final IDBField PACKAGE_INFOS_UNIT = //
+  PACKAGE_INFOS.addField("unit", DBType.VARCHAR, 255); //$NON-NLS-1$
+
+  public static final IDBIndex INDEX_PACKAGE_INFOS_PK = //
+  PACKAGE_INFOS.addIndex(IDBIndex.Type.PRIMARY_KEY, PACKAGE_INFOS_URI);
+
+  public static final IDBIndex INDEX_PACKAGE_INFOS_PARENT = //
+  PACKAGE_INFOS.addIndex(IDBIndex.Type.NON_UNIQUE, PACKAGE_INFOS_PARENT);
+
+  public static final IDBIndex INDEX_PACKAGE_INFOS_UNIT = //
+  PACKAGE_INFOS.addIndex(IDBIndex.Type.NON_UNIQUE, PACKAGE_INFOS_UNIT);
+
+  /**
+   * DBTable cdo_branches
+   */
+  public static final IDBTable BRANCHES = INSTANCE.addTable("cdo_branches"); //$NON-NLS-1$
+
+  public static final IDBField BRANCHES_ID = //
+  BRANCHES.addField("id", DBType.INTEGER); //$NON-NLS-1$
+
+  public static final IDBField BRANCHES_NAME = //
+  BRANCHES.addField("name", DBType.VARCHAR); //$NON-NLS-1$
+
+  public static final IDBField BRANCHES_BASE_BRANCH_ID = //
+  BRANCHES.addField("base_id", DBType.INTEGER); //$NON-NLS-1$
+
+  public static final IDBField BRANCHES_BASE_TIMESTAMP = //
+  BRANCHES.addField("base_time", DBType.BIGINT); //$NON-NLS-1$
+
+  public static final IDBIndex INDEX_BRANCHES_ID = //
+  BRANCHES.addIndex(IDBIndex.Type.PRIMARY_KEY, BRANCHES_ID);
+
+  public static final String SQL_CREATE_BRANCH = "INSERT INTO " + BRANCHES + " (" + BRANCHES_ID + ", " + BRANCHES_NAME //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+      + ", " + BRANCHES_BASE_BRANCH_ID + ", " + BRANCHES_BASE_TIMESTAMP + ") VALUES (?, ?, ?, ?)"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+
+  public static final String SQL_LOAD_BRANCH = "SELECT " + BRANCHES_NAME + ", " + BRANCHES_BASE_BRANCH_ID + ", " //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+      + BRANCHES_BASE_TIMESTAMP + " FROM " + BRANCHES + " WHERE " + BRANCHES_ID + "=?"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+
+  public static final String SQL_LOAD_SUB_BRANCHES = "SELECT " + BRANCHES_ID + ", " + BRANCHES_NAME + ", " //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+      + BRANCHES_BASE_TIMESTAMP + " FROM " + BRANCHES + " WHERE " + BRANCHES_BASE_BRANCH_ID + "=?"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+
+  public static final String SQL_LOAD_BRANCHES = "SELECT " + BRANCHES_ID + ", " + BRANCHES_NAME + ", " + //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+      BRANCHES_BASE_BRANCH_ID + ", " + BRANCHES_BASE_TIMESTAMP //$NON-NLS-1$
+      + " FROM " + BRANCHES + " WHERE " + BRANCHES_ID + " BETWEEN ? AND ? ORDER BY " + BRANCHES_ID; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+
+  /**
+   * DBTable cdo_commit_infos
+   */
+  public static final IDBTable COMMIT_INFOS = INSTANCE.addTable("cdo_commit_infos"); //$NON-NLS-1$
+
+  public static final IDBField COMMIT_INFOS_TIMESTAMP = //
+  COMMIT_INFOS.addField("commit_time", DBType.BIGINT); //$NON-NLS-1$
+
+  public static final IDBField COMMIT_INFOS_PREVIOUS_TIMESTAMP = //
+  COMMIT_INFOS.addField("previous_time", DBType.BIGINT); //$NON-NLS-1$
+
+  public static final IDBField COMMIT_INFOS_BRANCH = //
+  COMMIT_INFOS.addField("branch_id", DBType.INTEGER); //$NON-NLS-1$
+
+  public static final IDBField COMMIT_INFOS_USER = //
+  COMMIT_INFOS.addField("user_id", DBType.VARCHAR); //$NON-NLS-1$
+
+  public static final IDBField COMMIT_INFOS_COMMENT = //
+  COMMIT_INFOS.addField("commit_comment", DBType.VARCHAR); //$NON-NLS-1$
+
+  public static final IDBIndex INDEX_COMMIT_INFOS_PK = //
+  COMMIT_INFOS.addIndex(IDBIndex.Type.PRIMARY_KEY, COMMIT_INFOS_TIMESTAMP);
+
+  public static final IDBIndex INDEX_COMMIT_INFOS_BRANCH = //
+  COMMIT_INFOS.addIndex(IDBIndex.Type.NON_UNIQUE, COMMIT_INFOS_BRANCH);
+
+  public static final IDBIndex INDEX_COMMIT_INFOS_USER = //
+  COMMIT_INFOS.addIndex(IDBIndex.Type.NON_UNIQUE, COMMIT_INFOS_USER);
+
+  public static final String SQL_CREATE_COMMIT_INFO = "INSERT INTO " + COMMIT_INFOS + "(" + COMMIT_INFOS_TIMESTAMP //$NON-NLS-1$ //$NON-NLS-2$
+      + ", " + COMMIT_INFOS_PREVIOUS_TIMESTAMP + ", " + COMMIT_INFOS_BRANCH + ", " + COMMIT_INFOS_USER + ", " + COMMIT_INFOS_COMMENT + ") " //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
+      + "VALUES (?, ?, ?, ?, ?)"; //$NON-NLS-1$
+
+  /**
+   * DBTable cdo_lobs
+   */
+  public static final IDBTable LOBS = INSTANCE.addTable("cdo_lobs"); //$NON-NLS-1$
+
+  public static final IDBField LOBS_ID = //
+  LOBS.addField("id", DBType.VARCHAR, 64); //$NON-NLS-1$
+
+  public static final IDBField LOBS_SIZE = //
+  LOBS.addField("size", DBType.BIGINT); //$NON-NLS-1$
+
+  public static final IDBField LOBS_BDATA = //
+  LOBS.addField("bdata", DBType.BLOB); //$NON-NLS-1$
+
+  public static final IDBField LOBS_CDATA = //
+  LOBS.addField("cdata", DBType.CLOB); //$NON-NLS-1$
+
+  public static final IDBIndex INDEX_LOBS_ID = //
+  LOBS.addIndex(IDBIndex.Type.PRIMARY_KEY, LOBS_ID);
+
+  public static final String SQL_QUERY_LOBS = "SELECT 1 FROM " + CDODBSchema.LOBS + " WHERE " + CDODBSchema.LOBS_ID + "=?"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+
+  public static final String SQL_HANDLE_LOBS = "SELECT " + CDODBSchema.LOBS_ID + ", " + CDODBSchema.LOBS_SIZE + ", " + CDODBSchema.LOBS_BDATA + ", " + CDODBSchema.LOBS_CDATA + " FROM " + CDODBSchema.LOBS; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$
+
+  public static final String SQL_LOAD_LOB = "SELECT " + CDODBSchema.LOBS_SIZE + ", " + CDODBSchema.LOBS_BDATA + ", " + CDODBSchema.LOBS_CDATA + " FROM " + CDODBSchema.LOBS + " WHERE " + CDODBSchema.LOBS_ID + "=?"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$
+
+  public static final String SQL_WRITE_BLOB = "INSERT INTO " + CDODBSchema.LOBS + "(" + CDODBSchema.LOBS_ID + ", " + CDODBSchema.LOBS_SIZE + ", " + CDODBSchema.LOBS_BDATA + ") VALUES(?, ?, ?)"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$
+
+  public static final String SQL_WRITE_CLOB = "INSERT INTO " + CDODBSchema.LOBS + "(" + CDODBSchema.LOBS_ID + ", " + CDODBSchema.LOBS_SIZE + ", " + CDODBSchema.LOBS_CDATA + ") VALUES(?, ?, ?)"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$
+
+  /**
+   * Name of object table
+   */
+  public static final String CDO_OBJECTS = "cdo_objects"; //$NON-NLS-1$
+
+  /**
+   * Field names of attribute tables
+   */
+  public static final String ATTRIBUTES_ID = "cdo_id"; //$NON-NLS-1$
+
+  public static final String ATTRIBUTES_BRANCH = "cdo_branch"; //$NON-NLS-1$
+
+  public static final String ATTRIBUTES_VERSION = "cdo_version"; //$NON-NLS-1$
+
+  public static final String ATTRIBUTES_CLASS = "cdo_class"; //$NON-NLS-1$
+
+  public static final String ATTRIBUTES_CREATED = "cdo_created"; //$NON-NLS-1$
+
+  public static final String ATTRIBUTES_REVISED = "cdo_revised"; //$NON-NLS-1$
+
+  public static final String ATTRIBUTES_RESOURCE = "cdo_resource"; //$NON-NLS-1$
+
+  public static final String ATTRIBUTES_CONTAINER = "cdo_container"; //$NON-NLS-1$
+
+  public static final String ATTRIBUTES_FEATURE = "cdo_feature"; //$NON-NLS-1$
+
+  /**
+   * Field names of list tables
+   */
+  public static final String LIST_FEATURE = "cdo_feature"; //$NON-NLS-1$
+
+  public static final String LIST_REVISION_ID = "cdo_source"; //$NON-NLS-1$
+
+  public static final String LIST_REVISION_VERSION = "cdo_version"; //$NON-NLS-1$
+
+  public static final String LIST_REVISION_VERSION_ADDED = "cdo_version_added"; //$NON-NLS-1$
+
+  public static final String LIST_REVISION_VERSION_REMOVED = "cdo_version_removed"; //$NON-NLS-1$
+
+  public static final String LIST_REVISION_BRANCH = "cdo_branch"; //$NON-NLS-1$
+
+  public static final String LIST_IDX = "cdo_idx"; //$NON-NLS-1$
+
+  public static final String LIST_VALUE = "cdo_value"; //$NON-NLS-1$
+
+  /**
+   * Field names of featuremap tables
+   */
+  public static final String FEATUREMAP_REVISION_ID = "cdo_id"; //$NON-NLS-1$
+
+  public static final String FEATUREMAP_VERSION = "cdo_version"; //$NON-NLS-1$
+
+  public static final String FEATUREMAP_VERSION_ADDED = "cdo_version_added"; //$NON-NLS-1$
+
+  public static final String FEATUREMAP_VERSION_REMOVED = "cdo_version_removed"; //$NON-NLS-1$
+
+  public static final String FEATUREMAP_BRANCH = "cdo_branch"; //$NON-NLS-1$
+
+  public static final String FEATUREMAP_IDX = "cdo_idx"; //$NON-NLS-1$
+
+  public static final String FEATUREMAP_TAG = "cdo_tag"; //$NON-NLS-1$
+
+  public static final String FEATUREMAP_VALUE = "cdo_value"; //$NON-NLS-1$
+
+  private CDODBSchema()
+  {
+    super("CDO"); //$NON-NLS-1$
+  }
+
+  static
+  {
+    INSTANCE.lock();
+  }
+}
diff --git a/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/DBAnnotation.java b/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/DBAnnotation.java
new file mode 100644
index 0000000..1481156
--- /dev/null
+++ b/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/DBAnnotation.java
@@ -0,0 +1,67 @@
+/**
+ * Copyright (c) 2004 - 2011 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:
+ *    Kai Schlamp - initial API and implementation
+ *    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;
+
+import org.eclipse.emf.ecore.EModelElement;
+import org.eclipse.emf.ecore.util.EcoreUtil;
+
+/**
+ * @author Kai Schlamp
+ */
+public enum DBAnnotation
+{
+  TABLE_MAPPING("tableMapping"), //
+  TABLE_NAME("tableName"), //
+  COLUMN_NAME("columnName"), //
+  COLUMN_TYPE("columnType"), //
+  COLUMN_LENGTH("columnLength"), //
+  TYPE_MAPPING("typeMapping");
+
+  public final static String SOURCE_URI = "http://www.eclipse.org/CDO/DBStore";
+
+  public final static String TABLE_MAPPING_NONE = "NONE";
+
+  private String keyword;
+
+  private DBAnnotation(String keyword)
+  {
+    this.keyword = keyword;
+  }
+
+  public String getKeyword()
+  {
+    return keyword == null ? super.toString() : keyword;
+  }
+
+  /**
+   * @return A non-empty string or <code>null</code>.
+   */
+  public String getValue(EModelElement element)
+  {
+    String value = EcoreUtil.getAnnotation(element, SOURCE_URI, keyword);
+    if (value != null && value.length() == 0)
+    {
+      return null;
+    }
+
+    return value;
+  }
+
+  @Override
+  public String toString()
+  {
+    return getKeyword();
+  }
+}
diff --git a/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/DBBrowserPage.java b/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/DBBrowserPage.java
new file mode 100644
index 0000000..c81aafe
--- /dev/null
+++ b/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/DBBrowserPage.java
@@ -0,0 +1,208 @@
+/**
+ * Copyright (c) 2004 - 2011 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;
+
+import org.eclipse.emf.cdo.server.CDOServerBrowser;
+import org.eclipse.emf.cdo.server.CDOServerBrowser.AbstractPage;
+import org.eclipse.emf.cdo.spi.server.InternalRepository;
+
+import org.eclipse.net4j.db.DBException;
+import org.eclipse.net4j.db.DBUtil;
+import org.eclipse.net4j.db.IDBConnectionProvider;
+import org.eclipse.net4j.util.factory.ProductCreationException;
+
+import java.io.PrintStream;
+import java.sql.Connection;
+import java.sql.ResultSet;
+import java.sql.ResultSetMetaData;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.List;
+
+/**
+ * @author Eike Stepper
+ * @since 4.0
+ */
+public class DBBrowserPage extends AbstractPage
+{
+  public DBBrowserPage()
+  {
+    super("tables", "Database Tables");
+  }
+
+  public boolean canDisplay(InternalRepository repository)
+  {
+    return repository.getStore() instanceof IDBConnectionProvider;
+  }
+
+  public void display(CDOServerBrowser browser, InternalRepository repository, PrintStream out)
+  {
+    IDBConnectionProvider connectionProvider = (IDBConnectionProvider)repository.getStore();
+    Connection connection = null;
+
+    try
+    {
+      connection = connectionProvider.getConnection();
+
+      out.print("<table border=\"0\">\r\n");
+      out.print("<tr>\r\n");
+
+      out.print("<td valign=\"top\">\r\n");
+      String table = showTables(browser, out, connection, repository.getName());
+      out.print("</td>\r\n");
+
+      if (table != null)
+      {
+        out.print("<td valign=\"top\">\r\n");
+        showTable(browser, out, connection, table);
+        out.print("</td>\r\n");
+      }
+
+      out.print("</tr>\r\n");
+      out.print("</table>\r\n");
+    }
+    catch (DBException ex)
+    {
+      ex.printStackTrace();
+    }
+    finally
+    {
+      DBUtil.close(connection);
+    }
+  }
+
+  /**
+   * @since 4.0
+   */
+  protected String showTables(CDOServerBrowser browser, PrintStream pout, Connection connection, String repo)
+  {
+    String table = browser.getParam("table");
+
+    List<String> allTableNames = DBUtil.getAllTableNames(connection, repo);
+    for (String tableName : allTableNames)
+    {
+      if (table == null)
+      {
+        table = tableName;
+      }
+
+      String label = browser.escape(tableName)/* .toLowerCase() */;
+      if (tableName.equals(table))
+      {
+        pout.print("<b>" + label + "</b><br>\r\n");
+      }
+      else
+      {
+        pout.print(browser.href(label, getName(), "table", tableName, "order", null, "direction", null) + "<br>\r\n");
+      }
+    }
+
+    return table;
+  }
+
+  /**
+   * @since 4.0
+   */
+  protected void showTable(CDOServerBrowser browser, PrintStream pout, Connection connection, String table)
+  {
+    try
+    {
+      String order = browser.getParam("order");
+      executeQuery(browser, pout, connection, "SELECT * FROM " + table
+          + (order == null ? "" : " ORDER BY " + order + " " + browser.getParam("direction")));
+    }
+    catch (Exception ex)
+    {
+      browser.removeParam("order");
+      browser.removeParam("direction");
+      executeQuery(browser, pout, connection, "SELECT * FROM " + table);
+    }
+  }
+
+  protected void executeQuery(CDOServerBrowser browser, PrintStream pout, Connection connection, String sql)
+  {
+    String order = browser.getParam("order");
+    String direction = browser.getParam("direction");
+    String highlight = browser.getParam("highlight");
+
+    Statement stmt = null;
+    ResultSet resultSet = null;
+
+    try
+    {
+      stmt = connection.createStatement();
+      resultSet = stmt.executeQuery(sql);
+
+      ResultSetMetaData metaData = resultSet.getMetaData();
+      int columns = metaData.getColumnCount();
+
+      pout.print("<table border=\"1\" cellpadding=\"2\">\r\n");
+      pout.print("<tr>\r\n");
+      pout.print("<td>&nbsp;</td>\r\n");
+      for (int i = 0; i < columns; i++)
+      {
+        String column = metaData.getColumnLabel(1 + i);
+        String type = metaData.getColumnTypeName(1 + i).toLowerCase();
+
+        String dir = column.equals(order) && "ASC".equals(direction) ? "DESC" : "ASC";
+        pout.print("<td align=\"center\"><b>" + browser.href(column, getName(), "order", column, "direction", dir));
+        pout.print("</b><br>" + type + "</td>\r\n");
+      }
+
+      pout.print("</tr>\r\n");
+
+      int row = 0;
+      while (resultSet.next())
+      {
+        ++row;
+        pout.print("<tr>\r\n");
+        pout.print("<td><b>" + row + "</b></td>\r\n");
+        for (int i = 0; i < columns; i++)
+        {
+          String value = resultSet.getString(1 + i);
+          String bgcolor = highlight != null && highlight.equals(value) ? " bgcolor=\"#fffca6\"" : "";
+          pout.print("<td" + bgcolor + ">" + browser.href(value, getName(), "highlight", value) + "</td>\r\n");
+        }
+
+        pout.print("</tr>\r\n");
+      }
+
+      pout.print("</table>\r\n");
+    }
+    catch (SQLException ex)
+    {
+      ex.printStackTrace();
+    }
+    finally
+    {
+      DBUtil.close(resultSet);
+      DBUtil.close(stmt);
+    }
+  }
+
+  /**
+   * @author Eike Stepper
+   */
+  public static class Factory extends org.eclipse.net4j.util.factory.Factory
+  {
+    public static final String TYPE = "default";
+
+    public Factory()
+    {
+      super(PRODUCT_GROUP, TYPE);
+    }
+
+    public DBBrowserPage create(String description) throws ProductCreationException
+    {
+      return new DBBrowserPage();
+    }
+  }
+}
diff --git a/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/DBRevisionHandler.java b/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/DBRevisionHandler.java
new file mode 100644
index 0000000..d47db43
--- /dev/null
+++ b/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/DBRevisionHandler.java
@@ -0,0 +1,40 @@
+/**
+ * Copyright (c) 2004 - 2011 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;
+
+import org.eclipse.emf.cdo.common.branch.CDOBranchVersion;
+import org.eclipse.emf.cdo.common.revision.CDORevision;
+import org.eclipse.emf.cdo.common.revision.CDORevisionHandler;
+import org.eclipse.emf.cdo.spi.common.revision.DetachedCDORevision;
+
+/**
+ * @author Eike Stepper
+ */
+public class DBRevisionHandler implements CDORevisionHandler
+{
+  private CDORevisionHandler delegate;
+
+  public DBRevisionHandler(CDORevisionHandler delegate)
+  {
+    this.delegate = delegate;
+  }
+
+  public boolean handleRevision(CDORevision revision)
+  {
+    if (revision.getVersion() < CDOBranchVersion.FIRST_VERSION - 1)
+    {
+      revision = new DetachedCDORevision(revision.getEClass(), revision.getID(), revision.getBranch(),
+          -revision.getVersion(), revision.getTimeStamp(), revision.getRevised());
+    }
+
+    return delegate.handleRevision(revision);
+  }
+}
diff --git a/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/DBStore.java b/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/DBStore.java
new file mode 100644
index 0000000..3917333
--- /dev/null
+++ b/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/DBStore.java
@@ -0,0 +1,727 @@
+/**
+ * Copyright (c) 2004 - 2011 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 259402
+ *    Stefan Winkler - Bug 271444: [DB] Multiple refactorings bug 271444
+ *    Stefan Winkler - Bug 249610: [DB] Support external references (Implementation)
+ *    Stefan Winkler - Bug 289056: [DB] Exception "ERROR: relation "cdo_external_refs" does not exist" while executing test-suite for PostgreSQL
+ */
+package org.eclipse.emf.cdo.server.internal.db;
+
+import org.eclipse.emf.cdo.common.CDOCommonRepository.IDGenerationLocation;
+import org.eclipse.emf.cdo.common.branch.CDOBranch;
+import org.eclipse.emf.cdo.common.branch.CDOBranchPoint;
+import org.eclipse.emf.cdo.common.id.CDOID;
+import org.eclipse.emf.cdo.common.revision.CDOAllRevisionsProvider;
+import org.eclipse.emf.cdo.common.revision.CDORevision;
+import org.eclipse.emf.cdo.common.revision.CDORevisionHandler;
+import org.eclipse.emf.cdo.server.ISession;
+import org.eclipse.emf.cdo.server.ITransaction;
+import org.eclipse.emf.cdo.server.IView;
+import org.eclipse.emf.cdo.server.StoreThreadLocal;
+import org.eclipse.emf.cdo.server.db.IDBStore;
+import org.eclipse.emf.cdo.server.db.IDBStoreAccessor;
+import org.eclipse.emf.cdo.server.db.IIDHandler;
+import org.eclipse.emf.cdo.server.db.IMetaDataManager;
+import org.eclipse.emf.cdo.server.db.mapping.IMappingStrategy;
+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.server.InternalRepository;
+import org.eclipse.emf.cdo.spi.server.LongIDStoreAccessor;
+import org.eclipse.emf.cdo.spi.server.Store;
+import org.eclipse.emf.cdo.spi.server.StoreAccessorPool;
+
+import org.eclipse.net4j.db.DBException;
+import org.eclipse.net4j.db.DBUtil;
+import org.eclipse.net4j.db.IDBAdapter;
+import org.eclipse.net4j.db.IDBConnectionProvider;
+import org.eclipse.net4j.db.ddl.IDBSchema;
+import org.eclipse.net4j.db.ddl.IDBTable;
+import org.eclipse.net4j.spi.db.DBSchema;
+import org.eclipse.net4j.util.ReflectUtil.ExcludeFromDump;
+import org.eclipse.net4j.util.lifecycle.LifecycleUtil;
+import org.eclipse.net4j.util.om.monitor.ProgressDistributor;
+
+import javax.sql.DataSource;
+
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.text.MessageFormat;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.Timer;
+
+/**
+ * @author Eike Stepper
+ */
+public class DBStore extends Store implements IDBStore, CDOAllRevisionsProvider
+{
+  public static final String TYPE = "db"; //$NON-NLS-1$
+
+  private static final String PROP_REPOSITORY_CREATED = "org.eclipse.emf.cdo.server.db.repositoryCreated"; //$NON-NLS-1$
+
+  private static final String PROP_REPOSITORY_STOPPED = "org.eclipse.emf.cdo.server.db.repositoryStopped"; //$NON-NLS-1$
+
+  private static final String PROP_NEXT_LOCAL_CDOID = "org.eclipse.emf.cdo.server.db.nextLocalCDOID"; //$NON-NLS-1$
+
+  private static final String PROP_LAST_CDOID = "org.eclipse.emf.cdo.server.db.lastCDOID"; //$NON-NLS-1$
+
+  private static final String PROP_LAST_BRANCHID = "org.eclipse.emf.cdo.server.db.lastBranchID"; //$NON-NLS-1$
+
+  private static final String PROP_LAST_LOCAL_BRANCHID = "org.eclipse.emf.cdo.server.db.lastLocalBranchID"; //$NON-NLS-1$
+
+  private static final String PROP_LAST_COMMITTIME = "org.eclipse.emf.cdo.server.db.lastCommitTime"; //$NON-NLS-1$
+
+  private static final String PROP_LAST_NONLOCAL_COMMITTIME = "org.eclipse.emf.cdo.server.db.lastNonLocalCommitTime"; //$NON-NLS-1$
+
+  private static final String PROP_GRACEFULLY_SHUT_DOWN = "org.eclipse.emf.cdo.server.db.gracefullyShutDown"; //$NON-NLS-1$
+
+  private long creationTime;
+
+  private boolean firstTime;
+
+  private Map<String, String> properties;
+
+  private IIDHandler idHandler;
+
+  private IMetaDataManager metaDataManager = new MetaDataManager(this);
+
+  private DurableLockingManager durableLockingManager = new DurableLockingManager(this);
+
+  private IMappingStrategy mappingStrategy;
+
+  private IDBSchema dbSchema;
+
+  private IDBAdapter dbAdapter;
+
+  private IDBConnectionProvider dbConnectionProvider;
+
+  @ExcludeFromDump
+  private transient ProgressDistributor accessorWriteDistributor = new ProgressDistributor.Geometric()
+  {
+    @Override
+    public String toString()
+    {
+      String result = "accessorWriteDistributor"; //$NON-NLS-1$
+      if (getRepository() != null)
+      {
+        result += ": " + getRepository().getName(); //$NON-NLS-1$
+      }
+
+      return result;
+    }
+  };
+
+  @ExcludeFromDump
+  private transient StoreAccessorPool readerPool = new StoreAccessorPool(this, null);
+
+  @ExcludeFromDump
+  private transient StoreAccessorPool writerPool = new StoreAccessorPool(this, null);
+
+  @ExcludeFromDump
+  private transient Timer connectionKeepAliveTimer;
+
+  public DBStore()
+  {
+    super(TYPE, null, set(ChangeFormat.REVISION, ChangeFormat.DELTA), //
+        set(RevisionTemporality.AUDITING, RevisionTemporality.NONE), //
+        set(RevisionParallelism.NONE, RevisionParallelism.BRANCHING));
+  }
+
+  public IMappingStrategy getMappingStrategy()
+  {
+    return mappingStrategy;
+  }
+
+  public void setMappingStrategy(IMappingStrategy mappingStrategy)
+  {
+    this.mappingStrategy = mappingStrategy;
+    mappingStrategy.setStore(this);
+  }
+
+  public IDBAdapter getDBAdapter()
+  {
+    return dbAdapter;
+  }
+
+  public void setDBAdapter(IDBAdapter dbAdapter)
+  {
+    this.dbAdapter = dbAdapter;
+  }
+
+  public void setProperties(Map<String, String> properties)
+  {
+    this.properties = properties;
+  }
+
+  public Map<String, String> getProperties()
+  {
+    return properties;
+  }
+
+  public IIDHandler getIDHandler()
+  {
+    return idHandler;
+  }
+
+  public Connection getConnection()
+  {
+    Connection connection = dbConnectionProvider.getConnection();
+    if (connection == null)
+    {
+      throw new DBException("No connection from connection provider: " + dbConnectionProvider); //$NON-NLS-1$
+    }
+
+    try
+    {
+      connection.setAutoCommit(false);
+    }
+    catch (SQLException ex)
+    {
+      throw new DBException(ex, "SET AUTO COMMIT = false");
+    }
+
+    return connection;
+  }
+
+  public void setDbConnectionProvider(IDBConnectionProvider dbConnectionProvider)
+  {
+    this.dbConnectionProvider = dbConnectionProvider;
+  }
+
+  public void setDataSource(DataSource dataSource)
+  {
+    dbConnectionProvider = DBUtil.createConnectionProvider(dataSource);
+  }
+
+  public IMetaDataManager getMetaDataManager()
+  {
+    return metaDataManager;
+  }
+
+  public DurableLockingManager getDurableLockingManager()
+  {
+    return durableLockingManager;
+  }
+
+  public Timer getConnectionKeepAliveTimer()
+  {
+    return connectionKeepAliveTimer;
+  }
+
+  @Override
+  public Set<ChangeFormat> getSupportedChangeFormats()
+  {
+    if (mappingStrategy.hasDeltaSupport())
+    {
+      return set(ChangeFormat.DELTA);
+    }
+
+    return set(ChangeFormat.REVISION);
+  }
+
+  public ProgressDistributor getAccessorWriteDistributor()
+  {
+    return accessorWriteDistributor;
+  }
+
+  public IDBSchema getDBSchema()
+  {
+    return dbSchema;
+  }
+
+  public Map<String, String> getPersistentProperties(Set<String> names)
+  {
+    Connection connection = null;
+    PreparedStatement selectStmt = null;
+    String sql = null;
+
+    try
+    {
+      connection = getConnection();
+      Map<String, String> result = new HashMap<String, String>();
+      boolean allProperties = names == null || names.isEmpty();
+      if (allProperties)
+      {
+        sql = CDODBSchema.SQL_SELECT_ALL_PROPERTIES;
+        selectStmt = connection.prepareStatement(sql);
+        ResultSet resultSet = null;
+
+        try
+        {
+          resultSet = selectStmt.executeQuery();
+          while (resultSet.next())
+          {
+            String key = resultSet.getString(1);
+            String value = resultSet.getString(2);
+            result.put(key, value);
+          }
+        }
+        finally
+        {
+          DBUtil.close(resultSet);
+        }
+      }
+      else
+      {
+        sql = CDODBSchema.SQL_SELECT_PROPERTIES;
+        selectStmt = connection.prepareStatement(sql);
+        for (String name : names)
+        {
+          selectStmt.setString(1, name);
+          ResultSet resultSet = null;
+
+          try
+          {
+            resultSet = selectStmt.executeQuery();
+            if (resultSet.next())
+            {
+              String value = resultSet.getString(1);
+              result.put(name, value);
+            }
+          }
+          finally
+          {
+            DBUtil.close(resultSet);
+          }
+        }
+      }
+
+      return result;
+    }
+    catch (SQLException ex)
+    {
+      throw new DBException(ex, sql);
+    }
+    finally
+    {
+      DBUtil.close(selectStmt);
+      DBUtil.close(connection);
+    }
+  }
+
+  public void setPersistentProperties(Map<String, String> properties)
+  {
+    Connection connection = null;
+    PreparedStatement deleteStmt = null;
+    PreparedStatement insertStmt = null;
+    String sql = null;
+
+    try
+    {
+      connection = getConnection();
+      deleteStmt = connection.prepareStatement(CDODBSchema.SQL_DELETE_PROPERTIES);
+      insertStmt = connection.prepareStatement(CDODBSchema.SQL_INSERT_PROPERTIES);
+
+      for (Entry<String, String> entry : properties.entrySet())
+      {
+        String name = entry.getKey();
+        String value = entry.getValue();
+
+        sql = CDODBSchema.SQL_DELETE_PROPERTIES;
+        deleteStmt.setString(1, name);
+        deleteStmt.executeUpdate();
+
+        sql = CDODBSchema.SQL_INSERT_PROPERTIES;
+        insertStmt.setString(1, name);
+        insertStmt.setString(2, value);
+        insertStmt.executeUpdate();
+      }
+
+      sql = null;
+      connection.commit();
+    }
+    catch (SQLException ex)
+    {
+      throw new DBException(ex, sql);
+    }
+    finally
+    {
+      DBUtil.close(insertStmt);
+      DBUtil.close(deleteStmt);
+      DBUtil.close(connection);
+    }
+  }
+
+  public void removePersistentProperties(Set<String> names)
+  {
+    Connection connection = null;
+    PreparedStatement deleteStmt = null;
+
+    try
+    {
+      connection = getConnection();
+      deleteStmt = connection.prepareStatement(CDODBSchema.SQL_DELETE_PROPERTIES);
+
+      for (String name : names)
+      {
+        deleteStmt.setString(1, name);
+        deleteStmt.executeUpdate();
+      }
+
+      connection.commit();
+    }
+    catch (SQLException ex)
+    {
+      throw new DBException(ex, CDODBSchema.SQL_DELETE_PROPERTIES);
+    }
+    finally
+    {
+      DBUtil.close(deleteStmt);
+      DBUtil.close(connection);
+    }
+  }
+
+  @Override
+  public DBStoreAccessor getReader(ISession session)
+  {
+    return (DBStoreAccessor)super.getReader(session);
+  }
+
+  @Override
+  public DBStoreAccessor getWriter(ITransaction transaction)
+  {
+    return (DBStoreAccessor)super.getWriter(transaction);
+  }
+
+  @Override
+  protected StoreAccessorPool getReaderPool(ISession session, boolean forReleasing)
+  {
+    return readerPool;
+  }
+
+  @Override
+  protected StoreAccessorPool getWriterPool(IView view, boolean forReleasing)
+  {
+    return writerPool;
+  }
+
+  @Override
+  protected DBStoreAccessor createReader(ISession session) throws DBException
+  {
+    return new DBStoreAccessor(this, session);
+  }
+
+  @Override
+  protected DBStoreAccessor createWriter(ITransaction transaction) throws DBException
+  {
+    return new DBStoreAccessor(this, transaction);
+  }
+
+  public Map<CDOBranch, List<CDORevision>> getAllRevisions()
+  {
+    final Map<CDOBranch, List<CDORevision>> result = new HashMap<CDOBranch, List<CDORevision>>();
+    IDBStoreAccessor accessor = getReader(null);
+    StoreThreadLocal.setAccessor(accessor);
+
+    try
+    {
+      accessor.handleRevisions(null, null, CDOBranchPoint.UNSPECIFIED_DATE, true,
+          new CDORevisionHandler.Filtered.Undetached(new CDORevisionHandler()
+          {
+            public boolean handleRevision(CDORevision revision)
+            {
+              CDOBranch branch = revision.getBranch();
+              List<CDORevision> list = result.get(branch);
+              if (list == null)
+              {
+                list = new ArrayList<CDORevision>();
+                result.put(branch, list);
+              }
+
+              list.add(revision);
+              return true;
+            }
+          }));
+    }
+    finally
+    {
+      StoreThreadLocal.release();
+    }
+
+    return result;
+  }
+
+  public CDOID createObjectID(String val)
+  {
+    return idHandler.createCDOID(val);
+  }
+
+  public boolean isLocal(CDOID id)
+  {
+    return idHandler.isLocalCDOID(id);
+  }
+
+  public CDOID getNextCDOID(LongIDStoreAccessor accessor, CDORevision revision)
+  {
+    return idHandler.getNextCDOID(revision);
+  }
+
+  public long getCreationTime()
+  {
+    return creationTime;
+  }
+
+  public void setCreationTime(long creationTime)
+  {
+    this.creationTime = creationTime;
+
+    Map<String, String> map = new HashMap<String, String>();
+    map.put(PROP_REPOSITORY_CREATED, Long.toString(creationTime));
+    setPersistentProperties(map);
+  }
+
+  public boolean isFirstStart()
+  {
+    return firstTime;
+  }
+
+  @Override
+  protected void doBeforeActivate() throws Exception
+  {
+    super.doBeforeActivate();
+    checkNull(mappingStrategy, Messages.getString("DBStore.2")); //$NON-NLS-1$
+    checkNull(dbAdapter, Messages.getString("DBStore.1")); //$NON-NLS-1$
+    checkNull(dbConnectionProvider, Messages.getString("DBStore.0")); //$NON-NLS-1$
+  }
+
+  @Override
+  protected void doActivate() throws Exception
+  {
+    super.doActivate();
+
+    if (getRepository().getIDGenerationLocation() == IDGenerationLocation.CLIENT)
+    {
+      idHandler = new UUIDHandler(this);
+    }
+    else
+    {
+      idHandler = new LongIDHandler(this);
+    }
+
+    setObjectIDTypes(idHandler.getObjectIDTypes());
+    connectionKeepAliveTimer = new Timer("Connection-Keep-Alive-" + this); //$NON-NLS-1$
+
+    Set<IDBTable> createdTables = null;
+    Connection connection = getConnection();
+
+    try
+    {
+      if (isDropAllDataOnActivate())
+      {
+        OM.LOG.info("Dropping all tables from repository " + getRepository().getName() + "...");
+        DBUtil.dropAllTables(connection, null);
+        connection.commit();
+      }
+
+      createdTables = CDODBSchema.INSTANCE.create(dbAdapter, connection);
+      connection.commit();
+    }
+    finally
+    {
+      DBUtil.close(connection);
+    }
+
+    dbSchema = createSchema();
+
+    LifecycleUtil.activate(idHandler);
+    LifecycleUtil.activate(metaDataManager);
+    LifecycleUtil.activate(durableLockingManager);
+    LifecycleUtil.activate(mappingStrategy);
+
+    setRevisionTemporality(mappingStrategy.hasAuditSupport() ? RevisionTemporality.AUDITING : RevisionTemporality.NONE);
+    setRevisionParallelism(mappingStrategy.hasBranchingSupport() ? RevisionParallelism.BRANCHING
+        : RevisionParallelism.NONE);
+
+    if (isFirstStart(createdTables))
+    {
+      firstStart();
+    }
+    else
+    {
+      reStart();
+    }
+  }
+
+  @Override
+  protected void doDeactivate() throws Exception
+  {
+    LifecycleUtil.deactivate(mappingStrategy);
+    LifecycleUtil.deactivate(durableLockingManager);
+    LifecycleUtil.deactivate(metaDataManager);
+    LifecycleUtil.deactivate(idHandler);
+
+    Map<String, String> map = new HashMap<String, String>();
+    map.put(PROP_GRACEFULLY_SHUT_DOWN, Boolean.TRUE.toString());
+    map.put(PROP_REPOSITORY_STOPPED, Long.toString(getRepository().getTimeStamp()));
+
+    if (getRepository().getIDGenerationLocation() == IDGenerationLocation.STORE)
+    {
+      map.put(PROP_NEXT_LOCAL_CDOID, Store.idToString(idHandler.getNextLocalObjectID()));
+      map.put(PROP_LAST_CDOID, Store.idToString(idHandler.getLastObjectID()));
+    }
+
+    map.put(PROP_LAST_BRANCHID, Integer.toString(getLastBranchID()));
+    map.put(PROP_LAST_LOCAL_BRANCHID, Integer.toString(getLastLocalBranchID()));
+    map.put(PROP_LAST_COMMITTIME, Long.toString(getLastCommitTime()));
+    map.put(PROP_LAST_NONLOCAL_COMMITTIME, Long.toString(getLastNonLocalCommitTime()));
+    setPersistentProperties(map);
+
+    if (readerPool != null)
+    {
+      readerPool.dispose();
+    }
+
+    if (writerPool != null)
+    {
+      writerPool.dispose();
+    }
+
+    connectionKeepAliveTimer.cancel();
+    connectionKeepAliveTimer = null;
+
+    super.doDeactivate();
+  }
+
+  protected boolean isFirstStart(Set<IDBTable> createdTables)
+  {
+    if (createdTables.contains(CDODBSchema.PROPERTIES))
+    {
+      return true;
+    }
+
+    Set<String> names = new HashSet<String>();
+    names.add(PROP_REPOSITORY_CREATED);
+
+    Map<String, String> map = getPersistentProperties(names);
+    return map.get(PROP_REPOSITORY_CREATED) == null;
+  }
+
+  protected void firstStart()
+  {
+    InternalRepository repository = getRepository();
+    setCreationTime(repository.getTimeStamp());
+    firstTime = true;
+  }
+
+  protected void reStart()
+  {
+    Set<String> names = new HashSet<String>();
+    names.add(PROP_REPOSITORY_CREATED);
+    names.add(PROP_GRACEFULLY_SHUT_DOWN);
+
+    Map<String, String> map = getPersistentProperties(names);
+    creationTime = Long.valueOf(map.get(PROP_REPOSITORY_CREATED));
+
+    if (map.containsKey(PROP_GRACEFULLY_SHUT_DOWN))
+    {
+      names.clear();
+
+      InternalRepository repository = getRepository();
+      boolean generatingIDs = repository.getIDGenerationLocation() == IDGenerationLocation.STORE;
+      if (generatingIDs)
+      {
+        names.add(PROP_NEXT_LOCAL_CDOID);
+        names.add(PROP_LAST_CDOID);
+      }
+
+      names.add(PROP_LAST_BRANCHID);
+      names.add(PROP_LAST_LOCAL_BRANCHID);
+      names.add(PROP_LAST_COMMITTIME);
+      names.add(PROP_LAST_NONLOCAL_COMMITTIME);
+      map = getPersistentProperties(names);
+
+      if (generatingIDs)
+      {
+        idHandler.setNextLocalObjectID(Store.stringToID(map.get(PROP_NEXT_LOCAL_CDOID)));
+        idHandler.setLastObjectID(Store.stringToID(map.get(PROP_LAST_CDOID)));
+      }
+
+      setLastBranchID(Integer.valueOf(map.get(PROP_LAST_BRANCHID)));
+      setLastLocalBranchID(Integer.valueOf(map.get(PROP_LAST_LOCAL_BRANCHID)));
+      setLastCommitTime(Long.valueOf(map.get(PROP_LAST_COMMITTIME)));
+      setLastNonLocalCommitTime(Long.valueOf(map.get(PROP_LAST_NONLOCAL_COMMITTIME)));
+    }
+    else
+    {
+      repairAfterCrash();
+    }
+
+    removePersistentProperties(Collections.singleton(PROP_GRACEFULLY_SHUT_DOWN));
+  }
+
+  protected void repairAfterCrash()
+  {
+    String name = getRepository().getName();
+    OM.LOG.warn(MessageFormat.format(Messages.getString("DBStore.9"), name)); //$NON-NLS-1$
+
+    Connection connection = getConnection();
+
+    try
+    {
+      connection.setAutoCommit(false);
+      connection.setReadOnly(true);
+
+      mappingStrategy.repairAfterCrash(dbAdapter, connection); // Must update the idHandler
+
+      boolean storeIDs = getRepository().getIDGenerationLocation() == IDGenerationLocation.STORE;
+      CDOID lastObjectID = storeIDs ? idHandler.getLastObjectID() : CDOID.NULL;
+      CDOID nextLocalObjectID = storeIDs ? idHandler.getNextLocalObjectID() : CDOID.NULL;
+
+      int branchID = DBUtil.selectMaximumInt(connection, CDODBSchema.BRANCHES_ID);
+      setLastBranchID(branchID > 0 ? branchID : 0);
+
+      int localBranchID = DBUtil.selectMinimumInt(connection, CDODBSchema.BRANCHES_ID);
+      setLastLocalBranchID(localBranchID < 0 ? localBranchID : 0);
+
+      long lastCommitTime = DBUtil.selectMaximumLong(connection, CDODBSchema.COMMIT_INFOS_TIMESTAMP);
+      setLastCommitTime(lastCommitTime);
+
+      long lastNonLocalCommitTime = DBUtil.selectMaximumLong(connection, CDODBSchema.COMMIT_INFOS_TIMESTAMP,
+          CDOBranch.MAIN_BRANCH_ID + "<=" + CDODBSchema.COMMIT_INFOS_BRANCH);
+      setLastNonLocalCommitTime(lastNonLocalCommitTime);
+
+      if (storeIDs)
+      {
+        OM.LOG
+            .info(MessageFormat.format(
+                Messages.getString("DBStore.10"), name, lastObjectID, nextLocalObjectID, getLastBranchID(), getLastCommitTime(), getLastNonLocalCommitTime())); //$NON-NLS-1$
+      }
+      else
+      {
+        OM.LOG
+            .info(MessageFormat.format(
+                Messages.getString("DBStore.10b"), name, getLastBranchID(), getLastCommitTime(), getLastNonLocalCommitTime())); //$NON-NLS-1$
+      }
+    }
+    catch (SQLException e)
+    {
+      OM.LOG.error(MessageFormat.format(Messages.getString("DBStore.11"), name), e); //$NON-NLS-1$
+      throw new DBException(e);
+    }
+    finally
+    {
+      DBUtil.close(connection);
+    }
+  }
+
+  protected IDBSchema createSchema()
+  {
+    String name = getRepository().getName();
+    return new DBSchema(name);
+  }
+}
diff --git a/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/DBStoreAccessor.java b/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/DBStoreAccessor.java
new file mode 100644
index 0000000..42aca92
--- /dev/null
+++ b/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/DBStoreAccessor.java
@@ -0,0 +1,1393 @@
+/**
+ * Copyright (c) 2004 - 2011 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 259402
+ *    Stefan Winkler - 271444: [DB] Multiple refactorings bug 271444
+ *    Andre Dietisheim - bug 256649
+ *    Caspar De Groot - maintenance
+ */
+package org.eclipse.emf.cdo.server.internal.db;
+
+import org.eclipse.emf.cdo.common.CDOCommonRepository.IDGenerationLocation;
+import org.eclipse.emf.cdo.common.branch.CDOBranch;
+import org.eclipse.emf.cdo.common.branch.CDOBranchHandler;
+import org.eclipse.emf.cdo.common.branch.CDOBranchPoint;
+import org.eclipse.emf.cdo.common.branch.CDOBranchVersion;
+import org.eclipse.emf.cdo.common.commit.CDOCommitInfo;
+import org.eclipse.emf.cdo.common.commit.CDOCommitInfoHandler;
+import org.eclipse.emf.cdo.common.id.CDOID;
+import org.eclipse.emf.cdo.common.lob.CDOLobHandler;
+import org.eclipse.emf.cdo.common.lock.IDurableLockingManager.LockArea.Handler;
+import org.eclipse.emf.cdo.common.model.CDOClassifierRef;
+import org.eclipse.emf.cdo.common.model.CDOPackageRegistry;
+import org.eclipse.emf.cdo.common.protocol.CDODataInput;
+import org.eclipse.emf.cdo.common.protocol.CDODataOutput;
+import org.eclipse.emf.cdo.common.revision.CDORevision;
+import org.eclipse.emf.cdo.common.revision.CDORevisionCacheAdder;
+import org.eclipse.emf.cdo.common.revision.CDORevisionHandler;
+import org.eclipse.emf.cdo.common.util.CDOQueryInfo;
+import org.eclipse.emf.cdo.eresource.EresourcePackage;
+import org.eclipse.emf.cdo.server.IQueryHandler;
+import org.eclipse.emf.cdo.server.IRepository;
+import org.eclipse.emf.cdo.server.ISession;
+import org.eclipse.emf.cdo.server.IStoreAccessor;
+import org.eclipse.emf.cdo.server.IStoreAccessor.DurableLocking2;
+import org.eclipse.emf.cdo.server.ITransaction;
+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.IIDHandler;
+import org.eclipse.emf.cdo.server.db.IMetaDataManager;
+import org.eclipse.emf.cdo.server.db.IPreparedStatementCache;
+import org.eclipse.emf.cdo.server.db.IPreparedStatementCache.ReuseProbability;
+import org.eclipse.emf.cdo.server.db.mapping.IClassMapping;
+import org.eclipse.emf.cdo.server.db.mapping.IClassMappingAuditSupport;
+import org.eclipse.emf.cdo.server.db.mapping.IClassMappingDeltaSupport;
+import org.eclipse.emf.cdo.server.db.mapping.IMappingStrategy;
+import org.eclipse.emf.cdo.server.internal.db.bundle.OM;
+import org.eclipse.emf.cdo.spi.common.branch.InternalCDOBranch;
+import org.eclipse.emf.cdo.spi.common.branch.InternalCDOBranchManager;
+import org.eclipse.emf.cdo.spi.common.commit.CDOChangeSetSegment;
+import org.eclipse.emf.cdo.spi.common.commit.InternalCDOCommitInfoManager;
+import org.eclipse.emf.cdo.spi.common.model.InternalCDOPackageRegistry;
+import org.eclipse.emf.cdo.spi.common.model.InternalCDOPackageUnit;
+import org.eclipse.emf.cdo.spi.common.revision.DetachedCDORevision;
+import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevision;
+import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevisionDelta;
+import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevisionManager;
+import org.eclipse.emf.cdo.spi.server.InternalCommitContext;
+import org.eclipse.emf.cdo.spi.server.InternalRepository;
+import org.eclipse.emf.cdo.spi.server.StoreAccessor;
+
+import org.eclipse.net4j.db.DBException;
+import org.eclipse.net4j.db.DBUtil;
+import org.eclipse.net4j.util.HexUtil;
+import org.eclipse.net4j.util.ObjectUtil;
+import org.eclipse.net4j.util.StringUtil;
+import org.eclipse.net4j.util.collection.CloseableIterator;
+import org.eclipse.net4j.util.collection.Pair;
+import org.eclipse.net4j.util.concurrent.IRWLockManager.LockType;
+import org.eclipse.net4j.util.io.IOUtil;
+import org.eclipse.net4j.util.lifecycle.LifecycleUtil;
+import org.eclipse.net4j.util.om.monitor.OMMonitor;
+import org.eclipse.net4j.util.om.monitor.OMMonitor.Async;
+import org.eclipse.net4j.util.om.trace.ContextTracer;
+
+import org.eclipse.emf.ecore.EClass;
+import org.eclipse.emf.ecore.EPackage;
+import org.eclipse.emf.ecore.EStructuralFeature;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.Reader;
+import java.io.Writer;
+import java.sql.Blob;
+import java.sql.Clob;
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.TimerTask;
+
+/**
+ * @author Eike Stepper
+ */
+public class DBStoreAccessor extends StoreAccessor implements IDBStoreAccessor, DurableLocking2
+{
+  private static final ContextTracer TRACER = new ContextTracer(OM.DEBUG, DBStoreAccessor.class);
+
+  private Connection connection;
+
+  private ConnectionKeepAliveTask connectionKeepAliveTask;
+
+  private IPreparedStatementCache statementCache;
+
+  private Set<CDOID> newObjects = new HashSet<CDOID>();
+
+  private CDOID maxID = CDOID.NULL;
+
+  public DBStoreAccessor(DBStore store, ISession session) throws DBException
+  {
+    super(store, session);
+  }
+
+  public DBStoreAccessor(DBStore store, ITransaction transaction) throws DBException
+  {
+    super(store, transaction);
+  }
+
+  @Override
+  public DBStore getStore()
+  {
+    return (DBStore)super.getStore();
+  }
+
+  public IPreparedStatementCache getStatementCache()
+  {
+    return statementCache;
+  }
+
+  public DBStoreChunkReader createChunkReader(InternalCDORevision revision, EStructuralFeature feature)
+  {
+    return new DBStoreChunkReader(this, revision, feature);
+  }
+
+  /**
+   * Returns an iterator that iterates over all objects in the store and makes their CDOIDs available for processing.
+   * This method is supposed to be called very infrequently, for example during the recovery from a crash.
+   * 
+   * @since 2.0
+   * @deprecated Not used by the framework anymore.
+   */
+  @Deprecated
+  public CloseableIterator<CDOID> readObjectIDs()
+  {
+    if (TRACER.isEnabled())
+    {
+      TRACER.trace("Selecting object IDs"); //$NON-NLS-1$
+    }
+
+    return getStore().getMappingStrategy().readObjectIDs(this);
+  }
+
+  public CDOClassifierRef readObjectType(CDOID id)
+  {
+    if (TRACER.isEnabled())
+    {
+      TRACER.format("Selecting object type: {0}", id); //$NON-NLS-1$
+    }
+
+    IMappingStrategy mappingStrategy = getStore().getMappingStrategy();
+    return mappingStrategy.readObjectType(this, id);
+  }
+
+  protected EClass getObjectType(CDOID id)
+  {
+    IRepository repository = getStore().getRepository();
+    if (repository.getRootResourceID().equals(id))
+    {
+      return EresourcePackage.Literals.CDO_RESOURCE;
+    }
+
+    EClass result = repository.getRevisionManager().getObjectType(id);
+    if (result != null)
+    {
+      return result;
+    }
+
+    CDOClassifierRef type = readObjectType(id);
+    if (type != null)
+    {
+      CDOPackageRegistry packageRegistry = repository.getPackageRegistry();
+      return (EClass)type.resolve(packageRegistry);
+    }
+
+    return null;
+  }
+
+  public InternalCDORevision readRevision(CDOID id, CDOBranchPoint branchPoint, int listChunk,
+      CDORevisionCacheAdder cache)
+  {
+    if (TRACER.isEnabled())
+    {
+      TRACER.format("Selecting revision {0} from {1}", id, branchPoint); //$NON-NLS-1$
+    }
+
+    IMappingStrategy mappingStrategy = getStore().getMappingStrategy();
+
+    EClass eClass = getObjectType(id);
+    if (eClass != null)
+    {
+      InternalCDORevision revision = getStore().createRevision(eClass, id);
+      revision.setBranchPoint(branchPoint);
+
+      IClassMapping mapping = mappingStrategy.getClassMapping(eClass);
+      if (mapping.readRevision(this, revision, listChunk))
+      {
+        int version = revision.getVersion();
+        if (version < CDOBranchVersion.FIRST_VERSION - 1)
+        {
+          return new DetachedCDORevision(eClass, id, revision.getBranch(), -version, revision.getTimeStamp(),
+              revision.getRevised());
+        }
+
+        return revision;
+      }
+    }
+
+    // Reading failed - revision does not exist.
+    return null;
+  }
+
+  public InternalCDORevision readRevisionByVersion(CDOID id, CDOBranchVersion branchVersion, int listChunk,
+      CDORevisionCacheAdder cache)
+  {
+    DBStore store = getStore();
+    EClass eClass = getObjectType(id);
+
+    IMappingStrategy mappingStrategy = store.getMappingStrategy();
+    IClassMapping mapping = mappingStrategy.getClassMapping(eClass);
+
+    InternalCDORevision revision = store.createRevision(eClass, id);
+    revision.setVersion(branchVersion.getVersion());
+    revision.setBranchPoint(branchVersion.getBranch().getHead());
+
+    boolean success = false;
+
+    if (mappingStrategy.hasAuditSupport())
+    {
+      if (TRACER.isEnabled())
+      {
+        TRACER.format("Selecting revision {0} from {1}", id, branchVersion); //$NON-NLS-1$
+      }
+
+      // if audit support is present, just use the audit method
+      success = ((IClassMappingAuditSupport)mapping).readRevisionByVersion(this, revision, listChunk);
+      if (success && revision.getVersion() < CDOBranchVersion.FIRST_VERSION - 1)
+      {
+        // it is detached revision
+        revision = new DetachedCDORevision(eClass, id, revision.getBranch(), -revision.getVersion(),
+            revision.getTimeStamp(), revision.getRevised());
+
+      }
+    }
+    else
+    {
+      // if audit support is not present, we still have to provide a method
+      // to readRevisionByVersion because TransactionCommitContext.computeDirtyObject
+      // needs to lookup the base revision for a change. Hence we emulate this
+      // behavior by getting the current revision and asserting that the version
+      // has not changed. This is valid because if the version has changed,
+      // we are in trouble because of a conflict anyways.
+      if (TRACER.isEnabled())
+      {
+        TRACER.format("Selecting current base revision: {0}", id); //$NON-NLS-1$
+      }
+
+      success = mapping.readRevision(this, revision, listChunk);
+
+      if (success && revision.getVersion() != branchVersion.getVersion())
+      {
+        throw new IllegalStateException("Can only retrieve current version " + revision.getVersion() + " for " + id //$NON-NLS-1$ //$NON-NLS-2$
+            + " - version requested was " + branchVersion); //$NON-NLS-1$
+      }
+    }
+
+    return success ? revision : null;
+  }
+
+  /**
+   * @since 2.0
+   */
+  public void queryResources(QueryResourcesContext context)
+  {
+    IMappingStrategy mappingStrategy = getStore().getMappingStrategy();
+    mappingStrategy.queryResources(this, context);
+  }
+
+  public void queryXRefs(QueryXRefsContext context)
+  {
+    IMappingStrategy mappingStrategy = getStore().getMappingStrategy();
+    mappingStrategy.queryXRefs(this, context);
+  }
+
+  public IQueryHandler getQueryHandler(CDOQueryInfo info)
+  {
+    String queryLanguage = info.getQueryLanguage();
+    if (StringUtil.equalsUpperOrLowerCase(queryLanguage, SQLQueryHandler.QUERY_LANGUAGE))
+    {
+      return new SQLQueryHandler(this);
+    }
+
+    return null;
+  }
+
+  public void queryLobs(List<byte[]> ids)
+  {
+    PreparedStatement stmt = null;
+    ResultSet resultSet = null;
+
+    try
+    {
+      stmt = statementCache.getPreparedStatement(CDODBSchema.SQL_QUERY_LOBS, ReuseProbability.MEDIUM);
+
+      for (Iterator<byte[]> it = ids.iterator(); it.hasNext();)
+      {
+        byte[] id = it.next();
+        stmt.setString(1, HexUtil.bytesToHex(id));
+
+        try
+        {
+          resultSet = stmt.executeQuery();
+          if (!resultSet.next())
+          {
+            it.remove();
+          }
+        }
+        finally
+        {
+          DBUtil.close(resultSet);
+        }
+      }
+    }
+    catch (SQLException ex)
+    {
+      throw new DBException(ex);
+    }
+    finally
+    {
+      statementCache.releasePreparedStatement(stmt);
+    }
+  }
+
+  public void loadLob(byte[] id, OutputStream out) throws IOException
+  {
+    PreparedStatement stmt = null;
+    ResultSet resultSet = null;
+
+    try
+    {
+      stmt = statementCache.getPreparedStatement(CDODBSchema.SQL_LOAD_LOB, ReuseProbability.MEDIUM);
+      stmt.setString(1, HexUtil.bytesToHex(id));
+
+      try
+      {
+        resultSet = stmt.executeQuery();
+        resultSet.next();
+
+        long size = resultSet.getLong(1);
+        Blob blob = resultSet.getBlob(2);
+        if (resultSet.wasNull())
+        {
+          Clob clob = resultSet.getClob(3);
+          Reader in = clob.getCharacterStream();
+          IOUtil.copyCharacter(in, new OutputStreamWriter(out), size);
+        }
+        else
+        {
+          InputStream in = blob.getBinaryStream();
+          IOUtil.copyBinary(in, out, size);
+        }
+      }
+      finally
+      {
+        DBUtil.close(resultSet);
+      }
+    }
+    catch (SQLException ex)
+    {
+      throw new DBException(ex);
+    }
+    finally
+    {
+      statementCache.releasePreparedStatement(stmt);
+    }
+  }
+
+  public void handleLobs(long fromTime, long toTime, CDOLobHandler handler) throws IOException
+  {
+    PreparedStatement stmt = null;
+    ResultSet resultSet = null;
+
+    try
+    {
+      stmt = statementCache.getPreparedStatement(CDODBSchema.SQL_HANDLE_LOBS, ReuseProbability.LOW);
+
+      try
+      {
+        resultSet = stmt.executeQuery();
+        while (resultSet.next())
+        {
+          byte[] id = HexUtil.hexToBytes(resultSet.getString(1));
+          long size = resultSet.getLong(2);
+          Blob blob = resultSet.getBlob(3);
+          if (resultSet.wasNull())
+          {
+            Clob clob = resultSet.getClob(4);
+            Reader in = clob.getCharacterStream();
+            Writer out = handler.handleClob(id, size);
+            if (out != null)
+            {
+              try
+              {
+                IOUtil.copyCharacter(in, out, size);
+              }
+              finally
+              {
+                IOUtil.close(out);
+              }
+            }
+          }
+          else
+          {
+            InputStream in = blob.getBinaryStream();
+            OutputStream out = handler.handleBlob(id, size);
+            if (out != null)
+            {
+              try
+              {
+                IOUtil.copyBinary(in, out, size);
+              }
+              finally
+              {
+                IOUtil.close(out);
+              }
+            }
+          }
+        }
+      }
+      finally
+      {
+        DBUtil.close(resultSet);
+      }
+    }
+    catch (SQLException ex)
+    {
+      throw new DBException(ex);
+    }
+    finally
+    {
+      statementCache.releasePreparedStatement(stmt);
+    }
+  }
+
+  @Override
+  protected void applyIDMappings(InternalCommitContext context, OMMonitor monitor)
+  {
+    super.applyIDMappings(context, monitor);
+
+    // Remember maxID because it may have to be adjusted if the repository is BACKUP or CLONE. See bug 325097.
+    boolean adjustMaxID = !context.getBranchPoint().getBranch().isLocal()
+        && getStore().getRepository().getIDGenerationLocation() == IDGenerationLocation.STORE;
+
+    IIDHandler idHandler = getStore().getIDHandler();
+
+    // Remember CDOIDs of new objects. They are cleared after writeRevisions()
+    for (InternalCDORevision revision : context.getNewObjects())
+    {
+      CDOID id = revision.getID();
+      newObjects.add(id);
+
+      if (adjustMaxID && idHandler.compare(id, maxID) > 0)
+      {
+        maxID = id;
+      }
+    }
+  }
+
+  @Override
+  protected void writeCommitInfo(CDOBranch branch, long timeStamp, long previousTimeStamp, String userID,
+      String comment, OMMonitor monitor)
+  {
+    PreparedStatement stmt = null;
+
+    try
+    {
+      stmt = statementCache.getPreparedStatement(CDODBSchema.SQL_CREATE_COMMIT_INFO, ReuseProbability.HIGH);
+      stmt.setLong(1, timeStamp);
+      stmt.setLong(2, previousTimeStamp);
+      stmt.setInt(3, branch.getID());
+      stmt.setString(4, userID);
+      stmt.setString(5, comment);
+
+      DBUtil.update(stmt, true);
+    }
+    catch (SQLException ex)
+    {
+      throw new DBException(ex);
+    }
+    finally
+    {
+      statementCache.releasePreparedStatement(stmt);
+    }
+  }
+
+  @Override
+  protected void writeRevisionDeltas(InternalCDORevisionDelta[] revisionDeltas, CDOBranch branch, long created,
+      OMMonitor monitor)
+  {
+    IMappingStrategy mappingStrategy = getStore().getMappingStrategy();
+
+    if (!mappingStrategy.hasDeltaSupport())
+    {
+      throw new UnsupportedOperationException("Mapping strategy does not support revision deltas"); //$NON-NLS-1$
+    }
+
+    monitor.begin(revisionDeltas.length);
+    try
+    {
+      for (InternalCDORevisionDelta delta : revisionDeltas)
+      {
+        writeRevisionDelta(delta, created, monitor.fork());
+      }
+    }
+    finally
+    {
+      monitor.done();
+    }
+  }
+
+  protected void writeRevisionDelta(InternalCDORevisionDelta delta, long created, OMMonitor monitor)
+  {
+    CDOID id = delta.getID();
+    EClass eClass = getObjectType(id);
+    IClassMappingDeltaSupport mapping = (IClassMappingDeltaSupport)getStore().getMappingStrategy().getClassMapping(
+        eClass);
+    mapping.writeRevisionDelta(this, delta, created, monitor);
+  }
+
+  @Override
+  protected void writeRevisions(InternalCDORevision[] revisions, CDOBranch branch, OMMonitor monitor)
+  {
+    try
+    {
+      monitor.begin(revisions.length);
+      for (InternalCDORevision revision : revisions)
+      {
+        writeRevision(revision, newObjects.contains(revision.getID()), true, monitor.fork());
+      }
+    }
+    finally
+    {
+      newObjects.clear();
+      monitor.done();
+    }
+  }
+
+  protected void writeRevision(InternalCDORevision revision, boolean mapType, boolean revise, OMMonitor monitor)
+  {
+    if (TRACER.isEnabled())
+    {
+      TRACER.format("Writing revision: {0}", revision); //$NON-NLS-1$
+    }
+
+    EClass eClass = revision.getEClass();
+
+    IClassMapping mapping = getStore().getMappingStrategy().getClassMapping(eClass);
+    mapping.writeRevision(this, revision, mapType, revise, monitor);
+  }
+
+  /*
+   * XXX Eike: change API from CDOID[] to CDOIDAndVersion[]
+   */
+  @Override
+  protected void detachObjects(CDOID[] detachedObjects, CDOBranch branch, long timeStamp, OMMonitor monitor)
+  {
+    IMappingStrategy mappingStrategy = getStore().getMappingStrategy();
+    monitor.begin(detachedObjects.length);
+
+    try
+    {
+      InternalCDORevisionManager revisionManager = getStore().getRepository().getRevisionManager();
+      for (CDOID id : detachedObjects)
+      {
+        // TODO when CDOIDAndVersion is available:
+        // CDOID id = idAndVersion.getID(); //
+        // int version = idAndVersion.getVersion(); //
+
+        // but for now:
+
+        InternalCDORevision revision = revisionManager.getRevision(id, branch.getHead(), CDORevision.UNCHUNKED,
+            CDORevision.DEPTH_NONE, true);
+        int version = ObjectUtil.equals(branch, revision.getBranch()) ? revision.getVersion()
+            : CDOBranchVersion.FIRST_VERSION;
+
+        if (TRACER.isEnabled())
+        {
+          TRACER.format("Detaching object: {0}", id); //$NON-NLS-1$
+        }
+
+        EClass eClass = getObjectType(id);
+        IClassMapping mapping = mappingStrategy.getClassMapping(eClass);
+        mapping.detachObject(this, id, version, branch, timeStamp, monitor.fork());
+      }
+    }
+    finally
+    {
+      monitor.done();
+    }
+  }
+
+  public Connection getConnection()
+  {
+    return connection;
+  }
+
+  @Override
+  protected CDOID getNextCDOID(CDORevision revision)
+  {
+    return getStore().getIDHandler().getNextCDOID(revision);
+  }
+
+  @Override
+  protected void writeBlob(byte[] id, long size, InputStream inputStream) throws IOException
+  {
+    PreparedStatement stmt = null;
+
+    try
+    {
+      stmt = statementCache.getPreparedStatement(CDODBSchema.SQL_WRITE_BLOB, ReuseProbability.MEDIUM);
+      stmt.setString(1, HexUtil.bytesToHex(id));
+      stmt.setLong(2, size);
+      stmt.setBinaryStream(3, inputStream, (int)size);
+
+      DBUtil.update(stmt, true);
+    }
+    catch (SQLException ex)
+    {
+      throw new DBException(ex);
+    }
+    finally
+    {
+      statementCache.releasePreparedStatement(stmt);
+    }
+  }
+
+  @Override
+  protected void writeClob(byte[] id, long size, Reader reader) throws IOException
+  {
+    PreparedStatement stmt = null;
+
+    try
+    {
+      stmt = statementCache.getPreparedStatement(CDODBSchema.SQL_WRITE_CLOB, ReuseProbability.MEDIUM);
+      stmt.setString(1, HexUtil.bytesToHex(id));
+      stmt.setLong(2, size);
+      stmt.setCharacterStream(3, reader, (int)size);
+
+      DBUtil.update(stmt, true);
+    }
+    catch (SQLException ex)
+    {
+      throw new DBException(ex);
+    }
+    finally
+    {
+      statementCache.releasePreparedStatement(stmt);
+    }
+  }
+
+  @Override
+  protected final void doCommit(OMMonitor monitor)
+  {
+    if (TRACER.isEnabled())
+    {
+      TRACER.format("--- DB COMMIT ---"); //$NON-NLS-1$
+    }
+
+    Async async = null;
+    monitor.begin();
+
+    try
+    {
+      try
+      {
+        async = monitor.forkAsync();
+        getConnection().commit();
+
+        if (maxID != CDOID.NULL)
+        {
+          // See bug 325097
+          getStore().getIDHandler().adjustLastObjectID(maxID);
+          maxID = CDOID.NULL;
+        }
+      }
+      finally
+      {
+        if (async != null)
+        {
+          async.stop();
+        }
+      }
+    }
+    catch (SQLException ex)
+    {
+      throw new DBException(ex);
+    }
+    finally
+    {
+      monitor.done();
+    }
+  }
+
+  @Override
+  protected final void doRollback(IStoreAccessor.CommitContext commitContext)
+  {
+    getStore().getMetaDataManager().clearMetaIDMappings();
+
+    if (TRACER.isEnabled())
+    {
+      TRACER.format("--- DB ROLLBACK ---"); //$NON-NLS-1$
+    }
+
+    try
+    {
+      getConnection().rollback();
+
+      // Bugzilla 298632: Must rollback DBSchema to its prior state and drop the tables
+      getStore().getMappingStrategy().removeMapping(getConnection(), commitContext.getNewPackageUnits());
+    }
+    catch (SQLException ex)
+    {
+      throw new DBException(ex);
+    }
+  }
+
+  @Override
+  protected void doActivate() throws Exception
+  {
+    DBStore store = getStore();
+    connection = store.getConnection();
+    connectionKeepAliveTask = new ConnectionKeepAliveTask();
+
+    long keepAlivePeriod = ConnectionKeepAliveTask.EXECUTION_PERIOD;
+    Map<String, String> storeProps = store.getProperties();
+    if (storeProps != null)
+    {
+      String value = storeProps.get(IDBStore.Props.CONNECTION_KEEPALIVE_PERIOD);
+      if (value != null)
+      {
+        keepAlivePeriod = Long.parseLong(value) * 60L * 1000L;
+      }
+    }
+
+    store.getConnectionKeepAliveTimer().schedule(connectionKeepAliveTask, keepAlivePeriod, keepAlivePeriod);
+
+    // TODO - make this configurable?
+    statementCache = CDODBUtil.createStatementCache();
+    statementCache.setConnection(connection);
+    LifecycleUtil.activate(statementCache);
+  }
+
+  @Override
+  protected void doDeactivate() throws Exception
+  {
+    LifecycleUtil.deactivate(statementCache);
+    connectionKeepAliveTask.cancel();
+    DBUtil.close(connection);
+    connection = null;
+  }
+
+  @Override
+  protected void doPassivate() throws Exception
+  {
+    // this is called when the accessor is put back into the pool
+    // we want to make sure that no DB lock is held (see Bug 276926)
+    connection.rollback();
+  }
+
+  @Override
+  protected void doUnpassivate() throws Exception
+  {
+    // do nothing
+  }
+
+  public EPackage[] loadPackageUnit(InternalCDOPackageUnit packageUnit)
+  {
+    return getStore().getMetaDataManager().loadPackageUnit(getConnection(), packageUnit);
+  }
+
+  public Collection<InternalCDOPackageUnit> readPackageUnits()
+  {
+    return getStore().getMetaDataManager().readPackageUnits(getConnection());
+  }
+
+  public void writePackageUnits(InternalCDOPackageUnit[] packageUnits, OMMonitor monitor)
+  {
+    monitor.begin(2);
+
+    try
+    {
+      DBStore store = getStore();
+      Connection connection = getConnection();
+
+      IMetaDataManager metaDataManager = store.getMetaDataManager();
+      metaDataManager.writePackageUnits(connection, packageUnits, monitor.fork());
+
+      IMappingStrategy mappingStrategy = store.getMappingStrategy();
+      mappingStrategy.createMapping(connection, packageUnits, monitor.fork());
+    }
+    finally
+    {
+      monitor.done();
+    }
+  }
+
+  public Pair<Integer, Long> createBranch(int branchID, BranchInfo branchInfo)
+  {
+    checkBranchingSupport();
+    if (branchID == NEW_BRANCH)
+    {
+      branchID = getStore().getNextBranchID();
+    }
+    else if (branchID == NEW_LOCAL_BRANCH)
+    {
+      branchID = getStore().getNextLocalBranchID();
+    }
+
+    PreparedStatement stmt = null;
+
+    try
+    {
+      stmt = statementCache.getPreparedStatement(CDODBSchema.SQL_CREATE_BRANCH, ReuseProbability.LOW);
+      stmt.setInt(1, branchID);
+      stmt.setString(2, branchInfo.getName());
+      stmt.setInt(3, branchInfo.getBaseBranchID());
+      stmt.setLong(4, branchInfo.getBaseTimeStamp());
+
+      DBUtil.update(stmt, true);
+      getConnection().commit();
+      return new Pair<Integer, Long>(branchID, branchInfo.getBaseTimeStamp());
+    }
+    catch (SQLException ex)
+    {
+      throw new DBException(ex);
+    }
+    finally
+    {
+      statementCache.releasePreparedStatement(stmt);
+    }
+  }
+
+  public BranchInfo loadBranch(int branchID)
+  {
+    checkBranchingSupport();
+    PreparedStatement stmt = null;
+    ResultSet resultSet = null;
+
+    try
+    {
+      stmt = statementCache.getPreparedStatement(CDODBSchema.SQL_LOAD_BRANCH, ReuseProbability.HIGH);
+      stmt.setInt(1, branchID);
+
+      resultSet = stmt.executeQuery();
+      if (!resultSet.next())
+      {
+        throw new DBException("Branch with ID " + branchID + " does not exist");
+      }
+
+      String name = resultSet.getString(1);
+      int baseBranchID = resultSet.getInt(2);
+      long baseTimeStamp = resultSet.getLong(3);
+      return new BranchInfo(name, baseBranchID, baseTimeStamp);
+    }
+    catch (SQLException ex)
+    {
+      throw new DBException(ex);
+    }
+    finally
+    {
+      DBUtil.close(resultSet);
+      statementCache.releasePreparedStatement(stmt);
+    }
+  }
+
+  public SubBranchInfo[] loadSubBranches(int baseID)
+  {
+    checkBranchingSupport();
+    PreparedStatement stmt = null;
+    ResultSet resultSet = null;
+
+    try
+    {
+      stmt = statementCache.getPreparedStatement(CDODBSchema.SQL_LOAD_SUB_BRANCHES, ReuseProbability.HIGH);
+      stmt.setInt(1, baseID);
+
+      resultSet = stmt.executeQuery();
+      List<SubBranchInfo> result = new ArrayList<SubBranchInfo>();
+      while (resultSet.next())
+      {
+        int id = resultSet.getInt(1);
+        String name = resultSet.getString(2);
+        long baseTimeStamp = resultSet.getLong(3);
+        result.add(new SubBranchInfo(id, name, baseTimeStamp));
+      }
+
+      return result.toArray(new SubBranchInfo[result.size()]);
+    }
+    catch (SQLException ex)
+    {
+      throw new DBException(ex);
+    }
+    finally
+    {
+      DBUtil.close(resultSet);
+      statementCache.releasePreparedStatement(stmt);
+    }
+  }
+
+  private void checkBranchingSupport()
+  {
+    if (!getStore().getMappingStrategy().hasBranchingSupport())
+    {
+      throw new UnsupportedOperationException("Mapping strategy does not support branching"); //$NON-NLS-1$
+    }
+  }
+
+  public int loadBranches(int startID, int endID, CDOBranchHandler handler)
+  {
+    int count = 0;
+    PreparedStatement stmt = null;
+    ResultSet resultSet = null;
+
+    InternalRepository repository = getSession().getManager().getRepository();
+    InternalCDOBranchManager branchManager = repository.getBranchManager();
+
+    try
+    {
+      stmt = statementCache.getPreparedStatement(CDODBSchema.SQL_LOAD_BRANCHES, ReuseProbability.HIGH);
+      stmt.setInt(1, startID);
+      stmt.setInt(2, endID > 0 ? endID : Integer.MAX_VALUE);
+
+      resultSet = stmt.executeQuery();
+      while (resultSet.next())
+      {
+        int branchID = resultSet.getInt(1);
+        String name = resultSet.getString(2);
+        int baseBranchID = resultSet.getInt(3);
+        long baseTimeStamp = resultSet.getLong(4);
+
+        InternalCDOBranch branch = branchManager.getBranch(branchID, new BranchInfo(name, baseBranchID, baseTimeStamp));
+        handler.handleBranch(branch);
+        ++count;
+      }
+
+      return count;
+    }
+    catch (SQLException ex)
+    {
+      throw new DBException(ex);
+    }
+    finally
+    {
+      DBUtil.close(resultSet);
+      statementCache.releasePreparedStatement(stmt);
+    }
+  }
+
+  public void loadCommitInfos(CDOBranch branch, long startTime, long endTime, CDOCommitInfoHandler handler)
+  {
+    StringBuilder builder = new StringBuilder();
+    builder.append("SELECT "); //$NON-NLS-1$
+    builder.append(CDODBSchema.COMMIT_INFOS_TIMESTAMP);
+    builder.append(", "); //$NON-NLS-1$
+    builder.append(CDODBSchema.COMMIT_INFOS_PREVIOUS_TIMESTAMP);
+    builder.append(", "); //$NON-NLS-1$
+    builder.append(CDODBSchema.COMMIT_INFOS_USER);
+    builder.append(", "); //$NON-NLS-1$
+    builder.append(CDODBSchema.COMMIT_INFOS_COMMENT);
+    if (branch == null)
+    {
+      builder.append(", "); //$NON-NLS-1$
+      builder.append(CDODBSchema.COMMIT_INFOS_BRANCH);
+    }
+
+    builder.append(" FROM "); //$NON-NLS-1$
+    builder.append(CDODBSchema.COMMIT_INFOS);
+    boolean where = false;
+
+    if (branch != null)
+    {
+      builder.append(where ? " AND " : " WHERE "); //$NON-NLS-1$ //$NON-NLS-2$
+      builder.append(CDODBSchema.COMMIT_INFOS_BRANCH);
+      builder.append("="); //$NON-NLS-1$
+      builder.append(branch.getID());
+      where = true;
+    }
+
+    if (startTime != CDOBranchPoint.UNSPECIFIED_DATE)
+    {
+      builder.append(where ? " AND " : " WHERE "); //$NON-NLS-1$ //$NON-NLS-2$
+      builder.append(CDODBSchema.COMMIT_INFOS_TIMESTAMP);
+      builder.append(">="); //$NON-NLS-1$
+      builder.append(startTime);
+      where = true;
+    }
+
+    if (endTime != CDOBranchPoint.UNSPECIFIED_DATE)
+    {
+      builder.append(where ? " AND " : " WHERE "); //$NON-NLS-1$ //$NON-NLS-2$
+      builder.append(CDODBSchema.COMMIT_INFOS_TIMESTAMP);
+      builder.append("<="); //$NON-NLS-1$
+      builder.append(endTime);
+      where = true;
+    }
+
+    builder.append(" ORDER BY "); //$NON-NLS-1$
+    builder.append(CDODBSchema.COMMIT_INFOS_TIMESTAMP);
+    String sql = builder.toString();
+
+    PreparedStatement stmt = null;
+    ResultSet resultSet = null;
+
+    InternalRepository repository = getStore().getRepository();
+    InternalCDOBranchManager branchManager = repository.getBranchManager();
+    InternalCDOCommitInfoManager commitInfoManager = repository.getCommitInfoManager();
+
+    try
+    {
+      stmt = statementCache.getPreparedStatement(sql, ReuseProbability.MEDIUM);
+
+      resultSet = stmt.executeQuery();
+      while (resultSet.next())
+      {
+        long timeStamp = resultSet.getLong(1);
+        long previousTimeStamp = resultSet.getLong(2);
+        String userID = resultSet.getString(3);
+        String comment = resultSet.getString(4);
+        CDOBranch infoBranch = branch;
+        if (infoBranch == null)
+        {
+          int id = resultSet.getInt(5);
+          infoBranch = branchManager.getBranch(id);
+        }
+
+        CDOCommitInfo commitInfo = commitInfoManager.createCommitInfo(infoBranch, timeStamp, previousTimeStamp, userID,
+            comment, null);
+        handler.handleCommitInfo(commitInfo);
+      }
+    }
+    catch (SQLException ex)
+    {
+      throw new DBException(ex);
+    }
+    finally
+    {
+      DBUtil.close(resultSet);
+      statementCache.releasePreparedStatement(stmt);
+    }
+  }
+
+  public Set<CDOID> readChangeSet(OMMonitor monitor, CDOChangeSetSegment... segments)
+  {
+    IMappingStrategy mappingStrategy = getStore().getMappingStrategy();
+    return mappingStrategy.readChangeSet(this, monitor, segments);
+  }
+
+  public void handleRevisions(EClass eClass, CDOBranch branch, long timeStamp, boolean exactTime,
+      CDORevisionHandler handler)
+  {
+    IMappingStrategy mappingStrategy = getStore().getMappingStrategy();
+    mappingStrategy.handleRevisions(this, eClass, branch, timeStamp, exactTime, new DBRevisionHandler(handler));
+  }
+
+  public void rawExport(CDODataOutput out, int fromBranchID, int toBranchID, long fromCommitTime, long toCommitTime)
+      throws IOException
+  {
+    DBStore store = getStore();
+    if (store.getRepository().getIDGenerationLocation() == IDGenerationLocation.STORE)
+    {
+      out.writeCDOID(store.getIDHandler().getLastObjectID()); // See bug 325097
+    }
+
+    String where = " WHERE " + CDODBSchema.BRANCHES_ID + " BETWEEN " + fromBranchID + " AND " + toBranchID;
+    DBUtil.serializeTable(out, connection, CDODBSchema.BRANCHES, null, where);
+
+    where = " WHERE " + CDODBSchema.COMMIT_INFOS_TIMESTAMP + " BETWEEN " + fromCommitTime + " AND " + toCommitTime;
+    DBUtil.serializeTable(out, connection, CDODBSchema.COMMIT_INFOS, null, where);
+
+    IIDHandler idHandler = store.getIDHandler();
+    idHandler.rawExport(connection, out, fromCommitTime, toCommitTime);
+
+    IMetaDataManager metaDataManager = store.getMetaDataManager();
+    metaDataManager.rawExport(connection, out, fromCommitTime, toCommitTime);
+
+    IMappingStrategy mappingStrategy = store.getMappingStrategy();
+    mappingStrategy.rawExport(this, out, fromBranchID, toBranchID, fromCommitTime, toCommitTime);
+  }
+
+  public void rawImport(CDODataInput in, int fromBranchID, int toBranchID, long fromCommitTime, long toCommitTime,
+      OMMonitor monitor) throws IOException
+  {
+    DBStore store = getStore();
+    if (store.getRepository().getIDGenerationLocation() == IDGenerationLocation.STORE)
+    {
+      store.getIDHandler().setLastObjectID(in.readCDOID()); // See bug 325097
+    }
+
+    IMappingStrategy mappingStrategy = store.getMappingStrategy();
+    int size = mappingStrategy.getClassMappings().size();
+    int commitWork = 4;
+    monitor.begin(commitWork + size + commitWork);
+
+    Collection<InternalCDOPackageUnit> packageUnits = new HashSet<InternalCDOPackageUnit>();
+
+    try
+    {
+      DBUtil.deserializeTable(in, connection, CDODBSchema.BRANCHES, monitor.fork());
+      DBUtil.deserializeTable(in, connection, CDODBSchema.COMMIT_INFOS, monitor.fork());
+      store.getIDHandler().rawImport(connection, in, fromCommitTime, toCommitTime, monitor.fork());
+      rawImportPackageUnits(in, fromCommitTime, toCommitTime, packageUnits, monitor.fork());
+      mappingStrategy.rawImport(this, in, fromCommitTime, toCommitTime, monitor.fork(size));
+      rawCommit(commitWork, monitor);
+    }
+    catch (RuntimeException ex)
+    {
+      rawRollback(packageUnits);
+      throw ex;
+    }
+    catch (IOException ex)
+    {
+      rawRollback(packageUnits);
+      throw ex;
+    }
+    finally
+    {
+      monitor.done();
+    }
+  }
+
+  private void rawRollback(Collection<InternalCDOPackageUnit> packageUnits)
+  {
+    try
+    {
+      connection.rollback();
+    }
+    catch (SQLException ex)
+    {
+      OM.LOG.error(ex);
+    }
+
+    getStore().getMappingStrategy().removeMapping(getConnection(),
+        packageUnits.toArray(new InternalCDOPackageUnit[packageUnits.size()]));
+  }
+
+  protected void rawImportPackageUnits(CDODataInput in, long fromCommitTime, long toCommitTime,
+      Collection<InternalCDOPackageUnit> packageUnits, OMMonitor monitor) throws IOException
+  {
+    monitor.begin(2);
+
+    try
+    {
+      DBStore store = getStore();
+      IMetaDataManager metaDataManager = store.getMetaDataManager();
+
+      packageUnits.addAll(metaDataManager.rawImport(connection, in, fromCommitTime, toCommitTime, monitor.fork()));
+
+      InternalRepository repository = store.getRepository();
+      InternalCDOPackageRegistry packageRegistry = repository.getPackageRegistry(false);
+
+      for (InternalCDOPackageUnit packageUnit : packageUnits)
+      {
+        packageRegistry.putPackageUnit(packageUnit);
+      }
+
+      IMappingStrategy mappingStrategy = store.getMappingStrategy();
+
+      // Using another connection because CREATE TABLE (which is called in createMapping) on H2 databases does a commit.
+      Connection connection2 = null;
+      try
+      {
+        connection2 = store.getConnection();
+
+        mappingStrategy.createMapping(connection2,
+            packageUnits.toArray(new InternalCDOPackageUnit[packageUnits.size()]), monitor.fork());
+      }
+      finally
+      {
+        DBUtil.close(connection2);
+      }
+    }
+    finally
+    {
+      monitor.done();
+    }
+  }
+
+  public void rawStore(InternalCDOPackageUnit[] packageUnits, OMMonitor monitor)
+  {
+    writePackageUnits(packageUnits, monitor);
+  }
+
+  public void rawStore(InternalCDORevision revision, OMMonitor monitor)
+  {
+    CDOID id = revision.getID();
+
+    CDOClassifierRef classifierRef = getStore().getMappingStrategy().readObjectType(this, id);
+    boolean isFirstRevision = classifierRef == null;
+
+    if (!isFirstRevision)
+    {
+      EClass eClass = revision.getEClass();
+      boolean namesMatch = classifierRef.getClassifierName().equals(eClass.getName());
+      boolean packagesMatch = classifierRef.getPackageURI().equals(eClass.getEPackage().getNsURI());
+      if (!namesMatch || !packagesMatch)
+      {
+        throw new IllegalStateException();
+      }
+    }
+
+    writeRevision(revision, isFirstRevision, false, monitor);
+    getStore().getIDHandler().adjustLastObjectID(id);
+  }
+
+  public void rawStore(byte[] id, long size, InputStream inputStream) throws IOException
+  {
+    writeBlob(id, size, inputStream);
+  }
+
+  public void rawStore(byte[] id, long size, Reader reader) throws IOException
+  {
+    writeClob(id, size, reader);
+  }
+
+  public void rawStore(CDOBranch branch, long timeStamp, long previousTimeStamp, String userID, String comment,
+      OMMonitor monitor)
+  {
+    writeCommitInfo(branch, timeStamp, previousTimeStamp, userID, comment, monitor);
+  }
+
+  @Deprecated
+  public void rawDelete(CDOID id, int version, CDOBranch branch, EClass eClass, OMMonitor monitor)
+  {
+    throw new UnsupportedOperationException();
+
+    // IMappingStrategy mappingStrategy = getStore().getMappingStrategy();
+    // if (eClass == null)
+    // {
+    // eClass = getObjectType(id);
+    // }
+    //
+    // IClassMapping mapping = mappingStrategy.getClassMapping(eClass);
+    // mapping.detachObject(this, id, version, branch, CDOBranchPoint.UNSPECIFIED_DATE, monitor);
+  }
+
+  public void rawCommit(double commitWork, OMMonitor monitor)
+  {
+    monitor.begin();
+    Async async = monitor.forkAsync();
+
+    try
+    {
+      connection.commit();
+    }
+    catch (SQLException ex)
+    {
+      throw new DBException(ex);
+    }
+    finally
+    {
+      async.stop();
+      monitor.done();
+    }
+  }
+
+  public LockArea createLockArea(String userID, CDOBranchPoint branchPoint, boolean readOnly,
+      Map<CDOID, LockGrade> locks)
+  {
+    return createLockArea(null, userID, branchPoint, readOnly, locks);
+  }
+
+  public LockArea createLockArea(String durableLockingID, String userID, CDOBranchPoint branchPoint, boolean readOnly,
+      Map<CDOID, LockGrade> locks)
+  {
+    DurableLockingManager manager = getStore().getDurableLockingManager();
+    return manager.createLockArea(this, durableLockingID, userID, branchPoint, readOnly, locks);
+  }
+
+  public void updateLockArea(LockArea area)
+  {
+    DurableLockingManager manager = getStore().getDurableLockingManager();
+    manager.updateLockArea(this, area);
+  }
+
+  public LockArea getLockArea(String durableLockingID) throws LockAreaNotFoundException
+  {
+    DurableLockingManager manager = getStore().getDurableLockingManager();
+    return manager.getLockArea(this, durableLockingID);
+  }
+
+  public void getLockAreas(String userIDPrefix, Handler handler)
+  {
+    DurableLockingManager manager = getStore().getDurableLockingManager();
+    manager.getLockAreas(this, userIDPrefix, handler);
+  }
+
+  public void deleteLockArea(String durableLockingID)
+  {
+    DurableLockingManager manager = getStore().getDurableLockingManager();
+    manager.deleteLockArea(this, durableLockingID);
+  }
+
+  public void lock(String durableLockingID, LockType type, Collection<? extends Object> objectsToLock)
+  {
+    DurableLockingManager manager = getStore().getDurableLockingManager();
+    manager.lock(this, durableLockingID, type, objectsToLock);
+  }
+
+  public void unlock(String durableLockingID, LockType type, Collection<? extends Object> objectsToUnlock)
+  {
+    DurableLockingManager manager = getStore().getDurableLockingManager();
+    manager.unlock(this, durableLockingID, type, objectsToUnlock);
+  }
+
+  public void unlock(String durableLockingID)
+  {
+    DurableLockingManager manager = getStore().getDurableLockingManager();
+    manager.unlock(this, durableLockingID);
+  }
+
+  /**
+   * @author Stefan Winkler
+   */
+  private class ConnectionKeepAliveTask extends TimerTask
+  {
+    public static final long EXECUTION_PERIOD = 1000 * 60 * 60 * 4; // 4 hours
+
+    @Override
+    public void run()
+    {
+      Statement stmt = null;
+
+      try
+      {
+        if (TRACER.isEnabled())
+        {
+          TRACER.trace("DB connection keep-alive task activated"); //$NON-NLS-1$
+        }
+
+        stmt = connection.createStatement();
+        stmt.executeQuery("SELECT 1 FROM " + CDODBSchema.PROPERTIES); //$NON-NLS-1$
+      }
+      catch (java.sql.SQLException ex)
+      {
+        OM.LOG.error("DB connection keep-alive failed", ex); //$NON-NLS-1$
+
+        // Assume the connection has failed.
+        try
+        {
+          LifecycleUtil.deactivate(DBStoreAccessor.this);
+          LifecycleUtil.activate(DBStoreAccessor.this);
+        }
+        catch (Exception ex2)
+        {
+          OM.LOG.error("DB connection reconnect failed", ex2); //$NON-NLS-1$
+        }
+      }
+      catch (Exception ex) // Important: Do not throw any unchecked exceptions to the TimerThread!!!
+      {
+        OM.LOG.error("DB connection keep-alive failed", ex); //$NON-NLS-1$
+      }
+      finally
+      {
+        DBUtil.close(stmt);
+      }
+    }
+  }
+}
diff --git a/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/DBStoreChunkReader.java b/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/DBStoreChunkReader.java
new file mode 100644
index 0000000..59287fa
--- /dev/null
+++ b/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/DBStoreChunkReader.java
@@ -0,0 +1,94 @@
+/**
+ * Copyright (c) 2004 - 2011 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 283998: [DB] Chunk reading for multiple chunks fails
+ *    Victor Roldan Betancort - Bug 283998: [DB] Chunk reading for multiple chunks fails
+ */
+package org.eclipse.emf.cdo.server.internal.db;
+
+import org.eclipse.emf.cdo.common.revision.CDORevision;
+import org.eclipse.emf.cdo.server.db.IDBStoreChunkReader;
+import org.eclipse.emf.cdo.server.db.mapping.IClassMapping;
+import org.eclipse.emf.cdo.server.db.mapping.IListMapping;
+import org.eclipse.emf.cdo.server.db.mapping.IMappingStrategy;
+import org.eclipse.emf.cdo.spi.server.StoreChunkReader;
+
+import org.eclipse.emf.ecore.EStructuralFeature;
+
+import java.util.List;
+
+/**
+ * @author Eike Stepper
+ */
+public class DBStoreChunkReader extends StoreChunkReader implements IDBStoreChunkReader
+{
+  private IListMapping referenceMapping;
+
+  private StringBuilder builder = new StringBuilder();
+
+  public DBStoreChunkReader(DBStoreAccessor accessor, CDORevision revision, EStructuralFeature feature)
+  {
+    super(accessor, revision, feature);
+    IMappingStrategy mappingStrategy = accessor.getStore().getMappingStrategy();
+    IClassMapping mapping = mappingStrategy.getClassMapping(revision.getEClass());
+    referenceMapping = mapping.getListMapping(feature);
+  }
+
+  @Override
+  public DBStoreAccessor getAccessor()
+  {
+    return (DBStoreAccessor)super.getAccessor();
+  }
+
+  @Override
+  public void addSimpleChunk(int index)
+  {
+    super.addSimpleChunk(index);
+    prepareAddition();
+
+    builder.append(CDODBSchema.LIST_IDX);
+    builder.append('=');
+    builder.append(index);
+  }
+
+  @Override
+  public void addRangedChunk(int fromIndex, int toIndex)
+  {
+    super.addRangedChunk(fromIndex, toIndex);
+    prepareAddition();
+
+    builder.append(CDODBSchema.LIST_IDX);
+    builder.append(" BETWEEN "); //$NON-NLS-1$
+    builder.append(fromIndex);
+    builder.append(" AND "); //$NON-NLS-1$
+    builder.append(toIndex - 1);
+  }
+
+  public List<Chunk> executeRead()
+  {
+    List<Chunk> chunks = getChunks();
+    if (chunks.size() > 1)
+    {
+      builder.insert(0, '(');
+      builder.append(')');
+    }
+
+    referenceMapping.readChunks(this, chunks, builder.toString());
+    return chunks;
+  }
+
+  private void prepareAddition()
+  {
+    // If not empty, a chunk has been already added, and the next condition needs to be OR-ed
+    if (builder.length() > 0)
+    {
+      builder.append(" OR "); //$NON-NLS-1$
+    }
+  }
+}
diff --git a/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/DBStoreFactory.java b/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/DBStoreFactory.java
new file mode 100644
index 0000000..2290289
--- /dev/null
+++ b/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/DBStoreFactory.java
@@ -0,0 +1,130 @@
+/**
+ * Copyright (c) 2004 - 2011 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 - 271444: [DB] Multiple refactorings bug 271444
+ *    Caspar De Groot - maintenance  
+ */
+package org.eclipse.emf.cdo.server.internal.db;
+
+import org.eclipse.emf.cdo.server.IStore;
+import org.eclipse.emf.cdo.server.IStoreFactory;
+import org.eclipse.emf.cdo.server.db.CDODBUtil;
+import org.eclipse.emf.cdo.server.db.mapping.IMappingStrategy;
+import org.eclipse.emf.cdo.spi.server.RepositoryConfigurator;
+
+import org.eclipse.net4j.db.DBUtil;
+import org.eclipse.net4j.db.IDBAdapter;
+import org.eclipse.net4j.db.IDBConnectionProvider;
+
+import org.w3c.dom.Attr;
+import org.w3c.dom.Element;
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.NodeList;
+
+import javax.sql.DataSource;
+
+import java.util.Map;
+import java.util.Properties;
+
+/**
+ * @author Eike Stepper
+ */
+public class DBStoreFactory implements IStoreFactory
+{
+  public DBStoreFactory()
+  {
+  }
+
+  public String getStoreType()
+  {
+    return DBStore.TYPE;
+  }
+
+  public IStore createStore(String repositoryName, Map<String, String> repositoryProperties, Element storeConfig)
+  {
+    IMappingStrategy mappingStrategy = getMappingStrategy(repositoryName, repositoryProperties, storeConfig);
+    IDBAdapter dbAdapter = getDBAdapter(storeConfig);
+    DataSource dataSource = getDataSource(storeConfig);
+    IDBConnectionProvider connectionProvider = DBUtil.createConnectionProvider(dataSource);
+
+    DBStore store = new DBStore();
+    store.setMappingStrategy(mappingStrategy);
+    store.setDBAdapter(dbAdapter);
+    store.setDbConnectionProvider(connectionProvider);
+
+    Map<String, String> storeProperties = RepositoryConfigurator.getProperties(storeConfig, 1);
+    store.setProperties(storeProperties);
+
+    return store;
+  }
+
+  private IMappingStrategy getMappingStrategy(String repositoryName, Map<String, String> repositoryProperties,
+      Element storeConfig)
+  {
+    NodeList mappingStrategyConfigs = storeConfig.getElementsByTagName("mappingStrategy"); //$NON-NLS-1$
+    if (mappingStrategyConfigs.getLength() != 1)
+    {
+      throw new IllegalStateException("Exactly one mapping strategy must be configured for DB store"); //$NON-NLS-1$
+    }
+
+    Element mappingStrategyConfig = (Element)mappingStrategyConfigs.item(0);
+    String mappingStrategyType = mappingStrategyConfig.getAttribute("type"); //$NON-NLS-1$
+    IMappingStrategy mappingStrategy = CDODBUtil.createMappingStrategy(mappingStrategyType);
+    if (mappingStrategy == null)
+    {
+      throw new IllegalArgumentException("Unknown mapping strategy: " + mappingStrategyType); //$NON-NLS-1$
+    }
+
+    Map<String, String> properties = RepositoryConfigurator.getProperties(mappingStrategyConfig, 1);
+    properties.put("repositoryName", repositoryName);
+    properties.putAll(repositoryProperties);
+    mappingStrategy.setProperties(properties);
+
+    return mappingStrategy;
+  }
+
+  private IDBAdapter getDBAdapter(Element storeConfig)
+  {
+    NodeList dbAdapterConfigs = storeConfig.getElementsByTagName("dbAdapter"); //$NON-NLS-1$
+    if (dbAdapterConfigs.getLength() != 1)
+    {
+      throw new IllegalStateException("Exactly one dbAdapter must be configured for DB store"); //$NON-NLS-1$
+    }
+
+    Element dbAdapterConfig = (Element)dbAdapterConfigs.item(0);
+    String dbAdapterName = dbAdapterConfig.getAttribute("name"); //$NON-NLS-1$
+    IDBAdapter dbAdapter = DBUtil.getDBAdapter(dbAdapterName);
+    if (dbAdapter == null)
+    {
+      throw new IllegalArgumentException("Unknown DB adapter: " + dbAdapterName); //$NON-NLS-1$
+    }
+
+    return dbAdapter;
+  }
+
+  private DataSource getDataSource(Element storeConfig)
+  {
+    NodeList dataSourceConfigs = storeConfig.getElementsByTagName("dataSource"); //$NON-NLS-1$
+    if (dataSourceConfigs.getLength() != 1)
+    {
+      throw new IllegalStateException("Exactly one dataSource must be configured for DB store"); //$NON-NLS-1$
+    }
+
+    Properties properties = new Properties();
+    Element dataSourceConfig = (Element)dataSourceConfigs.item(0);
+    NamedNodeMap attributes = dataSourceConfig.getAttributes();
+    for (int i = 0; i < attributes.getLength(); i++)
+    {
+      Attr attribute = (Attr)attributes.item(i);
+      properties.put(attribute.getName(), attribute.getValue());
+    }
+
+    return DBUtil.createDataSource(properties);
+  }
+}
diff --git a/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/DurableLockingManager.java b/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/DurableLockingManager.java
new file mode 100644
index 0000000..7fbd726
--- /dev/null
+++ b/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/DurableLockingManager.java
@@ -0,0 +1,687 @@
+/**

+ * Copyright (c) 2004 - 2011 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;

+

+import org.eclipse.emf.cdo.common.branch.CDOBranchPoint;

+import org.eclipse.emf.cdo.common.id.CDOID;

+import org.eclipse.emf.cdo.common.lock.CDOLockUtil;

+import org.eclipse.emf.cdo.common.lock.IDurableLockingManager.LockArea;

+import org.eclipse.emf.cdo.common.lock.IDurableLockingManager.LockArea.Handler;

+import org.eclipse.emf.cdo.common.lock.IDurableLockingManager.LockAreaAlreadyExistsException;

+import org.eclipse.emf.cdo.common.lock.IDurableLockingManager.LockAreaNotFoundException;

+import org.eclipse.emf.cdo.common.lock.IDurableLockingManager.LockGrade;

+import org.eclipse.emf.cdo.server.db.IDBStoreAccessor;

+import org.eclipse.emf.cdo.server.db.IIDHandler;

+import org.eclipse.emf.cdo.server.db.IPreparedStatementCache;

+import org.eclipse.emf.cdo.server.db.IPreparedStatementCache.ReuseProbability;

+import org.eclipse.emf.cdo.spi.common.branch.InternalCDOBranchManager;

+import org.eclipse.emf.cdo.spi.server.InternalLockManager;

+

+import org.eclipse.net4j.db.DBException;

+import org.eclipse.net4j.db.DBType;

+import org.eclipse.net4j.db.DBUtil;

+import org.eclipse.net4j.db.ddl.IDBField;

+import org.eclipse.net4j.db.ddl.IDBIndex;

+import org.eclipse.net4j.db.ddl.IDBSchema;

+import org.eclipse.net4j.db.ddl.IDBTable;

+import org.eclipse.net4j.util.concurrent.IRWLockManager.LockType;

+import org.eclipse.net4j.util.lifecycle.Lifecycle;

+

+import java.sql.Connection;

+import java.sql.PreparedStatement;

+import java.sql.ResultSet;

+import java.sql.SQLException;

+import java.sql.Statement;

+import java.util.Collection;

+import java.util.HashMap;

+import java.util.Map;

+import java.util.Map.Entry;

+

+/**

+ * @author Eike Stepper

+ */

+public class DurableLockingManager extends Lifecycle

+{

+  private DBStore store;

+

+  private InternalCDOBranchManager branchManager;

+

+  private IIDHandler idHandler;

+

+  private IDBTable lockAreas;

+

+  private IDBField lockAreasID;

+

+  private IDBField lockAreasUser;

+

+  private IDBField lockAreasBranch;

+

+  private IDBField lockAreasTime;

+

+  private IDBField lockAreasReadOnly;

+

+  private IDBTable locks;

+

+  private IDBField locksArea;

+

+  private IDBField locksObject;

+

+  private IDBField locksGrade;

+

+  private String sqlInsertLockArea;

+

+  private String sqlSelectLockArea;

+

+  private String sqlSelectAllLockAreas;

+

+  private String sqlSelectLockAreas;

+

+  private String sqlDeleteLockArea;

+

+  private String sqlSelectLocks;

+

+  private String sqlSelectLock;

+

+  private String sqlInsertLock;

+

+  private String sqlUpdateLock;

+

+  private String sqlDeleteLock;

+

+  private String sqlDeleteLocks;

+

+  public DurableLockingManager(DBStore store)

+  {

+    this.store = store;

+  }

+

+  public synchronized LockArea createLockArea(DBStoreAccessor accessor, String durableLockingID, String userID,

+      CDOBranchPoint branchPoint, boolean readOnly, Map<CDOID, LockGrade> locks)

+  {

+    try

+    {

+      if (durableLockingID == null)

+      {

+        durableLockingID = getNextDurableLockingID(accessor);

+      }

+      else

+      {

+        // If the caller is specifying the ID, make sure there is no area with this ID yet

+        //

+        try

+        {

+          getLockArea(accessor, durableLockingID);

+          throw new LockAreaAlreadyExistsException(durableLockingID);

+        }

+        catch (LockAreaNotFoundException good)

+        {

+        }

+      }

+

+      IPreparedStatementCache statementCache = accessor.getStatementCache();

+      PreparedStatement stmt = null;

+

+      try

+      {

+        stmt = statementCache.getPreparedStatement(sqlInsertLockArea, ReuseProbability.LOW);

+        stmt.setString(1, durableLockingID);

+        stmt.setString(2, userID);

+        stmt.setInt(3, branchPoint.getBranch().getID());

+        stmt.setLong(4, branchPoint.getTimeStamp());

+        stmt.setBoolean(5, readOnly);

+

+        DBUtil.update(stmt, true);

+      }

+      catch (SQLException e)

+      {

+        throw new DBException(e);

+      }

+      finally

+      {

+        statementCache.releasePreparedStatement(stmt);

+      }

+

+      if (!locks.isEmpty())

+      {

+        insertLocks(accessor, durableLockingID, locks);

+      }

+

+      accessor.getConnection().commit();

+

+      return CDOLockUtil.createLockArea(durableLockingID, userID, branchPoint, readOnly, locks);

+    }

+    catch (SQLException ex)

+    {

+      throw new DBException(ex);

+    }

+  }

+

+  private void insertLocks(DBStoreAccessor accessor, String durableLockingID, Map<CDOID, LockGrade> locks)

+  {

+    IPreparedStatementCache statementCache = accessor.getStatementCache();

+    PreparedStatement stmt = null;

+

+    try

+    {

+      stmt = statementCache.getPreparedStatement(sqlInsertLock, ReuseProbability.MEDIUM);

+      stmt.setString(1, durableLockingID);

+

+      for (Entry<CDOID, LockGrade> entry : locks.entrySet())

+      {

+        CDOID id = entry.getKey();

+        int grade = entry.getValue().getValue();

+

+        idHandler.setCDOID(stmt, 2, id);

+        stmt.setInt(3, grade);

+

+        DBUtil.update(stmt, true);

+      }

+    }

+    catch (SQLException e)

+    {

+      throw new DBException(e);

+    }

+    finally

+    {

+      statementCache.releasePreparedStatement(stmt);

+    }

+  }

+

+  public LockArea getLockArea(DBStoreAccessor accessor, String durableLockingID) throws LockAreaNotFoundException

+  {

+    IPreparedStatementCache statementCache = accessor.getStatementCache();

+    PreparedStatement stmt = null;

+    ResultSet resultSet = null;

+

+    try

+    {

+      stmt = statementCache.getPreparedStatement(sqlSelectLockArea, ReuseProbability.MEDIUM);

+      stmt.setString(1, durableLockingID);

+      resultSet = stmt.executeQuery();

+

+      if (!resultSet.next())

+      {

+        throw new LockAreaNotFoundException(durableLockingID);

+      }

+

+      String userID = resultSet.getString(1);

+      int branchID = resultSet.getInt(2);

+      long timeStamp = resultSet.getLong(3);

+      boolean readOnly = resultSet.getBoolean(4);

+

+      return makeLockArea(accessor, durableLockingID, userID, branchID, timeStamp, readOnly);

+    }

+    catch (SQLException e)

+    {

+      throw new DBException(e);

+    }

+    finally

+    {

+      DBUtil.close(resultSet);

+      statementCache.releasePreparedStatement(stmt);

+    }

+  }

+

+  public void getLockAreas(DBStoreAccessor accessor, String userIDPrefix, Handler handler)

+  {

+    IPreparedStatementCache statementCache = accessor.getStatementCache();

+    PreparedStatement stmt = null;

+    ResultSet resultSet = null;

+

+    try

+    {

+      if (userIDPrefix.length() == 0)

+      {

+        stmt = statementCache.getPreparedStatement(sqlSelectAllLockAreas, ReuseProbability.MEDIUM);

+      }

+      else

+      {

+        stmt = statementCache.getPreparedStatement(sqlSelectLockAreas, ReuseProbability.MEDIUM);

+        stmt.setString(1, userIDPrefix + "%");

+      }

+

+      resultSet = stmt.executeQuery();

+      while (resultSet.next())

+      {

+        String durableLockingID = resultSet.getString(1);

+        String userID = resultSet.getString(2);

+        int branchID = resultSet.getInt(3);

+        long timeStamp = resultSet.getLong(4);

+        boolean readOnly = resultSet.getBoolean(5);

+

+        LockArea area = makeLockArea(accessor, durableLockingID, userID, branchID, timeStamp, readOnly);

+        if (!handler.handleLockArea(area))

+        {

+          break;

+        }

+      }

+    }

+    catch (SQLException e)

+    {

+      throw new DBException(e);

+    }

+    finally

+    {

+      DBUtil.close(resultSet);

+      statementCache.releasePreparedStatement(stmt);

+    }

+  }

+

+  public void deleteLockArea(DBStoreAccessor accessor, String durableLockingID)

+  {

+    try

+    {

+      unlockWithoutCommit(accessor, durableLockingID);

+

+      IPreparedStatementCache statementCache = accessor.getStatementCache();

+      PreparedStatement stmt = null;

+

+      try

+      {

+        stmt = statementCache.getPreparedStatement(sqlDeleteLockArea, ReuseProbability.LOW);

+        stmt.setString(1, durableLockingID);

+

+        DBUtil.update(stmt, true);

+      }

+      catch (SQLException e)

+      {

+        throw new DBException(e);

+      }

+      finally

+      {

+        statementCache.releasePreparedStatement(stmt);

+      }

+

+      accessor.getConnection().commit();

+    }

+    catch (SQLException e)

+    {

+      throw new DBException(e);

+    }

+  }

+

+  public void updateLockArea(DBStoreAccessor accessor, LockArea area)

+  {

+    try

+    {

+      String areaID = area.getDurableLockingID();

+      unlockWithoutCommit(accessor, areaID);

+      insertLocks(accessor, areaID, area.getLocks());

+

+      accessor.getConnection().commit();

+    }

+    catch (SQLException e)

+    {

+      throw new DBException(e);

+    }

+  }

+

+  public void lock(DBStoreAccessor accessor, String durableLockingID, LockType type,

+      Collection<? extends Object> objectsToLock)

+  {

+    changeLocks(accessor, durableLockingID, type, objectsToLock, true);

+  }

+

+  public void unlock(DBStoreAccessor accessor, String durableLockingID, LockType type,

+      Collection<? extends Object> objectsToUnlock)

+  {

+    changeLocks(accessor, durableLockingID, type, objectsToUnlock, false);

+  }

+

+  public void unlock(DBStoreAccessor accessor, String durableLockingID)

+  {

+    try

+    {

+      unlockWithoutCommit(accessor, durableLockingID);

+      accessor.getConnection().commit();

+    }

+    catch (SQLException e)

+    {

+      throw new DBException(e);

+    }

+  }

+

+  private void unlockWithoutCommit(DBStoreAccessor accessor, String durableLockingID)

+  {

+    IPreparedStatementCache statementCache = accessor.getStatementCache();

+    PreparedStatement stmt = null;

+

+    try

+    {

+      stmt = statementCache.getPreparedStatement(sqlDeleteLocks, ReuseProbability.MEDIUM);

+      stmt.setString(1, durableLockingID);

+

+      DBUtil.update(stmt, false);

+    }

+    catch (SQLException e)

+    {

+      throw new DBException(e);

+    }

+    finally

+    {

+      statementCache.releasePreparedStatement(stmt);

+    }

+  }

+

+  @Override

+  protected void doActivate() throws Exception

+  {

+    super.doActivate();

+

+    branchManager = store.getRepository().getBranchManager();

+    idHandler = store.getIDHandler();

+

+    IDBSchema schema = store.getDBSchema();

+

+    // Lock areas

+    lockAreas = schema.addTable("cdo_lock_areas");

+    lockAreasID = lockAreas.addField("id", DBType.VARCHAR);

+    lockAreasUser = lockAreas.addField("user_id", DBType.VARCHAR);

+    lockAreasBranch = lockAreas.addField("view_branch", DBType.INTEGER);

+    lockAreasTime = lockAreas.addField("view_time", DBType.BIGINT);

+    lockAreasReadOnly = lockAreas.addField("read_only", DBType.BOOLEAN);

+

+    lockAreas.addIndex(IDBIndex.Type.PRIMARY_KEY, lockAreasID);

+    lockAreas.addIndex(IDBIndex.Type.NON_UNIQUE, lockAreasUser);

+

+    // Locks

+    locks = schema.addTable("cdo_locks");

+    locksArea = locks.addField("area_id", DBType.VARCHAR);

+    locksObject = locks.addField("object_id", idHandler.getDBType());

+    locksGrade = locks.addField("lock_grade", DBType.INTEGER);

+

+    locks.addIndex(IDBIndex.Type.PRIMARY_KEY, locksArea, locksObject);

+    locks.addIndex(IDBIndex.Type.NON_UNIQUE, locksArea);

+

+    IDBStoreAccessor writer = store.getWriter(null);

+    Connection connection = writer.getConnection();

+    Statement statement = null;

+

+    try

+    {

+      statement = connection.createStatement();

+      store.getDBAdapter().createTable(lockAreas, statement);

+      store.getDBAdapter().createTable(locks, statement);

+      connection.commit();

+    }

+    catch (SQLException ex)

+    {

+      connection.rollback();

+      throw new DBException(ex);

+    }

+    finally

+    {

+      DBUtil.close(statement);

+      writer.release();

+    }

+

+    StringBuilder builder = new StringBuilder();

+    builder.append("INSERT INTO "); //$NON-NLS-1$

+    builder.append(lockAreas);

+    builder.append("("); //$NON-NLS-1$

+    builder.append(lockAreasID);

+    builder.append(","); //$NON-NLS-1$

+    builder.append(lockAreasUser);

+    builder.append(","); //$NON-NLS-1$

+    builder.append(lockAreasBranch);

+    builder.append(","); //$NON-NLS-1$

+    builder.append(lockAreasTime);

+    builder.append(","); //$NON-NLS-1$

+    builder.append(lockAreasReadOnly);

+    builder.append(") VALUES (?, ?, ?, ?, ?)"); //$NON-NLS-1$

+    sqlInsertLockArea = builder.toString();

+

+    builder = new StringBuilder();

+    builder.append("SELECT "); //$NON-NLS-1$

+    builder.append(lockAreasUser);

+    builder.append(","); //$NON-NLS-1$

+    builder.append(lockAreasBranch);

+    builder.append(","); //$NON-NLS-1$

+    builder.append(lockAreasTime);

+    builder.append(","); //$NON-NLS-1$

+    builder.append(lockAreasReadOnly);

+    builder.append(" FROM "); //$NON-NLS-1$

+    builder.append(lockAreas);

+    builder.append(" WHERE "); //$NON-NLS-1$

+    builder.append(lockAreasID);

+    builder.append("=?"); //$NON-NLS-1$

+    sqlSelectLockArea = builder.toString();

+

+    builder = new StringBuilder();

+    builder.append("SELECT "); //$NON-NLS-1$

+    builder.append(lockAreasID);

+    builder.append(","); //$NON-NLS-1$

+    builder.append(lockAreasUser);

+    builder.append(","); //$NON-NLS-1$

+    builder.append(lockAreasBranch);

+    builder.append(","); //$NON-NLS-1$

+    builder.append(lockAreasTime);

+    builder.append(","); //$NON-NLS-1$

+    builder.append(lockAreasReadOnly);

+    builder.append(" FROM "); //$NON-NLS-1$

+    builder.append(lockAreas);

+    sqlSelectAllLockAreas = builder.toString();

+

+    builder.append(" WHERE "); //$NON-NLS-1$

+    builder.append(lockAreasUser);

+    builder.append(" LIKE ?"); //$NON-NLS-1$

+    sqlSelectLockAreas = builder.toString();

+

+    builder = new StringBuilder();

+    builder.append("DELETE FROM "); //$NON-NLS-1$

+    builder.append(lockAreas);

+    builder.append(" WHERE "); //$NON-NLS-1$

+    builder.append(lockAreasID);

+    builder.append("=?"); //$NON-NLS-1$

+    sqlDeleteLockArea = builder.toString();

+

+    builder = new StringBuilder();

+    builder.append("SELECT "); //$NON-NLS-1$

+    builder.append(locksObject);

+    builder.append(","); //$NON-NLS-1$

+    builder.append(locksGrade);

+    builder.append(" FROM "); //$NON-NLS-1$

+    builder.append(locks);

+    builder.append(" WHERE "); //$NON-NLS-1$

+    builder.append(locksArea);

+    builder.append("=?"); //$NON-NLS-1$

+    sqlSelectLocks = builder.toString();

+

+    builder = new StringBuilder();

+    builder.append("SELECT "); //$NON-NLS-1$

+    builder.append(locksGrade);

+    builder.append(" FROM "); //$NON-NLS-1$

+    builder.append(locks);

+    builder.append(" WHERE "); //$NON-NLS-1$

+    builder.append(locksArea);

+    builder.append("=? AND "); //$NON-NLS-1$

+    builder.append(locksObject);

+    builder.append("=?"); //$NON-NLS-1$

+    sqlSelectLock = builder.toString();

+

+    builder = new StringBuilder();

+    builder.append("INSERT INTO "); //$NON-NLS-1$

+    builder.append(locks);

+    builder.append("("); //$NON-NLS-1$

+    builder.append(locksArea);

+    builder.append(","); //$NON-NLS-1$

+    builder.append(locksObject);

+    builder.append(","); //$NON-NLS-1$

+    builder.append(locksGrade);

+    builder.append(") VALUES (?, ?, ?)"); //$NON-NLS-1$

+    sqlInsertLock = builder.toString();

+

+    builder = new StringBuilder();

+    builder.append("UPDATE "); //$NON-NLS-1$

+    builder.append(locks);

+    builder.append(" SET "); //$NON-NLS-1$

+    builder.append(locksGrade);

+    builder.append("=? "); //$NON-NLS-1$

+    builder.append(" WHERE "); //$NON-NLS-1$

+    builder.append(locksArea);

+    builder.append("=? AND "); //$NON-NLS-1$

+    builder.append(locksObject);

+    builder.append("=?"); //$NON-NLS-1$

+    sqlUpdateLock = builder.toString();

+

+    builder = new StringBuilder();

+    builder.append("DELETE FROM "); //$NON-NLS-1$

+    builder.append(locks);

+    builder.append(" WHERE "); //$NON-NLS-1$

+    builder.append(locksArea);

+    builder.append("=? AND "); //$NON-NLS-1$

+    builder.append(locksObject);

+    builder.append("=?"); //$NON-NLS-1$

+    sqlDeleteLock = builder.toString();

+

+    builder = new StringBuilder();

+    builder.append("DELETE FROM "); //$NON-NLS-1$

+    builder.append(locks);

+    builder.append(" WHERE "); //$NON-NLS-1$

+    builder.append(locksArea);

+    builder.append("=?"); //$NON-NLS-1$

+    sqlDeleteLocks = builder.toString();

+  }

+

+  private String getNextDurableLockingID(DBStoreAccessor accessor)

+  {

+    for (;;)

+    {

+      String durableLockingID = CDOLockUtil.createDurableLockingID();

+

+      try

+      {

+        getLockArea(accessor, durableLockingID); // Check uniqueness

+        // Not unique; try once more...

+      }

+      catch (LockAreaNotFoundException ex)

+      {

+        return durableLockingID;

+      }

+    }

+  }

+

+  private LockArea makeLockArea(DBStoreAccessor accessor, String durableLockingID, String userID, int branchID,

+      long timeStamp, boolean readOnly)

+  {

+    CDOBranchPoint branchPoint = branchManager.getBranch(branchID).getPoint(timeStamp);

+    Map<CDOID, LockGrade> lockMap = getLockMap(accessor, durableLockingID);

+    return CDOLockUtil.createLockArea(durableLockingID, userID, branchPoint, readOnly, lockMap);

+  }

+

+  private Map<CDOID, LockGrade> getLockMap(DBStoreAccessor accessor, String durableLockingID)

+  {

+    IPreparedStatementCache statementCache = accessor.getStatementCache();

+    PreparedStatement stmt = null;

+    ResultSet resultSet = null;

+

+    try

+    {

+      stmt = statementCache.getPreparedStatement(sqlSelectLocks, ReuseProbability.MEDIUM);

+      stmt.setString(1, durableLockingID);

+      resultSet = stmt.executeQuery();

+

+      Map<CDOID, LockGrade> lockMap = new HashMap<CDOID, LockGrade>();

+      while (resultSet.next())

+      {

+        CDOID id = idHandler.getCDOID(resultSet, 1);

+        int grade = resultSet.getInt(2);

+

+        lockMap.put(id, LockGrade.get(grade));

+      }

+

+      return lockMap;

+    }

+    catch (SQLException e)

+    {

+      throw new DBException(e);

+    }

+    finally

+    {

+      DBUtil.close(resultSet);

+      statementCache.releasePreparedStatement(stmt);

+    }

+  }

+

+  private void changeLocks(DBStoreAccessor accessor, String durableLockingID, LockType type,

+      Collection<? extends Object> keys, boolean on)

+  {

+    if (keys.isEmpty())

+    {

+      return;

+    }

+

+    IPreparedStatementCache statementCache = accessor.getStatementCache();

+    PreparedStatement stmtSelect = null;

+    PreparedStatement stmtInsertOrDelete = null;

+    PreparedStatement stmtUpdate = null;

+    ResultSet resultSet = null;

+

+    try

+    {

+      stmtSelect = statementCache.getPreparedStatement(sqlSelectLock, ReuseProbability.MEDIUM);

+      stmtSelect.setString(1, durableLockingID);

+

+      String sql = on ? sqlInsertLock : sqlDeleteLock;

+      stmtInsertOrDelete = statementCache.getPreparedStatement(sql, ReuseProbability.MEDIUM);

+      stmtInsertOrDelete.setString(1, durableLockingID);

+

+      stmtUpdate = statementCache.getPreparedStatement(sqlUpdateLock, ReuseProbability.MEDIUM);

+      stmtUpdate.setString(2, durableLockingID);

+

+      InternalLockManager lockManager = accessor.getStore().getRepository().getLockManager();

+      for (Object key : keys)

+      {

+        CDOID id = lockManager.getLockKeyID(key);

+        idHandler.setCDOID(stmtSelect, 2, id);

+        resultSet = stmtSelect.executeQuery();

+

+        LockGrade oldGrade = LockGrade.NONE;

+        if (resultSet.next())

+        {

+          oldGrade = LockGrade.get(resultSet.getInt(1));

+        }

+

+        LockGrade newGrade = oldGrade.getUpdated(type, on);

+        if (on && oldGrade == LockGrade.NONE)

+        {

+          idHandler.setCDOID(stmtInsertOrDelete, 2, id);

+          stmtInsertOrDelete.setInt(3, newGrade.getValue());

+          DBUtil.update(stmtInsertOrDelete, true);

+        }

+        else if (!on && newGrade == LockGrade.NONE)

+        {

+          idHandler.setCDOID(stmtInsertOrDelete, 2, id);

+          DBUtil.update(stmtInsertOrDelete, true);

+        }

+        else

+        {

+          stmtUpdate.setInt(1, newGrade.getValue());

+          idHandler.setCDOID(stmtUpdate, 3, id);

+          DBUtil.update(stmtUpdate, true);

+        }

+      }

+

+      accessor.getConnection().commit();

+    }

+    catch (SQLException e)

+    {

+      throw new DBException(e);

+    }

+    finally

+    {

+      DBUtil.close(resultSet);

+      statementCache.releasePreparedStatement(stmtUpdate);

+      statementCache.releasePreparedStatement(stmtInsertOrDelete);

+      statementCache.releasePreparedStatement(stmtSelect);

+    }

+  }

+}

diff --git a/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/ExternalReferenceManager.java b/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/ExternalReferenceManager.java
new file mode 100644
index 0000000..34b5f89
--- /dev/null
+++ b/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/ExternalReferenceManager.java
@@ -0,0 +1,302 @@
+/**
+ * Copyright (c) 2004 - 2011 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 249610: [DB] Support external references (Implementation)
+ *    Eike Stepper - maintenance
+ */
+package org.eclipse.emf.cdo.server.internal.db;
+
+import org.eclipse.emf.cdo.common.id.CDOIDExternal;
+import org.eclipse.emf.cdo.common.id.CDOIDUtil;
+import org.eclipse.emf.cdo.common.protocol.CDODataInput;
+import org.eclipse.emf.cdo.common.protocol.CDODataOutput;
+import org.eclipse.emf.cdo.server.IStoreAccessor;
+import org.eclipse.emf.cdo.server.StoreThreadLocal;
+import org.eclipse.emf.cdo.server.db.IDBStore;
+import org.eclipse.emf.cdo.server.db.IDBStoreAccessor;
+import org.eclipse.emf.cdo.server.db.IIDHandler;
+import org.eclipse.emf.cdo.server.db.IPreparedStatementCache;
+import org.eclipse.emf.cdo.server.db.IPreparedStatementCache.ReuseProbability;
+import org.eclipse.emf.cdo.server.internal.db.bundle.OM;
+
+import org.eclipse.net4j.db.DBException;
+import org.eclipse.net4j.db.DBType;
+import org.eclipse.net4j.db.DBUtil;
+import org.eclipse.net4j.db.ddl.IDBField;
+import org.eclipse.net4j.db.ddl.IDBIndex;
+import org.eclipse.net4j.db.ddl.IDBTable;
+import org.eclipse.net4j.util.ReflectUtil.ExcludeFromDump;
+import org.eclipse.net4j.util.lifecycle.Lifecycle;
+import org.eclipse.net4j.util.om.monitor.OMMonitor;
+
+import java.io.IOException;
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.concurrent.atomic.AtomicLong;
+
+/**
+ * @author Stefan Winkler
+ */
+public class ExternalReferenceManager extends Lifecycle
+{
+  private static final int NULL = 0;
+
+  private IDBTable table;
+
+  private IDBField idField;
+
+  private IDBField uriField;
+
+  private IDBField timestampField;
+
+  private final IIDHandler idHandler;
+
+  private AtomicLong lastMappedID = new AtomicLong(NULL);
+
+  @ExcludeFromDump
+  private transient String sqlSelectByLongID;
+
+  @ExcludeFromDump
+  private transient String sqlSelectByURI;
+
+  @ExcludeFromDump
+  private transient String sqlInsert;
+
+  public ExternalReferenceManager(IIDHandler idHandler)
+  {
+    this.idHandler = idHandler;
+  }
+
+  public IIDHandler getIDHandler()
+  {
+    return idHandler;
+  }
+
+  public long mapExternalReference(CDOIDExternal id, long commitTime)
+  {
+    IDBStoreAccessor accessor = getAccessor();
+    return mapURI(accessor, id.getURI(), commitTime);
+  }
+
+  public CDOIDExternal unmapExternalReference(long mappedId)
+  {
+    IDBStoreAccessor accessor = getAccessor();
+    return CDOIDUtil.createExternal(unmapURI(accessor, mappedId));
+  }
+
+  public long mapURI(IDBStoreAccessor accessor, String uri, long commitTime)
+  {
+    long result = lookupByURI(accessor, uri);
+    if (result < NULL)
+    {
+      // mapping found
+      return result;
+    }
+
+    return insertNew(accessor, uri, commitTime);
+  }
+
+  public String unmapURI(IDBStoreAccessor accessor, long mappedId)
+  {
+    IPreparedStatementCache statementCache = accessor.getStatementCache();
+    PreparedStatement stmt = null;
+    ResultSet resultSet = null;
+
+    try
+    {
+      stmt = statementCache.getPreparedStatement(sqlSelectByLongID, ReuseProbability.HIGH);
+      stmt.setLong(1, mappedId);
+      resultSet = stmt.executeQuery();
+
+      if (!resultSet.next())
+      {
+        OM.LOG.error("External ID " + mappedId + " not found. Database inconsistent!");
+        throw new IllegalStateException("External ID " + mappedId + " not found. Database inconsistent!");
+      }
+
+      return resultSet.getString(1);
+    }
+    catch (SQLException e)
+    {
+      throw new DBException(e);
+    }
+    finally
+    {
+      DBUtil.close(resultSet);
+      statementCache.releasePreparedStatement(stmt);
+    }
+  }
+
+  public void rawExport(Connection connection, CDODataOutput out, long fromCommitTime, long toCommitTime)
+      throws IOException
+  {
+    String where = " WHERE " + timestampField + " BETWEEN " + fromCommitTime + " AND " + toCommitTime;
+    DBUtil.serializeTable(out, connection, table, null, where);
+  }
+
+  public void rawImport(Connection connection, CDODataInput in, long fromCommitTime, long toCommitTime,
+      OMMonitor monitor) throws IOException
+  {
+    DBUtil.deserializeTable(in, connection, table, monitor);
+  }
+
+  @Override
+  protected void doActivate() throws Exception
+  {
+    super.doActivate();
+
+    IDBStore store = idHandler.getStore();
+    table = store.getDBSchema().addTable("cdo_external_refs"); //$NON-NLS-1$
+    idField = table.addField("id", idHandler.getDBType()); //$NON-NLS-1$
+    uriField = table.addField("uri", DBType.VARCHAR, 1024); //$NON-NLS-1$
+    timestampField = table.addField("committime", DBType.BIGINT); //$NON-NLS-1$
+
+    table.addIndex(IDBIndex.Type.PRIMARY_KEY, idField);
+    table.addIndex(IDBIndex.Type.NON_UNIQUE, uriField);
+
+    IDBStoreAccessor writer = store.getWriter(null);
+    Connection connection = writer.getConnection();
+    Statement statement = null;
+    ResultSet resultSet = null;
+
+    try
+    {
+      statement = connection.createStatement();
+      store.getDBAdapter().createTable(table, statement);
+      connection.commit();
+
+      String sql = "SELECT MIN(" + idField + ") FROM " + table;
+      resultSet = statement.executeQuery(sql);
+
+      if (resultSet.next())
+      {
+        lastMappedID.set(resultSet.getLong(1));
+      }
+
+      // else: resultSet is empty => table is empty
+      // and lastMappedId stays 0 - as initialized.
+    }
+    catch (SQLException ex)
+    {
+      connection.rollback();
+      throw new DBException(ex);
+    }
+    finally
+    {
+      DBUtil.close(resultSet);
+      DBUtil.close(statement);
+      writer.release();
+    }
+
+    StringBuilder builder = new StringBuilder();
+    builder.append("INSERT INTO ");
+    builder.append(table);
+    builder.append("(");
+    builder.append(idField);
+    builder.append(",");
+    builder.append(uriField);
+    builder.append(",");
+    builder.append(timestampField);
+    builder.append(") VALUES (?, ?, ?)");
+    sqlInsert = builder.toString();
+
+    builder = new StringBuilder();
+    builder.append("SELECT "); //$NON-NLS-1$
+    builder.append(idField);
+    builder.append(" FROM "); //$NON-NLS-1$
+    builder.append(table);
+    builder.append(" WHERE "); //$NON-NLS-1$
+    builder.append(uriField);
+    builder.append("=?"); //$NON-NLS-1$
+    sqlSelectByURI = builder.toString();
+
+    builder = new StringBuilder();
+    builder.append("SELECT "); //$NON-NLS-1$
+    builder.append(uriField);
+    builder.append(" FROM "); //$NON-NLS-1$
+    builder.append(table);
+    builder.append(" WHERE "); //$NON-NLS-1$
+    builder.append(idField);
+    builder.append("=?"); //$NON-NLS-1$
+    sqlSelectByLongID = builder.toString();
+  }
+
+  private long insertNew(IDBStoreAccessor accessor, String uri, long commitTime)
+  {
+    long newMappedID = lastMappedID.decrementAndGet();
+
+    IPreparedStatementCache statementCache = accessor.getStatementCache();
+    PreparedStatement stmt = null;
+
+    try
+    {
+      stmt = statementCache.getPreparedStatement(sqlInsert, ReuseProbability.MEDIUM);
+      stmt.setLong(1, newMappedID);
+      stmt.setString(2, uri);
+      stmt.setLong(3, commitTime);
+
+      DBUtil.update(stmt, true);
+      return newMappedID;
+    }
+    catch (SQLException e)
+    {
+      throw new DBException(e);
+    }
+    finally
+    {
+      statementCache.releasePreparedStatement(stmt);
+    }
+  }
+
+  private long lookupByURI(IDBStoreAccessor accessor, String uri)
+  {
+    IPreparedStatementCache statementCache = accessor.getStatementCache();
+    PreparedStatement stmt = null;
+    ResultSet resultSet = null;
+
+    try
+    {
+      stmt = statementCache.getPreparedStatement(sqlSelectByURI, ReuseProbability.HIGH);
+      stmt.setString(1, uri);
+
+      resultSet = stmt.executeQuery();
+
+      if (resultSet.next())
+      {
+        return resultSet.getLong(1);
+      }
+
+      // Not found ...
+      return NULL;
+    }
+    catch (SQLException e)
+    {
+      throw new DBException(e);
+    }
+    finally
+    {
+      DBUtil.close(resultSet);
+      statementCache.releasePreparedStatement(stmt);
+    }
+  }
+
+  private static 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;
+  }
+}
diff --git a/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/IObjectTypeMapper.java b/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/IObjectTypeMapper.java
new file mode 100644
index 0000000..49344d3
--- /dev/null
+++ b/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/IObjectTypeMapper.java
@@ -0,0 +1,53 @@
+/**
+ * Copyright (c) 2004 - 2011 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 - 271444: [DB] Multiple refactorings bug 271444
+ */
+package org.eclipse.emf.cdo.server.internal.db;
+
+import org.eclipse.emf.cdo.common.id.CDOID;
+import org.eclipse.emf.cdo.common.model.CDOClassifierRef;
+import org.eclipse.emf.cdo.common.protocol.CDODataInput;
+import org.eclipse.emf.cdo.common.protocol.CDODataOutput;
+import org.eclipse.emf.cdo.server.db.IDBStoreAccessor;
+import org.eclipse.emf.cdo.server.db.IIDHandler;
+
+import org.eclipse.net4j.util.om.monitor.OMMonitor;
+
+import org.eclipse.emf.ecore.EClass;
+
+import java.io.IOException;
+import java.sql.Connection;
+
+/**
+ * @author Eike Stepper
+ * @since 4.0
+ */
+public interface IObjectTypeMapper
+{
+  public CDOClassifierRef getObjectType(IDBStoreAccessor accessor, CDOID id);
+
+  public void putObjectType(IDBStoreAccessor accessor, long timeStamp, CDOID id, EClass type);
+
+  public void removeObjectType(IDBStoreAccessor accessor, CDOID id);
+
+  /**
+   * Return the maximum object id managed by this cache.
+   * 
+   * @param connection
+   *          the DB connection to use.
+   * @return the maximum object ID.
+   */
+  public CDOID getMaxID(Connection connection, IIDHandler idHandler);
+
+  public void rawExport(Connection connection, CDODataOutput out, long fromCommitTime, long toCommitTime)
+      throws IOException;
+
+  public void rawImport(Connection connection, CDODataInput in, OMMonitor monitor) throws IOException;
+}
diff --git a/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/LongIDHandler.java b/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/LongIDHandler.java
new file mode 100644
index 0000000..79d0615
--- /dev/null
+++ b/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/LongIDHandler.java
@@ -0,0 +1,265 @@
+/**

+ * Copyright (c) 2004 - 2011 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;

+

+import org.eclipse.emf.cdo.common.branch.CDOBranchPoint;

+import org.eclipse.emf.cdo.common.id.CDOID;

+import org.eclipse.emf.cdo.common.id.CDOID.ObjectType;

+import org.eclipse.emf.cdo.common.id.CDOIDExternal;

+import org.eclipse.emf.cdo.common.id.CDOIDUtil;

+import org.eclipse.emf.cdo.common.protocol.CDODataInput;

+import org.eclipse.emf.cdo.common.protocol.CDODataOutput;

+import org.eclipse.emf.cdo.common.revision.CDORevision;

+import org.eclipse.emf.cdo.server.IStoreAccessor.CommitContext;

+import org.eclipse.emf.cdo.server.StoreThreadLocal;

+import org.eclipse.emf.cdo.server.db.IDBStoreAccessor;

+import org.eclipse.emf.cdo.server.db.IIDHandler;

+import org.eclipse.emf.cdo.server.db.mapping.ITypeMapping;

+import org.eclipse.emf.cdo.server.internal.db.mapping.CoreTypeMappings;

+import org.eclipse.emf.cdo.spi.server.LongIDStore;

+

+import org.eclipse.net4j.db.DBType;

+import org.eclipse.net4j.util.lifecycle.Lifecycle;

+import org.eclipse.net4j.util.om.monitor.OMMonitor;

+

+import java.io.IOException;

+import java.sql.Connection;

+import java.sql.PreparedStatement;

+import java.sql.ResultSet;

+import java.sql.SQLException;

+import java.util.Set;

+

+/**

+ * @author Eike Stepper

+ */

+public class LongIDHandler extends Lifecycle implements IIDHandler

+{

+  public static final CDOID MIN = CDOID.NULL;

+

+  public static final CDOID MAX = create(Long.MAX_VALUE);

+

+  private DBStore store;

+

+  private ExternalReferenceManager externalReferenceManager;

+

+  private CDOID lastObjectID = MIN;

+

+  private CDOID nextLocalObjectID = MAX;

+

+  public LongIDHandler(DBStore store)

+  {

+    this.store = store;

+    externalReferenceManager = new ExternalReferenceManager(this);

+  }

+

+  public DBStore getStore()

+  {

+    return store;

+  }

+

+  public Set<ObjectType> getObjectIDTypes()

+  {

+    return LongIDStore.OBJECT_ID_TYPES;

+  }

+

+  public CDOID getMinCDOID()

+  {

+    return MIN;

+  }

+

+  public CDOID getMaxCDOID()

+  {

+    return MAX;

+  }

+

+  public int compare(CDOID id1, CDOID id2)

+  {

+    return id1.compareTo(id2);

+  }

+

+  public CDOID createCDOID(String val)

+  {

+    Long id = Long.valueOf(val);

+    return create(id);

+  }

+

+  public synchronized CDOID getLastObjectID()

+  {

+    return lastObjectID;

+  }

+

+  public synchronized void setLastObjectID(CDOID lastObjectID)

+  {

+    this.lastObjectID = lastObjectID;

+  }

+

+  public synchronized void adjustLastObjectID(CDOID maxID)

+  {

+    if (compare(maxID, lastObjectID) > 0)

+    {

+      lastObjectID = maxID;

+    }

+  }

+

+  public synchronized CDOID getNextLocalObjectID()

+  {

+    return nextLocalObjectID;

+  }

+

+  public synchronized void setNextLocalObjectID(CDOID nextLocalObjectID)

+  {

+    this.nextLocalObjectID = nextLocalObjectID;

+  }

+

+  public synchronized CDOID getNextCDOID(CDORevision revision)

+  {

+    if (revision.getBranch().isLocal())

+    {

+      CDOID result = nextLocalObjectID;

+      nextLocalObjectID = create(value(result) - 1);

+      return result;

+    }

+

+    lastObjectID = create(value(lastObjectID) + 1);

+    return lastObjectID;

+  }

+

+  public boolean isLocalCDOID(CDOID id)

+  {

+    return compare(id, nextLocalObjectID) > 0;

+  }

+

+  public DBType getDBType()

+  {

+    return DBType.BIGINT;

+  }

+

+  public ITypeMapping getObjectTypeMapping()

+  {

+    return new CoreTypeMappings.TMObject();

+  }

+

+  public void appendCDOID(StringBuilder builder, CDOID id)

+  {

+    long value = value(id);

+    builder.append(value);

+  }

+

+  public void setCDOID(PreparedStatement stmt, int column, CDOID id) throws SQLException

+  {

+    setCDOID(stmt, column, id, CDOBranchPoint.INVALID_DATE);

+  }

+

+  public void setCDOID(PreparedStatement stmt, int column, CDOID id, long commitTime) throws SQLException

+  {

+    long value;

+    if (id.getType() == CDOID.Type.EXTERNAL_OBJECT)

+    {

+      if (commitTime == CDOBranchPoint.INVALID_DATE)

+      {

+        CommitContext commitContext = StoreThreadLocal.getCommitContext();

+        commitTime = commitContext != null ? commitContext.getBranchPoint().getTimeStamp()

+            : CDOBranchPoint.UNSPECIFIED_DATE; // Happens on rawStore for workspace checkouts

+      }

+

+      value = externalReferenceManager.mapExternalReference((CDOIDExternal)id, commitTime);

+    }

+    else

+    {

+      value = value(id);

+    }

+

+    stmt.setLong(column, value);

+  }

+

+  public CDOID getCDOID(ResultSet resultSet, int column) throws SQLException

+  {

+    long id = resultSet.getLong(column);

+    if (resultSet.wasNull())

+    {

+      return null;

+    }

+

+    return unmapExternalReference(id);

+  }

+

+  public CDOID getCDOID(ResultSet resultSet, String name) throws SQLException

+  {

+    long id = resultSet.getLong(name);

+    if (resultSet.wasNull())

+    {

+      return null;

+    }

+

+    return unmapExternalReference(id);

+  }

+

+  private CDOID unmapExternalReference(long id)

+  {

+    if (id < 0)

+    {

+      return externalReferenceManager.unmapExternalReference(id);

+    }

+

+    return create(id);

+  }

+

+  public CDOID mapURI(IDBStoreAccessor accessor, String uri, long commitTime)

+  {

+    return create(externalReferenceManager.mapURI(accessor, uri, commitTime));

+  }

+

+  public String unmapURI(IDBStoreAccessor accessor, CDOID id)

+  {

+    if (id.getType() == CDOID.Type.EXTERNAL_OBJECT)

+    {

+      return ((CDOIDExternal)id).getURI();

+    }

+

+    return externalReferenceManager.unmapURI(accessor, value(id));

+  }

+

+  public void rawExport(Connection connection, CDODataOutput out, long fromCommitTime, long toCommitTime)

+      throws IOException

+  {

+    externalReferenceManager.rawExport(connection, out, fromCommitTime, toCommitTime);

+  }

+

+  public void rawImport(Connection connection, CDODataInput in, long fromCommitTime, long toCommitTime,

+      OMMonitor monitor) throws IOException

+  {

+    externalReferenceManager.rawImport(connection, in, fromCommitTime, toCommitTime, monitor);

+  }

+

+  @Override

+  protected void doActivate() throws Exception

+  {

+    super.doActivate();

+    externalReferenceManager.activate();

+  }

+

+  @Override

+  protected void doDeactivate() throws Exception

+  {

+    externalReferenceManager.deactivate();

+    super.doDeactivate();

+  }

+

+  private static CDOID create(long id)

+  {

+    return CDOIDUtil.createLong(id);

+  }

+

+  private static long value(CDOID id)

+  {

+    return CDOIDUtil.getLong(id);

+  }

+}

diff --git a/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/MetaDataManager.java b/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/MetaDataManager.java
new file mode 100644
index 0000000..8882555
--- /dev/null
+++ b/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/MetaDataManager.java
@@ -0,0 +1,429 @@
+/**
+ * Copyright (c) 2004 - 2011 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
+ *    Kai Schlamp - bug 282976: [DB] Influence Mappings through EAnnotations
+ *    Stefan Winkler - bug 282976: [DB] Influence Mappings through EAnnotations
+ */
+package org.eclipse.emf.cdo.server.internal.db;
+
+import org.eclipse.emf.cdo.common.branch.CDOBranchPoint;
+import org.eclipse.emf.cdo.common.id.CDOID;
+import org.eclipse.emf.cdo.common.model.CDOModelConstants;
+import org.eclipse.emf.cdo.common.model.CDOModelUtil;
+import org.eclipse.emf.cdo.common.model.CDOPackageUnit;
+import org.eclipse.emf.cdo.common.model.EMFUtil;
+import org.eclipse.emf.cdo.common.protocol.CDODataInput;
+import org.eclipse.emf.cdo.common.protocol.CDODataOutput;
+import org.eclipse.emf.cdo.server.StoreThreadLocal;
+import org.eclipse.emf.cdo.server.db.IDBStore;
+import org.eclipse.emf.cdo.server.db.IDBStoreAccessor;
+import org.eclipse.emf.cdo.server.db.IMetaDataManager;
+import org.eclipse.emf.cdo.server.internal.db.bundle.OM;
+import org.eclipse.emf.cdo.spi.common.model.InternalCDOPackageInfo;
+import org.eclipse.emf.cdo.spi.common.model.InternalCDOPackageRegistry;
+import org.eclipse.emf.cdo.spi.common.model.InternalCDOPackageUnit;
+
+import org.eclipse.net4j.db.DBException;
+import org.eclipse.net4j.db.DBUtil;
+import org.eclipse.net4j.db.IDBRowHandler;
+import org.eclipse.net4j.util.lifecycle.Lifecycle;
+import org.eclipse.net4j.util.om.monitor.Monitor;
+import org.eclipse.net4j.util.om.monitor.OMMonitor;
+import org.eclipse.net4j.util.om.monitor.OMMonitor.Async;
+import org.eclipse.net4j.util.om.trace.ContextTracer;
+
+import org.eclipse.emf.common.util.URI;
+import org.eclipse.emf.ecore.EModelElement;
+import org.eclipse.emf.ecore.EPackage;
+import org.eclipse.emf.ecore.resource.ResourceSet;
+import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl;
+import org.eclipse.emf.ecore.util.EcoreUtil;
+
+import java.io.IOException;
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+
+/**
+ * @author Eike Stepper
+ */
+public class MetaDataManager extends Lifecycle implements IMetaDataManager
+{
+  private static final ContextTracer TRACER = new ContextTracer(OM.DEBUG, MetaDataManager.class);
+
+  private static final boolean ZIP_PACKAGE_BYTES = true;
+
+  private IDBStore store;
+
+  private Map<EModelElement, CDOID> modelElementToMetaID = new HashMap<EModelElement, CDOID>();
+
+  private Map<CDOID, EModelElement> metaIDToModelElement = new HashMap<CDOID, EModelElement>();
+
+  public MetaDataManager(IDBStore store)
+  {
+    this.store = store;
+  }
+
+  public synchronized CDOID getMetaID(EModelElement modelElement, long commitTime)
+  {
+    CDOID metaID = modelElementToMetaID.get(modelElement);
+    if (metaID != null)
+    {
+      return metaID;
+    }
+
+    IDBStoreAccessor accessor = (IDBStoreAccessor)StoreThreadLocal.getAccessor();
+    String uri = EcoreUtil.getURI(modelElement).toString();
+    metaID = store.getIDHandler().mapURI(accessor, uri, commitTime);
+    cacheMetaIDMapping(modelElement, metaID);
+
+    return metaID;
+  }
+
+  public synchronized EModelElement getMetaInstance(CDOID id)
+  {
+    EModelElement modelElement = metaIDToModelElement.get(id);
+    if (modelElement != null)
+    {
+      return modelElement;
+    }
+
+    IDBStoreAccessor accessor = (IDBStoreAccessor)StoreThreadLocal.getAccessor();
+    String uri = store.getIDHandler().unmapURI(accessor, id);
+
+    ResourceSet resourceSet = new ResourceSetImpl();
+    resourceSet.setPackageRegistry(getStore().getRepository().getPackageRegistry());
+
+    return (EModelElement)resourceSet.getEObject(URI.createURI(uri), true);
+  }
+
+  public synchronized void clearMetaIDMappings()
+  {
+    modelElementToMetaID.clear();
+    metaIDToModelElement.clear();
+  }
+
+  public final EPackage[] loadPackageUnit(Connection connection, InternalCDOPackageUnit packageUnit)
+  {
+    String where = CDODBSchema.PACKAGE_UNITS_ID.getName() + "='" + packageUnit.getID() + "'"; //$NON-NLS-1$ //$NON-NLS-2$
+    Object[] values = DBUtil.select(connection, where, CDODBSchema.PACKAGE_UNITS_PACKAGE_DATA);
+    byte[] bytes = (byte[])values[0];
+    EPackage ePackage = createEPackage(packageUnit, bytes);
+    return EMFUtil.getAllPackages(ePackage);
+  }
+
+  public Collection<InternalCDOPackageUnit> readPackageUnits(Connection connection)
+  {
+    return readPackageUnits(connection, CDOBranchPoint.UNSPECIFIED_DATE, CDOBranchPoint.UNSPECIFIED_DATE, new Monitor());
+  }
+
+  public final void writePackageUnits(Connection connection, InternalCDOPackageUnit[] packageUnits, OMMonitor monitor)
+  {
+    try
+    {
+      monitor.begin(2);
+      fillSystemTables(connection, packageUnits, monitor.fork());
+    }
+    finally
+    {
+      monitor.done();
+    }
+  }
+
+  public void rawExport(Connection connection, CDODataOutput out, long fromCommitTime, long toCommitTime)
+      throws IOException
+  {
+    // Export package units
+    String where = " WHERE p_u." + CDODBSchema.PACKAGE_UNITS_ID + "<>'" + CDOModelConstants.CORE_PACKAGE_URI + //
+        "' AND p_u." + CDODBSchema.PACKAGE_UNITS_ID + "<>'" + CDOModelConstants.RESOURCE_PACKAGE_URI + //
+        "' AND p_u." + CDODBSchema.PACKAGE_UNITS_ID + "<>'" + CDOModelConstants.TYPES_PACKAGE_URI + //
+        "' AND p_u." + CDODBSchema.PACKAGE_UNITS_TIME_STAMP + " BETWEEN " + fromCommitTime + " AND " + toCommitTime;
+    DBUtil.serializeTable(out, connection, CDODBSchema.PACKAGE_UNITS, "p_u", where);
+
+    // Export package infos
+    String join = ", " + CDODBSchema.PACKAGE_UNITS + " p_u" + where + " AND p_i." + CDODBSchema.PACKAGE_INFOS_UNIT
+        + "=p_u." + CDODBSchema.PACKAGE_UNITS_ID;
+    DBUtil.serializeTable(out, connection, CDODBSchema.PACKAGE_INFOS, "p_i", join);
+  }
+
+  public Collection<InternalCDOPackageUnit> rawImport(Connection connection, CDODataInput in, long fromCommitTime,
+      long toCommitTime, OMMonitor monitor) throws IOException
+  {
+    monitor.begin(3);
+
+    try
+    {
+      DBUtil.deserializeTable(in, connection, CDODBSchema.PACKAGE_UNITS, monitor.fork());
+      DBUtil.deserializeTable(in, connection, CDODBSchema.PACKAGE_INFOS, monitor.fork());
+      return readPackageUnits(connection, fromCommitTime, toCommitTime, monitor.fork());
+    }
+    finally
+    {
+      monitor.done();
+    }
+  }
+
+  protected IDBStore getStore()
+  {
+    return store;
+  }
+
+  @Override
+  protected void doBeforeActivate() throws Exception
+  {
+    checkState(store, "Store is not set"); //$NON-NLS-1$
+  }
+
+  @Override
+  protected void doDeactivate() throws Exception
+  {
+    clearMetaIDMappings();
+    super.doDeactivate();
+  }
+
+  protected InternalCDOPackageInfo createPackageInfo()
+  {
+    return (InternalCDOPackageInfo)CDOModelUtil.createPackageInfo();
+  }
+
+  protected InternalCDOPackageUnit createPackageUnit()
+  {
+    return (InternalCDOPackageUnit)CDOModelUtil.createPackageUnit();
+  }
+
+  private InternalCDOPackageRegistry getPackageRegistry()
+  {
+    return (InternalCDOPackageRegistry)store.getRepository().getPackageRegistry();
+  }
+
+  private EPackage createEPackage(InternalCDOPackageUnit packageUnit, byte[] bytes)
+  {
+    ResourceSet resourceSet = EMFUtil.newEcoreResourceSet(getPackageRegistry());
+    return EMFUtil.createEPackage(packageUnit.getID(), bytes, ZIP_PACKAGE_BYTES, resourceSet, false);
+  }
+
+  private byte[] getEPackageBytes(InternalCDOPackageUnit packageUnit)
+  {
+    EPackage ePackage = packageUnit.getTopLevelPackageInfo().getEPackage();
+    return EMFUtil.getEPackageBytes(ePackage, ZIP_PACKAGE_BYTES, getPackageRegistry());
+  }
+
+  private void fillSystemTables(Connection connection, InternalCDOPackageUnit packageUnit, OMMonitor monitor)
+  {
+    if (TRACER.isEnabled())
+    {
+      TRACER.format("Writing package unit: {0}", packageUnit); //$NON-NLS-1$
+    }
+
+    InternalCDOPackageInfo[] packageInfos = packageUnit.getPackageInfos();
+    Async async = null;
+    monitor.begin(1 + packageInfos.length);
+
+    try
+    {
+      String sql = "INSERT INTO " + CDODBSchema.PACKAGE_UNITS + " VALUES (?, ?, ?, ?)"; //$NON-NLS-1$ //$NON-NLS-2$
+      DBUtil.trace(sql);
+      PreparedStatement stmt = null;
+
+      try
+      {
+        async = monitor.forkAsync();
+        stmt = connection.prepareStatement(sql);
+        stmt.setString(1, packageUnit.getID());
+        stmt.setInt(2, packageUnit.getOriginalType().ordinal());
+        stmt.setLong(3, packageUnit.getTimeStamp());
+        stmt.setBytes(4, getEPackageBytes(packageUnit));
+
+        if (stmt.execute())
+        {
+          throw new DBException("No result set expected"); //$NON-NLS-1$
+        }
+
+        if (stmt.getUpdateCount() == 0)
+        {
+          throw new DBException("No row inserted into table " + CDODBSchema.PACKAGE_UNITS); //$NON-NLS-1$
+        }
+      }
+      catch (SQLException ex)
+      {
+        throw new DBException(ex);
+      }
+      finally
+      {
+        DBUtil.close(stmt);
+        if (async != null)
+        {
+          async.stop();
+        }
+      }
+
+      for (InternalCDOPackageInfo packageInfo : packageInfos)
+      {
+        fillSystemTables(connection, packageInfo, monitor); // Don't fork monitor
+      }
+    }
+    finally
+    {
+      monitor.done();
+    }
+  }
+
+  private void fillSystemTables(Connection connection, InternalCDOPackageUnit[] packageUnits, OMMonitor monitor)
+  {
+    try
+    {
+      monitor.begin(packageUnits.length);
+      for (InternalCDOPackageUnit packageUnit : packageUnits)
+      {
+        fillSystemTables(connection, packageUnit, monitor.fork());
+      }
+    }
+    finally
+    {
+      monitor.done();
+    }
+  }
+
+  private void fillSystemTables(Connection connection, InternalCDOPackageInfo packageInfo, OMMonitor monitor)
+  {
+    if (TRACER.isEnabled())
+    {
+      TRACER.format("Writing package info: {0}", packageInfo); //$NON-NLS-1$
+    }
+
+    String packageURI = packageInfo.getPackageURI();
+    String parentURI = packageInfo.getParentURI();
+    String unitID = packageInfo.getPackageUnit().getID();
+
+    String sql = "INSERT INTO " + CDODBSchema.PACKAGE_INFOS + " VALUES (?, ?, ?)"; //$NON-NLS-1$ //$NON-NLS-2$
+    DBUtil.trace(sql);
+    PreparedStatement stmt = null;
+    Async async = monitor.forkAsync();
+
+    try
+    {
+      stmt = connection.prepareStatement(sql);
+      stmt.setString(1, packageURI);
+      stmt.setString(2, parentURI);
+      stmt.setString(3, unitID);
+
+      if (stmt.execute())
+      {
+        throw new DBException("No result set expected"); //$NON-NLS-1$
+      }
+
+      if (stmt.getUpdateCount() == 0)
+      {
+        throw new DBException("No row inserted into table " + CDODBSchema.PACKAGE_INFOS); //$NON-NLS-1$
+      }
+    }
+    catch (SQLException ex)
+    {
+      throw new DBException(ex);
+    }
+    finally
+    {
+      DBUtil.close(stmt);
+      if (async != null)
+      {
+        async.stop();
+      }
+    }
+  }
+
+  private Collection<InternalCDOPackageUnit> readPackageUnits(Connection connection, long fromCommitTime,
+      long toCommitTime, OMMonitor monitor)
+  {
+    final Map<String, InternalCDOPackageUnit> packageUnits = new HashMap<String, InternalCDOPackageUnit>();
+    IDBRowHandler unitRowHandler = new IDBRowHandler()
+    {
+      public boolean handle(int row, final Object... values)
+      {
+        InternalCDOPackageUnit packageUnit = createPackageUnit();
+        packageUnit.setOriginalType(CDOPackageUnit.Type.values()[(Integer)values[1]]);
+        packageUnit.setTimeStamp((Long)values[2]);
+        packageUnits.put((String)values[0], packageUnit);
+        return true;
+      }
+    };
+
+    String where = null;
+    if (fromCommitTime != CDOBranchPoint.UNSPECIFIED_DATE)
+    {
+      where = CDODBSchema.PACKAGE_UNITS_ID + "<>'" + CDOModelConstants.CORE_PACKAGE_URI + "' AND "
+          + CDODBSchema.PACKAGE_UNITS_ID + "<>'" + CDOModelConstants.RESOURCE_PACKAGE_URI + "' AND "
+          + CDODBSchema.PACKAGE_UNITS_ID + "<>'" + CDOModelConstants.TYPES_PACKAGE_URI + "' AND "
+          + CDODBSchema.PACKAGE_UNITS_TIME_STAMP + " BETWEEN " + fromCommitTime + " AND " + toCommitTime;
+    }
+
+    DBUtil.select(connection, unitRowHandler, where, CDODBSchema.PACKAGE_UNITS_ID,
+        CDODBSchema.PACKAGE_UNITS_ORIGINAL_TYPE, CDODBSchema.PACKAGE_UNITS_TIME_STAMP);
+
+    final Map<String, List<InternalCDOPackageInfo>> packageInfos = new HashMap<String, List<InternalCDOPackageInfo>>();
+    IDBRowHandler infoRowHandler = new IDBRowHandler()
+    {
+      public boolean handle(int row, final Object... values)
+      {
+        InternalCDOPackageInfo packageInfo = createPackageInfo();
+        packageInfo.setPackageURI((String)values[1]);
+        packageInfo.setParentURI((String)values[2]);
+
+        String unit = (String)values[0];
+        List<InternalCDOPackageInfo> list = packageInfos.get(unit);
+        if (list == null)
+        {
+          list = new ArrayList<InternalCDOPackageInfo>();
+          packageInfos.put(unit, list);
+        }
+
+        list.add(packageInfo);
+        return true;
+      }
+    };
+
+    monitor.begin();
+    Async async = monitor.forkAsync();
+
+    try
+    {
+      DBUtil.select(connection, infoRowHandler, CDODBSchema.PACKAGE_INFOS_UNIT, CDODBSchema.PACKAGE_INFOS_URI,
+          CDODBSchema.PACKAGE_INFOS_PARENT);
+    }
+    finally
+    {
+      async.stop();
+      monitor.done();
+    }
+
+    for (Entry<String, InternalCDOPackageUnit> entry : packageUnits.entrySet())
+    {
+      String id = entry.getKey();
+      InternalCDOPackageUnit packageUnit = entry.getValue();
+
+      List<InternalCDOPackageInfo> list = packageInfos.get(id);
+      InternalCDOPackageInfo[] array = list.toArray(new InternalCDOPackageInfo[list.size()]);
+      packageUnit.setPackageInfos(array);
+    }
+
+    return packageUnits.values();
+  }
+
+  private void cacheMetaIDMapping(EModelElement modelElement, CDOID metaID)
+  {
+    modelElementToMetaID.put(modelElement, metaID);
+    metaIDToModelElement.put(metaID, modelElement);
+  }
+}
diff --git a/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/NullPreparedStatementCache.java b/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/NullPreparedStatementCache.java
new file mode 100644
index 0000000..86f1894
--- /dev/null
+++ b/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/NullPreparedStatementCache.java
@@ -0,0 +1,69 @@
+/**
+ * Copyright (c) 2004 - 2011 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 - 271444: [DB] Multiple refactorings bug 271444
+ */
+package org.eclipse.emf.cdo.server.internal.db;
+
+import org.eclipse.emf.cdo.server.internal.db.bundle.OM;
+
+import org.eclipse.net4j.db.DBException;
+import org.eclipse.net4j.db.DBUtil;
+
+import java.sql.PreparedStatement;
+import java.sql.SQLException;
+import java.util.HashSet;
+
+/**
+ * @author Stefan Winkler
+ * @since 2.0
+ */
+public class NullPreparedStatementCache extends AbstractPreparedStatementCache
+{
+  private HashSet<PreparedStatement> allocatedStatements = new HashSet<PreparedStatement>();
+
+  public NullPreparedStatementCache()
+  {
+  }
+
+  public PreparedStatement getPreparedStatement(String sql, ReuseProbability reuseProbability)
+  {
+    try
+    {
+      PreparedStatement result = getConnection().prepareStatement(sql);
+      allocatedStatements.add(result);
+      return result;
+    }
+    catch (SQLException ex)
+    {
+      throw new DBException(ex);
+    }
+  }
+
+  public void releasePreparedStatement(PreparedStatement ps)
+  {
+    allocatedStatements.remove(ps);
+    DBUtil.close(ps);
+  }
+
+  @Override
+  protected void doBeforeDeactivate() throws Exception
+  {
+    if (!allocatedStatements.isEmpty())
+    {
+      OM.LOG.warn("Possible Leak Detected:"); //$NON-NLS-1$
+      for (PreparedStatement ps : allocatedStatements)
+      {
+        OM.LOG.warn("- " + ps.toString()); //$NON-NLS-1$
+      }
+
+      assert false;
+    }
+  }
+}
diff --git a/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/ObjectIDIterator.java b/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/ObjectIDIterator.java
new file mode 100644
index 0000000..9328e5c
--- /dev/null
+++ b/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/ObjectIDIterator.java
@@ -0,0 +1,138 @@
+/**
+ * Copyright (c) 2004 - 2011 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
+ *    Victor Roldan Betancort - bug 208689
+ */
+package org.eclipse.emf.cdo.server.internal.db;
+
+import org.eclipse.emf.cdo.common.id.CDOID;
+import org.eclipse.emf.cdo.server.db.IDBStoreAccessor;
+import org.eclipse.emf.cdo.server.db.IIDHandler;
+import org.eclipse.emf.cdo.server.db.mapping.IMappingStrategy;
+
+import org.eclipse.net4j.db.DBException;
+import org.eclipse.net4j.db.DBUtil;
+import org.eclipse.net4j.util.collection.CloseableIterator;
+
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.NoSuchElementException;
+
+/**
+ * @author Eike Stepper
+ */
+public abstract class ObjectIDIterator implements CloseableIterator<CDOID>
+{
+  private IMappingStrategy mappingStrategy;
+
+  private IIDHandler idHandler;
+
+  private IDBStoreAccessor accessor;
+
+  private ResultSet currentResultSet;
+
+  private CDOID nextID;
+
+  private boolean closed;
+
+  /**
+   * Creates an iterator over all objects in a store. It is important to {@link #close()} of this iterator after usage
+   * to properly close internal result sets.
+   */
+  public ObjectIDIterator(IMappingStrategy mappingStrategy, IDBStoreAccessor accessor)
+  {
+    this.mappingStrategy = mappingStrategy;
+    this.accessor = accessor;
+    idHandler = getMappingStrategy().getStore().getIDHandler();
+
+  }
+
+  public void close()
+  {
+    closeCurrentResultSet();
+    nextID = null;
+    closed = true;
+  }
+
+  public boolean isClosed()
+  {
+    return closed;
+  }
+
+  public IMappingStrategy getMappingStrategy()
+  {
+    return mappingStrategy;
+  }
+
+  public IDBStoreAccessor getAccessor()
+  {
+    return accessor;
+  }
+
+  public boolean hasNext()
+  {
+    if (closed)
+    {
+      return false;
+    }
+
+    nextID = null;
+    for (;;)
+    {
+      if (currentResultSet == null)
+      {
+        currentResultSet = getNextResultSet();
+        if (currentResultSet == null)
+        {
+          return false;
+        }
+      }
+
+      try
+      {
+        if (currentResultSet.next())
+        {
+          nextID = idHandler.getCDOID(currentResultSet, 1);
+          return true;
+        }
+
+        closeCurrentResultSet();
+
+        currentResultSet = null;
+        return false;
+      }
+      catch (SQLException ex)
+      {
+        throw new DBException(ex);
+      }
+    }
+  }
+
+  protected void closeCurrentResultSet()
+  {
+    DBUtil.close(currentResultSet);
+  }
+
+  public CDOID next()
+  {
+    if (nextID == null)
+    {
+      throw new NoSuchElementException();
+    }
+
+    return nextID;
+  }
+
+  public void remove()
+  {
+    throw new UnsupportedOperationException();
+  }
+
+  protected abstract ResultSet getNextResultSet();
+}
diff --git a/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/SQLQueryHandler.java b/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/SQLQueryHandler.java
new file mode 100644
index 0000000..589e7a1
--- /dev/null
+++ b/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/SQLQueryHandler.java
@@ -0,0 +1,364 @@
+/**
+ * Copyright (c) 2004 - 2011 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:
+ *    Kai Schlamp - initial API and implementation
+ *    Eike Stepper - maintenance
+ *    Kai Schlamp - Bug 284812: [DB] Query non CDO object fails
+ *    Erdal Karaca - added cdoObjectResultAsMap parameter to return Map<String,Object> in result
+ */
+package org.eclipse.emf.cdo.server.internal.db;
+
+import org.eclipse.emf.cdo.common.id.CDOID;
+import org.eclipse.emf.cdo.common.util.CDOQueryInfo;
+import org.eclipse.emf.cdo.server.IQueryContext;
+import org.eclipse.emf.cdo.server.IQueryHandler;
+import org.eclipse.emf.cdo.server.db.IIDHandler;
+
+import org.eclipse.net4j.db.DBException;
+import org.eclipse.net4j.db.DBUtil;
+
+import java.sql.Clob;
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Implements server side SQL query execution.
+ * 
+ * @author Kai Schlamp
+ */
+public class SQLQueryHandler implements IQueryHandler
+{
+  public static final String QUERY_LANGUAGE = "sql";
+
+  public static final String FIRST_RESULT = "firstResult";
+
+  public static final String CDO_OBJECT_QUERY = "cdoObjectQuery";
+
+  public static final String MAP_QUERY = "mapQuery";
+
+  public static final String QUERY_STATEMENT = "queryStatement";
+
+  private DBStoreAccessor storeAccessor;
+
+  public SQLQueryHandler(DBStoreAccessor storeAccessor)
+  {
+    this.storeAccessor = storeAccessor;
+  }
+
+  public DBStoreAccessor getStoreAccessor()
+  {
+    return storeAccessor;
+  }
+
+  /**
+   * Executes SQL queries. Gets the connection from {@link DBStoreAccessor}, creates a SQL query and sets the parameters
+   * taken from the {@link CDOQueryInfo#getParameters()}.
+   * <p>
+   * Takes into account the {@link CDOQueryInfo#getMaxResults()} and the {@link SQLQueryHandler#FIRST_RESULT} (numbered
+   * from 0) values for paging.
+   * <p>
+   * By default (parameter {@link SQLQueryHandler#CDO_OBJECT_QUERY} == true) a query for CDO Objects is exectued. The
+   * SQL query must return the CDO ID in the first column for this to work. If you set
+   * {@link SQLQueryHandler#CDO_OBJECT_QUERY} parameter to false, the value of the first column of a row itself is
+   * returned.
+   * <p>
+   * By default (parameter {@link SQLQueryHandler#QUERY_STATEMENT} == true) query statements are executed. Set this
+   * parameter to false for update/DDL statements.
+   * <p>
+   * It is possible to use variables inside the SQL string with ":" as prefix. E.g.
+   * "SELECT cdo_id FROM Company WHERE name LIKE :name". The value must then be set by using a parameter. E.g.
+   * query.setParameter(":name", "Foo%");
+   * 
+   * @param info
+   *          the object containing the query and parameters
+   * @param context
+   *          the query results are placed in the context
+   * @see IQueryHandler#executeQuery(CDOQueryInfo, IQueryContext)
+   */
+  public void executeQuery(CDOQueryInfo info, IQueryContext context)
+  {
+    String language = info.getQueryLanguage();
+    if (!QUERY_LANGUAGE.equals(language))
+    {
+      throw new IllegalArgumentException("Unsupported query language: " + language);
+    }
+
+    IIDHandler idHandler = storeAccessor.getStore().getIDHandler();
+    Connection connection = storeAccessor.getConnection();
+    PreparedStatement statement = null;
+    ResultSet resultSet = null;
+    String query = info.getQueryString();
+
+    try
+    {
+      int firstResult = -1;
+      boolean queryStatement = true;
+      boolean objectQuery = true;
+      boolean mapQuery = false;
+
+      HashMap<String, List<Integer>> paramMap = new HashMap<String, List<Integer>>();
+      query = parse(query, paramMap);
+      statement = connection.prepareStatement(query, ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
+
+      for (String key : info.getParameters().keySet())
+      {
+        if (FIRST_RESULT.equalsIgnoreCase(key))
+        {
+          final Object o = info.getParameters().get(key);
+          if (o != null)
+          {
+            try
+            {
+              firstResult = (Integer)o;
+            }
+            catch (ClassCastException ex)
+            {
+              throw new IllegalArgumentException("Parameter " + FIRST_RESULT + " must be an integer but it is a " + o
+                  + " class " + o.getClass().getName(), ex);
+            }
+          }
+        }
+        else if (QUERY_STATEMENT.equalsIgnoreCase(key))
+        {
+          final Object o = info.getParameters().get(key);
+          if (o != null)
+          {
+            try
+            {
+              queryStatement = (Boolean)o;
+            }
+            catch (ClassCastException ex)
+            {
+              throw new IllegalArgumentException("Parameter " + QUERY_STATEMENT + " must be an boolean but it is a "
+                  + o + " class " + o.getClass().getName(), ex);
+            }
+          }
+        }
+        else if (CDO_OBJECT_QUERY.equalsIgnoreCase(key))
+        {
+          final Object o = info.getParameters().get(key);
+          if (o != null)
+          {
+            try
+            {
+              objectQuery = (Boolean)o;
+            }
+            catch (ClassCastException ex)
+            {
+              throw new IllegalArgumentException("Parameter " + CDO_OBJECT_QUERY + " must be a boolean but it is a "
+                  + o + " class " + o.getClass().getName(), ex);
+            }
+          }
+        }
+        else if (MAP_QUERY.equalsIgnoreCase(key))
+        {
+          final Object o = info.getParameters().get(key);
+          if (o != null)
+          {
+            try
+            {
+              mapQuery = (Boolean)o;
+            }
+            catch (ClassCastException ex)
+            {
+              throw new IllegalArgumentException("Parameter " + MAP_QUERY + " must be a boolean but it is a " + o
+                  + " class " + o.getClass().getName(), ex);
+            }
+          }
+        }
+        else
+        {
+          if (!paramMap.containsKey(key) || paramMap.get(key) == null)
+          {
+            throw new IllegalArgumentException("No parameter value found for named parameter " + key);
+          }
+
+          Integer[] indexes = paramMap.get(key).toArray(new Integer[0]);
+          for (int i = 0; i < indexes.length; i++)
+          {
+            Object parameter = info.getParameters().get(key);
+            statement.setObject(indexes[i], parameter);
+          }
+        }
+      }
+
+      if (queryStatement)
+      {
+        resultSet = statement.executeQuery();
+        if (firstResult > -1)
+        {
+          resultSet.absolute(firstResult);
+        }
+
+        String[] columnNames = null;
+        if (mapQuery)
+        {
+          columnNames = new String[resultSet.getMetaData().getColumnCount()];
+          for (int i = 1; i <= columnNames.length; i++)
+          {
+            columnNames[i - 1] = resultSet.getMetaData().getColumnName(i);
+          }
+        }
+
+        int maxResults = info.getMaxResults();
+        int counter = 0;
+
+        while (resultSet.next())
+        {
+          if (maxResults != CDOQueryInfo.UNLIMITED_RESULTS && counter++ >= maxResults)
+          {
+            break;
+          }
+
+          if (objectQuery)
+          {
+            CDOID result = idHandler.getCDOID(resultSet, 1);
+            context.addResult(result);
+          }
+          else
+          {
+            int columnCount = resultSet.getMetaData().getColumnCount();
+            if (columnCount == 1)
+            {
+              Object result = convertValue(resultSet.getObject(1));
+              context.addResult(mapQuery ? toMap(columnNames, new Object[] { result }) : result);
+            }
+            else
+            {
+              Object[] results = new Object[columnCount];
+              for (int i = 0; i < columnCount; i++)
+              {
+                results[i] = convertValue(resultSet.getObject(i + 1));
+              }
+
+              context.addResult(mapQuery ? toMap(columnNames, results) : results);
+            }
+          }
+        }
+      }
+      else
+      {
+        int result = statement.executeUpdate();
+        context.addResult(result);
+      }
+    }
+    catch (SQLException ex)
+    {
+      throw new DBException("Problem while executing SQL query: " + query, ex);
+    }
+    finally
+    {
+      DBUtil.close(resultSet);
+      DBUtil.close(statement);
+    }
+  }
+
+  private Object convertValue(Object value)
+  {
+    if (value instanceof Clob)
+    {
+      Clob clob = (Clob)value;
+
+      try
+      {
+        value = clob.getSubString(1, (int)clob.length());
+      }
+      catch (SQLException ex)
+      {
+        throw new DBException("Could not extract CLOB value", ex);
+      }
+    }
+
+    return value;
+  }
+
+  private Map<String, Object> toMap(String[] columnNames, Object[] results)
+  {
+    Map<String, Object> ret = new HashMap<String, Object>();
+
+    for (int i = 0; i < columnNames.length; i++)
+    {
+      String columnName = columnNames[i];
+      ret.put(columnName, results[i]);
+    }
+
+    return ret;
+  }
+
+  private String parse(String query, Map<String, List<Integer>> paramMap)
+  {
+    int length = query.length();
+    StringBuilder builder = new StringBuilder(length);
+
+    boolean inSingleQuote = false;
+    boolean inDoubleQuote = false;
+    int index = 1;
+
+    for (int i = 0; i < length; i++)
+    {
+      char c = query.charAt(i);
+      if (inSingleQuote)
+      {
+        if (c == '\'')
+        {
+          inSingleQuote = false;
+        }
+      }
+      else if (inDoubleQuote)
+      {
+        if (c == '"')
+        {
+          inDoubleQuote = false;
+        }
+      }
+      else
+      {
+        if (c == '\'')
+        {
+          inSingleQuote = true;
+        }
+        else if (c == '"')
+        {
+          inDoubleQuote = true;
+        }
+        else if (c == ':' && i + 1 < length && Character.isJavaIdentifierStart(query.charAt(i + 1)))
+        {
+          int j = i + 2;
+          while (j < length && Character.isJavaIdentifierPart(query.charAt(j)))
+          {
+            j++;
+          }
+
+          String name = query.substring(i + 1, j);
+          c = '?';
+          i += name.length();
+
+          List<Integer> indexList = paramMap.get(name);
+          if (indexList == null)
+          {
+            indexList = new ArrayList<Integer>();
+            paramMap.put(name, indexList);
+          }
+
+          indexList.add(new Integer(index));
+          index++;
+        }
+      }
+
+      builder.append(c);
+    }
+
+    return builder.toString();
+  }
+}
diff --git a/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/SmartPreparedStatementCache.java b/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/SmartPreparedStatementCache.java
new file mode 100644
index 0000000..0ea0e91
--- /dev/null
+++ b/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/SmartPreparedStatementCache.java
@@ -0,0 +1,291 @@
+/**
+ * Copyright (c) 2004 - 2011 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;
+
+import org.eclipse.emf.cdo.server.internal.db.bundle.OM;
+
+import org.eclipse.net4j.db.DBException;
+import org.eclipse.net4j.util.ImplementationError;
+
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.SQLException;
+import java.util.HashMap;
+
+/**
+ * @author Stefan Winkler
+ * @since 2.0
+ */
+public class SmartPreparedStatementCache extends AbstractPreparedStatementCache
+{
+  private Cache cache;
+
+  private HashMap<PreparedStatement, CachedPreparedStatement> checkedOut = new HashMap<PreparedStatement, CachedPreparedStatement>();
+
+  public SmartPreparedStatementCache(int capacity)
+  {
+    cache = new Cache(capacity);
+  }
+
+  public PreparedStatement getPreparedStatement(String sql, ReuseProbability reuseProbability)
+  {
+    CachedPreparedStatement cachedStatement = cache.remove(sql);
+    if (cachedStatement == null)
+    {
+      cachedStatement = createCachedPreparedStatement(sql, reuseProbability);
+    }
+
+    PreparedStatement result = cachedStatement.getPreparedStatement();
+    checkedOut.put(result, cachedStatement);
+
+    return result;
+  }
+
+  /**
+   * @param ps
+   *          the prepared statement to be released to the cache, or <code>null</code>.
+   */
+  public void releasePreparedStatement(PreparedStatement ps)
+  {
+    if (ps != null) // Bug 276926: Silently accept ps == null and do nothing.
+    {
+      CachedPreparedStatement cachedStatement = checkedOut.remove(ps);
+      cache.put(cachedStatement);
+    }
+  }
+
+  @Override
+  protected void doBeforeDeactivate() throws Exception
+  {
+    if (!checkedOut.isEmpty())
+    {
+      OM.LOG.warn("Statement leak detected"); //$NON-NLS-1$
+    }
+  }
+
+  private CachedPreparedStatement createCachedPreparedStatement(String sql, ReuseProbability reuseProbability)
+  {
+    try
+    {
+      Connection connection = getConnection();
+      PreparedStatement stmt = connection.prepareStatement(sql);
+      return new CachedPreparedStatement(sql, reuseProbability, stmt);
+    }
+    catch (SQLException ex)
+    {
+      throw new DBException(ex);
+    }
+  }
+
+  /**
+   * @author Stefan Winkler
+   */
+  private static final class Cache
+  {
+    private CacheList lists[];
+
+    private HashMap<String, CachedPreparedStatement> lookup;
+
+    private int capacity;
+
+    public Cache(int capacity)
+    {
+      this.capacity = capacity;
+
+      lookup = new HashMap<String, CachedPreparedStatement>(capacity);
+
+      lists = new CacheList[ReuseProbability.values().length];
+      for (ReuseProbability prob : ReuseProbability.values())
+      {
+        lists[prob.ordinal()] = new CacheList();
+      }
+    }
+
+    public void put(CachedPreparedStatement cachedStatement)
+    {
+      // refresh age
+      cachedStatement.touch();
+
+      // put into appripriate list
+      lists[cachedStatement.getProbability().ordinal()].add(cachedStatement);
+
+      // put into lookup table
+      if (lookup.put(cachedStatement.getSQL(), cachedStatement) != null)
+      {
+        throw new ImplementationError(cachedStatement.getSQL() + " already in cache"); //$NON-NLS-1$
+      }
+
+      // handle capacity overflow
+      if (lookup.size() > capacity)
+      {
+        evictOne();
+      }
+    }
+
+    private void evictOne()
+    {
+      long maxAge = -1;
+      int ordinal = -1;
+
+      for (ReuseProbability prob : ReuseProbability.values())
+      {
+        if (!lists[prob.ordinal()].isEmpty())
+        {
+          long age = lists[prob.ordinal()].tail().getAge();
+          if (maxAge < age)
+          {
+            maxAge = age;
+            ordinal = prob.ordinal();
+          }
+        }
+      }
+
+      remove(lists[ordinal].tail().getSQL());
+    }
+
+    public CachedPreparedStatement remove(String sql)
+    {
+      CachedPreparedStatement result = lookup.remove(sql);
+      if (result == null)
+      {
+        return null;
+      }
+
+      lists[result.getProbability().ordinal()].remove(result);
+      return result;
+    }
+
+    /**
+     * @author Stefan Winkler
+     */
+    private class CacheList
+    {
+      private CachedPreparedStatement first;
+
+      private CachedPreparedStatement last;
+
+      public CacheList()
+      {
+      }
+
+      public void add(CachedPreparedStatement s)
+      {
+        if (first == null)
+        {
+          first = s;
+          last = s;
+          s.previous = null;
+          s.next = null;
+        }
+        else
+        {
+          first.previous = s;
+          s.next = first;
+          first = s;
+        }
+      }
+
+      public void remove(CachedPreparedStatement s)
+      {
+        if (s == first)
+        {
+          first = s.next;
+        }
+
+        if (s.next != null)
+        {
+          s.next.previous = s.previous;
+        }
+
+        if (s == last)
+        {
+          last = s.previous;
+        }
+
+        if (s.previous != null)
+        {
+          s.previous.next = s.next;
+        }
+
+        s.previous = null;
+        s.next = null;
+      }
+
+      public CachedPreparedStatement tail()
+      {
+        return last;
+      }
+
+      public boolean isEmpty()
+      {
+        return first == null;
+      }
+    }
+  }
+
+  /**
+   * @author Stefan Winkler
+   */
+  private static final class CachedPreparedStatement
+  {
+    private long timeStamp;
+
+    private String sql;
+
+    private ReuseProbability probability;
+
+    private PreparedStatement statement;
+
+    /**
+     * DL field
+     */
+    private CachedPreparedStatement previous;
+
+    /**
+     * DL field
+     */
+    private CachedPreparedStatement next;
+
+    public CachedPreparedStatement(String sql, ReuseProbability prob, PreparedStatement stmt)
+    {
+      this.sql = sql;
+      probability = prob;
+      statement = stmt;
+      timeStamp = System.currentTimeMillis();
+    }
+
+    public PreparedStatement getPreparedStatement()
+    {
+      return statement;
+    }
+
+    public long getAge()
+    {
+      long currentTime = System.currentTimeMillis();
+      return (currentTime - timeStamp) * probability.ordinal();
+    }
+
+    public void touch()
+    {
+      timeStamp = System.currentTimeMillis();
+    }
+
+    public String getSQL()
+    {
+      return sql;
+    }
+
+    public ReuseProbability getProbability()
+    {
+      return probability;
+    }
+  }
+}
diff --git a/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/StringIDHandler.java b/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/StringIDHandler.java
new file mode 100644
index 0000000..8039584
--- /dev/null
+++ b/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/StringIDHandler.java
@@ -0,0 +1,249 @@
+/**

+ * Copyright (c) 2004 - 2011 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;

+

+import org.eclipse.emf.cdo.common.branch.CDOBranchPoint;

+import org.eclipse.emf.cdo.common.id.CDOID;

+import org.eclipse.emf.cdo.common.id.CDOID.ObjectType;

+import org.eclipse.emf.cdo.common.id.CDOIDUtil;

+import org.eclipse.emf.cdo.common.protocol.CDODataInput;

+import org.eclipse.emf.cdo.common.protocol.CDODataOutput;

+import org.eclipse.emf.cdo.common.revision.CDORevision;

+import org.eclipse.emf.cdo.server.db.IDBStoreAccessor;

+import org.eclipse.emf.cdo.server.db.IIDHandler;

+import org.eclipse.emf.cdo.server.db.mapping.ITypeMapping;

+import org.eclipse.emf.cdo.server.internal.db.mapping.CoreTypeMappings;

+

+import org.eclipse.net4j.db.DBType;

+import org.eclipse.net4j.util.lifecycle.Lifecycle;

+import org.eclipse.net4j.util.om.monitor.OMMonitor;

+

+import java.io.IOException;

+import java.sql.Connection;

+import java.sql.PreparedStatement;

+import java.sql.ResultSet;

+import java.sql.SQLException;

+import java.util.Collections;

+import java.util.Set;

+

+/**

+ * @author Eike Stepper

+ */

+public class StringIDHandler extends Lifecycle implements IIDHandler

+{

+  public static final Set<ObjectType> OBJECT_ID_TYPES = Collections.singleton(CDOID.ObjectType.STRING);

+

+  public static final CDOID MIN = CDOID.NULL;

+

+  public static final CDOID MAX = create(Long.toString(Long.MAX_VALUE));

+

+  private DBStore store;

+

+  private long lastObjectID = 0;

+

+  private long nextLocalObjectID = Long.MAX_VALUE;

+

+  public StringIDHandler(DBStore store)

+  {

+    this.store = store;

+  }

+

+  public DBStore getStore()

+  {

+    return store;

+  }

+

+  public int compare(CDOID id1, CDOID id2)

+  {

+    if (id1.getType() == CDOID.Type.OBJECT && id2.getType() == CDOID.Type.OBJECT)

+    {

+      return Long.valueOf(value(id1)).compareTo(Long.valueOf(value(id2)));

+    }

+

+    return id1.compareTo(id2);

+  }

+

+  public DBType getDBType()

+  {

+    return DBType.VARCHAR;

+  }

+

+  public Set<ObjectType> getObjectIDTypes()

+  {

+    return OBJECT_ID_TYPES;

+  }

+

+  public CDOID createCDOID(String val)

+  {

+    return create(val);

+  }

+

+  public synchronized CDOID getLastObjectID()

+  {

+    return CDOIDUtil.createString("" + lastObjectID);

+  }

+

+  public synchronized void setLastObjectID(CDOID lastObjectID)

+  {

+    this.lastObjectID = Long.parseLong(value(lastObjectID));

+  }

+

+  public void adjustLastObjectID(CDOID maxID)

+  {

+    // TODO: implement StringIDHandler.adjustLastObjectID(maxID)

+    throw new UnsupportedOperationException();

+  }

+

+  public synchronized CDOID getNextLocalObjectID()

+  {

+    return CDOIDUtil.createString("" + nextLocalObjectID);

+  }

+

+  public synchronized void setNextLocalObjectID(CDOID nextLocalObjectID)

+  {

+    this.nextLocalObjectID = Long.parseLong(value(nextLocalObjectID));

+  }

+

+  public synchronized CDOID getNextCDOID(CDORevision revision)

+  {

+    if (revision.getBranch().isLocal())

+    {

+      return CDOIDUtil.createString("" + nextLocalObjectID--);

+    }

+

+    return CDOIDUtil.createString("" + ++lastObjectID);

+  }

+

+  public boolean isLocalCDOID(CDOID id)

+  {

+    if (id.getType() == CDOID.Type.OBJECT)

+    {

+      return Long.parseLong(value(id)) > nextLocalObjectID;

+    }

+

+    return false;

+  }

+

+  public ITypeMapping getObjectTypeMapping()

+  {

+    return new CoreTypeMappings.TMObject();

+  }

+

+  public void appendCDOID(StringBuilder builder, CDOID id)

+  {

+    builder.append("'");

+    builder.append(value(id));

+    builder.append("'");

+  }

+

+  public void setCDOID(PreparedStatement stmt, int column, CDOID id) throws SQLException

+  {

+    setCDOID(stmt, column, id, CDOBranchPoint.INVALID_DATE);

+  }

+

+  public void setCDOID(PreparedStatement stmt, int column, CDOID id, long commitTime) throws SQLException

+  {

+    String value = value(id);

+    stmt.setString(column, value == null || value.length() == 0 ? "0" : value);

+  }

+

+  public CDOID getCDOID(ResultSet resultSet, int column) throws SQLException

+  {

+    String id = resultSet.getString(column);

+    if (resultSet.wasNull())

+    {

+      return null;

+    }

+

+    return create(id);

+  }

+

+  public CDOID getCDOID(ResultSet resultSet, String name) throws SQLException

+  {

+    String id = resultSet.getString(name);

+    if (resultSet.wasNull())

+    {

+      return null;

+    }

+

+    return create(id);

+  }

+

+  public CDOID getMinCDOID()

+  {

+    return MIN;

+  }

+

+  public CDOID getMaxCDOID()

+  {

+    return MAX;

+  }

+

+  public CDOID mapURI(IDBStoreAccessor accessor, String uri, long commitTime)

+  {

+    return create(uri);

+  }

+

+  public String unmapURI(IDBStoreAccessor accessor, CDOID id)

+  {

+    return value(id);

+  }

+

+  public void rawExport(Connection connection, CDODataOutput out, long fromCommitTime, long toCommitTime)

+      throws IOException

+  {

+    // Do nothing

+  }

+

+  public void rawImport(Connection connection, CDODataInput in, long fromCommitTime, long toCommitTime,

+      OMMonitor monitor) throws IOException

+  {

+    // Do nothing

+  }

+

+  private static CDOID create(String id)

+  {

+    if (id == null)

+    {

+      return null;

+    }

+

+    int length = id.length();

+    if (length == 0)

+    {

+      return null;

+    }

+

+    char firstChar = id.charAt(0);

+    if (length == 1 && firstChar == '0')

+    {

+      return null;

+    }

+

+    if (Character.isDigit(firstChar))

+    {

+      long value = Long.parseLong(id);

+      if (value < 0)

+      {

+        throw new IllegalArgumentException("Illegal ID value: " + id);

+      }

+

+      return CDOIDUtil.createString(id);

+    }

+

+    return CDOIDUtil.createExternal(id);

+  }

+

+  private static String value(CDOID id)

+  {

+    return CDOIDUtil.getString(id);

+  }

+}

diff --git a/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/UUIDHandler.java b/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/UUIDHandler.java
new file mode 100644
index 0000000..088cf83
--- /dev/null
+++ b/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/UUIDHandler.java
@@ -0,0 +1,237 @@
+/**

+ * Copyright (c) 2004 - 2011 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;

+

+import org.eclipse.emf.cdo.common.branch.CDOBranchPoint;

+import org.eclipse.emf.cdo.common.id.CDOID;

+import org.eclipse.emf.cdo.common.id.CDOID.ObjectType;

+import org.eclipse.emf.cdo.common.id.CDOIDUtil;

+import org.eclipse.emf.cdo.common.protocol.CDODataInput;

+import org.eclipse.emf.cdo.common.protocol.CDODataOutput;

+import org.eclipse.emf.cdo.common.revision.CDORevision;

+import org.eclipse.emf.cdo.server.db.IDBStoreAccessor;

+import org.eclipse.emf.cdo.server.db.IIDHandler;

+import org.eclipse.emf.cdo.server.db.mapping.ITypeMapping;

+import org.eclipse.emf.cdo.server.internal.db.mapping.CoreTypeMappings;

+

+import org.eclipse.net4j.db.DBType;

+import org.eclipse.net4j.util.lifecycle.Lifecycle;

+import org.eclipse.net4j.util.om.monitor.OMMonitor;

+

+import java.io.IOException;

+import java.sql.Connection;

+import java.sql.PreparedStatement;

+import java.sql.ResultSet;

+import java.sql.SQLException;

+import java.util.Collections;

+import java.util.Set;

+

+/**

+ * @author Eike Stepper

+ */

+public class UUIDHandler extends Lifecycle implements IIDHandler

+{

+  public static final Set<ObjectType> OBJECT_ID_TYPES = Collections.singleton(ObjectType.UUID);

+

+  private static final char NULL_CHAR = '0';

+

+  private static final String NULL_STRING = Character.toString(NULL_CHAR);

+

+  private static final char INTERNAL_CHAR = '@';

+

+  private static final String INTERNAL_STRING = Character.toString(INTERNAL_CHAR);

+

+  private DBStore store;

+

+  public UUIDHandler(DBStore store)

+  {

+    this.store = store;

+  }

+

+  public DBStore getStore()

+  {

+    return store;

+  }

+

+  public int compare(CDOID id1, CDOID id2)

+  {

+    throw new UnsupportedOperationException();

+  }

+

+  public DBType getDBType()

+  {

+    return DBType.VARCHAR;

+  }

+

+  public Set<ObjectType> getObjectIDTypes()

+  {

+    return OBJECT_ID_TYPES;

+  }

+

+  public CDOID createCDOID(String val)

+  {

+    return create(INTERNAL_STRING + val);

+  }

+

+  public synchronized CDOID getLastObjectID()

+  {

+    throw new UnsupportedOperationException();

+  }

+

+  public synchronized void setLastObjectID(CDOID lastObjectID)

+  {

+    // Do nothing

+  }

+

+  public void adjustLastObjectID(CDOID maxID)

+  {

+    // Do nothing

+  }

+

+  public synchronized CDOID getNextLocalObjectID()

+  {

+    throw new UnsupportedOperationException();

+  }

+

+  public synchronized void setNextLocalObjectID(CDOID nextLocalObjectID)

+  {

+    // Do nothing

+  }

+

+  public synchronized CDOID getNextCDOID(CDORevision revision)

+  {

+    throw new UnsupportedOperationException();

+  }

+

+  public boolean isLocalCDOID(CDOID id)

+  {

+    return false;

+  }

+

+  public ITypeMapping getObjectTypeMapping()

+  {

+    return new CoreTypeMappings.TMObject();

+  }

+

+  public void appendCDOID(StringBuilder builder, CDOID id)

+  {

+    builder.append("'");

+    builder.append(value(id));

+    builder.append("'");

+  }

+

+  public void setCDOID(PreparedStatement stmt, int column, CDOID id) throws SQLException

+  {

+    setCDOID(stmt, column, id, CDOBranchPoint.INVALID_DATE);

+  }

+

+  public void setCDOID(PreparedStatement stmt, int column, CDOID id, long commitTime) throws SQLException

+  {

+    stmt.setString(column, value(id));

+  }

+

+  public CDOID getCDOID(ResultSet resultSet, int column) throws SQLException

+  {

+    String id = resultSet.getString(column);

+    if (resultSet.wasNull())

+    {

+      return null;

+    }

+

+    return create(id);

+  }

+

+  public CDOID getCDOID(ResultSet resultSet, String name) throws SQLException

+  {

+    String id = resultSet.getString(name);

+    if (resultSet.wasNull())

+    {

+      return null;

+    }

+

+    return create(id);

+  }

+

+  public CDOID getMinCDOID()

+  {

+    throw new UnsupportedOperationException();

+  }

+

+  public CDOID getMaxCDOID()

+  {

+    throw new UnsupportedOperationException();

+  }

+

+  public CDOID mapURI(IDBStoreAccessor accessor, String uri, long commitTime)

+  {

+    return CDOIDUtil.createExternal(uri);

+  }

+

+  public String unmapURI(IDBStoreAccessor accessor, CDOID id)

+  {

+    return CDOIDUtil.getString(id);

+  }

+

+  public void rawExport(Connection connection, CDODataOutput out, long fromCommitTime, long toCommitTime)

+      throws IOException

+  {

+    // Do nothing

+  }

+

+  public void rawImport(Connection connection, CDODataInput in, long fromCommitTime, long toCommitTime,

+      OMMonitor monitor) throws IOException

+  {

+    // Do nothing

+  }

+

+  private static CDOID create(String id)

+  {

+    if (id == null)

+    {

+      return null;

+    }

+

+    int length = id.length();

+    if (length == 0)

+    {

+      return null;

+    }

+

+    char firstChar = id.charAt(0);

+    if (length == 1 && firstChar == NULL_CHAR)

+    {

+      return null;

+    }

+

+    if (firstChar == INTERNAL_CHAR)

+    {

+      byte[] bytes = CDOIDUtil.decodeUUID(id.substring(1));

+      return CDOIDUtil.createUUID(bytes);

+    }

+

+    return CDOIDUtil.createExternal(id);

+  }

+

+  private static String value(CDOID id)

+  {

+    if (CDOIDUtil.isNull(id))

+    {

+      return NULL_STRING;

+    }

+

+    if (id.isExternal())

+    {

+      return CDOIDUtil.getString(id);

+    }

+

+    return INTERNAL_STRING + id.toURIFragment();

+  }

+}

diff --git a/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/bundle/OM.java b/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/bundle/OM.java
new file mode 100644
index 0000000..d45d95c
--- /dev/null
+++ b/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/bundle/OM.java
@@ -0,0 +1,45 @@
+/**
+ * Copyright (c) 2004 - 2011 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 285426: [DB] Implement user-defined typeMapping support
+ */
+package org.eclipse.emf.cdo.server.internal.db.bundle;
+
+import org.eclipse.net4j.util.om.OMBundle;
+import org.eclipse.net4j.util.om.OMPlatform;
+import org.eclipse.net4j.util.om.OSGiActivator;
+import org.eclipse.net4j.util.om.log.OMLogger;
+import org.eclipse.net4j.util.om.trace.OMTracer;
+
+/**
+ * The <em>Operations & Maintenance</em> class of this bundle.
+ * 
+ * @author Eike Stepper
+ */
+public abstract class OM
+{
+  public static final String BUNDLE_ID = "org.eclipse.emf.cdo.server.db"; //$NON-NLS-1$
+
+  public static final OMBundle BUNDLE = OMPlatform.INSTANCE.bundle(BUNDLE_ID, OM.class);
+
+  public static final OMTracer DEBUG = BUNDLE.tracer("debug"); //$NON-NLS-1$
+
+  public static final OMLogger LOG = BUNDLE.logger();
+
+  /**
+   * @author Eike Stepper
+   */
+  public static final class Activator extends OSGiActivator
+  {
+    public Activator()
+    {
+      super(BUNDLE);
+    }
+  }
+}
diff --git a/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/jdbc/WrappedPreparedStatement.java b/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/jdbc/WrappedPreparedStatement.java
new file mode 100644
index 0000000..d4781d3
--- /dev/null
+++ b/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/jdbc/WrappedPreparedStatement.java
@@ -0,0 +1,81 @@
+/**
+ * Copyright (c) 2004 - 2011 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.jdbc;
+
+import org.eclipse.emf.cdo.server.internal.db.bundle.OM;
+
+import org.eclipse.net4j.db.DBUtil;
+import org.eclipse.net4j.util.om.trace.ContextTracer;
+
+import java.sql.PreparedStatement;
+import java.text.MessageFormat;
+
+/**
+ * Wrapper for a prepared statement that is cleaned up when it is cached in a WeakReferenceCache and gc'd. Note that
+ * this is just a wrapper with access to its wrapped object. There's no interface delegation, because the interface
+ * delegation would also put the necessity to wrap resultSets and maybe even more, which seems to much overkill for a
+ * simple internal implementation.
+ * 
+ * @author Stefan Winkler
+ */
+public class WrappedPreparedStatement
+{
+  private static final ContextTracer TRACER = new ContextTracer(OM.DEBUG, WrappedPreparedStatement.class);
+
+  private PreparedStatement wrappedStatement;
+
+  public WrappedPreparedStatement(PreparedStatement ps)
+  {
+    wrappedStatement = ps;
+    if (TRACER.isEnabled())
+    {
+      TRACER.format("Wrapping Statement: {0}", wrappedStatement); //$NON-NLS-1$
+    }
+  }
+
+  public PreparedStatement getWrappedStatement()
+  {
+    return wrappedStatement;
+  }
+
+  public PreparedStatement unwrapStatement()
+  {
+    if (TRACER.isEnabled())
+    {
+      TRACER.format("UnWrapping Statement: {0}", wrappedStatement); //$NON-NLS-1$
+    }
+
+    PreparedStatement result = wrappedStatement;
+    wrappedStatement = null;
+    return result;
+  }
+
+  @Override
+  public String toString()
+  {
+    return MessageFormat.format("Wrapped[{0}]", wrappedStatement); //$NON-NLS-1$
+  }
+
+  @Override
+  protected void finalize() throws Throwable
+  {
+    if (wrappedStatement != null)
+    {
+      if (TRACER.isEnabled())
+      {
+        TRACER.format("Closing statement: {0}", wrappedStatement); //$NON-NLS-1$
+      }
+
+      DBUtil.close(wrappedStatement);
+      wrappedStatement = null;
+    }
+  }
+}
diff --git a/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/AbstractMappingStrategy.java b/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/AbstractMappingStrategy.java
new file mode 100644
index 0000000..d9c76b3
--- /dev/null
+++ b/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/AbstractMappingStrategy.java
@@ -0,0 +1,641 @@
+/**
+ * Copyright (c) 2004 - 2011 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 - major refactoring
+ *    Stefan Winkler - Bug 271444: [DB] Multiple refactorings bug 271444
+ *    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;
+
+import org.eclipse.emf.cdo.common.branch.CDOBranch;
+import org.eclipse.emf.cdo.common.branch.CDOBranchPoint;
+import org.eclipse.emf.cdo.common.id.CDOID;
+import org.eclipse.emf.cdo.common.id.CDOIDUtil;
+import org.eclipse.emf.cdo.common.model.CDOModelUtil;
+import org.eclipse.emf.cdo.common.model.EMFUtil;
+import org.eclipse.emf.cdo.common.revision.CDORevisionHandler;
+import org.eclipse.emf.cdo.server.IStoreAccessor.CommitContext;
+import org.eclipse.emf.cdo.server.StoreThreadLocal;
+import org.eclipse.emf.cdo.server.db.IDBStore;
+import org.eclipse.emf.cdo.server.db.IDBStoreAccessor;
+import org.eclipse.emf.cdo.server.db.IMetaDataManager;
+import org.eclipse.emf.cdo.server.db.IPreparedStatementCache;
+import org.eclipse.emf.cdo.server.db.mapping.IClassMapping;
+import org.eclipse.emf.cdo.server.db.mapping.IListMapping;
+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.ObjectIDIterator;
+import org.eclipse.emf.cdo.spi.common.commit.CDOChangeSetSegment;
+import org.eclipse.emf.cdo.spi.common.model.InternalCDOPackageInfo;
+import org.eclipse.emf.cdo.spi.common.model.InternalCDOPackageRegistry;
+import org.eclipse.emf.cdo.spi.common.model.InternalCDOPackageUnit;
+import org.eclipse.emf.cdo.spi.server.InternalRepository;
+
+import org.eclipse.net4j.db.DBException;
+import org.eclipse.net4j.db.DBUtil;
+import org.eclipse.net4j.db.ddl.IDBSchema;
+import org.eclipse.net4j.db.ddl.IDBTable;
+import org.eclipse.net4j.util.ImplementationError;
+import org.eclipse.net4j.util.StringUtil;
+import org.eclipse.net4j.util.collection.CloseableIterator;
+import org.eclipse.net4j.util.lifecycle.Lifecycle;
+import org.eclipse.net4j.util.om.monitor.OMMonitor;
+import org.eclipse.net4j.util.om.monitor.OMMonitor.Async;
+
+import org.eclipse.emf.ecore.EClass;
+import org.eclipse.emf.ecore.EClassifier;
+import org.eclipse.emf.ecore.ENamedElement;
+import org.eclipse.emf.ecore.EPackage;
+import org.eclipse.emf.ecore.EStructuralFeature;
+import org.eclipse.emf.ecore.util.FeatureMapUtil;
+
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
+/**
+ * This abstract base class implements those methods which are most likely common to most mapping strategies. It can be
+ * used to derive custom mapping strategy implementation.
+ * 
+ * @author Eike Stepper
+ * @since 2.0
+ */
+public abstract class AbstractMappingStrategy extends Lifecycle implements IMappingStrategy
+{
+  // --------- database name generation strings --------------
+  protected static final String NAME_SEPARATOR = "_"; //$NON-NLS-1$
+
+  protected static final String TYPE_PREFIX_FEATURE = "F"; //$NON-NLS-1$
+
+  protected static final String TYPE_PREFIX_CLASS = "C"; //$NON-NLS-1$
+
+  protected static final String TYPE_PREFIX_PACKAGE = "P"; //$NON-NLS-1$
+
+  protected static final String GENERAL_PREFIX = "X"; //$NON-NLS-1$
+
+  protected static final String GENERAL_SUFFIX = "0"; //$NON-NLS-1$
+
+  /**
+   * Prefix for unsettable feature helper columns
+   */
+  protected static final String CDO_SET_PREFIX = "cdo_set_"; //$NON-NLS-1$
+
+  protected static final String FEATURE_TABLE_SUFFIX = "_list"; //$NON-NLS-1$
+
+  private IDBStore store;
+
+  private Map<String, String> properties;
+
+  private ConcurrentMap<EClass, IClassMapping> classMappings;
+
+  private boolean allClassMappingsCreated;
+
+  public AbstractMappingStrategy()
+  {
+    classMappings = new ConcurrentHashMap<EClass, IClassMapping>();
+  }
+
+  // -- property related methods -----------------------------------------
+
+  public synchronized Map<String, String> getProperties()
+  {
+    if (properties == null)
+    {
+      properties = new HashMap<String, String>();
+    }
+
+    return properties;
+  }
+
+  public synchronized void setProperties(Map<String, String> properties)
+  {
+    this.properties = properties;
+  }
+
+  private int getMaxTableNameLength()
+  {
+    String value = getProperties().get(PROP_MAX_TABLE_NAME_LENGTH);
+    return value == null ? store.getDBAdapter().getMaxTableNameLength() : Integer.valueOf(value);
+  }
+
+  private int getMaxFieldNameLength()
+  {
+    String value = getProperties().get(PROP_MAX_FIELD_NAME_LENGTH);
+    return value == null ? store.getDBAdapter().getMaxFieldNameLength() : Integer.valueOf(value);
+  }
+
+  private boolean isQualifiedNames()
+  {
+    String value = getProperties().get(PROP_QUALIFIED_NAMES);
+    return value == null ? false : Boolean.valueOf(value);
+  }
+
+  private boolean isForceNamesWithID()
+  {
+    String value = getProperties().get(PROP_FORCE_NAMES_WITH_ID);
+    return value == null ? false : Boolean.valueOf(value);
+  }
+
+  private String getTableNamePrefix()
+  {
+    String value = getProperties().get(PROP_TABLE_NAME_PREFIX);
+    return StringUtil.safe(value);
+  }
+
+  // -- getters and setters ----------------------------------------------
+
+  public final IDBStore getStore()
+  {
+    return store;
+  }
+
+  public final void setStore(IDBStore dbStore)
+  {
+    checkInactive();
+    store = dbStore;
+  }
+
+  protected final IMetaDataManager getMetaDataManager()
+  {
+    return getStore().getMetaDataManager();
+  }
+
+  // -- object id related methods ----------------------------------------
+
+  public void handleRevisions(IDBStoreAccessor accessor, EClass eClass, CDOBranch branch, long timeStamp,
+      boolean exactTime, CDORevisionHandler handler)
+  {
+    if (eClass == null)
+    {
+      Collection<IClassMapping> values = getClassMappings().values();
+      for (IClassMapping mapping : values)
+      {
+        mapping.handleRevisions(accessor, branch, timeStamp, exactTime, handler);
+      }
+    }
+    else
+    {
+      IClassMapping classMapping = getClassMapping(eClass);
+      classMapping.handleRevisions(accessor, branch, timeStamp, exactTime, handler);
+    }
+  }
+
+  public Set<CDOID> readChangeSet(IDBStoreAccessor accessor, OMMonitor monitor, CDOChangeSetSegment[] segments)
+  {
+    Set<CDOID> result = new HashSet<CDOID>();
+    Collection<IClassMapping> classMappings = getClassMappings().values();
+
+    monitor.begin(classMappings.size());
+
+    try
+    {
+      for (IClassMapping mapping : classMappings)
+      {
+        Async async = monitor.forkAsync();
+
+        try
+        {
+          Set<CDOID> ids = mapping.readChangeSet(accessor, segments);
+          result.addAll(ids);
+        }
+        finally
+        {
+          async.stop();
+        }
+      }
+
+      return result;
+    }
+    finally
+    {
+      monitor.done();
+    }
+  }
+
+  public CloseableIterator<CDOID> readObjectIDs(IDBStoreAccessor accessor)
+  {
+    Collection<EClass> classes = getClassesWithObjectInfo();
+    final Iterator<EClass> classIt = classes.iterator();
+
+    return new ObjectIDIterator(this, accessor)
+    {
+      private PreparedStatement currentStatement;
+
+      @Override
+      protected ResultSet getNextResultSet()
+      {
+        while (classIt.hasNext())
+        {
+          EClass eClass = classIt.next();
+          IClassMapping mapping = getClassMapping(eClass);
+          currentStatement = mapping.createObjectIDStatement(getAccessor());
+
+          ResultSet resultSet = null;
+
+          try
+          {
+            resultSet = currentStatement.executeQuery();
+            return resultSet;
+          }
+          catch (Exception ex)
+          {
+            DBUtil.close(resultSet); // only on error
+            releaseCurrentStatement();
+            throw new DBException(ex);
+          }
+        }
+
+        return null;
+      }
+
+      @Override
+      protected void closeCurrentResultSet()
+      {
+        super.closeCurrentResultSet();
+        releaseCurrentStatement();
+      }
+
+      private void releaseCurrentStatement()
+      {
+        IPreparedStatementCache statementCache = getAccessor().getStatementCache();
+        statementCache.releasePreparedStatement(currentStatement);
+        currentStatement = null;
+      }
+    };
+  }
+
+  protected abstract Collection<EClass> getClassesWithObjectInfo();
+
+  // -- database name demangling methods ---------------------------------
+
+  public String getTableName(ENamedElement element)
+  {
+    String name = null;
+    String typePrefix = null;
+
+    if (element instanceof EClass)
+    {
+      typePrefix = TYPE_PREFIX_CLASS;
+      name = DBAnnotation.TABLE_NAME.getValue(element);
+      if (name == null)
+      {
+        name = isQualifiedNames() ? EMFUtil.getQualifiedName((EClass)element, NAME_SEPARATOR) : element.getName();
+      }
+    }
+    else if (element instanceof EPackage)
+    {
+      typePrefix = TYPE_PREFIX_PACKAGE;
+      name = DBAnnotation.TABLE_NAME.getValue(element);
+      if (name == null)
+      {
+        name = isQualifiedNames() ? EMFUtil.getQualifiedName((EPackage)element, NAME_SEPARATOR) : element.getName();
+      }
+    }
+    else
+    {
+      throw new ImplementationError("Unknown element: " + element); //$NON-NLS-1$
+    }
+
+    String prefix = getTableNamePrefix();
+    if (prefix.length() != 0 && !prefix.endsWith(NAME_SEPARATOR))
+    {
+      prefix += NAME_SEPARATOR;
+    }
+
+    return getName(prefix + name, typePrefix + getUniqueID(element), getMaxTableNameLength());
+  }
+
+  public String getTableName(EClass eClass, EStructuralFeature feature)
+  {
+    String name = DBAnnotation.TABLE_NAME.getValue(eClass);
+    if (name == null)
+    {
+      name = isQualifiedNames() ? EMFUtil.getQualifiedName(eClass, NAME_SEPARATOR) : eClass.getName();
+    }
+
+    name += NAME_SEPARATOR;
+    name += feature.getName();
+    name += FEATURE_TABLE_SUFFIX;
+
+    String prefix = getTableNamePrefix();
+    if (prefix.length() != 0 && !prefix.endsWith(NAME_SEPARATOR))
+    {
+      prefix += NAME_SEPARATOR;
+    }
+
+    return getName(prefix + name, TYPE_PREFIX_FEATURE + getUniqueID(feature), getMaxTableNameLength());
+  }
+
+  public String getFieldName(EStructuralFeature feature)
+  {
+    String name = DBAnnotation.COLUMN_NAME.getValue(feature);
+    if (name == null)
+    {
+      name = getName(feature.getName(), TYPE_PREFIX_FEATURE + getUniqueID(feature), getMaxFieldNameLength());
+    }
+
+    return name;
+  }
+
+  public String getUnsettableFieldName(EStructuralFeature feature)
+  {
+    String name = DBAnnotation.COLUMN_NAME.getValue(feature);
+    if (name != null)
+    {
+      return CDO_SET_PREFIX + name;
+    }
+
+    return getName(CDO_SET_PREFIX + feature.getName(), TYPE_PREFIX_FEATURE + getUniqueID(feature),
+        getMaxFieldNameLength());
+  }
+
+  private String getName(String name, String suffix, int maxLength)
+  {
+    if (!store.getDBAdapter().isValidFirstChar(name.charAt(0)))
+    {
+      name = GENERAL_PREFIX + name;
+    }
+
+    boolean forceNamesWithID = isForceNamesWithID();
+    if (!forceNamesWithID && store.getDBAdapter().isReservedWord(name))
+    {
+      name = name + GENERAL_SUFFIX;
+    }
+
+    if (name.length() > maxLength || forceNamesWithID)
+    {
+      suffix = NAME_SEPARATOR + suffix.replace('-', 'S');
+      int length = Math.min(name.length(), maxLength - suffix.length());
+      name = name.substring(0, length) + suffix;
+    }
+
+    return name;
+  }
+
+  private String getUniqueID(ENamedElement element)
+  {
+    long timeStamp;
+    CommitContext commitContext = StoreThreadLocal.getCommitContext();
+    if (commitContext != null)
+    {
+      timeStamp = commitContext.getBranchPoint().getTimeStamp();
+    }
+    else
+    {
+      // This happens outside a commit, i.e. at system init time.
+      // Ensure that resulting ext refs are not replicated!
+      timeStamp = CDOBranchPoint.INVALID_DATE;
+
+      // timeStamp = getStore().getRepository().getTimeStamp();
+    }
+
+    CDOID result = getMetaDataManager().getMetaID(element, timeStamp);
+
+    StringBuilder builder = new StringBuilder();
+    CDOIDUtil.write(builder, result);
+    return builder.toString();
+  }
+
+  // -- factories for mapping of classes, values, lists ------------------
+
+  public void createMapping(Connection connection, InternalCDOPackageUnit[] packageUnits, OMMonitor monitor)
+  {
+    Async async = null;
+    monitor.begin();
+
+    try
+    {
+      async = monitor.forkAsync();
+
+      try
+      {
+        mapPackageUnits(packageUnits, connection, false);
+      }
+      finally
+      {
+        if (async != null)
+        {
+          async.stop();
+        }
+      }
+    }
+    finally
+    {
+      monitor.done();
+    }
+  }
+
+  public void removeMapping(Connection connection, InternalCDOPackageUnit[] packageUnits)
+  {
+    mapPackageUnits(packageUnits, connection, true);
+  }
+
+  private void mapPackageUnits(InternalCDOPackageUnit[] packageUnits, Connection connection, boolean unmap)
+  {
+    if (packageUnits != null && packageUnits.length != 0)
+    {
+      for (InternalCDOPackageUnit packageUnit : packageUnits)
+      {
+        mapPackageInfos(packageUnit.getPackageInfos(), connection, unmap);
+      }
+    }
+  }
+
+  private void mapPackageInfos(InternalCDOPackageInfo[] packageInfos, Connection connection, boolean unmap)
+  {
+    boolean supportingEcore = getStore().getRepository().isSupportingEcore();
+    for (InternalCDOPackageInfo packageInfo : packageInfos)
+    {
+      EPackage ePackage = packageInfo.getEPackage();
+      if (!CDOModelUtil.isCorePackage(ePackage) || supportingEcore)
+      {
+        mapClasses(connection, unmap, EMFUtil.getPersistentClasses(ePackage));
+      }
+    }
+  }
+
+  private void mapClasses(Connection connection, boolean unmap, EClass... eClasses)
+  {
+    for (EClass eClass : eClasses)
+    {
+      if (!(eClass.isInterface() || eClass.isAbstract()))
+      {
+        String mappingAnnotation = DBAnnotation.TABLE_MAPPING.getValue(eClass);
+
+        // TODO Maybe we should explicitly report unknown values of the annotation
+        if (mappingAnnotation != null && mappingAnnotation.equalsIgnoreCase(DBAnnotation.TABLE_MAPPING_NONE))
+        {
+          continue;
+        }
+
+        if (!unmap)
+        {
+          // TODO Bugzilla 296087: Before we go ahead with creation, we should check if it's already there
+          IClassMapping mapping = createClassMapping(eClass);
+          getStore().getDBAdapter().createTables(mapping.getDBTables(), connection);
+        }
+        else
+        {
+          IClassMapping mapping = removeClassMapping(eClass);
+          getStore().getDBAdapter().dropTables(mapping.getDBTables(), connection);
+        }
+      }
+    }
+  }
+
+  private IClassMapping createClassMapping(EClass eClass)
+  {
+    IClassMapping mapping = doCreateClassMapping(eClass);
+    if (mapping != null)
+    {
+      classMappings.put(eClass, mapping);
+    }
+
+    return mapping;
+  }
+
+  private IClassMapping removeClassMapping(EClass eClass)
+  {
+    IClassMapping mapping = classMappings.get(eClass);
+    if (mapping != null)
+    {
+      IDBSchema schema = getStore().getDBSchema();
+      for (IDBTable table : mapping.getDBTables())
+      {
+        schema.removeTable(table.getName());
+      }
+      classMappings.remove(eClass);
+    }
+    return mapping;
+  }
+
+  protected abstract IClassMapping doCreateClassMapping(EClass eClass);
+
+  public final IClassMapping getClassMapping(EClass eClass)
+  {
+    if (!isMapped(eClass))
+    {
+      throw new IllegalArgumentException("Class is not mapped: " + eClass);
+    }
+
+    // Try without synchronization first; this will almost always succeed, so it avoids the
+    // performance penalty of syncing in the majority of cases
+    IClassMapping result = classMappings.get(eClass);
+    if (result == null)
+    {
+      // Synchronize on the classMappings to prevent concurrent invocations of createClassMapping
+      // (Synchronizing on the eClass allows for more concurrency, but is risky because application
+      // code may be syncing on the eClass also.)
+      synchronized (classMappings)
+      {
+        // Check again, because other thread may have just added the mapping
+        result = classMappings.get(eClass);
+        if (result == null)
+        {
+          result = createClassMapping(eClass);
+        }
+      }
+    }
+
+    return result;
+  }
+
+  public final Map<EClass, IClassMapping> getClassMappings()
+  {
+    return getClassMappings(true);
+  }
+
+  public final Map<EClass, IClassMapping> getClassMappings(boolean createOnDemand)
+  {
+    return doGetClassMappings(createOnDemand);
+  }
+
+  public final Map<EClass, IClassMapping> doGetClassMappings(boolean createOnDemand)
+  {
+    if (createOnDemand)
+    {
+      synchronized (classMappings)
+      {
+        if (!allClassMappingsCreated)
+        {
+          createAllClassMappings();
+          allClassMappingsCreated = true;
+        }
+      }
+    }
+
+    return classMappings;
+  }
+
+  private void createAllClassMappings()
+  {
+    InternalRepository repository = (InternalRepository)getStore().getRepository();
+    InternalCDOPackageRegistry packageRegistry = repository.getPackageRegistry(false);
+    for (InternalCDOPackageInfo packageInfo : packageRegistry.getPackageInfos())
+    {
+      if (!packageInfo.isSystemPackage())
+      {
+        for (EClassifier eClassifier : packageInfo.getEPackage().getEClassifiers())
+        {
+          if (eClassifier instanceof EClass)
+          {
+            EClass eClass = (EClass)eClassifier;
+            if (isMapped(eClass))
+            {
+              getClassMapping(eClass); // Get or create it
+            }
+          }
+        }
+      }
+    }
+  }
+
+  protected abstract boolean isMapped(EClass eClass);
+
+  public ITypeMapping createValueMapping(EStructuralFeature 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)
+  {
+    checkArg(feature.isMany(), "Only many-valued features allowed"); //$NON-NLS-1$
+    IListMapping mapping = doCreateListMapping(containingClass, feature);
+    return mapping;
+  }
+
+  public final IListMapping createFeatureMapMapping(EClass containingClass, EStructuralFeature feature)
+  {
+    checkArg(FeatureMapUtil.isFeatureMap(feature), "Only FeatureMaps allowed"); //$NON-NLS-1$
+    IListMapping mapping = doCreateFeatureMapMapping(containingClass, feature);
+    return mapping;
+  }
+
+  public abstract IListMapping doCreateListMapping(EClass containingClass, EStructuralFeature feature);
+
+  public abstract IListMapping doCreateFeatureMapMapping(EClass containingClass, EStructuralFeature feature);
+}
diff --git a/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/CoreTypeMappings.java b/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/CoreTypeMappings.java
new file mode 100644
index 0000000..f5baf6a
--- /dev/null
+++ b/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/CoreTypeMappings.java
@@ -0,0 +1,882 @@
+/**
+ * Copyright (c) 2004 - 2011 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.lob.CDOBlob;
+import org.eclipse.emf.cdo.common.lob.CDOClob;
+import org.eclipse.emf.cdo.common.lob.CDOLobUtil;
+import org.eclipse.emf.cdo.common.revision.CDORevisionData;
+import org.eclipse.emf.cdo.etypes.EtypesPackage;
+import org.eclipse.emf.cdo.server.db.IIDHandler;
+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.HexUtil;
+import org.eclipse.net4j.util.factory.ProductCreationException;
+
+import org.eclipse.emf.common.util.Enumerator;
+import org.eclipse.emf.ecore.EDataType;
+import org.eclipse.emf.ecore.EEnum;
+import org.eclipse.emf.ecore.EEnumLiteral;
+import org.eclipse.emf.ecore.EFactory;
+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 Factory FACTORY = new Factory(TypeMappingUtil.createDescriptor(ID_PREFIX + ".Enum",
+        EcorePackage.eINSTANCE.getEEnum(), DBType.INTEGER));
+
+    @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 Factory extends AbstractTypeMappingFactory
+    {
+      public Factory(Descriptor descriptor)
+      {
+        super(descriptor);
+      }
+
+      @Override
+      public ITypeMapping create(String description) throws ProductCreationException
+      {
+        return new TMEnum();
+      }
+    }
+  }
+
+  /**
+   * @author Eike Stepper
+   */
+  public static class TMString extends AbstractTypeMapping
+  {
+    public static final Factory FACTORY_VARCHAR = new Factory(TypeMappingUtil.createDescriptor(ID_PREFIX
+        + ".StringVarchar", EcorePackage.eINSTANCE.getEString(), DBType.VARCHAR));
+
+    public static final Factory FACTORY_LONG_VARCHAR = new Factory(TypeMappingUtil.createDescriptor(ID_PREFIX
+        + ".StringLongVarchar", EcorePackage.eINSTANCE.getEString(), DBType.LONGVARCHAR));
+
+    public static final Factory FACTORY_CLOB = new Factory(TypeMappingUtil.createDescriptor(ID_PREFIX + ".StringClob",
+        EcorePackage.eINSTANCE.getEString(), DBType.CLOB));
+
+    @Override
+    public Object getResultSetValue(ResultSet resultSet) throws SQLException
+    {
+      return resultSet.getString(getField().getName());
+    }
+
+    /**
+     * @author Eike Stepper
+     */
+    public static class Factory extends AbstractTypeMappingFactory
+    {
+      public Factory(Descriptor descriptor)
+      {
+        super(descriptor);
+      }
+
+      @Override
+      public ITypeMapping create(String description) throws ProductCreationException
+      {
+        return new TMString();
+      }
+    }
+  }
+
+  /**
+   * @author Eike Stepper
+   */
+  public static class TMBlob extends AbstractTypeMapping
+  {
+    public static final Factory FACTORY_VARCHAR = new Factory(TypeMappingUtil.createDescriptor(ID_PREFIX
+        + ".BlobStream", EtypesPackage.eINSTANCE.getBlob(), DBType.VARCHAR));
+
+    public static final Factory FACTORY_LONG_VARCHAR = new Factory(TypeMappingUtil.createDescriptor(ID_PREFIX
+        + ".BlobStreamLongVarchar", EtypesPackage.eINSTANCE.getBlob(), DBType.LONGVARCHAR));
+
+    @Override
+    protected void doSetValue(PreparedStatement stmt, int index, Object value) throws SQLException
+    {
+      CDOBlob blob = (CDOBlob)value;
+      stmt.setString(index, HexUtil.bytesToHex(blob.getID()) + "-" + blob.getSize());
+    }
+
+    @Override
+    public Object getResultSetValue(ResultSet resultSet) throws SQLException
+    {
+      String str = resultSet.getString(getField().getName());
+      if (str == null)
+      {
+        return null;
+      }
+      
+      int pos = str.indexOf('-');
+
+      byte[] id = HexUtil.hexToBytes(str.substring(0, pos));
+      long size = Long.parseLong(str.substring(pos + 1));
+      return CDOLobUtil.createBlob(id, size);
+    }
+
+    /**
+     * @author Eike Stepper
+     */
+    public static class Factory extends AbstractTypeMappingFactory
+    {
+      public Factory(Descriptor descriptor)
+      {
+        super(descriptor);
+      }
+
+      @Override
+      public ITypeMapping create(String description) throws ProductCreationException
+      {
+        return new TMBlob();
+      }
+    }
+  }
+
+  /**
+   * @author Eike Stepper
+   */
+  public static class TMClob extends AbstractTypeMapping
+  {
+    public static final Factory FACTORY_VARCHAR = new Factory(TypeMappingUtil.createDescriptor(ID_PREFIX
+        + ".ClobStream", EtypesPackage.eINSTANCE.getClob(), DBType.VARCHAR));
+
+    public static final Factory FACTORY_LONG_VARCHAR = new Factory(TypeMappingUtil.createDescriptor(ID_PREFIX
+        + ".ClobStreamLongVarchar", EtypesPackage.eINSTANCE.getClob(), DBType.LONGVARCHAR));
+
+    @Override
+    protected void doSetValue(PreparedStatement stmt, int index, Object value) throws SQLException
+    {
+      CDOClob clob = (CDOClob)value;
+      stmt.setString(index, HexUtil.bytesToHex(clob.getID()) + "-" + clob.getSize());
+    }
+
+    @Override
+    public Object getResultSetValue(ResultSet resultSet) throws SQLException
+    {
+      String str = resultSet.getString(getField().getName());
+      if (str == null)
+      {
+        return null;
+      }
+      
+      int pos = str.indexOf('-');
+
+      byte[] id = HexUtil.hexToBytes(str.substring(0, pos));
+      long size = Long.parseLong(str.substring(pos + 1));
+      return CDOLobUtil.createClob(id, size);
+    }
+
+    /**
+     * @author Eike Stepper
+     */
+    public static class Factory extends AbstractTypeMappingFactory
+    {
+      public Factory(Descriptor descriptor)
+      {
+        super(descriptor);
+      }
+
+      @Override
+      public ITypeMapping create(String description) throws ProductCreationException
+      {
+        return new TMClob();
+      }
+    }
+  }
+
+  /**
+   * @author Eike Stepper
+   */
+  public static class TMShort extends AbstractTypeMapping
+  {
+    public static final Factory FACTORY = new Factory(TypeMappingUtil.createDescriptor(ID_PREFIX + ".Short",
+        EcorePackage.eINSTANCE.getEShort(), DBType.SMALLINT));
+
+    public static final Factory FACTORY_OBJECT = new Factory(TypeMappingUtil.createDescriptor(ID_PREFIX
+        + ".ShortObject", EcorePackage.eINSTANCE.getEShortObject(), DBType.SMALLINT));
+
+    @Override
+    public Object getResultSetValue(ResultSet resultSet) throws SQLException
+    {
+      return resultSet.getShort(getField().getName());
+    }
+
+    /**
+     * @author Eike Stepper
+     */
+    public static class Factory extends AbstractTypeMappingFactory
+    {
+      public Factory(Descriptor descriptor)
+      {
+        super(descriptor);
+      }
+
+      @Override
+      public ITypeMapping create(String description) throws ProductCreationException
+      {
+        return new TMShort();
+      }
+    }
+  }
+
+  /**
+   * @author Eike Stepper <br>
+   */
+  public static class TMObject extends AbstractTypeMapping
+  {
+    @Override
+    public Object getResultSetValue(ResultSet resultSet) throws SQLException
+    {
+      IIDHandler idHandler = getMappingStrategy().getStore().getIDHandler();
+      CDOID id = idHandler.getCDOID(resultSet, getField().getName());
+
+      if (id == null && getFeature().isUnsettable())
+      {
+        return CDORevisionData.NIL;
+      }
+
+      return id;
+    }
+
+    @Override
+    protected void doSetValue(PreparedStatement stmt, int index, Object value) throws SQLException
+    {
+      IIDHandler idHandler = getMappingStrategy().getStore().getIDHandler();
+      idHandler.setCDOID(stmt, index, (CDOID)value);
+    }
+
+    /**
+     * @author Eike Stepper
+     */
+    public static class Factory extends AbstractTypeMappingFactory
+    {
+      public Factory(Descriptor descriptor)
+      {
+        super(descriptor);
+      }
+
+      @Override
+      public ITypeMapping create(String description) throws ProductCreationException
+      {
+        return new TMObject();
+      }
+    }
+  }
+
+  /**
+   * @author Eike Stepper
+   */
+  public static class TMLong extends AbstractTypeMapping
+  {
+    public static final Factory FACTORY = new Factory(TypeMappingUtil.createDescriptor(ID_PREFIX + ".Long",
+        EcorePackage.eINSTANCE.getELong(), DBType.BIGINT));
+
+    public static final Factory FACTORY_OBJECT = new Factory(TypeMappingUtil.createDescriptor(
+        ID_PREFIX + ".LongObject", EcorePackage.eINSTANCE.getELongObject(), DBType.BIGINT));
+
+    @Override
+    public Object getResultSetValue(ResultSet resultSet) throws SQLException
+    {
+      return resultSet.getLong(getField().getName());
+    }
+
+    /**
+     * @author Eike Stepper
+     */
+    public static class Factory extends AbstractTypeMappingFactory
+    {
+      public Factory(Descriptor descriptor)
+      {
+        super(descriptor);
+      }
+
+      @Override
+      public ITypeMapping create(String description) throws ProductCreationException
+      {
+        return new TMLong();
+      }
+    }
+  }
+
+  /**
+   * @author Eike Stepper
+   */
+  public static class TMInteger extends AbstractTypeMapping
+  {
+    public static final Factory FACTORY = new Factory(TypeMappingUtil.createDescriptor(ID_PREFIX + ".Integer",
+        EcorePackage.eINSTANCE.getEInt(), DBType.INTEGER));
+
+    public static final Factory FACTORY_OBJECT = new Factory(TypeMappingUtil.createDescriptor(ID_PREFIX
+        + ".IntegerObject", EcorePackage.eINSTANCE.getEIntegerObject(), DBType.INTEGER));
+
+    @Override
+    public Object getResultSetValue(ResultSet resultSet) throws SQLException
+    {
+      return resultSet.getInt(getField().getName());
+    }
+
+    /**
+     * @author Eike Stepper
+     */
+    public static class Factory extends AbstractTypeMappingFactory
+    {
+      public Factory(Descriptor descriptor)
+      {
+        super(descriptor);
+      }
+
+      @Override
+      public ITypeMapping create(String description) throws ProductCreationException
+      {
+        return new TMInteger();
+      }
+    }
+  }
+
+  /**
+   * @author Eike Stepper
+   */
+  public static class TMFloat extends AbstractTypeMapping
+  {
+    public static final Factory FACTORY = new Factory(TypeMappingUtil.createDescriptor(ID_PREFIX + ".Float",
+        EcorePackage.eINSTANCE.getEFloat(), DBType.FLOAT));
+
+    public static final Factory FACTORY_OBJECT = new Factory(TypeMappingUtil.createDescriptor(ID_PREFIX
+        + ".FloatObject", EcorePackage.eINSTANCE.getEFloatObject(), DBType.FLOAT));
+
+    @Override
+    public Object getResultSetValue(ResultSet resultSet) throws SQLException
+    {
+      return resultSet.getFloat(getField().getName());
+    }
+
+    /**
+     * @author Eike Stepper
+     */
+    public static class Factory extends AbstractTypeMappingFactory
+    {
+      public Factory(Descriptor descriptor)
+      {
+        super(descriptor);
+      }
+
+      @Override
+      public ITypeMapping create(String description) throws ProductCreationException
+      {
+        return new TMFloat();
+      }
+    }
+  }
+
+  /**
+   * @author Eike Stepper
+   */
+  public static class TMDouble extends AbstractTypeMapping
+  {
+    public static final Factory FACTORY = new Factory(TypeMappingUtil.createDescriptor(ID_PREFIX + ".Double",
+        EcorePackage.eINSTANCE.getEDouble(), DBType.DOUBLE));
+
+    public static final Factory FACTORY_OBJECT = new Factory(TypeMappingUtil.createDescriptor(ID_PREFIX
+        + ".DoubleObject", EcorePackage.eINSTANCE.getEDoubleObject(), DBType.DOUBLE));
+
+    @Override
+    public Object getResultSetValue(ResultSet resultSet) throws SQLException
+    {
+      return resultSet.getDouble(getField().getName());
+    }
+
+    /**
+     * @author Eike Stepper
+     */
+    public static class Factory extends AbstractTypeMappingFactory
+    {
+      public Factory(Descriptor descriptor)
+      {
+        super(descriptor);
+      }
+
+      @Override
+      public ITypeMapping create(String description) throws ProductCreationException
+      {
+        return new TMDouble();
+      }
+    }
+  }
+
+  /**
+   * @author Eike Stepper
+   */
+  public static class TMDate2Timestamp extends AbstractTypeMapping
+  {
+    public static final Factory FACTORY = new Factory(TypeMappingUtil.createDescriptor(ID_PREFIX + ".Timestamp",
+        EcorePackage.eINSTANCE.getEDate(), DBType.TIMESTAMP));
+
+    @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 Eike Stepper
+     */
+    public static class Factory extends AbstractTypeMappingFactory
+    {
+      public Factory(Descriptor descriptor)
+      {
+        super(descriptor);
+      }
+
+      @Override
+      public ITypeMapping create(String description) throws ProductCreationException
+      {
+        return new TMDate2Timestamp();
+      }
+    }
+  }
+
+  /**
+   * @author Heiko Ahlig
+   */
+  public static class TMDate2Date extends AbstractTypeMapping
+  {
+    public static final Factory FACTORY = new Factory(TypeMappingUtil.createDescriptor(ID_PREFIX + ".Date",
+        EcorePackage.eINSTANCE.getEDate(), DBType.DATE));
+
+    @Override
+    public Object getResultSetValue(ResultSet resultSet) throws SQLException
+    {
+      return resultSet.getDate(getField().getName(), Calendar.getInstance());
+    }
+
+    /**
+     * @author Eike Stepper
+     */
+    public static class Factory extends AbstractTypeMappingFactory
+    {
+      public Factory(Descriptor descriptor)
+      {
+        super(descriptor);
+      }
+
+      @Override
+      public ITypeMapping create(String description) throws ProductCreationException
+      {
+        return new TMDate2Date();
+      }
+    }
+  }
+
+  /**
+   * @author Heiko Ahlig
+   */
+  public static class TMDate2Time extends AbstractTypeMapping
+  {
+    public static final Factory FACTORY = new Factory(TypeMappingUtil.createDescriptor(ID_PREFIX + ".Time",
+        EcorePackage.eINSTANCE.getEDate(), DBType.TIME));
+
+    @Override
+    public Object getResultSetValue(ResultSet resultSet) throws SQLException
+    {
+      return resultSet.getTime(getField().getName(), Calendar.getInstance());
+    }
+
+    /**
+     * @author Eike Stepper
+     */
+    public static class Factory extends AbstractTypeMappingFactory
+    {
+      public Factory(Descriptor descriptor)
+      {
+        super(descriptor);
+      }
+
+      @Override
+      public ITypeMapping create(String description) throws ProductCreationException
+      {
+        return new TMDate2Time();
+      }
+    }
+  }
+
+  /**
+   * @author Eike Stepper
+   */
+  public static class TMCharacter extends AbstractTypeMapping
+  {
+    public static final Factory FACTORY = new Factory(TypeMappingUtil.createDescriptor(ID_PREFIX + ".Character",
+        EcorePackage.eINSTANCE.getEChar(), DBType.CHAR));
+
+    public static final Factory FACTORY_OBJECT = new Factory(TypeMappingUtil.createDescriptor(ID_PREFIX
+        + ".CharacterObject", EcorePackage.eINSTANCE.getECharacterObject(), DBType.CHAR));
+
+    @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 Factory extends AbstractTypeMappingFactory
+    {
+      public Factory(Descriptor descriptor)
+      {
+        super(descriptor);
+      }
+
+      @Override
+      public ITypeMapping create(String description) throws ProductCreationException
+      {
+        return new TMCharacter();
+      }
+    }
+  }
+
+  /**
+   * @author Eike Stepper
+   */
+  public static class TMByte extends AbstractTypeMapping
+  {
+    public static final Factory FACTORY = new Factory(TypeMappingUtil.createDescriptor(ID_PREFIX + ".Byte",
+        EcorePackage.eINSTANCE.getEByte(), DBType.SMALLINT));
+
+    public static final Factory FACTORY_OBJECT = new Factory(TypeMappingUtil.createDescriptor(
+        ID_PREFIX + ".ByteObject", EcorePackage.eINSTANCE.getEByteObject(), DBType.SMALLINT));
+
+    @Override
+    public Object getResultSetValue(ResultSet resultSet) throws SQLException
+    {
+      return resultSet.getByte(getField().getName());
+    }
+
+    /**
+     * @author Eike Stepper
+     */
+    public static class Factory extends AbstractTypeMappingFactory
+    {
+      public Factory(Descriptor descriptor)
+      {
+        super(descriptor);
+      }
+
+      @Override
+      public ITypeMapping create(String description) throws ProductCreationException
+      {
+        return new TMByte();
+      }
+    }
+  }
+
+  /**
+   * @author Eike Stepper
+   */
+  public static class TMBytes extends AbstractTypeMapping
+  {
+    public static final Factory FACTORY = new Factory(TypeMappingUtil.createDescriptor(ID_PREFIX + ".ByteArray",
+        EcorePackage.eINSTANCE.getEByteArray(), DBType.BLOB));
+
+    @Override
+    public Object getResultSetValue(ResultSet resultSet) throws SQLException
+    {
+      return resultSet.getBytes(getField().getName());
+    }
+
+    /**
+     * @author Eike Stepper
+     */
+    public static class Factory extends AbstractTypeMappingFactory
+    {
+      public Factory(Descriptor descriptor)
+      {
+        super(descriptor);
+      }
+
+      @Override
+      public ITypeMapping create(String description) throws ProductCreationException
+      {
+        return new TMBytes();
+      }
+    }
+  }
+
+  /**
+   * @author Eike Stepper
+   */
+  public static class TMBoolean extends AbstractTypeMapping
+  {
+    public static final Factory FACTORY = new Factory(TypeMappingUtil.createDescriptor(ID_PREFIX + ".Boolean",
+        EcorePackage.eINSTANCE.getEBoolean(), DBType.BOOLEAN));
+
+    public static final Factory FACTORY_OBJECT = new Factory(TypeMappingUtil.createDescriptor(ID_PREFIX
+        + ".BooleanObject", EcorePackage.eINSTANCE.getEBooleanObject(), DBType.BOOLEAN));
+
+    public static final Factory FACTORY_SMALLINT = new Factory(TypeMappingUtil.createDescriptor(ID_PREFIX
+        + ".Boolean_SMALLINT", EcorePackage.eINSTANCE.getEBoolean(), DBType.SMALLINT));
+
+    public static final Factory FACTORY_OBJECT_SMALLINT = new Factory(TypeMappingUtil.createDescriptor(ID_PREFIX
+        + ".BooleanObject_SMALLINT", EcorePackage.eINSTANCE.getEBooleanObject(), DBType.SMALLINT));
+
+    @Override
+    public Object getResultSetValue(ResultSet resultSet) throws SQLException
+    {
+      return resultSet.getBoolean(getField().getName());
+    }
+
+    /**
+     * @author Eike Stepper
+     */
+    public static class Factory extends AbstractTypeMappingFactory
+    {
+      public Factory(Descriptor descriptor)
+      {
+        super(descriptor);
+      }
+
+      @Override
+      public ITypeMapping create(String description) throws ProductCreationException
+      {
+        return new TMBoolean();
+      }
+    }
+  }
+
+  /**
+   * @author Stefan Winkler
+   */
+  public static class TMBigInteger extends AbstractTypeMapping
+  {
+    public static final Factory FACTORY = new Factory(TypeMappingUtil.createDescriptor(ID_PREFIX + ".BigInteger",
+        EcorePackage.eINSTANCE.getEBigInteger(), DBType.VARCHAR));
+
+    public static final Factory FACTORY_LONG_VARCHAR = new Factory(TypeMappingUtil.createDescriptor(ID_PREFIX
+        + ".BigIntegerLongVarChar", EcorePackage.eINSTANCE.getEBigInteger(), DBType.LONGVARCHAR));
+
+    @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 Eike Stepper
+     */
+    public static class Factory extends AbstractTypeMappingFactory
+    {
+      public Factory(Descriptor descriptor)
+      {
+        super(descriptor);
+      }
+
+      @Override
+      public ITypeMapping create(String description) throws ProductCreationException
+      {
+        return new TMBigInteger();
+      }
+    }
+  }
+
+  /**
+   * @author Stefan Winkler
+   */
+  public static class TMBigDecimal extends AbstractTypeMapping
+  {
+    public static final Factory FACTORY = new Factory(TypeMappingUtil.createDescriptor(ID_PREFIX + ".BigDecimal",
+        EcorePackage.eINSTANCE.getEBigDecimal(), DBType.VARCHAR));
+
+    public static final Factory FACTORY_LONG_VARCHAR = new Factory(TypeMappingUtil.createDescriptor(ID_PREFIX
+        + ".BigDecimalLongVarchar", EcorePackage.eINSTANCE.getEBigDecimal(), DBType.LONGVARCHAR));
+
+    @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 Eike Stepper
+     */
+    public static class Factory extends AbstractTypeMappingFactory
+    {
+      public Factory(Descriptor descriptor)
+      {
+        super(descriptor);
+      }
+
+      @Override
+      public ITypeMapping create(String description) throws ProductCreationException
+      {
+        return new TMBigDecimal();
+      }
+    }
+  }
+
+  /**
+   * @author Stefan Winkler
+   */
+  public static class TMCustom extends AbstractTypeMapping
+  {
+    public static final Factory FACTORY_VARCHAR = new Factory(TypeMappingUtil.createDescriptor(ID_PREFIX
+        + ".CustomVarchar", EcorePackage.eINSTANCE.getEDataType(), DBType.VARCHAR));
+
+    public static final Factory FACTORY_LONG_VARCHAR = new Factory(TypeMappingUtil.createDescriptor(ID_PREFIX
+        + ".CustomLongVarchar", EcorePackage.eINSTANCE.getEDataType(), DBType.LONGVARCHAR));
+
+    public static final Factory FACTORY_CLOB = new Factory(TypeMappingUtil.createDescriptor(ID_PREFIX + ".CustomClob",
+        EcorePackage.eINSTANCE.getEDataType(), DBType.CLOB));
+
+    @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
+    protected Object getDefaultValue()
+    {
+      Object defaultValue = getFeature().getDefaultValue();
+      if (defaultValue == null)
+      {
+        return null;
+      }
+      
+      EFactory factory = getFeature().getEType().getEPackage().getEFactoryInstance();
+      return factory.convertToString((EDataType)getFeature().getEType(), defaultValue);
+    }
+
+    /**
+     * @author Eike Stepper
+     */
+    public static class Factory extends AbstractTypeMappingFactory
+    {
+      public Factory(Descriptor descriptor)
+      {
+        super(descriptor);
+      }
+
+      @Override
+      public ITypeMapping create(String description) throws ProductCreationException
+      {
+        return new TMCustom();
+      }
+    }
+  }
+}
diff --git a/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/TypeMappingDescriptor.java b/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/TypeMappingDescriptor.java
new file mode 100644
index 0000000..f47075d
--- /dev/null
+++ b/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/TypeMappingDescriptor.java
@@ -0,0 +1,65 @@
+/**
+ * Copyright (c) 2004 - 2011 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/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/TypeMappingRegistry.java b/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/TypeMappingRegistry.java
new file mode 100644
index 0000000..096e2c9
--- /dev/null
+++ b/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/TypeMappingRegistry.java
@@ -0,0 +1,447 @@
+/**
+ * Copyright (c) 2004 - 2011 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.etypes.EtypesPackage;
+import org.eclipse.emf.cdo.server.db.IIDHandler;
+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.EPackage;
+import org.eclipse.emf.ecore.EReference;
+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 = new RegistryPopulator();
+
+  public TypeMappingRegistry()
+  {
+    init();
+  }
+
+  public void init()
+  {
+    populator.disconnect();
+
+    defaultFeatureMapDBTypes = new HashSet<DBType>();
+    typeMappingsById = new HashMap<String, ITypeMapping.Descriptor>();
+    typeMappingByTypes = new HashMap<Pair<EClassifier, DBType>, ITypeMapping.Descriptor>();
+    classifierDefaultMapping = new HashMap<EClassifier, DBType>();
+
+    registerCoreTypeMappings();
+    populator.connect();
+  }
+
+  /**
+   * Register builtin type mapping factories
+   */
+  private void registerCoreTypeMappings()
+  {
+    IManagedContainer container = getContainer();
+    container.registerFactory(CoreTypeMappings.TMBigDecimal.FACTORY);
+    container.registerFactory(CoreTypeMappings.TMBigDecimal.FACTORY_LONG_VARCHAR);
+    container.registerFactory(CoreTypeMappings.TMBigInteger.FACTORY);
+    container.registerFactory(CoreTypeMappings.TMBigInteger.FACTORY_LONG_VARCHAR);
+    container.registerFactory(CoreTypeMappings.TMBoolean.FACTORY);
+    container.registerFactory(CoreTypeMappings.TMBoolean.FACTORY_SMALLINT);
+    container.registerFactory(CoreTypeMappings.TMBoolean.FACTORY_OBJECT);
+    container.registerFactory(CoreTypeMappings.TMBoolean.FACTORY_OBJECT_SMALLINT);
+    container.registerFactory(CoreTypeMappings.TMByte.FACTORY);
+    container.registerFactory(CoreTypeMappings.TMByte.FACTORY_OBJECT);
+    container.registerFactory(CoreTypeMappings.TMBytes.FACTORY);
+    container.registerFactory(CoreTypeMappings.TMCharacter.FACTORY);
+    container.registerFactory(CoreTypeMappings.TMCharacter.FACTORY_OBJECT);
+    container.registerFactory(CoreTypeMappings.TMCustom.FACTORY_VARCHAR);
+    container.registerFactory(CoreTypeMappings.TMCustom.FACTORY_CLOB);
+    container.registerFactory(CoreTypeMappings.TMCustom.FACTORY_LONG_VARCHAR);
+    container.registerFactory(CoreTypeMappings.TMDate2Date.FACTORY);
+    container.registerFactory(CoreTypeMappings.TMDate2Time.FACTORY);
+    container.registerFactory(CoreTypeMappings.TMDate2Timestamp.FACTORY);
+    container.registerFactory(CoreTypeMappings.TMDouble.FACTORY);
+    container.registerFactory(CoreTypeMappings.TMDouble.FACTORY_OBJECT);
+    container.registerFactory(CoreTypeMappings.TMEnum.FACTORY);
+    container.registerFactory(CoreTypeMappings.TMFloat.FACTORY);
+    container.registerFactory(CoreTypeMappings.TMFloat.FACTORY_OBJECT);
+    container.registerFactory(CoreTypeMappings.TMInteger.FACTORY);
+    container.registerFactory(CoreTypeMappings.TMInteger.FACTORY_OBJECT);
+    container.registerFactory(CoreTypeMappings.TMLong.FACTORY);
+    container.registerFactory(CoreTypeMappings.TMLong.FACTORY_OBJECT);
+    container.registerFactory(CoreTypeMappings.TMShort.FACTORY);
+    container.registerFactory(CoreTypeMappings.TMShort.FACTORY_OBJECT);
+    container.registerFactory(CoreTypeMappings.TMString.FACTORY_VARCHAR);
+    container.registerFactory(CoreTypeMappings.TMString.FACTORY_CLOB);
+    container.registerFactory(CoreTypeMappings.TMString.FACTORY_LONG_VARCHAR);
+    container.registerFactory(CoreTypeMappings.TMBlob.FACTORY_VARCHAR);
+    container.registerFactory(CoreTypeMappings.TMBlob.FACTORY_LONG_VARCHAR);
+    container.registerFactory(CoreTypeMappings.TMClob.FACTORY_VARCHAR);
+    container.registerFactory(CoreTypeMappings.TMClob.FACTORY_LONG_VARCHAR);
+
+    classifierDefaultMapping.put(EcorePackage.eINSTANCE.getEDataType(), DBType.VARCHAR);
+
+    classifierDefaultMapping.put(EcorePackage.eINSTANCE.getEBigDecimal(), DBType.VARCHAR);
+    classifierDefaultMapping.put(EcorePackage.eINSTANCE.getEBigInteger(), DBType.VARCHAR);
+    classifierDefaultMapping.put(EcorePackage.eINSTANCE.getEBoolean(), DBType.BOOLEAN);
+    classifierDefaultMapping.put(EcorePackage.eINSTANCE.getEBooleanObject(), DBType.BOOLEAN);
+    classifierDefaultMapping.put(EcorePackage.eINSTANCE.getEByte(), DBType.SMALLINT);
+    classifierDefaultMapping.put(EcorePackage.eINSTANCE.getEByteObject(), DBType.SMALLINT);
+    classifierDefaultMapping.put(EcorePackage.eINSTANCE.getEByteArray(), DBType.BLOB);
+    classifierDefaultMapping.put(EcorePackage.eINSTANCE.getEChar(), DBType.CHAR);
+    classifierDefaultMapping.put(EcorePackage.eINSTANCE.getECharacterObject(), DBType.CHAR);
+    classifierDefaultMapping.put(EcorePackage.eINSTANCE.getEDate(), DBType.TIMESTAMP);
+    classifierDefaultMapping.put(EcorePackage.eINSTANCE.getEDouble(), DBType.DOUBLE);
+    classifierDefaultMapping.put(EcorePackage.eINSTANCE.getEDoubleObject(), DBType.DOUBLE);
+    classifierDefaultMapping.put(EcorePackage.eINSTANCE.getEEnum(), DBType.INTEGER);
+    classifierDefaultMapping.put(EcorePackage.eINSTANCE.getEFloat(), DBType.FLOAT);
+    classifierDefaultMapping.put(EcorePackage.eINSTANCE.getEFloatObject(), DBType.FLOAT);
+    classifierDefaultMapping.put(EcorePackage.eINSTANCE.getEInt(), DBType.INTEGER);
+    classifierDefaultMapping.put(EcorePackage.eINSTANCE.getEIntegerObject(), DBType.INTEGER);
+    classifierDefaultMapping.put(EcorePackage.eINSTANCE.getELong(), DBType.BIGINT);
+    classifierDefaultMapping.put(EcorePackage.eINSTANCE.getELongObject(), DBType.BIGINT);
+    classifierDefaultMapping.put(EcorePackage.eINSTANCE.getEShort(), DBType.SMALLINT);
+    classifierDefaultMapping.put(EcorePackage.eINSTANCE.getEShortObject(), DBType.SMALLINT);
+    classifierDefaultMapping.put(EcorePackage.eINSTANCE.getEString(), DBType.VARCHAR);
+
+    classifierDefaultMapping.put(EtypesPackage.eINSTANCE.getBlob(), DBType.VARCHAR); // TODO Should be DBType.BLOB?
+    classifierDefaultMapping.put(EtypesPackage.eINSTANCE.getClob(), DBType.VARCHAR); // TODO Should be DBType.CLOB?
+  }
+
+  protected IManagedContainer getContainer()
+  {
+    return IPluginContainer.INSTANCE;
+  }
+
+  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)
+  {
+    ITypeMapping typeMapping = null;
+    if (feature instanceof EReference)
+    {
+      IIDHandler idHandler = mappingStrategy.getStore().getIDHandler();
+      typeMapping = idHandler.getObjectTypeMapping();
+      typeMapping.setDBType(idHandler.getDBType());
+    }
+    else
+    {
+      IDBAdapter dbAdapter = mappingStrategy.getStore().getDBAdapter();
+      DBType dbType = getDBType(feature, dbAdapter);
+
+      ITypeMapping.Descriptor descriptor = null;
+
+      String typeMappingID = DBAnnotation.TYPE_MAPPING.getValue(feature);
+      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)
+      {
+        EClassifier type = getEType(feature);
+        throw new IllegalStateException(MessageFormat.format(Messages.getString("TypeMappingRegistry.1"), feature
+            .getEContainingClass().getName() + "." + feature.getName(),
+            type.getEPackage().getName() + "." + type.getName(), dbType.getKeyword()));
+      }
+
+      IFactory factory = getContainer().getFactory(ITypeMapping.Factory.PRODUCT_GROUP, descriptor.getFactoryType());
+      typeMapping = (ITypeMapping)factory.create(null);
+      typeMapping.setDBType(dbType);
+    }
+
+    typeMapping.setMappingStrategy(mappingStrategy);
+    typeMapping.setFeature(feature);
+    return typeMapping;
+  }
+
+  private EClassifier getEType(EStructuralFeature feature)
+  {
+    EClassifier classifier = feature.getEType();
+    if (classifier instanceof EEnum)
+    {
+      return EcorePackage.eINSTANCE.getEEnum();
+    }
+
+    if (classifier instanceof EClass)
+    {
+      return EcorePackage.eINSTANCE.getEClass();
+    }
+
+    EPackage ePackage = classifier.getEPackage();
+    if (CDOModelUtil.isCorePackage(ePackage))
+    {
+      return classifier;
+    }
+
+    if (CDOModelUtil.isTypesPackage(ePackage))
+    {
+      return classifier;
+    }
+
+    return EcorePackage.eINSTANCE.getEDataType();
+  }
+
+  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(getEType(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>(getEType(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 = getContainer();
+
+    public RegistryPopulator()
+    {
+    }
+
+    /**
+     * Connect to the factory registry.
+     */
+    public void connect()
+    {
+      populateTypeMappingRegistry();
+      container.getFactoryRegistry().addListener(this);
+    }
+
+    public void disconnect()
+    {
+      container.getFactoryRegistry().removeListener(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/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/TypeMappingUtil.java b/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/TypeMappingUtil.java
new file mode 100644
index 0000000..1bdbaa1
--- /dev/null
+++ b/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/TypeMappingUtil.java
@@ -0,0 +1,113 @@
+/**
+ * Copyright (c) 2004 - 2011 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/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/AbstractFeatureMapTableMapping.java b/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/AbstractFeatureMapTableMapping.java
new file mode 100644
index 0000000..83493b4
--- /dev/null
+++ b/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/AbstractFeatureMapTableMapping.java
@@ -0,0 +1,588 @@
+/**
+ * Copyright (c) 2004 - 2011 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 - 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
+ *    Stefan Winkler - Bug 329025: [DB] Support branching for range-based mapping strategy
+ */
+package org.eclipse.emf.cdo.server.internal.db.mapping.horizontal;
+
+import org.eclipse.emf.cdo.common.id.CDOID;
+import org.eclipse.emf.cdo.common.revision.CDOList;
+import org.eclipse.emf.cdo.common.revision.CDORevision;
+import org.eclipse.emf.cdo.common.revision.CDORevisionUtil;
+import org.eclipse.emf.cdo.server.IStoreAccessor.QueryXRefsContext;
+import org.eclipse.emf.cdo.server.IStoreChunkReader.Chunk;
+import org.eclipse.emf.cdo.server.db.IDBStore;
+import org.eclipse.emf.cdo.server.db.IDBStoreAccessor;
+import org.eclipse.emf.cdo.server.db.IDBStoreChunkReader;
+import org.eclipse.emf.cdo.server.db.IIDHandler;
+import org.eclipse.emf.cdo.server.db.IPreparedStatementCache;
+import org.eclipse.emf.cdo.server.db.IPreparedStatementCache.ReuseProbability;
+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.spi.common.revision.InternalCDORevision;
+
+import org.eclipse.net4j.db.DBException;
+import org.eclipse.net4j.db.DBType;
+import org.eclipse.net4j.db.DBUtil;
+import org.eclipse.net4j.db.ddl.IDBField;
+import org.eclipse.net4j.db.ddl.IDBIndex.Type;
+import org.eclipse.net4j.db.ddl.IDBTable;
+import org.eclipse.net4j.util.ImplementationError;
+import org.eclipse.net4j.util.collection.MoveableList;
+import org.eclipse.net4j.util.om.trace.ContextTracer;
+
+import org.eclipse.emf.ecore.EClass;
+import org.eclipse.emf.ecore.EStructuralFeature;
+import org.eclipse.emf.ecore.util.FeatureMap;
+
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * This abstract base class provides basic behavior needed for mapping many-valued attributes to tables.
+ * 
+ * @author Eike Stepper
+ * @since 3.0
+ */
+public abstract class AbstractFeatureMapTableMapping extends BasicAbstractListTableMapping
+{
+  private static final ContextTracer TRACER = new ContextTracer(OM.DEBUG, AbstractFeatureMapTableMapping.class);
+
+  /**
+   * The table of this mapping.
+   */
+  private IDBTable table;
+
+  /**
+   * The tags mapped to column names
+   */
+  private HashMap<CDOID, String> tagMap;
+
+  /**
+   * Column name Set
+   */
+  private List<String> columnNames;
+
+  /**
+   * The type mappings for the value fields.
+   */
+  private Map<CDOID, ITypeMapping> typeMappings;
+
+  // --------- SQL strings - see initSQLStrings() -----------------
+  private String sqlSelectChunksPrefix;
+
+  private String sqlOrderByIndex;
+
+  protected String sqlInsert;
+
+  private List<DBType> dbTypes;
+
+  public AbstractFeatureMapTableMapping(IMappingStrategy mappingStrategy, EClass eClass, EStructuralFeature feature)
+  {
+    super(mappingStrategy, eClass, feature);
+    initDBTypes();
+    initTable();
+    initSQLStrings();
+  }
+
+  private void initDBTypes()
+  {
+    // TODO add annotation processing here ...
+    ITypeMapping.Registry registry = getTypeMappingRegistry();
+    dbTypes = new ArrayList<DBType>(registry.getDefaultFeatureMapDBTypes());
+  }
+
+  protected ITypeMapping.Registry getTypeMappingRegistry()
+  {
+    return ITypeMapping.Registry.INSTANCE;
+  }
+
+  private void initTable()
+  {
+    IDBStore store = getMappingStrategy().getStore();
+    String tableName = getMappingStrategy().getTableName(getContainingClass(), getFeature());
+    table = store.getDBSchema().addTable(tableName);
+
+    // add fields for keys (cdo_id, version, feature_id)
+    FieldInfo[] fields = getKeyFields();
+    IDBField[] dbFields = new IDBField[fields.length];
+
+    for (int i = 0; i < fields.length; i++)
+    {
+      dbFields[i] = table.addField(fields[i].getName(), fields[i].getDbType());
+    }
+
+    // add field for list index
+    IDBField idxField = table.addField(CDODBSchema.FEATUREMAP_IDX, DBType.INTEGER);
+
+    // add field for FeatureMap tag (MetaID for Feature in CDO registry)
+    IDBField tagField = table.addField(CDODBSchema.FEATUREMAP_TAG, store.getIDHandler().getDBType());
+
+    tagMap = new HashMap<CDOID, String>();
+    typeMappings = new HashMap<CDOID, ITypeMapping>();
+    columnNames = new ArrayList<String>();
+
+    // create columns for all DBTypes
+    for (DBType type : getDBTypes())
+    {
+      String column = CDODBSchema.FEATUREMAP_VALUE + "_" + type.name();
+      table.addField(column, type);
+      columnNames.add(column);
+    }
+
+    table.addIndex(Type.NON_UNIQUE, dbFields);
+    table.addIndex(Type.NON_UNIQUE, idxField);
+    table.addIndex(Type.NON_UNIQUE, tagField);
+  }
+
+  protected abstract FieldInfo[] getKeyFields();
+
+  protected abstract void setKeyFields(PreparedStatement stmt, CDORevision revision) throws SQLException;
+
+  public Collection<IDBTable> getDBTables()
+  {
+    return Arrays.asList(table);
+  }
+
+  private void initSQLStrings()
+  {
+    String tableName = getTable().getName();
+    FieldInfo[] fields = getKeyFields();
+
+    // ---------------- SELECT to read chunks ----------------------------
+    StringBuilder builder = new StringBuilder();
+    builder.append("SELECT ");
+
+    builder.append(CDODBSchema.FEATUREMAP_TAG);
+    builder.append(", ");
+
+    Iterator<String> iter = columnNames.iterator();
+    while (iter.hasNext())
+    {
+      builder.append(iter.next());
+      if (iter.hasNext())
+      {
+        builder.append(", ");
+      }
+    }
+
+    builder.append(" FROM ");
+    builder.append(tableName);
+    builder.append(" WHERE ");
+
+    for (int i = 0; i < fields.length; i++)
+    {
+      builder.append(fields[i].getName());
+      if (i + 1 < fields.length)
+      {
+        // more to come
+        builder.append("=? AND ");
+      }
+      else
+      {
+        // last one
+        builder.append("=? ");
+      }
+    }
+
+    sqlSelectChunksPrefix = builder.toString();
+
+    sqlOrderByIndex = " ORDER BY " + CDODBSchema.FEATUREMAP_IDX; //$NON-NLS-1$
+
+    // INSERT with dynamic field name
+    // TODO: Better: universal INSERT-Statement, because of stmt caching!
+
+    // ----------------- INSERT - prefix -----------------
+    builder = new StringBuilder("INSERT INTO ");
+    builder.append(tableName);
+    builder.append(" ("); //$NON-NLS-1$
+    for (int i = 0; i < fields.length; i++)
+    {
+      builder.append(fields[i].getName());
+      builder.append(", "); //$NON-NLS-1$
+    }
+
+    for (int i = 0; i < columnNames.size(); i++)
+    {
+      builder.append(columnNames.get(i));
+      builder.append(", "); //$NON-NLS-1$
+    }
+
+    builder.append(CDODBSchema.FEATUREMAP_IDX);
+    builder.append(", "); //$NON-NLS-1$
+    builder.append(CDODBSchema.FEATUREMAP_TAG);
+    builder.append(") VALUES ("); //$NON-NLS-1$
+    for (int i = 0; i < fields.length + columnNames.size(); i++)
+    {
+      builder.append("?, ");
+    }
+
+    builder.append("?, ?)");
+    sqlInsert = builder.toString();
+  }
+
+  protected List<DBType> getDBTypes()
+  {
+    return dbTypes;
+  }
+
+  protected final IDBTable getTable()
+  {
+    return table;
+  }
+
+  protected final List<String> getColumnNames()
+  {
+    return columnNames;
+  }
+
+  protected final Map<CDOID, ITypeMapping> getTypeMappings()
+  {
+    return typeMappings;
+  }
+
+  protected final Map<CDOID, String> getTagMap()
+  {
+    return tagMap;
+  }
+
+  public void readValues(IDBStoreAccessor accessor, InternalCDORevision revision, int listChunk)
+  {
+    MoveableList<Object> list = revision.getList(getFeature());
+    if (listChunk == 0 || list.size() == 0)
+    {
+      // nothing to read take shortcut
+      return;
+    }
+
+    if (TRACER.isEnabled())
+    {
+      TRACER.format("Reading list values for feature {0}.{1} of {2}v{3}", getContainingClass().getName(), getFeature()
+          .getName(), revision.getID(), revision.getVersion());
+    }
+
+    IIDHandler idHandler = getMappingStrategy().getStore().getIDHandler();
+    IPreparedStatementCache statementCache = accessor.getStatementCache();
+    PreparedStatement stmt = null;
+    ResultSet resultSet = null;
+
+    try
+    {
+      String sql = sqlSelectChunksPrefix + sqlOrderByIndex;
+      stmt = statementCache.getPreparedStatement(sql, ReuseProbability.HIGH);
+      setKeyFields(stmt, revision);
+
+      if (listChunk != CDORevision.UNCHUNKED)
+      {
+        stmt.setMaxRows(listChunk); // optimization - don't read unneeded rows.
+      }
+
+      resultSet = stmt.executeQuery();
+      int currentIndex = 0;
+
+      while ((listChunk == CDORevision.UNCHUNKED || --listChunk >= 0) && resultSet.next())
+      {
+        CDOID tag = idHandler.getCDOID(resultSet, 1);
+        Object value = getTypeMapping(tag).readValue(resultSet);
+
+        if (TRACER.isEnabled())
+        {
+          TRACER.format("Read value for index {0} from result set: {1}", list.size(), value);
+        }
+
+        list.set(currentIndex++, CDORevisionUtil.createFeatureMapEntry(getFeatureByTag(tag), value));
+      }
+    }
+    catch (SQLException ex)
+    {
+      throw new DBException(ex);
+    }
+    finally
+    {
+      DBUtil.close(resultSet);
+      statementCache.releasePreparedStatement(stmt);
+    }
+
+    if (TRACER.isEnabled())
+    {
+      TRACER.format("Reading list values done for feature {0}.{1} of {2}v{3}", getContainingClass().getName(),
+          getFeature().getName(), revision.getID(), revision.getVersion());
+    }
+  }
+
+  private void addFeature(CDOID tag)
+  {
+    EStructuralFeature modelFeature = getFeatureByTag(tag);
+
+    ITypeMapping typeMapping = getMappingStrategy().createValueMapping(modelFeature);
+    String column = CDODBSchema.FEATUREMAP_VALUE + "_" + typeMapping.getDBType();
+
+    tagMap.put(tag, column);
+    typeMapping.setDBField(table, column);
+    typeMappings.put(tag, typeMapping);
+  }
+
+  public final void readChunks(IDBStoreChunkReader chunkReader, List<Chunk> chunks, String where)
+  {
+    if (TRACER.isEnabled())
+    {
+      TRACER.format("Reading list chunk values for feature {0}.{1} of {2}v{3}", getContainingClass().getName(),
+          getFeature().getName(), chunkReader.getRevision().getID(), chunkReader.getRevision().getVersion());
+    }
+
+    IIDHandler idHandler = getMappingStrategy().getStore().getIDHandler();
+    IPreparedStatementCache statementCache = chunkReader.getAccessor().getStatementCache();
+    PreparedStatement stmt = null;
+    ResultSet resultSet = null;
+
+    try
+    {
+      StringBuilder builder = new StringBuilder(sqlSelectChunksPrefix);
+      if (where != null)
+      {
+        builder.append(" AND "); //$NON-NLS-1$
+        builder.append(where);
+      }
+
+      builder.append(sqlOrderByIndex);
+
+      String sql = builder.toString();
+      stmt = statementCache.getPreparedStatement(sql, ReuseProbability.LOW);
+      setKeyFields(stmt, chunkReader.getRevision());
+
+      resultSet = stmt.executeQuery();
+
+      Chunk chunk = null;
+      int chunkSize = 0;
+      int chunkIndex = 0;
+      int indexInChunk = 0;
+
+      while (resultSet.next())
+      {
+        CDOID tag = idHandler.getCDOID(resultSet, 1);
+        Object value = getTypeMapping(tag).readValue(resultSet);
+
+        if (chunk == null)
+        {
+          chunk = chunks.get(chunkIndex++);
+          chunkSize = chunk.size();
+
+          if (TRACER.isEnabled())
+          {
+            TRACER.format("Current chunk no. {0} is [start = {1}, size = {2}]", chunkIndex - 1, chunk.getStartIndex(),
+                chunkSize);
+          }
+        }
+
+        if (TRACER.isEnabled())
+        {
+          TRACER.format("Read value for chunk index {0} from result set: {1}", indexInChunk, value);
+        }
+
+        chunk.add(indexInChunk++, CDORevisionUtil.createFeatureMapEntry(getFeatureByTag(tag), value));
+        if (indexInChunk == chunkSize)
+        {
+          if (TRACER.isEnabled())
+          {
+            TRACER.format("Chunk finished");
+          }
+
+          chunk = null;
+          indexInChunk = 0;
+        }
+      }
+
+      if (TRACER.isEnabled())
+      {
+        TRACER.format("Reading list chunk values done for feature {0}.{1} of {2}", getContainingClass().getName(),
+            getFeature(), chunkReader.getRevision());
+      }
+    }
+    catch (SQLException ex)
+    {
+      throw new DBException(ex);
+    }
+    finally
+    {
+      DBUtil.close(resultSet);
+      statementCache.releasePreparedStatement(stmt);
+    }
+  }
+
+  public void writeValues(IDBStoreAccessor accessor, InternalCDORevision revision)
+  {
+    CDOList values = revision.getList(getFeature());
+
+    int idx = 0;
+    for (Object element : values)
+    {
+      writeValue(accessor, revision, idx++, element);
+    }
+  }
+
+  protected final void writeValue(IDBStoreAccessor accessor, CDORevision revision, int idx, Object value)
+  {
+    IIDHandler idHandler = getMappingStrategy().getStore().getIDHandler();
+    IPreparedStatementCache statementCache = accessor.getStatementCache();
+    PreparedStatement stmt = null;
+
+    if (TRACER.isEnabled())
+    {
+      TRACER
+          .format(
+              "Writing value for feature {0}.{1} index {2} of {3} : {4}", getContainingClass().getName(), getFeature(), idx, revision, value); //$NON-NLS-1$
+    }
+
+    try
+    {
+      FeatureMap.Entry entry = (FeatureMap.Entry)value;
+      EStructuralFeature entryFeature = entry.getEStructuralFeature();
+      CDOID tag = getTagByFeature(entryFeature, revision.getTimeStamp());
+      String columnName = getColumnName(tag);
+
+      stmt = statementCache.getPreparedStatement(sqlInsert, ReuseProbability.HIGH);
+      setKeyFields(stmt, revision);
+      int column = getKeyFields().length + 1;
+
+      for (int i = 0; i < columnNames.size(); i++)
+      {
+        if (columnNames.get(i).equals(columnName))
+        {
+          getTypeMapping(tag).setValue(stmt, column++, entry.getValue());
+        }
+        else
+        {
+          stmt.setNull(column++, getDBTypes().get(i).getCode());
+        }
+      }
+
+      stmt.setInt(column++, idx);
+      idHandler.setCDOID(stmt, column++, tag);
+      DBUtil.update(stmt, true);
+    }
+    catch (SQLException e)
+    {
+      throw new DBException(e);
+    }
+    finally
+    {
+      statementCache.releasePreparedStatement(stmt);
+    }
+  }
+
+  /**
+   * Get column name (lazy)
+   * 
+   * @param tag
+   *          The feature's MetaID in CDO
+   * @return the column name where the values are stored
+   */
+  protected String getColumnName(CDOID tag)
+  {
+    String column = tagMap.get(tag);
+    if (column == null)
+    {
+      addFeature(tag);
+      column = tagMap.get(tag);
+    }
+
+    return column;
+  }
+
+  /**
+   * Get type mapping (lazy)
+   * 
+   * @param tag
+   *          The feature's MetaID in CDO
+   * @return the corresponding type mapping
+   */
+  protected ITypeMapping getTypeMapping(CDOID tag)
+  {
+    ITypeMapping typeMapping = typeMappings.get(tag);
+    if (typeMapping == null)
+    {
+      addFeature(tag);
+      typeMapping = typeMappings.get(tag);
+    }
+
+    return typeMapping;
+  }
+
+  /**
+   * @param metaID
+   * @return the column name where the values are stored
+   */
+  private EStructuralFeature getFeatureByTag(CDOID tag)
+  {
+    return (EStructuralFeature)getMappingStrategy().getStore().getMetaDataManager().getMetaInstance(tag);
+  }
+
+  /**
+   * @param feature
+   *          The EStructuralFeature
+   * @return The feature's MetaID in CDO
+   */
+  protected CDOID getTagByFeature(EStructuralFeature feature, long timeStamp)
+  {
+    return getMappingStrategy().getStore().getMetaDataManager().getMetaID(feature, timeStamp);
+  }
+
+  /**
+   * Used by subclasses to indicate which fields should be in the table. I.e. just a pair of name and DBType ...
+   * 
+   * @author Stefan Winkler
+   */
+  protected static class FieldInfo
+  {
+    private String name;
+
+    private DBType dbType;
+
+    public FieldInfo(String name, DBType dbType)
+    {
+      this.name = name;
+      this.dbType = dbType;
+    }
+
+    public String getName()
+    {
+      return name;
+    }
+
+    public DBType getDbType()
+    {
+      return dbType;
+    }
+  }
+
+  public final boolean queryXRefs(IDBStoreAccessor accessor, String mainTableName, String mainTableWhere,
+      QueryXRefsContext context, String idString)
+  {
+    /*
+     * must never be called (a feature map is not associated with an EReference feature, so XRefs are nor supported
+     * here)
+     */
+    throw new ImplementationError("Should never be called!");
+  }
+
+}
diff --git a/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/AbstractHorizontalClassMapping.java b/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/AbstractHorizontalClassMapping.java
new file mode 100644
index 0000000..bb500d3
--- /dev/null
+++ b/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/AbstractHorizontalClassMapping.java
@@ -0,0 +1,870 @@
+/**
+ * Copyright (c) 2004 - 2011 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 - 271444: [DB] Multiple refactorings bug 271444
+ *    Stefan Winkler - 249610: [DB] Support external references (Implementation)
+ *    Stefan Winkler - Bug 329025: [DB] Support branching for range-based mapping strategy
+ */
+package org.eclipse.emf.cdo.server.internal.db.mapping.horizontal;
+
+import org.eclipse.emf.cdo.common.branch.CDOBranch;
+import org.eclipse.emf.cdo.common.branch.CDOBranchManager;
+import org.eclipse.emf.cdo.common.branch.CDOBranchPoint;
+import org.eclipse.emf.cdo.common.branch.CDOBranchVersion;
+import org.eclipse.emf.cdo.common.id.CDOID;
+import org.eclipse.emf.cdo.common.model.CDOModelUtil;
+import org.eclipse.emf.cdo.common.revision.CDOList;
+import org.eclipse.emf.cdo.common.revision.CDORevision;
+import org.eclipse.emf.cdo.common.revision.CDORevisionHandler;
+import org.eclipse.emf.cdo.common.revision.CDORevisionManager;
+import org.eclipse.emf.cdo.eresource.EresourcePackage;
+import org.eclipse.emf.cdo.server.IRepository;
+import org.eclipse.emf.cdo.server.IStoreAccessor.QueryXRefsContext;
+import org.eclipse.emf.cdo.server.db.IDBStore;
+import org.eclipse.emf.cdo.server.db.IDBStoreAccessor;
+import org.eclipse.emf.cdo.server.db.IIDHandler;
+import org.eclipse.emf.cdo.server.db.IPreparedStatementCache;
+import org.eclipse.emf.cdo.server.db.IPreparedStatementCache.ReuseProbability;
+import org.eclipse.emf.cdo.server.db.mapping.IClassMapping;
+import org.eclipse.emf.cdo.server.db.mapping.IListMapping;
+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.spi.common.commit.CDOChangeSetSegment;
+import org.eclipse.emf.cdo.spi.common.revision.InternalCDOList;
+import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevision;
+
+import org.eclipse.net4j.db.DBException;
+import org.eclipse.net4j.db.DBType;
+import org.eclipse.net4j.db.DBUtil;
+import org.eclipse.net4j.db.ddl.IDBField;
+import org.eclipse.net4j.db.ddl.IDBIndex;
+import org.eclipse.net4j.db.ddl.IDBTable;
+import org.eclipse.net4j.util.om.monitor.OMMonitor;
+import org.eclipse.net4j.util.om.monitor.OMMonitor.Async;
+import org.eclipse.net4j.util.om.trace.ContextTracer;
+
+import org.eclipse.emf.ecore.EClass;
+import org.eclipse.emf.ecore.EReference;
+import org.eclipse.emf.ecore.EStructuralFeature;
+import org.eclipse.emf.ecore.util.FeatureMapUtil;
+
+import org.eclipse.core.runtime.Assert;
+
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * @author Eike Stepper
+ * @since 2.0
+ */
+public abstract class AbstractHorizontalClassMapping implements IClassMapping
+{
+  private static final ContextTracer TRACER = new ContextTracer(OM.DEBUG, AbstractHorizontalClassMapping.class);
+
+  private EClass eClass;
+
+  private IDBTable table;
+
+  private AbstractHorizontalMappingStrategy mappingStrategy;
+
+  private List<ITypeMapping> valueMappings;
+
+  private List<IListMapping> listMappings;
+
+  private Map<EStructuralFeature, String> listSizeFields;
+
+  private Map<EStructuralFeature, String> unsettableFields;
+
+  private String sqlSelectForHandle;
+
+  private String sqlSelectForChangeSet;
+
+  public AbstractHorizontalClassMapping(AbstractHorizontalMappingStrategy mappingStrategy, EClass eClass)
+  {
+    this.mappingStrategy = mappingStrategy;
+    this.eClass = eClass;
+
+    initTable();
+    initFeatures();
+    initSQLStrings();
+  }
+
+  private void initTable()
+  {
+    IDBStore store = getMappingStrategy().getStore();
+    DBType idType = store.getIDHandler().getDBType();
+
+    String name = getMappingStrategy().getTableName(eClass);
+    table = store.getDBSchema().addTable(name);
+
+    IDBField idField = table.addField(CDODBSchema.ATTRIBUTES_ID, idType, true);
+    IDBField versionField = table.addField(CDODBSchema.ATTRIBUTES_VERSION, DBType.INTEGER, true);
+
+    IDBField branchField = addBranchingField(table);
+
+    table.addField(CDODBSchema.ATTRIBUTES_CREATED, DBType.BIGINT, true);
+    IDBField revisedField = table.addField(CDODBSchema.ATTRIBUTES_REVISED, DBType.BIGINT, true);
+    table.addField(CDODBSchema.ATTRIBUTES_RESOURCE, idType, true);
+    table.addField(CDODBSchema.ATTRIBUTES_CONTAINER, idType, true);
+    table.addField(CDODBSchema.ATTRIBUTES_FEATURE, DBType.INTEGER, true);
+
+    if (branchField != null)
+    {
+      table.addIndex(IDBIndex.Type.UNIQUE, idField, versionField, branchField);
+    }
+    else
+    {
+      table.addIndex(IDBIndex.Type.UNIQUE, idField, versionField);
+    }
+
+    table.addIndex(IDBIndex.Type.NON_UNIQUE, idField, revisedField);
+  }
+
+  protected IDBField addBranchingField(IDBTable table)
+  {
+    return null;
+  }
+
+  private void initFeatures()
+  {
+    EStructuralFeature[] features = CDOModelUtil.getAllPersistentFeatures(eClass);
+
+    if (features == null)
+    {
+      valueMappings = Collections.emptyList();
+      listMappings = Collections.emptyList();
+    }
+    else
+    {
+      valueMappings = createValueMappings(features);
+      listMappings = createListMappings(features);
+    }
+  }
+
+  private void initSQLStrings()
+  {
+    // ----------- Select all revisions (for handleRevisions) ---
+    StringBuilder builder = new StringBuilder("SELECT "); //$NON-NLS-1$
+    builder.append(CDODBSchema.ATTRIBUTES_ID);
+    builder.append(", "); //$NON-NLS-1$
+    builder.append(CDODBSchema.ATTRIBUTES_VERSION);
+    builder.append(" FROM "); //$NON-NLS-1$
+    builder.append(getTable());
+    sqlSelectForHandle = builder.toString();
+
+    // ----------- Select all revisions (for readChangeSet) ---
+    builder = new StringBuilder("SELECT DISTINCT "); //$NON-NLS-1$
+    builder.append(CDODBSchema.ATTRIBUTES_ID);
+    builder.append(" FROM "); //$NON-NLS-1$
+    builder.append(getTable());
+    builder.append(" WHERE "); //$NON-NLS-1$
+    sqlSelectForChangeSet = builder.toString();
+  }
+
+  private List<ITypeMapping> createValueMappings(EStructuralFeature[] features)
+  {
+    List<ITypeMapping> mappings = new ArrayList<ITypeMapping>();
+    for (EStructuralFeature feature : features)
+    {
+      if (!feature.isMany())
+      {
+        ITypeMapping mapping = mappingStrategy.createValueMapping(feature);
+        mapping.createDBField(getTable());
+        mappings.add(mapping);
+
+        if (feature.isUnsettable())
+        {
+          String fieldName = mappingStrategy.getUnsettableFieldName(feature);
+          if (unsettableFields == null)
+          {
+            unsettableFields = new LinkedHashMap<EStructuralFeature, String>();
+          }
+
+          unsettableFields.put(feature, fieldName);
+        }
+      }
+    }
+
+    // add unsettable fields to end of table
+    if (unsettableFields != null)
+    {
+      for (String fieldName : unsettableFields.values())
+      {
+        table.addField(fieldName, DBType.BOOLEAN, 1);
+      }
+    }
+
+    return mappings;
+  }
+
+  private List<IListMapping> createListMappings(EStructuralFeature[] features)
+  {
+    List<IListMapping> listMappings = new ArrayList<IListMapping>();
+    for (EStructuralFeature feature : features)
+    {
+      if (feature.isMany())
+      {
+        IListMapping mapping = null;
+        if (FeatureMapUtil.isFeatureMap(feature))
+        {
+          mapping = mappingStrategy.createFeatureMapMapping(eClass, feature);
+        }
+        else
+        {
+          mapping = mappingStrategy.createListMapping(eClass, feature);
+        }
+
+        listMappings.add(mapping);
+
+        // add field for list sizes
+        createListSizeField(feature);
+      }
+    }
+
+    return listMappings;
+  }
+
+  /**
+   * Create an integer field in the attribute tabel for the list size of the associated list mapping.
+   */
+  private void createListSizeField(EStructuralFeature feature)
+  {
+    if (listSizeFields == null)
+    {
+      listSizeFields = new LinkedHashMap<EStructuralFeature, String>();
+    }
+
+    String fieldName = mappingStrategy.getFieldName(feature);
+    table.addField(fieldName, DBType.INTEGER);
+
+    listSizeFields.put(feature, fieldName);
+  }
+
+  /**
+   * Read the revision's values from the DB.
+   * 
+   * @return <code>true</code> if the revision has been read successfully.<br>
+   *         <code>false</code> if the revision does not exist in the DB.
+   */
+  protected final boolean readValuesFromStatement(PreparedStatement stmt, InternalCDORevision revision,
+      IDBStoreAccessor accessor)
+  {
+    ResultSet resultSet = null;
+
+    try
+    {
+      if (TRACER.isEnabled())
+      {
+        TRACER.format("Executing Query: {0}", stmt.toString()); //$NON-NLS-1$
+      }
+
+      stmt.setMaxRows(1); // Optimization: only 1 row
+
+      resultSet = stmt.executeQuery();
+      if (!resultSet.next())
+      {
+        if (TRACER.isEnabled())
+        {
+          TRACER.format("Resultset was empty"); //$NON-NLS-1$
+        }
+
+        return false;
+      }
+
+      revision.setVersion(resultSet.getInt(CDODBSchema.ATTRIBUTES_VERSION));
+
+      long timeStamp = resultSet.getLong(CDODBSchema.ATTRIBUTES_CREATED);
+
+      IIDHandler idHandler = getMappingStrategy().getStore().getIDHandler();
+      CDOBranchPoint branchPoint = revision.getBranch().getPoint(timeStamp);
+
+      revision.setBranchPoint(branchPoint);
+      revision.setRevised(resultSet.getLong(CDODBSchema.ATTRIBUTES_REVISED));
+      revision.setResourceID(idHandler.getCDOID(resultSet, CDODBSchema.ATTRIBUTES_RESOURCE));
+      revision.setContainerID(idHandler.getCDOID(resultSet, CDODBSchema.ATTRIBUTES_CONTAINER));
+      revision.setContainingFeatureID(resultSet.getInt(CDODBSchema.ATTRIBUTES_FEATURE));
+
+      for (ITypeMapping mapping : valueMappings)
+      {
+        EStructuralFeature feature = mapping.getFeature();
+        if (feature.isUnsettable())
+        {
+          if (!resultSet.getBoolean(unsettableFields.get(feature)))
+          {
+            // isSet==false -- setValue: null
+            revision.setValue(feature, null);
+            continue;
+          }
+        }
+
+        mapping.readValueToRevision(resultSet, revision);
+      }
+
+      if (listSizeFields != null)
+      {
+        for (Map.Entry<EStructuralFeature, String> listSizeEntry : listSizeFields.entrySet())
+        {
+          EStructuralFeature feature = listSizeEntry.getKey();
+          String fieldName = listSizeEntry.getValue();
+          int size = resultSet.getInt(fieldName);
+
+          // ensure the listSize (TODO: remove assertion)
+          CDOList list = revision.getList(feature, size);
+
+          for (int i = 0; i < size; i++)
+          {
+            list.add(InternalCDOList.UNINITIALIZED);
+          }
+
+          if (list.size() != size)
+          {
+            Assert.isTrue(false);
+          }
+        }
+      }
+
+      return true;
+    }
+    catch (SQLException ex)
+    {
+      throw new DBException(ex);
+    }
+    finally
+    {
+      DBUtil.close(resultSet);
+    }
+  }
+
+  protected final void readLists(IDBStoreAccessor accessor, InternalCDORevision revision, int listChunk)
+  {
+    for (IListMapping listMapping : listMappings)
+    {
+      listMapping.readValues(accessor, revision, listChunk);
+    }
+  }
+
+  protected final IMappingStrategy getMappingStrategy()
+  {
+    return mappingStrategy;
+  }
+
+  public final EClass getEClass()
+  {
+    return eClass;
+  }
+
+  protected final Map<EStructuralFeature, String> getUnsettableFields()
+  {
+    return unsettableFields;
+  }
+
+  protected final Map<EStructuralFeature, String> getListSizeFields()
+  {
+    return listSizeFields;
+  }
+
+  public final List<ITypeMapping> getValueMappings()
+  {
+    return valueMappings;
+  }
+
+  public final ITypeMapping getValueMapping(EStructuralFeature feature)
+  {
+    for (ITypeMapping mapping : valueMappings)
+    {
+      if (mapping.getFeature() == feature)
+      {
+        return mapping;
+      }
+    }
+
+    return null;
+  }
+
+  public final List<IListMapping> getListMappings()
+  {
+    return listMappings;
+  }
+
+  public final IListMapping getListMapping(EStructuralFeature feature)
+  {
+    for (IListMapping mapping : listMappings)
+    {
+      if (mapping.getFeature() == feature)
+      {
+        return mapping;
+      }
+    }
+
+    throw new IllegalArgumentException("List mapping for feature " + feature + " does not exist"); //$NON-NLS-1$ //$NON-NLS-2$
+  }
+
+  protected final IDBTable getTable()
+  {
+    return table;
+  }
+
+  public List<IDBTable> getDBTables()
+  {
+    List<IDBTable> tables = new ArrayList<IDBTable>();
+    tables.add(table);
+
+    for (IListMapping listMapping : listMappings)
+    {
+      tables.addAll(listMapping.getDBTables());
+    }
+
+    return tables;
+  }
+
+  protected void checkDuplicateResources(IDBStoreAccessor accessor, CDORevision revision) throws IllegalStateException
+  {
+    CDOID folderID = (CDOID)revision.data().getContainerID();
+    String name = (String)revision.data().get(EresourcePackage.eINSTANCE.getCDOResourceNode_Name(), 0);
+    CDOID existingID = accessor.readResourceID(folderID, name, revision.getBranch().getHead());
+    if (existingID != null && !existingID.equals(revision.getID()))
+    {
+      throw new IllegalStateException("Duplicate resource or folder: " + name + " in folder " + folderID); //$NON-NLS-1$ //$NON-NLS-2$
+    }
+  }
+
+  protected void writeLists(IDBStoreAccessor accessor, InternalCDORevision revision)
+  {
+    for (IListMapping listMapping : listMappings)
+    {
+      listMapping.writeValues(accessor, revision);
+    }
+  }
+
+  public void writeRevision(IDBStoreAccessor accessor, InternalCDORevision revision, boolean mapType, boolean revise,
+      OMMonitor monitor)
+  {
+    Async async = null;
+    monitor.begin(10);
+
+    try
+    {
+      try
+      {
+        async = monitor.forkAsync();
+        CDOID id = revision.getID();
+        if (mapType)
+        {
+          long timeStamp = revision.getTimeStamp();
+          mappingStrategy.putObjectType(accessor, timeStamp, id, eClass);
+        }
+        else if (revise)
+        {
+          long revised = revision.getTimeStamp() - 1;
+          reviseOldRevision(accessor, id, revision.getBranch(), revised);
+          for (IListMapping mapping : getListMappings())
+          {
+            mapping.objectDetached(accessor, id, revised);
+          }
+        }
+      }
+      finally
+      {
+        if (async != null)
+        {
+          async.stop();
+        }
+      }
+
+      try
+      {
+        async = monitor.forkAsync();
+        if (revision.isResourceFolder() || revision.isResource())
+        {
+          checkDuplicateResources(accessor, revision);
+        }
+      }
+      finally
+      {
+        if (async != null)
+        {
+          async.stop();
+        }
+      }
+
+      try
+      {
+        // Write attribute table always (even without modeled attributes!)
+        async = monitor.forkAsync();
+        writeValues(accessor, revision);
+      }
+      finally
+      {
+        if (async != null)
+        {
+          async.stop();
+        }
+      }
+
+      try
+      {
+        // Write list tables only if they exist
+        if (listMappings != null)
+        {
+          async = monitor.forkAsync(7);
+          writeLists(accessor, revision);
+        }
+        else
+        {
+          monitor.worked(7);
+        }
+      }
+      finally
+      {
+        if (async != null)
+        {
+          async.stop();
+        }
+      }
+    }
+    finally
+    {
+      monitor.done();
+    }
+  }
+
+  public void handleRevisions(IDBStoreAccessor accessor, CDOBranch branch, long timeStamp, boolean exactTime,
+      CDORevisionHandler handler)
+  {
+    // branch parameter is ignored, because either it is null or main branch.
+    // this does not make any difference for non-branching store.
+    // see #handleRevisions() implementation in HorizontalBranchingClassMapping
+    // for branch handling.
+
+    IRepository repository = accessor.getStore().getRepository();
+    CDORevisionManager revisionManager = repository.getRevisionManager();
+    CDOBranchManager branchManager = repository.getBranchManager();
+
+    IIDHandler idHandler = getMappingStrategy().getStore().getIDHandler();
+    IPreparedStatementCache statementCache = accessor.getStatementCache();
+    PreparedStatement stmt = null;
+    ResultSet resultSet = null;
+
+    // TODO: test for timeStamp == INVALID_TIME and encode revision.isValid() as WHERE instead of fetching all revisions
+    // in order to increase performance
+
+    StringBuilder builder = new StringBuilder(sqlSelectForHandle);
+
+    int timeParameters = 0;
+    if (timeStamp != CDOBranchPoint.INVALID_DATE)
+    {
+      if (exactTime)
+      {
+        if (timeStamp != CDOBranchPoint.UNSPECIFIED_DATE)
+        {
+          builder.append(" WHERE "); //$NON-NLS-1$
+          builder.append(CDODBSchema.ATTRIBUTES_CREATED);
+          builder.append("=?"); //$NON-NLS-1$
+          timeParameters = 1;
+        }
+      }
+      else
+      {
+        builder.append(" WHERE "); //$NON-NLS-1$
+        if (timeStamp != CDOBranchPoint.UNSPECIFIED_DATE)
+        {
+          builder.append(CDODBSchema.ATTRIBUTES_CREATED);
+          builder.append(">=?"); //$NON-NLS-1$
+          builder.append(" AND ("); //$NON-NLS-1$
+          builder.append(CDODBSchema.ATTRIBUTES_REVISED);
+          builder.append("<=? OR "); //$NON-NLS-1$
+          builder.append(CDODBSchema.ATTRIBUTES_REVISED);
+          builder.append("="); //$NON-NLS-1$
+          builder.append(CDOBranchPoint.UNSPECIFIED_DATE);
+          builder.append(")"); //$NON-NLS-1$
+          timeParameters = 2;
+        }
+        else
+        {
+          builder.append(CDODBSchema.ATTRIBUTES_REVISED);
+          builder.append("="); //$NON-NLS-1$
+          builder.append(CDOBranchPoint.UNSPECIFIED_DATE);
+        }
+      }
+    }
+
+    try
+    {
+      stmt = statementCache.getPreparedStatement(builder.toString(), ReuseProbability.LOW);
+      for (int i = 0; i < timeParameters; i++)
+      {
+        stmt.setLong(i + 1, timeStamp);
+      }
+
+      resultSet = stmt.executeQuery();
+      while (resultSet.next())
+      {
+        CDOID id = idHandler.getCDOID(resultSet, 1);
+        int version = resultSet.getInt(2);
+
+        if (version >= CDOBranchVersion.FIRST_VERSION)
+        {
+          InternalCDORevision revision = (InternalCDORevision)revisionManager.getRevisionByVersion(id, branchManager
+              .getMainBranch().getVersion(version), CDORevision.UNCHUNKED, true);
+
+          if (!handler.handleRevision(revision))
+          {
+            break;
+          }
+        }
+      }
+    }
+    catch (SQLException e)
+    {
+      throw new DBException(e);
+    }
+    finally
+    {
+      DBUtil.close(resultSet);
+      statementCache.releasePreparedStatement(stmt);
+    }
+  }
+
+  public Set<CDOID> readChangeSet(IDBStoreAccessor accessor, CDOChangeSetSegment[] segments)
+  {
+    StringBuilder builder = new StringBuilder(sqlSelectForChangeSet);
+    boolean isFirst = true;
+
+    for (int i = 0; i < segments.length; i++)
+    {
+      if (isFirst)
+      {
+        isFirst = false;
+      }
+      else
+      {
+        builder.append(" OR "); //$NON-NLS-1$
+      }
+
+      builder.append(CDODBSchema.ATTRIBUTES_CREATED);
+      builder.append(">=?"); //$NON-NLS-1$
+      builder.append(" AND ("); //$NON-NLS-1$
+      builder.append(CDODBSchema.ATTRIBUTES_REVISED);
+      builder.append("<=? OR "); //$NON-NLS-1$
+      builder.append(CDODBSchema.ATTRIBUTES_REVISED);
+      builder.append("="); //$NON-NLS-1$
+      builder.append(CDOBranchPoint.UNSPECIFIED_DATE);
+      builder.append(")"); //$NON-NLS-1$
+    }
+
+    IIDHandler idHandler = getMappingStrategy().getStore().getIDHandler();
+    IPreparedStatementCache statementCache = accessor.getStatementCache();
+    PreparedStatement stmt = null;
+    ResultSet resultSet = null;
+
+    Set<CDOID> result = new HashSet<CDOID>();
+
+    try
+    {
+      stmt = statementCache.getPreparedStatement(builder.toString(), ReuseProbability.LOW);
+      int column = 1;
+      for (CDOChangeSetSegment segment : segments)
+      {
+        stmt.setLong(column++, segment.getTimeStamp());
+        stmt.setLong(column++, segment.getEndTime());
+      }
+
+      resultSet = stmt.executeQuery();
+      while (resultSet.next())
+      {
+        CDOID id = idHandler.getCDOID(resultSet, 1);
+        result.add(id);
+      }
+
+      return result;
+    }
+    catch (SQLException e)
+    {
+      throw new DBException(e);
+    }
+    finally
+    {
+      DBUtil.close(resultSet);
+      statementCache.releasePreparedStatement(stmt);
+    }
+  }
+
+  public void detachObject(IDBStoreAccessor accessor, CDOID id, int version, CDOBranch branch, long timeStamp,
+      OMMonitor monitor)
+  {
+    Async async = null;
+    monitor.begin(1 + listMappings.size());
+
+    try
+    {
+      if (version >= CDOBranchVersion.FIRST_VERSION)
+      {
+        reviseOldRevision(accessor, id, branch, timeStamp - 1);
+      }
+
+      detachAttributes(accessor, id, version + 1, branch, timeStamp, monitor.fork());
+
+      // notify list mappings so they can clean up
+      for (IListMapping mapping : getListMappings())
+      {
+        try
+        {
+          async = monitor.forkAsync();
+          mapping.objectDetached(accessor, id, timeStamp);
+        }
+        finally
+        {
+          if (async != null)
+          {
+            async.stop();
+          }
+        }
+      }
+    }
+    finally
+    {
+      monitor.done();
+    }
+  }
+
+  public final boolean queryXRefs(IDBStoreAccessor accessor, QueryXRefsContext context, String idString)
+  {
+    String tableName = getTable().getName();
+    EClass eClass = getEClass();
+    List<EReference> refs = context.getSourceCandidates().get(eClass);
+    List<EReference> scalarRefs = new ArrayList<EReference>();
+
+    for (EReference ref : refs)
+    {
+      if (ref.isMany())
+      {
+        IListMapping listMapping = getListMapping(ref);
+        String where = getListXRefsWhere(context);
+
+        boolean more = listMapping.queryXRefs(accessor, tableName, where, context, idString);
+        if (!more)
+        {
+          return false;
+        }
+      }
+      else
+      {
+        scalarRefs.add(ref);
+      }
+    }
+
+    if (!scalarRefs.isEmpty())
+    {
+      boolean more = queryScalarXRefs(accessor, scalarRefs, context, idString);
+      if (!more)
+      {
+        return false;
+      }
+    }
+
+    return true;
+  }
+
+  protected final boolean queryScalarXRefs(IDBStoreAccessor accessor, List<EReference> scalarRefs,
+      QueryXRefsContext context, String idString)
+  {
+    String tableName = getTable().getName();
+    String where = getListXRefsWhere(context);
+
+    for (EReference ref : scalarRefs)
+    {
+      ITypeMapping valueMapping = getValueMapping(ref);
+      String valueField = valueMapping.getField().getName();
+
+      StringBuilder builder = new StringBuilder();
+      builder.append("SELECT ");
+      builder.append(CDODBSchema.ATTRIBUTES_ID);
+      builder.append(", ");
+      builder.append(valueField);
+      builder.append(" FROM ");
+      builder.append(tableName);
+      builder.append(" WHERE ");
+      builder.append(CDODBSchema.ATTRIBUTES_VERSION);
+      builder.append(">0 AND ");
+      builder.append(where);
+      builder.append(" AND ");
+      builder.append(valueField);
+      builder.append(" IN ");
+      builder.append(idString);
+      String sql = builder.toString();
+
+      IIDHandler idHandler = getMappingStrategy().getStore().getIDHandler();
+      ResultSet resultSet = null;
+      Statement stmt = null;
+
+      try
+      {
+        stmt = accessor.getConnection().createStatement();
+        if (TRACER.isEnabled())
+        {
+          TRACER.format("Query XRefs (attributes): {0}", sql);
+        }
+
+        resultSet = stmt.executeQuery(sql);
+        while (resultSet.next())
+        {
+          CDOID sourceID = idHandler.getCDOID(resultSet, 1);
+          CDOID targetID = idHandler.getCDOID(resultSet, 2);
+
+          boolean more = context.addXRef(targetID, sourceID, ref, 0);
+          if (TRACER.isEnabled())
+          {
+            TRACER.format("  add XRef to context: src={0}, tgt={1}, idx=0", sourceID, targetID);
+          }
+
+          if (!more)
+          {
+            if (TRACER.isEnabled())
+            {
+              TRACER.format("  result limit reached. Ignoring further results.");
+            }
+
+            return false;
+          }
+        }
+      }
+      catch (SQLException ex)
+      {
+        throw new DBException(ex);
+      }
+      finally
+      {
+        DBUtil.close(resultSet);
+        DBUtil.close(stmt);
+      }
+    }
+
+    return true;
+  }
+
+  protected abstract String getListXRefsWhere(QueryXRefsContext context);
+
+  protected abstract void detachAttributes(IDBStoreAccessor accessor, CDOID id, int version, CDOBranch branch,
+      long timeStamp, OMMonitor fork);
+
+  protected abstract void reviseOldRevision(IDBStoreAccessor accessor, CDOID id, CDOBranch branch, long timeStamp);
+
+  protected abstract void writeValues(IDBStoreAccessor accessor, InternalCDORevision revision);
+}
diff --git a/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/AbstractHorizontalMappingStrategy.java b/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/AbstractHorizontalMappingStrategy.java
new file mode 100644
index 0000000..7a9cd33
--- /dev/null
+++ b/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/AbstractHorizontalMappingStrategy.java
@@ -0,0 +1,480 @@
+/**
+ * Copyright (c) 2004 - 2011 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 - 271444: [DB] Multiple refactorings bug 271444
+ */
+package org.eclipse.emf.cdo.server.internal.db.mapping.horizontal;
+
+import org.eclipse.emf.cdo.common.CDOCommonRepository.IDGenerationLocation;
+import org.eclipse.emf.cdo.common.id.CDOID;
+import org.eclipse.emf.cdo.common.model.CDOClassifierRef;
+import org.eclipse.emf.cdo.common.protocol.CDODataInput;
+import org.eclipse.emf.cdo.common.protocol.CDODataOutput;
+import org.eclipse.emf.cdo.common.revision.CDORevision;
+import org.eclipse.emf.cdo.eresource.CDOResourceNode;
+import org.eclipse.emf.cdo.eresource.EresourcePackage;
+import org.eclipse.emf.cdo.server.IStoreAccessor.QueryResourcesContext;
+import org.eclipse.emf.cdo.server.IStoreAccessor.QueryXRefsContext;
+import org.eclipse.emf.cdo.server.db.IDBStore;
+import org.eclipse.emf.cdo.server.db.IDBStoreAccessor;
+import org.eclipse.emf.cdo.server.db.IIDHandler;
+import org.eclipse.emf.cdo.server.db.mapping.IClassMapping;
+import org.eclipse.emf.cdo.server.db.mapping.IListMapping;
+import org.eclipse.emf.cdo.server.internal.db.CDODBSchema;
+import org.eclipse.emf.cdo.server.internal.db.IObjectTypeMapper;
+import org.eclipse.emf.cdo.server.internal.db.bundle.OM;
+import org.eclipse.emf.cdo.server.internal.db.mapping.AbstractMappingStrategy;
+
+import org.eclipse.net4j.db.DBException;
+import org.eclipse.net4j.db.DBUtil;
+import org.eclipse.net4j.db.IDBAdapter;
+import org.eclipse.net4j.db.ddl.IDBTable;
+import org.eclipse.net4j.util.lifecycle.LifecycleUtil;
+import org.eclipse.net4j.util.om.monitor.OMMonitor;
+import org.eclipse.net4j.util.om.trace.ContextTracer;
+
+import org.eclipse.emf.ecore.EClass;
+
+import java.io.IOException;
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * * This abstract base class refines {@link AbstractMappingStrategy} by implementing aspects common to horizontal
+ * mapping strategies -- namely:
+ * <ul>
+ * <li>object type cache (table cdo_objects)
+ * <li>resource query handling
+ * </ul>
+ * 
+ * @author Eike Stepper
+ * @since 2.0
+ */
+public abstract class AbstractHorizontalMappingStrategy extends AbstractMappingStrategy
+{
+  private static final ContextTracer TRACER = new ContextTracer(OM.DEBUG, AbstractHorizontalMappingStrategy.class);
+
+  /**
+   * The associated object type mapper.
+   */
+  private IObjectTypeMapper objectTypeMapper;
+
+  public CDOClassifierRef readObjectType(IDBStoreAccessor accessor, CDOID id)
+  {
+    return objectTypeMapper.getObjectType(accessor, id);
+  }
+
+  public void putObjectType(IDBStoreAccessor accessor, long timeStamp, CDOID id, EClass type)
+  {
+    objectTypeMapper.putObjectType(accessor, timeStamp, id, type);
+  }
+
+  public void repairAfterCrash(IDBAdapter dbAdapter, Connection connection)
+  {
+    IDBStore store = getStore();
+    if (store.getRepository().getIDGenerationLocation() == IDGenerationLocation.STORE)
+    {
+      IIDHandler idHandler = store.getIDHandler();
+
+      CDOID minLocalID = getMinLocalID(connection);
+      idHandler.setNextLocalObjectID(minLocalID);
+
+      CDOID maxID = objectTypeMapper.getMaxID(connection, idHandler);
+      idHandler.setLastObjectID(maxID);
+    }
+  }
+
+  public void queryResources(IDBStoreAccessor accessor, QueryResourcesContext context)
+  {
+    // only support timestamp in audit mode
+    if (context.getTimeStamp() != CDORevision.UNSPECIFIED_DATE && !hasAuditSupport())
+    {
+      throw new IllegalArgumentException("Mapping Strategy does not support audits"); //$NON-NLS-1$
+    }
+
+    EresourcePackage resourcesPackage = EresourcePackage.eINSTANCE;
+
+    // first query folders
+    IClassMapping resourceFolder = getClassMapping(resourcesPackage.getCDOResourceFolder());
+    boolean shallContinue = queryResources(accessor, resourceFolder, context);
+
+    // not enough results? -> query resources
+    if (shallContinue)
+    {
+      IClassMapping resource = getClassMapping(resourcesPackage.getCDOResource());
+      queryResources(accessor, resource, context);
+    }
+  }
+
+  public void queryXRefs(IDBStoreAccessor accessor, QueryXRefsContext context)
+  {
+    IIDHandler idHandler = getStore().getIDHandler();
+    StringBuilder builder = null;
+
+    // create a string containing "(id1,id2,...)"
+    // NOTE: this might not scale infinitely, because of dbms-dependent
+    // max size for SQL strings. But for now, it's the easiest way...
+    for (CDOID targetID : context.getTargetObjects().keySet())
+    {
+      // NOTE: currently no support for external references!
+      if (builder == null)
+      {
+        builder = new StringBuilder("(");
+      }
+      else
+      {
+        builder.append(",");
+      }
+
+      idHandler.appendCDOID(builder, targetID);
+    }
+
+    builder.append(")");
+    String idString = builder.toString();
+
+    for (EClass eClass : context.getSourceCandidates().keySet())
+    {
+      IClassMapping classMapping = getClassMapping(eClass);
+      boolean more = classMapping.queryXRefs(accessor, context, idString);
+      if (!more)
+      {
+        // cancel query (max results reached or user canceled)
+        return;
+      }
+    }
+  }
+
+  public void rawExport(IDBStoreAccessor accessor, CDODataOutput out, int fromBranchID, int toBranchID,
+      long fromCommitTime, long toCommitTime) throws IOException
+  {
+    StringBuilder builder = new StringBuilder();
+    builder.append(" WHERE a_t."); //$NON-NLS-1$
+    builder.append(CDODBSchema.ATTRIBUTES_CREATED);
+    builder.append(" BETWEEN "); //$NON-NLS-1$
+    builder.append(fromCommitTime);
+    builder.append(" AND "); //$NON-NLS-1$
+    builder.append(toCommitTime);
+
+    String attrSuffix = builder.toString();
+    Connection connection = accessor.getConnection();
+
+    Collection<IClassMapping> classMappings = getClassMappings(true).values();
+    out.writeInt(classMappings.size());
+
+    for (IClassMapping classMapping : classMappings)
+    {
+      EClass eClass = classMapping.getEClass();
+      out.writeCDOClassifierRef(eClass);
+
+      IDBTable table = classMapping.getDBTables().get(0);
+      DBUtil.serializeTable(out, connection, table, "a_t", attrSuffix);
+
+      for (IListMapping listMapping : classMapping.getListMappings())
+      {
+        rawExportList(out, connection, listMapping, table, attrSuffix);
+      }
+    }
+
+    objectTypeMapper.rawExport(connection, out, fromCommitTime, toCommitTime);
+  }
+
+  protected void rawExportList(CDODataOutput out, Connection connection, IListMapping listMapping, IDBTable attrTable,
+      String attrSuffix) throws IOException
+  {
+    for (IDBTable table : listMapping.getDBTables())
+    {
+      String listSuffix = ", " + attrTable + " a_t" + attrSuffix;
+      String listJoin = getListJoin("a_t", "l_t");
+      if (listJoin != null)
+      {
+        listSuffix += listJoin;
+      }
+
+      DBUtil.serializeTable(out, connection, table, "l_t", listSuffix);
+    }
+  }
+
+  public void rawImport(IDBStoreAccessor accessor, CDODataInput in, long fromCommitTime, long toCommitTime,
+      OMMonitor monitor) throws IOException
+  {
+    int size = in.readInt();
+    if (size == 0)
+    {
+      return;
+    }
+
+    int objectTypeMapperWork = 10;
+    monitor.begin(3 * size + objectTypeMapperWork);
+
+    try
+    {
+      Connection connection = accessor.getConnection();
+      for (int i = 0; i < size; i++)
+      {
+        EClass eClass = (EClass)in.readCDOClassifierRefAndResolve();
+        IClassMapping classMapping = getClassMapping(eClass);
+
+        IDBTable table = classMapping.getDBTables().get(0);
+        DBUtil.deserializeTable(in, connection, table, monitor.fork());
+        rawImportReviseOldRevisions(connection, table, monitor.fork());
+        rawImportUnreviseNewRevisions(connection, table, fromCommitTime, toCommitTime, monitor.fork());
+
+        List<IListMapping> listMappings = classMapping.getListMappings();
+        int listSize = listMappings.size();
+        if (listSize == 0)
+        {
+          monitor.worked();
+        }
+        else
+        {
+          OMMonitor listMonitor = monitor.fork();
+          listMonitor.begin(listSize);
+
+          try
+          {
+            for (IListMapping listMapping : listMappings)
+            {
+              rawImportList(in, connection, listMapping, listMonitor.fork());
+            }
+          }
+          finally
+          {
+            listMonitor.done();
+          }
+        }
+      }
+
+      objectTypeMapper.rawImport(connection, in, monitor.fork(objectTypeMapperWork));
+    }
+    finally
+    {
+      monitor.done();
+    }
+  }
+
+  protected void rawImportUnreviseNewRevisions(Connection connection, IDBTable table, long fromCommitTime,
+      long toCommitTime, OMMonitor monitor)
+  {
+    throw new UnsupportedOperationException("Must be overridden");
+  }
+
+  protected void rawImportReviseOldRevisions(Connection connection, IDBTable table, OMMonitor monitor)
+  {
+    throw new UnsupportedOperationException("Must be overridden");
+  }
+
+  protected void rawImportList(CDODataInput in, Connection connection, IListMapping listMapping, OMMonitor monitor)
+      throws IOException
+  {
+    Collection<IDBTable> tables = listMapping.getDBTables();
+    int size = tables.size();
+    if (size == 0)
+    {
+      return;
+    }
+
+    monitor.begin(size);
+
+    try
+    {
+      for (IDBTable table : tables)
+      {
+        DBUtil.deserializeTable(in, connection, table, monitor.fork());
+      }
+    }
+    finally
+    {
+      monitor.done();
+    }
+  }
+
+  public String getListJoin(String attrTable, String listTable)
+  {
+    return " AND " + attrTable + "." + CDODBSchema.ATTRIBUTES_ID + "=" + listTable + "." + CDODBSchema.LIST_REVISION_ID;
+  }
+
+  @Override
+  protected boolean isMapped(EClass eClass)
+  {
+    return !eClass.isAbstract() && !eClass.isInterface();
+  }
+
+  @Override
+  protected Collection<EClass> getClassesWithObjectInfo()
+  {
+    return getClassMappings().keySet();
+  }
+
+  @Override
+  protected void doActivate() throws Exception
+  {
+    super.doActivate();
+    if (objectTypeMapper == null)
+    {
+      objectTypeMapper = createObjectTypeMapper();
+    }
+
+    LifecycleUtil.activate(objectTypeMapper);
+  }
+
+  @Override
+  protected void doDeactivate() throws Exception
+  {
+    LifecycleUtil.deactivate(objectTypeMapper);
+    super.doDeactivate();
+  }
+
+  private IObjectTypeMapper createObjectTypeMapper()
+  {
+    ObjectTypeTable table = new ObjectTypeTable();
+    table.setMappingStrategy(this);
+
+    int cacheSize = getObjectTypeCacheSize();
+    if (cacheSize == 0)
+    {
+      return table;
+    }
+
+    ObjectTypeCache cache = new ObjectTypeCache(cacheSize);
+    cache.setMappingStrategy(this);
+    cache.setDelegate(table);
+    return cache;
+  }
+
+  private int getObjectTypeCacheSize()
+  {
+    int objectTypeCacheSize = ObjectTypeCache.DEFAULT_CACHE_CAPACITY;
+
+    Object value = getProperties().get(PROP_OBJECT_TYPE_CACHE_SIZE);
+    if (value != null)
+    {
+      try
+      {
+        int intValue = Integer.parseInt((String)value);
+        objectTypeCacheSize = intValue;
+      }
+      catch (NumberFormatException e)
+      {
+        OM.LOG.warn("Malformed configuration option for object type cache size. Using default.");
+      }
+    }
+
+    return objectTypeCacheSize;
+  }
+
+  /**
+   * This is an intermediate implementation. It should be changed after classmappings support a general way to implement
+   * queries ...
+   * 
+   * @param accessor
+   *          the accessor to use.
+   * @param classMapping
+   *          the class mapping of a class instanceof {@link CDOResourceNode} which should be queried.
+   * @param context
+   *          the query context containing the parameters and the result.
+   * @return <code>true</code> if result context is not yet full and query should continue false, if result context is
+   *         full and query should stop.
+   */
+  private boolean queryResources(IDBStoreAccessor accessor, IClassMapping classMapping, QueryResourcesContext context)
+  {
+    IIDHandler idHandler = getStore().getIDHandler();
+    PreparedStatement stmt = null;
+    ResultSet resultSet = null;
+
+    CDOID folderID = context.getFolderID();
+    String name = context.getName();
+    boolean exactMatch = context.exactMatch();
+
+    try
+    {
+      stmt = classMapping.createResourceQueryStatement(accessor, folderID, name, exactMatch, context);
+      resultSet = stmt.executeQuery();
+
+      while (resultSet.next())
+      {
+        CDOID id = idHandler.getCDOID(resultSet, 1);
+        if (TRACER.isEnabled())
+        {
+          TRACER.trace("Resource query returned ID " + id); //$NON-NLS-1$
+        }
+
+        if (!context.addResource(id))
+        {
+          // No more results allowed
+          return false; // don't continue
+        }
+      }
+
+      return true; // continue with other results
+    }
+    catch (SQLException ex)
+    {
+      throw new DBException(ex);
+    }
+    finally
+    {
+      DBUtil.close(resultSet);
+      accessor.getStatementCache().releasePreparedStatement(stmt);
+    }
+  }
+
+  private CDOID getMinLocalID(Connection connection)
+  {
+    IIDHandler idHandler = getStore().getIDHandler();
+    CDOID min = idHandler.getMaxCDOID();
+
+    // Do not call getClassMappings() at this point, as the package registry is not yet initialized!
+    String dbName = getStore().getRepository().getName();
+    List<String> names = DBUtil.getAllTableNames(connection, dbName);
+
+    String prefix = "SELECT MIN(t." + CDODBSchema.ATTRIBUTES_ID + ") FROM " + dbName + "." + CDODBSchema.CDO_OBJECTS
+        + " AS o, " + dbName + ".";
+
+    String suffix = " AS t WHERE t." + CDODBSchema.ATTRIBUTES_BRANCH + "<0 AND t." + CDODBSchema.ATTRIBUTES_ID + "=o."
+        + CDODBSchema.ATTRIBUTES_ID + " AND t." + CDODBSchema.ATTRIBUTES_CREATED + "=o."
+        + CDODBSchema.ATTRIBUTES_CREATED;
+
+    for (String name : names)
+    {
+      Statement stmt = null;
+      ResultSet resultSet = null;
+
+      try
+      {
+        stmt = connection.createStatement();
+        resultSet = stmt.executeQuery(prefix + name + suffix);
+
+        if (resultSet.next())
+        {
+          CDOID id = idHandler.getCDOID(resultSet, 1);
+          if (id != null && idHandler.compare(id, min) < 0)
+          {
+            min = id;
+          }
+        }
+      }
+      catch (SQLException ex)
+      {
+        //$FALL-THROUGH$
+      }
+      finally
+      {
+        DBUtil.close(resultSet);
+        DBUtil.close(stmt);
+      }
+    }
+
+    return min;
+  }
+}
diff --git a/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/AbstractListTableMapping.java b/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/AbstractListTableMapping.java
new file mode 100644
index 0000000..9ca17b9
--- /dev/null
+++ b/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/AbstractListTableMapping.java
@@ -0,0 +1,485 @@
+/**
+ * Copyright (c) 2004 - 2011 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 283998: [DB] Chunk reading for multiple chunks fails
+ *    Stefan Winkler - Bug 329025: [DB] Support branching for range-based mapping strategy
+ */
+package org.eclipse.emf.cdo.server.internal.db.mapping.horizontal;
+
+import org.eclipse.emf.cdo.common.id.CDOID;
+import org.eclipse.emf.cdo.common.revision.CDOList;
+import org.eclipse.emf.cdo.common.revision.CDORevision;
+import org.eclipse.emf.cdo.server.IStoreAccessor.QueryXRefsContext;
+import org.eclipse.emf.cdo.server.IStoreChunkReader.Chunk;
+import org.eclipse.emf.cdo.server.db.IDBStoreAccessor;
+import org.eclipse.emf.cdo.server.db.IDBStoreChunkReader;
+import org.eclipse.emf.cdo.server.db.IIDHandler;
+import org.eclipse.emf.cdo.server.db.IPreparedStatementCache;
+import org.eclipse.emf.cdo.server.db.IPreparedStatementCache.ReuseProbability;
+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.spi.common.revision.InternalCDORevision;
+
+import org.eclipse.net4j.db.DBException;
+import org.eclipse.net4j.db.DBType;
+import org.eclipse.net4j.db.DBUtil;
+import org.eclipse.net4j.db.ddl.IDBField;
+import org.eclipse.net4j.db.ddl.IDBIndex.Type;
+import org.eclipse.net4j.db.ddl.IDBTable;
+import org.eclipse.net4j.util.collection.MoveableList;
+import org.eclipse.net4j.util.om.trace.ContextTracer;
+
+import org.eclipse.emf.ecore.EClass;
+import org.eclipse.emf.ecore.EReference;
+import org.eclipse.emf.ecore.EStructuralFeature;
+
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * This abstract base class provides basic behavior needed for mapping many-valued attributes to tables.
+ * 
+ * @author Eike Stepper
+ * @since 2.0
+ */
+public abstract class AbstractListTableMapping extends BasicAbstractListTableMapping
+{
+  private static final ContextTracer TRACER = new ContextTracer(OM.DEBUG, AbstractListTableMapping.class);
+
+  /**
+   * The table of this mapping.
+   */
+  private IDBTable table;
+
+  /**
+   * The type mapping for the value field.
+   */
+  private ITypeMapping typeMapping;
+
+  // --------- SQL strings - see initSQLStrings() -----------------
+  private String sqlSelectChunksPrefix;
+
+  private String sqlOrderByIndex;
+
+  private String sqlInsertEntry;
+
+  public AbstractListTableMapping(IMappingStrategy mappingStrategy, EClass eClass, EStructuralFeature feature)
+  {
+    super(mappingStrategy, eClass, feature);
+    initTable();
+    initSQLStrings();
+  }
+
+  private void initTable()
+  {
+    IMappingStrategy mappingStrategy = getMappingStrategy();
+    String tableName = mappingStrategy.getTableName(getContainingClass(), getFeature());
+    table = mappingStrategy.getStore().getDBSchema().addTable(tableName);
+
+    // add fields for keys (cdo_id, version, feature_id)
+    FieldInfo[] fields = getKeyFields();
+    IDBField[] dbFields = new IDBField[fields.length + 1];
+
+    for (int i = 0; i < fields.length; i++)
+    {
+      dbFields[i] = table.addField(fields[i].getName(), fields[i].getDbType());
+    }
+
+    // add field for list index
+    dbFields[dbFields.length - 1] = table.addField(CDODBSchema.LIST_IDX, DBType.INTEGER);
+
+    // add field for value
+    typeMapping = mappingStrategy.createValueMapping(getFeature());
+    typeMapping.createDBField(table, CDODBSchema.LIST_VALUE);
+
+    // add table indexes
+    table.addIndex(Type.UNIQUE, dbFields);
+  }
+
+  protected abstract FieldInfo[] getKeyFields();
+
+  protected abstract void setKeyFields(PreparedStatement stmt, CDORevision revision) throws SQLException;
+
+  public Collection<IDBTable> getDBTables()
+  {
+    return Arrays.asList(table);
+  }
+
+  private void initSQLStrings()
+  {
+    String tableName = getTable().getName();
+    FieldInfo[] fields = getKeyFields();
+
+    // ---------------- SELECT to read chunks ----------------------------
+    StringBuilder builder = new StringBuilder();
+    builder.append("SELECT "); //$NON-NLS-1$
+    builder.append(CDODBSchema.LIST_VALUE);
+    builder.append(" FROM "); //$NON-NLS-1$
+    builder.append(tableName);
+    builder.append(" WHERE "); //$NON-NLS-1$
+
+    for (int i = 0; i < fields.length; i++)
+    {
+      builder.append(fields[i].getName());
+      if (i + 1 < fields.length)
+      {
+        // more to come
+        builder.append("=? AND "); //$NON-NLS-1$
+      }
+      else
+      {
+        // last one
+        builder.append("=? "); //$NON-NLS-1$
+      }
+    }
+
+    sqlSelectChunksPrefix = builder.toString();
+
+    sqlOrderByIndex = " ORDER BY " + CDODBSchema.LIST_IDX; //$NON-NLS-1$
+
+    // ----------------- INSERT - reference entry -----------------
+    builder = new StringBuilder("INSERT INTO "); //$NON-NLS-1$
+    builder.append(tableName);
+    builder.append("("); //$NON-NLS-1$
+
+    for (int i = 0; i < fields.length; i++)
+    {
+      builder.append(fields[i].getName());
+      builder.append(", "); //$NON-NLS-1$
+    }
+
+    builder.append(CDODBSchema.LIST_IDX);
+    builder.append(", "); //$NON-NLS-1$
+    builder.append(CDODBSchema.LIST_VALUE);
+    builder.append(") VALUES ("); //$NON-NLS-1$
+    for (int i = 0; i < fields.length; i++)
+    {
+      builder.append("?, "); //$NON-NLS-1$
+    }
+
+    builder.append(" ?, ?)"); //$NON-NLS-1$
+    sqlInsertEntry = builder.toString();
+  }
+
+  protected final IDBTable getTable()
+  {
+    return table;
+  }
+
+  protected final ITypeMapping getTypeMapping()
+  {
+    return typeMapping;
+  }
+
+  public void readValues(IDBStoreAccessor accessor, InternalCDORevision revision, int listChunk)
+  {
+    MoveableList<Object> list = revision.getList(getFeature());
+
+    if (listChunk == 0 || list.size() == 0)
+    {
+      // nothing to read take shortcut
+      return;
+    }
+
+    if (TRACER.isEnabled())
+    {
+      TRACER.format("Reading list values for feature {0}.{1} of {2}v{3}", getContainingClass().getName(), //$NON-NLS-1$
+          getFeature().getName(), revision.getID(), revision.getVersion());
+    }
+
+    IPreparedStatementCache statementCache = accessor.getStatementCache();
+    PreparedStatement stmt = null;
+    ResultSet resultSet = null;
+
+    try
+    {
+      String sql = sqlSelectChunksPrefix + sqlOrderByIndex;
+      stmt = statementCache.getPreparedStatement(sql, ReuseProbability.HIGH);
+      setKeyFields(stmt, revision);
+
+      if (TRACER.isEnabled())
+      {
+        TRACER.trace(stmt.toString());
+      }
+
+      if (listChunk != CDORevision.UNCHUNKED)
+      {
+        stmt.setMaxRows(listChunk); // optimization - don't read unneeded rows.
+      }
+
+      resultSet = stmt.executeQuery();
+
+      int currentIndex = 0;
+      while ((listChunk == CDORevision.UNCHUNKED || --listChunk >= 0) && resultSet.next())
+      {
+        Object value = typeMapping.readValue(resultSet);
+        if (TRACER.isEnabled())
+        {
+          TRACER.format("Read value for index {0} from result set: {1}", list.size(), value); //$NON-NLS-1$
+        }
+
+        list.set(currentIndex++, value);
+      }
+    }
+    catch (SQLException ex)
+    {
+      throw new DBException(ex);
+    }
+    finally
+    {
+      DBUtil.close(resultSet);
+      statementCache.releasePreparedStatement(stmt);
+    }
+
+    if (TRACER.isEnabled())
+    {
+      TRACER.format("Reading list values done for feature {0}.{1} of {2}v{3}", getContainingClass().getName(), //$NON-NLS-1$
+          getFeature().getName(), revision.getID(), revision.getVersion());
+    }
+  }
+
+  public final void readChunks(IDBStoreChunkReader chunkReader, List<Chunk> chunks, String where)
+  {
+    if (TRACER.isEnabled())
+    {
+      TRACER.format("Reading list chunk values for feature {0}.{1} of {2}v{3}", getContainingClass().getName(), //$NON-NLS-1$
+          getFeature().getName(), chunkReader.getRevision().getID(), chunkReader.getRevision().getVersion());
+    }
+
+    IPreparedStatementCache statementCache = chunkReader.getAccessor().getStatementCache();
+    PreparedStatement stmt = null;
+    ResultSet resultSet = null;
+
+    try
+    {
+      StringBuilder builder = new StringBuilder(sqlSelectChunksPrefix);
+      if (where != null)
+      {
+        builder.append(" AND "); //$NON-NLS-1$
+        builder.append(where);
+      }
+
+      builder.append(sqlOrderByIndex);
+
+      String sql = builder.toString();
+      stmt = statementCache.getPreparedStatement(sql, ReuseProbability.LOW);
+      setKeyFields(stmt, chunkReader.getRevision());
+
+      resultSet = stmt.executeQuery();
+
+      Chunk chunk = null;
+      int chunkSize = 0;
+      int chunkIndex = 0;
+      int indexInChunk = 0;
+
+      while (resultSet.next())
+      {
+        Object value = typeMapping.readValue(resultSet);
+
+        if (chunk == null)
+        {
+          chunk = chunks.get(chunkIndex++);
+          chunkSize = chunk.size();
+
+          if (TRACER.isEnabled())
+          {
+            TRACER.format("Current chunk no. {0} is [start = {1}, size = {2}]", chunkIndex - 1, chunk.getStartIndex(), //$NON-NLS-1$
+                chunkSize);
+          }
+        }
+
+        if (TRACER.isEnabled())
+        {
+          TRACER.format("Read value for chunk index {0} from result set: {1}", indexInChunk, value); //$NON-NLS-1$
+        }
+
+        chunk.add(indexInChunk++, value);
+        if (indexInChunk == chunkSize)
+        {
+          if (TRACER.isEnabled())
+          {
+            TRACER.format("Chunk finished"); //$NON-NLS-1$
+          }
+
+          chunk = null;
+          indexInChunk = 0;
+        }
+      }
+
+      if (TRACER.isEnabled())
+      {
+        TRACER.format("Reading list chunk values done for feature {0}.{1} of {2}v{3}", getContainingClass().getName(), //$NON-NLS-1$
+            getFeature().getName(), chunkReader.getRevision().getID(), chunkReader.getRevision().getVersion());
+      }
+    }
+    catch (SQLException ex)
+    {
+      throw new DBException(ex);
+    }
+    finally
+    {
+      DBUtil.close(resultSet);
+      statementCache.releasePreparedStatement(stmt);
+    }
+  }
+
+  public void writeValues(IDBStoreAccessor accessor, InternalCDORevision revision)
+  {
+    CDOList values = revision.getList(getFeature());
+
+    int idx = 0;
+    for (Object element : values)
+    {
+      writeValue(accessor, revision, idx++, element);
+    }
+  }
+
+  protected final void writeValue(IDBStoreAccessor accessor, CDORevision revision, int idx, Object value)
+  {
+    IPreparedStatementCache statementCache = accessor.getStatementCache();
+    PreparedStatement stmt = null;
+
+    if (TRACER.isEnabled())
+    {
+      TRACER.format("Writing value for feature {0}.{1} index {2} of {3}v{4} : {5}", getContainingClass().getName(),
+          getFeature().getName(), idx, revision.getID(), revision.getVersion(), value);
+    }
+
+    try
+    {
+      stmt = statementCache.getPreparedStatement(sqlInsertEntry, ReuseProbability.HIGH);
+
+      setKeyFields(stmt, revision);
+      int column = getKeyFields().length + 1;
+      stmt.setInt(column++, idx);
+      typeMapping.setValue(stmt, column++, value);
+
+      DBUtil.update(stmt, true);
+    }
+    catch (SQLException e)
+    {
+      throw new DBException(e);
+    }
+    finally
+    {
+      statementCache.releasePreparedStatement(stmt);
+    }
+  }
+
+  public boolean queryXRefs(IDBStoreAccessor accessor, String mainTableName, String mainTableWhere,
+      QueryXRefsContext context, String idString)
+  {
+    String tableName = getTable().getName();
+    String listJoin = getMappingStrategy().getListJoin("a_t", "l_t");
+
+    StringBuilder builder = new StringBuilder();
+    builder.append("SELECT l_t."); //$NON-NLS-1$
+    builder.append(CDODBSchema.LIST_REVISION_ID);
+    builder.append(", l_t."); //$NON-NLS-1$
+    builder.append(CDODBSchema.LIST_VALUE);
+    builder.append(", l_t."); //$NON-NLS-1$
+    builder.append(CDODBSchema.LIST_IDX);
+    builder.append(" FROM "); //$NON-NLS-1$
+    builder.append(tableName);
+    builder.append(" AS l_t, ");//$NON-NLS-1$
+    builder.append(mainTableName);
+    builder.append(" AS a_t WHERE ");//$NON-NLS-1$
+    builder.append("a_t." + mainTableWhere);//$NON-NLS-1$
+    builder.append(listJoin);
+    builder.append(" AND "); //$NON-NLS-1$
+    builder.append(CDODBSchema.LIST_VALUE);
+    builder.append(" IN "); //$NON-NLS-1$
+    builder.append(idString);
+    String sql = builder.toString();
+
+    IIDHandler idHandler = getMappingStrategy().getStore().getIDHandler();
+    ResultSet resultSet = null;
+    Statement stmt = null;
+
+    try
+    {
+      stmt = accessor.getConnection().createStatement();
+      if (TRACER.isEnabled())
+      {
+        TRACER.format("Query XRefs (list): {0}", sql);
+      }
+
+      resultSet = stmt.executeQuery(sql);
+      while (resultSet.next())
+      {
+        CDOID srcId = idHandler.getCDOID(resultSet, 1);
+        CDOID targetId = idHandler.getCDOID(resultSet, 2);
+        int idx = resultSet.getInt(3);
+
+        boolean more = context.addXRef(targetId, srcId, (EReference)getFeature(), idx);
+        if (TRACER.isEnabled())
+        {
+          TRACER.format("  add XRef to context: src={0}, tgt={1}, idx={2}", srcId, targetId, idx);
+        }
+
+        if (!more)
+        {
+          if (TRACER.isEnabled())
+          {
+            TRACER.format("  result limit reached. Ignoring further results.");
+          }
+
+          return false;
+        }
+      }
+
+      return true;
+    }
+    catch (SQLException ex)
+    {
+      throw new DBException(ex);
+    }
+    finally
+    {
+      DBUtil.close(resultSet);
+      DBUtil.close(stmt);
+    }
+  }
+
+  /**
+   * Used by subclasses to indicate which fields should be in the table. I.e. just a pair of name and DBType ...
+   * 
+   * @author Stefan Winkler
+   */
+  protected static class FieldInfo
+  {
+    private String name;
+
+    private DBType dbType;
+
+    public FieldInfo(String name, DBType dbType)
+    {
+      this.name = name;
+      this.dbType = dbType;
+    }
+
+    public String getName()
+    {
+      return name;
+    }
+
+    public DBType getDbType()
+    {
+      return dbType;
+    }
+  }
+}
diff --git a/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/AbstractObjectTypeMapper.java b/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/AbstractObjectTypeMapper.java
new file mode 100644
index 0000000..d24e223
--- /dev/null
+++ b/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/AbstractObjectTypeMapper.java
@@ -0,0 +1,69 @@
+/**
+ * Copyright (c) 2004 - 2011 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 259402
+ *    Stefan Winkler - redesign (prepared statements)
+ *    Stefan Winkler - bug 276926
+ */
+package org.eclipse.emf.cdo.server.internal.db.mapping.horizontal;
+
+import org.eclipse.emf.cdo.server.db.IMetaDataManager;
+import org.eclipse.emf.cdo.server.db.mapping.IMappingStrategy;
+import org.eclipse.emf.cdo.server.internal.db.IObjectTypeMapper;
+
+import org.eclipse.net4j.util.lifecycle.Lifecycle;
+
+/**
+ * @author Eike Stepper
+ * @since 4.0
+ */
+public abstract class AbstractObjectTypeMapper extends Lifecycle implements IObjectTypeMapper
+{
+  private IMappingStrategy mappingStrategy;
+
+  private IMetaDataManager metaDataManager;
+
+  public AbstractObjectTypeMapper()
+  {
+  }
+
+  public IMappingStrategy getMappingStrategy()
+  {
+    return mappingStrategy;
+  }
+
+  public void setMappingStrategy(IMappingStrategy mappingStrategy)
+  {
+    this.mappingStrategy = mappingStrategy;
+  }
+
+  public IMetaDataManager getMetaDataManager()
+  {
+    return metaDataManager;
+  }
+
+  @Override
+  protected void doBeforeActivate() throws Exception
+  {
+    super.doBeforeActivate();
+    checkState(mappingStrategy, "mappingStrategy"); //$NON-NLS-1$
+  }
+
+  @Override
+  protected void doActivate() throws Exception
+  {
+    metaDataManager = getMappingStrategy().getStore().getMetaDataManager();
+  }
+
+  @Override
+  protected void doDeactivate() throws Exception
+  {
+    metaDataManager = null;
+  }
+}
diff --git a/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/AuditFeatureMapTableMapping.java b/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/AuditFeatureMapTableMapping.java
new file mode 100644
index 0000000..a9c7adc
--- /dev/null
+++ b/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/AuditFeatureMapTableMapping.java
@@ -0,0 +1,68 @@
+/**
+ * Copyright (c) 2004 - 2011 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 - 271444: [DB] Multiple refactorings bug 271444
+ *    Christopher Albert - 254455: [DB] Support FeatureMaps bug 254455  
+ */
+package org.eclipse.emf.cdo.server.internal.db.mapping.horizontal;
+
+import org.eclipse.emf.cdo.common.id.CDOID;
+import org.eclipse.emf.cdo.common.revision.CDORevision;
+import org.eclipse.emf.cdo.server.db.IDBStoreAccessor;
+import org.eclipse.emf.cdo.server.db.mapping.IMappingStrategy;
+import org.eclipse.emf.cdo.server.internal.db.CDODBSchema;
+
+import org.eclipse.net4j.db.DBType;
+
+import org.eclipse.emf.ecore.EClass;
+import org.eclipse.emf.ecore.EStructuralFeature;
+
+import java.sql.PreparedStatement;
+import java.sql.SQLException;
+
+/**
+ * This is a featuremap-table mapping for audit mode. It has ID and version columns and no delta support.
+ * 
+ * @author Eike Stepper
+ * @since 3.0
+ */
+public class AuditFeatureMapTableMapping extends AbstractFeatureMapTableMapping
+{
+  private FieldInfo[] keyFields;
+
+  public AuditFeatureMapTableMapping(IMappingStrategy mappingStrategy, EClass eClass, EStructuralFeature feature)
+  {
+    super(mappingStrategy, eClass, feature);
+  }
+
+  @Override
+  protected FieldInfo[] getKeyFields()
+  {
+    if (keyFields == null)
+    {
+      keyFields = new FieldInfo[] {
+          new FieldInfo(CDODBSchema.FEATUREMAP_REVISION_ID, getMappingStrategy().getStore().getIDHandler().getDBType()),
+          new FieldInfo(CDODBSchema.FEATUREMAP_VERSION, DBType.INTEGER) };
+    }
+
+    return keyFields;
+  }
+
+  @Override
+  protected void setKeyFields(PreparedStatement stmt, CDORevision revision) throws SQLException
+  {
+    getMappingStrategy().getStore().getIDHandler().setCDOID(stmt, 1, revision.getID());
+    stmt.setInt(2, revision.getVersion());
+  }
+
+  public void objectDetached(IDBStoreAccessor accessor, CDOID id, long revised)
+  {
+    // the audit list mapping does not care about revised references -> NOP
+  }
+}
diff --git a/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/AuditFeatureMapTableMappingWithRanges.java b/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/AuditFeatureMapTableMappingWithRanges.java
new file mode 100644
index 0000000..150fc06
--- /dev/null
+++ b/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/AuditFeatureMapTableMappingWithRanges.java
@@ -0,0 +1,1212 @@
+/**
+ * Copyright (c) 2004 - 2011 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 bug 271444
+ *    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 - Bug 285426: [DB] Implement user-defined typeMapping support
+ *    Stefan Winkler - Bug 329025: [DB] Support branching for range-based mapping strategy
+ */
+package org.eclipse.emf.cdo.server.internal.db.mapping.horizontal;
+
+import org.eclipse.emf.cdo.common.branch.CDOBranch;
+import org.eclipse.emf.cdo.common.id.CDOID;
+import org.eclipse.emf.cdo.common.revision.CDOList;
+import org.eclipse.emf.cdo.common.revision.CDORevision;
+import org.eclipse.emf.cdo.common.revision.CDORevisionUtil;
+import org.eclipse.emf.cdo.common.revision.delta.CDOAddFeatureDelta;
+import org.eclipse.emf.cdo.common.revision.delta.CDOClearFeatureDelta;
+import org.eclipse.emf.cdo.common.revision.delta.CDOContainerFeatureDelta;
+import org.eclipse.emf.cdo.common.revision.delta.CDOFeatureDelta;
+import org.eclipse.emf.cdo.common.revision.delta.CDOFeatureDeltaVisitor;
+import org.eclipse.emf.cdo.common.revision.delta.CDOListFeatureDelta;
+import org.eclipse.emf.cdo.common.revision.delta.CDOMoveFeatureDelta;
+import org.eclipse.emf.cdo.common.revision.delta.CDORemoveFeatureDelta;
+import org.eclipse.emf.cdo.common.revision.delta.CDOSetFeatureDelta;
+import org.eclipse.emf.cdo.common.revision.delta.CDOUnsetFeatureDelta;
+import org.eclipse.emf.cdo.server.IRepository;
+import org.eclipse.emf.cdo.server.IStoreAccessor.QueryXRefsContext;
+import org.eclipse.emf.cdo.server.IStoreChunkReader.Chunk;
+import org.eclipse.emf.cdo.server.db.IDBStore;
+import org.eclipse.emf.cdo.server.db.IDBStoreAccessor;
+import org.eclipse.emf.cdo.server.db.IDBStoreChunkReader;
+import org.eclipse.emf.cdo.server.db.IIDHandler;
+import org.eclipse.emf.cdo.server.db.IPreparedStatementCache;
+import org.eclipse.emf.cdo.server.db.IPreparedStatementCache.ReuseProbability;
+import org.eclipse.emf.cdo.server.db.mapping.IListMappingDeltaSupport;
+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.spi.common.revision.InternalCDORevision;
+
+import org.eclipse.net4j.db.DBException;
+import org.eclipse.net4j.db.DBType;
+import org.eclipse.net4j.db.DBUtil;
+import org.eclipse.net4j.db.ddl.IDBField;
+import org.eclipse.net4j.db.ddl.IDBIndex.Type;
+import org.eclipse.net4j.db.ddl.IDBTable;
+import org.eclipse.net4j.util.ImplementationError;
+import org.eclipse.net4j.util.collection.MoveableList;
+import org.eclipse.net4j.util.om.trace.ContextTracer;
+
+import org.eclipse.emf.ecore.EClass;
+import org.eclipse.emf.ecore.EStructuralFeature;
+import org.eclipse.emf.ecore.util.FeatureMap;
+
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * This is a featuremap-table mapping for audit mode. It is optimized for frequent insert operations at the list's end,
+ * which causes just 1 DB row to be changed. This is achieved by introducing a version range (columns
+ * {@link CDODBSchema#LIST_REVISION_VERSION_ADDED cdo_version_added} and
+ * {@link CDODBSchema#LIST_REVISION_VERSION_REMOVED cdo_version_removed}) which records for which revisions a particular
+ * entry existed. Also, this mapping is mainly optimized for potentially very large lists: the need for having the
+ * complete list stored in memory to do in-the-middle-moved and inserts is traded in for a few more DB access
+ * operations.
+ * 
+ * @author Eike Stepper
+ * @author Stefan Winkler
+ * @author Lothar Werzinger
+ * @since 3.0
+ */
+public class AuditFeatureMapTableMappingWithRanges extends BasicAbstractListTableMapping implements
+    IListMappingDeltaSupport
+{
+  private static final ContextTracer TRACER = new ContextTracer(OM.DEBUG, AuditFeatureMapTableMappingWithRanges.class);
+
+  /**
+   * Used to clean up lists for detached objects.
+   */
+  private static final int FINAL_VERSION = Integer.MAX_VALUE;
+
+  /**
+   * The table of this mapping.
+   */
+  private IDBTable table;
+
+  /**
+   * The tags mapped to column names
+   */
+  private HashMap<CDOID, String> tagMap;
+
+  /**
+   * Column name Set
+   */
+  private List<String> columnNames;
+
+  /**
+   * The type mappings for the value fields.
+   */
+  private Map<CDOID, ITypeMapping> typeMappings;
+
+  private List<DBType> dbTypes;
+
+  // --------- SQL strings - see initSQLStrings() -----------------
+
+  private String sqlSelectChunksPrefix;
+
+  private String sqlOrderByIndex;
+
+  private String sqlInsert;
+
+  private String sqlRemoveEntry;
+
+  private String sqlDeleteEntry;
+
+  private String sqlUpdateIndex;
+
+  private String sqlGetValue;
+
+  private String sqlClearList;
+
+  private String sqlDeleteList;
+
+  public AuditFeatureMapTableMappingWithRanges(IMappingStrategy mappingStrategy, EClass eClass,
+      EStructuralFeature feature)
+  {
+    super(mappingStrategy, eClass, feature);
+    initDBTypes();
+    initTable();
+    initSQLStrings();
+  }
+
+  private void initDBTypes()
+  {
+    // TODO add annotation processing here ...
+    ITypeMapping.Registry registry = ITypeMapping.Registry.INSTANCE;
+    dbTypes = new ArrayList<DBType>(registry.getDefaultFeatureMapDBTypes());
+  }
+
+  private void initTable()
+  {
+    IDBStore store = getMappingStrategy().getStore();
+    String tableName = getMappingStrategy().getTableName(getContainingClass(), getFeature());
+    table = store.getDBSchema().addTable(tableName);
+
+    // add fields for CDOID
+    IDBField idField = table.addField(CDODBSchema.FEATUREMAP_REVISION_ID, store.getIDHandler().getDBType());
+
+    // add fields for version range
+    IDBField versionAddedField = table.addField(CDODBSchema.FEATUREMAP_VERSION_ADDED, DBType.INTEGER);
+    IDBField versionRemovedField = table.addField(CDODBSchema.FEATUREMAP_VERSION_REMOVED, DBType.INTEGER);
+
+    // add field for list index
+    IDBField idxField = table.addField(CDODBSchema.FEATUREMAP_IDX, DBType.INTEGER);
+
+    // add field for FeatureMap tag (MetaID for Feature in CDO registry)
+    IDBField tagField = table.addField(CDODBSchema.FEATUREMAP_TAG, store.getIDHandler().getDBType());
+
+    tagMap = new HashMap<CDOID, String>();
+    typeMappings = new HashMap<CDOID, ITypeMapping>();
+    columnNames = new ArrayList<String>();
+
+    // create columns for all DBTypes
+    for (DBType type : getDBTypes())
+    {
+      String column = CDODBSchema.FEATUREMAP_VALUE + "_" + type.name();
+      table.addField(column, type);
+      columnNames.add(column);
+    }
+
+    // TODO think about indices
+    table.addIndex(Type.NON_UNIQUE, idField);
+    table.addIndex(Type.NON_UNIQUE, versionAddedField);
+    table.addIndex(Type.NON_UNIQUE, versionRemovedField);
+    table.addIndex(Type.NON_UNIQUE, idxField);
+    table.addIndex(Type.NON_UNIQUE, tagField);
+  }
+
+  private void initSQLStrings()
+  {
+    String tableName = getTable().getName();
+
+    // ---------------- SELECT to read chunks ----------------------------
+    StringBuilder builder = new StringBuilder();
+    builder.append("SELECT "); //$NON-NLS-1$
+
+    builder.append(CDODBSchema.FEATUREMAP_TAG);
+    builder.append(", "); //$NON-NLS-1$
+
+    Iterator<String> iter = columnNames.iterator();
+    while (iter.hasNext())
+    {
+      builder.append(iter.next());
+      if (iter.hasNext())
+      {
+        builder.append(", "); //$NON-NLS-1$
+      }
+    }
+
+    builder.append(" FROM "); //$NON-NLS-1$
+    builder.append(tableName);
+    builder.append(" WHERE "); //$NON-NLS-1$
+    builder.append(CDODBSchema.FEATUREMAP_REVISION_ID);
+    builder.append("=? AND "); //$NON-NLS-1$
+    builder.append(CDODBSchema.FEATUREMAP_VERSION_ADDED);
+    builder.append("<=? AND ("); //$NON-NLS-1$
+    builder.append(CDODBSchema.FEATUREMAP_VERSION_REMOVED);
+    builder.append(" IS NULL OR "); //$NON-NLS-1$
+    builder.append(CDODBSchema.FEATUREMAP_VERSION_REMOVED);
+    builder.append(">?)"); //$NON-NLS-1$
+    sqlSelectChunksPrefix = builder.toString();
+
+    sqlOrderByIndex = " ORDER BY " + CDODBSchema.FEATUREMAP_IDX; //$NON-NLS-1$
+
+    // ----------------- INSERT - prefix -----------------
+    builder = new StringBuilder("INSERT INTO "); //$NON-NLS-1$
+    builder.append(tableName);
+    builder.append("("); //$NON-NLS-1$
+    builder.append(CDODBSchema.FEATUREMAP_REVISION_ID);
+    builder.append(", "); //$NON-NLS-1$
+    builder.append(CDODBSchema.FEATUREMAP_VERSION_ADDED);
+    builder.append(", "); //$NON-NLS-1$
+    builder.append(CDODBSchema.FEATUREMAP_VERSION_REMOVED);
+    builder.append(", "); //$NON-NLS-1$
+    builder.append(CDODBSchema.FEATUREMAP_IDX);
+    builder.append(", "); //$NON-NLS-1$
+    builder.append(CDODBSchema.FEATUREMAP_TAG);
+
+    for (int i = 0; i < columnNames.size(); i++)
+    {
+      builder.append(", "); //$NON-NLS-1$
+      builder.append(columnNames.get(i));
+    }
+
+    builder.append(") VALUES (?, ?, ?, ?, ?"); //$NON-NLS-1$
+    for (int i = 0; i < columnNames.size(); i++)
+    {
+      builder.append(", ?"); //$NON-NLS-1$
+    }
+
+    builder.append(")"); //$NON-NLS-1$
+    sqlInsert = builder.toString();
+
+    // ----------------- remove current entry -----------------
+    builder = new StringBuilder("UPDATE "); //$NON-NLS-1$
+    builder.append(tableName);
+    builder.append(" SET "); //$NON-NLS-1$
+    builder.append(CDODBSchema.FEATUREMAP_VERSION_REMOVED);
+    builder.append("=? "); //$NON-NLS-1$
+    builder.append(" WHERE "); //$NON-NLS-1$
+    builder.append(CDODBSchema.FEATUREMAP_REVISION_ID);
+    builder.append("=? AND "); //$NON-NLS-1$
+    builder.append(CDODBSchema.FEATUREMAP_IDX);
+    builder.append("=? AND "); //$NON-NLS-1$
+    builder.append(CDODBSchema.FEATUREMAP_VERSION_REMOVED);
+    builder.append(" IS NULL"); //$NON-NLS-1$
+    sqlRemoveEntry = builder.toString();
+
+    // ----------------- delete temporary entry -----------------
+    builder = new StringBuilder("DELETE FROM "); //$NON-NLS-1$
+    builder.append(tableName);
+    builder.append(" WHERE "); //$NON-NLS-1$
+    builder.append(CDODBSchema.FEATUREMAP_REVISION_ID);
+    builder.append("=? AND "); //$NON-NLS-1$
+    builder.append(CDODBSchema.FEATUREMAP_IDX);
+    builder.append("=? AND "); //$NON-NLS-1$
+    builder.append(CDODBSchema.FEATUREMAP_VERSION_ADDED);
+    builder.append("=?"); //$NON-NLS-1$
+    sqlDeleteEntry = builder.toString();
+
+    // ----------------- update index -----------------
+    builder = new StringBuilder("UPDATE "); //$NON-NLS-1$
+    builder.append(tableName);
+    builder.append(" SET "); //$NON-NLS-1$
+    builder.append(CDODBSchema.FEATUREMAP_IDX);
+    builder.append("=? WHERE "); //$NON-NLS-1$
+    builder.append(CDODBSchema.FEATUREMAP_REVISION_ID);
+    builder.append("=? AND "); //$NON-NLS-1$
+    builder.append(CDODBSchema.FEATUREMAP_VERSION_ADDED);
+    builder.append("=? AND "); //$NON-NLS-1$
+    builder.append(CDODBSchema.FEATUREMAP_IDX);
+    builder.append("=?"); //$NON-NLS-1$
+    sqlUpdateIndex = builder.toString();
+
+    // ----------------- get current value -----------------
+    builder = new StringBuilder("SELECT "); //$NON-NLS-1$
+    builder.append(CDODBSchema.FEATUREMAP_TAG);
+    builder.append(", "); //$NON-NLS-1$
+
+    iter = columnNames.iterator();
+    while (iter.hasNext())
+    {
+      builder.append(iter.next());
+      if (iter.hasNext())
+      {
+        builder.append(", "); //$NON-NLS-1$
+      }
+    }
+
+    builder.append(" FROM "); //$NON-NLS-1$
+    builder.append(tableName);
+    builder.append(" WHERE "); //$NON-NLS-1$
+    builder.append(CDODBSchema.FEATUREMAP_REVISION_ID);
+    builder.append("=? AND "); //$NON-NLS-1$
+    builder.append(CDODBSchema.FEATUREMAP_IDX);
+    builder.append("=? AND "); //$NON-NLS-1$
+    builder.append(CDODBSchema.FEATUREMAP_VERSION_REMOVED);
+    builder.append(" IS NULL"); //$NON-NLS-1$
+    sqlGetValue = builder.toString();
+
+    // ----------- clear list items -------------------------
+    builder = new StringBuilder("UPDATE "); //$NON-NLS-1$
+    builder.append(tableName);
+    builder.append(" SET "); //$NON-NLS-1$
+    builder.append(CDODBSchema.FEATUREMAP_VERSION_REMOVED);
+    builder.append("=? "); //$NON-NLS-1$
+    builder.append(" WHERE "); //$NON-NLS-1$
+    builder.append(CDODBSchema.FEATUREMAP_REVISION_ID);
+    builder.append("=? AND "); //$NON-NLS-1$
+    builder.append(CDODBSchema.FEATUREMAP_VERSION_REMOVED);
+    builder.append(" IS NULL"); //$NON-NLS-1$
+    sqlClearList = builder.toString();
+
+    // ----------- delete temporary list items -------------------------
+    builder = new StringBuilder("DELETE FROM "); //$NON-NLS-1$
+    builder.append(tableName);
+    builder.append(" WHERE "); //$NON-NLS-1$
+    builder.append(CDODBSchema.FEATUREMAP_REVISION_ID);
+    builder.append("=? AND "); //$NON-NLS-1$
+    builder.append(CDODBSchema.FEATUREMAP_VERSION_ADDED);
+    builder.append("=? AND "); //$NON-NLS-1$
+    builder.append(CDODBSchema.FEATUREMAP_VERSION_REMOVED);
+    builder.append(" IS NULL"); //$NON-NLS-1$
+    sqlDeleteList = builder.toString();
+  }
+
+  protected List<DBType> getDBTypes()
+  {
+    return dbTypes;
+  }
+
+  public Collection<IDBTable> getDBTables()
+  {
+    return Arrays.asList(table);
+  }
+
+  protected final IDBTable getTable()
+  {
+    return table;
+  }
+
+  protected final List<String> getColumnNames()
+  {
+    return columnNames;
+  }
+
+  protected final Map<CDOID, ITypeMapping> getTypeMappings()
+  {
+    return typeMappings;
+  }
+
+  protected final Map<CDOID, String> getTagMap()
+  {
+    return tagMap;
+  }
+
+  public void readValues(IDBStoreAccessor accessor, InternalCDORevision revision, int listChunk)
+  {
+    MoveableList<Object> list = revision.getList(getFeature());
+
+    if (listChunk == 0 || list.size() == 0)
+    {
+      // nothing to read take shortcut
+      return;
+    }
+
+    if (TRACER.isEnabled())
+    {
+      TRACER.format("Reading list values for feature {0}.{1} of {2}v{3}", getContainingClass().getName(), getFeature() //$NON-NLS-1$
+          .getName(), revision.getID(), revision.getVersion());
+    }
+
+    IIDHandler idHandler = getMappingStrategy().getStore().getIDHandler();
+    IPreparedStatementCache statementCache = accessor.getStatementCache();
+    PreparedStatement stmt = null;
+    ResultSet resultSet = null;
+
+    try
+    {
+      String sql = sqlSelectChunksPrefix + sqlOrderByIndex;
+
+      stmt = statementCache.getPreparedStatement(sql, ReuseProbability.HIGH);
+
+      idHandler.setCDOID(stmt, 1, revision.getID());
+      stmt.setInt(2, revision.getVersion());
+      stmt.setInt(3, revision.getVersion());
+
+      if (listChunk != CDORevision.UNCHUNKED)
+      {
+        stmt.setMaxRows(listChunk); // optimization - don't read unneeded rows.
+      }
+
+      resultSet = stmt.executeQuery();
+
+      int currentIndex = 0;
+      while ((listChunk == CDORevision.UNCHUNKED || --listChunk >= 0) && resultSet.next())
+      {
+        CDOID tag = idHandler.getCDOID(resultSet, 1);
+        Object value = getTypeMapping(tag).readValue(resultSet);
+
+        if (TRACER.isEnabled())
+        {
+          TRACER.format("Read value for index {0} from result set: {1}", list.size(), value); //$NON-NLS-1$
+        }
+
+        list.set(currentIndex++, CDORevisionUtil.createFeatureMapEntry(getFeatureByTag(tag), value));
+      }
+    }
+    catch (SQLException ex)
+    {
+      throw new DBException(ex);
+    }
+    finally
+    {
+      DBUtil.close(resultSet);
+      statementCache.releasePreparedStatement(stmt);
+    }
+
+    if (TRACER.isEnabled())
+    {
+      TRACER.format("Reading list values done for feature {0}.{1} of {2}v{3}", getContainingClass().getName(), //$NON-NLS-1$
+          getFeature().getName(), revision.getID(), revision.getVersion());
+    }
+  }
+
+  private void addFeature(CDOID tag)
+  {
+    EStructuralFeature modelFeature = getFeatureByTag(tag);
+
+    ITypeMapping typeMapping = getMappingStrategy().createValueMapping(modelFeature);
+    String column = CDODBSchema.FEATUREMAP_VALUE + "_" + typeMapping.getDBType(); //$NON-NLS-1$
+
+    tagMap.put(tag, column);
+    typeMapping.setDBField(table, column);
+    typeMappings.put(tag, typeMapping);
+  }
+
+  public final void readChunks(IDBStoreChunkReader chunkReader, List<Chunk> chunks, String where)
+  {
+    if (TRACER.isEnabled())
+    {
+      TRACER.format("Reading list chunk values for feature {0}.{1} of {2}v{3}", getContainingClass().getName(), //$NON-NLS-1$
+          getFeature().getName(), chunkReader.getRevision().getID(), chunkReader.getRevision().getVersion());
+    }
+
+    IIDHandler idHandler = getMappingStrategy().getStore().getIDHandler();
+    IPreparedStatementCache statementCache = chunkReader.getAccessor().getStatementCache();
+    PreparedStatement stmt = null;
+    ResultSet resultSet = null;
+
+    try
+    {
+      StringBuilder builder = new StringBuilder(sqlSelectChunksPrefix);
+      if (where != null)
+      {
+        builder.append(" AND "); //$NON-NLS-1$
+        builder.append(where);
+      }
+
+      builder.append(sqlOrderByIndex);
+
+      String sql = builder.toString();
+      stmt = statementCache.getPreparedStatement(sql, ReuseProbability.LOW);
+      idHandler.setCDOID(stmt, 1, chunkReader.getRevision().getID());
+      stmt.setInt(2, chunkReader.getRevision().getVersion());
+      stmt.setInt(3, chunkReader.getRevision().getVersion());
+
+      resultSet = stmt.executeQuery();
+
+      Chunk chunk = null;
+      int chunkSize = 0;
+      int chunkIndex = 0;
+      int indexInChunk = 0;
+
+      while (resultSet.next())
+      {
+        CDOID tag = idHandler.getCDOID(resultSet, 1);
+        Object value = getTypeMapping(tag).readValue(resultSet);
+
+        if (chunk == null)
+        {
+          chunk = chunks.get(chunkIndex++);
+          chunkSize = chunk.size();
+
+          if (TRACER.isEnabled())
+          {
+            TRACER.format("Current chunk no. {0} is [start = {1}, size = {2}]", chunkIndex - 1, chunk.getStartIndex(), //$NON-NLS-1$
+                chunkSize);
+          }
+        }
+
+        if (TRACER.isEnabled())
+        {
+          TRACER.format("Read value for chunk index {0} from result set: {1}", indexInChunk, value); //$NON-NLS-1$
+        }
+
+        chunk.add(indexInChunk++, CDORevisionUtil.createFeatureMapEntry(getFeatureByTag(tag), value));
+        if (indexInChunk == chunkSize)
+        {
+          if (TRACER.isEnabled())
+          {
+            TRACER.format("Chunk finished"); //$NON-NLS-1$
+          }
+
+          chunk = null;
+          indexInChunk = 0;
+        }
+      }
+
+      if (TRACER.isEnabled())
+      {
+        TRACER.format("Reading list chunk values done for feature {0}.{1} of {2}", getContainingClass().getName(), //$NON-NLS-1$
+            getFeature(), chunkReader.getRevision());
+      }
+    }
+    catch (SQLException ex)
+    {
+      throw new DBException(ex);
+    }
+    finally
+    {
+      DBUtil.close(resultSet);
+      statementCache.releasePreparedStatement(stmt);
+    }
+  }
+
+  public void writeValues(IDBStoreAccessor accessor, InternalCDORevision revision)
+  {
+    CDOList values = revision.getList(getFeature());
+
+    int idx = 0;
+    for (Object element : values)
+    {
+      writeValue(accessor, revision, idx++, element);
+    }
+
+    if (TRACER.isEnabled())
+    {
+      TRACER.format("Writing done"); //$NON-NLS-1$
+    }
+  }
+
+  protected final void writeValue(IDBStoreAccessor accessor, CDORevision revision, int idx, Object value)
+  {
+    if (TRACER.isEnabled())
+    {
+      TRACER
+          .format(
+              "Writing value for feature {0}.{1} index {2} of {3} : {4}", getContainingClass().getName(), getFeature(), idx, revision, value); //$NON-NLS-1$
+    }
+
+    addEntry(accessor, revision.getID(), revision.getVersion(), idx, value, revision.getTimeStamp());
+  }
+
+  /**
+   * Get column name (lazy).
+   * 
+   * @param tag
+   *          The feature's MetaID in CDO
+   * @return the column name where the values are stored
+   */
+  protected String getColumnName(CDOID tag)
+  {
+    String column = tagMap.get(tag);
+    if (column == null)
+    {
+      addFeature(tag);
+      column = tagMap.get(tag);
+    }
+
+    return column;
+  }
+
+  /**
+   * Get type mapping (lazy).
+   * 
+   * @param tag
+   *          The feature's MetaID in CDO
+   * @return the corresponding type mapping
+   */
+  protected ITypeMapping getTypeMapping(CDOID tag)
+  {
+    ITypeMapping typeMapping = typeMappings.get(tag);
+    if (typeMapping == null)
+    {
+      addFeature(tag);
+      typeMapping = typeMappings.get(tag);
+    }
+
+    return typeMapping;
+  }
+
+  /**
+   * @param metaID
+   * @return the column name where the values are stored
+   */
+  private EStructuralFeature getFeatureByTag(CDOID tag)
+  {
+    return (EStructuralFeature)getMappingStrategy().getStore().getMetaDataManager().getMetaInstance(tag);
+  }
+
+  /**
+   * @param feature
+   *          The EStructuralFeature
+   * @return The feature's MetaID in CDO
+   */
+  protected CDOID getTagByFeature(EStructuralFeature feature, long timestamp)
+  {
+    return getMappingStrategy().getStore().getMetaDataManager().getMetaID(feature, timestamp);
+  }
+
+  /**
+   * Clear a list of a given revision.
+   * 
+   * @param accessor
+   *          the accessor to use
+   * @param id
+   *          the id of the revision from which to remove all items
+   */
+  public void clearList(IDBStoreAccessor accessor, CDOID id, int oldVersion, int newVersion)
+  {
+    IIDHandler idHandler = getMappingStrategy().getStore().getIDHandler();
+    IPreparedStatementCache statementCache = accessor.getStatementCache();
+    PreparedStatement stmtDeleteTemp = null;
+    PreparedStatement stmtClear = null;
+
+    try
+    {
+      // delete temporary entries
+      stmtDeleteTemp = statementCache.getPreparedStatement(sqlDeleteList, ReuseProbability.HIGH);
+      idHandler.setCDOID(stmtDeleteTemp, 1, id);
+      stmtDeleteTemp.setInt(2, newVersion);
+
+      int result = DBUtil.update(stmtDeleteTemp, false);
+      if (TRACER.isEnabled())
+      {
+        TRACER.format("DeleteList result: {0}", result); //$NON-NLS-1$
+      }
+
+      // clear rest of the list
+      stmtClear = statementCache.getPreparedStatement(sqlClearList, ReuseProbability.HIGH);
+      stmtClear.setInt(1, newVersion);
+      idHandler.setCDOID(stmtClear, 2, id);
+
+      result = DBUtil.update(stmtClear, false);
+      if (TRACER.isEnabled())
+      {
+        TRACER.format("ClearList result: {0}", result); //$NON-NLS-1$
+      }
+    }
+    catch (SQLException e)
+    {
+      throw new DBException(e);
+    }
+    finally
+    {
+      statementCache.releasePreparedStatement(stmtDeleteTemp);
+      statementCache.releasePreparedStatement(stmtClear);
+    }
+  }
+
+  public void objectDetached(IDBStoreAccessor accessor, CDOID id, long revised)
+  {
+    if (TRACER.isEnabled())
+    {
+      TRACER.format("objectRevised {0}: {1}", id, revised); //$NON-NLS-1$
+    }
+
+    CDOBranch main = getMappingStrategy().getStore().getRepository().getBranchManager().getMainBranch();
+
+    // get revision from cache to find out version number
+    CDORevision revision = getMappingStrategy().getStore().getRepository().getRevisionManager()
+        .getRevision(id, main.getHead(), /* chunksize = */0, CDORevision.DEPTH_NONE, true);
+
+    // set cdo_revision_removed for all list items (so we have no NULL values)
+    clearList(accessor, id, revision.getVersion(), FINAL_VERSION);
+  }
+
+  public void processDelta(final IDBStoreAccessor accessor, final CDOID id, final int branchId, int oldVersion,
+      final int newVersion, long created, CDOListFeatureDelta delta)
+  {
+    IRepository repo = accessor.getStore().getRepository();
+    InternalCDORevision originalRevision = (InternalCDORevision)repo.getRevisionManager().getRevision(id,
+        repo.getBranchManager().getMainBranch().getHead(), /* chunksize = */0, CDORevision.DEPTH_NONE, true);
+
+    int oldListSize = originalRevision.getList(getFeature()).size();
+
+    if (TRACER.isEnabled())
+    {
+      TRACER.format("ListTableMapping.processDelta for revision {0} - previous list size: {1}", originalRevision, //$NON-NLS-1$
+          oldListSize);
+    }
+
+    // let the visitor collect the changes
+    ListDeltaVisitor visitor = new ListDeltaVisitor(accessor, originalRevision, oldVersion, newVersion, created);
+
+    if (TRACER.isEnabled())
+    {
+      TRACER.format("Processing deltas..."); //$NON-NLS-1$
+    }
+
+    for (CDOFeatureDelta listDelta : delta.getListChanges())
+    {
+      listDelta.accept(visitor);
+    }
+  }
+
+  private class ListDeltaVisitor implements CDOFeatureDeltaVisitor
+  {
+    private IDBStoreAccessor accessor;
+
+    private InternalCDORevision originalRevision;
+
+    private CDOID id;
+
+    private int oldVersion;
+
+    private int newVersion;
+
+    private int lastIndex;
+
+    private long timestamp;
+
+    public ListDeltaVisitor(IDBStoreAccessor accessor, InternalCDORevision originalRevision, int oldVersion,
+        int newVersion, long timestamp)
+    {
+      this.accessor = accessor;
+      this.originalRevision = originalRevision;
+      id = this.originalRevision.getID();
+      this.oldVersion = oldVersion;
+      this.newVersion = newVersion;
+      lastIndex = originalRevision.getList(getFeature()).size() - 1;
+      this.timestamp = timestamp;
+    }
+
+    public void visit(CDOMoveFeatureDelta delta)
+    {
+      int fromIdx = delta.getOldPosition();
+      int toIdx = delta.getNewPosition();
+
+      if (TRACER.isEnabled())
+      {
+        TRACER.format("Delta Moving: {0} to {1}", fromIdx, toIdx); //$NON-NLS-1$
+      }
+
+      Object value = getValue(accessor, id, fromIdx);
+
+      // remove the item
+      removeEntry(accessor, id, oldVersion, newVersion, fromIdx);
+
+      // adjust indexes and shift either up or down
+      if (fromIdx < toIdx)
+      {
+        moveOneUp(accessor, id, oldVersion, newVersion, fromIdx + 1, toIdx);
+      }
+      else
+      { // fromIdx > toIdx here
+        moveOneDown(accessor, id, oldVersion, newVersion, toIdx, fromIdx - 1);
+      }
+
+      // cr