You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cayenne.apache.org by aa...@apache.org on 2016/09/29 17:39:01 UTC
[15/15] cayenne git commit: CAY-2116 Split schema synchronization
code in a separate module
CAY-2116 Split schema synchronization code in a separate module
Project: http://git-wip-us.apache.org/repos/asf/cayenne/repo
Commit: http://git-wip-us.apache.org/repos/asf/cayenne/commit/2f7b1d53
Tree: http://git-wip-us.apache.org/repos/asf/cayenne/tree/2f7b1d53
Diff: http://git-wip-us.apache.org/repos/asf/cayenne/diff/2f7b1d53
Branch: refs/heads/master
Commit: 2f7b1d53388883a2e341e9156bddd8d694f7ef88
Parents: 8c7bec0
Author: Andrus Adamchik <an...@objectstyle.com>
Authored: Thu Sep 29 20:33:54 2016 +0300
Committer: Andrus Adamchik <an...@objectstyle.com>
Committed: Thu Sep 29 20:38:29 2016 +0300
----------------------------------------------------------------------
assembly/pom.xml | 6 +
.../resources/assemblies/assembly-generic.xml | 1 +
.../main/resources/assemblies/assembly-mac.xml | 1 +
.../resources/assemblies/assembly-windows.xml | 1 +
cayenne-dbsync/pom.xml | 117 +++
.../cayenne/dbsync/CayenneDbSyncModule.java | 82 ++
.../cayenne/dbsync/merge/AbstractToDbToken.java | 126 +++
.../dbsync/merge/AbstractToModelToken.java | 122 +++
.../cayenne/dbsync/merge/AddColumnToDb.java | 65 ++
.../cayenne/dbsync/merge/AddColumnToModel.java | 55 ++
.../dbsync/merge/AddRelationshipToDb.java | 87 ++
.../dbsync/merge/AddRelationshipToModel.java | 95 +++
.../cayenne/dbsync/merge/CreateTableToDb.java | 66 ++
.../dbsync/merge/CreateTableToModel.java | 102 +++
.../apache/cayenne/dbsync/merge/DbMerger.java | 405 +++++++++
.../cayenne/dbsync/merge/DbMergerConfig.java | 63 ++
.../dbsync/merge/DefaultModelMergeDelegate.java | 89 ++
.../merge/DefaultValueForNullProvider.java | 62 ++
.../cayenne/dbsync/merge/DropColumnToDb.java | 52 ++
.../cayenne/dbsync/merge/DropColumnToModel.java | 75 ++
.../dbsync/merge/DropRelationshipToDb.java | 72 ++
.../dbsync/merge/DropRelationshipToModel.java | 51 ++
.../cayenne/dbsync/merge/DropTableToDb.java | 50 ++
.../cayenne/dbsync/merge/DropTableToModel.java | 49 ++
.../cayenne/dbsync/merge/DummyReverseToken.java | 60 ++
.../dbsync/merge/EmptyValueForNullProvider.java | 40 +
.../dbsync/merge/EntityMergeSupport.java | 522 ++++++++++++
.../cayenne/dbsync/merge/MergeDirection.java | 70 ++
.../cayenne/dbsync/merge/MergerContext.java | 118 +++
.../cayenne/dbsync/merge/MergerToken.java | 53 ++
.../dbsync/merge/ModelMergeDelegate.java | 62 ++
.../dbsync/merge/ProxyModelMergeDelegate.java | 108 +++
.../cayenne/dbsync/merge/SetAllowNullToDb.java | 57 ++
.../dbsync/merge/SetAllowNullToModel.java | 43 +
.../cayenne/dbsync/merge/SetColumnTypeToDb.java | 119 +++
.../dbsync/merge/SetColumnTypeToModel.java | 102 +++
.../cayenne/dbsync/merge/SetNotNullToDb.java | 51 ++
.../cayenne/dbsync/merge/SetNotNullToModel.java | 43 +
.../cayenne/dbsync/merge/SetPrimaryKeyToDb.java | 86 ++
.../dbsync/merge/SetPrimaryKeyToModel.java | 78 ++
.../dbsync/merge/SetValueForNullToDb.java | 47 ++
.../dbsync/merge/ValueForNullProvider.java | 42 +
.../merge/factory/DB2MergerTokenFactory.java | 47 ++
.../factory/DefaultMergerTokenFactory.java | 181 ++++
.../merge/factory/DerbyMergerTokenFactory.java | 85 ++
.../factory/FirebirdMergerTokenFactory.java | 91 ++
.../merge/factory/H2MergerTokenFactory.java | 82 ++
.../merge/factory/HSQLMergerTokenFactory.java | 82 ++
.../merge/factory/IngresMergerTokenFactory.java | 224 +++++
.../merge/factory/MergerTokenFactory.java | 88 ++
.../factory/MergerTokenFactoryProvider.java | 36 +
.../merge/factory/MySQLMergerTokenFactory.java | 156 ++++
.../factory/OpenBaseMergerTokenFactory.java | 143 ++++
.../merge/factory/OracleMergerTokenFactory.java | 111 +++
.../factory/PostgresMergerTokenFactory.java | 49 ++
.../factory/SQLServerMergerTokenFactory.java | 112 +++
.../merge/factory/SybaseMergerTokenFactory.java | 166 ++++
.../dbsync/reverse/DbAttributesBaseLoader.java | 107 +++
.../dbsync/reverse/DbAttributesLoader.java | 43 +
.../reverse/DbAttributesPerSchemaLoader.java | 130 +++
.../apache/cayenne/dbsync/reverse/DbLoader.java | 829 ++++++++++++++++++
.../dbsync/reverse/DbLoaderConfiguration.java | 150 ++++
.../dbsync/reverse/DbLoaderDelegate.java | 58 ++
.../cayenne/dbsync/reverse/DbTableLoader.java | 195 +++++
.../dbsync/reverse/DefaultDbLoaderDelegate.java | 59 ++
.../dbsync/reverse/FiltersConfigBuilder.java | 393 +++++++++
.../dbsync/reverse/LoggingDbLoaderDelegate.java | 76 ++
.../reverse/ManyToManyCandidateEntity.java | 142 ++++
.../cayenne/dbsync/reverse/NameFilter.java | 27 +
.../dbsync/reverse/NamePatternMatcher.java | 225 +++++
.../dbsync/reverse/filters/CatalogFilter.java | 62 ++
.../dbsync/reverse/filters/FiltersConfig.java | 81 ++
.../reverse/filters/IncludeTableFilter.java | 71 ++
.../filters/LegacyFilterConfigBridge.java | 150 ++++
.../dbsync/reverse/filters/PatternFilter.java | 169 ++++
.../dbsync/reverse/filters/SchemaFilter.java | 44 +
.../dbsync/reverse/filters/TableFilter.java | 133 +++
.../cayenne/dbsync/reverse/mapper/DbType.java | 194 +++++
.../mapper/DefaultJdbc2JavaTypeMapper.java | 282 +++++++
.../reverse/mapper/Jdbc2JavaTypeMapper.java | 33 +
.../dbsync/merge/AddColumnToModelIT.java | 98 +++
.../dbsync/merge/CreateTableToModelIT.java | 97 +++
.../cayenne/dbsync/merge/DbMergerTest.java | 261 ++++++
.../dbsync/merge/DropColumnToModelIT.java | 235 ++++++
.../dbsync/merge/DropRelationshipToModelIT.java | 188 +++++
.../dbsync/merge/DropTableToModelIT.java | 94 +++
.../dbsync/merge/EntityMergeSupportIT.java | 102 +++
.../apache/cayenne/dbsync/merge/MergeCase.java | 209 +++++
.../cayenne/dbsync/merge/MergerFactoryIT.java | 310 +++++++
.../dbsync/merge/SetAllowNullToDbIT.java | 66 ++
.../cayenne/dbsync/merge/SetNotNullToDbIT.java | 62 ++
.../dbsync/merge/SetPrimaryKeyToDbIT.java | 58 ++
.../cayenne/dbsync/merge/TokensReversTest.java | 89 ++
.../merge/TokensToModelExecutionTest.java | 80 ++
.../cayenne/dbsync/merge/ValueForNullIT.java | 127 +++
.../cayenne/dbsync/merge/builders/Builder.java | 38 +
.../dbsync/merge/builders/DataMapBuilder.java | 128 +++
.../merge/builders/DbAttributeBuilder.java | 115 +++
.../dbsync/merge/builders/DbEntityBuilder.java | 90 ++
.../merge/builders/DbRelationshipBuilder.java | 85 ++
.../dbsync/merge/builders/DefaultBuilder.java | 57 ++
.../merge/builders/ObjAttributeBuilder.java | 67 ++
.../dbsync/merge/builders/ObjEntityBuilder.java | 98 +++
.../dbsync/merge/builders/ObjectMother.java | 70 ++
.../cayenne/dbsync/reverse/DbLoaderIT.java | 430 ++++++++++
.../dbsync/reverse/DbLoaderPartialIT.java | 116 +++
.../reverse/FiltersConfigBuilderTest.java | 391 +++++++++
.../reverse/ManyToManyCandidateEntityTest.java | 113 +++
.../reverse/filters/FiltersConfigTest.java | 93 +++
.../reverse/filters/IncludeFilterTest.java | 34 +
.../reverse/filters/PatternFilterTest.java | 78 ++
.../dbsync/reverse/filters/TableFilterTest.java | 91 ++
.../dbsync/reverse/mapper/DbTypeTest.java | 87 ++
.../apache/cayenne/dbsync/unit/DbSyncCase.java | 57 ++
.../cayenne/dbsync/unit/DbSyncCaseModule.java | 38 +
.../unit/DbSyncServerRuntimeProvider.java | 50 ++
.../cayenne-relationship-optimisation.xml | 4 +
.../reverse/relationship-optimisation.map.xml | 43 +
.../org/apache/cayenne/access/DbLoader.java | 832 -------------------
.../apache/cayenne/access/DbLoaderDelegate.java | 58 --
.../access/loader/DbAttributesBaseLoader.java | 107 ---
.../access/loader/DbAttributesLoader.java | 43 -
.../loader/DbAttributesPerSchemaLoader.java | 130 ---
.../access/loader/DbLoaderConfiguration.java | 150 ----
.../cayenne/access/loader/DbTableLoader.java | 196 -----
.../access/loader/DefaultDbLoaderDelegate.java | 60 --
.../access/loader/LoggingDbLoaderDelegate.java | 76 --
.../loader/ManyToManyCandidateEntity.java | 142 ----
.../cayenne/access/loader/NameFilter.java | 27 -
.../access/loader/NamePatternMatcher.java | 225 -----
.../access/loader/filters/CatalogFilter.java | 62 --
.../access/loader/filters/FiltersConfig.java | 81 --
.../loader/filters/IncludeTableFilter.java | 71 --
.../filters/LegacyFilterConfigBridge.java | 150 ----
.../access/loader/filters/PatternFilter.java | 169 ----
.../access/loader/filters/SchemaFilter.java | 44 -
.../access/loader/filters/TableFilter.java | 133 ---
.../cayenne/access/loader/mapper/DbType.java | 194 -----
.../mapper/DefaultJdbc2JavaTypeMapper.java | 282 -------
.../loader/mapper/Jdbc2JavaTypeMapper.java | 33 -
.../org/apache/cayenne/dba/AutoAdapter.java | 6 -
.../java/org/apache/cayenne/dba/DbAdapter.java | 6 -
.../org/apache/cayenne/dba/JdbcAdapter.java | 14 +-
.../apache/cayenne/dba/PerAdapterProvider.java | 46 +
.../org/apache/cayenne/dba/db2/DB2Adapter.java | 13 +-
.../cayenne/dba/db2/DB2MergerFactory.java | 49 --
.../apache/cayenne/dba/derby/DerbyAdapter.java | 36 +-
.../cayenne/dba/derby/DerbyMergerFactory.java | 86 --
.../cayenne/dba/firebird/FirebirdAdapter.java | 6 +-
.../dba/firebird/FirebirdMergerFactory.java | 91 --
.../org/apache/cayenne/dba/h2/H2Adapter.java | 6 -
.../apache/cayenne/dba/h2/H2MergerFactory.java | 83 --
.../cayenne/dba/hsqldb/HSQLDBAdapter.java | 7 -
.../cayenne/dba/hsqldb/HSQLMergerFactory.java | 83 --
.../cayenne/dba/ingres/IngresAdapter.java | 6 -
.../cayenne/dba/ingres/IngresMergerFactory.java | 226 -----
.../apache/cayenne/dba/mysql/MySQLAdapter.java | 26 +-
.../cayenne/dba/mysql/MySQLMergerFactory.java | 157 ----
.../cayenne/dba/openbase/OpenBaseAdapter.java | 469 +++++------
.../dba/openbase/OpenBaseMergerFactory.java | 144 ----
.../cayenne/dba/oracle/OracleAdapter.java | 25 +-
.../cayenne/dba/oracle/OracleMergerFactory.java | 112 ---
.../cayenne/dba/postgres/PostgresAdapter.java | 6 -
.../dba/postgres/PostgresMergerFactory.java | 50 --
.../cayenne/dba/sqlserver/SQLServerAdapter.java | 6 -
.../dba/sqlserver/SQLServerMergerFactory.java | 114 ---
.../cayenne/dba/sybase/SybaseAdapter.java | 14 +-
.../cayenne/dba/sybase/SybaseMergerFactory.java | 167 ----
.../cayenne/dbimport/FiltersConfigBuilder.java | 383 ---------
.../apache/cayenne/merge/AbstractToDbToken.java | 126 ---
.../cayenne/merge/AbstractToModelToken.java | 122 ---
.../org/apache/cayenne/merge/AddColumnToDb.java | 64 --
.../apache/cayenne/merge/AddColumnToModel.java | 55 --
.../cayenne/merge/AddRelationshipToDb.java | 86 --
.../cayenne/merge/AddRelationshipToModel.java | 95 ---
.../apache/cayenne/merge/CreateTableToDb.java | 65 --
.../cayenne/merge/CreateTableToModel.java | 102 ---
.../java/org/apache/cayenne/merge/DbMerger.java | 405 ---------
.../apache/cayenne/merge/DbMergerConfig.java | 63 --
.../merge/DefaultModelMergeDelegate.java | 89 --
.../merge/DefaultValueForNullProvider.java | 62 --
.../apache/cayenne/merge/DropColumnToDb.java | 51 --
.../apache/cayenne/merge/DropColumnToModel.java | 74 --
.../cayenne/merge/DropRelationshipToDb.java | 71 --
.../cayenne/merge/DropRelationshipToModel.java | 50 --
.../org/apache/cayenne/merge/DropTableToDb.java | 49 --
.../apache/cayenne/merge/DropTableToModel.java | 48 --
.../apache/cayenne/merge/DummyReverseToken.java | 58 --
.../merge/EmptyValueForNullProvider.java | 40 -
.../apache/cayenne/merge/MergeDirection.java | 70 --
.../org/apache/cayenne/merge/MergerContext.java | 118 ---
.../org/apache/cayenne/merge/MergerFactory.java | 142 ----
.../org/apache/cayenne/merge/MergerToken.java | 51 --
.../cayenne/merge/ModelMergeDelegate.java | 65 --
.../cayenne/merge/ProxyModelMergeDelegate.java | 108 ---
.../apache/cayenne/merge/SetAllowNullToDb.java | 56 --
.../cayenne/merge/SetAllowNullToModel.java | 42 -
.../apache/cayenne/merge/SetColumnTypeToDb.java | 119 ---
.../cayenne/merge/SetColumnTypeToModel.java | 101 ---
.../apache/cayenne/merge/SetNotNullToDb.java | 50 --
.../apache/cayenne/merge/SetNotNullToModel.java | 42 -
.../apache/cayenne/merge/SetPrimaryKeyToDb.java | 85 --
.../cayenne/merge/SetPrimaryKeyToModel.java | 77 --
.../cayenne/merge/SetValueForNullToDb.java | 46 -
.../cayenne/merge/ValueForNullProvider.java | 42 -
.../apache/cayenne/util/EntityMergeSupport.java | 520 ------------
.../org/apache/cayenne/access/DbLoaderIT.java | 431 ----------
.../cayenne/access/DbLoaderPartialIT.java | 118 ---
.../loader/ManyToManyCandidateEntityTest.java | 113 ---
.../loader/filters/FiltersConfigTest.java | 93 ---
.../loader/filters/IncludeFilterTest.java | 34 -
.../loader/filters/PatternFilterTest.java | 78 --
.../access/loader/filters/TableFilterTest.java | 91 --
.../access/loader/mapper/DbTypeTest.java | 87 --
.../cayenne/dba/PerAdapterProviderTest.java | 83 ++
.../dbimport/FiltersConfigBuilderTest.java | 382 ---------
.../cayenne/merge/AddColumnToModelIT.java | 98 ---
.../cayenne/merge/CreateTableToModelIT.java | 97 ---
.../org/apache/cayenne/merge/DbMergerTest.java | 261 ------
.../cayenne/merge/DropColumnToModelIT.java | 235 ------
.../merge/DropRelationshipToModelIT.java | 188 -----
.../cayenne/merge/DropTableToModelIT.java | 94 ---
.../org/apache/cayenne/merge/MergeCase.java | 215 -----
.../apache/cayenne/merge/MergerFactoryIT.java | 310 -------
.../cayenne/merge/SetAllowNullToDbIT.java | 66 --
.../apache/cayenne/merge/SetNotNullToDbIT.java | 62 --
.../cayenne/merge/SetPrimaryKeyToDbIT.java | 58 --
.../apache/cayenne/merge/TokensReversTest.java | 88 --
.../cayenne/merge/TokensToModelExecution.java | 83 --
.../apache/cayenne/merge/ValueForNullIT.java | 128 ---
.../apache/cayenne/merge/builders/Builder.java | 38 -
.../cayenne/merge/builders/DataMapBuilder.java | 128 ---
.../merge/builders/DbAttributeBuilder.java | 115 ---
.../cayenne/merge/builders/DbEntityBuilder.java | 90 --
.../merge/builders/DbRelationshipBuilder.java | 85 --
.../cayenne/merge/builders/DefaultBuilder.java | 57 --
.../merge/builders/ObjAttributeBuilder.java | 67 --
.../merge/builders/ObjEntityBuilder.java | 98 ---
.../cayenne/merge/builders/ObjectMother.java | 70 --
.../unit/di/server/ServerRuntimeProvider.java | 13 +-
.../cayenne/util/EntityMergeSupportIT.java | 103 ---
.../cayenne-relationship-optimisation.xml | 4 -
.../loader/relationship-optimisation.map.xml | 43 -
cayenne-tools/pom.xml | 14 +
.../cayenne/gen/ClassGenerationAction.java | 22 +-
.../cayenne/tools/AntDataPortDelegate.java | 10 +-
.../CayenneGeneratorEntityFilterAction.java | 10 +-
.../cayenne/tools/CayenneGeneratorTask.java | 2 +-
.../apache/cayenne/tools/DbGeneratorTask.java | 9 +-
.../apache/cayenne/tools/DbImporterTask.java | 9 +-
.../tools/dbimport/DbImportConfiguration.java | 27 +-
.../dbimport/DbImportDbLoaderDelegate.java | 2 +-
.../cayenne/tools/dbimport/DbImportModule.java | 4 +-
.../tools/dbimport/DefaultDbImportAction.java | 34 +-
.../config/DefaultTypeMapperBuilder.java | 6 +-
.../cayenne/tools/NamePatternMatcherTest.java | 8 +-
.../tools/dbimport/DbImportModuleTest.java | 3 +-
.../dbimport/DefaultDbImportActionTest.java | 40 +-
docs/doc/src/main/resources/RELEASE-NOTES.txt | 1 +
.../java/org/apache/cayenne/modeler/Main.java | 17 +-
.../modeler/action/CreateObjEntityAction.java | 6 +-
.../modeler/action/DbEntitySyncAction.java | 8 +-
.../cayenne/modeler/action/MigrateAction.java | 72 +-
.../modeler/action/ObjEntitySyncAction.java | 13 +-
.../modeler/dialog/db/DbLoaderHelper.java | 16 +-
.../modeler/dialog/db/MergerOptions.java | 67 +-
.../db/MergerTokenSelectorController.java | 40 +-
.../dialog/db/MergerTokenTableModel.java | 6 +-
.../dialog/db/ModelerDbImportAction.java | 6 +-
.../dialog/db/ReverseEngineeringController.java | 17 +-
.../dialog/objentity/EntitySyncController.java | 15 +-
.../cayenne/tools/CayenneGeneratorMojo.java | 2 +-
.../apache/cayenne/tools/DbGeneratorMojo.java | 9 +-
.../apache/cayenne/tools/DbImporterMojo.java | 21 +-
.../tools/DbImporterMojoConfigurationTest.java | 8 +-
pom.xml | 1 +
276 files changed, 14069 insertions(+), 13421 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/cayenne/blob/2f7b1d53/assembly/pom.xml
----------------------------------------------------------------------
diff --git a/assembly/pom.xml b/assembly/pom.xml
index 6b7f423..45c042e 100644
--- a/assembly/pom.xml
+++ b/assembly/pom.xml
@@ -50,6 +50,12 @@
<dependency>
<groupId>org.apache.cayenne</groupId>
+ <artifactId>cayenne-dbsync</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.cayenne</groupId>
<artifactId>cayenne-tools</artifactId>
<version>${project.version}</version>
</dependency>
http://git-wip-us.apache.org/repos/asf/cayenne/blob/2f7b1d53/assembly/src/main/resources/assemblies/assembly-generic.xml
----------------------------------------------------------------------
diff --git a/assembly/src/main/resources/assemblies/assembly-generic.xml b/assembly/src/main/resources/assemblies/assembly-generic.xml
index 4414219..5eb4a62 100644
--- a/assembly/src/main/resources/assemblies/assembly-generic.xml
+++ b/assembly/src/main/resources/assemblies/assembly-generic.xml
@@ -80,6 +80,7 @@
<include>org.apache.cayenne:cayenne-lifecycle</include>
<include>org.apache.cayenne:cayenne-project</include>
<include>org.apache.cayenne:cayenne-server</include>
+ <include>org.apache.cayenne:cayenne-dbsync</include>
<include>org.apache.cayenne:cayenne-tools</include>
<include>org.apache.cayenne:cayenne-dbcp2</include>
<include>org.apache.cayenne:cayenne-java8</include>
http://git-wip-us.apache.org/repos/asf/cayenne/blob/2f7b1d53/assembly/src/main/resources/assemblies/assembly-mac.xml
----------------------------------------------------------------------
diff --git a/assembly/src/main/resources/assemblies/assembly-mac.xml b/assembly/src/main/resources/assemblies/assembly-mac.xml
index 05a4d1f..11e3546 100644
--- a/assembly/src/main/resources/assemblies/assembly-mac.xml
+++ b/assembly/src/main/resources/assemblies/assembly-mac.xml
@@ -80,6 +80,7 @@
<include>org.apache.cayenne:cayenne-lifecycle</include>
<include>org.apache.cayenne:cayenne-project</include>
<include>org.apache.cayenne:cayenne-server</include>
+ <include>org.apache.cayenne:cayenne-dbsync</include>
<include>org.apache.cayenne:cayenne-tools</include>
<include>org.apache.cayenne:cayenne-dbcp2</include>
<include>org.apache.cayenne:cayenne-java8</include>
http://git-wip-us.apache.org/repos/asf/cayenne/blob/2f7b1d53/assembly/src/main/resources/assemblies/assembly-windows.xml
----------------------------------------------------------------------
diff --git a/assembly/src/main/resources/assemblies/assembly-windows.xml b/assembly/src/main/resources/assemblies/assembly-windows.xml
index 7401a42..efa451d 100644
--- a/assembly/src/main/resources/assemblies/assembly-windows.xml
+++ b/assembly/src/main/resources/assemblies/assembly-windows.xml
@@ -80,6 +80,7 @@
<include>org.apache.cayenne:cayenne-lifecycle</include>
<include>org.apache.cayenne:cayenne-project</include>
<include>org.apache.cayenne:cayenne-server</include>
+ <include>org.apache.cayenne:cayenne-dbsync</include>
<include>org.apache.cayenne:cayenne-tools</include>
<include>org.apache.cayenne:cayenne-dbcp2</include>
<include>org.apache.cayenne:cayenne-java8</include>
http://git-wip-us.apache.org/repos/asf/cayenne/blob/2f7b1d53/cayenne-dbsync/pom.xml
----------------------------------------------------------------------
diff --git a/cayenne-dbsync/pom.xml b/cayenne-dbsync/pom.xml
new file mode 100644
index 0000000..5cc1a63
--- /dev/null
+++ b/cayenne-dbsync/pom.xml
@@ -0,0 +1,117 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+
+ <parent>
+ <artifactId>cayenne-parent</artifactId>
+ <groupId>org.apache.cayenne</groupId>
+ <version>4.0.M4-SNAPSHOT</version>
+ </parent>
+
+ <modelVersion>4.0.0</modelVersion>
+
+ <artifactId>cayenne-dbsync</artifactId>
+ <packaging>jar</packaging>
+ <name>Cayenne Database Synchronization Tools</name>
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.cayenne</groupId>
+ <artifactId>cayenne-server</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.mockito</groupId>
+ <artifactId>mockito-all</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>xmlunit</groupId>
+ <artifactId>xmlunit</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.cayenne</groupId>
+ <artifactId>cayenne-server</artifactId>
+ <version>${project.version}</version>
+ <scope>test</scope>
+ <type>test-jar</type>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.cayenne.build-tools</groupId>
+ <artifactId>cayenne-test-utilities</artifactId>
+ <version>${project.version}</version>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <plugins>
+ <!-- This ensures LICESNE and NOTICE inclusion in all jars -->
+ <plugin>
+ <artifactId>maven-remote-resources-plugin</artifactId>
+ <executions>
+ <execution>
+ <goals>
+ <goal>process</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <artifactId>maven-jar-plugin</artifactId>
+ <!-- include OSGi stuff -->
+ <configuration>
+ <archive>
+ <manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile>
+ </archive>
+ </configuration>
+ <!-- share tests with downstream modules -->
+ <executions>
+ <execution>
+ <goals>
+ <goal>test-jar</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>bundle-manifest</id>
+ <phase>process-classes</phase>
+ <goals>
+ <goal>manifest</goal>
+ </goals>
+ <!-- TODO: export package filters. -->
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+</project>
http://git-wip-us.apache.org/repos/asf/cayenne/blob/2f7b1d53/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/CayenneDbSyncModule.java
----------------------------------------------------------------------
diff --git a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/CayenneDbSyncModule.java b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/CayenneDbSyncModule.java
new file mode 100644
index 0000000..4fa43b2
--- /dev/null
+++ b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/CayenneDbSyncModule.java
@@ -0,0 +1,82 @@
+package org.apache.cayenne.dbsync;
+
+import org.apache.cayenne.dba.db2.DB2Adapter;
+import org.apache.cayenne.dba.derby.DerbyAdapter;
+import org.apache.cayenne.dba.firebird.FirebirdAdapter;
+import org.apache.cayenne.dba.h2.H2Adapter;
+import org.apache.cayenne.dba.hsqldb.HSQLDBAdapter;
+import org.apache.cayenne.dba.ingres.IngresAdapter;
+import org.apache.cayenne.dba.mysql.MySQLAdapter;
+import org.apache.cayenne.dba.openbase.OpenBaseAdapter;
+import org.apache.cayenne.dba.oracle.Oracle8Adapter;
+import org.apache.cayenne.dba.oracle.OracleAdapter;
+import org.apache.cayenne.dba.postgres.PostgresAdapter;
+import org.apache.cayenne.dba.sqlserver.SQLServerAdapter;
+import org.apache.cayenne.dba.sybase.SybaseAdapter;
+import org.apache.cayenne.dbsync.merge.factory.MergerTokenFactoryProvider;
+import org.apache.cayenne.dbsync.merge.factory.DB2MergerTokenFactory;
+import org.apache.cayenne.dbsync.merge.factory.DefaultMergerTokenFactory;
+import org.apache.cayenne.dbsync.merge.factory.DerbyMergerTokenFactory;
+import org.apache.cayenne.dbsync.merge.factory.FirebirdMergerTokenFactory;
+import org.apache.cayenne.dbsync.merge.factory.H2MergerTokenFactory;
+import org.apache.cayenne.dbsync.merge.factory.HSQLMergerTokenFactory;
+import org.apache.cayenne.dbsync.merge.factory.IngresMergerTokenFactory;
+import org.apache.cayenne.dbsync.merge.factory.MergerTokenFactory;
+import org.apache.cayenne.dbsync.merge.factory.MySQLMergerTokenFactory;
+import org.apache.cayenne.dbsync.merge.factory.OpenBaseMergerTokenFactory;
+import org.apache.cayenne.dbsync.merge.factory.OracleMergerTokenFactory;
+import org.apache.cayenne.dbsync.merge.factory.PostgresMergerTokenFactory;
+import org.apache.cayenne.dbsync.merge.factory.SQLServerMergerTokenFactory;
+import org.apache.cayenne.dbsync.merge.factory.SybaseMergerTokenFactory;
+import org.apache.cayenne.di.Binder;
+import org.apache.cayenne.di.Module;
+
+/**
+ * @since 4.0
+ */
+public class CayenneDbSyncModule implements Module {
+
+ /**
+ * A DI container key for the Map<String, String> storing properties
+ * used by built-in Cayenne service.
+ */
+ public static final String MERGER_FACTORIES_MAP = "cayenne.dbsync.mergerfactories";
+
+ @Override
+ public void configure(Binder binder) {
+
+ // TODO: explicit binding before inserting into a map will be uneeded soon
+ binder.bind(DB2MergerTokenFactory.class).to(DB2MergerTokenFactory.class);
+ binder.bind(DerbyMergerTokenFactory.class).to(DerbyMergerTokenFactory.class);
+ binder.bind(FirebirdMergerTokenFactory.class).to(FirebirdMergerTokenFactory.class);
+ binder.bind(H2MergerTokenFactory.class).to(H2MergerTokenFactory.class);
+ binder.bind(HSQLMergerTokenFactory.class).to(HSQLMergerTokenFactory.class);
+ binder.bind(IngresMergerTokenFactory.class).to(IngresMergerTokenFactory.class);
+ binder.bind(MySQLMergerTokenFactory.class).to(MySQLMergerTokenFactory.class);
+ binder.bind(OpenBaseMergerTokenFactory.class).to(OpenBaseMergerTokenFactory.class);
+ binder.bind(OracleMergerTokenFactory.class).to(OracleMergerTokenFactory.class);
+ binder.bind(PostgresMergerTokenFactory.class).to(PostgresMergerTokenFactory.class);
+ binder.bind(SQLServerMergerTokenFactory.class).to(SQLServerMergerTokenFactory.class);
+ binder.bind(SybaseMergerTokenFactory.class).to(SybaseMergerTokenFactory.class);
+
+ // default and per adapter merger factories...
+ binder.bind(MergerTokenFactory.class).to(DefaultMergerTokenFactory.class);
+ binder.bindMap(MERGER_FACTORIES_MAP)
+ .put(DB2Adapter.class.getName(), DB2MergerTokenFactory.class)
+ .put(DerbyAdapter.class.getName(), DerbyMergerTokenFactory.class)
+ .put(FirebirdAdapter.class.getName(), FirebirdMergerTokenFactory.class)
+ .put(H2Adapter.class.getName(), H2MergerTokenFactory.class)
+ .put(HSQLDBAdapter.class.getName(), HSQLMergerTokenFactory.class)
+ .put(IngresAdapter.class.getName(), IngresMergerTokenFactory.class)
+ .put(MySQLAdapter.class.getName(), MySQLMergerTokenFactory.class)
+ .put(OpenBaseAdapter.class.getName(), OpenBaseMergerTokenFactory.class)
+ .put(OracleAdapter.class.getName(), OracleMergerTokenFactory.class)
+ .put(Oracle8Adapter.class.getName(), OracleMergerTokenFactory.class)
+ .put(PostgresAdapter.class.getName(), PostgresMergerTokenFactory.class)
+ .put(SQLServerAdapter.class.getName(), SQLServerMergerTokenFactory.class)
+ .put(SybaseAdapter.class.getName(), SybaseMergerTokenFactory.class);
+
+ binder.bind(MergerTokenFactoryProvider.class).to(MergerTokenFactoryProvider.class);
+
+ }
+}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/2f7b1d53/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/AbstractToDbToken.java
----------------------------------------------------------------------
diff --git a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/AbstractToDbToken.java b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/AbstractToDbToken.java
new file mode 100644
index 0000000..1cc3092
--- /dev/null
+++ b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/AbstractToDbToken.java
@@ -0,0 +1,126 @@
+/*****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ ****************************************************************/
+package org.apache.cayenne.dbsync.merge;
+
+import org.apache.cayenne.dba.DbAdapter;
+import org.apache.cayenne.log.JdbcEventLogger;
+import org.apache.cayenne.map.DbAttribute;
+import org.apache.cayenne.map.DbEntity;
+import org.apache.cayenne.validation.SimpleValidationFailure;
+
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.List;
+
+/**
+ * Common abstract superclass for all {@link MergerToken}s going from the model
+ * to the database.
+ */
+public abstract class AbstractToDbToken implements MergerToken, Comparable<MergerToken> {
+
+ private final String tokenName;
+
+ protected AbstractToDbToken(String tokenName) {
+ this.tokenName = tokenName;
+ }
+
+ @Override
+ public final String getTokenName() {
+ return tokenName;
+ }
+
+ @Override
+ public final MergeDirection getDirection() {
+ return MergeDirection.TO_DB;
+ }
+
+ @Override
+ public void execute(MergerContext mergerContext) {
+ for (String sql : createSql(mergerContext.getDataNode().getAdapter())) {
+ executeSql(mergerContext, sql);
+ }
+ }
+
+ protected void executeSql(MergerContext mergerContext, String sql) {
+ JdbcEventLogger logger = mergerContext.getDataNode().getJdbcEventLogger();
+ logger.log(sql);
+
+ try (Connection conn = mergerContext.getDataNode().getDataSource().getConnection();) {
+
+ try (Statement st = conn.createStatement();) {
+ st.execute(sql);
+ }
+ } catch (SQLException e) {
+ mergerContext.getValidationResult().addFailure(new SimpleValidationFailure(sql, e.getMessage()));
+ logger.logQueryError(e);
+ }
+ }
+
+ @Override
+ public String toString() {
+ return getTokenName() + ' ' + getTokenValue() + ' ' + getDirection();
+ }
+
+ public abstract List<String> createSql(DbAdapter adapter);
+
+ abstract static class Entity extends AbstractToDbToken {
+
+ private DbEntity entity;
+
+ public Entity(String tokenName, DbEntity entity) {
+ super(tokenName);
+ this.entity = entity;
+ }
+
+ public DbEntity getEntity() {
+ return entity;
+ }
+
+ public String getTokenValue() {
+ return getEntity().getName();
+ }
+
+ public int compareTo(MergerToken o) {
+ // default order as tokens are created
+ return 0;
+ }
+
+ }
+
+ abstract static class EntityAndColumn extends Entity {
+
+ private DbAttribute column;
+
+ public EntityAndColumn(String tokenName, DbEntity entity, DbAttribute column) {
+ super(tokenName, entity);
+ this.column = column;
+ }
+
+ public DbAttribute getColumn() {
+ return column;
+ }
+
+ @Override
+ public String getTokenValue() {
+ return getEntity().getName() + "." + getColumn().getName();
+ }
+
+ }
+}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/2f7b1d53/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/AbstractToModelToken.java
----------------------------------------------------------------------
diff --git a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/AbstractToModelToken.java b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/AbstractToModelToken.java
new file mode 100644
index 0000000..0c4b22e
--- /dev/null
+++ b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/AbstractToModelToken.java
@@ -0,0 +1,122 @@
+/*****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ ****************************************************************/
+package org.apache.cayenne.dbsync.merge;
+
+import org.apache.cayenne.map.DbAttribute;
+import org.apache.cayenne.map.DbEntity;
+import org.apache.cayenne.map.DbRelationship;
+import org.apache.cayenne.map.ObjEntity;
+import org.apache.cayenne.map.ObjRelationship;
+
+/**
+ * Common abstract superclass for all {@link MergerToken}s going from the database to the
+ * model.
+ *
+ */
+public abstract class AbstractToModelToken implements MergerToken {
+
+ private final String tokenName;
+
+ protected AbstractToModelToken(String tokenName) {
+ this.tokenName = tokenName;
+ }
+
+ @Override
+ public final String getTokenName() {
+ return tokenName;
+ }
+
+ public final MergeDirection getDirection() {
+ return MergeDirection.TO_MODEL;
+ }
+
+ protected static void remove(ModelMergeDelegate mergerContext, DbRelationship rel, boolean reverse) {
+ if (rel == null) {
+ return;
+ }
+ if (reverse) {
+ remove(mergerContext, rel.getReverseRelationship(), false);
+ }
+
+ DbEntity dbEntity = rel.getSourceEntity();
+ for (ObjEntity objEntity : dbEntity.mappedObjEntities()) {
+ remove(mergerContext, objEntity.getRelationshipForDbRelationship(rel), true);
+ }
+
+ rel.getSourceEntity().removeRelationship(rel.getName());
+ mergerContext.dbRelationshipRemoved(rel);
+ }
+
+ protected static void remove(ModelMergeDelegate mergerContext, ObjRelationship rel, boolean reverse) {
+ if (rel == null) {
+ return;
+ }
+ if (reverse) {
+ remove(mergerContext, rel.getReverseRelationship(), false);
+ }
+ rel.getSourceEntity().removeRelationship(rel.getName());
+ mergerContext.objRelationshipRemoved(rel);
+ }
+
+ @Override
+ public String toString() {
+ return getTokenName() + ' ' + getTokenValue() + ' ' + getDirection();
+ }
+
+ abstract static class Entity extends AbstractToModelToken {
+
+ private final DbEntity entity;
+
+ protected Entity(String tokenName, DbEntity entity) {
+ super(tokenName);
+ this.entity = entity;
+ }
+
+ public DbEntity getEntity() {
+ return entity;
+ }
+
+ public String getTokenValue() {
+ return getEntity().getName();
+ }
+
+ }
+
+ abstract static class EntityAndColumn extends Entity {
+
+ private final DbAttribute column;
+
+ protected EntityAndColumn(String tokenName, DbEntity entity, DbAttribute column) {
+ super(tokenName, entity);
+ this.column = column;
+ }
+
+ public DbAttribute getColumn() {
+ return column;
+ }
+
+ @Override
+ public String getTokenValue() {
+ return getEntity().getName() + "." + getColumn().getName();
+ }
+
+ }
+
+
+}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/2f7b1d53/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/AddColumnToDb.java
----------------------------------------------------------------------
diff --git a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/AddColumnToDb.java b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/AddColumnToDb.java
new file mode 100644
index 0000000..977128c
--- /dev/null
+++ b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/AddColumnToDb.java
@@ -0,0 +1,65 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.cayenne.dbsync.merge;
+
+import java.util.Collections;
+import java.util.List;
+
+import org.apache.cayenne.dba.DbAdapter;
+import org.apache.cayenne.dba.JdbcAdapter;
+import org.apache.cayenne.dba.QuotingStrategy;
+import org.apache.cayenne.dbsync.merge.factory.MergerTokenFactory;
+import org.apache.cayenne.map.DbAttribute;
+import org.apache.cayenne.map.DbEntity;
+
+public class AddColumnToDb extends AbstractToDbToken.EntityAndColumn {
+
+ public AddColumnToDb(DbEntity entity, DbAttribute column) {
+ super("Add Column", entity, column);
+ }
+
+ /**
+ * append the part of the token before the actual column data type
+ */
+ protected void appendPrefix(StringBuffer sqlBuffer, QuotingStrategy context) {
+
+ sqlBuffer.append("ALTER TABLE ");
+ sqlBuffer.append(context.quotedFullyQualifiedName(getEntity()));
+ sqlBuffer.append(" ADD COLUMN ");
+ sqlBuffer.append(context.quotedName(getColumn()));
+ sqlBuffer.append(" ");
+ }
+
+ @Override
+ public List<String> createSql(DbAdapter adapter) {
+ StringBuffer sqlBuffer = new StringBuffer();
+ QuotingStrategy context = adapter.getQuotingStrategy();
+ appendPrefix(sqlBuffer, context);
+
+ sqlBuffer.append(JdbcAdapter.getType(adapter, getColumn()));
+ sqlBuffer.append(JdbcAdapter.sizeAndPrecision(adapter, getColumn()));
+
+ return Collections.singletonList(sqlBuffer.toString());
+ }
+
+ public MergerToken createReverse(MergerTokenFactory factory) {
+ return factory.createDropColumnToModel(getEntity(), getColumn());
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/2f7b1d53/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/AddColumnToModel.java
----------------------------------------------------------------------
diff --git a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/AddColumnToModel.java b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/AddColumnToModel.java
new file mode 100644
index 0000000..30390ca
--- /dev/null
+++ b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/AddColumnToModel.java
@@ -0,0 +1,55 @@
+/*****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ ****************************************************************/
+package org.apache.cayenne.dbsync.merge;
+
+import org.apache.cayenne.dbsync.merge.factory.MergerTokenFactory;
+import org.apache.cayenne.map.DbAttribute;
+import org.apache.cayenne.map.DbEntity;
+import org.apache.cayenne.map.ObjEntity;
+
+/**
+ * A {@link MergerToken} to add a {@link DbAttribute} to a {@link DbEntity}. The
+ * {@link EntityMergeSupport} will be used to update the mapped {@link ObjEntity}
+ *
+ */
+public class AddColumnToModel extends AbstractToModelToken.EntityAndColumn {
+
+ public AddColumnToModel(DbEntity entity, DbAttribute column) {
+ super("Add Column", entity, column);
+ }
+
+ public MergerToken createReverse(MergerTokenFactory factory) {
+ return factory.createDropColumnToDb(getEntity(), getColumn());
+ }
+
+ public void execute(MergerContext mergerContext) {
+ getEntity().addAttribute(getColumn());
+
+ // TODO: use EntityMergeSupport from DbImportConfiguration... otherwise we are ignoring a bunch of
+ // important settings
+
+ EntityMergeSupport entityMergeSupport = new EntityMergeSupport(mergerContext.getDataMap());
+ for(ObjEntity e : getEntity().mappedObjEntities()) {
+ entityMergeSupport.synchronizeOnDbAttributeAdded(e, getColumn());
+ }
+
+ mergerContext.getModelMergeDelegate().dbAttributeAdded(getColumn());
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/2f7b1d53/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/AddRelationshipToDb.java
----------------------------------------------------------------------
diff --git a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/AddRelationshipToDb.java b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/AddRelationshipToDb.java
new file mode 100644
index 0000000..5c851a6
--- /dev/null
+++ b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/AddRelationshipToDb.java
@@ -0,0 +1,87 @@
+/*****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ ****************************************************************/
+package org.apache.cayenne.dbsync.merge;
+
+import java.util.Collections;
+import java.util.List;
+
+import org.apache.cayenne.access.DbGenerator;
+import org.apache.cayenne.dba.DbAdapter;
+import org.apache.cayenne.dbsync.merge.factory.MergerTokenFactory;
+import org.apache.cayenne.map.DbEntity;
+import org.apache.cayenne.map.DbRelationship;
+
+public class AddRelationshipToDb extends AbstractToDbToken.Entity {
+
+ private DbRelationship rel;
+
+ public AddRelationshipToDb(DbEntity entity, DbRelationship rel) {
+ super("Add foreign key", entity);
+ this.rel = rel;
+ }
+
+ /**
+ * @see DbGenerator#createConstraintsQueries(org.apache.cayenne.map.DbEntity)
+ */
+ @Override
+ public List<String> createSql(DbAdapter adapter) {
+ // TODO: skip FK to a different DB
+
+ if (this.shouldGenerateFkConstraint()) {
+ String fksql = adapter.createFkConstraint(rel);
+ if (fksql != null) {
+ return Collections.singletonList(fksql);
+ }
+ }
+ return Collections.emptyList();
+ }
+
+ public boolean shouldGenerateFkConstraint() {
+ return !rel.isToMany()
+ && rel.isToPK() // TODO it is not necessary primary key it can be unique index
+ && !rel.isToDependentPK();
+ }
+
+ public MergerToken createReverse(MergerTokenFactory factory) {
+ return factory.createDropRelationshipToModel(getEntity(), rel);
+ }
+
+ @Override
+ public String getTokenValue() {
+ if (this.shouldGenerateFkConstraint()) {
+ return rel.getSourceEntity().getName() + "->" + rel.getTargetEntityName();
+ } else {
+ return "Skip. No sql representation.";
+ }
+ }
+
+ public DbRelationship getRelationship() {
+ return rel;
+ }
+
+ @Override
+ public int compareTo(MergerToken o) {
+ // add all AddRelationshipToDb to the end.
+ if (o instanceof AddRelationshipToDb) {
+ return super.compareTo(o);
+ }
+ return 1;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/2f7b1d53/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/AddRelationshipToModel.java
----------------------------------------------------------------------
diff --git a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/AddRelationshipToModel.java b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/AddRelationshipToModel.java
new file mode 100644
index 0000000..f516a3e
--- /dev/null
+++ b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/AddRelationshipToModel.java
@@ -0,0 +1,95 @@
+/*****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ ****************************************************************/
+package org.apache.cayenne.dbsync.merge;
+
+import org.apache.cayenne.dbsync.merge.factory.MergerTokenFactory;
+import org.apache.cayenne.map.DbEntity;
+import org.apache.cayenne.map.DbJoin;
+import org.apache.cayenne.map.DbRelationship;
+import org.apache.cayenne.map.ObjEntity;
+
+public class AddRelationshipToModel extends AbstractToModelToken.Entity {
+
+ public static final String COMMA_SEPARATOR = ", ";
+ public static final int COMMA_SEPARATOR_LENGTH = COMMA_SEPARATOR.length();
+ private DbRelationship rel;
+
+ public AddRelationshipToModel(DbEntity entity, DbRelationship rel) {
+ super("Add Relationship", entity);
+ this.rel = rel;
+ }
+
+ public MergerToken createReverse(MergerTokenFactory factory) {
+ return factory.createDropRelationshipToDb(getEntity(), rel);
+ }
+
+ public void execute(MergerContext mergerContext) {
+ getEntity().addRelationship(rel);
+ // TODO: add reverse relationship as well if it does not exist
+
+ // TODO: use EntityMergeSupport from DbImportConfiguration... otherwise we are ignoring a bunch of
+ // important settings
+
+ EntityMergeSupport entityMergeSupport = new EntityMergeSupport(mergerContext.getDataMap());
+ for(ObjEntity e : getEntity().mappedObjEntities()) {
+ entityMergeSupport.synchronizeOnDbRelationshipAdded(e, rel);
+ }
+
+ mergerContext.getModelMergeDelegate().dbRelationshipAdded(rel);
+ }
+
+ @Override
+ public String getTokenValue() {
+ String attributes = "";
+ if (rel.getJoins().size() == 1) {
+ attributes = rel.getJoins().get(0).getTargetName();
+ } else {
+ for (DbJoin dbJoin : rel.getJoins()) {
+ attributes += dbJoin.getTargetName() + COMMA_SEPARATOR;
+ }
+
+ attributes = "{" + attributes.substring(0, attributes.length() - COMMA_SEPARATOR_LENGTH) + "}";
+ }
+
+ return rel.getName() + " " + rel.getSourceEntity().getName() + "->" + rel.getTargetEntityName() + "." + attributes;
+ }
+
+
+ public static String getTokenValue(DbRelationship rel) {
+ String attributes = "";
+ if (rel.getJoins().size() == 1) {
+ attributes = rel.getJoins().get(0).getTargetName();
+ } else {
+ for (DbJoin dbJoin : rel.getJoins()) {
+ attributes += dbJoin.getTargetName() + COMMA_SEPARATOR;
+ }
+
+ attributes = "{" + attributes.substring(0, attributes.length() - COMMA_SEPARATOR_LENGTH) + "}";
+ }
+
+ return rel.getName() + " " + rel.getSourceEntity().getName() + "->" + rel.getTargetEntityName() + "." + attributes;
+ }
+
+ public DbRelationship getRelationship() {
+ return rel;
+ }
+
+
+
+}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/2f7b1d53/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/CreateTableToDb.java
----------------------------------------------------------------------
diff --git a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/CreateTableToDb.java b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/CreateTableToDb.java
new file mode 100644
index 0000000..9584aaf
--- /dev/null
+++ b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/CreateTableToDb.java
@@ -0,0 +1,66 @@
+/*****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ ****************************************************************/
+package org.apache.cayenne.dbsync.merge;
+
+import org.apache.cayenne.access.DataNode;
+import org.apache.cayenne.dba.DbAdapter;
+import org.apache.cayenne.dbsync.merge.factory.MergerTokenFactory;
+import org.apache.cayenne.map.DbEntity;
+import org.apache.cayenne.validation.SimpleValidationFailure;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+public class CreateTableToDb extends AbstractToDbToken.Entity {
+
+ public CreateTableToDb(DbEntity entity) {
+ super("Create Table", entity);
+ }
+
+ @Override
+ public List<String> createSql(DbAdapter adapter) {
+ List<String> sqls = new ArrayList<String>();
+ sqls.addAll(adapter.getPkGenerator().createAutoPkStatements(
+ Collections.singletonList(getEntity())));
+ sqls.add(adapter.createTable(getEntity()));
+ return sqls;
+ }
+
+ @Override
+ public void execute(MergerContext mergerContext) {
+ try {
+ DataNode node = mergerContext.getDataNode();
+ DbAdapter adapter = node.getAdapter();
+ adapter.getPkGenerator().createAutoPk(
+ node,
+ Collections.singletonList(getEntity()));
+ executeSql(mergerContext, adapter.createTable(getEntity()));
+ }
+ catch (Exception e) {
+ mergerContext.getValidationResult().addFailure(
+ new SimpleValidationFailure(this, e.getMessage()));
+ }
+ }
+
+ public MergerToken createReverse(MergerTokenFactory factory) {
+ return factory.createDropTableToModel(getEntity());
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/2f7b1d53/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/CreateTableToModel.java
----------------------------------------------------------------------
diff --git a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/CreateTableToModel.java b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/CreateTableToModel.java
new file mode 100644
index 0000000..69e18b3
--- /dev/null
+++ b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/CreateTableToModel.java
@@ -0,0 +1,102 @@
+/*****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ ****************************************************************/
+package org.apache.cayenne.dbsync.merge;
+
+import org.apache.cayenne.dbsync.merge.factory.MergerTokenFactory;
+import org.apache.cayenne.map.DataMap;
+import org.apache.cayenne.map.DbEntity;
+import org.apache.cayenne.map.ObjEntity;
+import org.apache.cayenne.map.naming.NameConverter;
+
+/**
+ * A {@link MergerToken} to add a {@link DbEntity} to a {@link DataMap}
+ *
+ */
+public class CreateTableToModel extends AbstractToModelToken.Entity {
+
+ /**
+ * className if {@link ObjEntity} should be generated with a
+ * special class name.
+ * Setting this to <code>null</code>, because by default class name should be generated
+ */
+ private String objEntityClassName = null; //CayenneDataObject.class.getName();
+
+ public CreateTableToModel(DbEntity entity) {
+ super("Create Table", entity);
+ }
+
+ /**
+ * Set the {@link ObjEntity} className if {@link ObjEntity} should be generated with a
+ * special class name. Set to null if the {@link ObjEntity} should be created with a
+ * name based on {@link DataMap#getDefaultPackage()} and {@link ObjEntity#getName()}
+ * <p>
+ * The default value is <code>null</code>
+ */
+ public void setObjEntityClassName(String n) {
+ objEntityClassName = n;
+ }
+
+ public void execute(MergerContext mergerContext) {
+ DataMap map = mergerContext.getDataMap();
+ map.addDbEntity(getEntity());
+
+ // create a ObjEntity
+ String objEntityName = NameConverter.underscoredToJava(getEntity().getName(), true);
+ // this loop will terminate even if no valid name is found
+ // to prevent loader from looping forever (though such case is very unlikely)
+ String baseName = objEntityName;
+ for (int i = 1; i < 1000 && map.getObjEntity(objEntityName) != null; i++) {
+ objEntityName = baseName + i;
+ }
+
+ ObjEntity objEntity = new ObjEntity(objEntityName);
+ objEntity.setDbEntity(getEntity());
+
+ // try to find a class name for the ObjEntity
+ String className = objEntityClassName;
+ if (className == null) {
+ // we should generate a className based on the objEntityName
+ className = map.getNameWithDefaultPackage(objEntityName);
+ }
+
+ objEntity.setClassName(className);
+ objEntity.setSuperClassName(map.getDefaultSuperclass());
+
+ if (map.isClientSupported()) {
+ objEntity.setClientClassName(map.getNameWithDefaultClientPackage(objEntity.getName()));
+ objEntity.setClientSuperClassName(map.getDefaultClientSuperclass());
+ }
+
+ map.addObjEntity(objEntity);
+
+ // presumably there are no other ObjEntities pointing to this DbEntity, so syncing just this one...
+
+ // TODO: use EntityMergeSupport from DbImportConfiguration... otherwise we are ignoring a bunch of
+ // important settings
+ new EntityMergeSupport(map).synchronizeWithDbEntity(objEntity);
+
+ mergerContext.getModelMergeDelegate().dbEntityAdded(getEntity());
+ mergerContext.getModelMergeDelegate().objEntityAdded(objEntity);
+ }
+
+ public MergerToken createReverse(MergerTokenFactory factory) {
+ return factory.createDropTableToDb(getEntity());
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/2f7b1d53/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/DbMerger.java
----------------------------------------------------------------------
diff --git a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/DbMerger.java b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/DbMerger.java
new file mode 100644
index 0000000..f7d4346
--- /dev/null
+++ b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/DbMerger.java
@@ -0,0 +1,405 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.cayenne.dbsync.merge;
+
+import org.apache.cayenne.CayenneRuntimeException;
+import org.apache.cayenne.access.DataNode;
+import org.apache.cayenne.dba.DbAdapter;
+import org.apache.cayenne.dbsync.merge.factory.MergerTokenFactory;
+import org.apache.cayenne.dbsync.reverse.DbLoader;
+import org.apache.cayenne.dbsync.reverse.DbLoaderConfiguration;
+import org.apache.cayenne.dbsync.reverse.LoggingDbLoaderDelegate;
+import org.apache.cayenne.dbsync.reverse.filters.FiltersConfig;
+import org.apache.cayenne.map.Attribute;
+import org.apache.cayenne.map.DataMap;
+import org.apache.cayenne.map.DbAttribute;
+import org.apache.cayenne.map.DbEntity;
+import org.apache.cayenne.map.DbJoin;
+import org.apache.cayenne.map.DbRelationship;
+import org.apache.cayenne.map.DetectedDbEntity;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import javax.sql.DataSource;
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.sql.Types;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * Traverse a {@link DataNode} and a {@link DataMap} and create a group of
+ * {@link MergerToken}s to alter the {@link DataNode} data store to match the
+ * {@link DataMap}.
+ *
+ */
+public class DbMerger {
+
+ private static final Log LOGGER = LogFactory.getLog(DbMerger.class);
+
+ private final MergerTokenFactory factory;
+
+ private final ValueForNullProvider valueForNull;
+
+ public DbMerger(MergerTokenFactory factory) {
+ this(factory, null);
+ }
+
+ public DbMerger(MergerTokenFactory factory, ValueForNullProvider valueForNull) {
+ this.factory = factory;
+ this.valueForNull = valueForNull == null ? new EmptyValueForNullProvider() : valueForNull;
+ }
+
+ /**
+ * Create and return a {@link List} of {@link MergerToken}s to alter the
+ * given {@link DataNode} to match the given {@link DataMap}
+ */
+ public List<MergerToken> createMergeTokens(DataSource dataSource, DbAdapter adapter, DataMap existingDataMap,
+ DbLoaderConfiguration config) {
+ return createMergeTokens(existingDataMap, loadDataMapFromDb(dataSource, adapter, config), config);
+ }
+
+ /**
+ * Create and return a {@link List} of {@link MergerToken}s to alter the
+ * given {@link DataNode} to match the given {@link DataMap}
+ */
+ public List<MergerToken> createMergeTokens(DataMap existing, DataMap loadedFomDb, DbLoaderConfiguration config) {
+
+ loadedFomDb.setQuotingSQLIdentifiers(existing.isQuotingSQLIdentifiers());
+
+ List<MergerToken> tokens = createMergeTokens(filter(existing, config.getFiltersConfig()),
+ loadedFomDb.getDbEntities(), config);
+
+ // sort. use a custom Comparator since only toDb tokens are comparable
+ // by now
+ Collections.sort(tokens, new Comparator<MergerToken>() {
+
+ public int compare(MergerToken o1, MergerToken o2) {
+ if (o1 instanceof AbstractToDbToken && o2 instanceof AbstractToDbToken) {
+
+ return ((AbstractToDbToken) o1).compareTo(o2);
+ }
+ return 0;
+ }
+ });
+
+ return tokens;
+ }
+
+ private Collection<DbEntity> filter(DataMap existing, FiltersConfig filtersConfig) {
+ Collection<DbEntity> existingFiltered = new LinkedList<DbEntity>();
+ for (DbEntity entity : existing.getDbEntities()) {
+ if (filtersConfig.tableFilter(entity.getCatalog(), entity.getSchema()).isIncludeTable(entity.getName()) != null) {
+ existingFiltered.add(entity);
+ }
+ }
+ return existingFiltered;
+ }
+
+ private DataMap loadDataMapFromDb(DataSource dataSource, DbAdapter adapter, DbLoaderConfiguration config) {
+ try (Connection conn = dataSource.getConnection();) {
+
+ return new DbLoader(conn, adapter, new LoggingDbLoaderDelegate(LOGGER)).load(config);
+ } catch (SQLException e) {
+ throw new CayenneRuntimeException("Can't doLoad dataMap from db.", e);
+ }
+ }
+
+ public List<MergerToken> createMergeTokens(Collection<DbEntity> existing, Collection<DbEntity> loadedFromDb,
+ DbLoaderConfiguration config) {
+ Collection<DbEntity> dbEntitiesToDrop = new LinkedList<DbEntity>(loadedFromDb);
+
+ List<MergerToken> tokens = new LinkedList<MergerToken>();
+ for (DbEntity dbEntity : existing) {
+ String tableName = dbEntity.getName();
+
+ // look for table
+ DbEntity detectedEntity = findDbEntity(loadedFromDb, tableName);
+ if (detectedEntity == null) {
+ tokens.add(factory.createCreateTableToDb(dbEntity));
+ // TODO: does this work properly with createReverse?
+ for (DbRelationship rel : dbEntity.getRelationships()) {
+ tokens.add(factory.createAddRelationshipToDb(dbEntity, rel));
+ }
+ continue;
+ }
+
+ dbEntitiesToDrop.remove(detectedEntity);
+
+ tokens.addAll(checkRelationshipsToDrop(dbEntity, detectedEntity));
+ if (!config.isSkipRelationshipsLoading()) {
+ tokens.addAll(checkRelationshipsToAdd(dbEntity, detectedEntity));
+ }
+ tokens.addAll(checkRows(dbEntity, detectedEntity));
+
+ if (!config.isSkipPrimaryKeyLoading()) {
+ MergerToken token = checkPrimaryKeyChange(dbEntity, detectedEntity);
+ if (token != null) {
+ tokens.add(token);
+ }
+ }
+ }
+
+ // drop table
+ // TODO: support drop table. currently, too many tables are marked for
+ // drop
+ for (DbEntity e : dbEntitiesToDrop) {
+ tokens.add(factory.createDropTableToDb(e));
+ for (DbRelationship relationship : e.getRelationships()) {
+ DbEntity detectedEntity = findDbEntity(existing, relationship.getTargetEntityName());
+ if (detectedEntity != null) {
+ tokens.add(factory.createDropRelationshipToDb(detectedEntity, relationship.getReverseRelationship()));
+ }
+ }
+ }
+
+ return tokens;
+ }
+
+ private List<MergerToken> checkRows(DbEntity existing, DbEntity loadedFromDb) {
+ List<MergerToken> tokens = new LinkedList<MergerToken>();
+
+ // columns to drop
+ for (DbAttribute detected : loadedFromDb.getAttributes()) {
+ if (findDbAttribute(existing, detected.getName()) == null) {
+ tokens.add(factory.createDropColumnToDb(existing, detected));
+ }
+ }
+
+ // columns to add or modify
+ for (DbAttribute attr : existing.getAttributes()) {
+ String columnName = attr.getName().toUpperCase();
+
+ DbAttribute detected = findDbAttribute(loadedFromDb, columnName);
+
+ if (detected == null) {
+ tokens.add(factory.createAddColumnToDb(existing, attr));
+ if (attr.isMandatory()) {
+ if (valueForNull.hasValueFor(existing, attr)) {
+ tokens.add(factory.createSetValueForNullToDb(existing, attr, valueForNull));
+ }
+ tokens.add(factory.createSetNotNullToDb(existing, attr));
+ }
+ continue;
+ }
+
+ // check for not null
+ if (attr.isMandatory() != detected.isMandatory()) {
+ if (attr.isMandatory()) {
+ if (valueForNull.hasValueFor(existing, attr)) {
+ tokens.add(factory.createSetValueForNullToDb(existing, attr, valueForNull));
+ }
+ tokens.add(factory.createSetNotNullToDb(existing, attr));
+ } else {
+ tokens.add(factory.createSetAllowNullToDb(existing, attr));
+ }
+ }
+
+ // TODO: check more types than char/varchar
+ // TODO: psql report VARCHAR for text column, not clob
+ switch (detected.getType()) {
+ case Types.VARCHAR:
+ case Types.CHAR:
+ if (attr.getMaxLength() != detected.getMaxLength()) {
+ tokens.add(factory.createSetColumnTypeToDb(existing, detected, attr));
+ }
+ break;
+ }
+ }
+
+ return tokens;
+ }
+
+ private List<MergerToken> checkRelationshipsToDrop(DbEntity dbEntity, DbEntity detectedEntity) {
+ List<MergerToken> tokens = new LinkedList<MergerToken>();
+
+ // relationships to drop
+ for (DbRelationship detected : detectedEntity.getRelationships()) {
+ if (findDbRelationship(dbEntity, detected) == null) {
+
+ // alter detected relationship to match entity and attribute
+ // names.
+ // (case sensitively)
+
+ DbEntity targetEntity = findDbEntity(dbEntity.getDataMap().getDbEntities(),
+ detected.getTargetEntityName());
+ if (targetEntity == null) {
+ continue;
+ }
+
+ detected.setSourceEntity(dbEntity);
+ detected.setTargetEntityName(targetEntity);
+
+ // manipulate the joins to match the DbAttributes in the model
+ for (DbJoin join : detected.getJoins()) {
+ DbAttribute sattr = findDbAttribute(dbEntity, join.getSourceName());
+ if (sattr != null) {
+ join.setSourceName(sattr.getName());
+ }
+ DbAttribute tattr = findDbAttribute(targetEntity, join.getTargetName());
+ if (tattr != null) {
+ join.setTargetName(tattr.getName());
+ }
+ }
+
+ MergerToken token = factory.createDropRelationshipToDb(dbEntity, detected);
+ if (detected.isToMany()) {
+ // default toModel as we can not do drop a toMany in the db.
+ // only
+ // toOne are represented using foreign key
+ token = token.createReverse(factory);
+ }
+ tokens.add(token);
+ }
+ }
+
+ return tokens;
+ }
+
+ private List<MergerToken> checkRelationshipsToAdd(DbEntity dbEntity, DbEntity detectedEntity) {
+
+ List<MergerToken> tokens = new LinkedList<MergerToken>();
+
+ for (DbRelationship rel : dbEntity.getRelationships()) {
+ if (findDbRelationship(detectedEntity, rel) == null) {
+ AddRelationshipToDb token = (AddRelationshipToDb) factory.createAddRelationshipToDb(dbEntity, rel);
+
+ if (token.shouldGenerateFkConstraint()) {
+ // TODO I guess we should add relationship always; in order
+ // to have ability
+ // TODO generate reverse relationship. If it doesn't have
+ // anything to execute it will be passed
+ // TODO through execution without any affect on db
+ tokens.add(token);
+ }
+ }
+ }
+
+ return tokens;
+ }
+
+ private MergerToken checkPrimaryKeyChange(DbEntity dbEntity, DbEntity detectedEntity) {
+ Collection<DbAttribute> primaryKeyOriginal = detectedEntity.getPrimaryKeys();
+ Collection<DbAttribute> primaryKeyNew = dbEntity.getPrimaryKeys();
+
+ String primaryKeyName = null;
+ if (detectedEntity instanceof DetectedDbEntity) {
+ primaryKeyName = ((DetectedDbEntity) detectedEntity).getPrimaryKeyName();
+ }
+
+ if (upperCaseEntityNames(primaryKeyOriginal).equals(upperCaseEntityNames(primaryKeyNew))) {
+ return null;
+ }
+
+ return factory.createSetPrimaryKeyToDb(dbEntity, primaryKeyOriginal, primaryKeyNew, primaryKeyName);
+ }
+
+ private Set<String> upperCaseEntityNames(Collection<? extends Attribute> attrs) {
+ Set<String> names = new HashSet<String>();
+ for (Attribute attr : attrs) {
+ names.add(attr.getName().toUpperCase());
+ }
+ return names;
+ }
+
+ /**
+ * case insensitive search for a {@link DbEntity} in a {@link DataMap} by
+ * name
+ */
+ private DbEntity findDbEntity(Collection<DbEntity> dbEntities, String caseInsensitiveName) {
+ // TODO: create a Map with upper case keys?
+ for (DbEntity e : dbEntities) {
+ if (e.getName().equalsIgnoreCase(caseInsensitiveName)) {
+ return e;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * case insensitive search for a {@link DbAttribute} in a {@link DbEntity}
+ * by name
+ */
+ private DbAttribute findDbAttribute(DbEntity entity, String caseInsensitiveName) {
+ for (DbAttribute a : entity.getAttributes()) {
+ if (a.getName().equalsIgnoreCase(caseInsensitiveName)) {
+ return a;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * search for a {@link DbRelationship} like rel in the given
+ * {@link DbEntity}
+ */
+ private DbRelationship findDbRelationship(DbEntity entity, DbRelationship rel) {
+ for (DbRelationship candidate : entity.getRelationships()) {
+ if (equalDbJoinCollections(candidate.getJoins(), rel.getJoins())) {
+ return candidate;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Return true if the two unordered {@link Collection}s of {@link DbJoin}s
+ * are equal. Entity and Attribute names are compared case insensitively.
+ *
+ * TODO complexity n^2; sort both collection and go through them to compare
+ * = 2*n*log(n) + n
+ */
+ private static boolean equalDbJoinCollections(Collection<DbJoin> j1s, Collection<DbJoin> j2s) {
+ if (j1s.size() != j2s.size()) {
+ return false;
+ }
+
+ for (DbJoin j1 : j1s) {
+ if (!havePair(j2s, j1)) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ private static boolean havePair(Collection<DbJoin> j2s, DbJoin j1) {
+ for (DbJoin j2 : j2s) {
+ if (!isNull(j1.getSource()) && !isNull(j1.getTarget()) && !isNull(j2.getSource())
+ && !isNull(j2.getTarget())
+ && j1.getSource().getEntity().getName().equalsIgnoreCase(j2.getSource().getEntity().getName())
+ && j1.getTarget().getEntity().getName().equalsIgnoreCase(j2.getTarget().getEntity().getName())
+ && j1.getSourceName().equalsIgnoreCase(j2.getSourceName())
+ && j1.getTargetName().equalsIgnoreCase(j2.getTargetName())) {
+
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private static boolean isNull(DbAttribute attribute) {
+ return attribute == null || attribute.getEntity() == null;
+ }
+}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/2f7b1d53/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/DbMergerConfig.java
----------------------------------------------------------------------
diff --git a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/DbMergerConfig.java b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/DbMergerConfig.java
new file mode 100644
index 0000000..1cd80df
--- /dev/null
+++ b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/DbMergerConfig.java
@@ -0,0 +1,63 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.cayenne.dbsync.merge;
+
+import org.apache.cayenne.dbsync.reverse.filters.FiltersConfig;
+
+/**
+ * @since 4.0
+ */
+public class DbMergerConfig {
+
+ private FiltersConfig filtersConfig;
+
+ private boolean skipRelationships;
+
+ private boolean skipPrimaryKey;
+
+ public DbMergerConfig(FiltersConfig filtersConfig, boolean skipRelationships, boolean skipPrimaryKey) {
+ this.filtersConfig = filtersConfig;
+ this.skipRelationships = skipRelationships;
+ this.skipPrimaryKey = skipPrimaryKey;
+ }
+
+ public void setSkipRelationships(boolean skipRelationships) {
+ this.skipRelationships = skipRelationships;
+ }
+
+ public boolean isSkipRelationships() {
+ return skipRelationships;
+ }
+
+ public void setSkipPrimaryKey(boolean skipPrimaryKey) {
+ this.skipPrimaryKey = skipPrimaryKey;
+ }
+
+ public boolean isSkipPrimaryKey() {
+ return skipPrimaryKey;
+ }
+
+ public FiltersConfig getFiltersConfig() {
+ return filtersConfig;
+ }
+
+ public void setFiltersConfig(FiltersConfig filtersConfig) {
+ this.filtersConfig = filtersConfig;
+ }
+}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/2f7b1d53/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/DefaultModelMergeDelegate.java
----------------------------------------------------------------------
diff --git a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/DefaultModelMergeDelegate.java b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/DefaultModelMergeDelegate.java
new file mode 100644
index 0000000..617aad2
--- /dev/null
+++ b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/DefaultModelMergeDelegate.java
@@ -0,0 +1,89 @@
+/*****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ ****************************************************************/
+package org.apache.cayenne.dbsync.merge;
+
+import org.apache.cayenne.map.DbAttribute;
+import org.apache.cayenne.map.DbEntity;
+import org.apache.cayenne.map.DbRelationship;
+import org.apache.cayenne.map.ObjAttribute;
+import org.apache.cayenne.map.ObjEntity;
+import org.apache.cayenne.map.ObjRelationship;
+
+/**
+ * A default noop implementation of {@link ModelMergeDelegate}.
+ */
+public class DefaultModelMergeDelegate implements ModelMergeDelegate {
+
+ @Override
+ public void dbAttributeAdded(DbAttribute att) {
+ }
+
+ @Override
+ public void dbAttributeModified(DbAttribute att) {
+ }
+
+ @Override
+ public void dbAttributeRemoved(DbAttribute att) {
+ }
+
+ @Override
+ public void dbEntityAdded(DbEntity ent) {
+ }
+
+ @Override
+ public void dbEntityRemoved(DbEntity ent) {
+ }
+
+ @Override
+ public void dbRelationshipAdded(DbRelationship rel) {
+ }
+
+ @Override
+ public void dbRelationshipRemoved(DbRelationship rel) {
+ }
+
+ @Override
+ public void objAttributeAdded(ObjAttribute att) {
+ }
+
+ @Override
+ public void objAttributeModified(ObjAttribute att) {
+ }
+
+ @Override
+ public void objAttributeRemoved(ObjAttribute att) {
+ }
+
+ @Override
+ public void objEntityAdded(ObjEntity ent) {
+ }
+
+ @Override
+ public void objEntityRemoved(ObjEntity ent) {
+ }
+
+ @Override
+ public void objRelationshipAdded(ObjRelationship rel) {
+ }
+
+ @Override
+ public void objRelationshipRemoved(ObjRelationship rel) {
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/2f7b1d53/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/DefaultValueForNullProvider.java
----------------------------------------------------------------------
diff --git a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/DefaultValueForNullProvider.java b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/DefaultValueForNullProvider.java
new file mode 100644
index 0000000..9d4e0cd
--- /dev/null
+++ b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/DefaultValueForNullProvider.java
@@ -0,0 +1,62 @@
+/*****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ ****************************************************************/
+package org.apache.cayenne.dbsync.merge;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.cayenne.access.jdbc.SQLParameterBinding;
+import org.apache.cayenne.map.DbAttribute;
+import org.apache.cayenne.map.DbEntity;
+
+public class DefaultValueForNullProvider implements ValueForNullProvider {
+
+ private Map<String, SQLParameterBinding> values = new HashMap<>();
+
+ public void set(DbEntity entity, DbAttribute column, Object value, int type) {
+ values.put(createKey(entity, column), new SQLParameterBinding(value, type, column
+ .getAttributePrecision()));
+ }
+
+ protected SQLParameterBinding get(DbEntity entity, DbAttribute column) {
+ return values.get(createKey(entity, column));
+ }
+
+ public List<String> createSql(DbEntity entity, DbAttribute column) {
+ SQLParameterBinding value = get(entity, column);
+ if (value == null) {
+ return Collections.emptyList();
+ }
+
+ // TODO: change things so it is possible to use prepared statements here
+ return Collections.singletonList("UPDATE " + entity.getFullyQualifiedName()
+ + " SET " + column.getName() + "='" + value.getValue() + "' WHERE " + column.getName() + " IS NULL");
+ }
+
+ public boolean hasValueFor(DbEntity entity, DbAttribute column) {
+ return values.containsKey(createKey(entity, column));
+ }
+
+ private String createKey(DbEntity entity, DbAttribute attribute) {
+ return (entity.getFullyQualifiedName() + "." + attribute.getName()).toUpperCase();
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/2f7b1d53/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/DropColumnToDb.java
----------------------------------------------------------------------
diff --git a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/DropColumnToDb.java b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/DropColumnToDb.java
new file mode 100644
index 0000000..19914f0
--- /dev/null
+++ b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/DropColumnToDb.java
@@ -0,0 +1,52 @@
+/*****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ ****************************************************************/
+package org.apache.cayenne.dbsync.merge;
+
+import java.util.Collections;
+import java.util.List;
+
+import org.apache.cayenne.dba.DbAdapter;
+import org.apache.cayenne.dba.QuotingStrategy;
+import org.apache.cayenne.dbsync.merge.factory.MergerTokenFactory;
+import org.apache.cayenne.map.DbAttribute;
+import org.apache.cayenne.map.DbEntity;
+
+public class DropColumnToDb extends AbstractToDbToken.EntityAndColumn {
+
+ public DropColumnToDb(DbEntity entity, DbAttribute column) {
+ super("Drop Column", entity, column);
+ }
+
+ @Override
+ public List<String> createSql(DbAdapter adapter) {
+ StringBuilder sqlBuffer = new StringBuilder();
+ QuotingStrategy context = adapter.getQuotingStrategy();
+ sqlBuffer.append("ALTER TABLE ");
+ sqlBuffer.append(context.quotedFullyQualifiedName(getEntity()));
+ sqlBuffer.append(" DROP COLUMN ");
+ sqlBuffer.append(context.quotedName(getColumn()));
+
+ return Collections.singletonList(sqlBuffer.toString());
+ }
+
+ public MergerToken createReverse(MergerTokenFactory factory) {
+ return factory.createAddColumnToModel(getEntity(), getColumn());
+ }
+
+}