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/12/14 18:29:50 UTC

[1/9] cayenne git commit: New DbLoader for dbsync utils - loading process split in independent small steps - DbLoader always return new DataMap, it doesn't accept it from outside

Repository: cayenne
Updated Branches:
  refs/heads/master 1f6100db2 -> 836399cba


http://git-wip-us.apache.org/repos/asf/cayenne/blob/8c273022/cayenne-dbsync/src/test/java/org/apache/cayenne/dbsync/reverse/dbload/DbLoaderIT.java
----------------------------------------------------------------------
diff --git a/cayenne-dbsync/src/test/java/org/apache/cayenne/dbsync/reverse/dbload/DbLoaderIT.java b/cayenne-dbsync/src/test/java/org/apache/cayenne/dbsync/reverse/dbload/DbLoaderIT.java
new file mode 100644
index 0000000..bf0f89f
--- /dev/null
+++ b/cayenne-dbsync/src/test/java/org/apache/cayenne/dbsync/reverse/dbload/DbLoaderIT.java
@@ -0,0 +1,105 @@
+/*****************************************************************
+ *   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.reverse.dbload;
+
+import org.apache.cayenne.configuration.server.ServerRuntime;
+import org.apache.cayenne.dba.DbAdapter;
+import org.apache.cayenne.dba.TypesMapping;
+import org.apache.cayenne.dbsync.naming.DefaultObjectNameGenerator;
+import org.apache.cayenne.dbsync.naming.NoStemStemmer;
+import org.apache.cayenne.di.Inject;
+import org.apache.cayenne.map.DataMap;
+import org.apache.cayenne.map.DbAttribute;
+import org.apache.cayenne.unit.UnitDbAdapter;
+import org.apache.cayenne.unit.di.server.CayenneProjects;
+import org.apache.cayenne.unit.di.server.ServerCase;
+import org.apache.cayenne.unit.di.server.ServerCaseDataSourceFactory;
+import org.apache.cayenne.unit.di.server.UseServerRuntime;
+import org.junit.After;
+import org.junit.Before;
+
+import java.sql.Connection;
+
+/**
+ * All tests have been moved to corresponding loaders tests.
+ */
+@UseServerRuntime(CayenneProjects.TESTMAP_PROJECT)
+public class DbLoaderIT extends ServerCase {
+
+    public static final DbLoaderConfiguration CONFIG = new DbLoaderConfiguration();
+    @Inject
+    private ServerRuntime runtime;
+
+    @Inject
+    private DbAdapter adapter;
+
+    @Inject
+    private ServerCaseDataSourceFactory dataSourceFactory;
+
+    @Inject
+    private UnitDbAdapter accessStackAdapter;
+
+    private Connection connection;
+
+    private static String msgForTypeMismatch(DbAttribute origAttr, DbAttribute newAttr) {
+        return msgForTypeMismatch(origAttr.getType(), newAttr);
+    }
+
+    private static String msgForTypeMismatch(int origType, DbAttribute newAttr) {
+        String nt = TypesMapping.getSqlNameByType(newAttr.getType());
+        String ot = TypesMapping.getSqlNameByType(origType);
+        return attrMismatch(newAttr.getName(), "expected type: <" + ot + ">, but was <" + nt + ">");
+    }
+
+    private static String attrMismatch(String attrName, String msg) {
+        return "[Error loading attribute '" + attrName + "': " + msg + "]";
+    }
+
+    @Before
+    public void before() throws Exception {
+        this.connection = dataSourceFactory.getSharedDataSource().getConnection();
+    }
+
+    private DbLoader createDbLoader(boolean meaningfulPK, boolean meaningfulFK) {
+        return new DbLoader(adapter, connection, CONFIG, null, new DefaultObjectNameGenerator(NoStemStemmer.getInstance()));
+    }
+
+    @After
+    public void after() throws Exception {
+        connection.close();
+    }
+
+    private void assertUniqueConstraintsInRelationships(DataMap map) {
+        // unfortunately JDBC metadata doesn't provide info for UNIQUE
+        // constraints....
+        // cant reengineer them...
+        // upd. actually it's provided:
+        // http://docs.oracle.com/javase/7/docs/api/java/sql/DatabaseMetaData.html#getIndexInfo%28java.lang.String,%20java.lang.String,%20java.lang.String,%20boolean,%20boolean%29
+
+        // find rel to TO_ONEFK1
+        /*
+         * Iterator it = getDbEntity(map,
+         * "TO_ONEFK2").getRelationships().iterator(); DbRelationship rel =
+         * (DbRelationship) it.next(); assertEquals("TO_ONEFK1",
+         * rel.getTargetEntityName());
+         * assertFalse("UNIQUE constraint was ignored...", rel.isToMany());
+         */
+    }
+}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/8c273022/cayenne-dbsync/src/test/java/org/apache/cayenne/dbsync/reverse/dbload/EntityLoaderIT.java
----------------------------------------------------------------------
diff --git a/cayenne-dbsync/src/test/java/org/apache/cayenne/dbsync/reverse/dbload/EntityLoaderIT.java b/cayenne-dbsync/src/test/java/org/apache/cayenne/dbsync/reverse/dbload/EntityLoaderIT.java
new file mode 100644
index 0000000..b05bc21
--- /dev/null
+++ b/cayenne-dbsync/src/test/java/org/apache/cayenne/dbsync/reverse/dbload/EntityLoaderIT.java
@@ -0,0 +1,98 @@
+/*****************************************************************
+ *   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.reverse.dbload;
+
+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.DbEntity;
+
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+
+public class EntityLoaderIT extends BaseLoaderIT {
+
+    @Test
+    public void testGetTablesWithWrongCatalog() throws Exception {
+        DbLoaderConfiguration config = new DbLoaderConfiguration();
+        config.setFiltersConfig(
+                FiltersConfig.create("WRONG", null, TableFilter.everything(), PatternFilter.INCLUDE_NOTHING)
+        );
+
+        EntityLoader loader = new EntityLoader(adapter, config, new DefaultDbLoaderDelegate());
+        loader.load(connection.getMetaData(), store);
+
+        assertTrue("Store is not empty", store.getDbEntities().isEmpty());
+    }
+
+    @Test
+    public void testGetTablesWithWrongSchema() throws Exception {
+        DbLoaderConfiguration config = new DbLoaderConfiguration();
+        config.setFiltersConfig(
+                FiltersConfig.create(null, "WRONG", TableFilter.everything(), PatternFilter.INCLUDE_NOTHING)
+        );
+
+        EntityLoader loader = new EntityLoader(adapter, config, new DefaultDbLoaderDelegate());
+        loader.load(connection.getMetaData(), store);
+
+        assertTrue("Store is not empty", store.getDbEntities().isEmpty());
+    }
+
+    @Test
+    public void testLoad() throws Exception {
+
+        EntityLoader loader = new EntityLoader(adapter, EMPTY_CONFIG, new DefaultDbLoaderDelegate());
+        loader.load(connection.getMetaData(), store);
+
+        assertFalse("Store not empty", store.getDbEntities().isEmpty());
+        assertDbEntities();
+
+        if(accessStackAdapter.supportsLobs()) {
+            assertLobDbEntities();
+        }
+    }
+
+    private void assertDbEntities() {
+        DbEntity dae = getDbEntity("ARTIST");
+        assertNotNull("Null 'ARTIST' entity, other DbEntities: " + store.getDbEntityMap(), dae);
+        assertEquals("ARTIST", dae.getName().toUpperCase());
+
+        if (adapter.supportsGeneratedKeys()) {
+            DbEntity bag = getDbEntity("GENERATED_COLUMN_TEST");
+            assertNotNull("Null 'GENERATED_COLUMN_TEST' entity, other DbEntities: " + store.getDbEntityMap(), bag);
+        }
+    }
+
+    private void assertLobDbEntities() {
+        DbEntity blobEnt = getDbEntity("BLOB_TEST");
+        assertNotNull(blobEnt);
+
+        DbEntity clobEnt = getDbEntity("CLOB_TEST");
+        assertNotNull(clobEnt);
+    }
+
+
+}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/8c273022/cayenne-dbsync/src/test/java/org/apache/cayenne/dbsync/reverse/dbload/ExportedKeyLoaderIT.java
----------------------------------------------------------------------
diff --git a/cayenne-dbsync/src/test/java/org/apache/cayenne/dbsync/reverse/dbload/ExportedKeyLoaderIT.java b/cayenne-dbsync/src/test/java/org/apache/cayenne/dbsync/reverse/dbload/ExportedKeyLoaderIT.java
new file mode 100644
index 0000000..9c71159
--- /dev/null
+++ b/cayenne-dbsync/src/test/java/org/apache/cayenne/dbsync/reverse/dbload/ExportedKeyLoaderIT.java
@@ -0,0 +1,71 @@
+/*****************************************************************
+ *   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.reverse.dbload;
+
+import org.apache.cayenne.map.DbAttribute;
+import org.apache.cayenne.map.DbEntity;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+
+public class ExportedKeyLoaderIT extends BaseLoaderIT {
+
+    @Test
+    public void testExportedKeyLoad() throws Exception {
+        boolean supportsFK = accessStackAdapter.supportsFKConstraints();
+        if(!supportsFK) {
+            return;
+        }
+
+        createEntity("ARTIST");
+        createEntity("GALLERY");
+        createEntity("PAINTING");
+        DbEntity artist = getDbEntity("ARTIST");
+        DbAttribute artistId = new DbAttribute("ARTIST_ID");
+        artist.addAttribute(artistId);
+
+        DbEntity gallery = getDbEntity("GALLERY");
+        DbAttribute galleryId = new DbAttribute("GALLERY_ID");
+        gallery.addAttribute(galleryId);
+
+        DbEntity painting = getDbEntity("PAINTING");
+        DbAttribute paintingId = new DbAttribute("PAINTING_ID");
+        DbAttribute paintingArtistId = new DbAttribute("ARTIST_ID");
+        DbAttribute paintingGalleryId = new DbAttribute("GALLERY_ID");
+        painting.addAttribute(paintingId);
+        painting.addAttribute(paintingArtistId);
+        painting.addAttribute(paintingGalleryId);
+
+        ExportedKeyLoader loader = new ExportedKeyLoader(EMPTY_CONFIG, new DefaultDbLoaderDelegate());
+        loader.load(connection.getMetaData(), store);
+
+        assertEquals(2, store.getExportedKeysEntrySet().size());
+
+        ExportedKey artistIdFk = store.getExportedKeysEntrySet()
+                .iterator().next()
+                .getValue().iterator().next();
+        assertEquals("ARTIST", artistIdFk.getPk().getTable());
+        assertEquals("ARTIST_ID", artistIdFk.getPk().getColumn());
+
+        assertEquals("PAINTING", artistIdFk.getFk().getTable());
+        assertEquals("ARTIST_ID", artistIdFk.getFk().getColumn());
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/8c273022/cayenne-dbsync/src/test/java/org/apache/cayenne/dbsync/reverse/dbload/PrimaryKeyLoaderIT.java
----------------------------------------------------------------------
diff --git a/cayenne-dbsync/src/test/java/org/apache/cayenne/dbsync/reverse/dbload/PrimaryKeyLoaderIT.java b/cayenne-dbsync/src/test/java/org/apache/cayenne/dbsync/reverse/dbload/PrimaryKeyLoaderIT.java
new file mode 100644
index 0000000..56be301
--- /dev/null
+++ b/cayenne-dbsync/src/test/java/org/apache/cayenne/dbsync/reverse/dbload/PrimaryKeyLoaderIT.java
@@ -0,0 +1,60 @@
+/*****************************************************************
+ *   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.reverse.dbload;
+
+import java.util.Collection;
+
+import org.apache.cayenne.map.DbAttribute;
+import org.apache.cayenne.map.DbEntity;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+public class PrimaryKeyLoaderIT extends BaseLoaderIT {
+
+    @Test
+    public void testPrimaryKeyLoad() throws Exception {
+        createDbEntities();
+        DbEntity artist = getDbEntity("ARTIST");
+        DbAttribute artistId = new DbAttribute("ARTIST_ID");
+        DbAttribute artistName = new DbAttribute("ARTIST_NAME");
+        DbAttribute artistId1 = new DbAttribute("ARTIST_ID1");
+
+        artist.addAttribute(artistId);
+        artist.addAttribute(artistName);
+        artist.addAttribute(artistId1);
+        assertFalse(artistId.isPrimaryKey());
+        assertFalse(artistName.isPrimaryKey());
+        assertFalse(artistId1.isPrimaryKey());
+
+        PrimaryKeyLoader loader = new PrimaryKeyLoader(EMPTY_CONFIG, new DefaultDbLoaderDelegate());
+        loader.load(connection.getMetaData(), store);
+
+        assertTrue(artistId.isPrimaryKey());
+        assertFalse(artistId1.isPrimaryKey());
+        assertFalse(artistName.isPrimaryKey());
+        Collection<DbAttribute> pk = artist.getPrimaryKeys();
+        assertEquals(1, pk.size());
+        assertEquals(artistId, pk.iterator().next());
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/8c273022/cayenne-dbsync/src/test/java/org/apache/cayenne/dbsync/reverse/dbload/RelationshipsLoaderIT.java
----------------------------------------------------------------------
diff --git a/cayenne-dbsync/src/test/java/org/apache/cayenne/dbsync/reverse/dbload/RelationshipsLoaderIT.java b/cayenne-dbsync/src/test/java/org/apache/cayenne/dbsync/reverse/dbload/RelationshipsLoaderIT.java
new file mode 100644
index 0000000..a73833e
--- /dev/null
+++ b/cayenne-dbsync/src/test/java/org/apache/cayenne/dbsync/reverse/dbload/RelationshipsLoaderIT.java
@@ -0,0 +1,82 @@
+/*****************************************************************
+ *   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.reverse.dbload;
+
+import java.sql.DatabaseMetaData;
+import java.util.Collection;
+
+import org.apache.cayenne.dbsync.naming.DefaultObjectNameGenerator;
+import org.apache.cayenne.map.DbRelationship;
+import org.junit.Test;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+public class RelationshipsLoaderIT extends BaseLoaderIT {
+
+    @Test
+    public void testRelationshipLoad() throws Exception {
+        boolean supportsFK = accessStackAdapter.supportsFKConstraints();
+        if(!supportsFK) {
+            return;
+        }
+
+        DatabaseMetaData metaData = connection.getMetaData();
+        DbLoaderDelegate delegate = new DefaultDbLoaderDelegate();
+
+        // We need all data to check relationships, so simply load it all
+        EntityLoader entityLoader = new EntityLoader(adapter, EMPTY_CONFIG, delegate);
+        AttributeLoader attributeLoader = new AttributeLoader(adapter, EMPTY_CONFIG, delegate);
+        PrimaryKeyLoader primaryKeyLoader = new PrimaryKeyLoader(EMPTY_CONFIG, delegate);
+        ExportedKeyLoader exportedKeyLoader = new ExportedKeyLoader(EMPTY_CONFIG, delegate);
+
+        entityLoader.load(metaData, store);
+        attributeLoader.load(metaData, store);
+        primaryKeyLoader.load(metaData, store);
+        exportedKeyLoader.load(metaData, store);
+
+        // *** TESTING THIS ***
+        RelationshipLoader relationshipLoader = new RelationshipLoader(EMPTY_CONFIG, delegate, new DefaultObjectNameGenerator());
+        relationshipLoader.load(metaData, store);
+
+        Collection<DbRelationship> rels = getDbEntity("ARTIST").getRelationships();
+        assertNotNull(rels);
+        assertTrue(!rels.isEmpty());
+
+        // test one-to-one
+        rels = getDbEntity("PAINTING").getRelationships();
+        assertNotNull(rels);
+
+        // find relationship to PAINTING_INFO
+        DbRelationship oneToOne = null;
+        for (DbRelationship rel : rels) {
+            if ("PAINTING_INFO".equalsIgnoreCase(rel.getTargetEntityName())) {
+                oneToOne = rel;
+                break;
+            }
+        }
+
+        assertNotNull("No relationship to PAINTING_INFO", oneToOne);
+        assertFalse("Relationship to PAINTING_INFO must be to-one", oneToOne.isToMany());
+        assertTrue("Relationship to PAINTING_INFO must be to-one", oneToOne.isToDependentPK());
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/8c273022/cayenne-dbsync/src/test/java/org/apache/cayenne/dbsync/reverse/filters/TableFilterTest.java
----------------------------------------------------------------------
diff --git a/cayenne-dbsync/src/test/java/org/apache/cayenne/dbsync/reverse/filters/TableFilterTest.java b/cayenne-dbsync/src/test/java/org/apache/cayenne/dbsync/reverse/filters/TableFilterTest.java
index 979b20f..4ef3c23 100644
--- a/cayenne-dbsync/src/test/java/org/apache/cayenne/dbsync/reverse/filters/TableFilterTest.java
+++ b/cayenne-dbsync/src/test/java/org/apache/cayenne/dbsync/reverse/filters/TableFilterTest.java
@@ -18,13 +18,17 @@
  ****************************************************************/
 package org.apache.cayenne.dbsync.reverse.filters;
 
-import junit.framework.TestCase;
-
 import java.util.TreeSet;
 import java.util.regex.Pattern;
 
-public class TableFilterTest extends TestCase {
+import org.apache.cayenne.dbimport.ExcludeTable;
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+public class TableFilterTest {
 
+    @Test
     public void testIncludeEverything() {
         TableFilter filter = TableFilter.everything();
 
@@ -34,58 +38,79 @@ public class TableFilterTest extends TestCase {
         assertNotNull(filter.isIncludeTable("alex"));
     }
 
+    @Test
     public void testInclude() {
-        TreeSet<IncludeTableFilter> includes = new TreeSet<IncludeTableFilter>();
+        TreeSet<IncludeTableFilter> includes = new TreeSet<>();
         includes.add(new IncludeTableFilter("aaa"));
         includes.add(new IncludeTableFilter("bb"));
 
-        TableFilter filter = new TableFilter(includes, new TreeSet<Pattern>(PatternFilter.PATTERN_COMPARATOR));
+        TableFilter filter = new TableFilter(includes, new TreeSet<>(PatternFilter.PATTERN_COMPARATOR));
 
-        assertNotNull(filter.isIncludeTable("aaa"));
-        assertNull(filter.isIncludeTable("aa"));
-        assertNull(filter.isIncludeTable("aaaa"));
+        assertTrue(filter.isIncludeTable("aaa"));
+        assertFalse(filter.isIncludeTable("aa"));
+        assertFalse(filter.isIncludeTable("aaaa"));
 
-        assertNotNull(filter.isIncludeTable("bb"));
-        assertNull(filter.isIncludeTable(""));
-        assertNull(filter.isIncludeTable("bbbb"));
+        assertTrue(filter.isIncludeTable("bb"));
+        assertFalse(filter.isIncludeTable(""));
+        assertFalse(filter.isIncludeTable("bbbb"));
     }
 
-
+    @Test
     public void testExclude() {
-        TreeSet<Pattern> excludes = new TreeSet<Pattern>(PatternFilter.PATTERN_COMPARATOR);
+        TreeSet<Pattern> excludes = new TreeSet<>(PatternFilter.PATTERN_COMPARATOR);
         excludes.add(Pattern.compile("aaa"));
         excludes.add(Pattern.compile("bb"));
 
-        TreeSet<IncludeTableFilter> includes = new TreeSet<IncludeTableFilter>();
+        TreeSet<IncludeTableFilter> includes = new TreeSet<>();
         includes.add(new IncludeTableFilter(null, PatternFilter.INCLUDE_EVERYTHING));
 
         TableFilter filter = new TableFilter(includes, excludes);
 
-        assertNull(filter.isIncludeTable("aaa"));
-        assertNotNull(filter.isIncludeTable("aa"));
-        assertNotNull(filter.isIncludeTable("aaaa"));
+        assertFalse(filter.isIncludeTable("aaa"));
+        assertTrue(filter.isIncludeTable("aa"));
+        assertTrue(filter.isIncludeTable("aaaa"));
 
-        assertNull(filter.isIncludeTable("bb"));
-        assertNotNull(filter.isIncludeTable(""));
-        assertNotNull(filter.isIncludeTable("bbbb"));
+        assertFalse(filter.isIncludeTable("bb"));
+        assertTrue(filter.isIncludeTable(""));
+        assertTrue(filter.isIncludeTable("bbbb"));
     }
 
+    @Test
     public void testIncludeExclude() {
-        TreeSet<Pattern> excludes = new TreeSet<Pattern>(PatternFilter.PATTERN_COMPARATOR);
+        TreeSet<Pattern> excludes = new TreeSet<>(PatternFilter.PATTERN_COMPARATOR);
         excludes.add(Pattern.compile("aaa"));
         excludes.add(Pattern.compile("bb"));
 
-        TreeSet<IncludeTableFilter> includes = new TreeSet<IncludeTableFilter>();
+        TreeSet<IncludeTableFilter> includes = new TreeSet<>();
         includes.add(new IncludeTableFilter("aa.*"));
 
         TableFilter filter = new TableFilter(includes, excludes);
 
-        assertNull(filter.isIncludeTable("aaa"));
-        assertNotNull(filter.isIncludeTable("aa"));
-        assertNotNull(filter.isIncludeTable("aaaa"));
+        assertFalse(filter.isIncludeTable("aaa"));
+        assertTrue(filter.isIncludeTable("aa"));
+        assertTrue(filter.isIncludeTable("aaaa"));
+
+        assertFalse(filter.isIncludeTable("bb"));
+        assertFalse(filter.isIncludeTable(""));
+        assertFalse(filter.isIncludeTable("bbbb"));
+    }
+
+    @Test
+    public void testGetTableFilter() {
+        TreeSet<IncludeTableFilter> includes = new TreeSet<IncludeTableFilter>();
+        includes.add(new IncludeTableFilter("aaa"));
+        includes.add(new IncludeTableFilter("bb"));
+
+        TreeSet<Pattern> excludes = new TreeSet<>();
+
+        TableFilter filter = new TableFilter(includes, excludes);
+
+        assertNotNull(filter.getIncludeTableColumnFilter("aaa"));
+        assertNull(filter.getIncludeTableColumnFilter("aa"));
+        assertNull(filter.getIncludeTableColumnFilter("aaaa"));
 
-        assertNull(filter.isIncludeTable("bb"));
-        assertNull(filter.isIncludeTable(""));
-        assertNull(filter.isIncludeTable("bbbb"));
+        assertNotNull(filter.getIncludeTableColumnFilter("bb"));
+        assertNull(filter.getIncludeTableColumnFilter(""));
+        assertNull(filter.getIncludeTableColumnFilter("bbbb"));
     }
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cayenne/blob/8c273022/cayenne-tools/src/main/java/org/apache/cayenne/tools/dbimport/DbImportConfiguration.java
----------------------------------------------------------------------
diff --git a/cayenne-tools/src/main/java/org/apache/cayenne/tools/dbimport/DbImportConfiguration.java b/cayenne-tools/src/main/java/org/apache/cayenne/tools/dbimport/DbImportConfiguration.java
index 681d353..720ce54 100644
--- a/cayenne-tools/src/main/java/org/apache/cayenne/tools/dbimport/DbImportConfiguration.java
+++ b/cayenne-tools/src/main/java/org/apache/cayenne/tools/dbimport/DbImportConfiguration.java
@@ -31,10 +31,10 @@ import org.apache.cayenne.dbsync.naming.DefaultObjectNameGenerator;
 import org.apache.cayenne.dbsync.naming.NoStemStemmer;
 import org.apache.cayenne.dbsync.naming.ObjectNameGenerator;
 import org.apache.cayenne.dbsync.naming.PatternStemmer;
-import org.apache.cayenne.dbsync.reverse.db.DbLoaderConfiguration;
-import org.apache.cayenne.dbsync.reverse.db.DbLoaderDelegate;
-import org.apache.cayenne.dbsync.reverse.db.DefaultDbLoaderDelegate;
-import org.apache.cayenne.dbsync.reverse.db.LoggingDbLoaderDelegate;
+import org.apache.cayenne.dbsync.reverse.dbload.DbLoaderConfiguration;
+import org.apache.cayenne.dbsync.reverse.dbload.DbLoaderDelegate;
+import org.apache.cayenne.dbsync.reverse.dbload.DefaultDbLoaderDelegate;
+import org.apache.cayenne.dbsync.reverse.dbload.LoggingDbLoaderDelegate;
 import org.apache.cayenne.dbsync.reverse.filters.FiltersConfig;
 import org.apache.commons.logging.Log;
 

http://git-wip-us.apache.org/repos/asf/cayenne/blob/8c273022/cayenne-tools/src/main/java/org/apache/cayenne/tools/dbimport/DefaultDbImportAction.java
----------------------------------------------------------------------
diff --git a/cayenne-tools/src/main/java/org/apache/cayenne/tools/dbimport/DefaultDbImportAction.java b/cayenne-tools/src/main/java/org/apache/cayenne/tools/dbimport/DefaultDbImportAction.java
index 331a155..24466b3 100644
--- a/cayenne-tools/src/main/java/org/apache/cayenne/tools/dbimport/DefaultDbImportAction.java
+++ b/cayenne-tools/src/main/java/org/apache/cayenne/tools/dbimport/DefaultDbImportAction.java
@@ -34,9 +34,8 @@ import org.apache.cayenne.dbsync.merge.TokenComparator;
 import org.apache.cayenne.dbsync.merge.factory.MergerTokenFactory;
 import org.apache.cayenne.dbsync.merge.factory.MergerTokenFactoryProvider;
 import org.apache.cayenne.dbsync.naming.ObjectNameGenerator;
-import org.apache.cayenne.dbsync.reverse.db.DbLoader;
-import org.apache.cayenne.dbsync.reverse.db.DbLoaderConfiguration;
-import org.apache.cayenne.dbsync.reverse.db.DbLoaderDelegate;
+import org.apache.cayenne.dbsync.reverse.dbload.DbLoader;
+import org.apache.cayenne.dbsync.reverse.dbload.DbLoaderConfiguration;
 import org.apache.cayenne.dbsync.reverse.filters.CatalogFilter;
 import org.apache.cayenne.dbsync.reverse.filters.FiltersConfig;
 import org.apache.cayenne.dbsync.reverse.filters.PatternFilter;
@@ -143,7 +142,7 @@ public class DefaultDbImportAction implements DbImportAction {
 
         DataMap sourceDataMap;
         try (Connection connection = dataSource.getConnection()) {
-            sourceDataMap = load(config, adapter, connection, objectNameGenerator);
+            sourceDataMap = load(config, adapter, connection);
         }
 
         DataMap targetDataMap = existingTargetMap(config);
@@ -409,19 +408,16 @@ public class DefaultDbImportAction implements DbImportAction {
 
     protected DataMap load(DbImportConfiguration config,
                            DbAdapter adapter,
-                           Connection connection,
-                           ObjectNameGenerator objectNameGenerator) throws Exception {
-
-        DataMap dataMap = new DataMap("_import_source_");
-        createDbLoader(adapter, connection, config.createLoaderDelegate(), objectNameGenerator)
-                .load(dataMap, config.getDbLoaderConfig());
-        return dataMap;
+                           Connection connection) throws Exception {
+        return createDbLoader(adapter, connection, config).load();
     }
 
     protected DbLoader createDbLoader(DbAdapter adapter,
-                                      Connection connection,
-                                      DbLoaderDelegate dbLoaderDelegate,
-                                      ObjectNameGenerator objectNameGenerator) {
-        return new DbLoader(connection, adapter, dbLoaderDelegate, objectNameGenerator);
+                                       Connection connection,
+                                       DbImportConfiguration config) {
+        return new DbLoader(adapter, connection,
+                config.getDbLoaderConfig(),
+                config.createLoaderDelegate(),
+                config.createNameGenerator());
     }
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cayenne/blob/8c273022/cayenne-tools/src/test/java/org/apache/cayenne/tools/dbimport/DefaultDbImportActionTest.java
----------------------------------------------------------------------
diff --git a/cayenne-tools/src/test/java/org/apache/cayenne/tools/dbimport/DefaultDbImportActionTest.java b/cayenne-tools/src/test/java/org/apache/cayenne/tools/dbimport/DefaultDbImportActionTest.java
index aa635b2..855d3ee 100644
--- a/cayenne-tools/src/test/java/org/apache/cayenne/tools/dbimport/DefaultDbImportActionTest.java
+++ b/cayenne-tools/src/test/java/org/apache/cayenne/tools/dbimport/DefaultDbImportActionTest.java
@@ -37,9 +37,9 @@ 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.naming.ObjectNameGenerator;
-import org.apache.cayenne.dbsync.reverse.db.DbLoader;
-import org.apache.cayenne.dbsync.reverse.db.DbLoaderConfiguration;
-import org.apache.cayenne.dbsync.reverse.db.DbLoaderDelegate;
+import org.apache.cayenne.dbsync.reverse.dbload.DbLoader;
+import org.apache.cayenne.dbsync.reverse.dbload.DbLoaderConfiguration;
+import org.apache.cayenne.dbsync.reverse.dbload.DbLoaderDelegate;
 import org.apache.cayenne.di.DIBootstrap;
 import org.apache.cayenne.di.Injector;
 import org.apache.cayenne.map.DataMap;
@@ -113,21 +113,22 @@ public class DefaultDbImportActionTest {
     @Test
     public void testNewDataMapImport() throws Exception {
 
-        DbLoader dbLoader = new DbLoader(mockConnection, mockAdapter, mockDelegate, mockNameGenerator) {
-            @Override
-            public void load(DataMap dataMap, DbLoaderConfiguration config) throws SQLException {
-                new DataMapBuilder(dataMap).withDbEntities(2).build();
-            }
-        };
-
         DbImportConfiguration config = mock(DbImportConfiguration.class);
-
         when(config.createMergeDelegate()).thenReturn(new DefaultModelMergeDelegate());
         when(config.getDbLoaderConfig()).thenReturn(new DbLoaderConfiguration());
         when(config.getTargetDataMap()).thenReturn(new File("xyz.map.xml"));
         when(config.createNameGenerator()).thenReturn(new DefaultObjectNameGenerator(NoStemStemmer.getInstance()));
         when(config.createMeaningfulPKFilter()).thenReturn(NamePatternMatcher.EXCLUDE_ALL);
 
+        DbLoader dbLoader = new DbLoader(mockAdapter, mockConnection, config.getDbLoaderConfig(), mockDelegate, mockNameGenerator) {
+            @Override
+            public DataMap load() throws SQLException {
+                DataMap map = new DataMap();
+                new DataMapBuilder(map).withDbEntities(2).build();
+                return map;
+            }
+        };
+
         final boolean[] haveWeTriedToSave = {false};
         DefaultDbImportAction action = buildDbImportAction(new FileProjectSaver() {
             @Override
@@ -146,9 +147,19 @@ public class DefaultDbImportActionTest {
 
     @Test
     public void testImportWithFieldChanged() throws Exception {
-        DbLoader dbLoader = new DbLoader(mockConnection, mockAdapter, mockDelegate, mockNameGenerator) {
+
+        DbImportConfiguration config = mock(DbImportConfiguration.class);
+
+        when(config.getTargetDataMap()).thenReturn(FILE_STUB);
+        when(config.createMergeDelegate()).thenReturn(new DefaultModelMergeDelegate());
+        when(config.getDbLoaderConfig()).thenReturn(new DbLoaderConfiguration());
+        when(config.createNameGenerator()).thenReturn(new DefaultObjectNameGenerator(NoStemStemmer.getInstance()));
+        when(config.createMeaningfulPKFilter()).thenReturn(NamePatternMatcher.EXCLUDE_ALL);
+
+        DbLoader dbLoader = new DbLoader(mockAdapter, mockConnection, config.getDbLoaderConfig(), mockDelegate, mockNameGenerator) {
             @Override
-            public void load(DataMap dataMap, DbLoaderConfiguration config) throws SQLException {
+            public DataMap load() throws SQLException {
+                DataMap dataMap = new DataMap();
                 new DataMapBuilder(dataMap).with(
                         dbEntity("ARTGROUP").attributes(
                                 dbAttr("GROUP_ID").typeInt().primaryKey(),
@@ -159,72 +170,70 @@ public class DefaultDbImportActionTest {
                         objEntity("org.apache.cayenne.testdo.testmap", "ArtGroup", "ARTGROUP").attributes(
                                 objAttr("name").type(String.class).dbPath("NAME")
                         ));
+                return dataMap;
             }
         };
 
-        DbImportConfiguration params = mock(DbImportConfiguration.class);
-
-        when(params.getTargetDataMap()).thenReturn(FILE_STUB);
-        when(params.createMergeDelegate()).thenReturn(new DefaultModelMergeDelegate());
-        when(params.getDbLoaderConfig()).thenReturn(new DbLoaderConfiguration());
-        when(params.createNameGenerator()).thenReturn(new DefaultObjectNameGenerator(NoStemStemmer.getInstance()));
-        when(params.createMeaningfulPKFilter()).thenReturn(NamePatternMatcher.EXCLUDE_ALL);
-
         final boolean[] haveWeTriedToSave = {false};
-        DefaultDbImportAction action = buildDbImportAction(new FileProjectSaver() {
-            @Override
-            public void save(Project project) {
-                haveWeTriedToSave[0] = true;
+        DefaultDbImportAction action = buildDbImportAction(
+            new FileProjectSaver() {
+                @Override
+                public void save(Project project) {
+                    haveWeTriedToSave[0] = true;
+
+                    // Validation phase
+                    DataMap rootNode = (DataMap) project.getRootNode();
+                    assertEquals(1, rootNode.getObjEntities().size());
+                    assertEquals(1, rootNode.getDbEntityMap().size());
+
+                    DbEntity entity = rootNode.getDbEntity("ARTGROUP");
+                    assertNotNull(entity);
+                    assertEquals(4, entity.getAttributes().size());
+                    assertNotNull(entity.getAttribute("NAME_01"));
+                }
+            },
+
+            new MapLoader() {
+                @Override
+                public synchronized DataMap loadDataMap(InputSource src) throws CayenneRuntimeException {
+                    return new DataMapBuilder().with(
+                            dbEntity("ARTGROUP").attributes(
+                                    dbAttr("GROUP_ID").typeInt().primaryKey(),
+                                    dbAttr("NAME").typeVarchar(100).mandatory(),
+                                    dbAttr("PARENT_GROUP_ID").typeInt()
+                            )).with(
+                            objEntity("org.apache.cayenne.testdo.testmap", "ArtGroup", "ARTGROUP").attributes(
+                                    objAttr("name").type(String.class).dbPath("NAME")
+                            )).build();
+                }
+            },
+            dbLoader
+        );
 
-                // Validation phase
-                DataMap rootNode = (DataMap) project.getRootNode();
-                assertEquals(1, rootNode.getObjEntities().size());
-                assertEquals(1, rootNode.getDbEntityMap().size());
-
-                DbEntity entity = rootNode.getDbEntity("ARTGROUP");
-                assertNotNull(entity);
-                assertEquals(4, entity.getAttributes().size());
-                assertNotNull(entity.getAttribute("NAME_01"));
-            }
-        }, new MapLoader() {
-
-            @Override
-            public synchronized DataMap loadDataMap(InputSource src) throws CayenneRuntimeException {
-                return new DataMapBuilder().with(
-                        dbEntity("ARTGROUP").attributes(
-                                dbAttr("GROUP_ID").typeInt().primaryKey(),
-                                dbAttr("NAME").typeVarchar(100).mandatory(),
-                                dbAttr("PARENT_GROUP_ID").typeInt()
-                        )).with(
-                        objEntity("org.apache.cayenne.testdo.testmap", "ArtGroup", "ARTGROUP").attributes(
-                                objAttr("name").type(String.class).dbPath("NAME")
-                        )).build();
-            }
-        }, dbLoader);
-
-        action.execute(params);
+        action.execute(config);
 
         assertTrue("We should try to save.", haveWeTriedToSave[0]);
     }
 
     @Test
     public void testImportWithoutChanges() throws Exception {
-        DbLoader dbLoader = new DbLoader(mockConnection, mockAdapter, mockDelegate, mockNameGenerator) {
+        DbImportConfiguration config = mock(DbImportConfiguration.class);
+        when(config.getTargetDataMap()).thenReturn(FILE_STUB);
+        when(config.createMergeDelegate()).thenReturn(new DefaultModelMergeDelegate());
+        when(config.getDbLoaderConfig()).thenReturn(new DbLoaderConfiguration());
+
+        DbLoader dbLoader = new DbLoader(mockAdapter, mockConnection, config.getDbLoaderConfig(), mockDelegate, mockNameGenerator) {
             @Override
-            public void load(DataMap dataMap, DbLoaderConfiguration config) throws SQLException {
+            public DataMap load() throws SQLException {
+                DataMap dataMap = new DataMap();
                 new DataMapBuilder(dataMap).with(
                         dbEntity("ARTGROUP").attributes(
                                 dbAttr("NAME").typeVarchar(100).mandatory()
                         ));
+                return dataMap;
             }
         };
 
-        DbImportConfiguration params = mock(DbImportConfiguration.class);
-        when(params.getTargetDataMap()).thenReturn(FILE_STUB);
-        when(params.createMergeDelegate()).thenReturn(new DefaultModelMergeDelegate());
-        when(params.getDbLoaderConfig()).thenReturn(new DbLoaderConfiguration());
-
-
         FileProjectSaver projectSaver = mock(FileProjectSaver.class);
         doNothing().when(projectSaver).save(any(Project.class));
 
@@ -236,7 +245,7 @@ public class DefaultDbImportActionTest {
 
         DefaultDbImportAction action = buildDbImportAction(projectSaver, mapLoader, dbLoader);
 
-        action.execute(params);
+        action.execute(config);
 
         // no changes - we still
         verify(projectSaver, never()).save(any(Project.class));
@@ -246,7 +255,7 @@ public class DefaultDbImportActionTest {
     @Test
     public void testImportWithDbError() throws Exception {
         DbLoader dbLoader = mock(DbLoader.class);
-        doThrow(new SQLException()).when(dbLoader).load(any(DataMap.class), any(DbLoaderConfiguration.class));
+        doThrow(new SQLException()).when(dbLoader).load();
 
         DbImportConfiguration params = mock(DbImportConfiguration.class);
 
@@ -290,11 +299,9 @@ public class DefaultDbImportActionTest {
 
         return new DefaultDbImportAction(log, projectSaver, dataSourceFactory, adapterFactory, mapLoader, mergerTokenFactoryProvider) {
 
-            @Override
             protected DbLoader createDbLoader(DbAdapter adapter,
-                                              Connection connection,
-                                              DbLoaderDelegate dbLoaderDelegate,
-                                              ObjectNameGenerator objectNameGenerator) {
+                                               Connection connection,
+                                               DbImportConfiguration config) {
                 return dbLoader;
             }
         };

http://git-wip-us.apache.org/repos/asf/cayenne/blob/8c273022/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/action/MigrateAction.java
----------------------------------------------------------------------
diff --git 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
index 00e27bf..0648d2c 100644
--- 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
@@ -21,7 +21,7 @@ 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.db.DbLoader;
+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;

http://git-wip-us.apache.org/repos/asf/cayenne/blob/8c273022/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/dialog/db/DbLoaderHelper.java
----------------------------------------------------------------------
diff --git a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/dialog/db/DbLoaderHelper.java b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/dialog/db/DbLoaderHelper.java
index d314214..0f49e49 100644
--- a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/dialog/db/DbLoaderHelper.java
+++ b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/dialog/db/DbLoaderHelper.java
@@ -33,8 +33,8 @@ import org.apache.cayenne.dbimport.Schema;
 import org.apache.cayenne.dbsync.DbSyncModule;
 import org.apache.cayenne.dbsync.merge.factory.MergerTokenFactoryProvider;
 import org.apache.cayenne.dbsync.naming.NameBuilder;
-import org.apache.cayenne.dbsync.reverse.db.DbLoader;
-import org.apache.cayenne.dbsync.reverse.db.DefaultDbLoaderDelegate;
+import org.apache.cayenne.dbsync.reverse.dbload.DbLoader;
+import org.apache.cayenne.dbsync.reverse.dbload.DefaultDbLoaderDelegate;
 import org.apache.cayenne.dbsync.reverse.filters.FiltersConfigBuilder;
 import org.apache.cayenne.di.DIBootstrap;
 import org.apache.cayenne.di.Injector;
@@ -68,7 +68,7 @@ import java.util.Collections;
 import java.util.List;
 
 /**
- * Stateful helper class that encapsulates access to DbLoader.
+ * Stateful helper class that encapsulates access to DbLoader2.
  */
 public class DbLoaderHelper {
 
@@ -377,7 +377,7 @@ public class DbLoaderHelper {
             ProjectUtil.cleanObjMappings(dataMap);
         }
 
-        protected DbImportAction createAction(DataMap targetDataMap) {
+        DbImportAction createAction(DataMap targetDataMap) {
             Injector injector = DIBootstrap.createInjector(new DbSyncModule(),
                     new ToolsModule(LOGGER),
                     new DbImportModule());
@@ -393,8 +393,8 @@ public class DbLoaderHelper {
                     createDbLoader(config));
         }
 
-        protected DbLoader createDbLoader(DbImportConfiguration configuration) {
-            return new DbLoader(connection, adapter, new LoaderDelegate(), configuration.createNameGenerator());
+        DbLoader createDbLoader(DbImportConfiguration configuration) {
+            return new DbLoader(adapter, connection, configuration.getDbLoaderConfig(), new LoaderDelegate(), configuration.createNameGenerator());
         }
     }
 

http://git-wip-us.apache.org/repos/asf/cayenne/blob/8c273022/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/dialog/db/MergerOptions.java
----------------------------------------------------------------------
diff --git a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/dialog/db/MergerOptions.java b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/dialog/db/MergerOptions.java
index 52a3666..b74fc73 100644
--- a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/dialog/db/MergerOptions.java
+++ b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/dialog/db/MergerOptions.java
@@ -34,9 +34,9 @@ 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;
@@ -169,14 +169,13 @@ public class MergerOptions extends CayenneController {
 
             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);
             }

http://git-wip-us.apache.org/repos/asf/cayenne/blob/8c273022/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/dialog/db/ModelerDbImportAction.java
----------------------------------------------------------------------
diff --git a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/dialog/db/ModelerDbImportAction.java b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/dialog/db/ModelerDbImportAction.java
index 1b271bb..e645e0e 100644
--- a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/dialog/db/ModelerDbImportAction.java
+++ b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/dialog/db/ModelerDbImportAction.java
@@ -22,9 +22,7 @@ import org.apache.cayenne.configuration.server.DataSourceFactory;
 import org.apache.cayenne.configuration.server.DbAdapterFactory;
 import org.apache.cayenne.dba.DbAdapter;
 import org.apache.cayenne.dbsync.merge.factory.MergerTokenFactoryProvider;
-import org.apache.cayenne.dbsync.naming.ObjectNameGenerator;
-import org.apache.cayenne.dbsync.reverse.db.DbLoader;
-import org.apache.cayenne.dbsync.reverse.db.DbLoaderDelegate;
+import org.apache.cayenne.dbsync.reverse.dbload.DbLoader;
 import org.apache.cayenne.map.DataMap;
 import org.apache.cayenne.map.MapLoader;
 import org.apache.cayenne.project.ProjectSaver;
@@ -47,8 +45,7 @@ public class ModelerDbImportAction extends DefaultDbImportAction {
                                  MapLoader mapLoader,
                                  MergerTokenFactoryProvider mergerTokenFactoryProvider,
                                  DataMap targetMap,
-                                 DbLoader dbLoader
-                                 ) {
+                                 DbLoader dbLoader) {
 
         super(logger, projectSaver, dataSourceFactory, adapterFactory, mapLoader, mergerTokenFactoryProvider);
 
@@ -58,9 +55,8 @@ public class ModelerDbImportAction extends DefaultDbImportAction {
 
     @Override
     protected DbLoader createDbLoader(DbAdapter adapter,
-                                      Connection connection,
-                                      DbLoaderDelegate dbLoaderDelegate,
-                                      ObjectNameGenerator objectNameGenerator) {
+                                       Connection connection,
+                                       DbImportConfiguration config) {
         return dbLoader;
     }
 


[8/9] cayenne git commit: Merge branch '154'

Posted by aa...@apache.org.
Merge branch '154'


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

Branch: refs/heads/master
Commit: 62029df7fa4fefe1babb39a7e447979d7e7a9301
Parents: 1f6100d 7cd1b20
Author: Andrus Adamchik <an...@objectstyle.com>
Authored: Wed Dec 14 21:11:56 2016 +0300
Committer: Andrus Adamchik <an...@objectstyle.com>
Committed: Wed Dec 14 21:11:56 2016 +0300

----------------------------------------------------------------------
 .../apache/cayenne/dbsync/merge/DbMerger.java   |   2 +-
 .../dbsync/merge/DropRelationshipToDb.java      |   2 +-
 .../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 +++
 .../dbsync/reverse/dbload/EntityLoader.java     | 106 ++++
 .../dbsync/reverse/dbload/ExportedKey.java      | 220 ++++++++
 .../reverse/dbload/ExportedKeyLoader.java       |  74 +++
 .../reverse/dbload/LoggingDbLoaderDelegate.java |  61 +++
 .../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/RelationshipLoader.java      | 168 ++++++
 .../dbsync/reverse/filters/TableFilter.java     |   7 +-
 .../apache/cayenne/dbsync/merge/MergeCase.java  |  14 +-
 .../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 ++-
 .../tools/dbimport/DbImportConfiguration.java   |   8 +-
 .../tools/dbimport/DefaultDbImportAction.java   |  26 +-
 .../dbimport/DefaultDbImportActionTest.java     | 139 ++---
 .../cayenne/modeler/action/MigrateAction.java   |   2 +-
 .../modeler/dialog/db/DbLoaderHelper.java       |  10 +-
 .../modeler/dialog/db/MergerOptions.java        |  15 +-
 .../dialog/db/ModelerDbImportAction.java        |  12 +-
 49 files changed, 2550 insertions(+), 2108 deletions(-)
----------------------------------------------------------------------



[4/9] cayenne git commit: New DbLoader for dbsync utils - loading process split in independent small steps - DbLoader always return new DataMap, it doesn't accept it from outside

Posted by aa...@apache.org.
New DbLoader for dbsync utils
 - loading process split in independent small steps
 - DbLoader always return new DataMap, it doesn't accept it from outside

Final clean up


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

Branch: refs/heads/master
Commit: e68c72c245c1799b725a52d5821850b9d89da01d
Parents: 8c27302
Author: Nikita Timofeev <st...@gmail.com>
Authored: Mon Dec 12 11:38:13 2016 +0300
Committer: Nikita Timofeev <st...@gmail.com>
Committed: Mon Dec 12 11:38:13 2016 +0300

----------------------------------------------------------------------
 .../cayenne/dbsync/reverse/dbload/AttributeLoader.java       | 4 ++--
 .../cayenne/dbsync/reverse/dbload/DbLoadDataStore.java       | 8 +++++---
 .../org/apache/cayenne/dbsync/reverse/dbload/DbLoader.java   | 2 +-
 .../dbsync/reverse/dbload/DbRelationshipDetected.java        | 4 ++--
 .../dbsync/reverse/dbload/DefaultDbLoaderDelegate.java       | 1 -
 .../apache/cayenne/dbsync/reverse/dbload/EntityLoader.java   | 4 ++--
 .../apache/cayenne/dbsync/reverse/dbload/ExportedKey.java    | 4 ++--
 .../dbsync/reverse/dbload/LoggingDbLoaderDelegate.java       | 1 -
 .../dbsync/reverse/dbload/PerCatalogAndSchemaLoader.java     | 4 ++--
 .../cayenne/dbsync/reverse/dbload/PrimaryKeyLoader.java      | 2 +-
 .../cayenne/dbsync/reverse/dbload/ProcedureColumnLoader.java | 4 ++--
 .../cayenne/dbsync/reverse/dbload/ProcedureLoader.java       | 4 ++--
 .../cayenne/dbsync/reverse/dbload/RelationshipLoader.java    | 2 +-
 13 files changed, 22 insertions(+), 22 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cayenne/blob/e68c72c2/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbload/AttributeLoader.java
----------------------------------------------------------------------
diff --git a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbload/AttributeLoader.java b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbload/AttributeLoader.java
index 25f64d2..af44f7b 100644
--- a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbload/AttributeLoader.java
+++ b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbload/AttributeLoader.java
@@ -36,7 +36,7 @@ import org.apache.commons.logging.LogFactory;
 
 class AttributeLoader extends PerCatalogAndSchemaLoader {
 
-    private static final Log LOGGER = LogFactory.getLog(AttributeLoader.class);
+    private static final Log LOGGER = LogFactory.getLog(DbLoader.class);
 
     private boolean firstRow;
     private boolean supportAutoIncrement;
@@ -52,7 +52,7 @@ class AttributeLoader extends PerCatalogAndSchemaLoader {
     }
 
     @Override
-    protected void processResultSet(CatalogFilter catalog, SchemaFilter schema, DbLoadDataStore map, ResultSet rs) throws SQLException {
+    protected void processResultSetRow(CatalogFilter catalog, SchemaFilter schema, DbLoadDataStore map, ResultSet rs) throws SQLException {
         if (firstRow) {
             supportAutoIncrement = checkForAutoIncrement(rs);
             firstRow = false;

http://git-wip-us.apache.org/repos/asf/cayenne/blob/e68c72c2/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbload/DbLoadDataStore.java
----------------------------------------------------------------------
diff --git a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbload/DbLoadDataStore.java b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbload/DbLoadDataStore.java
index c0e79a8..ec06163 100644
--- a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbload/DbLoadDataStore.java
+++ b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbload/DbLoadDataStore.java
@@ -19,7 +19,6 @@
 
 package org.apache.cayenne.dbsync.reverse.dbload;
 
-import java.util.Collection;
 import java.util.HashMap;
 import java.util.Map;
 import java.util.Set;
@@ -34,8 +33,11 @@ import org.apache.cayenne.map.Procedure;
  * Temporary storage for loaded from DB DbEntities and Procedures.
  * DataMap is used but it's functionality is excessive and
  * there can be unwanted side effects.
- * To get rid of it parallel data structure for dbEntity, attributes,
- * procedures etc.. must be created
+ * But we can't get rid of it right now as parallel data structure
+ * for dbEntity, attributes, procedures etc.. must be created
+ * or some other work around should be implemented because
+ * some functionality relies on side effects (e.g. entity resolution
+ * in relationship)
  */
 public class DbLoadDataStore extends DataMap {
 

http://git-wip-us.apache.org/repos/asf/cayenne/blob/e68c72c2/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbload/DbLoader.java
----------------------------------------------------------------------
diff --git a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbload/DbLoader.java b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbload/DbLoader.java
index 5c1cfde..e350b04 100644
--- a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbload/DbLoader.java
+++ b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbload/DbLoader.java
@@ -35,7 +35,7 @@ import org.apache.cayenne.map.DataMap;
  * Creates DbEntities and Procedures based on DB meta data.
  * Consists of list of loaders that iteratively loads small parts of data,
  * e.g. Entity name, Attributes, Relationships...
- * @see AbstractLoader and its children
+ * @see AbstractLoader and its descendants
  */
 public class DbLoader {
 

http://git-wip-us.apache.org/repos/asf/cayenne/blob/e68c72c2/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbload/DbRelationshipDetected.java
----------------------------------------------------------------------
diff --git a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbload/DbRelationshipDetected.java b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbload/DbRelationshipDetected.java
index 5a8b8cd..f827bde 100644
--- a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbload/DbRelationshipDetected.java
+++ b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbload/DbRelationshipDetected.java
@@ -34,7 +34,7 @@ public class DbRelationshipDetected extends DbRelationship {
         super(uniqueRelName);
     }
 
-    public DbRelationshipDetected() {
+    DbRelationshipDetected() {
     }
 
     /**
@@ -47,7 +47,7 @@ public class DbRelationshipDetected extends DbRelationship {
     /**
      * Set the name of the underlying foreign key. Typically FK_NAME from jdbc metadata.
      */
-    public void setFkName(String fkName) {
+    void setFkName(String fkName) {
         this.fkName = fkName;
     }
 

http://git-wip-us.apache.org/repos/asf/cayenne/blob/e68c72c2/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbload/DefaultDbLoaderDelegate.java
----------------------------------------------------------------------
diff --git a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbload/DefaultDbLoaderDelegate.java b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbload/DefaultDbLoaderDelegate.java
index 607bd2c..6b06be8 100644
--- a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbload/DefaultDbLoaderDelegate.java
+++ b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbload/DefaultDbLoaderDelegate.java
@@ -19,7 +19,6 @@
 
 package org.apache.cayenne.dbsync.reverse.dbload;
 
-import org.apache.cayenne.dbsync.reverse.dbload.DbLoaderDelegate;
 import org.apache.cayenne.map.DbEntity;
 import org.apache.cayenne.map.DbRelationship;
 import org.apache.cayenne.map.ObjEntity;

http://git-wip-us.apache.org/repos/asf/cayenne/blob/e68c72c2/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbload/EntityLoader.java
----------------------------------------------------------------------
diff --git a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbload/EntityLoader.java b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbload/EntityLoader.java
index bbccc15..9f2afb2 100644
--- a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbload/EntityLoader.java
+++ b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbload/EntityLoader.java
@@ -35,7 +35,7 @@ import org.apache.commons.logging.LogFactory;
 
 class EntityLoader extends PerCatalogAndSchemaLoader {
 
-    private static final Log LOGGER = LogFactory.getLog(EntityLoader.class);
+    private static final Log LOGGER = LogFactory.getLog(DbLoader.class);
 
     private final String[] types;
 
@@ -50,7 +50,7 @@ class EntityLoader extends PerCatalogAndSchemaLoader {
     }
 
     @Override
-    protected void processResultSet(CatalogFilter catalog, SchemaFilter schema, DbLoadDataStore map, ResultSet rs) throws SQLException {
+    protected void processResultSetRow(CatalogFilter catalog, SchemaFilter schema, DbLoadDataStore map, ResultSet rs) throws SQLException {
         String name = rs.getString("TABLE_NAME");
         String catalogName = rs.getString("TABLE_CAT");
         String schemaName = rs.getString("TABLE_SCHEM");

http://git-wip-us.apache.org/repos/asf/cayenne/blob/e68c72c2/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbload/ExportedKey.java
----------------------------------------------------------------------
diff --git a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbload/ExportedKey.java b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbload/ExportedKey.java
index a288fe8..e9c90eb 100644
--- a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbload/ExportedKey.java
+++ b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbload/ExportedKey.java
@@ -45,7 +45,7 @@ public class ExportedKey implements Comparable {
      * @param rs ResultSet pointing to a exported key, fetched using
      *           DataBaseMetaData.getExportedKeys(...)
      */
-    public ExportedKey(ResultSet rs) throws SQLException {
+    ExportedKey(ResultSet rs) throws SQLException {
         String pkCatalog = rs.getString("PKTABLE_CAT");
         String pkSchema = rs.getString("PKTABLE_SCHEM");
         String pkTable = rs.getString("PKTABLE_NAME");
@@ -121,7 +121,7 @@ public class ExportedKey implements Comparable {
         return getStrKey() + " # " + keySeq;
     }
 
-    public String getStrKey() {
+    String getStrKey() {
         return pk + " <- " + fk;
     }
 

http://git-wip-us.apache.org/repos/asf/cayenne/blob/e68c72c2/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbload/LoggingDbLoaderDelegate.java
----------------------------------------------------------------------
diff --git a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbload/LoggingDbLoaderDelegate.java b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbload/LoggingDbLoaderDelegate.java
index 58635f7..70279c1 100644
--- a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbload/LoggingDbLoaderDelegate.java
+++ b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbload/LoggingDbLoaderDelegate.java
@@ -18,7 +18,6 @@
  ****************************************************************/
 package org.apache.cayenne.dbsync.reverse.dbload;
 
-import org.apache.cayenne.dbsync.reverse.dbload.DefaultDbLoaderDelegate;
 import org.apache.cayenne.map.DbEntity;
 import org.apache.cayenne.map.DbRelationship;
 import org.apache.commons.logging.Log;

http://git-wip-us.apache.org/repos/asf/cayenne/blob/e68c72c2/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbload/PerCatalogAndSchemaLoader.java
----------------------------------------------------------------------
diff --git a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbload/PerCatalogAndSchemaLoader.java b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbload/PerCatalogAndSchemaLoader.java
index 5ec1b67..376defb 100644
--- a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbload/PerCatalogAndSchemaLoader.java
+++ b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbload/PerCatalogAndSchemaLoader.java
@@ -41,7 +41,7 @@ public abstract class PerCatalogAndSchemaLoader extends AbstractLoader {
                 }
                 try (ResultSet rs = getResultSet(catalog.name, schema.name, metaData)) {
                     while (rs.next()) {
-                        processResultSet(catalog, schema, map, rs);
+                        processResultSetRow(catalog, schema, map, rs);
                     }
                 }
             }
@@ -54,5 +54,5 @@ public abstract class PerCatalogAndSchemaLoader extends AbstractLoader {
 
     abstract ResultSet getResultSet(String catalogName, String schemaName, DatabaseMetaData metaData) throws SQLException;
 
-    abstract void processResultSet(CatalogFilter catalog, SchemaFilter schema, DbLoadDataStore map, ResultSet rs) throws SQLException;
+    abstract void processResultSetRow(CatalogFilter catalog, SchemaFilter schema, DbLoadDataStore map, ResultSet rs) throws SQLException;
 }

http://git-wip-us.apache.org/repos/asf/cayenne/blob/e68c72c2/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbload/PrimaryKeyLoader.java
----------------------------------------------------------------------
diff --git a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbload/PrimaryKeyLoader.java b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbload/PrimaryKeyLoader.java
index 9a1d206..4f80534 100644
--- a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbload/PrimaryKeyLoader.java
+++ b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbload/PrimaryKeyLoader.java
@@ -31,7 +31,7 @@ import org.apache.commons.logging.LogFactory;
 
 class PrimaryKeyLoader extends PerEntityLoader {
 
-    private static final Log LOGGER = LogFactory.getLog(PrimaryKeyLoader.class);
+    private static final Log LOGGER = LogFactory.getLog(DbLoader.class);
 
     PrimaryKeyLoader(DbLoaderConfiguration config, DbLoaderDelegate delegate) {
         super(null, config, delegate);

http://git-wip-us.apache.org/repos/asf/cayenne/blob/e68c72c2/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbload/ProcedureColumnLoader.java
----------------------------------------------------------------------
diff --git a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbload/ProcedureColumnLoader.java b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbload/ProcedureColumnLoader.java
index 4ff77c0..8ac0fde 100644
--- a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbload/ProcedureColumnLoader.java
+++ b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbload/ProcedureColumnLoader.java
@@ -35,7 +35,7 @@ import org.apache.commons.logging.LogFactory;
 
 public class ProcedureColumnLoader extends PerCatalogAndSchemaLoader {
 
-    private static final Log LOGGER = LogFactory.getLog(ProcedureColumnLoader.class);
+    private static final Log LOGGER = LogFactory.getLog(DbLoader.class);
 
     ProcedureColumnLoader(DbAdapter adapter, DbLoaderConfiguration config, DbLoaderDelegate delegate) {
         super(adapter, config, delegate);
@@ -53,7 +53,7 @@ public class ProcedureColumnLoader extends PerCatalogAndSchemaLoader {
     }
 
     @Override
-    protected void processResultSet(CatalogFilter catalog, SchemaFilter schema, DbLoadDataStore map, ResultSet rs) throws SQLException {
+    protected void processResultSetRow(CatalogFilter catalog, SchemaFilter schema, DbLoadDataStore map, ResultSet rs) throws SQLException {
         String procSchema = rs.getString("PROCEDURE_SCHEM");
         String procCatalog = rs.getString("PROCEDURE_CAT");
         String name = rs.getString("PROCEDURE_NAME");

http://git-wip-us.apache.org/repos/asf/cayenne/blob/e68c72c2/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbload/ProcedureLoader.java
----------------------------------------------------------------------
diff --git a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbload/ProcedureLoader.java b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbload/ProcedureLoader.java
index 633f033..34808a0 100644
--- a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbload/ProcedureLoader.java
+++ b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbload/ProcedureLoader.java
@@ -33,7 +33,7 @@ import org.apache.commons.logging.LogFactory;
 
 public class ProcedureLoader extends PerCatalogAndSchemaLoader {
 
-    private static final Log LOGGER = LogFactory.getLog(ProcedureLoader.class);
+    private static final Log LOGGER = LogFactory.getLog(DbLoader.class);
 
     ProcedureLoader(DbAdapter adapter, DbLoaderConfiguration config, DbLoaderDelegate delegate) {
         super(adapter, config, delegate);
@@ -51,7 +51,7 @@ public class ProcedureLoader extends PerCatalogAndSchemaLoader {
     }
 
     @Override
-    protected void processResultSet(CatalogFilter catalog, SchemaFilter schema, DbLoadDataStore map, ResultSet rs) throws SQLException {
+    protected void processResultSetRow(CatalogFilter catalog, SchemaFilter schema, DbLoadDataStore map, ResultSet rs) throws SQLException {
         PatternFilter filter = config.getFiltersConfig().proceduresFilter(catalog.name, schema.name);
         String name = rs.getString("PROCEDURE_NAME");
         if (!filter.isIncluded(name)) {

http://git-wip-us.apache.org/repos/asf/cayenne/blob/e68c72c2/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbload/RelationshipLoader.java
----------------------------------------------------------------------
diff --git a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbload/RelationshipLoader.java b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbload/RelationshipLoader.java
index 91a48f4..52de8a6 100644
--- a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbload/RelationshipLoader.java
+++ b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbload/RelationshipLoader.java
@@ -36,7 +36,7 @@ import org.apache.commons.logging.LogFactory;
 
 public class RelationshipLoader extends AbstractLoader {
 
-    private static final Log LOGGER = LogFactory.getLog(RelationshipLoader.class);
+    private static final Log LOGGER = LogFactory.getLog(DbLoader.class);
 
     private final ObjectNameGenerator nameGenerator;
 


[6/9] cayenne git commit: New DbLoader for dbsync utils - loading process split in independent small steps - DbLoader always return new DataMap, it doesn't accept it from outside

Posted by aa...@apache.org.
New DbLoader for dbsync utils
 - loading process split in independent small steps
 - DbLoader always return new DataMap, it doesn't accept it from outside

Final clean up of tests


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

Branch: refs/heads/master
Commit: 17053f9ca430658a9b8acc86cd04f5a2b877f941
Parents: 4151546
Author: Nikita Timofeev <st...@gmail.com>
Authored: Mon Dec 12 12:40:02 2016 +0300
Committer: Nikita Timofeev <st...@gmail.com>
Committed: Mon Dec 12 12:40:02 2016 +0300

----------------------------------------------------------------------
 .../java/org/apache/cayenne/dbsync/reverse/dbload/DbLoader.java  | 4 ++--
 .../apache/cayenne/dbsync/reverse/dbload/DbLoaderDelegate.java   | 4 ++--
 2 files changed, 4 insertions(+), 4 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cayenne/blob/17053f9c/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbload/DbLoader.java
----------------------------------------------------------------------
diff --git a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbload/DbLoader.java b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbload/DbLoader.java
index e350b04..8df5aa9 100644
--- a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbload/DbLoader.java
+++ b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbload/DbLoader.java
@@ -88,7 +88,7 @@ public class DbLoader {
 
     /**
      * Retrieves catalogs for a given connection.
-     * using a static method for catalog loading as we don't need a full DbLoader2 for this operation
+     * using a static method for catalog loading as we don't need a full DbLoader for this operation
      * @return List with the catalog names; empty list if none found.
      */
     public static List<String> loadCatalogs(Connection connection) throws SQLException {
@@ -99,7 +99,7 @@ public class DbLoader {
 
     /**
      * Retrieves the schemas for the given connection.
-     * using a static method for catalog loading as we don't need a full DbLoader2 for this operation
+     * using a static method for catalog loading as we don't need a full DbLoader for this operation
      * @return List with the schema names; empty list if none found.
      */
     public static List<String> loadSchemas(Connection connection) throws SQLException {

http://git-wip-us.apache.org/repos/asf/cayenne/blob/17053f9c/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbload/DbLoaderDelegate.java
----------------------------------------------------------------------
diff --git a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbload/DbLoaderDelegate.java b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbload/DbLoaderDelegate.java
index ae694eb..e0b8c67 100644
--- a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbload/DbLoaderDelegate.java
+++ b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbload/DbLoaderDelegate.java
@@ -50,13 +50,13 @@ public interface DbLoaderDelegate {
     boolean dbRelationshipLoaded(DbEntity entity, DbRelationship relationship);
 
     /**
-     * @deprecated since 4.0 no longer invoked as DbLoader2 does not deal with object layer anymore.
+     * @deprecated since 4.0 no longer invoked as DbLoader does not deal with object layer anymore.
      */
     @Deprecated
     void objEntityAdded(ObjEntity entity);
 
     /**
-     * @deprecated since 4.0 no longer invoked as DbLoader2 does not deal with object layer anymore.
+     * @deprecated since 4.0 no longer invoked as DbLoader does not deal with object layer anymore.
      */
     @Deprecated
     void objEntityRemoved(ObjEntity entity);


[9/9] cayenne git commit: minor javadoc tweaks

Posted by aa...@apache.org.
minor javadoc tweaks


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

Branch: refs/heads/master
Commit: 836399cba584416b129f75a55bdb6dc11b442acf
Parents: 62029df
Author: Andrus Adamchik <an...@objectstyle.com>
Authored: Wed Dec 14 21:25:22 2016 +0300
Committer: Andrus Adamchik <an...@objectstyle.com>
Committed: Wed Dec 14 21:25:22 2016 +0300

----------------------------------------------------------------------
 .../cayenne/dbsync/reverse/dbload/DbLoader.java     | 16 ++++++++--------
 .../dbsync/reverse/dbload/DbLoaderDelegate.java     |  2 +-
 2 files changed, 9 insertions(+), 9 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cayenne/blob/836399cb/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbload/DbLoader.java
----------------------------------------------------------------------
diff --git a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbload/DbLoader.java b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbload/DbLoader.java
index 8df5aa9..f0da783 100644
--- a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbload/DbLoader.java
+++ b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbload/DbLoader.java
@@ -18,6 +18,10 @@
  */
 package org.apache.cayenne.dbsync.reverse.dbload;
 
+import org.apache.cayenne.dba.DbAdapter;
+import org.apache.cayenne.dbsync.naming.ObjectNameGenerator;
+import org.apache.cayenne.map.DataMap;
+
 import java.sql.Connection;
 import java.sql.DatabaseMetaData;
 import java.sql.ResultSet;
@@ -26,16 +30,12 @@ import java.util.ArrayList;
 import java.util.List;
 import java.util.Objects;
 
-import org.apache.cayenne.dba.DbAdapter;
-import org.apache.cayenne.dbsync.naming.ObjectNameGenerator;
-import org.apache.cayenne.map.DataMap;
-
 /**
- * Loader for data from DB.
- * Creates DbEntities and Procedures based on DB meta data.
- * Consists of list of loaders that iteratively loads small parts of data,
- * e.g. Entity name, Attributes, Relationships...
+ * Loads DB schema into a DataMap, creating DbEntities and Procedures. Consists of a list of specialized loaders that
+ * iteratively load parts of metadata, such as Entity names, Attributes, Relationships, etc.
+ *
  * @see AbstractLoader and its descendants
+ * @since 4.0
  */
 public class DbLoader {
 

http://git-wip-us.apache.org/repos/asf/cayenne/blob/836399cb/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbload/DbLoaderDelegate.java
----------------------------------------------------------------------
diff --git a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbload/DbLoaderDelegate.java b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbload/DbLoaderDelegate.java
index e0b8c67..77b854e 100644
--- a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbload/DbLoaderDelegate.java
+++ b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbload/DbLoaderDelegate.java
@@ -24,7 +24,7 @@ import org.apache.cayenne.map.DbRelationship;
 import org.apache.cayenne.map.ObjEntity;
 
 /**
- * Defines API for progress tracking and altering the folow of reverse-engineering.
+ * Defines API for progress tracking and altering the flow of reverse-engineering.
  */
 public interface DbLoaderDelegate {
 


[7/9] cayenne git commit: Fix failing ExportedKeyLoaderIT test

Posted by aa...@apache.org.
Fix failing ExportedKeyLoaderIT test


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

Branch: refs/heads/master
Commit: 7cd1b2004c175193555873b858df619e9658b649
Parents: 17053f9
Author: Nikita Timofeev <st...@gmail.com>
Authored: Mon Dec 12 13:12:43 2016 +0300
Committer: Nikita Timofeev <st...@gmail.com>
Committed: Mon Dec 12 13:12:43 2016 +0300

----------------------------------------------------------------------
 .../reverse/dbload/ExportedKeyLoaderIT.java     | 20 +++++++++++++++++---
 1 file changed, 17 insertions(+), 3 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cayenne/blob/7cd1b200/cayenne-dbsync/src/test/java/org/apache/cayenne/dbsync/reverse/dbload/ExportedKeyLoaderIT.java
----------------------------------------------------------------------
diff --git a/cayenne-dbsync/src/test/java/org/apache/cayenne/dbsync/reverse/dbload/ExportedKeyLoaderIT.java b/cayenne-dbsync/src/test/java/org/apache/cayenne/dbsync/reverse/dbload/ExportedKeyLoaderIT.java
index 9c71159..9e74d8c 100644
--- a/cayenne-dbsync/src/test/java/org/apache/cayenne/dbsync/reverse/dbload/ExportedKeyLoaderIT.java
+++ b/cayenne-dbsync/src/test/java/org/apache/cayenne/dbsync/reverse/dbload/ExportedKeyLoaderIT.java
@@ -19,11 +19,15 @@
 
 package org.apache.cayenne.dbsync.reverse.dbload;
 
+import java.util.Map;
+import java.util.Set;
+
 import org.apache.cayenne.map.DbAttribute;
 import org.apache.cayenne.map.DbEntity;
 import org.junit.Test;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
 
 public class ExportedKeyLoaderIT extends BaseLoaderIT {
 
@@ -58,9 +62,9 @@ public class ExportedKeyLoaderIT extends BaseLoaderIT {
 
         assertEquals(2, store.getExportedKeysEntrySet().size());
 
-        ExportedKey artistIdFk = store.getExportedKeysEntrySet()
-                .iterator().next()
-                .getValue().iterator().next();
+        ExportedKey artistIdFk = findArtistExportedKey();
+        assertNotNull(artistIdFk);
+
         assertEquals("ARTIST", artistIdFk.getPk().getTable());
         assertEquals("ARTIST_ID", artistIdFk.getPk().getColumn());
 
@@ -68,4 +72,14 @@ public class ExportedKeyLoaderIT extends BaseLoaderIT {
         assertEquals("ARTIST_ID", artistIdFk.getFk().getColumn());
     }
 
+    ExportedKey findArtistExportedKey() {
+        for(Map.Entry<String, Set<ExportedKey>> entry : store.getExportedKeysEntrySet()) {
+            if(entry.getKey().endsWith(".ARTIST_ID")) {
+                return entry.getValue().iterator().next();
+            }
+        }
+
+        return null;
+    }
+
 }


[3/9] cayenne git commit: New DbLoader for dbsync utils - loading process split in independent small steps - DbLoader always return new DataMap, it doesn't accept it from outside

Posted by aa...@apache.org.
New DbLoader for dbsync utils
 - loading process split in independent small steps
 - DbLoader always return new DataMap, it doesn't accept it from outside


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

Branch: refs/heads/master
Commit: 8c273022330129b87f502a30864e94b0281afc4b
Parents: 1e01dc8
Author: Nikita Timofeev <st...@gmail.com>
Authored: Thu Dec 8 18:09:29 2016 +0300
Committer: Nikita Timofeev <st...@gmail.com>
Committed: Thu Dec 8 18:09:29 2016 +0300

----------------------------------------------------------------------
 .../apache/cayenne/dbsync/merge/DbMerger.java   |   2 +-
 .../dbsync/merge/DropRelationshipToDb.java      |   2 +-
 .../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  |  88 +++
 .../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 |  65 +++
 .../dbsync/reverse/dbload/EntityLoader.java     | 106 ++++
 .../dbsync/reverse/dbload/ExportedKey.java      | 220 ++++++++
 .../reverse/dbload/ExportedKeyLoader.java       |  74 +++
 .../reverse/dbload/LoggingDbLoaderDelegate.java |  62 +++
 .../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/RelationshipLoader.java      | 168 ++++++
 .../dbsync/reverse/filters/TableFilter.java     |   7 +-
 .../apache/cayenne/dbsync/merge/MergeCase.java  |  14 +-
 .../cayenne/dbsync/reverse/db/DbLoaderIT.java   | 408 --------------
 .../reverse/dbload/AttributeLoaderIT.java       | 154 ++++++
 .../dbsync/reverse/dbload/BaseLoaderIT.java     |  91 ++++
 .../dbsync/reverse/dbload/DbLoaderIT.java       | 105 ++++
 .../dbsync/reverse/dbload/EntityLoaderIT.java   |  98 ++++
 .../reverse/dbload/ExportedKeyLoaderIT.java     |  71 +++
 .../reverse/dbload/PrimaryKeyLoaderIT.java      |  60 +++
 .../reverse/dbload/RelationshipsLoaderIT.java   |  82 +++
 .../dbsync/reverse/filters/TableFilterTest.java |  81 ++-
 .../tools/dbimport/DbImportConfiguration.java   |   8 +-
 .../tools/dbimport/DefaultDbImportAction.java   |  26 +-
 .../dbimport/DefaultDbImportActionTest.java     | 139 ++---
 .../cayenne/modeler/action/MigrateAction.java   |   2 +-
 .../modeler/dialog/db/DbLoaderHelper.java       |  12 +-
 .../modeler/dialog/db/MergerOptions.java        |  15 +-
 .../dialog/db/ModelerDbImportAction.java        |  12 +-
 49 files changed, 2504 insertions(+), 2109 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cayenne/blob/8c273022/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
index 7adb0e5..102c3c4 100644
--- 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
@@ -121,7 +121,7 @@ public class DbMerger {
         Collection<DbEntity> existingFiltered = new LinkedList<>();
         for (DbEntity entity : existing.getDbEntities()) {
             TableFilter tableFilter = filtersConfig.tableFilter(entity.getCatalog(), entity.getSchema());
-            if (tableFilter != null && tableFilter.isIncludeTable(entity.getName()) != null) {
+            if (tableFilter != null && tableFilter.isIncludeTable(entity.getName())) {
                 existingFiltered.add(entity);
             }
         }

http://git-wip-us.apache.org/repos/asf/cayenne/blob/8c273022/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/DropRelationshipToDb.java
----------------------------------------------------------------------
diff --git a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/DropRelationshipToDb.java b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/DropRelationshipToDb.java
index 612c4a6..6f34c8e 100644
--- a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/DropRelationshipToDb.java
+++ b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/DropRelationshipToDb.java
@@ -23,7 +23,7 @@ import org.apache.cayenne.dba.QuotingStrategy;
 import org.apache.cayenne.dbsync.merge.factory.MergerTokenFactory;
 import org.apache.cayenne.map.DbEntity;
 import org.apache.cayenne.map.DbRelationship;
-import org.apache.cayenne.dbsync.reverse.db.DbRelationshipDetected;
+import org.apache.cayenne.dbsync.reverse.dbload.DbRelationshipDetected;
 
 import java.util.Collections;
 import java.util.List;

http://git-wip-us.apache.org/repos/asf/cayenne/blob/8c273022/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/db/DbAttributesBaseLoader.java
----------------------------------------------------------------------
diff --git a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/db/DbAttributesBaseLoader.java b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/db/DbAttributesBaseLoader.java
deleted file mode 100644
index 591d8b5..0000000
--- a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/db/DbAttributesBaseLoader.java
+++ /dev/null
@@ -1,107 +0,0 @@
-/*****************************************************************
- *   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.reverse.db;
-
-import org.apache.cayenne.dba.DbAdapter;
-import org.apache.cayenne.dba.TypesMapping;
-import org.apache.cayenne.map.DbAttribute;
-import org.apache.cayenne.map.DbEntity;
-
-import java.sql.DatabaseMetaData;
-import java.sql.ResultSet;
-import java.sql.SQLException;
-import java.util.List;
-import java.util.Set;
-
-/**
-* @since 4.0.
-*/
-public abstract class DbAttributesBaseLoader implements DbAttributesLoader {
-    private final String catalog;
-    private final String schema;
-
-    private final DatabaseMetaData metaData;
-    private final DbAdapter adapter;
-
-    public DbAttributesBaseLoader(String catalog, String schema, DatabaseMetaData metaData, DbAdapter adapter) {
-        this.catalog = catalog;
-        this.schema = schema;
-        this.metaData = metaData;
-        this.adapter = adapter;
-    }
-
-    protected DbAttribute loadDbAttribute(Set<String> columns, ResultSet rs) throws SQLException {
-
-        // gets attribute's (column's) information
-        int columnType = rs.getInt("DATA_TYPE");
-
-        // ignore precision of non-decimal columns
-        int decimalDigits = -1;
-        if (TypesMapping.isDecimal(columnType)) {
-            decimalDigits = rs.getInt("DECIMAL_DIGITS");
-            if (rs.wasNull()) {
-                decimalDigits = -1;
-            }
-        }
-
-        // create attribute delegating this task to adapter
-        DbAttribute attr = adapter.buildAttribute(
-                rs.getString("COLUMN_NAME"),
-                rs.getString("TYPE_NAME"),
-                columnType,
-                rs.getInt("COLUMN_SIZE"),
-                decimalDigits,
-                rs.getBoolean("NULLABLE"));
-
-        if (columns.contains("IS_AUTOINCREMENT")) {
-            String autoIncrement = rs.getString("IS_AUTOINCREMENT");
-            if ("YES".equals(autoIncrement)) {
-                attr.setGenerated(true);
-            }
-        }
-        return attr;
-    }
-
-    @Override
-    public void loadDbAttributes(DbEntity entity) {
-        for (DbAttribute attr : loadDbAttributes(entity.getName())) {
-            attr.setEntity(entity);
-
-            // override existing attributes if it comes again
-            if (entity.getAttribute(attr.getName()) != null) {
-                entity.removeAttribute(attr.getName());
-            }
-            entity.addAttribute(attr);
-        }
-    }
-
-    protected abstract List<DbAttribute> loadDbAttributes(String tableName);
-
-    protected String getCatalog() {
-        return catalog;
-    }
-
-    protected String getSchema() {
-        return schema;
-    }
-
-    protected DatabaseMetaData getMetaData() {
-        return metaData;
-    }
-}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/8c273022/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/db/DbAttributesLoader.java
----------------------------------------------------------------------
diff --git a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/db/DbAttributesLoader.java b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/db/DbAttributesLoader.java
deleted file mode 100644
index fb342c9..0000000
--- a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/db/DbAttributesLoader.java
+++ /dev/null
@@ -1,43 +0,0 @@
-/*****************************************************************
- *   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.reverse.db;
-
-import org.apache.cayenne.map.DbEntity;
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-
-/**
- * Interface responsible for attributes loading. Several options possible here
- *  1) load attributes for each table separately
- *  2) load attributes for schema and group it by table names
- *
- *  here is a trade of between count of queries and amount af calculation.
- *
- *
- * @since 4.0
- */
-public interface DbAttributesLoader {
-
-    // TODO use instant field for logging
-    Log LOGGER = LogFactory.getLog(DbTableLoader.class);
-
-    void loadDbAttributes(DbEntity entity);
-
-}
-

http://git-wip-us.apache.org/repos/asf/cayenne/blob/8c273022/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/db/DbAttributesPerSchemaLoader.java
----------------------------------------------------------------------
diff --git a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/db/DbAttributesPerSchemaLoader.java b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/db/DbAttributesPerSchemaLoader.java
deleted file mode 100644
index 1ac0b07..0000000
--- a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/db/DbAttributesPerSchemaLoader.java
+++ /dev/null
@@ -1,131 +0,0 @@
-/*****************************************************************
- *   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.reverse.db;
-
-import org.apache.cayenne.dba.DbAdapter;
-import org.apache.cayenne.dbsync.reverse.filters.PatternFilter;
-import org.apache.cayenne.dbsync.reverse.filters.TableFilter;
-import org.apache.cayenne.map.DbAttribute;
-
-import java.sql.DatabaseMetaData;
-import java.sql.ResultSet;
-import java.sql.ResultSetMetaData;
-import java.sql.SQLException;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-/**
- * Load all attributes for schema and return it for each table
- * */
-public class DbAttributesPerSchemaLoader extends DbAttributesBaseLoader {
-
-	private final TableFilter filter;
-
-	private Map<String, List<DbAttribute>> attributes;
-
-	public DbAttributesPerSchemaLoader(String catalog, String schema, DatabaseMetaData metaData, DbAdapter adapter,
-			TableFilter filter) {
-		super(catalog, schema, metaData, adapter);
-
-		this.filter = filter;
-	}
-
-	private Map<String, List<DbAttribute>> loadDbAttributes() throws SQLException {
-		Map<String, List<DbAttribute>> attributes = new HashMap<>();
-
-		try (ResultSet rs = getMetaData().getColumns(getCatalog(), getSchema(), "%", "%");) {
-			Set<String> columns = new HashSet<String>();
-
-			while (rs.next()) {
-				if (columns.isEmpty()) {
-					ResultSetMetaData rsMetaData = rs.getMetaData();
-					for (int i = 1; i <= rsMetaData.getColumnCount(); i++) {
-						columns.add(rsMetaData.getColumnLabel(i));
-					}
-				}
-
-				// for a reason not quiet apparent to me, Oracle sometimes
-				// returns duplicate record sets for the same table, messing up
-				// table
-				// names. E.g. for the system table "WK$_ATTR_MAPPING" columns
-				// are
-				// returned twice - as "WK$_ATTR_MAPPING" and
-				// "WK$$_ATTR_MAPPING"... Go figure
-				String tableName = rs.getString("TABLE_NAME");
-				String columnName = rs.getString("COLUMN_NAME");
-
-				// TODO: instead of elaborate filtering, can we just limit this to the tables that we already have?
-				PatternFilter columnFilter = filter.isIncludeTable(tableName);
-				/*
-				 * Here is possible optimization if filter will contain
-				 * map<tableName, columnFilter> we can replace it after tables
-				 * loading since already done pattern matching once and exactly
-				 * know all tables that we want to process
-				 */
-				if (columnFilter == null || !columnFilter.isIncluded(columnName)) {
-					if (LOGGER.isDebugEnabled()) {
-						LOGGER.debug("Skip column '" + tableName + "." + columnName + "' (Path: " + getCatalog() + "/"
-								+ getSchema() + "; Filter: " + columnFilter + ")");
-					}
-					continue;
-				}
-
-				List<DbAttribute> attrs = attributes.get(tableName);
-				if (attrs == null) {
-					attrs = new LinkedList<DbAttribute>();
-
-					attributes.put(tableName, attrs);
-				}
-
-				attrs.add(loadDbAttribute(columns, rs));
-			}
-		}
-
-		return attributes;
-	}
-
-	@Override
-	protected List<DbAttribute> loadDbAttributes(String tableName) {
-		Map<String, List<DbAttribute>> attributes = getAttributes();
-		if (attributes != null) {
-			List<DbAttribute> dbAttributes = attributes.get(tableName);
-			if (dbAttributes != null) {
-				return dbAttributes;
-			}
-		}
-
-		return new LinkedList<DbAttribute>();
-	}
-
-	public Map<String, List<DbAttribute>> getAttributes() {
-		if (attributes == null) {
-			try {
-				attributes = loadDbAttributes();
-			} catch (SQLException e) {
-				LOGGER.error(e);
-				attributes = new HashMap<>();
-			}
-		}
-		return attributes;
-	}
-}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/8c273022/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/db/DbLoader.java
----------------------------------------------------------------------
diff --git a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/db/DbLoader.java b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/db/DbLoader.java
deleted file mode 100644
index b171b5f..0000000
--- a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/db/DbLoader.java
+++ /dev/null
@@ -1,534 +0,0 @@
-/*
- * 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.reverse.db;
-
-import org.apache.cayenne.dba.DbAdapter;
-import org.apache.cayenne.dba.TypesMapping;
-import org.apache.cayenne.dbsync.naming.NameBuilder;
-import org.apache.cayenne.dbsync.naming.ObjectNameGenerator;
-import org.apache.cayenne.dbsync.reverse.filters.CatalogFilter;
-import org.apache.cayenne.dbsync.reverse.filters.FiltersConfig;
-import org.apache.cayenne.dbsync.reverse.filters.SchemaFilter;
-import org.apache.cayenne.dbsync.reverse.filters.TableFilter;
-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.Procedure;
-import org.apache.cayenne.map.ProcedureParameter;
-import org.apache.cayenne.util.EqualsBuilder;
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-
-import java.sql.Connection;
-import java.sql.DatabaseMetaData;
-import java.sql.ResultSet;
-import java.sql.SQLException;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Objects;
-import java.util.Set;
-import java.util.TreeSet;
-
-/**
- * Performs reverse engineering of the database, loading DB metadata in provided DataMap.
- *
- * @since 4.0
- */
-public class DbLoader {
-
-    private static final Log LOGGER = LogFactory.getLog(DbLoader.class);
-
-    private static final String WILDCARD = "%";
-
-    private final Connection connection;
-    private final DbAdapter adapter;
-    private final DbLoaderDelegate delegate;
-    private final ObjectNameGenerator nameGenerator;
-    private DatabaseMetaData metaData;
-
-    public DbLoader(Connection connection, DbAdapter adapter, DbLoaderDelegate delegate, ObjectNameGenerator nameGenerator) {
-        this.adapter = Objects.requireNonNull(adapter);
-        this.connection = Objects.requireNonNull(connection);
-        this.nameGenerator = Objects.requireNonNull(nameGenerator);
-        this.delegate = delegate == null ? new DefaultDbLoaderDelegate() : delegate;
-    }
-
-    private static List<String> getStrings(ResultSet rs) throws SQLException {
-        List<String> strings = new ArrayList<>();
-
-        while (rs.next()) {
-            strings.add(rs.getString(1));
-        }
-
-        return strings;
-    }
-
-    private static int getDirection(short type) {
-        switch (type) {
-            case DatabaseMetaData.procedureColumnIn:
-                return ProcedureParameter.IN_PARAMETER;
-            case DatabaseMetaData.procedureColumnInOut:
-                return ProcedureParameter.IN_OUT_PARAMETER;
-            case DatabaseMetaData.procedureColumnOut:
-                return ProcedureParameter.OUT_PARAMETER;
-            default:
-                return -1;
-        }
-    }
-
-    /**
-     * Retrieves catalogs for a given connection.
-     *
-     * @return List with the catalog names; empty list if none found.
-     */
-    // using a static method for catalog loading as we don't need a full DbLoader for this operation
-    public static List<String> loadCatalogs(Connection connection) throws SQLException {
-        try (ResultSet rs = connection.getMetaData().getCatalogs()) {
-            return getStrings(rs);
-        }
-    }
-
-    /**
-     * Retrieves the schemas for the given connection.
-     *
-     * @return List with the schema names; empty list if none found.
-     */
-    // using a static method for catalog loading as we don't need a full DbLoader for this operation
-    public static List<String> loadSchemas(Connection connection) throws SQLException {
-
-        try (ResultSet rs = connection.getMetaData().getSchemas()) {
-            return getStrings(rs);
-        }
-    }
-
-    /**
-     * Returns DatabaseMetaData object associated with this DbLoader.
-     */
-    private DatabaseMetaData getMetaData() throws SQLException {
-        if (metaData == null) {
-            metaData = connection.getMetaData();
-        }
-        return metaData;
-    }
-
-    protected void loadDbRelationships(DbLoaderConfiguration config, String catalog, String schema,
-                                       List<DbEntity> tables) throws SQLException {
-        if (config.isSkipRelationshipsLoading()) {
-            return;
-        }
-
-        // Get all the foreign keys referencing this table
-        Map<String, DbEntity> tablesMap = new HashMap<>();
-        for (DbEntity table : tables) {
-            tablesMap.put(table.getName(), table);
-        }
-
-        Map<String, Set<ExportedKey>> keys = loadExportedKeys(config, catalog, schema, tablesMap);
-        for (Map.Entry<String, Set<ExportedKey>> entry : keys.entrySet()) {
-            if (LOGGER.isDebugEnabled()) {
-                LOGGER.debug("Process keys for: " + entry.getKey());
-            }
-
-            Set<ExportedKey> exportedKeys = entry.getValue();
-            ExportedKey key = exportedKeys.iterator().next();
-            if (key == null) {
-                throw new IllegalStateException();
-            }
-
-            DbEntity pkEntity = tablesMap.get(key.getPKTableName());
-            if (pkEntity == null) {
-                skipRelationLog(key, key.getPKTableName());
-                continue;
-            }
-
-            DbEntity fkEntity = tablesMap.get(key.getFKTableName());
-            if (fkEntity == null) {
-                skipRelationLog(key, key.getFKTableName());
-                continue;
-            }
-
-            if (!new EqualsBuilder().append(pkEntity.getCatalog(), key.getPkCatalog())
-                    .append(pkEntity.getSchema(), key.getPkSchema()).append(fkEntity.getCatalog(), key.getFkCatalog())
-                    .append(fkEntity.getSchema(), key.getFkSchema()).isEquals()) {
-
-                LOGGER.info("Skip relation: '" + key + "' because it related to objects from other catalog/schema");
-                LOGGER.info("     relation primary key: '" + key.getPkCatalog() + "." + key.getPkSchema() + "'");
-                LOGGER.info("       primary key entity: '" + pkEntity.getCatalog() + "." + pkEntity.getSchema() + "'");
-                LOGGER.info("     relation foreign key: '" + key.getFkCatalog() + "." + key.getFkSchema() + "'");
-                LOGGER.info("       foreign key entity: '" + fkEntity.getCatalog() + "." + fkEntity.getSchema() + "'");
-                continue;
-            }
-
-            // forwardRelationship is a reference from table with primary key
-            DbRelationship forwardRelationship = new DbRelationship();
-
-            forwardRelationship.setSourceEntity(pkEntity);
-            forwardRelationship.setTargetEntityName(fkEntity);
-
-            // forwardRelationship is a reference from table with foreign key,
-            // it is what exactly we load from db
-
-            // TODO: dirty and non-transparent... using DbRelationshipDetected for the benefit of the merge package.
-            // This info is available from joins....
-            DbRelationshipDetected reverseRelationship = new DbRelationshipDetected();
-
-
-            reverseRelationship.setFkName(key.getFKName());
-            reverseRelationship.setSourceEntity(fkEntity);
-            reverseRelationship.setTargetEntityName(pkEntity);
-            reverseRelationship.setToMany(false);
-
-            createAndAppendJoins(exportedKeys, pkEntity, fkEntity, forwardRelationship, reverseRelationship);
-
-            boolean toDependentPK = isToDependentPK(forwardRelationship);
-            forwardRelationship.setToDependentPK(toDependentPK);
-
-            boolean isOneToOne = toDependentPK
-                    && fkEntity.getPrimaryKeys().size() == forwardRelationship.getJoins().size();
-
-            forwardRelationship.setToMany(!isOneToOne);
-
-            // set relationship names only after their joins are ready ... generator logic is based on relationship
-            // state...
-            forwardRelationship.setName(NameBuilder
-                    .builder(forwardRelationship, pkEntity)
-                    .baseName(nameGenerator.relationshipName(forwardRelationship))
-                    .name());
-
-            reverseRelationship.setName(NameBuilder
-                    .builder(reverseRelationship, fkEntity)
-                    .baseName(nameGenerator.relationshipName(reverseRelationship))
-                    .name());
-
-            if (delegate.dbRelationshipLoaded(fkEntity, reverseRelationship)) {
-                fkEntity.addRelationship(reverseRelationship);
-            }
-            if (delegate.dbRelationshipLoaded(pkEntity, forwardRelationship)) {
-                pkEntity.addRelationship(forwardRelationship);
-            }
-        }
-    }
-
-    private boolean isToDependentPK(DbRelationship forwardRelationship) {
-        for (DbJoin dbJoin : forwardRelationship.getJoins()) {
-            if (!dbJoin.getTarget().isPrimaryKey()) {
-                return false;
-            }
-        }
-
-        return true;
-    }
-
-    private void createAndAppendJoins(Set<ExportedKey> exportedKeys, DbEntity pkEntity, DbEntity fkEntity,
-                                      DbRelationship forwardRelationship, DbRelationship reverseRelationship) {
-        for (ExportedKey exportedKey : exportedKeys) {
-            // Create and append joins
-            String pkName = exportedKey.getPKColumnName();
-            String fkName = exportedKey.getFKColumnName();
-
-            // skip invalid joins...
-            DbAttribute pkAtt = pkEntity.getAttribute(pkName);
-            if (pkAtt == null) {
-                LOGGER.info("no attribute for declared primary key: " + pkName);
-                continue;
-            }
-
-            DbAttribute fkAtt = fkEntity.getAttribute(fkName);
-            if (fkAtt == null) {
-                LOGGER.info("no attribute for declared foreign key: " + fkName);
-                continue;
-            }
-
-            forwardRelationship.addJoin(new DbJoin(forwardRelationship, pkName, fkName));
-            reverseRelationship.addJoin(new DbJoin(reverseRelationship, fkName, pkName));
-        }
-    }
-
-    private Map<String, Set<ExportedKey>> loadExportedKeys(DbLoaderConfiguration config, String catalog, String schema,
-                                                           Map<String, DbEntity> tables) throws SQLException {
-        Map<String, Set<ExportedKey>> keys = new HashMap<>();
-
-        for (DbEntity dbEntity : tables.values()) {
-            if (!delegate.dbRelationship(dbEntity)) {
-                continue;
-            }
-
-            ResultSet rs;
-            try {
-                rs = getMetaData().getExportedKeys(catalog, schema, dbEntity.getName());
-            } catch (SQLException cay182Ex) {
-                // Sybase-specific - the line above blows on VIEWS, see CAY-182.
-                LOGGER.info("Error getting relationships for '" + catalog + "." + schema + "', ignoring. "
-                        + cay182Ex.getMessage(), cay182Ex);
-                return new HashMap<>();
-            }
-
-            try {
-                while (rs.next()) {
-                    ExportedKey key = ExportedKey.extractData(rs);
-
-                    DbEntity fkEntity = tables.get(key.getFKTableName());
-                    if (fkEntity == null) {
-                        skipRelationLog(key, key.getFKTableName());
-                        continue;
-                    }
-
-                    if (config.getFiltersConfig().tableFilter(fkEntity.getCatalog(), fkEntity.getSchema())
-                            .isIncludeTable(fkEntity.getName()) == null) {
-                        continue;
-                    }
-
-                    Set<ExportedKey> exportedKeys = keys.get(key.getStrKey());
-                    if (exportedKeys == null) {
-                        exportedKeys = new TreeSet<ExportedKey>();
-
-                        keys.put(key.getStrKey(), exportedKeys);
-                    }
-                    exportedKeys.add(key);
-                }
-
-            } finally {
-                rs.close();
-            }
-        }
-        return keys;
-    }
-
-    private void skipRelationLog(ExportedKey key, String tableName) {
-        LOGGER.info("Skip relation: '" + key + "' because table '" + tableName + "' not found");
-    }
-
-    protected String[] getTableTypes(DbLoaderConfiguration config) {
-
-        String[] configTypes = config.getTableTypes();
-        if (configTypes != null && configTypes.length > 0) {
-            return configTypes;
-        }
-
-        List<String> list = new ArrayList<>(2);
-
-        String viewType = adapter.tableTypeForView();
-        if (viewType != null) {
-            list.add(viewType);
-        }
-
-        String tableType = adapter.tableTypeForTable();
-        if (tableType != null) {
-            list.add(tableType);
-        }
-
-        return list.toArray(new String[list.size()]);
-    }
-
-    /**
-     * Performs database reverse engineering based on provided configuration. Stores the resulting {@link DbEntity}
-     * and {@link Procedure} objects in provided DataMap.
-     *
-     * @since 4.0
-     */
-    public void load(DataMap dataMap, DbLoaderConfiguration config) throws SQLException {
-        loadDbEntities(dataMap, config);
-        loadProcedures(dataMap, config);
-    }
-
-    protected void loadDbEntities(DataMap dataMap, DbLoaderConfiguration config) throws SQLException {
-
-        String[] types = getTableTypes(config);
-
-        for (CatalogFilter catalog : config.getFiltersConfig().getCatalogs()) {
-            for (SchemaFilter schema : catalog.schemas) {
-                List<DbEntity> entities = createTableLoader(catalog.name, schema.name, schema.tables).loadDbEntities(
-                        dataMap, config, types);
-                loadDbRelationships(config, catalog.name, schema.name, entities);
-            }
-        }
-    }
-
-    protected DbTableLoader createTableLoader(String catalog, String schema, TableFilter filter) throws SQLException {
-        return new DbTableLoader(catalog,
-                schema,
-                getMetaData(),
-                delegate,
-                new DbAttributesPerSchemaLoader(catalog, schema, getMetaData(), adapter, filter));
-    }
-
-
-    /**
-     * Loads database stored procedures into the DataMap.
-     * <p>
-     * <i>As of 1.1 there is no boolean property or delegate method to make
-     * procedure loading optional or to implement custom merging logic, so
-     * currently this method is NOT CALLED from "loadDataMapFromDB" and should
-     * be invoked explicitly by the user. </i>
-     * </p>
-     *
-     * @since 4.0
-     */
-    protected Map<String, Procedure> loadProcedures(DataMap dataMap, DbLoaderConfiguration config) throws SQLException {
-
-        Map<String, Procedure> procedures = loadProcedures(config);
-        if (procedures.isEmpty()) {
-            return procedures;
-        }
-
-        loadProceduresColumns(config, procedures);
-
-        for (Procedure procedure : procedures.values()) {
-            dataMap.addProcedure(procedure);
-        }
-
-        return procedures;
-    }
-
-    private void loadProceduresColumns(DbLoaderConfiguration config, Map<String, Procedure> procedures)
-            throws SQLException {
-
-        for (CatalogFilter catalog : config.getFiltersConfig().getCatalogs()) {
-            for (SchemaFilter schema : catalog.schemas) {
-                loadProceduresColumns(procedures, catalog.name, schema.name);
-            }
-        }
-    }
-
-    private void loadProceduresColumns(Map<String, Procedure> procedures, String catalog, String schema)
-            throws SQLException {
-
-        try (ResultSet columnsRS = getMetaData().getProcedureColumns(catalog, schema, null, null);) {
-            while (columnsRS.next()) {
-                String procSchema = columnsRS.getString("PROCEDURE_SCHEM");
-                String procCatalog = columnsRS.getString("PROCEDURE_CAT");
-                String name = columnsRS.getString("PROCEDURE_NAME");
-                String key = Procedure.generateFullyQualifiedName(procCatalog, procSchema, name);
-                Procedure procedure = procedures.get(key);
-                if (procedure == null) {
-                    continue;
-                }
-
-                ProcedureParameter column = loadProcedureParams(columnsRS, key, procedure);
-                if (column == null) {
-                    continue;
-                }
-                procedure.addCallParameter(column);
-            }
-        }
-    }
-
-    private ProcedureParameter loadProcedureParams(ResultSet columnsRS, String key, Procedure procedure)
-            throws SQLException {
-        String columnName = columnsRS.getString("COLUMN_NAME");
-
-        // skip ResultSet columns, as they are not described in Cayenne
-        // procedures yet...
-        short type = columnsRS.getShort("COLUMN_TYPE");
-        if (type == DatabaseMetaData.procedureColumnResult) {
-            LOGGER.debug("skipping ResultSet column: " + key + "." + columnName);
-        }
-
-        if (columnName == null) {
-            if (type == DatabaseMetaData.procedureColumnReturn) {
-                LOGGER.debug("null column name, assuming result column: " + key);
-                columnName = "_return_value";
-                procedure.setReturningValue(true);
-            } else {
-                LOGGER.info("invalid null column name, skipping column : " + key);
-                return null;
-            }
-        }
-
-        int columnType = columnsRS.getInt("DATA_TYPE");
-
-        // ignore precision of non-decimal columns
-        int decimalDigits = -1;
-        if (TypesMapping.isDecimal(columnType)) {
-            decimalDigits = columnsRS.getShort("SCALE");
-            if (columnsRS.wasNull()) {
-                decimalDigits = -1;
-            }
-        }
-
-        ProcedureParameter column = new ProcedureParameter(columnName);
-        int direction = getDirection(type);
-        if (direction != -1) {
-            column.setDirection(direction);
-        }
-
-        column.setType(columnType);
-        column.setMaxLength(columnsRS.getInt("LENGTH"));
-        column.setPrecision(decimalDigits);
-
-        column.setProcedure(procedure);
-        return column;
-    }
-
-    private Map<String, Procedure> loadProcedures(DbLoaderConfiguration config) throws SQLException {
-        Map<String, Procedure> procedures = new HashMap<>();
-
-        FiltersConfig filters = config.getFiltersConfig();
-        for (CatalogFilter catalog : filters.getCatalogs()) {
-            for (SchemaFilter schema : catalog.schemas) {
-                if (filters.proceduresFilter(catalog.name, schema.name).isEmpty()) {
-                    continue;
-                }
-
-                procedures.putAll(loadProcedures(filters, catalog.name, schema.name));
-            }
-        }
-
-        return procedures;
-    }
-
-    private Map<String, Procedure> loadProcedures(FiltersConfig filters, String catalog, String schema)
-            throws SQLException {
-        Map<String, Procedure> procedures = new HashMap<>();
-        // get procedures
-
-        try (ResultSet rs = getMetaData().getProcedures(catalog, schema, WILDCARD);) {
-            while (rs.next()) {
-
-                String name = rs.getString("PROCEDURE_NAME");
-                Procedure procedure = new Procedure(name);
-                procedure.setCatalog(rs.getString("PROCEDURE_CAT"));
-                procedure.setSchema(rs.getString("PROCEDURE_SCHEM"));
-
-                if (!filters.proceduresFilter(procedure.getCatalog(), procedure.getSchema()).isIncluded(
-                        procedure.getName())) {
-                    LOGGER.info("skipping Cayenne PK procedure: " + name);
-                    continue;
-                }
-
-                switch (rs.getShort("PROCEDURE_TYPE")) {
-                    case DatabaseMetaData.procedureNoResult:
-                    case DatabaseMetaData.procedureResultUnknown:
-                        procedure.setReturningValue(false);
-                        break;
-                    case DatabaseMetaData.procedureReturnsResult:
-                        procedure.setReturningValue(true);
-                        break;
-                }
-
-                procedures.put(procedure.getFullyQualifiedName(), procedure);
-            }
-        }
-        return procedures;
-    }
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cayenne/blob/8c273022/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/db/DbLoaderConfiguration.java
----------------------------------------------------------------------
diff --git a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/db/DbLoaderConfiguration.java b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/db/DbLoaderConfiguration.java
deleted file mode 100644
index e7c5e81..0000000
--- a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/db/DbLoaderConfiguration.java
+++ /dev/null
@@ -1,84 +0,0 @@
-/*****************************************************************
- *   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.reverse.db;
-
-import org.apache.cayenne.dbsync.reverse.filters.TableFilter;
-import org.apache.cayenne.dbsync.reverse.filters.FiltersConfig;
-import org.apache.cayenne.dbsync.reverse.filters.PatternFilter;
-
-/**
- * @since 4.0
- */
-public class DbLoaderConfiguration {
-
-    private Boolean skipRelationshipsLoading;
-    private Boolean skipPrimaryKeyLoading;
-    private String[] tableTypes;
-    private FiltersConfig filtersConfig;
-
-    public String[] getTableTypes() {
-        return tableTypes;
-    }
-
-    public void setTableTypes(String[] tableTypes) {
-        this.tableTypes = tableTypes;
-    }
-
-    public FiltersConfig getFiltersConfig() {
-        if (filtersConfig == null) {
-            // this case is used often in tests where config not initialized properly
-            return FiltersConfig.create(null, null, TableFilter.everything(), PatternFilter.INCLUDE_NOTHING);
-        }
-        return filtersConfig;
-    }
-
-    public void setFiltersConfig(FiltersConfig filtersConfig) {
-        this.filtersConfig = filtersConfig;
-    }
-
-    public boolean isSkipRelationshipsLoading() {
-        return skipRelationshipsLoading != null && skipRelationshipsLoading;
-    }
-
-    public void setSkipRelationshipsLoading(Boolean skipRelationshipsLoading) {
-        this.skipRelationshipsLoading = skipRelationshipsLoading;
-    }
-
-    public boolean isSkipPrimaryKeyLoading() {
-        return skipPrimaryKeyLoading != null && skipPrimaryKeyLoading;
-    }
-
-    public void setSkipPrimaryKeyLoading(Boolean skipPrimaryKeyLoading) {
-        this.skipPrimaryKeyLoading = skipPrimaryKeyLoading;
-    }
-
-    @Override
-    public String toString() {
-        String res = "EntitiesFilters: " + getFiltersConfig();
-        if (isSkipRelationshipsLoading()) {
-            res += "\n Skip Loading Relationships! \n";
-        }
-
-        if (isSkipPrimaryKeyLoading()) {
-            res += "\n Skip Loading PrimaryKeys! \n";
-        }
-
-        return res;
-    }
-}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/8c273022/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/db/DbLoaderDelegate.java
----------------------------------------------------------------------
diff --git a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/db/DbLoaderDelegate.java b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/db/DbLoaderDelegate.java
deleted file mode 100644
index 94705c6..0000000
--- a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/db/DbLoaderDelegate.java
+++ /dev/null
@@ -1,63 +0,0 @@
-/*****************************************************************
- *   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.reverse.db;
-
-import org.apache.cayenne.map.DbEntity;
-import org.apache.cayenne.map.DbRelationship;
-import org.apache.cayenne.map.ObjEntity;
-
-/**
- * Defines API for progress tracking and altering the folow of reverse-engineering.
- */
-public interface DbLoaderDelegate {
-
-    void dbEntityAdded(DbEntity entity);
-
-    void dbEntityRemoved(DbEntity entity);
-
-    /**
-     * Called before relationship loading for a {@link DbEntity}.
-     *
-     * @param entity DbEntity for which {@link DbRelationship} is about to be loaded.
-     * @return true in case you want process relationships for this entity, false otherwise.
-     */
-    boolean dbRelationship(DbEntity entity);
-
-    /**
-     * Called before relationship will be added into db-entity but after it was loaded from db
-     *
-     * @param entity
-     * @return true in case you want add this relationship into entity
-     * false otherwise
-     */
-    boolean dbRelationshipLoaded(DbEntity entity, DbRelationship relationship);
-
-    /**
-     * @deprecated since 4.0 no longer invoked as DbLoader does not deal with object layer anymore.
-     */
-    @Deprecated
-    void objEntityAdded(ObjEntity entity);
-
-    /**
-     * @deprecated since 4.0 no longer invoked as DbLoader does not deal with object layer anymore.
-     */
-    @Deprecated
-    void objEntityRemoved(ObjEntity entity);
-}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/8c273022/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/db/DbRelationshipDetected.java
----------------------------------------------------------------------
diff --git a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/db/DbRelationshipDetected.java b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/db/DbRelationshipDetected.java
deleted file mode 100644
index dfad14f..0000000
--- a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/db/DbRelationshipDetected.java
+++ /dev/null
@@ -1,53 +0,0 @@
-/*****************************************************************
- *   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.reverse.db;
-
-
-import org.apache.cayenne.map.DbRelationship;
-
-/**
- * A subclass of {@link DbRelationship} to hold some extra runtime information.
- */
-// TODO: dirty ... can we lookup fkName via joins?
-public class DbRelationshipDetected extends DbRelationship {
-
-    private String fkName;
-
-    public DbRelationshipDetected(String uniqueRelName) {
-        super(uniqueRelName);
-    }
-
-    public DbRelationshipDetected() {
-    }
-
-    /**
-     * Get the name of the underlying foreign key. Typically FK_NAME from jdbc metadata.
-     */
-    public String getFkName() {
-        return fkName;
-    }
-
-    /**
-     * Set the name of the underlying foreign key. Typically FK_NAME from jdbc metadata.
-     */
-    public void setFkName(String fkName) {
-        this.fkName = fkName;
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/8c273022/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/db/DbTableLoader.java
----------------------------------------------------------------------
diff --git a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/db/DbTableLoader.java b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/db/DbTableLoader.java
deleted file mode 100644
index f3476af..0000000
--- a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/db/DbTableLoader.java
+++ /dev/null
@@ -1,183 +0,0 @@
-/*****************************************************************
- *   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.reverse.db;
-
-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.DbAttribute;
-import org.apache.cayenne.map.DbEntity;
-import org.apache.cayenne.map.DetectedDbEntity;
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-
-import java.sql.DatabaseMetaData;
-import java.sql.ResultSet;
-import java.sql.SQLException;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.LinkedList;
-import java.util.List;
-
-/**
- * @since 4.0
- */
-public class DbTableLoader {
-
-	private static final Log LOGGER = LogFactory.getLog(DbTableLoader.class);
-
-	private static final String WILDCARD = "%";
-
-	private final String catalog;
-	private final String schema;
-
-	private final DatabaseMetaData metaData;
-	private final DbLoaderDelegate delegate;
-
-	private final DbAttributesLoader attributesLoader;
-
-	public DbTableLoader(String catalog, String schema, DatabaseMetaData metaData, DbLoaderDelegate delegate,
-			DbAttributesLoader attributesLoader) {
-		this.catalog = catalog;
-		this.schema = schema;
-		this.metaData = metaData;
-		this.delegate = delegate;
-
-		this.attributesLoader = attributesLoader;
-	}
-
-	/**
-	 * Returns all tables for given combination of the criteria. Tables returned
-	 * as DbEntities without any attributes or relationships.
-	 *
-	 * @param types
-	 *            The types of table names to retrieve, null returns all types.
-	 * @since 4.0
-	 */
-	public List<DetectedDbEntity> getDbEntities(TableFilter filters, String[] types) throws SQLException {
-		if (LOGGER.isDebugEnabled()) {
-			LOGGER.debug("Read tables: catalog=" + catalog + ", schema=" + schema + ", types=" + Arrays.toString(types));
-		}
-
-		List<DetectedDbEntity> tables = new LinkedList<DetectedDbEntity>();
-		try (ResultSet rs = metaData.getTables(catalog, schema, WILDCARD, types);) {
-			while (rs.next()) {
-				// Oracle 9i and newer has a nifty recycle bin feature... but we
-				// don't
-				// want dropped tables to be included here; in fact they may
-				// even result
-				// in errors on reverse engineering as their names have special
-				// chars like
-				// "/", etc. So skip them all together
-
-				String name = rs.getString("TABLE_NAME");
-				if (name == null) {
-					continue;
-				}
-
-				DetectedDbEntity table = new DetectedDbEntity(name);
-
-				String catalog = rs.getString("TABLE_CAT");
-				table.setCatalog(catalog);
-
-				String schema = rs.getString("TABLE_SCHEM");
-				table.setSchema(schema);
-				if (!(this.catalog == null || this.catalog.equals(catalog))
-						|| !(this.schema == null || this.schema.equals(schema))) {
-
-					LOGGER.error(catalog + "." + schema + "." + name + " wrongly loaded for catalog/schema : "
-							+ this.catalog + "." + this.schema);
-
-					continue;
-				}
-
-				PatternFilter includeTable = filters.isIncludeTable(table.getName());
-				if (includeTable != null) {
-					tables.add(table);
-				}
-			}
-		}
-		return tables;
-	}
-
-	/**
-	 * Loads dbEntities for the specified tables.
-	 * 
-	 * @param config
-	 * @param types
-	 */
-	public List<DbEntity> loadDbEntities(DataMap map, DbLoaderConfiguration config, String[] types) throws SQLException {
-		/** List of db entities to process. */
-
-		List<DetectedDbEntity> tables = getDbEntities(config.getFiltersConfig().tableFilter(catalog, schema), types);
-
-		List<DbEntity> dbEntities = new ArrayList<>();
-		for (DbEntity dbEntity : tables) {
-			DbEntity oldEnt = map.getDbEntity(dbEntity.getName());
-			if (oldEnt != null) {
-				LOGGER.debug("Overwrite DbEntity: " + oldEnt.getName());
-				map.removeDbEntity(oldEnt.getName(), true);
-				delegate.dbEntityRemoved(oldEnt);
-			}
-
-			map.addDbEntity(dbEntity);
-
-			delegate.dbEntityAdded(dbEntity);
-
-			// delegate might have thrown this entity out... so check if it is
-			// still
-			// around before continuing processing
-			if (map.getDbEntity(dbEntity.getName()) == dbEntity) {
-				dbEntities.add(dbEntity);
-				attributesLoader.loadDbAttributes(dbEntity);
-				if (!config.isSkipPrimaryKeyLoading()) {
-					loadPrimaryKey(dbEntity);
-				}
-			}
-		}
-
-		return dbEntities;
-	}
-
-	private void loadPrimaryKey(DbEntity dbEntity) throws SQLException {
-
-		try (ResultSet rs = metaData.getPrimaryKeys(dbEntity.getCatalog(), dbEntity.getSchema(), dbEntity.getName());) {
-			while (rs.next()) {
-				String columnName = rs.getString("COLUMN_NAME");
-				DbAttribute attribute = dbEntity.getAttribute(columnName);
-
-				if (attribute != null) {
-					attribute.setPrimaryKey(true);
-				} else {
-					// why an attribute might be null is not quiet clear
-					// but there is a bug report 731406 indicating that it is
-					// possible
-					// so just print the warning, and ignore
-					LOGGER.warn("Can't locate attribute for primary key: " + columnName);
-				}
-
-				String pkName = rs.getString("PK_NAME");
-				if (pkName != null && dbEntity instanceof DetectedDbEntity) {
-					((DetectedDbEntity) dbEntity).setPrimaryKeyName(pkName);
-				}
-
-			}
-		}
-	}
-}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/8c273022/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/db/DefaultDbLoaderDelegate.java
----------------------------------------------------------------------
diff --git a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/db/DefaultDbLoaderDelegate.java b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/db/DefaultDbLoaderDelegate.java
deleted file mode 100644
index fef024f..0000000
--- a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/db/DefaultDbLoaderDelegate.java
+++ /dev/null
@@ -1,63 +0,0 @@
-/*****************************************************************
- *   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.reverse.db;
-
-import org.apache.cayenne.map.DbEntity;
-import org.apache.cayenne.map.DbRelationship;
-import org.apache.cayenne.map.ObjEntity;
-
-/**
- * A noop {@link DbLoaderDelegate}.
- *
- * @since 4.0
- */
-public class DefaultDbLoaderDelegate implements DbLoaderDelegate {
-
-    @Override
-    public void dbEntityAdded(DbEntity entity) {
-
-    }
-
-    @Override
-    public void dbEntityRemoved(DbEntity entity) {
-
-    }
-
-    @Override
-    public boolean dbRelationship(DbEntity entity) {
-        return true;
-    }
-
-    @Override
-    public boolean dbRelationshipLoaded(DbEntity entity, DbRelationship relationship) {
-        return true;
-    }
-
-    @Deprecated
-    @Override
-    public void objEntityAdded(ObjEntity entity) {
-
-    }
-
-    @Deprecated
-    @Override
-    public void objEntityRemoved(ObjEntity entity) {
-
-    }
-}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/8c273022/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/db/ExportedKey.java
----------------------------------------------------------------------
diff --git a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/db/ExportedKey.java b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/db/ExportedKey.java
deleted file mode 100644
index 093cbf0..0000000
--- a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/db/ExportedKey.java
+++ /dev/null
@@ -1,233 +0,0 @@
-/*****************************************************************
- *   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.reverse.db;
-
-import org.apache.cayenne.util.EqualsBuilder;
-import org.apache.cayenne.util.HashCodeBuilder;
-import org.apache.commons.lang.builder.CompareToBuilder;
-
-import java.sql.ResultSet;
-import java.sql.SQLException;
-
-/**
- * A representation of relationship between two tables in database. It can be used for creating names
- * for relationships.
- *
- * @since 4.0
- */
-class ExportedKey implements Comparable {
-
-    private final String pkCatalog;
-    private final String pkSchema;
-    private final String pkTable;
-    private final String pkColumn;
-    private final String fkCatalog;
-    private final String fkSchema;
-    private final String fkTable;
-    private final String fkColumn;
-    private final String fkName;
-    private final String pkName;
-    private final short keySeq;
-
-    public ExportedKey(String pkTable, String pkColumn, String pkName,
-                       String fkTable, String fkColumn, String fkName, short keySeq) {
-        this(null, null, pkTable, pkColumn, pkName, null, null, fkTable, fkColumn, fkName, keySeq);
-    }
-
-    public ExportedKey(String pkCatalog, String pkSchema, String pkTable, String pkColumn, String pkName,
-                       String fkCatalog, String fkSchema, String fkTable, String fkColumn, String fkName, short keySeq) {
-        this.pkCatalog = pkCatalog;
-        this.pkSchema = pkSchema;
-        this.pkTable = pkTable;
-        this.pkColumn = pkColumn;
-        this.pkName = pkName;
-        this.fkCatalog = fkCatalog;
-        this.fkSchema = fkSchema;
-        this.fkTable = fkTable;
-        this.fkColumn = fkColumn;
-        this.fkName = fkName;
-        this.keySeq = keySeq;
-    }
-
-    /**
-     * Extracts data from a resultset pointing to a exported key to
-     * ExportedKey class instance
-     *
-     * @param rs ResultSet pointing to a exported key, fetched using
-     *           DataBaseMetaData.getExportedKeys(...)
-     */
-    public static ExportedKey extractData(ResultSet rs) throws SQLException {
-        return new ExportedKey(
-                rs.getString("PKTABLE_CAT"),
-                rs.getString("PKTABLE_SCHEM"),
-                rs.getString("PKTABLE_NAME"),
-                rs.getString("PKCOLUMN_NAME"),
-                rs.getString("PK_NAME"),
-                rs.getString("FKTABLE_CAT"),
-                rs.getString("FKTABLE_SCHEM"),
-                rs.getString("FKTABLE_NAME"),
-                rs.getString("FKCOLUMN_NAME"),
-                rs.getString("FK_NAME"),
-                rs.getShort("KEY_SEQ")
-        );
-    }
-
-
-    public String getPkCatalog() {
-        return pkCatalog;
-    }
-
-    public String getPkSchema() {
-        return pkSchema;
-    }
-
-    public String getFkCatalog() {
-        return fkCatalog;
-    }
-
-    public String getFkSchema() {
-        return fkSchema;
-    }
-
-    /**
-     * @return source table name
-     */
-    public String getPKTableName() {
-        return pkTable;
-    }
-
-    /**
-     * @return destination table name
-     */
-    public String getFKTableName() {
-        return fkTable;
-    }
-
-    /**
-     * @return source column name
-     */
-    public String getPKColumnName() {
-        return pkColumn;
-    }
-
-    /**
-     * @return destination column name
-     */
-    public String getFKColumnName() {
-        return fkColumn;
-    }
-
-    /**
-     * @return PK name
-     */
-    public String getPKName() {
-        return pkName;
-    }
-
-    /**
-     * @return FK name
-     */
-    public String getFKName() {
-        return fkName;
-    }
-
-    public short getKeySeq() {
-        return keySeq;
-    }
-
-
-    @Override
-    public boolean equals(Object obj) {
-        if (obj == null) {
-            return false;
-        }
-        if (obj == this) {
-            return true;
-        }
-        if (obj.getClass() != getClass()) {
-            return false;
-        }
-        ExportedKey rhs = (ExportedKey) obj;
-        return new EqualsBuilder()
-                .append(this.pkCatalog, rhs.pkCatalog)
-                .append(this.pkSchema, rhs.pkSchema)
-                .append(this.pkTable, rhs.pkTable)
-                .append(this.pkColumn, rhs.pkColumn)
-                .append(this.fkCatalog, rhs.fkCatalog)
-                .append(this.fkSchema, rhs.fkSchema)
-                .append(this.fkTable, rhs.fkTable)
-                .append(this.fkColumn, rhs.fkColumn)
-                .append(this.fkName, rhs.fkName)
-                .append(this.pkName, rhs.pkName)
-                .append(this.keySeq, rhs.keySeq)
-                .isEquals();
-    }
-
-    @Override
-    public int hashCode() {
-        return new HashCodeBuilder()
-                .append(pkCatalog)
-                .append(pkSchema)
-                .append(pkTable)
-                .append(pkColumn)
-                .append(fkCatalog)
-                .append(fkSchema)
-                .append(fkTable)
-                .append(fkColumn)
-                .append(fkName)
-                .append(pkName)
-                .append(keySeq)
-                .toHashCode();
-    }
-
-    @Override
-    public int compareTo(Object obj) {
-        if (obj == null || !obj.getClass().equals(getClass())) {
-            throw new IllegalArgumentException();
-        }
-        if (obj == this) {
-            return 0;
-        }
-
-        ExportedKey rhs = (ExportedKey) obj;
-        return new CompareToBuilder()
-                .append(pkCatalog, rhs.pkCatalog)
-                .append(pkSchema, rhs.pkSchema)
-                .append(pkTable, rhs.pkTable)
-                .append(pkName, rhs.pkName)
-                .append(fkCatalog, rhs.fkCatalog)
-                .append(fkSchema, rhs.fkSchema)
-                .append(fkTable, rhs.fkTable)
-                .append(fkName, rhs.fkName)
-                .append(keySeq, rhs.keySeq)
-                .append(pkColumn, rhs.pkColumn)
-                .append(fkColumn, rhs.fkColumn)
-                .toComparison();
-    }
-
-    @Override
-    public String toString() {
-        return getStrKey() + " # " + keySeq;
-    }
-
-    public String getStrKey() {
-        return pkCatalog + "." + pkSchema + "." + pkTable + "." + pkColumn
-                + " <- " + fkCatalog + "." + fkSchema + "." + fkTable + "." + fkColumn;
-    }
-}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/8c273022/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/db/LoggingDbLoaderDelegate.java
----------------------------------------------------------------------
diff --git a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/db/LoggingDbLoaderDelegate.java b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/db/LoggingDbLoaderDelegate.java
deleted file mode 100644
index 2632626..0000000
--- a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/db/LoggingDbLoaderDelegate.java
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * 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.reverse.db;
-
-import org.apache.cayenne.map.DbEntity;
-import org.apache.cayenne.map.DbRelationship;
-import org.apache.commons.logging.Log;
-
-/**
- * @since 4.0
- */
-public class LoggingDbLoaderDelegate extends DefaultDbLoaderDelegate {
-
-    private final Log logger;
-
-    public LoggingDbLoaderDelegate(Log logger) {
-        this.logger = logger;
-    }
-
-    @Override
-    public void dbEntityAdded(DbEntity entity) {
-        logger.info("  Table: " + entity.getFullyQualifiedName());
-    }
-
-    @Override
-    public void dbEntityRemoved(DbEntity entity) {
-        logger.info("  Table removed: " + entity.getFullyQualifiedName());
-    }
-
-    @Override
-    public boolean dbRelationship(DbEntity entity) {
-        if (logger.isDebugEnabled()) {
-            logger.debug("    Relationships for " + entity.getFullyQualifiedName());
-        }
-
-        return true;
-    }
-
-    @Override
-    public boolean dbRelationshipLoaded(DbEntity entity, DbRelationship relationship) {
-        logger.info("    " + relationship);
-
-        return true;
-    }
-}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/8c273022/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbload/AbstractLoader.java
----------------------------------------------------------------------
diff --git a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbload/AbstractLoader.java b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbload/AbstractLoader.java
new file mode 100644
index 0000000..9c0cee4
--- /dev/null
+++ b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbload/AbstractLoader.java
@@ -0,0 +1,43 @@
+/*****************************************************************
+ *   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.reverse.dbload;
+
+import java.sql.DatabaseMetaData;
+import java.sql.SQLException;
+import java.util.Objects;
+
+import org.apache.cayenne.dba.DbAdapter;
+
+public abstract class AbstractLoader {
+
+    static final String WILDCARD = "%";
+
+    protected DbAdapter adapter;
+    protected DbLoaderConfiguration config;
+    protected DbLoaderDelegate delegate;
+
+    AbstractLoader(DbAdapter adapter, DbLoaderConfiguration config, DbLoaderDelegate delegate) {
+        this.adapter = adapter;
+        this.config = Objects.requireNonNull(config);
+        this.delegate = Objects.requireNonNull(delegate);
+    }
+
+    public abstract void load(DatabaseMetaData metaData, DbLoadDataStore map) throws SQLException;
+}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/8c273022/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbload/AttributeLoader.java
----------------------------------------------------------------------
diff --git a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbload/AttributeLoader.java b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbload/AttributeLoader.java
new file mode 100644
index 0000000..25f64d2
--- /dev/null
+++ b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbload/AttributeLoader.java
@@ -0,0 +1,137 @@
+/*****************************************************************
+ *   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.reverse.dbload;
+
+import java.sql.DatabaseMetaData;
+import java.sql.ResultSet;
+import java.sql.ResultSetMetaData;
+import java.sql.SQLException;
+
+import org.apache.cayenne.dba.DbAdapter;
+import org.apache.cayenne.dba.TypesMapping;
+import org.apache.cayenne.dbsync.reverse.filters.CatalogFilter;
+import org.apache.cayenne.dbsync.reverse.filters.PatternFilter;
+import org.apache.cayenne.dbsync.reverse.filters.SchemaFilter;
+import org.apache.cayenne.map.DbAttribute;
+import org.apache.cayenne.map.DbEntity;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+class AttributeLoader extends PerCatalogAndSchemaLoader {
+
+    private static final Log LOGGER = LogFactory.getLog(AttributeLoader.class);
+
+    private boolean firstRow;
+    private boolean supportAutoIncrement;
+
+    AttributeLoader(DbAdapter adapter, DbLoaderConfiguration config, DbLoaderDelegate delegate) {
+        super(adapter, config, delegate);
+        firstRow = true;
+        supportAutoIncrement = false;
+    }
+
+    protected ResultSet getResultSet(String catalogName, String schemaName, DatabaseMetaData metaData) throws SQLException {
+        return metaData.getColumns(catalogName, schemaName, WILDCARD, WILDCARD);
+    }
+
+    @Override
+    protected void processResultSet(CatalogFilter catalog, SchemaFilter schema, DbLoadDataStore map, ResultSet rs) throws SQLException {
+        if (firstRow) {
+            supportAutoIncrement = checkForAutoIncrement(rs);
+            firstRow = false;
+        }
+
+        // for a reason not quiet apparent to me, Oracle sometimes
+        // returns duplicate record sets for the same table, messing up
+        // table names. E.g. for the system table "WK$_ATTR_MAPPING" columns
+        // are returned twice - as "WK$_ATTR_MAPPING" and "WK$$_ATTR_MAPPING"...
+        // Go figure
+        String tableName = rs.getString("TABLE_NAME");
+        DbEntity entity = map.getDbEntity(tableName);
+        if(entity == null) {
+            return;
+        }
+
+        // Filter out columns by name
+        String columnName = rs.getString("COLUMN_NAME");
+        PatternFilter columnFilter = schema.tables.getIncludeTableColumnFilter(tableName);
+        if (columnFilter == null || !columnFilter.isIncluded(columnName)) {
+            if (LOGGER.isDebugEnabled()) {
+                LOGGER.debug("Skip column '" + tableName + "." + columnName +
+                        "' (Path: " + catalog.name + "/" + schema.name + "; Filter: " + columnFilter + ")");
+            }
+            return;
+        }
+
+        DbAttribute attribute = createDbAttribute(rs);
+        addToDbEntity(entity, attribute);
+    }
+
+    private boolean checkForAutoIncrement(ResultSet rs) throws SQLException {
+        ResultSetMetaData rsMetaData = rs.getMetaData();
+        for (int i = 1; i <= rsMetaData.getColumnCount(); i++) {
+            if("IS_AUTOINCREMENT".equals(rsMetaData.getColumnLabel(i))) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private void addToDbEntity(DbEntity entity, DbAttribute attribute) {
+        attribute.setEntity(entity);
+
+        // override existing attributes if it comes again
+        if (entity.getAttribute(attribute.getName()) != null) {
+            entity.removeAttribute(attribute.getName());
+        }
+        entity.addAttribute(attribute);
+    }
+
+    private DbAttribute createDbAttribute(ResultSet rs) throws SQLException {
+
+        // gets attribute's (column's) information
+        int columnType = rs.getInt("DATA_TYPE");
+
+        // ignore precision of non-decimal columns
+        int decimalDigits = -1;
+        if (TypesMapping.isDecimal(columnType)) {
+            decimalDigits = rs.getInt("DECIMAL_DIGITS");
+            if (rs.wasNull()) {
+                decimalDigits = -1;
+            }
+        }
+
+        // create attribute delegating this task to adapter
+        DbAttribute attr = adapter.buildAttribute(
+                rs.getString("COLUMN_NAME"),
+                rs.getString("TYPE_NAME"),
+                columnType,
+                rs.getInt("COLUMN_SIZE"),
+                decimalDigits,
+                rs.getBoolean("NULLABLE"));
+
+        if (supportAutoIncrement) {
+            if ("YES".equals(rs.getString("IS_AUTOINCREMENT"))) {
+                attr.setGenerated(true);
+            }
+        }
+        return attr;
+    }
+}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/8c273022/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbload/DbLoadDataStore.java
----------------------------------------------------------------------
diff --git a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbload/DbLoadDataStore.java b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbload/DbLoadDataStore.java
new file mode 100644
index 0000000..c0e79a8
--- /dev/null
+++ b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbload/DbLoadDataStore.java
@@ -0,0 +1,88 @@
+/*****************************************************************
+ *   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.reverse.dbload;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeSet;
+
+import org.apache.cayenne.map.DataMap;
+import org.apache.cayenne.map.DbEntity;
+import org.apache.cayenne.map.DetectedDbEntity;
+import org.apache.cayenne.map.Procedure;
+
+/**
+ * Temporary storage for loaded from DB DbEntities and Procedures.
+ * DataMap is used but it's functionality is excessive and
+ * there can be unwanted side effects.
+ * To get rid of it parallel data structure for dbEntity, attributes,
+ * procedures etc.. must be created
+ */
+public class DbLoadDataStore extends DataMap {
+
+    private Map<String, Set<ExportedKey>> exportedKeys = new HashMap<>();
+
+    DbLoadDataStore() {
+        super("__generated_by_dbloader__");
+    }
+
+    @Override
+    public void addDbEntity(DbEntity entity) {
+        if(!(entity instanceof DetectedDbEntity)) {
+            throw new IllegalArgumentException("Only DetectedDbEntity can be inserted in this map");
+        }
+        super.addDbEntity(entity);
+    }
+
+    DbEntity addDbEntitySafe(DbEntity entity) {
+        if(!(entity instanceof DetectedDbEntity)) {
+            throw new IllegalArgumentException("Only DetectedDbEntity can be inserted in this map");
+        }
+        DbEntity old = getDbEntity(entity.getName());
+        if(old != null) {
+            removeDbEntity(old.getName());
+        }
+        addDbEntity(entity);
+        return old;
+    }
+
+    void addProcedureSafe(Procedure procedure) {
+        Procedure old = getProcedure(procedure.getName());
+        if(old != null) {
+            removeProcedure(old.getName());
+        }
+        addProcedure(procedure);
+    }
+
+    void addExportedKey(ExportedKey key) {
+        Set<ExportedKey> exportedKeys = this.exportedKeys.get(key.getStrKey());
+        if (exportedKeys == null) {
+            exportedKeys = new TreeSet<>();
+            this.exportedKeys.put(key.getStrKey(), exportedKeys);
+        }
+        exportedKeys.add(key);
+    }
+
+    Set<Map.Entry<String, Set<ExportedKey>>> getExportedKeysEntrySet() {
+        return exportedKeys.entrySet();
+    }
+}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/8c273022/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbload/DbLoader.java
----------------------------------------------------------------------
diff --git a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbload/DbLoader.java b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbload/DbLoader.java
new file mode 100644
index 0000000..5c1cfde
--- /dev/null
+++ b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbload/DbLoader.java
@@ -0,0 +1,118 @@
+/*
+ * 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.reverse.dbload;
+
+import java.sql.Connection;
+import java.sql.DatabaseMetaData;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+
+import org.apache.cayenne.dba.DbAdapter;
+import org.apache.cayenne.dbsync.naming.ObjectNameGenerator;
+import org.apache.cayenne.map.DataMap;
+
+/**
+ * Loader for data from DB.
+ * Creates DbEntities and Procedures based on DB meta data.
+ * Consists of list of loaders that iteratively loads small parts of data,
+ * e.g. Entity name, Attributes, Relationships...
+ * @see AbstractLoader and its children
+ */
+public class DbLoader {
+
+    private List<AbstractLoader> loaders = new ArrayList<>();
+
+    private final Connection connection;
+    private final DbAdapter adapter;
+    private final DbLoaderConfiguration config;
+    private final DbLoaderDelegate delegate;
+    private final ObjectNameGenerator nameGenerator;
+
+    public DbLoader(DbAdapter adapter, Connection connection, DbLoaderConfiguration config,
+                    DbLoaderDelegate delegate, ObjectNameGenerator nameGenerator) {
+        this.adapter = Objects.requireNonNull(adapter);
+        this.connection = Objects.requireNonNull(connection);
+        this.config = Objects.requireNonNull(config);
+        this.nameGenerator = Objects.requireNonNull(nameGenerator);
+        this.delegate = delegate == null ? new DefaultDbLoaderDelegate() : delegate;
+
+        createLoaders();
+    }
+
+    /**
+     * Order of loaders is important, as loader can rely on data previously loaded
+     */
+    private void createLoaders() {
+        loaders.add(new EntityLoader(adapter, config, delegate));
+        loaders.add(new AttributeLoader(adapter, config, delegate));
+        loaders.add(new PrimaryKeyLoader(config, delegate));
+        loaders.add(new ExportedKeyLoader(config, delegate));
+        loaders.add(new RelationshipLoader(config, delegate, nameGenerator));
+        loaders.add(new ProcedureLoader(adapter, config, delegate));
+        loaders.add(new ProcedureColumnLoader(adapter, config, delegate));
+    }
+
+    /**
+     * @return new DataMap with data loaded from DB
+     */
+    public DataMap load() throws SQLException {
+        DbLoadDataStore loadedData = new DbLoadDataStore();
+        DatabaseMetaData metaData = connection.getMetaData();
+
+        for(AbstractLoader loader : loaders) {
+            loader.load(metaData, loadedData);
+        }
+        return loadedData;
+    }
+
+    //// Utility methods that better be moved somewhere ////
+
+    /**
+     * Retrieves catalogs for a given connection.
+     * using a static method for catalog loading as we don't need a full DbLoader2 for this operation
+     * @return List with the catalog names; empty list if none found.
+     */
+    public static List<String> loadCatalogs(Connection connection) throws SQLException {
+        try (ResultSet rs = connection.getMetaData().getCatalogs()) {
+            return getStrings(rs);
+        }
+    }
+
+    /**
+     * Retrieves the schemas for the given connection.
+     * using a static method for catalog loading as we don't need a full DbLoader2 for this operation
+     * @return List with the schema names; empty list if none found.
+     */
+    public static List<String> loadSchemas(Connection connection) throws SQLException {
+        try (ResultSet rs = connection.getMetaData().getSchemas()) {
+            return getStrings(rs);
+        }
+    }
+
+    private static List<String> getStrings(ResultSet rs) throws SQLException {
+        List<String> strings = new ArrayList<>();
+        while (rs.next()) {
+            strings.add(rs.getString(1));
+        }
+        return strings;
+    }
+}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/8c273022/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbload/DbLoaderConfiguration.java
----------------------------------------------------------------------
diff --git a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbload/DbLoaderConfiguration.java b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbload/DbLoaderConfiguration.java
new file mode 100644
index 0000000..e37ae60
--- /dev/null
+++ b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbload/DbLoaderConfiguration.java
@@ -0,0 +1,85 @@
+/*****************************************************************
+ *   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.reverse.dbload;
+
+import org.apache.cayenne.dbsync.reverse.filters.TableFilter;
+import org.apache.cayenne.dbsync.reverse.filters.FiltersConfig;
+import org.apache.cayenne.dbsync.reverse.filters.PatternFilter;
+
+/**
+ * @since 4.0
+ */
+public class DbLoaderConfiguration {
+
+    private Boolean skipRelationshipsLoading;
+    private Boolean skipPrimaryKeyLoading;
+    private String[] tableTypes;
+    private FiltersConfig filtersConfig;
+
+    public String[] getTableTypes() {
+        return tableTypes;
+    }
+
+    public void setTableTypes(String[] tableTypes) {
+        this.tableTypes = tableTypes;
+    }
+
+    public FiltersConfig getFiltersConfig() {
+        if (filtersConfig == null) {
+            // this case is used often in tests where config not initialized properly
+            return FiltersConfig.create(null, null, TableFilter.everything(), PatternFilter.INCLUDE_NOTHING);
+        }
+        return filtersConfig;
+    }
+
+    public void setFiltersConfig(FiltersConfig filtersConfig) {
+        this.filtersConfig = filtersConfig;
+    }
+
+    public boolean isSkipRelationshipsLoading() {
+        return skipRelationshipsLoading != null && skipRelationshipsLoading;
+    }
+
+    public void setSkipRelationshipsLoading(Boolean skipRelationshipsLoading) {
+        this.skipRelationshipsLoading = skipRelationshipsLoading;
+    }
+
+    public boolean isSkipPrimaryKeyLoading() {
+        return skipPrimaryKeyLoading != null && skipPrimaryKeyLoading;
+    }
+
+    public void setSkipPrimaryKeyLoading(Boolean skipPrimaryKeyLoading) {
+        this.skipPrimaryKeyLoading = skipPrimaryKeyLoading;
+    }
+
+    @Override
+    public String toString() {
+        String res = "EntitiesFilters: " + getFiltersConfig();
+        if (isSkipRelationshipsLoading()) {
+            res += "\n Skip Loading Relationships! \n";
+        }
+
+        if (isSkipPrimaryKeyLoading()) {
+            res += "\n Skip Loading PrimaryKeys! \n";
+        }
+
+        return res;
+    }
+}


[2/9] cayenne git commit: New DbLoader for dbsync utils - loading process split in independent small steps - DbLoader always return new DataMap, it doesn't accept it from outside

Posted by aa...@apache.org.
http://git-wip-us.apache.org/repos/asf/cayenne/blob/8c273022/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbload/DbLoaderDelegate.java
----------------------------------------------------------------------
diff --git a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbload/DbLoaderDelegate.java b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbload/DbLoaderDelegate.java
new file mode 100644
index 0000000..ae694eb
--- /dev/null
+++ b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbload/DbLoaderDelegate.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.reverse.dbload;
+
+import org.apache.cayenne.map.DbEntity;
+import org.apache.cayenne.map.DbRelationship;
+import org.apache.cayenne.map.ObjEntity;
+
+/**
+ * Defines API for progress tracking and altering the folow of reverse-engineering.
+ */
+public interface DbLoaderDelegate {
+
+    void dbEntityAdded(DbEntity entity);
+
+    void dbEntityRemoved(DbEntity entity);
+
+    /**
+     * Called before relationship loading for a {@link DbEntity}.
+     *
+     * @param entity DbEntity for which {@link DbRelationship} is about to be loaded.
+     * @return true in case you want process relationships for this entity, false otherwise.
+     */
+    boolean dbRelationship(DbEntity entity);
+
+    /**
+     * Called before relationship will be added into db-entity but after it was loaded from db
+     *
+     * @param entity
+     * @return true in case you want add this relationship into entity
+     * false otherwise
+     */
+    boolean dbRelationshipLoaded(DbEntity entity, DbRelationship relationship);
+
+    /**
+     * @deprecated since 4.0 no longer invoked as DbLoader2 does not deal with object layer anymore.
+     */
+    @Deprecated
+    void objEntityAdded(ObjEntity entity);
+
+    /**
+     * @deprecated since 4.0 no longer invoked as DbLoader2 does not deal with object layer anymore.
+     */
+    @Deprecated
+    void objEntityRemoved(ObjEntity entity);
+}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/8c273022/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbload/DbRelationshipDetected.java
----------------------------------------------------------------------
diff --git a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbload/DbRelationshipDetected.java b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbload/DbRelationshipDetected.java
new file mode 100644
index 0000000..5a8b8cd
--- /dev/null
+++ b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbload/DbRelationshipDetected.java
@@ -0,0 +1,54 @@
+/*****************************************************************
+ *   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.reverse.dbload;
+
+
+import org.apache.cayenne.map.DbRelationship;
+
+/**
+ * A subclass of {@link DbRelationship} to hold some extra runtime information.
+ */
+// TODO: dirty ... can we lookup fkName via joins?
+public class DbRelationshipDetected extends DbRelationship {
+
+    private String fkName;
+
+    public DbRelationshipDetected(String uniqueRelName) {
+        super(uniqueRelName);
+    }
+
+    public DbRelationshipDetected() {
+    }
+
+    /**
+     * Get the name of the underlying foreign key. Typically FK_NAME from jdbc metadata.
+     */
+    public String getFkName() {
+        return fkName;
+    }
+
+    /**
+     * Set the name of the underlying foreign key. Typically FK_NAME from jdbc metadata.
+     */
+    public void setFkName(String fkName) {
+        this.fkName = fkName;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/8c273022/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbload/DefaultDbLoaderDelegate.java
----------------------------------------------------------------------
diff --git a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbload/DefaultDbLoaderDelegate.java b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbload/DefaultDbLoaderDelegate.java
new file mode 100644
index 0000000..607bd2c
--- /dev/null
+++ b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbload/DefaultDbLoaderDelegate.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.reverse.dbload;
+
+import org.apache.cayenne.dbsync.reverse.dbload.DbLoaderDelegate;
+import org.apache.cayenne.map.DbEntity;
+import org.apache.cayenne.map.DbRelationship;
+import org.apache.cayenne.map.ObjEntity;
+
+/**
+ * A noop {@link DbLoaderDelegate}.
+ *
+ * @since 4.0
+ */
+public class DefaultDbLoaderDelegate implements DbLoaderDelegate {
+
+    @Override
+    public void dbEntityAdded(DbEntity entity) {
+
+    }
+
+    @Override
+    public void dbEntityRemoved(DbEntity entity) {
+
+    }
+
+    @Override
+    public boolean dbRelationship(DbEntity entity) {
+        return true;
+    }
+
+    @Override
+    public boolean dbRelationshipLoaded(DbEntity entity, DbRelationship relationship) {
+        return true;
+    }
+
+    @Deprecated
+    @Override
+    public void objEntityAdded(ObjEntity entity) {
+
+    }
+
+    @Deprecated
+    @Override
+    public void objEntityRemoved(ObjEntity entity) {
+
+    }
+}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/8c273022/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbload/EntityLoader.java
----------------------------------------------------------------------
diff --git a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbload/EntityLoader.java b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbload/EntityLoader.java
new file mode 100644
index 0000000..bbccc15
--- /dev/null
+++ b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbload/EntityLoader.java
@@ -0,0 +1,106 @@
+/*****************************************************************
+ *   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.reverse.dbload;
+
+import java.sql.DatabaseMetaData;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.cayenne.dba.DbAdapter;
+import org.apache.cayenne.dbsync.reverse.filters.CatalogFilter;
+import org.apache.cayenne.dbsync.reverse.filters.SchemaFilter;
+import org.apache.cayenne.map.DbEntity;
+import org.apache.cayenne.map.DetectedDbEntity;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+class EntityLoader extends PerCatalogAndSchemaLoader {
+
+    private static final Log LOGGER = LogFactory.getLog(EntityLoader.class);
+
+    private final String[] types;
+
+    EntityLoader(DbAdapter adapter, DbLoaderConfiguration config, DbLoaderDelegate delegate) {
+        super(adapter, config, delegate);
+        types = getTableTypes();
+    }
+
+    @Override
+    protected ResultSet getResultSet(String catalogName, String schemaName, DatabaseMetaData metaData) throws SQLException {
+        return metaData.getTables(catalogName, schemaName, WILDCARD, types);
+    }
+
+    @Override
+    protected void processResultSet(CatalogFilter catalog, SchemaFilter schema, DbLoadDataStore map, ResultSet rs) throws SQLException {
+        String name = rs.getString("TABLE_NAME");
+        String catalogName = rs.getString("TABLE_CAT");
+        String schemaName = rs.getString("TABLE_SCHEM");
+
+        // Oracle 9i and newer has a nifty recycle bin feature...
+        // but we don't want dropped tables to be included here;
+        // in fact they may even result in errors on reverse engineering
+        // as their names have special chars like "/", etc.
+        // So skip them all together (it's about "name == null" check)
+        if (name == null || !schema.tables.isIncludeTable(name)) {
+            return;
+        }
+
+        if (!(catalog.name == null || catalog.name.equals(catalogName))
+                || !(schema.name == null || schema.name.equals(schemaName))) {
+            LOGGER.error(catalogName + "." + schema + "." + schemaName + " wrongly loaded for catalog/schema : "
+                    + catalog.name + "." + schema.name);
+            return;
+        }
+
+        DetectedDbEntity table = new DetectedDbEntity(name);
+        table.setCatalog(catalogName);
+        table.setSchema(schemaName);
+        addDbEntityToMap(table, map);
+    }
+
+    private void addDbEntityToMap(DetectedDbEntity table, DbLoadDataStore map) {
+        DbEntity oldEnt = map.addDbEntitySafe(table);
+        if (oldEnt != null) {
+            LOGGER.debug("Overwrite DbEntity: " + oldEnt.getName());
+            delegate.dbEntityRemoved(oldEnt);
+        }
+        delegate.dbEntityAdded(table);
+    }
+
+    private String[] getTableTypes() {
+        String[] configTypes = config.getTableTypes();
+        if (configTypes != null && configTypes.length > 0) {
+            return configTypes;
+        }
+
+        List<String> list = new ArrayList<>(2);
+        String viewType = adapter.tableTypeForView();
+        if (viewType != null) {
+            list.add(viewType);
+        }
+        String tableType = adapter.tableTypeForTable();
+        if (tableType != null) {
+            list.add(tableType);
+        }
+        return list.toArray(new String[0]);
+    }
+}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/8c273022/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbload/ExportedKey.java
----------------------------------------------------------------------
diff --git a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbload/ExportedKey.java b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbload/ExportedKey.java
new file mode 100644
index 0000000..a288fe8
--- /dev/null
+++ b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbload/ExportedKey.java
@@ -0,0 +1,220 @@
+/*****************************************************************
+ *   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.reverse.dbload;
+
+import org.apache.cayenne.util.EqualsBuilder;
+import org.apache.cayenne.util.HashCodeBuilder;
+import org.apache.commons.lang.builder.CompareToBuilder;
+
+import java.sql.ResultSet;
+import java.sql.SQLException;
+
+/**
+ * A representation of relationship between two tables in database. It can be used for creating names
+ * for relationships.
+ *
+ * @since 4.0
+ */
+public class ExportedKey implements Comparable {
+
+    private final KeyData pk;
+    private final KeyData fk;
+    private final short keySeq;
+
+    /**
+     * Extracts data from a resultset pointing to a exported key to
+     * ExportedKey class instance
+     *
+     * @param rs ResultSet pointing to a exported key, fetched using
+     *           DataBaseMetaData.getExportedKeys(...)
+     */
+    public ExportedKey(ResultSet rs) throws SQLException {
+        String pkCatalog = rs.getString("PKTABLE_CAT");
+        String pkSchema = rs.getString("PKTABLE_SCHEM");
+        String pkTable = rs.getString("PKTABLE_NAME");
+        String pkColumn = rs.getString("PKCOLUMN_NAME");
+        String pkName = rs.getString("PK_NAME");
+        pk = new KeyData(pkCatalog, pkSchema, pkTable, pkColumn, pkName);
+
+        String fkCatalog = rs.getString("FKTABLE_CAT");
+        String fkSchema = rs.getString("FKTABLE_SCHEM");
+        String fkTable = rs.getString("FKTABLE_NAME");
+        String fkColumn = rs.getString("FKCOLUMN_NAME");
+        String fkName = rs.getString("FK_NAME");
+        fk = new KeyData(fkCatalog, fkSchema, fkTable, fkColumn, fkName);
+
+        this.keySeq = rs.getShort("KEY_SEQ");
+    }
+
+    public KeyData getPk() {
+        return pk;
+    }
+
+    public KeyData getFk() {
+        return fk;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (obj == null) {
+            return false;
+        }
+        if (obj == this) {
+            return true;
+        }
+        if (obj.getClass() != getClass()) {
+            return false;
+        }
+        ExportedKey rhs = (ExportedKey) obj;
+        return new EqualsBuilder()
+                .append(this.pk, rhs.pk)
+                .append(this.fk, rhs.fk)
+                .append(this.keySeq, rhs.keySeq)
+                .isEquals();
+    }
+
+    @Override
+    public int hashCode() {
+        return new HashCodeBuilder()
+                .append(pk)
+                .append(fk)
+                .append(keySeq)
+                .toHashCode();
+    }
+
+    @Override
+    public int compareTo(Object obj) {
+        if (obj == null || !obj.getClass().equals(getClass())) {
+            throw new IllegalArgumentException();
+        }
+        if (obj == this) {
+            return 0;
+        }
+
+        ExportedKey rhs = (ExportedKey) obj;
+        return new CompareToBuilder()
+                .append(pk, rhs.pk)
+                .append(fk, rhs.fk)
+                .append(keySeq, rhs.keySeq)
+                .toComparison();
+    }
+
+    @Override
+    public String toString() {
+        return getStrKey() + " # " + keySeq;
+    }
+
+    public String getStrKey() {
+        return pk + " <- " + fk;
+    }
+
+    public static class KeyData implements Comparable {
+        private final String catalog;
+        private final String schema;
+        private final String table;
+        private final String column;
+        private final String name;
+
+        private KeyData(String catalog, String schema, String table, String column, String name) {
+            this.catalog = catalog;
+            this.schema = schema;
+            this.table = table;
+            this.column = column;
+            this.name = name;
+        }
+
+        public String getCatalog() {
+            return catalog;
+        }
+
+        public String getSchema() {
+            return schema;
+        }
+
+        public String getTable() {
+            return table;
+        }
+
+        public String getColumn() {
+            return column;
+        }
+
+        public String getName() {
+            return name;
+        }
+
+        @Override
+        public String toString() {
+            return catalog + "." + schema + "." + table + "." + column;
+        }
+
+        @Override
+        public int compareTo(Object obj) {
+            if (obj == null || !obj.getClass().equals(getClass())) {
+                throw new IllegalArgumentException();
+            }
+            if (obj == this) {
+                return 0;
+            }
+
+            KeyData rhs = (KeyData) obj;
+            return new CompareToBuilder()
+                    .append(catalog, rhs.catalog)
+                    .append(schema, rhs.schema)
+                    .append(table, rhs.table)
+                    .append(column, rhs.column)
+                    .append(name, rhs.name)
+                    .toComparison();
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (obj == null) {
+                return false;
+            }
+            if (obj == this) {
+                return true;
+            }
+            if (obj.getClass() != getClass()) {
+                return false;
+            }
+            KeyData rhs = (KeyData) obj;
+            return new EqualsBuilder()
+                    .append(this.catalog, rhs.catalog)
+                    .append(this.schema, rhs.schema)
+                    .append(this.table, rhs.table)
+                    .append(this.column, rhs.column)
+                    .append(this.name, rhs.name)
+                    .isEquals();
+        }
+
+        @Override
+        public int hashCode() {
+            return new HashCodeBuilder()
+                    .append(catalog)
+                    .append(schema)
+                    .append(table)
+                    .append(column)
+                    .append(name)
+                    .toHashCode();
+        }
+
+    }
+}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/8c273022/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbload/ExportedKeyLoader.java
----------------------------------------------------------------------
diff --git a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbload/ExportedKeyLoader.java b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbload/ExportedKeyLoader.java
new file mode 100644
index 0000000..779218b
--- /dev/null
+++ b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbload/ExportedKeyLoader.java
@@ -0,0 +1,74 @@
+/*****************************************************************
+ *   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.reverse.dbload;
+
+import java.sql.DatabaseMetaData;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+
+import org.apache.cayenne.map.DbEntity;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+class ExportedKeyLoader extends PerEntityLoader {
+
+    private static final Log LOGGER = LogFactory.getLog(ExportedKeyLoader.class);
+
+    ExportedKeyLoader(DbLoaderConfiguration config, DbLoaderDelegate delegate) {
+        super(null, config, delegate);
+    }
+
+    @Override
+    boolean shouldLoad(DbEntity entity) {
+        return delegate.dbRelationship(entity);
+    }
+
+    @Override
+    boolean catchException(DbEntity entity, SQLException ex) {
+        LOGGER.info("Error getting relationships for '"
+                + entity.getCatalog() + "." + entity.getSchema()
+                + "', ignoring. " + ex.getMessage(), ex);
+        return true;
+    }
+
+    @Override
+    ResultSet getResultSet(DbEntity dbEntity, DatabaseMetaData metaData) throws SQLException {
+        return metaData.getExportedKeys(dbEntity.getCatalog(), dbEntity.getSchema(), dbEntity.getName());
+    }
+
+    @Override
+    void processResultSet(DbEntity dbEntity, DbLoadDataStore map, ResultSet rs) throws SQLException {
+        ExportedKey key = new ExportedKey(rs);
+
+        DbEntity pkEntity = map.getDbEntity(key.getPk().getTable());
+        if (pkEntity == null) {
+            LOGGER.info("Skip relation: '" + key + "' because table '" + key.getPk().getTable() + "' not found");
+            return;
+        }
+
+        DbEntity fkEntity = map.getDbEntity(key.getFk().getTable());
+        if (fkEntity == null) {
+            LOGGER.info("Skip relation: '" + key + "' because table '" + key.getFk().getTable() + "' not found");
+            return;
+        }
+
+        map.addExportedKey(key);
+    }
+}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/8c273022/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbload/LoggingDbLoaderDelegate.java
----------------------------------------------------------------------
diff --git a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbload/LoggingDbLoaderDelegate.java b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbload/LoggingDbLoaderDelegate.java
new file mode 100644
index 0000000..58635f7
--- /dev/null
+++ b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbload/LoggingDbLoaderDelegate.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.reverse.dbload;
+
+import org.apache.cayenne.dbsync.reverse.dbload.DefaultDbLoaderDelegate;
+import org.apache.cayenne.map.DbEntity;
+import org.apache.cayenne.map.DbRelationship;
+import org.apache.commons.logging.Log;
+
+/**
+ * @since 4.0
+ */
+public class LoggingDbLoaderDelegate extends DefaultDbLoaderDelegate {
+
+    private final Log logger;
+
+    public LoggingDbLoaderDelegate(Log logger) {
+        this.logger = logger;
+    }
+
+    @Override
+    public void dbEntityAdded(DbEntity entity) {
+        logger.info("  Table: " + entity.getFullyQualifiedName());
+    }
+
+    @Override
+    public void dbEntityRemoved(DbEntity entity) {
+        logger.info("  Table removed: " + entity.getFullyQualifiedName());
+    }
+
+    @Override
+    public boolean dbRelationship(DbEntity entity) {
+        if (logger.isDebugEnabled()) {
+            logger.debug("    Relationships for " + entity.getFullyQualifiedName());
+        }
+
+        return true;
+    }
+
+    @Override
+    public boolean dbRelationshipLoaded(DbEntity entity, DbRelationship relationship) {
+        logger.info("    " + relationship);
+
+        return true;
+    }
+}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/8c273022/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbload/PerCatalogAndSchemaLoader.java
----------------------------------------------------------------------
diff --git a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbload/PerCatalogAndSchemaLoader.java b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbload/PerCatalogAndSchemaLoader.java
new file mode 100644
index 0000000..5ec1b67
--- /dev/null
+++ b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbload/PerCatalogAndSchemaLoader.java
@@ -0,0 +1,58 @@
+/*****************************************************************
+ *   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.reverse.dbload;
+
+import java.sql.DatabaseMetaData;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+
+import org.apache.cayenne.dba.DbAdapter;
+import org.apache.cayenne.dbsync.reverse.filters.CatalogFilter;
+import org.apache.cayenne.dbsync.reverse.filters.SchemaFilter;
+
+public abstract class PerCatalogAndSchemaLoader extends AbstractLoader {
+
+    PerCatalogAndSchemaLoader(DbAdapter adapter, DbLoaderConfiguration config, DbLoaderDelegate delegate) {
+        super(adapter, config, delegate);
+    }
+
+    public void load(DatabaseMetaData metaData, DbLoadDataStore map) throws SQLException {
+        for (CatalogFilter catalog : config.getFiltersConfig().getCatalogs()) {
+            for (SchemaFilter schema : catalog.schemas) {
+                if(!shouldLoad(catalog, schema)) {
+                    continue;
+                }
+                try (ResultSet rs = getResultSet(catalog.name, schema.name, metaData)) {
+                    while (rs.next()) {
+                        processResultSet(catalog, schema, map, rs);
+                    }
+                }
+            }
+        }
+    }
+
+    boolean shouldLoad(CatalogFilter catalog, SchemaFilter schema) {
+        return true;
+    }
+
+    abstract ResultSet getResultSet(String catalogName, String schemaName, DatabaseMetaData metaData) throws SQLException;
+
+    abstract void processResultSet(CatalogFilter catalog, SchemaFilter schema, DbLoadDataStore map, ResultSet rs) throws SQLException;
+}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/8c273022/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbload/PerEntityLoader.java
----------------------------------------------------------------------
diff --git a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbload/PerEntityLoader.java b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbload/PerEntityLoader.java
new file mode 100644
index 0000000..7a479b2
--- /dev/null
+++ b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbload/PerEntityLoader.java
@@ -0,0 +1,64 @@
+/*****************************************************************
+ *   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.reverse.dbload;
+
+import java.sql.DatabaseMetaData;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+
+import org.apache.cayenne.dba.DbAdapter;
+import org.apache.cayenne.map.DbEntity;
+
+public abstract class PerEntityLoader extends AbstractLoader {
+
+    PerEntityLoader(DbAdapter adapter, DbLoaderConfiguration config, DbLoaderDelegate delegate) {
+        super(adapter, config, delegate);
+    }
+
+    @Override
+    public void load(DatabaseMetaData metaData, DbLoadDataStore map) throws SQLException {
+        for(DbEntity dbEntity : map.getDbEntities()) {
+            if(!shouldLoad(dbEntity)) {
+                continue;
+            }
+            try(ResultSet rs = getResultSet(dbEntity, metaData)) {
+                while(rs.next()) {
+                    processResultSet(dbEntity, map, rs);
+                }
+            } catch (SQLException ex) {
+                if(!catchException(dbEntity, ex)) {
+                    throw ex;
+                }
+            }
+        }
+    }
+
+    boolean shouldLoad(DbEntity entity) {
+        return true;
+    }
+
+    boolean catchException(DbEntity entity, SQLException ex) {
+        return false;
+    }
+
+    abstract ResultSet getResultSet(DbEntity dbEntity, DatabaseMetaData metaData) throws SQLException;
+
+    abstract void processResultSet(DbEntity dbEntity, DbLoadDataStore map, ResultSet rs) throws SQLException;
+}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/8c273022/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbload/PrimaryKeyLoader.java
----------------------------------------------------------------------
diff --git a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbload/PrimaryKeyLoader.java b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbload/PrimaryKeyLoader.java
new file mode 100644
index 0000000..9a1d206
--- /dev/null
+++ b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbload/PrimaryKeyLoader.java
@@ -0,0 +1,60 @@
+/*****************************************************************
+ *   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.reverse.dbload;
+
+import java.sql.DatabaseMetaData;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+
+import org.apache.cayenne.map.DbAttribute;
+import org.apache.cayenne.map.DbEntity;
+import org.apache.cayenne.map.DetectedDbEntity;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+class PrimaryKeyLoader extends PerEntityLoader {
+
+    private static final Log LOGGER = LogFactory.getLog(PrimaryKeyLoader.class);
+
+    PrimaryKeyLoader(DbLoaderConfiguration config, DbLoaderDelegate delegate) {
+        super(null, config, delegate);
+    }
+
+    @Override
+    ResultSet getResultSet(DbEntity dbEntity, DatabaseMetaData metaData) throws SQLException {
+        return metaData.getPrimaryKeys(dbEntity.getCatalog(), dbEntity.getSchema(), dbEntity.getName());
+    }
+
+    @Override
+    void processResultSet(DbEntity dbEntity, DbLoadDataStore map, ResultSet rs) throws SQLException {
+        String columnName = rs.getString("COLUMN_NAME");
+        DbAttribute attribute = dbEntity.getAttribute(columnName);
+        if (attribute == null) {
+            // why an attribute might be null is not quiet clear
+            // but there is a bug report 731406 indicating that it is
+            // possible so just print the warning, and ignore
+            LOGGER.warn("Can't locate attribute for primary key: " + columnName);
+            return;
+        }
+
+        attribute.setPrimaryKey(true);
+        ((DetectedDbEntity) dbEntity).setPrimaryKeyName(rs.getString("PK_NAME"));
+    }
+}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/8c273022/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbload/ProcedureColumnLoader.java
----------------------------------------------------------------------
diff --git a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbload/ProcedureColumnLoader.java b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbload/ProcedureColumnLoader.java
new file mode 100644
index 0000000..4ff77c0
--- /dev/null
+++ b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbload/ProcedureColumnLoader.java
@@ -0,0 +1,127 @@
+/*****************************************************************
+ *   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.reverse.dbload;
+
+import java.sql.DatabaseMetaData;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+
+import org.apache.cayenne.dba.DbAdapter;
+import org.apache.cayenne.dba.TypesMapping;
+import org.apache.cayenne.dbsync.reverse.filters.CatalogFilter;
+import org.apache.cayenne.dbsync.reverse.filters.PatternFilter;
+import org.apache.cayenne.dbsync.reverse.filters.SchemaFilter;
+import org.apache.cayenne.map.Procedure;
+import org.apache.cayenne.map.ProcedureParameter;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+public class ProcedureColumnLoader extends PerCatalogAndSchemaLoader {
+
+    private static final Log LOGGER = LogFactory.getLog(ProcedureColumnLoader.class);
+
+    ProcedureColumnLoader(DbAdapter adapter, DbLoaderConfiguration config, DbLoaderDelegate delegate) {
+        super(adapter, config, delegate);
+    }
+
+    @Override
+    protected ResultSet getResultSet(String catalogName, String schemaName, DatabaseMetaData metaData) throws SQLException {
+        return metaData.getProcedureColumns(catalogName, schemaName, WILDCARD, WILDCARD);
+    }
+
+    @Override
+    protected boolean shouldLoad(CatalogFilter catalog, SchemaFilter schema) {
+        PatternFilter filter = config.getFiltersConfig().proceduresFilter(catalog.name, schema.name);
+        return !filter.isEmpty();
+    }
+
+    @Override
+    protected void processResultSet(CatalogFilter catalog, SchemaFilter schema, DbLoadDataStore map, ResultSet rs) throws SQLException {
+        String procSchema = rs.getString("PROCEDURE_SCHEM");
+        String procCatalog = rs.getString("PROCEDURE_CAT");
+        String name = rs.getString("PROCEDURE_NAME");
+        String key = Procedure.generateFullyQualifiedName(procCatalog, procSchema, name);
+        Procedure procedure = map.getProcedure(key);
+        if (procedure == null) {
+            return;
+        }
+
+        ProcedureParameter column = loadProcedureParams(rs, key, procedure);
+        if (column == null) {
+            return;
+        }
+        procedure.addCallParameter(column);
+    }
+
+    private ProcedureParameter loadProcedureParams(ResultSet rs, String key, Procedure procedure) throws SQLException {
+        String columnName = rs.getString("COLUMN_NAME");
+
+        // skip ResultSet columns, as they are not described in Cayenne procedures yet...
+        short type = rs.getShort("COLUMN_TYPE");
+        if (type == DatabaseMetaData.procedureColumnResult) {
+            LOGGER.debug("skipping ResultSet column: " + key + "." + columnName);
+            return null;
+        }
+
+        if (columnName == null) {
+            if (type == DatabaseMetaData.procedureColumnReturn) {
+                LOGGER.debug("null column name, assuming result column: " + key);
+                columnName = "_return_value";
+                procedure.setReturningValue(true);
+            } else {
+                LOGGER.info("invalid null column name, skipping column : " + key);
+                return null;
+            }
+        }
+
+        int columnType = rs.getInt("DATA_TYPE");
+
+        // ignore precision of non-decimal columns
+        int decimalDigits = -1;
+        if (TypesMapping.isDecimal(columnType)) {
+            decimalDigits = rs.getShort("SCALE");
+            if (rs.wasNull()) {
+                decimalDigits = -1;
+            }
+        }
+
+        ProcedureParameter column = new ProcedureParameter(columnName);
+        column.setDirection(getDirection(type));
+        column.setType(columnType);
+        column.setMaxLength(rs.getInt("LENGTH"));
+        column.setPrecision(decimalDigits);
+        column.setProcedure(procedure);
+
+        return column;
+    }
+
+    private int getDirection(short type) {
+        switch (type) {
+            case DatabaseMetaData.procedureColumnIn:
+                return ProcedureParameter.IN_PARAMETER;
+            case DatabaseMetaData.procedureColumnInOut:
+                return ProcedureParameter.IN_OUT_PARAMETER;
+            case DatabaseMetaData.procedureColumnOut:
+                return ProcedureParameter.OUT_PARAMETER;
+            default:
+                return -1;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/8c273022/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbload/ProcedureLoader.java
----------------------------------------------------------------------
diff --git a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbload/ProcedureLoader.java b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbload/ProcedureLoader.java
new file mode 100644
index 0000000..633f033
--- /dev/null
+++ b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbload/ProcedureLoader.java
@@ -0,0 +1,77 @@
+/*****************************************************************
+ *   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.reverse.dbload;
+
+import java.sql.DatabaseMetaData;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+
+import org.apache.cayenne.dba.DbAdapter;
+import org.apache.cayenne.dbsync.reverse.filters.CatalogFilter;
+import org.apache.cayenne.dbsync.reverse.filters.PatternFilter;
+import org.apache.cayenne.dbsync.reverse.filters.SchemaFilter;
+import org.apache.cayenne.map.Procedure;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+public class ProcedureLoader extends PerCatalogAndSchemaLoader {
+
+    private static final Log LOGGER = LogFactory.getLog(ProcedureLoader.class);
+
+    ProcedureLoader(DbAdapter adapter, DbLoaderConfiguration config, DbLoaderDelegate delegate) {
+        super(adapter, config, delegate);
+    }
+
+    @Override
+    protected ResultSet getResultSet(String catalogName, String schemaName, DatabaseMetaData metaData) throws SQLException {
+        return metaData.getProcedures(catalogName, schemaName, WILDCARD);
+    }
+
+    @Override
+    protected boolean shouldLoad(CatalogFilter catalog, SchemaFilter schema) {
+        PatternFilter filter = config.getFiltersConfig().proceduresFilter(catalog.name, schema.name);
+        return !filter.isEmpty();
+    }
+
+    @Override
+    protected void processResultSet(CatalogFilter catalog, SchemaFilter schema, DbLoadDataStore map, ResultSet rs) throws SQLException {
+        PatternFilter filter = config.getFiltersConfig().proceduresFilter(catalog.name, schema.name);
+        String name = rs.getString("PROCEDURE_NAME");
+        if (!filter.isIncluded(name)) {
+            LOGGER.info("skipping Cayenne PK procedure: " + name);
+            return;
+        }
+
+        Procedure procedure = new Procedure(name);
+        procedure.setCatalog(rs.getString("PROCEDURE_CAT"));
+        procedure.setSchema(rs.getString("PROCEDURE_SCHEM"));
+
+        switch (rs.getShort("PROCEDURE_TYPE")) {
+            case DatabaseMetaData.procedureNoResult:
+            case DatabaseMetaData.procedureResultUnknown:
+                procedure.setReturningValue(false);
+                break;
+            case DatabaseMetaData.procedureReturnsResult:
+                procedure.setReturningValue(true);
+                break;
+        }
+        map.addProcedureSafe(procedure);
+    }
+}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/8c273022/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbload/RelationshipLoader.java
----------------------------------------------------------------------
diff --git a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbload/RelationshipLoader.java b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbload/RelationshipLoader.java
new file mode 100644
index 0000000..91a48f4
--- /dev/null
+++ b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbload/RelationshipLoader.java
@@ -0,0 +1,168 @@
+/*****************************************************************
+ *   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.reverse.dbload;
+
+import java.sql.DatabaseMetaData;
+import java.sql.SQLException;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.cayenne.dbsync.naming.NameBuilder;
+import org.apache.cayenne.dbsync.naming.ObjectNameGenerator;
+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.util.EqualsBuilder;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+public class RelationshipLoader extends AbstractLoader {
+
+    private static final Log LOGGER = LogFactory.getLog(RelationshipLoader.class);
+
+    private final ObjectNameGenerator nameGenerator;
+
+    RelationshipLoader(DbLoaderConfiguration config, DbLoaderDelegate delegate, ObjectNameGenerator nameGenerator) {
+        super(null, config, delegate);
+        this.nameGenerator = nameGenerator;
+    }
+
+    @Override
+    public void load(DatabaseMetaData metaData, DbLoadDataStore map) throws SQLException {
+        if (config.isSkipRelationshipsLoading()) {
+            return;
+        }
+
+        for (Map.Entry<String, Set<ExportedKey>> entry : map.getExportedKeysEntrySet()) {
+            if (LOGGER.isDebugEnabled()) {
+                LOGGER.debug("Process keys for: " + entry.getKey());
+            }
+
+            Set<ExportedKey> exportedKeys = entry.getValue();
+            ExportedKey key = exportedKeys.iterator().next();
+            if (key == null) {
+                throw new IllegalStateException();
+            }
+
+            ExportedKey.KeyData PK = key.getPk();
+            ExportedKey.KeyData FK = key.getFk();
+            DbEntity pkEntity = map.getDbEntity(PK.getTable());
+            DbEntity fkEntity = map.getDbEntity(FK.getTable());
+            if(pkEntity == null || fkEntity == null) {
+                // Check for existence of this entities were made in creation of ExportedKey
+                throw new IllegalStateException();
+            }
+
+            if (!new EqualsBuilder()
+                    .append(pkEntity.getCatalog(), PK.getCatalog())
+                    .append(pkEntity.getSchema(), PK.getSchema()).append(fkEntity.getCatalog(), FK.getCatalog())
+                    .append(fkEntity.getSchema(), PK.getSchema()).isEquals()) {
+
+                LOGGER.info("Skip relation: '" + key + "' because it related to objects from other catalog/schema");
+                LOGGER.info("     relation primary key: '" + PK.getCatalog() + "." + PK.getSchema() + "'");
+                LOGGER.info("       primary key entity: '" + pkEntity.getCatalog() + "." + pkEntity.getSchema() + "'");
+                LOGGER.info("     relation foreign key: '" + FK.getCatalog() + "." + FK.getSchema() + "'");
+                LOGGER.info("       foreign key entity: '" + fkEntity.getCatalog() + "." + fkEntity.getSchema() + "'");
+                continue;
+            }
+
+            // forwardRelationship is a reference from table with primary key
+            // it is what exactly we load from db
+            DbRelationship forwardRelationship = new DbRelationship();
+            forwardRelationship.setSourceEntity(pkEntity);
+            forwardRelationship.setTargetEntityName(fkEntity);
+
+            // TODO: dirty and non-transparent... using DbRelationshipDetected for the benefit of the merge package.
+            // This info is available from joins....
+            DbRelationshipDetected reverseRelationship = new DbRelationshipDetected();
+            reverseRelationship.setFkName(FK.getName());
+            reverseRelationship.setSourceEntity(fkEntity);
+            reverseRelationship.setTargetEntityName(pkEntity);
+            reverseRelationship.setToMany(false);
+
+            createAndAppendJoins(exportedKeys, pkEntity, fkEntity, forwardRelationship, reverseRelationship);
+
+            boolean toDependentPK = isToDependentPK(forwardRelationship);
+            boolean toMany = isToMany(toDependentPK, fkEntity, forwardRelationship);
+
+            forwardRelationship.setToDependentPK(toDependentPK);
+            forwardRelationship.setToMany(toMany);
+
+            // set relationship names only after their joins are ready ...
+            // generator logic is based on relationship state...
+            forwardRelationship.setName(NameBuilder
+                    .builder(forwardRelationship, pkEntity)
+                    .baseName(nameGenerator.relationshipName(forwardRelationship))
+                    .name());
+
+            reverseRelationship.setName(NameBuilder
+                    .builder(reverseRelationship, fkEntity)
+                    .baseName(nameGenerator.relationshipName(reverseRelationship))
+                    .name());
+
+            if (delegate.dbRelationshipLoaded(fkEntity, reverseRelationship)) {
+                fkEntity.addRelationship(reverseRelationship);
+            }
+            if (delegate.dbRelationshipLoaded(pkEntity, forwardRelationship)) {
+                pkEntity.addRelationship(forwardRelationship);
+            }
+        }
+    }
+
+    private boolean isToMany(boolean toDependentPK, DbEntity fkEntity, DbRelationship forwardRelationship) {
+        return !toDependentPK || fkEntity.getPrimaryKeys().size() != forwardRelationship.getJoins().size();
+    }
+
+    private boolean isToDependentPK(DbRelationship forwardRelationship) {
+        for (DbJoin dbJoin : forwardRelationship.getJoins()) {
+            if (!dbJoin.getTarget().isPrimaryKey()) {
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+    private void createAndAppendJoins(Set<ExportedKey> exportedKeys, DbEntity pkEntity, DbEntity fkEntity,
+                                      DbRelationship forwardRelationship, DbRelationship reverseRelationship) {
+        for (ExportedKey exportedKey : exportedKeys) {
+            // Create and append joins
+            String pkName = exportedKey.getPk().getColumn();
+            String fkName = exportedKey.getFk().getColumn();
+
+            // skip invalid joins...
+            DbAttribute pkAtt = pkEntity.getAttribute(pkName);
+            if (pkAtt == null) {
+                LOGGER.info("no attribute for declared primary key: " + pkName);
+                continue;
+            }
+
+            DbAttribute fkAtt = fkEntity.getAttribute(fkName);
+            if (fkAtt == null) {
+                LOGGER.info("no attribute for declared foreign key: " + fkName);
+                continue;
+            }
+
+            forwardRelationship.addJoin(new DbJoin(forwardRelationship, pkName, fkName));
+            reverseRelationship.addJoin(new DbJoin(reverseRelationship, fkName, pkName));
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/8c273022/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/filters/TableFilter.java
----------------------------------------------------------------------
diff --git a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/filters/TableFilter.java b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/filters/TableFilter.java
index 44297d8..ebc2358 100644
--- a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/filters/TableFilter.java
+++ b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/filters/TableFilter.java
@@ -49,13 +49,18 @@ public class TableFilter {
         this.excludes = excludes;
     }
 
+    public boolean isIncludeTable(String tableName) {
+        PatternFilter columnFilter = getIncludeTableColumnFilter(tableName);
+        return columnFilter != null;
+    }
+
     /**
      * Return filter for columns in case we should take this table
      *
      * @param tableName
      * @return
      */
-    public PatternFilter isIncludeTable(String tableName) {
+    public PatternFilter getIncludeTableColumnFilter(String tableName) {
         IncludeTableFilter include = null;
         for (IncludeTableFilter p : includes) {
             if (p.pattern == null || p.pattern.matcher(tableName).matches()) {

http://git-wip-us.apache.org/repos/asf/cayenne/blob/8c273022/cayenne-dbsync/src/test/java/org/apache/cayenne/dbsync/merge/MergeCase.java
----------------------------------------------------------------------
diff --git a/cayenne-dbsync/src/test/java/org/apache/cayenne/dbsync/merge/MergeCase.java b/cayenne-dbsync/src/test/java/org/apache/cayenne/dbsync/merge/MergeCase.java
index 63e7563..65afa21 100644
--- a/cayenne-dbsync/src/test/java/org/apache/cayenne/dbsync/merge/MergeCase.java
+++ b/cayenne-dbsync/src/test/java/org/apache/cayenne/dbsync/merge/MergeCase.java
@@ -26,9 +26,9 @@ 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;
@@ -112,13 +112,13 @@ public abstract class MergeCase extends DbSyncCase {
         DbLoaderConfiguration loaderConfiguration = new DbLoaderConfiguration();
         loaderConfiguration.setFiltersConfig(filters);
 
-        DataMap dbImport = new DataMap();
+        DataMap dbImport;
         try (Connection conn = node.getDataSource().getConnection();) {
-            new DbLoader(conn,
-                    node.getAdapter(),
+            dbImport = new DbLoader(node.getAdapter(), conn,
+                    loaderConfiguration,
                     new LoggingDbLoaderDelegate(LogFactory.getLog(DbLoader.class)),
                     new DefaultObjectNameGenerator(NoStemStemmer.getInstance()))
-                    .load(dbImport, loaderConfiguration);
+                    .load();
 
         } catch (SQLException e) {
             throw new CayenneRuntimeException("Can't doLoad dataMap from db.", e);

http://git-wip-us.apache.org/repos/asf/cayenne/blob/8c273022/cayenne-dbsync/src/test/java/org/apache/cayenne/dbsync/reverse/db/DbLoaderIT.java
----------------------------------------------------------------------
diff --git a/cayenne-dbsync/src/test/java/org/apache/cayenne/dbsync/reverse/db/DbLoaderIT.java b/cayenne-dbsync/src/test/java/org/apache/cayenne/dbsync/reverse/db/DbLoaderIT.java
deleted file mode 100644
index cf154b8..0000000
--- a/cayenne-dbsync/src/test/java/org/apache/cayenne/dbsync/reverse/db/DbLoaderIT.java
+++ /dev/null
@@ -1,408 +0,0 @@
-/*****************************************************************
- *   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.reverse.db;
-
-import org.apache.cayenne.configuration.server.ServerRuntime;
-import org.apache.cayenne.dba.DbAdapter;
-import org.apache.cayenne.dba.TypesMapping;
-import org.apache.cayenne.dbsync.naming.DefaultObjectNameGenerator;
-import org.apache.cayenne.dbsync.naming.NoStemStemmer;
-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.di.Inject;
-import org.apache.cayenne.map.DataMap;
-import org.apache.cayenne.map.DbAttribute;
-import org.apache.cayenne.map.DbEntity;
-import org.apache.cayenne.map.DbRelationship;
-import org.apache.cayenne.map.DetectedDbEntity;
-import org.apache.cayenne.map.ObjAttribute;
-import org.apache.cayenne.map.ObjEntity;
-import org.apache.cayenne.unit.UnitDbAdapter;
-import org.apache.cayenne.unit.di.server.CayenneProjects;
-import org.apache.cayenne.unit.di.server.ServerCase;
-import org.apache.cayenne.unit.di.server.ServerCaseDataSourceFactory;
-import org.apache.cayenne.unit.di.server.UseServerRuntime;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-
-import java.sql.Connection;
-import java.sql.Types;
-import java.util.Collection;
-import java.util.List;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
-
-@UseServerRuntime(CayenneProjects.TESTMAP_PROJECT)
-public class DbLoaderIT extends ServerCase {
-
-    public static final DbLoaderConfiguration CONFIG = new DbLoaderConfiguration();
-    @Inject
-    private ServerRuntime runtime;
-
-    @Inject
-    private DbAdapter adapter;
-
-    @Inject
-    private ServerCaseDataSourceFactory dataSourceFactory;
-
-    @Inject
-    private UnitDbAdapter accessStackAdapter;
-
-    private Connection connection;
-
-    private static String msgForTypeMismatch(DbAttribute origAttr, DbAttribute newAttr) {
-        return msgForTypeMismatch(origAttr.getType(), newAttr);
-    }
-
-    private static String msgForTypeMismatch(int origType, DbAttribute newAttr) {
-        String nt = TypesMapping.getSqlNameByType(newAttr.getType());
-        String ot = TypesMapping.getSqlNameByType(origType);
-        return attrMismatch(newAttr.getName(), "expected type: <" + ot + ">, but was <" + nt + ">");
-    }
-
-    private static String attrMismatch(String attrName, String msg) {
-        return "[Error loading attribute '" + attrName + "': " + msg + "]";
-    }
-
-    @Before
-    public void before() throws Exception {
-        this.connection = dataSourceFactory.getSharedDataSource().getConnection();
-    }
-
-    private DbLoader createDbLoader(boolean meaningfulPK, boolean meaningfulFK) {
-        return new DbLoader(connection, adapter, null, new DefaultObjectNameGenerator(NoStemStemmer.getInstance()));
-    }
-
-    @After
-    public void after() throws Exception {
-        connection.close();
-    }
-
-    @Test
-    public void testGetTables() throws Exception {
-
-        String tableLabel = adapter.tableTypeForTable();
-
-        DbLoader loader = createDbLoader(false, false);
-
-        List<DetectedDbEntity> tables = loader.createTableLoader(null, null, TableFilter.everything())
-                .getDbEntities(TableFilter.everything(), new String[]{tableLabel});
-
-        assertNotNull(tables);
-
-        boolean foundArtist = false;
-
-        for (DetectedDbEntity table : tables) {
-            if ("ARTIST".equalsIgnoreCase(table.getName())) {
-                foundArtist = true;
-                break;
-            }
-        }
-
-        assertTrue("'ARTIST' is missing from the table list: " + tables, foundArtist);
-    }
-
-    @Test
-    public void testGetTablesWithWrongCatalog() throws Exception {
-
-        DbLoader loader = createDbLoader(false, false);
-
-        DbLoaderConfiguration config = new DbLoaderConfiguration();
-        config.setFiltersConfig(
-                FiltersConfig.create("WRONG", null, TableFilter.everything(), PatternFilter.INCLUDE_NOTHING));
-        List<DetectedDbEntity> tables = loader
-                .createTableLoader("WRONG", null, TableFilter.everything())
-                .getDbEntities(TableFilter.everything(), new String[]{adapter.tableTypeForTable()});
-
-        assertNotNull(tables);
-        assertTrue(tables.isEmpty());
-    }
-
-    @Test
-    public void testGetTablesWithWrongSchema() throws Exception {
-
-        DbLoader loader = createDbLoader(false, false);
-
-        DbLoaderConfiguration config = new DbLoaderConfiguration();
-        config.setFiltersConfig(
-                FiltersConfig.create(null, "WRONG", TableFilter.everything(), PatternFilter.INCLUDE_NOTHING));
-        List<DetectedDbEntity> tables = loader
-                .createTableLoader(null, "WRONG", TableFilter.everything())
-                .getDbEntities(TableFilter.everything(), new String[]{adapter.tableTypeForTable()});
-
-        assertNotNull(tables);
-        assertTrue(tables.isEmpty());
-    }
-
-    /**
-     * DataMap loading is in one big test method, since breaking it in
-     * individual tests would require multiple reads of metatdata which is
-     * extremely slow on some RDBMS (Sybase).
-     */
-    @Test
-    public void testLoad() throws Exception {
-        DbLoader loader = createDbLoader(false, false);
-
-        boolean supportsUnique = runtime.getDataDomain().getDataNodes().iterator().next().getAdapter()
-                .supportsUniqueConstraints();
-        boolean supportsLobs = accessStackAdapter.supportsLobs();
-        boolean supportsFK = accessStackAdapter.supportsFKConstraints();
-
-        DataMap map = new DataMap();
-        map.setDefaultPackage("foo.x");
-
-        String tableLabel = adapter.tableTypeForTable();
-
-        // *** TESTING THIS ***
-        List<DbEntity> entities = loader
-                .createTableLoader(null, null, TableFilter.everything())
-                .loadDbEntities(map, CONFIG, new String[]{adapter.tableTypeForTable()});
-
-
-        assertDbEntities(map);
-
-        if (supportsLobs) {
-            assertLobDbEntities(map);
-        }
-
-        // *** TESTING THIS ***
-        loader.loadDbRelationships(CONFIG, null, null, entities);
-
-        if (supportsFK) {
-            Collection<DbRelationship> rels = getDbEntity(map, "ARTIST").getRelationships();
-            assertNotNull(rels);
-            assertTrue(!rels.isEmpty());
-
-            // test one-to-one
-            rels = getDbEntity(map, "PAINTING").getRelationships();
-            assertNotNull(rels);
-
-            // find relationship to PAINTING_INFO
-            DbRelationship oneToOne = null;
-            for (DbRelationship rel : rels) {
-                if ("PAINTING_INFO".equalsIgnoreCase(rel.getTargetEntityName())) {
-                    oneToOne = rel;
-                    break;
-                }
-            }
-
-            assertNotNull("No relationship to PAINTING_INFO", oneToOne);
-            assertFalse("Relationship to PAINTING_INFO must be to-one", oneToOne.isToMany());
-            assertTrue("Relationship to PAINTING_INFO must be to-one", oneToOne.isToDependentPK());
-
-            // test UNIQUE only if FK is supported...
-            if (supportsUnique) {
-                assertUniqueConstraintsInRelationships(map);
-            }
-        }
-
-        // now when the map is loaded, test
-        // various things selectively check how different types were processed
-        if (accessStackAdapter.supportsColumnTypeReengineering()) {
-            checkTypes(map);
-        }
-    }
-
-    private void assertUniqueConstraintsInRelationships(DataMap map) {
-        // unfortunately JDBC metadata doesn't provide info for UNIQUE
-        // constraints....
-        // cant reengineer them...
-
-        // find rel to TO_ONEFK1
-        /*
-         * Iterator it = getDbEntity(map,
-         * "TO_ONEFK2").getRelationships().iterator(); DbRelationship rel =
-         * (DbRelationship) it.next(); assertEquals("TO_ONEFK1",
-         * rel.getTargetEntityName());
-         * assertFalse("UNIQUE constraint was ignored...", rel.isToMany());
-         */
-    }
-
-    private void assertDbEntities(DataMap map) {
-        DbEntity dae = getDbEntity(map, "ARTIST");
-        assertNotNull("Null 'ARTIST' entity, other DbEntities: " + map.getDbEntityMap(), dae);
-        assertEquals("ARTIST", dae.getName().toUpperCase());
-
-        DbAttribute a = getDbAttribute(dae, "ARTIST_ID");
-        assertNotNull(a);
-        assertTrue(a.isPrimaryKey());
-        assertFalse(a.isGenerated());
-
-        if (adapter.supportsGeneratedKeys()) {
-            DbEntity bag = getDbEntity(map, "GENERATED_COLUMN_TEST");
-            DbAttribute id = getDbAttribute(bag, "GENERATED_COLUMN");
-            assertTrue(id.isPrimaryKey());
-            assertTrue(id.isGenerated());
-        }
-    }
-
-    private void assertObjEntities(DataMap map) {
-
-        boolean supportsLobs = accessStackAdapter.supportsLobs();
-        boolean supportsFK = accessStackAdapter.supportsFKConstraints();
-
-        ObjEntity ae = map.getObjEntity("Artist");
-        assertNotNull(ae);
-        assertEquals("Artist", ae.getName());
-
-        // assert primary key is not an attribute
-        assertNull(ae.getAttribute("artistId"));
-
-        if (supportsLobs) {
-            assertLobObjEntities(map);
-        }
-
-        if (supportsFK) {
-            Collection<?> rels1 = ae.getRelationships();
-            assertNotNull(rels1);
-            assertTrue(rels1.size() > 0);
-        }
-
-        assertEquals("foo.x.Artist", ae.getClassName());
-    }
-
-    private void assertLobDbEntities(DataMap map) {
-        DbEntity blobEnt = getDbEntity(map, "BLOB_TEST");
-        assertNotNull(blobEnt);
-        DbAttribute blobAttr = getDbAttribute(blobEnt, "BLOB_COL");
-        assertNotNull(blobAttr);
-        assertTrue(msgForTypeMismatch(Types.BLOB, blobAttr), Types.BLOB == blobAttr.getType()
-                || Types.LONGVARBINARY == blobAttr.getType());
-
-        DbEntity clobEnt = getDbEntity(map, "CLOB_TEST");
-        assertNotNull(clobEnt);
-        DbAttribute clobAttr = getDbAttribute(clobEnt, "CLOB_COL");
-        assertNotNull(clobAttr);
-        assertTrue(msgForTypeMismatch(Types.CLOB, clobAttr), Types.CLOB == clobAttr.getType()
-                || Types.LONGVARCHAR == clobAttr.getType());
-
-/*
-        DbEntity nclobEnt = getDbEntity(map, "NCLOB_TEST");
-        assertNotNull(nclobEnt);
-        DbAttribute nclobAttr = getDbAttribute(nclobEnt, "NCLOB_COL");
-        assertNotNull(nclobAttr);
-        assertTrue(msgForTypeMismatch(Types.NCLOB, nclobAttr), Types.NCLOB == nclobAttr.getType()
-                || Types.LONGVARCHAR == nclobAttr.getType());
-*/
-    }
-
-    private void assertLobObjEntities(DataMap map) {
-        ObjEntity blobEnt = map.getObjEntity("BlobTest");
-        assertNotNull(blobEnt);
-        // BLOBs should be mapped as byte[]
-        ObjAttribute blobAttr = blobEnt.getAttribute("blobCol");
-        assertNotNull("BlobTest.blobCol failed to doLoad", blobAttr);
-        assertEquals("byte[]", blobAttr.getType());
-
-
-        ObjEntity clobEnt = map.getObjEntity("ClobTest");
-        assertNotNull(clobEnt);
-        // CLOBs should be mapped as Strings by default
-        ObjAttribute clobAttr = clobEnt.getAttribute("clobCol");
-        assertNotNull(clobAttr);
-        assertEquals(String.class.getName(), clobAttr.getType());
-
-
-        ObjEntity nclobEnt = map.getObjEntity("NclobTest");
-        assertNotNull(nclobEnt);
-        // CLOBs should be mapped as Strings by default
-        ObjAttribute nclobAttr = nclobEnt.getAttribute("nclobCol");
-        assertNotNull(nclobAttr);
-        assertEquals(String.class.getName(), nclobAttr.getType());
-    }
-
-    private DbEntity getDbEntity(DataMap map, String name) {
-        DbEntity de = map.getDbEntity(name);
-        // sometimes table names get converted to lowercase
-        if (de == null) {
-            de = map.getDbEntity(name.toLowerCase());
-        }
-
-        return de;
-    }
-
-    private DbAttribute getDbAttribute(DbEntity ent, String name) {
-        DbAttribute da = ent.getAttribute(name);
-        // sometimes table names get converted to lowercase
-        if (da == null) {
-            da = ent.getAttribute(name.toLowerCase());
-        }
-
-        return da;
-    }
-
-    private DataMap originalMap() {
-        return runtime.getDataDomain().getDataNodes().iterator().next().getDataMaps().iterator().next();
-    }
-
-    /**
-     * Selectively check how different types were processed.
-     */
-    public void checkTypes(DataMap map) {
-        DbEntity dbe = getDbEntity(map, "PAINTING");
-        DbEntity floatTest = getDbEntity(map, "FLOAT_TEST");
-        DbEntity smallintTest = getDbEntity(map, "SMALLINT_TEST");
-        DbAttribute integerAttr = getDbAttribute(dbe, "PAINTING_ID");
-        DbAttribute decimalAttr = getDbAttribute(dbe, "ESTIMATED_PRICE");
-        DbAttribute varcharAttr = getDbAttribute(dbe, "PAINTING_TITLE");
-        DbAttribute floatAttr = getDbAttribute(floatTest, "FLOAT_COL");
-        DbAttribute smallintAttr = getDbAttribute(smallintTest, "SMALLINT_COL");
-
-        // check decimal
-        assertTrue(msgForTypeMismatch(Types.DECIMAL, decimalAttr), Types.DECIMAL == decimalAttr.getType()
-                || Types.NUMERIC == decimalAttr.getType());
-        assertEquals(2, decimalAttr.getScale());
-
-        // check varchar
-        assertEquals(msgForTypeMismatch(Types.VARCHAR, varcharAttr), Types.VARCHAR, varcharAttr.getType());
-        assertEquals(255, varcharAttr.getMaxLength());
-        // check integer
-        assertEquals(msgForTypeMismatch(Types.INTEGER, integerAttr), Types.INTEGER, integerAttr.getType());
-        // check float
-        assertTrue(msgForTypeMismatch(Types.FLOAT, floatAttr), Types.FLOAT == floatAttr.getType()
-                || Types.DOUBLE == floatAttr.getType() || Types.REAL == floatAttr.getType());
-
-        // check smallint
-        assertTrue(msgForTypeMismatch(Types.SMALLINT, smallintAttr), Types.SMALLINT == smallintAttr.getType()
-                || Types.INTEGER == smallintAttr.getType());
-    }
-
-    public void checkAllDBEntities(DataMap map) {
-
-        for (DbEntity origEnt : originalMap().getDbEntities()) {
-            DbEntity newEnt = map.getDbEntity(origEnt.getName());
-            for (DbAttribute origAttr : origEnt.getAttributes()) {
-                DbAttribute newAttr = newEnt.getAttribute(origAttr.getName());
-                assertNotNull("No matching DbAttribute for '" + origAttr.getName(), newAttr);
-                assertEquals(msgForTypeMismatch(origAttr, newAttr), origAttr.getType(), newAttr.getType());
-                // length and precision doesn't have to be the same
-                // it must be greater or equal
-                assertTrue(origAttr.getMaxLength() <= newAttr.getMaxLength());
-                assertTrue(origAttr.getScale() <= newAttr.getScale());
-            }
-        }
-    }
-}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/8c273022/cayenne-dbsync/src/test/java/org/apache/cayenne/dbsync/reverse/dbload/AttributeLoaderIT.java
----------------------------------------------------------------------
diff --git a/cayenne-dbsync/src/test/java/org/apache/cayenne/dbsync/reverse/dbload/AttributeLoaderIT.java b/cayenne-dbsync/src/test/java/org/apache/cayenne/dbsync/reverse/dbload/AttributeLoaderIT.java
new file mode 100644
index 0000000..d1abac5
--- /dev/null
+++ b/cayenne-dbsync/src/test/java/org/apache/cayenne/dbsync/reverse/dbload/AttributeLoaderIT.java
@@ -0,0 +1,154 @@
+/*****************************************************************
+ *   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.reverse.dbload;
+
+import java.sql.DatabaseMetaData;
+import java.sql.Types;
+
+import org.apache.cayenne.dba.TypesMapping;
+import org.apache.cayenne.map.DbAttribute;
+import org.apache.cayenne.map.DbEntity;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+public class AttributeLoaderIT extends BaseLoaderIT {
+
+    @Test
+    public void testAttributeLoad() throws Exception {
+        createDbEntities();
+
+        AttributeLoader loader = new AttributeLoader(adapter, EMPTY_CONFIG, new DefaultDbLoaderDelegate());
+        loader.load(connection.getMetaData(), store);
+
+        DbEntity artist = getDbEntity("ARTIST");
+        DbAttribute a = getDbAttribute(artist, "ARTIST_ID");
+        assertNotNull(a);
+        assertEquals(Types.BIGINT, a.getType());
+        assertTrue(a.isMandatory());
+        assertFalse(a.isGenerated());
+
+        a = getDbAttribute(artist, "ARTIST_NAME");
+        assertNotNull(a);
+        assertEquals(Types.CHAR, a.getType());
+        assertEquals(254, a.getMaxLength());
+        assertTrue(a.isMandatory());
+
+        a = getDbAttribute(artist, "DATE_OF_BIRTH");
+        assertNotNull(a);
+        assertEquals(Types.DATE, a.getType());
+        assertFalse(a.isMandatory());
+
+        if(accessStackAdapter.supportsLobs()) {
+            assertLobDbEntities();
+        }
+
+        if (adapter.supportsGeneratedKeys()) {
+            assertGenerated();
+        }
+    }
+
+    @Test
+    public void testAttributeLoadTypes() throws Exception {
+        DatabaseMetaData metaData = connection.getMetaData();
+        DbLoaderDelegate delegate = new DefaultDbLoaderDelegate();
+
+        // We need all data to check relationships, so simply load it all
+        EntityLoader entityLoader = new EntityLoader(adapter, EMPTY_CONFIG, delegate);
+        AttributeLoader attributeLoader = new AttributeLoader(adapter, EMPTY_CONFIG, delegate);
+
+        entityLoader.load(metaData, store);
+        attributeLoader.load(metaData, store);
+
+        DbEntity dbe = getDbEntity("PAINTING");
+        DbEntity floatTest = getDbEntity("FLOAT_TEST");
+        DbEntity smallintTest = getDbEntity("SMALLINT_TEST");
+        DbAttribute integerAttr = getDbAttribute(dbe, "PAINTING_ID");
+        DbAttribute decimalAttr = getDbAttribute(dbe, "ESTIMATED_PRICE");
+        DbAttribute varcharAttr = getDbAttribute(dbe, "PAINTING_TITLE");
+        DbAttribute floatAttr = getDbAttribute(floatTest, "FLOAT_COL");
+        DbAttribute smallintAttr = getDbAttribute(smallintTest, "SMALLINT_COL");
+
+        // check decimal
+        assertTrue(msgForTypeMismatch(Types.DECIMAL, decimalAttr), Types.DECIMAL == decimalAttr.getType()
+                || Types.NUMERIC == decimalAttr.getType());
+        assertEquals(2, decimalAttr.getScale());
+
+        // check varchar
+        assertEquals(msgForTypeMismatch(Types.VARCHAR, varcharAttr), Types.VARCHAR, varcharAttr.getType());
+        assertEquals(255, varcharAttr.getMaxLength());
+        // check integer
+        assertEquals(msgForTypeMismatch(Types.INTEGER, integerAttr), Types.INTEGER, integerAttr.getType());
+        // check float
+        assertTrue(msgForTypeMismatch(Types.FLOAT, floatAttr), Types.FLOAT == floatAttr.getType()
+                || Types.DOUBLE == floatAttr.getType() || Types.REAL == floatAttr.getType());
+
+        // check smallint
+        assertTrue(msgForTypeMismatch(Types.SMALLINT, smallintAttr), Types.SMALLINT == smallintAttr.getType()
+                || Types.INTEGER == smallintAttr.getType());
+    }
+
+    private void assertGenerated() {
+        DbEntity bag = getDbEntity("GENERATED_COLUMN_TEST");
+        DbAttribute id = getDbAttribute(bag, "GENERATED_COLUMN");
+        assertTrue(id.isGenerated());
+    }
+
+    private void assertLobDbEntities() {
+        DbEntity blobEnt = getDbEntity("BLOB_TEST");
+        assertNotNull(blobEnt);
+        DbAttribute blobAttr = getDbAttribute(blobEnt, "BLOB_COL");
+        assertNotNull(blobAttr);
+        assertTrue(msgForTypeMismatch(Types.BLOB, blobAttr), Types.BLOB == blobAttr.getType()
+                || Types.LONGVARBINARY == blobAttr.getType());
+
+        DbEntity clobEnt = getDbEntity("CLOB_TEST");
+        assertNotNull(clobEnt);
+        DbAttribute clobAttr = getDbAttribute(clobEnt, "CLOB_COL");
+        assertNotNull(clobAttr);
+        assertTrue(msgForTypeMismatch(Types.CLOB, clobAttr), Types.CLOB == clobAttr.getType()
+                || Types.LONGVARCHAR == clobAttr.getType());
+    }
+
+
+
+    private DbAttribute getDbAttribute(DbEntity ent, String name) {
+        DbAttribute da = ent.getAttribute(name);
+        // sometimes table names get converted to lowercase
+        if (da == null) {
+            da = ent.getAttribute(name.toLowerCase());
+        }
+
+        return da;
+    }
+
+    private static String msgForTypeMismatch(int origType, DbAttribute newAttr) {
+        String nt = TypesMapping.getSqlNameByType(newAttr.getType());
+        String ot = TypesMapping.getSqlNameByType(origType);
+        return attrMismatch(newAttr.getName(), "expected type: <" + ot + ">, but was <" + nt + ">");
+    }
+
+    private static String attrMismatch(String attrName, String msg) {
+        return "[Error loading attribute '" + attrName + "': " + msg + "]";
+    }
+}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/8c273022/cayenne-dbsync/src/test/java/org/apache/cayenne/dbsync/reverse/dbload/BaseLoaderIT.java
----------------------------------------------------------------------
diff --git a/cayenne-dbsync/src/test/java/org/apache/cayenne/dbsync/reverse/dbload/BaseLoaderIT.java b/cayenne-dbsync/src/test/java/org/apache/cayenne/dbsync/reverse/dbload/BaseLoaderIT.java
new file mode 100644
index 0000000..1edc938
--- /dev/null
+++ b/cayenne-dbsync/src/test/java/org/apache/cayenne/dbsync/reverse/dbload/BaseLoaderIT.java
@@ -0,0 +1,91 @@
+/*****************************************************************
+ *   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.reverse.dbload;
+
+import java.sql.Connection;
+
+import org.apache.cayenne.configuration.server.ServerRuntime;
+import org.apache.cayenne.dba.DbAdapter;
+import org.apache.cayenne.di.Inject;
+import org.apache.cayenne.map.DbEntity;
+import org.apache.cayenne.map.DetectedDbEntity;
+import org.apache.cayenne.unit.UnitDbAdapter;
+import org.apache.cayenne.unit.di.server.CayenneProjects;
+import org.apache.cayenne.unit.di.server.ServerCase;
+import org.apache.cayenne.unit.di.server.ServerCaseDataSourceFactory;
+import org.apache.cayenne.unit.di.server.UseServerRuntime;
+import org.junit.After;
+import org.junit.Before;
+
+import static org.junit.Assert.assertTrue;
+
+@UseServerRuntime(CayenneProjects.TESTMAP_PROJECT)
+public class BaseLoaderIT extends ServerCase {
+
+    static final DbLoaderConfiguration EMPTY_CONFIG = new DbLoaderConfiguration();
+
+    @Inject
+    protected DbAdapter adapter;
+
+    @Inject
+    protected ServerRuntime runtime;
+
+    @Inject
+    protected ServerCaseDataSourceFactory dataSourceFactory;
+
+    @Inject
+    protected UnitDbAdapter accessStackAdapter;
+
+    Connection connection;
+
+    DbLoadDataStore store;
+
+    @Before
+    public void before() throws Exception {
+        store = new DbLoadDataStore();
+        assertTrue("Store is not empty", store.getDbEntities().isEmpty());
+        this.connection = dataSourceFactory.getSharedDataSource().getConnection();
+    }
+
+    @After
+    public void after() throws Exception {
+        connection.close();
+    }
+
+    void createDbEntities() {
+        String[] names = {"ARTIST", "BLOB_TEST", "CLOB_TEST", "GENERATED_COLUMN_TEST"};
+        for(String name : names) {
+            createEntity(name);
+        }
+    }
+
+    void createEntity(String name) {
+        store.addDbEntity(new DetectedDbEntity(name));
+    }
+
+    DbEntity getDbEntity(String name) {
+        DbEntity de = store.getDbEntity(name);
+        // sometimes table names get converted to lowercase
+        if (de == null) {
+            de = store.getDbEntity(name.toLowerCase());
+        }
+        return de;
+    }
+}


[5/9] cayenne git commit: New DbLoader for dbsync utils - loading process split in independent small steps - DbLoader always return new DataMap, it doesn't accept it from outside

Posted by aa...@apache.org.
New DbLoader for dbsync utils
 - loading process split in independent small steps
 - DbLoader always return new DataMap, it doesn't accept it from outside

Final clean up of tests


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

Branch: refs/heads/master
Commit: 41515467c4a0804dcb35d99070046ea0ac44a6e0
Parents: e68c72c
Author: Nikita Timofeev <st...@gmail.com>
Authored: Mon Dec 12 12:34:14 2016 +0300
Committer: Nikita Timofeev <st...@gmail.com>
Committed: Mon Dec 12 12:34:14 2016 +0300

----------------------------------------------------------------------
 .../dbsync/reverse/dbload/DbLoaderIT.java       | 75 ++++++++++++--------
 .../reverse/dbload/RelationshipsLoaderIT.java   | 16 +++++
 .../modeler/dialog/db/DbLoaderHelper.java       |  2 +-
 3 files changed, 63 insertions(+), 30 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cayenne/blob/41515467/cayenne-dbsync/src/test/java/org/apache/cayenne/dbsync/reverse/dbload/DbLoaderIT.java
----------------------------------------------------------------------
diff --git a/cayenne-dbsync/src/test/java/org/apache/cayenne/dbsync/reverse/dbload/DbLoaderIT.java b/cayenne-dbsync/src/test/java/org/apache/cayenne/dbsync/reverse/dbload/DbLoaderIT.java
index bf0f89f..d2e87a5 100644
--- a/cayenne-dbsync/src/test/java/org/apache/cayenne/dbsync/reverse/dbload/DbLoaderIT.java
+++ b/cayenne-dbsync/src/test/java/org/apache/cayenne/dbsync/reverse/dbload/DbLoaderIT.java
@@ -21,12 +21,13 @@ package org.apache.cayenne.dbsync.reverse.dbload;
 
 import org.apache.cayenne.configuration.server.ServerRuntime;
 import org.apache.cayenne.dba.DbAdapter;
-import org.apache.cayenne.dba.TypesMapping;
 import org.apache.cayenne.dbsync.naming.DefaultObjectNameGenerator;
 import org.apache.cayenne.dbsync.naming.NoStemStemmer;
 import org.apache.cayenne.di.Inject;
 import org.apache.cayenne.map.DataMap;
 import org.apache.cayenne.map.DbAttribute;
+import org.apache.cayenne.map.DbEntity;
+import org.apache.cayenne.map.DbRelationship;
 import org.apache.cayenne.unit.UnitDbAdapter;
 import org.apache.cayenne.unit.di.server.CayenneProjects;
 import org.apache.cayenne.unit.di.server.ServerCase;
@@ -34,16 +35,23 @@ import org.apache.cayenne.unit.di.server.ServerCaseDataSourceFactory;
 import org.apache.cayenne.unit.di.server.UseServerRuntime;
 import org.junit.After;
 import org.junit.Before;
+import org.junit.Test;
 
 import java.sql.Connection;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
 /**
  * All tests have been moved to corresponding loaders tests.
  */
 @UseServerRuntime(CayenneProjects.TESTMAP_PROJECT)
 public class DbLoaderIT extends ServerCase {
 
-    public static final DbLoaderConfiguration CONFIG = new DbLoaderConfiguration();
+    private static final DbLoaderConfiguration CONFIG = new DbLoaderConfiguration();
+
     @Inject
     private ServerRuntime runtime;
 
@@ -58,19 +66,45 @@ public class DbLoaderIT extends ServerCase {
 
     private Connection connection;
 
-    private static String msgForTypeMismatch(DbAttribute origAttr, DbAttribute newAttr) {
-        return msgForTypeMismatch(origAttr.getType(), newAttr);
-    }
 
-    private static String msgForTypeMismatch(int origType, DbAttribute newAttr) {
-        String nt = TypesMapping.getSqlNameByType(newAttr.getType());
-        String ot = TypesMapping.getSqlNameByType(origType);
-        return attrMismatch(newAttr.getName(), "expected type: <" + ot + ">, but was <" + nt + ">");
+    /**
+     * Test that parts of loader are in place
+     */
+    @Test
+    public void testSimpleLoad() throws Exception {
+        DbLoader loader = createDbLoader(true, true);
+        DataMap loaded = loader.load();
+        assertNotNull(loaded);
+        assertEquals("__generated_by_dbloader__", loaded.getName());
+
+        // DbEntity
+        DbEntity artist = loaded.getDbEntity("ARTIST");
+        assertNotNull(artist);
+
+        // DbAttribute
+        DbAttribute id = artist.getAttribute("ARTIST_ID");
+        assertNotNull(id);
+        assertTrue(id.isMandatory());
+        assertTrue(id.isPrimaryKey());
+
+        DbAttribute name = artist.getAttribute("ARTIST_NAME");
+        assertNotNull(name);
+        assertTrue(name.isMandatory());
+
+        DbAttribute date = artist.getAttribute("DATE_OF_BIRTH");
+        assertNotNull(date);
+        assertFalse(date.isMandatory());
+
+        // DbRelationship
+        assertEquals(4, artist.getRelationships().size());
+
+        DbRelationship exhibits = artist.getRelationship("artistExhibits");
+        assertNotNull(exhibits);
+        assertEquals("ARTIST_EXHIBIT", exhibits.getTargetEntityName());
+        DbEntity target = exhibits.getTargetEntity();
+        assertNotNull(target);
     }
 
-    private static String attrMismatch(String attrName, String msg) {
-        return "[Error loading attribute '" + attrName + "': " + msg + "]";
-    }
 
     @Before
     public void before() throws Exception {
@@ -85,21 +119,4 @@ public class DbLoaderIT extends ServerCase {
     public void after() throws Exception {
         connection.close();
     }
-
-    private void assertUniqueConstraintsInRelationships(DataMap map) {
-        // unfortunately JDBC metadata doesn't provide info for UNIQUE
-        // constraints....
-        // cant reengineer them...
-        // upd. actually it's provided:
-        // http://docs.oracle.com/javase/7/docs/api/java/sql/DatabaseMetaData.html#getIndexInfo%28java.lang.String,%20java.lang.String,%20java.lang.String,%20boolean,%20boolean%29
-
-        // find rel to TO_ONEFK1
-        /*
-         * Iterator it = getDbEntity(map,
-         * "TO_ONEFK2").getRelationships().iterator(); DbRelationship rel =
-         * (DbRelationship) it.next(); assertEquals("TO_ONEFK1",
-         * rel.getTargetEntityName());
-         * assertFalse("UNIQUE constraint was ignored...", rel.isToMany());
-         */
-    }
 }

http://git-wip-us.apache.org/repos/asf/cayenne/blob/41515467/cayenne-dbsync/src/test/java/org/apache/cayenne/dbsync/reverse/dbload/RelationshipsLoaderIT.java
----------------------------------------------------------------------
diff --git a/cayenne-dbsync/src/test/java/org/apache/cayenne/dbsync/reverse/dbload/RelationshipsLoaderIT.java b/cayenne-dbsync/src/test/java/org/apache/cayenne/dbsync/reverse/dbload/RelationshipsLoaderIT.java
index a73833e..e983f09 100644
--- a/cayenne-dbsync/src/test/java/org/apache/cayenne/dbsync/reverse/dbload/RelationshipsLoaderIT.java
+++ b/cayenne-dbsync/src/test/java/org/apache/cayenne/dbsync/reverse/dbload/RelationshipsLoaderIT.java
@@ -79,4 +79,20 @@ public class RelationshipsLoaderIT extends BaseLoaderIT {
         assertTrue("Relationship to PAINTING_INFO must be to-one", oneToOne.isToDependentPK());
     }
 
+//    private void assertUniqueConstraintsInRelationships(DataMap map) {
+        // unfortunately JDBC metadata doesn't provide info for UNIQUE
+        // constraints....
+        // cant reengineer them...
+        // upd. actually it's provided:
+        // http://docs.oracle.com/javase/7/docs/api/java/sql/DatabaseMetaData.html#getIndexInfo%28java.lang.String,%20java.lang.String,%20java.lang.String,%20boolean,%20boolean%29
+
+        // find rel to TO_ONEFK1
+        /*
+         * Iterator it = getDbEntity(map,
+         * "TO_ONEFK2").getRelationships().iterator(); DbRelationship rel =
+         * (DbRelationship) it.next(); assertEquals("TO_ONEFK1",
+         * rel.getTargetEntityName());
+         * assertFalse("UNIQUE constraint was ignored...", rel.isToMany());
+         */
+//    }
 }

http://git-wip-us.apache.org/repos/asf/cayenne/blob/41515467/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/dialog/db/DbLoaderHelper.java
----------------------------------------------------------------------
diff --git a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/dialog/db/DbLoaderHelper.java b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/dialog/db/DbLoaderHelper.java
index 0f49e49..462ceef 100644
--- a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/dialog/db/DbLoaderHelper.java
+++ b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/dialog/db/DbLoaderHelper.java
@@ -68,7 +68,7 @@ import java.util.Collections;
 import java.util.List;
 
 /**
- * Stateful helper class that encapsulates access to DbLoader2.
+ * Stateful helper class that encapsulates access to DbLoader.
  */
 public class DbLoaderHelper {