You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cayenne.apache.org by sk...@apache.org on 2016/12/19 11:46:22 UTC

[06/10] cayenne git commit: Merge branch 'master' into CAY-2172

Merge branch 'master' into CAY-2172

# Conflicts:
#	modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/action/MigrateAction.java
#	modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/dialog/db/DbLoaderHelper.java
#	modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/dialog/db/ModelerDbImportAction.java


Project: http://git-wip-us.apache.org/repos/asf/cayenne/repo
Commit: http://git-wip-us.apache.org/repos/asf/cayenne/commit/391c564b
Tree: http://git-wip-us.apache.org/repos/asf/cayenne/tree/391c564b
Diff: http://git-wip-us.apache.org/repos/asf/cayenne/diff/391c564b

Branch: refs/heads/master
Commit: 391c564be288412898c3861bc08305fabb1403b8
Parents: 190ab7c 25ae44a
Author: stariy <st...@gmail.com>
Authored: Wed Dec 14 22:47:27 2016 +0300
Committer: stariy <st...@gmail.com>
Committed: Wed Dec 14 22:47:27 2016 +0300

----------------------------------------------------------------------
 .../cayenne/dbsync/merge/AbstractMerger.java    |  92 ++++
 .../cayenne/dbsync/merge/AbstractToDbToken.java | 130 -----
 .../dbsync/merge/AbstractToModelToken.java      | 125 -----
 .../cayenne/dbsync/merge/AddColumnToDb.java     |  74 ---
 .../cayenne/dbsync/merge/AddColumnToModel.java  |  52 --
 .../dbsync/merge/AddRelationshipToDb.java       |  87 ---
 .../dbsync/merge/AddRelationshipToModel.java    |  89 ----
 .../cayenne/dbsync/merge/ChainMerger.java       |  71 +++
 .../cayenne/dbsync/merge/CreateTableToDb.java   |  86 ---
 .../dbsync/merge/CreateTableToModel.java        |  98 ----
 .../cayenne/dbsync/merge/DataMapMerger.java     | 156 ++++++
 .../dbsync/merge/DbAttributeDictionary.java     |  44 ++
 .../cayenne/dbsync/merge/DbAttributeMerger.java | 168 ++++++
 .../dbsync/merge/DbEntityDictionary.java        |  66 +++
 .../cayenne/dbsync/merge/DbEntityMerger.java    | 127 +++++
 .../apache/cayenne/dbsync/merge/DbMerger.java   | 396 --------------
 .../dbsync/merge/DbRelationshipDictionary.java  |  83 +++
 .../dbsync/merge/DbRelationshipMerger.java      | 133 +++++
 .../dbsync/merge/DefaultModelMergeDelegate.java |  89 ----
 .../merge/DefaultValueForNullProvider.java      |  62 ---
 .../cayenne/dbsync/merge/DropColumnToDb.java    |  61 ---
 .../cayenne/dbsync/merge/DropColumnToModel.java |  77 ---
 .../dbsync/merge/DropRelationshipToDb.java      |  83 ---
 .../dbsync/merge/DropRelationshipToModel.java   |  49 --
 .../cayenne/dbsync/merge/DropTableToDb.java     |  51 --
 .../cayenne/dbsync/merge/DropTableToModel.java  |  51 --
 .../cayenne/dbsync/merge/DummyReverseToken.java |  65 ---
 .../dbsync/merge/EmptyValueForNullProvider.java |  40 --
 .../dbsync/merge/EntityMergeSupport.java        | 515 ------------------
 .../cayenne/dbsync/merge/MergeDirection.java    |  70 ---
 .../org/apache/cayenne/dbsync/merge/Merger.java |  30 ++
 .../cayenne/dbsync/merge/MergerContext.java     | 170 ------
 .../cayenne/dbsync/merge/MergerDictionary.java  |  54 ++
 .../dbsync/merge/MergerDictionaryDiff.java      | 117 ++++
 .../cayenne/dbsync/merge/MergerDiffPair.java    |  39 ++
 .../cayenne/dbsync/merge/MergerToken.java       |  57 --
 .../dbsync/merge/ModelMergeDelegate.java        |  62 ---
 .../dbsync/merge/ProxyModelMergeDelegate.java   | 108 ----
 .../cayenne/dbsync/merge/SetAllowNullToDb.java  |  58 --
 .../dbsync/merge/SetAllowNullToModel.java       |  45 --
 .../cayenne/dbsync/merge/SetColumnTypeToDb.java | 111 ----
 .../dbsync/merge/SetColumnTypeToModel.java      |  95 ----
 .../cayenne/dbsync/merge/SetNotNullToDb.java    |  52 --
 .../cayenne/dbsync/merge/SetNotNullToModel.java |  45 --
 .../cayenne/dbsync/merge/SetPrimaryKeyToDb.java |  87 ---
 .../dbsync/merge/SetPrimaryKeyToModel.java      |  80 ---
 .../dbsync/merge/SetValueForNullToDb.java       |  48 --
 .../cayenne/dbsync/merge/TokenComparator.java   |  46 --
 .../dbsync/merge/ValueForNullProvider.java      |  41 --
 .../merge/context/EntityMergeSupport.java       | 516 ++++++++++++++++++
 .../dbsync/merge/context/MergeDirection.java    |  71 +++
 .../dbsync/merge/context/MergerContext.java     | 174 ++++++
 .../merge/factory/DB2MergerTokenFactory.java    |   4 +-
 .../factory/DefaultMergerTokenFactory.java      |  46 +-
 .../merge/factory/DerbyMergerTokenFactory.java  |   8 +-
 .../factory/FirebirdMergerTokenFactory.java     |  10 +-
 .../merge/factory/H2MergerTokenFactory.java     |   8 +-
 .../merge/factory/HSQLMergerTokenFactory.java   |  10 +-
 .../merge/factory/IngresMergerTokenFactory.java |  14 +-
 .../merge/factory/MergerTokenFactory.java       |   4 +-
 .../merge/factory/MySQLMergerTokenFactory.java  |  12 +-
 .../factory/OpenBaseMergerTokenFactory.java     |  12 +-
 .../merge/factory/OracleMergerTokenFactory.java |  10 +-
 .../factory/PostgresMergerTokenFactory.java     |   4 +-
 .../factory/SQLServerMergerTokenFactory.java    |  10 +-
 .../merge/factory/SybaseMergerTokenFactory.java |  12 +-
 .../token/DefaultValueForNullProvider.java      |  63 +++
 .../dbsync/merge/token/DummyReverseToken.java   |  68 +++
 .../merge/token/EmptyValueForNullProvider.java  |  41 ++
 .../cayenne/dbsync/merge/token/MergerToken.java |  58 ++
 .../dbsync/merge/token/TokenComparator.java     |  58 ++
 .../merge/token/ValueForNullProvider.java       |  42 ++
 .../merge/token/db/AbstractToDbToken.java       | 134 +++++
 .../dbsync/merge/token/db/AddColumnToDb.java    |  76 +++
 .../merge/token/db/AddRelationshipToDb.java     |  84 +++
 .../dbsync/merge/token/db/CreateTableToDb.java  |  89 ++++
 .../dbsync/merge/token/db/DropColumnToDb.java   |  63 +++
 .../merge/token/db/DropRelationshipToDb.java    |  85 +++
 .../dbsync/merge/token/db/DropTableToDb.java    |  53 ++
 .../dbsync/merge/token/db/SetAllowNullToDb.java |  60 +++
 .../merge/token/db/SetColumnTypeToDb.java       | 113 ++++
 .../dbsync/merge/token/db/SetNotNullToDb.java   |  54 ++
 .../merge/token/db/SetPrimaryKeyToDb.java       |  89 ++++
 .../merge/token/db/SetValueForNullToDb.java     |  52 ++
 .../merge/token/model/AbstractToModelToken.java | 129 +++++
 .../merge/token/model/AddColumnToModel.java     |  56 ++
 .../token/model/AddRelationshipToModel.java     |  92 ++++
 .../merge/token/model/CreateTableToModel.java   | 101 ++++
 .../merge/token/model/DropColumnToModel.java    |  80 +++
 .../token/model/DropRelationshipToModel.java    |  52 ++
 .../merge/token/model/DropTableToModel.java     |  54 ++
 .../merge/token/model/SetAllowNullToModel.java  |  48 ++
 .../merge/token/model/SetColumnTypeToModel.java |  98 ++++
 .../merge/token/model/SetNotNullToModel.java    |  48 ++
 .../merge/token/model/SetPrimaryKeyToModel.java |  83 +++
 .../reverse/db/DbAttributesBaseLoader.java      | 107 ----
 .../dbsync/reverse/db/DbAttributesLoader.java   |  43 --
 .../reverse/db/DbAttributesPerSchemaLoader.java | 131 -----
 .../cayenne/dbsync/reverse/db/DbLoader.java     | 534 -------------------
 .../reverse/db/DbLoaderConfiguration.java       |  84 ---
 .../dbsync/reverse/db/DbLoaderDelegate.java     |  63 ---
 .../reverse/db/DbRelationshipDetected.java      |  53 --
 .../dbsync/reverse/db/DbTableLoader.java        | 183 -------
 .../reverse/db/DefaultDbLoaderDelegate.java     |  63 ---
 .../cayenne/dbsync/reverse/db/ExportedKey.java  | 233 --------
 .../reverse/db/LoggingDbLoaderDelegate.java     |  61 ---
 .../dbsync/reverse/dbload/AbstractLoader.java   |  43 ++
 .../dbsync/reverse/dbload/AttributeLoader.java  | 137 +++++
 .../dbsync/reverse/dbload/DbLoadDataStore.java  |  90 ++++
 .../cayenne/dbsync/reverse/dbload/DbLoader.java | 118 ++++
 .../reverse/dbload/DbLoaderConfiguration.java   |  85 +++
 .../dbsync/reverse/dbload/DbLoaderDelegate.java |  63 +++
 .../reverse/dbload/DbRelationshipDetected.java  |  54 ++
 .../reverse/dbload/DefaultDbLoaderDelegate.java |  64 +++
 .../dbload/DefaultModelMergeDelegate.java       |  90 ++++
 .../dbsync/reverse/dbload/EntityLoader.java     | 106 ++++
 .../dbsync/reverse/dbload/ExportedKey.java      | 220 ++++++++
 .../reverse/dbload/ExportedKeyLoader.java       |  74 +++
 .../reverse/dbload/LoggingDbLoaderDelegate.java |  61 +++
 .../reverse/dbload/ModelMergeDelegate.java      |  65 +++
 .../dbload/PerCatalogAndSchemaLoader.java       |  58 ++
 .../dbsync/reverse/dbload/PerEntityLoader.java  |  64 +++
 .../dbsync/reverse/dbload/PrimaryKeyLoader.java |  60 +++
 .../reverse/dbload/ProcedureColumnLoader.java   | 127 +++++
 .../dbsync/reverse/dbload/ProcedureLoader.java  |  77 +++
 .../reverse/dbload/ProxyModelMergeDelegate.java | 109 ++++
 .../reverse/dbload/RelationshipLoader.java      | 168 ++++++
 .../dbsync/reverse/filters/TableFilter.java     |   7 +-
 .../dbsync/merge/AddColumnToModelIT.java        |  98 ----
 .../dbsync/merge/CreateTableToModelIT.java      |  97 ----
 .../cayenne/dbsync/merge/DataMapMergerTest.java | 400 ++++++++++++++
 .../cayenne/dbsync/merge/DbMergerTest.java      | 334 ------------
 .../dbsync/merge/DropColumnToModelIT.java       | 235 --------
 .../dbsync/merge/DropRelationshipToModelIT.java | 190 -------
 .../dbsync/merge/DropTableToModelIT.java        |  94 ----
 .../dbsync/merge/EntityMergeSupportIT.java      |   1 +
 .../apache/cayenne/dbsync/merge/MergeCase.java  |  21 +-
 .../dbsync/merge/SetAllowNullToDbIT.java        |  66 ---
 .../cayenne/dbsync/merge/SetNotNullToDbIT.java  |  62 ---
 .../dbsync/merge/SetPrimaryKeyToDbIT.java       |  58 --
 .../dbsync/merge/TokenComparatorTest.java       | 101 ----
 .../cayenne/dbsync/merge/TokensReverseTest.java |  90 ----
 .../merge/TokensToModelExecutionTest.java       |  80 ---
 .../cayenne/dbsync/merge/ValueForNullIT.java    | 126 -----
 .../dbsync/merge/token/TokenComparatorTest.java | 113 ++++
 .../dbsync/merge/token/TokensReverseTest.java   |  90 ++++
 .../merge/token/TokensToModelExecutionTest.java |  82 +++
 .../dbsync/merge/token/ValueForNullIT.java      | 129 +++++
 .../merge/token/db/SetAllowNullToDbIT.java      |  68 +++
 .../dbsync/merge/token/db/SetNotNullToDbIT.java |  64 +++
 .../merge/token/db/SetPrimaryKeyToDbIT.java     |  60 +++
 .../merge/token/model/AddColumnToModelIT.java   | 101 ++++
 .../merge/token/model/CreateTableToModelIT.java | 100 ++++
 .../merge/token/model/DropColumnToModelIT.java  | 238 +++++++++
 .../token/model/DropRelationshipToModelIT.java  | 192 +++++++
 .../merge/token/model/DropTableToModelIT.java   |  97 ++++
 .../cayenne/dbsync/reverse/db/DbLoaderIT.java   | 408 --------------
 .../reverse/dbload/AttributeLoaderIT.java       | 154 ++++++
 .../dbsync/reverse/dbload/BaseLoaderIT.java     |  91 ++++
 .../dbsync/reverse/dbload/DbLoaderIT.java       | 122 +++++
 .../dbsync/reverse/dbload/EntityLoaderIT.java   |  98 ++++
 .../reverse/dbload/ExportedKeyLoaderIT.java     |  85 +++
 .../reverse/dbload/PrimaryKeyLoaderIT.java      |  60 +++
 .../reverse/dbload/RelationshipsLoaderIT.java   |  98 ++++
 .../dbsync/reverse/filters/TableFilterTest.java |  81 ++-
 .../java/org/apache/cayenne/map/DbEntity.java   |   4 +-
 .../tools/dbimport/DbImportConfiguration.java   |  12 +-
 .../tools/dbimport/DefaultDbImportAction.java   |  42 +-
 .../dbimport/DefaultDbImportActionTest.java     | 151 +++---
 docs/doc/src/main/resources/RELEASE-NOTES.txt   |   1 +
 .../getting-started/src/docbkx/delete.xml       |  10 +-
 .../getting-started/src/docbkx/index.xml        |   4 +-
 .../getting-started/src/docbkx/java-classes.xml |  32 +-
 .../src/docbkx/object-context.xml               |  39 +-
 .../src/docbkx/object-relational-mapping.xml    |  69 ++-
 .../getting-started/src/docbkx/part1.xml        |   4 +-
 .../getting-started/src/docbkx/part2.xml        |   4 +-
 .../getting-started/src/docbkx/part3.xml        |   4 +-
 .../getting-started/src/docbkx/part4.xml        |   4 +-
 .../src/docbkx/persistent-objects.xml           |  37 +-
 .../getting-started/src/docbkx/select-query.xml |  24 +-
 .../getting-started/src/docbkx/setup.xml        |  28 +-
 .../src/docbkx/starting-project.xml             |  98 ++--
 .../getting-started/src/docbkx/webapp.xml       | 119 +++--
 .../getting-started/src/images/base-datamap.png | Bin 91074 -> 94872 bytes
 .../src/images/base-datanode.png                | Bin 81748 -> 96978 bytes
 .../src/images/chrome-webapp.png                | Bin 0 -> 42124 bytes
 .../src/images/eclipse-generatedclasses.png     | Bin 141000 -> 0 bytes
 .../src/images/eclipse-mvnrun.png               | Bin 147012 -> 0 bytes
 .../src/images/eclipse-xmlfiles.png             | Bin 27801 -> 0 bytes
 .../src/images/firefox-webapp.png               | Bin 25898 -> 0 bytes
 .../src/images/icon-attribute.gif               | Bin 0 -> 1171 bytes
 .../getting-started/src/images/icon-datamap.gif | Bin 0 -> 755 bytes
 .../src/images/icon-dbentity.gif                | Bin 0 -> 1171 bytes
 .../getting-started/src/images/icon-info.gif    | Bin 0 -> 755 bytes
 .../getting-started/src/images/icon-info.png    | Bin 0 -> 1098 bytes
 .../getting-started/src/images/icon-node.gif    | Bin 0 -> 331 bytes
 .../src/images/icon-objentity.gif               | Bin 0 -> 755 bytes
 .../src/images/icon-relationship.gif            | Bin 0 -> 1171 bytes
 .../src/images/icon-relationship.png            | Bin 0 -> 835 bytes
 .../getting-started/src/images/icon-sync.gif    | Bin 0 -> 331 bytes
 .../src/images/idea-configuration-menu.png      | Bin 0 -> 32911 bytes
 .../src/images/idea-generated-classes.png       | Bin 0 -> 198808 bytes
 .../src/images/idea-run-configuration.png       | Bin 0 -> 93059 bytes
 .../src/images/idea-xmlfiles.png                | Bin 0 -> 27783 bytes
 .../src/images/maven-plugin-install.png         | Bin 97455 -> 0 bytes
 .../src/images/modeler-artistid.png             | Bin 59372 -> 65879 bytes
 .../src/images/modeler-dbrelationship.png       | Bin 42245 -> 41730 bytes
 .../src/images/modeler-deleterule.png           | Bin 69992 -> 83349 bytes
 .../src/images/modeler-started.png              | Bin 133410 -> 98815 bytes
 .../src/images/tutorial-eclipse-project.png     | Bin 70937 -> 0 bytes
 .../src/images/tutorial-idea-project.png        | Bin 0 -> 48037 bytes
 .../modeler/action/CreateObjEntityAction.java   |   2 +-
 .../modeler/action/DbEntitySyncAction.java      |   2 +-
 .../cayenne/modeler/action/MigrateAction.java   |   1 +
 .../modeler/action/ObjEntitySyncAction.java     |   2 +-
 .../modeler/dialog/db/merge/MergerOptions.java  |  33 +-
 .../db/merge/MergerTokenSelectorController.java |   6 +-
 .../dialog/db/merge/MergerTokenTableModel.java  |   4 +-
 .../dialog/objentity/EntitySyncController.java  |   2 +-
 220 files changed, 8975 insertions(+), 7525 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cayenne/blob/391c564b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/action/MigrateAction.java
----------------------------------------------------------------------
diff --cc modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/action/MigrateAction.java
index ccf6d3e,0648d2c..af0dcd0
--- a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/action/MigrateAction.java
+++ b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/action/MigrateAction.java
@@@ -19,15 -19,21 +19,16 @@@
  
  package org.apache.cayenne.modeler.action;
  
 -import org.apache.cayenne.dba.DbAdapter;
  import org.apache.cayenne.dbsync.merge.factory.MergerTokenFactoryProvider;
+ import org.apache.cayenne.dbsync.reverse.dbload.DbLoader;
  import org.apache.cayenne.map.DataMap;
  import org.apache.cayenne.modeler.Application;
 -import org.apache.cayenne.modeler.dialog.db.DataSourceController;
 -import org.apache.cayenne.modeler.dialog.db.DbMigrateOptionsDialog;
 -import org.apache.cayenne.modeler.dialog.db.MergerOptions;
 -import org.apache.cayenne.modeler.pref.DBConnectionInfo;
 +import org.apache.cayenne.modeler.dialog.db.DataSourceWizard;
 +import org.apache.cayenne.modeler.dialog.db.merge.DbMigrateOptionsDialog;
 +import org.apache.cayenne.modeler.dialog.db.merge.MergerOptions;
  
 -import javax.sql.DataSource;
 -import javax.swing.*;
  import java.awt.event.ActionEvent;
 -import java.util.Collections;
 -import java.util.List;
 +import java.util.Collection;
  
  /**
   * Action that alter database schema to match a DataMap.

http://git-wip-us.apache.org/repos/asf/cayenne/blob/391c564b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/dialog/db/merge/MergerOptions.java
----------------------------------------------------------------------
diff --cc modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/dialog/db/merge/MergerOptions.java
index a914cf1,0000000..26564a3
mode 100644,000000..100644
--- a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/dialog/db/merge/MergerOptions.java
+++ b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/dialog/db/merge/MergerOptions.java
@@@ -1,395 -1,0 +1,394 @@@
 +/*****************************************************************
 + *   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.modeler.dialog.db.merge;
 +
 +import org.apache.cayenne.CayenneRuntimeException;
 +import org.apache.cayenne.configuration.event.DataMapEvent;
 +import org.apache.cayenne.dba.DbAdapter;
- import org.apache.cayenne.dbsync.merge.AbstractToDbToken;
- import org.apache.cayenne.dbsync.merge.DbMerger;
- import org.apache.cayenne.dbsync.merge.DefaultModelMergeDelegate;
- import org.apache.cayenne.dbsync.merge.MergeDirection;
- import org.apache.cayenne.dbsync.merge.MergerContext;
- import org.apache.cayenne.dbsync.merge.MergerToken;
- import org.apache.cayenne.dbsync.merge.ModelMergeDelegate;
- import org.apache.cayenne.dbsync.merge.ProxyModelMergeDelegate;
++import org.apache.cayenne.dbsync.merge.token.db.AbstractToDbToken;
++import org.apache.cayenne.dbsync.merge.DataMapMerger;
++import org.apache.cayenne.dbsync.reverse.dbload.DefaultModelMergeDelegate;
++import org.apache.cayenne.dbsync.merge.context.MergeDirection;
++import org.apache.cayenne.dbsync.merge.context.MergerContext;
++import org.apache.cayenne.dbsync.merge.token.MergerToken;
++import org.apache.cayenne.dbsync.reverse.dbload.ModelMergeDelegate;
++import org.apache.cayenne.dbsync.reverse.dbload.ProxyModelMergeDelegate;
 +import org.apache.cayenne.dbsync.merge.factory.MergerTokenFactory;
 +import org.apache.cayenne.dbsync.merge.factory.MergerTokenFactoryProvider;
 +import org.apache.cayenne.dbsync.naming.DefaultObjectNameGenerator;
 +import org.apache.cayenne.dbsync.naming.NoStemStemmer;
- import org.apache.cayenne.dbsync.reverse.db.DbLoader;
- import org.apache.cayenne.dbsync.reverse.db.DbLoaderConfiguration;
- import org.apache.cayenne.dbsync.reverse.db.LoggingDbLoaderDelegate;
++import org.apache.cayenne.dbsync.reverse.dbload.DbLoader;
++import org.apache.cayenne.dbsync.reverse.dbload.DbLoaderConfiguration;
++import org.apache.cayenne.dbsync.reverse.dbload.LoggingDbLoaderDelegate;
 +import org.apache.cayenne.dbsync.reverse.filters.FiltersConfig;
 +import org.apache.cayenne.dbsync.reverse.filters.PatternFilter;
 +import org.apache.cayenne.dbsync.reverse.filters.TableFilter;
 +import org.apache.cayenne.map.DataMap;
 +import org.apache.cayenne.map.ObjEntity;
 +import org.apache.cayenne.map.event.MapEvent;
 +import org.apache.cayenne.modeler.Application;
 +import org.apache.cayenne.modeler.ProjectController;
 +import org.apache.cayenne.modeler.dialog.ValidationResultBrowser;
 +import org.apache.cayenne.modeler.pref.DBConnectionInfo;
 +import org.apache.cayenne.modeler.util.CayenneController;
 +import org.apache.cayenne.project.Project;
 +import org.apache.cayenne.resource.Resource;
 +import org.apache.cayenne.swing.BindingBuilder;
 +import org.apache.cayenne.swing.ObjectBinding;
 +import org.apache.cayenne.tools.dbimport.DefaultDbImportAction;
 +import org.apache.cayenne.validation.ValidationResult;
 +import org.apache.commons.logging.LogFactory;
 +
 +import javax.sql.DataSource;
 +import javax.swing.JFileChooser;
 +import javax.swing.JOptionPane;
 +import javax.swing.WindowConstants;
 +import javax.swing.event.ChangeEvent;
 +import javax.swing.event.ChangeListener;
 +import java.awt.Component;
 +import java.io.File;
 +import java.io.FileWriter;
 +import java.io.IOException;
 +import java.io.PrintWriter;
 +import java.sql.Connection;
 +import java.sql.SQLException;
 +import java.util.Collection;
 +import java.util.Iterator;
 +import java.util.LinkedList;
 +import java.util.List;
 +
 +public class MergerOptions extends CayenneController {
 +
 +    protected MergerOptionsView view;
 +    protected ObjectBinding sqlBinding;
 +
 +    protected DBConnectionInfo connectionInfo;
 +    protected DataMap dataMap;
 +    protected DbAdapter adapter;
 +    protected String textForSQL;
 +
 +    protected MergerTokenSelectorController tokens;
 +    protected String defaultCatalog;
 +    protected String defaultSchema;
 +    private MergerTokenFactoryProvider mergerTokenFactoryProvider;
 +
 +    public MergerOptions(ProjectController parent,
 +                         String title,
 +                         DBConnectionInfo connectionInfo,
 +                         DataMap dataMap,
 +                         String defaultCatalog,
 +                         String defaultSchema,
 +                         MergerTokenFactoryProvider mergerTokenFactoryProvider) {
 +        super(parent);
 +
 +        this.mergerTokenFactoryProvider = mergerTokenFactoryProvider;
 +        this.dataMap = dataMap;
 +        this.tokens = new MergerTokenSelectorController(parent);
 +        this.view = new MergerOptionsView(tokens.getView());
 +        this.connectionInfo = connectionInfo;
 +        this.defaultCatalog = defaultCatalog;
 +        this.defaultSchema = defaultSchema;
 +        this.view.setTitle(title);
 +        initController();
 +
 +        prepareMigrator();
 +        createSQL();
 +        refreshView();
 +    }
 +
 +    public Component getView() {
 +        return view;
 +    }
 +
 +    public String getTextForSQL() {
 +        return textForSQL;
 +    }
 +
 +    protected void initController() {
 +
 +        BindingBuilder builder = new BindingBuilder(
 +                getApplication().getBindingFactory(),
 +                this);
 +
 +        sqlBinding = builder.bindToTextArea(view.getSql(), "textForSQL");
 +
 +        builder.bindToAction(view.getGenerateButton(), "generateSchemaAction()");
 +        builder.bindToAction(view.getSaveSqlButton(), "storeSQLAction()");
 +        builder.bindToAction(view.getCancelButton(), "closeAction()");
 +
 +        // refresh SQL if different tables were selected
 +        view.getTabs().addChangeListener(new ChangeListener() {
 +
 +            public void stateChanged(ChangeEvent e) {
 +                if (view.getTabs().getSelectedIndex() == 1) {
 +                    // this assumes that some tables where checked/unchecked... not very
 +                    // efficient
 +                    refreshGeneratorAction();
 +                }
 +            }
 +        });
 +    }
 +
 +    /**
 +     * check database and create the {@link List} of {@link MergerToken}s
 +     */
 +    protected void prepareMigrator() {
 +        try {
 +            adapter = connectionInfo.makeAdapter(getApplication().getClassLoadingService());
 +
 +            MergerTokenFactory mergerTokenFactory = mergerTokenFactoryProvider.get(adapter);
 +            tokens.setMergerTokenFactory(mergerTokenFactory);
 +
 +
 +            FiltersConfig filters = FiltersConfig.create(defaultCatalog, defaultSchema, TableFilter.everything(),
 +                    PatternFilter.INCLUDE_NOTHING);
 +
-             DbMerger merger = DbMerger.builder(mergerTokenFactory)
++            DataMapMerger merger = DataMapMerger.builder(mergerTokenFactory)
 +                    .filters(filters)
 +                    .build();
 +
 +            DbLoaderConfiguration config = new DbLoaderConfiguration();
 +            config.setFiltersConfig(filters);
 +
 +            DataSource dataSource = connectionInfo.makeDataSource(getApplication().getClassLoadingService());
 +
-             DataMap dbImport = new DataMap();
++            DataMap dbImport;
 +            try (Connection conn = dataSource.getConnection();) {
-                 new DbLoader(conn,
-                         adapter,
++                dbImport = new DbLoader(adapter, conn,
++                        config,
 +                        new LoggingDbLoaderDelegate(LogFactory.getLog(DbLoader.class)),
 +                        new DefaultObjectNameGenerator(NoStemStemmer.getInstance()))
-                         .load(dbImport, config);
- 
++                        .load();
 +            } catch (SQLException e) {
 +                throw new CayenneRuntimeException("Can't doLoad dataMap from db.", e);
 +            }
 +
 +            tokens.setTokens(merger.createMergeTokens(dataMap, dbImport));
 +        } catch (Exception ex) {
 +            reportError("Error loading adapter", ex);
 +        }
 +    }
 +
 +    /**
 +     * Returns SQL statements generated for selected schema generation options.
 +     */
 +    protected void createSQL() {
 +        // convert them to string representation for display
 +        StringBuilder buf = new StringBuilder();
 +
 +        Iterator<MergerToken> it = tokens.getSelectedTokens().iterator();
 +        String batchTerminator = adapter.getBatchTerminator();
 +
 +        String lineEnd = batchTerminator != null ? "\n" + batchTerminator + "\n\n" : "\n\n";
 +        while (it.hasNext()) {
 +            MergerToken token = it.next();
 +
 +            if (token instanceof AbstractToDbToken) {
 +                AbstractToDbToken tdb = (AbstractToDbToken) token;
 +                for (String sql : tdb.createSql(adapter)) {
 +                    buf.append(sql);
 +                    buf.append(lineEnd);
 +                }
 +            }
 +        }
 +
 +        textForSQL = buf.toString();
 +    }
 +
 +    protected void refreshView() {
 +        sqlBinding.updateView();
 +    }
 +
 +    // ===============
 +    // Actions
 +    // ===============
 +
 +    /**
 +     * Starts options dialog.
 +     */
 +    public void startupAction() {
 +        view.pack();
 +        view.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
 +        view.setModal(true);
 +        makeCloseableOnEscape();
 +        centerView();
 +        view.setVisible(true);
 +    }
 +
 +    public void refreshGeneratorAction() {
 +        refreshSQLAction();
 +    }
 +
 +    /**
 +     * Updates a text area showing generated SQL.
 +     */
 +    public void refreshSQLAction() {
 +        createSQL();
 +        sqlBinding.updateView();
 +    }
 +
 +    /**
 +     * Performs configured schema operations via DbGenerator.
 +     */
 +    public void generateSchemaAction() {
 +        refreshGeneratorAction();
 +
 +        // sanity check...
 +        List<MergerToken> tokensToMigrate = tokens.getSelectedTokens();
 +        if (tokensToMigrate.isEmpty()) {
 +            JOptionPane.showMessageDialog(getView(), "Nothing to migrate.");
 +            return;
 +        }
 +
 +        DataSource dataSource;
 +        try {
 +            dataSource = connectionInfo.makeDataSource(getApplication()
 +                    .getClassLoadingService());
 +        } catch (SQLException ex) {
 +            reportError("Migration Error", ex);
 +            return;
 +        }
 +
 +        final Collection<ObjEntity> loadedObjEntities = new LinkedList<>();
 +
 +        MergerContext mergerContext = MergerContext.builder(dataMap)
 +                .syntheticDataNode(dataSource, adapter)
 +                .delegate(createDelegate(loadedObjEntities))
 +                .build();
 +
 +        boolean modelChanged = applyTokens(tokensToMigrate, mergerContext);
 +
 +        DefaultDbImportAction.flattenManyToManyRelationships(
 +                dataMap,
 +                loadedObjEntities,
 +                mergerContext.getNameGenerator());
 +
 +        notifyProjectModified(modelChanged);
 +
 +        reportFailures(mergerContext);
 +    }
 +
 +    private ModelMergeDelegate createDelegate(final Collection<ObjEntity> loadedObjEntities) {
 +        return new ProxyModelMergeDelegate(new DefaultModelMergeDelegate()) {
 +            @Override
 +            public void objEntityAdded(ObjEntity ent) {
 +                loadedObjEntities.add(ent);
 +                super.objEntityAdded(ent);
 +            }
 +        };
 +    }
 +
 +    private boolean applyTokens(List<MergerToken> tokensToMigrate, MergerContext mergerContext) {
 +        boolean modelChanged = false;
 +
 +        try {
 +            for (MergerToken tok : tokensToMigrate) {
 +                int numOfFailuresBefore = getFailuresCount(mergerContext);
 +
 +                tok.execute(mergerContext);
 +
 +                if (!modelChanged && tok.getDirection().equals(MergeDirection.TO_MODEL)) {
 +                    modelChanged = true;
 +                }
 +                if (numOfFailuresBefore == getFailuresCount(mergerContext)) {
 +                    // looks like the token executed without failures
 +                    tokens.removeToken(tok);
 +                }
 +            }
 +        } catch (Throwable th) {
 +            reportError("Migration Error", th);
 +        }
 +
 +        return modelChanged;
 +    }
 +
 +    private int getFailuresCount(MergerContext mergerContext) {
 +        return mergerContext.getValidationResult().getFailures().size();
 +    }
 +
 +    private void reportFailures(MergerContext mergerContext) {
 +        ValidationResult failures = mergerContext.getValidationResult();
 +        if (failures == null || !failures.hasFailures()) {
 +            JOptionPane.showMessageDialog(getView(), "Migration Complete.");
 +        } else {
 +            new ValidationResultBrowser(this).startupAction(
 +                    "Migration Complete",
 +                    "Migration finished. The following problem(s) were ignored.",
 +                    failures);
 +        }
 +    }
 +
 +    private void notifyProjectModified(boolean modelChanged) {
 +        if(!modelChanged) {
 +            return;
 +        }
 +
 +        // mark the model as unsaved
 +        Project project = getApplication().getProject();
 +        project.setModified(true);
 +
 +        ProjectController projectController = getProjectController();
 +        projectController.setDirty(true);
 +
 +        projectController.fireDataMapEvent(new DataMapEvent(Application.getFrame(),
 +                dataMap, MapEvent.REMOVE));
 +        projectController.fireDataMapEvent(new DataMapEvent(Application.getFrame(),
 +                dataMap, MapEvent.ADD));
 +    }
 +
 +    /**
 +     * Allows user to save generated SQL in a file.
 +     */
 +    public void storeSQLAction() {
 +        JFileChooser fc = new JFileChooser();
 +        fc.setDialogType(JFileChooser.SAVE_DIALOG);
 +        fc.setDialogTitle("Save SQL Script");
 +
 +        Resource projectDir = getApplication().getProject().getConfigurationResource();
 +
 +        if (projectDir != null) {
 +            fc.setCurrentDirectory(new File(projectDir.getURL().getPath()));
 +        }
 +
 +        if (fc.showSaveDialog(getView()) == JFileChooser.APPROVE_OPTION) {
 +            refreshGeneratorAction();
 +
 +            try {
 +                File file = fc.getSelectedFile();
 +                FileWriter fw = new FileWriter(file);
 +                PrintWriter pw = new PrintWriter(fw);
 +                pw.print(textForSQL);
 +                pw.flush();
 +                pw.close();
 +            } catch (IOException ex) {
 +                reportError("Error Saving SQL", ex);
 +            }
 +        }
 +    }
 +
 +    private ProjectController getProjectController() {
 +        return getApplication().getFrameController().getProjectController();
 +    }
 +
 +    public void closeAction() {
 +        view.dispose();
 +    }
 +
 +}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/391c564b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/dialog/db/merge/MergerTokenSelectorController.java
----------------------------------------------------------------------
diff --cc modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/dialog/db/merge/MergerTokenSelectorController.java
index 52d6ce3,0000000..7f6d4da
mode 100644,000000..100644
--- a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/dialog/db/merge/MergerTokenSelectorController.java
+++ b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/dialog/db/merge/MergerTokenSelectorController.java
@@@ -1,240 -1,0 +1,240 @@@
 +/*****************************************************************
 + *   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.modeler.dialog.db.merge;
 +
- import org.apache.cayenne.dbsync.merge.MergeDirection;
- import org.apache.cayenne.dbsync.merge.MergerToken;
- import org.apache.cayenne.dbsync.merge.TokenComparator;
++import org.apache.cayenne.dbsync.merge.context.MergeDirection;
++import org.apache.cayenne.dbsync.merge.token.MergerToken;
++import org.apache.cayenne.dbsync.merge.token.TokenComparator;
 +import org.apache.cayenne.dbsync.merge.factory.MergerTokenFactory;
 +import org.apache.cayenne.modeler.Application;
 +import org.apache.cayenne.modeler.util.CayenneController;
 +import org.apache.cayenne.swing.BindingBuilder;
 +import org.apache.cayenne.swing.ObjectBinding;
 +
 +import javax.swing.*;
 +import javax.swing.table.AbstractTableModel;
 +import javax.swing.table.TableColumn;
 +import javax.swing.table.TableColumnModel;
 +import javax.swing.table.TableModel;
 +import java.awt.*;
 +import java.util.ArrayList;
 +import java.util.Collections;
 +import java.util.HashSet;
 +import java.util.List;
 +import java.util.Set;
 +
 +public class MergerTokenSelectorController extends CayenneController {
 +
 +    protected MergerTokenSelectorView view;
 +    protected ObjectBinding tableBinding;
 +
 +    protected MergerToken token;
 +    protected int permanentlyExcludedCount;
 +    protected Set<MergerToken> excludedTokens;
 +    protected List<MergerToken> selectableTokensList;
 +    protected MergerTokenFactory mergerTokenFactory;
 +
 +    public MergerTokenSelectorController(CayenneController parent) {
 +        super(parent);
 +        this.view = new MergerTokenSelectorView();
 +        this.excludedTokens = new HashSet<MergerToken>();
 +        this.selectableTokensList = new ArrayList<MergerToken>();
 +        initController();
 +    }
 +
 +    public void setMergerTokenFactory(MergerTokenFactory mergerTokenFactory) {
 +        this.mergerTokenFactory = mergerTokenFactory;
 +    }
 +
 +    public void setTokens(List<MergerToken> tokens) {
 +        selectableTokensList.clear();
 +        selectableTokensList.addAll(tokens);
 +        excludedTokens.addAll(tokens);
 +    }
 +
 +    public List<MergerToken> getSelectedTokens() {
 +        List<MergerToken> t = new ArrayList<MergerToken>(selectableTokensList);
 +        t.removeAll(excludedTokens);
 +        return Collections.unmodifiableList(t);
 +    }
 +
 +    public List<MergerToken> getSelectableTokens() {
 +        return Collections.unmodifiableList(selectableTokensList);
 +    }
 +    
 +    public void removeToken(MergerToken token) {
 +        selectableTokensList.remove(token);
 +        excludedTokens.remove(token);
 +
 +        AbstractTableModel model = (AbstractTableModel) view.getTokens().getModel();
 +        model.fireTableDataChanged();
 +    }
 +
 +    // ----- properties -----
 +
 +    public Component getView() {
 +        return view;
 +    }
 +
 +    /**
 +     * Called by table binding script to set current token.
 +     */
 +    public void setToken(MergerToken token) {
 +        this.token = token;
 +    }
 +
 +    /**
 +     * Returns {@link MergerToken}s that are excluded from DB generation.
 +     */
 +    /*
 +     * public Collection getExcludedTokens() { return excludedTokens; }
 +     */
 +
 +    public boolean isIncluded() {
 +        if (token == null) {
 +            return false;
 +        }
 +
 +        return !excludedTokens.contains(token);
 +    }
 +
 +    public void setIncluded(boolean b) {
 +        if (token == null) {
 +            return;
 +        }
 +
 +        if (b) {
 +            excludedTokens.remove(token);
 +        }
 +        else {
 +            excludedTokens.add(token);
 +        }
 +
 +        tableSelectedAction();
 +    }
 +
 +    /**
 +     * A callback action that updates the state of Select All checkbox.
 +     */
 +    public void tableSelectedAction() {
 +        int unselectedCount = excludedTokens.size() - permanentlyExcludedCount;
 +
 +        if (unselectedCount == selectableTokensList.size()) {
 +            view.getCheckAll().setSelected(false);
 +        }
 +        else if (unselectedCount == 0) {
 +            view.getCheckAll().setSelected(true);
 +        }
 +    }
 +
 +    // ------ other stuff ------
 +
 +    protected void initController() {
 +        BindingBuilder builder = new BindingBuilder(
 +                getApplication().getBindingFactory(),
 +                this);
 +
 +        builder.bindToAction(view.getCheckAll(), "checkAllAction()");
 +        builder.bindToAction(view.getReverseAll(), "reverseAllAction()");
 +
 +        TableModel model = new MergerTokenTableModel(this);
 +
 +        MergeDirection[] dirs = new MergeDirection[] {
 +                MergeDirection.TO_DB, MergeDirection.TO_MODEL
 +        };
 +
 +        view.getTokens().setModel(model);
 +
 +        TableColumnModel columnModel = view.getTokens().getColumnModel();
 +        
 +        // dropdown for direction column
 +        JComboBox directionCombo = Application.getWidgetFactory().createComboBox(dirs, false);
 +        directionCombo.setEditable(false);
 +        TableColumn directionColumn = columnModel.getColumn(
 +                MergerTokenTableModel.COL_DIRECTION);
 +        directionColumn.setCellEditor(new DefaultCellEditor(directionCombo));
 +
 +        columnModel.getColumn(MergerTokenTableModel.COL_SELECT).setPreferredWidth(50);
 +        columnModel.getColumn(MergerTokenTableModel.COL_DIRECTION).setPreferredWidth(100);
 +        columnModel.getColumn(MergerTokenTableModel.COL_SELECT).setMaxWidth(50);
 +        columnModel.getColumn(MergerTokenTableModel.COL_DIRECTION).setMaxWidth(100);
 +    }
 +
 +    public boolean isSelected(MergerToken token) {
 +        return (selectableTokensList.contains(token) && !excludedTokens.contains(token));
 +    }
 +
 +    public void select(MergerToken token, boolean select) {
 +        if (select) {
 +            excludedTokens.remove(token);
 +        }
 +        else {
 +            excludedTokens.add(token);
 +        }
 +    }
 +
 +    public void setDirection(MergerToken token, MergeDirection direction) {
 +        if (token.getDirection().equals(direction)) {
 +            return;
 +        }
 +        int i = selectableTokensList.indexOf(token);
 +        MergerToken reverse = token.createReverse(mergerTokenFactory);
 +        selectableTokensList.set(i, reverse);
 +        if (excludedTokens.remove(token)) {
 +            excludedTokens.add(reverse);
 +        }
 +        
 +        /**
 +         * Repaint, so that "Operation" column updates properly
 +         */
 +        view.getTokens().repaint();
 +    }
 +
 +    public void checkAllAction() {
 +
 +        boolean isCheckAllSelected = view.getCheckAll().isSelected();
 +
 +        if (isCheckAllSelected) {
 +            excludedTokens.clear();
 +        }
 +        else {
 +            excludedTokens.addAll(selectableTokensList);
 +        }
 +
 +        AbstractTableModel model = (AbstractTableModel) view.getTokens().getModel();
 +        model.fireTableDataChanged();
 +    }
 +
 +    public void reverseAllAction() {
 +        
 +        for (int i = 0; i < selectableTokensList.size(); i++) {
 +            MergerToken token = selectableTokensList.get(i);
 +            MergerToken reverse = token.createReverse(mergerTokenFactory);
 +            selectableTokensList.set(i, reverse);
 +            if (excludedTokens.remove(token)) {
 +                excludedTokens.add(reverse);
 +            }
 +        }
 +
 +        Collections.sort(selectableTokensList, new TokenComparator());
 +        AbstractTableModel model = (AbstractTableModel) view.getTokens().getModel();
 +        model.fireTableDataChanged();
 +    }
 +}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/391c564b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/dialog/db/merge/MergerTokenTableModel.java
----------------------------------------------------------------------
diff --cc modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/dialog/db/merge/MergerTokenTableModel.java
index 4fc78f0,0000000..7a04f16
mode 100644,000000..100644
--- a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/dialog/db/merge/MergerTokenTableModel.java
+++ b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/dialog/db/merge/MergerTokenTableModel.java
@@@ -1,129 -1,0 +1,129 @@@
 +/*****************************************************************
 + *   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.modeler.dialog.db.merge;
 +
- import org.apache.cayenne.dbsync.merge.MergeDirection;
- import org.apache.cayenne.dbsync.merge.MergerToken;
++import org.apache.cayenne.dbsync.merge.context.MergeDirection;
++import org.apache.cayenne.dbsync.merge.token.MergerToken;
 +
 +import javax.swing.table.AbstractTableModel;
 +import java.util.List;
 +
 +
 +public class MergerTokenTableModel extends AbstractTableModel {
 +
 +    public static final int COL_SELECT = 0;
 +    public static final int COL_DIRECTION = 1;
 +    public static final int COL_NAME = 2;
 +    public static final int COL_VALUE = 3;
 +
 +    private MergerTokenSelectorController controller;
 +
 +    private List<MergerToken> tokens;
 +
 +    public MergerTokenTableModel(MergerTokenSelectorController controller) {
 +        this.controller = controller;
 +        this.tokens = controller.getSelectableTokens();
 +    }
 +
 +    private MergerTokenSelectorController getController() {
 +        return controller;
 +    }
 +
 +    public Class getColumnClass(int columnIndex) {
 +        switch (columnIndex) {
 +            case COL_SELECT:
 +                return Boolean.class;
 +            case COL_DIRECTION:
 +                // TODO: correct?
 +                return String.class;
 +            case COL_NAME:
 +            case COL_VALUE:
 +                return String.class;
 +        }
 +
 +        return null;
 +    }
 +
 +    public int getColumnCount() {
 +        return 4;
 +    }
 +
 +    public String getColumnName(int columnIndex) {
 +        switch (columnIndex) {
 +            case COL_SELECT:
 +                return "";
 +            case COL_NAME:
 +                return "Operation";
 +            case COL_DIRECTION:
 +                return "Direction";
 +            case COL_VALUE:
 +                return "";
 +        }
 +
 +        return null;
 +    }
 +
 +    public int getRowCount() {
 +        return tokens.size();
 +    }
 +
 +    public MergerToken getToken(int rowIndex) {
 +        return tokens.get(rowIndex);
 +    }
 +
 +    public Object getValueAt(int rowIndex, int columnIndex) {
 +        MergerToken token = getToken(rowIndex);
 +        switch (columnIndex) {
 +            case COL_SELECT:
 +                return Boolean.valueOf(getController().isSelected(token));
 +            case COL_NAME:
 +                return token.getTokenName();
 +            case COL_DIRECTION:
 +                return token.getDirection();
 +            case COL_VALUE:
 +                return token.getTokenValue();
 +        }
 +        return null;
 +    }
 +
 +    public boolean isCellEditable(int rowIndex, int columnIndex) {
 +        switch (columnIndex) {
 +            case COL_SELECT:
 +            case COL_DIRECTION:
 +                return true;
 +        }
 +        return false;
 +    }
 +
 +    public void setValueAt(Object value, int rowIndex, int columnIndex) {
 +        MergerToken token = getToken(rowIndex);
 +        switch (columnIndex) {
 +            case COL_SELECT:
 +                Boolean val = (Boolean) value;
 +                getController().select(token, val.booleanValue());
 +                break;
 +            case COL_DIRECTION:
 +                MergeDirection direction = (MergeDirection) value;
 +                getController().setDirection(token, direction);
 +                break;
 +        }
 +    }
 +
 +}