You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cayenne.apache.org by aa...@apache.org on 2016/09/30 14:23:50 UTC

[4/9] cayenne git commit: CAY-2115 DbLoader - allow loading DataMap without Obj layer

CAY-2115 DbLoader - allow loading DataMap without Obj layer

.. in progress ...

* subpackage for db stage of reverse engineering


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

Branch: refs/heads/master
Commit: cf172fc97156897203aff30698ab98a41b1024e0
Parents: 7296d1f
Author: Andrus Adamchik <an...@objectstyle.com>
Authored: Fri Sep 30 11:42:43 2016 +0300
Committer: Andrus Adamchik <an...@objectstyle.com>
Committed: Fri Sep 30 14:05:59 2016 +0300

----------------------------------------------------------------------
 .../apache/cayenne/dbsync/merge/DbMerger.java   |   6 +-
 .../dbsync/reverse/DbAttributesBaseLoader.java  | 107 ---
 .../dbsync/reverse/DbAttributesLoader.java      |  43 --
 .../reverse/DbAttributesPerSchemaLoader.java    | 130 ----
 .../apache/cayenne/dbsync/reverse/DbLoader.java | 725 -------------------
 .../dbsync/reverse/DbLoaderConfiguration.java   | 150 ----
 .../dbsync/reverse/DbLoaderDelegate.java        |  58 --
 .../cayenne/dbsync/reverse/DbTableLoader.java   | 195 -----
 .../dbsync/reverse/DefaultDbLoaderDelegate.java |  59 --
 .../dbsync/reverse/FiltersConfigBuilder.java    |  17 +-
 .../dbsync/reverse/LoggingDbLoaderDelegate.java |  76 --
 .../reverse/ManyToManyCandidateEntity.java      | 142 ----
 .../reverse/db/DbAttributesBaseLoader.java      | 107 +++
 .../dbsync/reverse/db/DbAttributesLoader.java   |  43 ++
 .../reverse/db/DbAttributesPerSchemaLoader.java | 130 ++++
 .../cayenne/dbsync/reverse/db/DbLoader.java     | 702 ++++++++++++++++++
 .../reverse/db/DbLoaderConfiguration.java       | 128 ++++
 .../dbsync/reverse/db/DbLoaderDelegate.java     |  58 ++
 .../dbsync/reverse/db/DbTableLoader.java        | 195 +++++
 .../reverse/db/DefaultDbLoaderDelegate.java     |  59 ++
 .../reverse/db/LoggingDbLoaderDelegate.java     |  76 ++
 .../reverse/db/ManyToManyCandidateEntity.java   | 143 ++++
 .../cayenne/dbsync/merge/DbMergerTest.java      |   2 +-
 .../apache/cayenne/dbsync/merge/MergeCase.java  |   2 +-
 .../cayenne/dbsync/reverse/DbLoaderIT.java      | 434 -----------
 .../reverse/FiltersConfigBuilderTest.java       |  14 +-
 .../reverse/ManyToManyCandidateEntityTest.java  | 113 ---
 .../cayenne/dbsync/reverse/db/DbLoaderIT.java   | 418 +++++++++++
 .../db/ManyToManyCandidateEntityTest.java       | 113 +++
 .../apache/cayenne/tools/DbImporterTask.java    |   4 +-
 .../tools/dbimport/DbImportConfiguration.java   |  10 +-
 .../dbimport/DbImportDbLoaderDelegate.java      |   2 +-
 .../tools/dbimport/DefaultDbImportAction.java   |   2 +-
 .../dbimport/DefaultDbImportActionTest.java     |  22 +-
 .../cayenne/modeler/action/MigrateAction.java   |   2 +-
 .../modeler/dialog/db/DbLoaderHelper.java       |   6 +-
 .../modeler/dialog/db/MergerOptions.java        |   2 +-
 .../modeler/dialog/db/ModelerDbLoader.java      |  12 +-
 .../dialog/db/ReverseEngineeringController.java |   6 +-
 .../apache/cayenne/tools/DbImporterMojo.java    |   4 +-
 40 files changed, 2220 insertions(+), 2297 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cayenne/blob/cf172fc9/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 f7d4346..41ff7c8 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
@@ -22,9 +22,9 @@ import org.apache.cayenne.CayenneRuntimeException;
 import org.apache.cayenne.access.DataNode;
 import org.apache.cayenne.dba.DbAdapter;
 import org.apache.cayenne.dbsync.merge.factory.MergerTokenFactory;
-import org.apache.cayenne.dbsync.reverse.DbLoader;
-import org.apache.cayenne.dbsync.reverse.DbLoaderConfiguration;
-import org.apache.cayenne.dbsync.reverse.LoggingDbLoaderDelegate;
+import org.apache.cayenne.dbsync.reverse.db.DbLoader;
+import org.apache.cayenne.dbsync.reverse.db.DbLoaderConfiguration;
+import org.apache.cayenne.dbsync.reverse.db.LoggingDbLoaderDelegate;
 import org.apache.cayenne.dbsync.reverse.filters.FiltersConfig;
 import org.apache.cayenne.map.Attribute;
 import org.apache.cayenne.map.DataMap;

http://git-wip-us.apache.org/repos/asf/cayenne/blob/cf172fc9/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/DbAttributesBaseLoader.java
----------------------------------------------------------------------
diff --git a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/DbAttributesBaseLoader.java b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/DbAttributesBaseLoader.java
deleted file mode 100644
index 2bb55c0..0000000
--- a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/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;
-
-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/cf172fc9/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/DbAttributesLoader.java
----------------------------------------------------------------------
diff --git a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/DbAttributesLoader.java b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/DbAttributesLoader.java
deleted file mode 100644
index 6658cdc..0000000
--- a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/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;
-
-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/cf172fc9/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/DbAttributesPerSchemaLoader.java
----------------------------------------------------------------------
diff --git a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/DbAttributesPerSchemaLoader.java b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/DbAttributesPerSchemaLoader.java
deleted file mode 100644
index 83ce60b..0000000
--- a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/DbAttributesPerSchemaLoader.java
+++ /dev/null
@@ -1,130 +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;
-
-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;
-
-import org.apache.cayenne.dbsync.reverse.filters.PatternFilter;
-import org.apache.cayenne.dbsync.reverse.filters.TableFilter;
-import org.apache.cayenne.dba.DbAdapter;
-import org.apache.cayenne.map.DbAttribute;
-
-/**
- * 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");
-
-				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.isInclude(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/cf172fc9/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/DbLoader.java
----------------------------------------------------------------------
diff --git a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/DbLoader.java b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/DbLoader.java
deleted file mode 100644
index 22764ef..0000000
--- a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/DbLoader.java
+++ /dev/null
@@ -1,725 +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;
-
-import org.apache.cayenne.dba.DbAdapter;
-import org.apache.cayenne.dba.TypesMapping;
-import org.apache.cayenne.dbsync.merge.EntityMergeSupport;
-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.DbRelationshipDetected;
-import org.apache.cayenne.map.ObjEntity;
-import org.apache.cayenne.map.Procedure;
-import org.apache.cayenne.map.ProcedureParameter;
-import org.apache.cayenne.map.naming.DefaultUniqueNameGenerator;
-import org.apache.cayenne.map.naming.ExportedKey;
-import org.apache.cayenne.map.naming.LegacyNameGenerator;
-import org.apache.cayenne.map.naming.NameCheckers;
-import org.apache.cayenne.map.naming.ObjectNameGenerator;
-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.Collection;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.TreeSet;
-
-/**
- * Performs reverse engineering of the database. It can create
- * DataMaps using database meta data obtained via JDBC driver.
- *
- * @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 boolean creatingMeaningfulPK;
-
-	private DatabaseMetaData metaData;
-
-	/**
-	 * Strategy for choosing names for entities, attributes and relationships
-	 */
-	private ObjectNameGenerator nameGenerator;
-
-	/**
-	 * Creates new DbLoader.
-	 */
-	public DbLoader(Connection connection, DbAdapter adapter, DbLoaderDelegate delegate) {
-		this(connection, adapter, delegate, new LegacyNameGenerator());
-	}
-
-	/**
-	 * Creates new DbLoader with specified naming strategy.
-	 *
-	 * @since 3.0
-	 */
-	public DbLoader(Connection connection, DbAdapter adapter, DbLoaderDelegate delegate, ObjectNameGenerator strategy) {
-		this.adapter = adapter;
-		this.connection = connection;
-		this.delegate = delegate == null ? new DefaultDbLoaderDelegate() : delegate;
-
-		setNameGenerator(strategy);
-	}
-
-	/**
-	 * Returns DatabaseMetaData object associated with this DbLoader.
-	 */
-	private DatabaseMetaData getMetaData() throws SQLException {
-		if (metaData == null) {
-			metaData = connection.getMetaData();
-		}
-		return metaData;
-	}
-
-	/**
-	 * Check if database support schemas.
-	 */
-	protected boolean supportSchemas() throws SQLException {
-		if (metaData == null) {
-			metaData = connection.getMetaData();
-		}
-		return metaData.supportsSchemasInTableDefinitions();
-	}
-
-	/**
-	 * Check if database support catalogs.
-	 */
-	protected boolean supportCatalogs() throws SQLException {
-		if (metaData == null) {
-			metaData = connection.getMetaData();
-		}
-		return metaData.supportsCatalogsInTableDefinitions();
-	}
-
-	/**
-	 * @since 3.0
-	 */
-	public void setCreatingMeaningfulPK(boolean creatingMeaningfulPK) {
-		this.creatingMeaningfulPK = creatingMeaningfulPK;
-	}
-	
-	/**
-	 * Retrieves catalogs for the database associated with this DbLoader.
-	 *
-	 * @return List with the catalog names, empty Array if none found.
-	 */
-	public List<String> loadCatalogs() throws SQLException {
-		try (ResultSet rs = getMetaData().getCatalogs()) {
-			return getStrings(rs);
-		}
-	}
-
-	/**
-	 * Retrieves the schemas for the database.
-	 *
-	 * @return List with the schema names, empty Array if none found.
-	 */
-	public List<String> loadSchemas() throws SQLException {
-
-		try (ResultSet rs = getMetaData().getSchemas()) {
-			return getStrings(rs);
-		}
-	}
-
-	private static List<String> getStrings(ResultSet rs) throws SQLException {
-		List<String> strings = new ArrayList<String>();
-
-		while (rs.next()) {
-			strings.add(rs.getString(1));
-		}
-
-		return strings;
-	}
-
-	/**
-	 * Returns all the table types for the given database. Types may be such as
-	 * Typical types are "TABLE", "VIEW", "SYSTEM TABLE", "GLOBAL TEMPORARY",
-	 * "LOCAL TEMPORARY", "ALIAS", "SYNONYM"., etc.
-	 *
-	 * @return List of Strings, empty array if nothing found.
-	 */
-	public List<String> getTableTypes() throws SQLException {
-		List<String> types = new ArrayList<String>();
-
-		try (ResultSet rs = getMetaData().getTableTypes();) {
-			while (rs.next()) {
-				types.add(rs.getString("TABLE_TYPE").trim());
-			}
-		}
-
-		return types;
-	}
-
-	/**
-	 * Creates an ObjEntity for each DbEntity in the map.
-	 */
-	public Collection<ObjEntity> loadObjEntities(DataMap map, DbLoaderConfiguration config,
-			Collection<DbEntity> entities) {
-		Collection<ObjEntity> loadedEntities = DbLoader.loadObjEntities(map, config, entities, nameGenerator);
-
-		createEntityMerger(map).synchronizeWithDbEntities(loadedEntities);
-
-		return loadedEntities;
-	}
-
-	public static Collection<ObjEntity> loadObjEntities(DataMap map, DbLoaderConfiguration config,
-			Collection<DbEntity> entities, ObjectNameGenerator nameGenerator) {
-		if (entities.isEmpty()) {
-			return Collections.emptyList();
-		}
-
-		Collection<ObjEntity> loadedEntities = new ArrayList<ObjEntity>(entities.size());
-
-		// doLoad empty ObjEntities for all the tables
-		for (DbEntity dbEntity : entities) {
-
-			// check if there are existing entities
-
-			// TODO: performance. This is an O(n^2) search and it shows on
-			// YourKit profiles. Pre-cache mapped entities perhaps (?)
-			Collection<ObjEntity> existing = map.getMappedEntities(dbEntity);
-			if (!existing.isEmpty()) {
-				loadedEntities.addAll(existing);
-				continue;
-			}
-
-			String objEntityName = DefaultUniqueNameGenerator.generate(NameCheckers.objEntity, map,
-					nameGenerator.createObjEntityName(dbEntity));
-
-			ObjEntity objEntity = new ObjEntity(objEntityName);
-			objEntity.setDbEntity(dbEntity);
-			objEntity.setClassName(config.getGenericClassName() != null ? config.getGenericClassName() : map
-					.getNameWithDefaultPackage(objEntity.getName()));
-
-			map.addObjEntity(objEntity);
-			loadedEntities.add(objEntity);
-		}
-
-		return loadedEntities;
-	}
-
-	/**
-	 * @since 4.0
-	 */
-	protected EntityMergeSupport createEntityMerger(DataMap map) {
-		return new EntityMergeSupport(map, nameGenerator, !creatingMeaningfulPK);
-	}
-
-	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.pkCatalog)
-					.append(pkEntity.getSchema(), key.pkSchema).append(fkEntity.getCatalog(), key.fkCatalog)
-					.append(fkEntity.getSchema(), key.fkSchema).isEquals()) {
-
-				LOGGER.info("Skip relation: '" + key + "' because it related to objects from other catalog/schema");
-				LOGGER.info("     relation primary key: '" + key.pkCatalog + "." + key.pkSchema + "'");
-				LOGGER.info("       primary key entity: '" + pkEntity.getCatalog() + "." + pkEntity.getSchema() + "'");
-				LOGGER.info("     relation foreign key: '" + key.fkCatalog + "." + key.fkSchema + "'");
-				LOGGER.info("       foreign key entity: '" + fkEntity.getCatalog() + "." + fkEntity.getSchema() + "'");
-				continue;
-			}
-
-			// forwardRelationship is a reference from table with primary key
-			DbRelationship forwardRelationship = new DbRelationship(generateName(pkEntity, key, true));
-			forwardRelationship.setSourceEntity(pkEntity);
-			forwardRelationship.setTargetEntityName(fkEntity);
-
-			// forwardRelationship is a reference from table with foreign key,
-			// it is what exactly we load from db
-			DbRelationshipDetected reverseRelationship = new DbRelationshipDetected(generateName(fkEntity, key, false));
-			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);
-			forwardRelationship.setName(generateName(pkEntity, key, !isOneToOne));
-
-			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, DbRelationshipDetected 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) {
-		// if (LOGGER.isDebugEnabled()) {
-		LOGGER.info("Skip relation: '" + key + "' because table '" + tableName + "' not found");
-		// }
-	}
-
-	private String generateName(DbEntity entity, ExportedKey key, boolean toMany) {
-		String forwardPreferredName = nameGenerator.createDbRelationshipName(key, toMany);
-		return DefaultUniqueNameGenerator.generate(NameCheckers.dbRelationship, entity, forwardPreferredName);
-	}
-
-	/**
-	 * Flattens many-to-many relationships in the generated model.
-	 */
-	public static void flattenManyToManyRelationships(DataMap map, Collection<ObjEntity> loadedObjEntities,
-			ObjectNameGenerator objectNameGenerator) {
-		if (loadedObjEntities.isEmpty()) {
-			return;
-		}
-		Collection<ObjEntity> entitiesForDelete = new LinkedList<ObjEntity>();
-
-		for (ObjEntity curEntity : loadedObjEntities) {
-			ManyToManyCandidateEntity entity = ManyToManyCandidateEntity.build(curEntity);
-
-			if (entity != null) {
-				entity.optimizeRelationships(objectNameGenerator);
-				entitiesForDelete.add(curEntity);
-			}
-		}
-
-		// remove needed entities
-		for (ObjEntity curDeleteEntity : entitiesForDelete) {
-			map.removeObjEntity(curDeleteEntity.getName(), true);
-		}
-		loadedObjEntities.removeAll(entitiesForDelete);
-	}
-
-	private void fireObjEntitiesAddedEvents(Collection<ObjEntity> loadedObjEntities) {
-		for (ObjEntity curEntity : loadedObjEntities) {
-			// notify delegate
-			if (delegate != null) {
-				delegate.objEntityAdded(curEntity);
-			}
-		}
-	}
-
-	/**
-	 * By default we want to load Tables and Views for mo types
-	 *
-	 * @see DbLoader#getTableTypes()
-	 * @since 4.0
-	 */
-	public String[] getDefaultTableTypes() {
-		List<String> list = new ArrayList<String>(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 the specified config and
-	 * fills the specified DataMap object with DB and object mapping info.
-	 *
-	 * @since 4.0
-	 */
-	public void load(DataMap dataMap, DbLoaderConfiguration config) throws SQLException {
-		LOGGER.info("Schema loading...");
-
-		String[] types = config.getTableTypes();
-		if (types == null || types.length == 0) {
-			types = getDefaultTableTypes();
-		}
-
-		for (CatalogFilter catalog : config.getFiltersConfig().catalogs) {
-			for (SchemaFilter schema : catalog.schemas) {
-
-				List<DbEntity> entities = createTableLoader(catalog.name, schema.name, schema.tables).loadDbEntities(
-						dataMap, config, types);
-
-				if (entities != null) {
-					loadDbRelationships(config, catalog.name, schema.name, entities);
-
-					prepareObjLayer(dataMap, config, 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));
-	}
-
-	private void prepareObjLayer(DataMap dataMap, DbLoaderConfiguration config, Collection<DbEntity> entities) {
-		Collection<ObjEntity> loadedObjEntities = loadObjEntities(dataMap, config, entities);
-		flattenManyToManyRelationships(dataMap, loadedObjEntities, nameGenerator);
-		fireObjEntitiesAddedEvents(loadedObjEntities);
-	}
-
-	/**
-	 * Performs database reverse engineering to match the specified catalog,
-	 * schema, table name and table type patterns and fills the specified
-	 * DataMap object with DB and object mapping info.
-	 *
-	 * @since 4.0
-	 */
-	public DataMap load(DbLoaderConfiguration config) throws SQLException {
-
-		DataMap dataMap = new DataMap();
-		load(dataMap, config);
-		loadProcedures(dataMap, config);
-
-		return dataMap;
-	}
-
-	/**
-	 * 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
-	 */
-	public 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().catalogs) {
-			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 s = columnsRS.getString("PROCEDURE_SCHEM");
-				String name = columnsRS.getString("PROCEDURE_NAME");
-				String key = (s == null ? "" : s + '.') + 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 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;
-		}
-	}
-
-	private Map<String, Procedure> loadProcedures(DbLoaderConfiguration config) throws SQLException {
-		Map<String, Procedure> procedures = new HashMap<>();
-
-		FiltersConfig filters = config.getFiltersConfig();
-		for (CatalogFilter catalog : filters.catalogs) {
-			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()).isInclude(
-						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;
-	}
-
-	/**
-	 * Sets new naming strategy for reverse engineering
-	 *
-	 * @since 3.0
-	 */
-	public void setNameGenerator(ObjectNameGenerator strategy) {
-		if (strategy == null) {
-			LOGGER.warn("Attempt to set null into NameGenerator. LegacyNameGenerator will be used.");
-			this.nameGenerator = new LegacyNameGenerator();
-		} else {
-			this.nameGenerator = strategy;
-		}
-	}
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cayenne/blob/cf172fc9/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/DbLoaderConfiguration.java
----------------------------------------------------------------------
diff --git a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/DbLoaderConfiguration.java b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/DbLoaderConfiguration.java
deleted file mode 100644
index e5421fe..0000000
--- a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/DbLoaderConfiguration.java
+++ /dev/null
@@ -1,150 +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;
-
-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 {
-
-    /**
-     * Returns a name of a generic class that should be used for all
-     * ObjEntities. The most common generic class is
-     * {@link org.apache.cayenne.CayenneDataObject}. If generic class name is
-     * null (which is the default), DbLoader will assign each entity a unique
-     * class name derived from the table name.
-     *
-     */
-    private String genericClassName;
-
-/*
-    // TODO: Andrus, 10/29/2005 - this type of filtering should be delegated to adapter
-       TODO by default should skip name.startsWith("BIN$")
-
-    private NameFilter tableFilter = NamePatternMatcher.build(null, null, "BIN$");
-
-    private NameFilter columnFilter;
-
-    private NameFilter proceduresFilter = new NameFilter() {
-        private final Collection<String> excludedProcedures = Arrays.asList(
-                "auto_pk_for_table",
-                "auto_pk_for_table;1" // the last name is some Mac OS X Sybase artifact
-        );
-
-        @Override
-        public boolean isIncluded(String string) {
-            return !excludedProcedures.contains(string);
-        }
-    };
-*/
-
-
-    /**
-     * Java class implementing org.apache.cayenne.map.naming.NamingStrategy.
-     * This is used to specify how ObjEntities will be mapped from the imported
-     * DB schema.
-     */
-    private String namingStrategy;
-
-    private Boolean skipRelationshipsLoading;
-
-    private Boolean skipPrimaryKeyLoading;
-
-    private String[] tableTypes;
-
-    private FiltersConfig filtersConfig;
-
-    public String getGenericClassName() {
-        return genericClassName;
-    }
-
-    public void setGenericClassName(String genericClassName) {
-        this.genericClassName = genericClassName;
-    }
-
-    public String[] getTableTypes() {
-        return tableTypes;
-    }
-
-    public void setTableTypes(String[] tableTypes) {
-        this.tableTypes = tableTypes;
-    }
-
-    public String getNamingStrategy() {
-        return namingStrategy;
-    }
-
-    public void setNamingStrategy(String namingStrategy) {
-        this.namingStrategy = namingStrategy;
-    }
-
-    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 Boolean getSkipRelationshipsLoading() {
-        return skipRelationshipsLoading;
-    }
-
-    public void setSkipRelationshipsLoading(Boolean skipRelationshipsLoading) {
-        this.skipRelationshipsLoading = skipRelationshipsLoading;
-    }
-
-    public void setSkipPrimaryKeyLoading(Boolean skipPrimaryKeyLoading) {
-        this.skipPrimaryKeyLoading = skipPrimaryKeyLoading;
-    }
-
-    public boolean getSkipPrimaryKeyLoading() {
-        return skipPrimaryKeyLoading;
-    }
-
-    public boolean isSkipPrimaryKeyLoading() {
-        return skipPrimaryKeyLoading != null && 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/cf172fc9/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/DbLoaderDelegate.java
----------------------------------------------------------------------
diff --git a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/DbLoaderDelegate.java b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/DbLoaderDelegate.java
deleted file mode 100644
index 35a61fb..0000000
--- a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/DbLoaderDelegate.java
+++ /dev/null
@@ -1,58 +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;
-
-import org.apache.cayenne.map.DbEntity;
-import org.apache.cayenne.map.DbRelationship;
-import org.apache.cayenne.map.ObjEntity;
-
-/**
- * DbLoaderDelegate defines API that allows to control the behavior of DbLoader
- * during the database reverse-engineering. Delegate is also notified of the
- * progress of reverse-engineering.
- */
-public interface DbLoaderDelegate {
-
-    void dbEntityAdded(DbEntity entity);
-
-    void dbEntityRemoved(DbEntity entity);
-
-    /**
-     * Called before relationship loading for db-entity
-     * @param entity
-     *
-     * @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);
-
-    void objEntityAdded(ObjEntity entity);
-
-    void objEntityRemoved(ObjEntity entity);
-}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/cf172fc9/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/DbTableLoader.java
----------------------------------------------------------------------
diff --git a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/DbTableLoader.java b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/DbTableLoader.java
deleted file mode 100644
index 0d12e64..0000000
--- a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/DbTableLoader.java
+++ /dev/null
@@ -1,195 +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;
-
-import java.sql.DatabaseMetaData;
-import java.sql.ResultSet;
-import java.sql.SQLException;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.LinkedList;
-import java.util.List;
-
-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.cayenne.map.ObjEntity;
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-
-/**
- * @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.
-	 * @return
-	 * @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<DbEntity>();
-		for (DbEntity dbEntity : tables) {
-			DbEntity oldEnt = map.getDbEntity(dbEntity.getName());
-			if (oldEnt != null) {
-				Collection<ObjEntity> oldObjEnt = map.getMappedEntities(oldEnt);
-				if (!oldObjEnt.isEmpty()) {
-					for (ObjEntity objEntity : oldObjEnt) {
-						LOGGER.debug("Delete ObjEntity: " + objEntity.getName());
-						map.removeObjEntity(objEntity.getName(), true);
-						delegate.objEntityRemoved(objEntity);
-					}
-				}
-
-				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/cf172fc9/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/DefaultDbLoaderDelegate.java
----------------------------------------------------------------------
diff --git a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/DefaultDbLoaderDelegate.java b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/DefaultDbLoaderDelegate.java
deleted file mode 100644
index b39fd5f..0000000
--- a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/DefaultDbLoaderDelegate.java
+++ /dev/null
@@ -1,59 +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;
-
-import org.apache.cayenne.map.DbEntity;
-import org.apache.cayenne.map.DbRelationship;
-import org.apache.cayenne.map.ObjEntity;
-
-/**
- * @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;
-    }
-
-    @Override
-    public void objEntityAdded(ObjEntity entity) {
-
-    }
-
-    @Override
-    public void objEntityRemoved(ObjEntity entity) {
-
-    }
-}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/cf172fc9/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/FiltersConfigBuilder.java
----------------------------------------------------------------------
diff --git a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/FiltersConfigBuilder.java b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/FiltersConfigBuilder.java
index 390d91a..2035f44 100644
--- a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/FiltersConfigBuilder.java
+++ b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/FiltersConfigBuilder.java
@@ -42,7 +42,7 @@ import java.util.regex.Pattern;
 import static org.apache.commons.lang.StringUtils.isBlank;
 
 /**
- * @since 4.0.
+ * @since 4.0
  */
 public final class FiltersConfigBuilder {
 
@@ -52,7 +52,7 @@ public final class FiltersConfigBuilder {
         this.engineering = engineering;
     }
 
-    public FiltersConfig filtersConfig() {
+    public FiltersConfig build() {
         compact();
 
         return new FiltersConfig(transformCatalogs(engineering.getCatalogs()));
@@ -120,6 +120,7 @@ public final class FiltersConfigBuilder {
     /**
      * Goal of this method transform ReverseEngineering config into more regular form
      * From
+     * <pre>
      *      ReverseEngineering
      *          Catalog
      *              Schema
@@ -156,9 +157,10 @@ public final class FiltersConfigBuilder {
      *          ExcludeProcedures
      *          IncludeColumn
      *          ExcludeColumn
-     *
+     * </pre>
      * Into
-     *      ReverseEngineering
+     * <pre>
+     *  ReverseEngineering
      *          Catalog
      *              Schema
      *                  IncludeTable
@@ -167,10 +169,9 @@ public final class FiltersConfigBuilder {
      *                  ExcludeTable
      *                  IncludeProcedures
      *                  ExcludeProcedures
-     *
-     *
-     * */
-    public void compact() {
+     * </pre>
+     */
+    void compact() {
         addEmptyElements();
 
         compactColumnFilters();

http://git-wip-us.apache.org/repos/asf/cayenne/blob/cf172fc9/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/LoggingDbLoaderDelegate.java
----------------------------------------------------------------------
diff --git a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/LoggingDbLoaderDelegate.java b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/LoggingDbLoaderDelegate.java
deleted file mode 100644
index 3777ccc..0000000
--- a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/LoggingDbLoaderDelegate.java
+++ /dev/null
@@ -1,76 +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;
-
-import org.apache.cayenne.map.DbEntity;
-import org.apache.cayenne.map.DbRelationship;
-import org.apache.cayenne.map.ObjEntity;
-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;
-    }
-
-    @Override
-    public void objEntityAdded(ObjEntity entity) {
-        if (logger.isDebugEnabled()) {
-            logger.debug("  Class: " + entity.getName());
-        }
-    }
-
-    @Override
-    public void objEntityRemoved(ObjEntity entity) {
-        if (logger.isDebugEnabled()) {
-            logger.debug("  Class removed: " + entity.getName());
-        }
-    }
-}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/cf172fc9/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/ManyToManyCandidateEntity.java
----------------------------------------------------------------------
diff --git a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/ManyToManyCandidateEntity.java b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/ManyToManyCandidateEntity.java
deleted file mode 100644
index 9666e08..0000000
--- a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/ManyToManyCandidateEntity.java
+++ /dev/null
@@ -1,142 +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;
-
-import org.apache.cayenne.map.DbRelationship;
-import org.apache.cayenne.map.ObjEntity;
-import org.apache.cayenne.map.ObjRelationship;
-import org.apache.cayenne.map.naming.DefaultUniqueNameGenerator;
-import org.apache.cayenne.map.naming.ExportedKey;
-import org.apache.cayenne.map.naming.NameCheckers;
-import org.apache.cayenne.map.naming.ObjectNameGenerator;
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * Class represent ObjEntity that may be optimized using flattened relationships
- * as many to many table
- */
-public class ManyToManyCandidateEntity {
-
-    private static final Log LOG = LogFactory.getLog(ManyToManyCandidateEntity.class);
-
-    private final ObjEntity joinEntity;
-
-    private final DbRelationship dbRel1;
-    private final DbRelationship dbRel2;
-
-    private final ObjEntity entity1;
-    private final ObjEntity entity2;
-
-    private final DbRelationship reverseRelationship1;
-    private final DbRelationship reverseRelationship2;
-
-    private ManyToManyCandidateEntity(ObjEntity entityValue, List<ObjRelationship> relationships) {
-        joinEntity = entityValue;
-
-        ObjRelationship rel1 = relationships.get(0);
-        ObjRelationship rel2 = relationships.get(1);
-
-        dbRel1 = rel1.getDbRelationships().get(0);
-        dbRel2 = rel2.getDbRelationships().get(0);
-
-        reverseRelationship1 = dbRel1.getReverseRelationship();
-        reverseRelationship2 = dbRel2.getReverseRelationship();
-
-        entity1 = rel1.getTargetEntity();
-        entity2 = rel2.getTargetEntity();
-    }
-
-    /**
-     * Method check - if current entity represent many to many temporary table
-     * @return true if current entity is represent many to many table; otherwise returns false
-     */
-    public static ManyToManyCandidateEntity build(ObjEntity joinEntity) {
-        ArrayList<ObjRelationship> relationships = new ArrayList<ObjRelationship>(joinEntity.getRelationships());
-        if (relationships.size() != 2 || (relationships.get(0).getDbRelationships().isEmpty() || relationships.get(1).getDbRelationships().isEmpty())) {
-            return null;
-        }
-
-        ManyToManyCandidateEntity candidateEntity = new ManyToManyCandidateEntity(joinEntity, relationships);
-        if (candidateEntity.isManyToMany()) {
-            return candidateEntity;
-        }
-
-        return null;
-    }
-
-    private boolean isManyToMany() {
-        boolean isNotHaveAttributes = joinEntity.getAttributes().size() == 0;
-
-        return isNotHaveAttributes
-                && reverseRelationship1 != null && reverseRelationship1.isToDependentPK()
-                && reverseRelationship2 != null && reverseRelationship2.isToDependentPK()
-                && entity1 != null && entity2 != null;
-    }
-
-    private void addFlattenedRelationship(ObjectNameGenerator nameGenerator, ObjEntity srcEntity, ObjEntity dstEntity,
-                                          DbRelationship rel1, DbRelationship rel2) {
-
-        if (rel1.getSourceAttributes().isEmpty() && rel2.getTargetAttributes().isEmpty()) {
-            LOG.warn("Wrong call ManyToManyCandidateEntity.addFlattenedRelationship(... , " + srcEntity.getName()
-                    + ", " + dstEntity.getName() + ", ...)");
-
-            return;
-        }
-
-        ExportedKey key = new ExportedKey(
-                rel1.getSourceEntity().getName(),
-                rel1.getSourceAttributes().iterator().next().getName(),
-                null,
-                rel2.getTargetEntity().getName(),
-                rel2.getTargetAttributes().iterator().next().getName(),
-                null,
-                (short) 1);
-
-        ObjRelationship newRelationship = new ObjRelationship();
-        newRelationship.setName(DefaultUniqueNameGenerator.generate(NameCheckers.objRelationship, srcEntity,
-                nameGenerator.createDbRelationshipName(key, true)));
-
-        newRelationship.setSourceEntity(srcEntity);
-        newRelationship.setTargetEntityName(dstEntity);
-
-        newRelationship.addDbRelationship(rel1);
-        newRelationship.addDbRelationship(rel2);
-
-        srcEntity.addRelationship(newRelationship);
-    }
-
-    /**
-     * Method make direct relationships between 2 entities and remove relationships to
-     * many to many entity
-     *
-     * @param nameGenerator
-     */
-    public void optimizeRelationships(ObjectNameGenerator nameGenerator) {
-        entity1.removeRelationship(reverseRelationship1.getName());
-        entity2.removeRelationship(reverseRelationship2.getName());
-
-        addFlattenedRelationship(nameGenerator, entity1, entity2, reverseRelationship1, dbRel2);
-        addFlattenedRelationship(nameGenerator, entity2, entity1, reverseRelationship2, dbRel1);
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/cf172fc9/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
new file mode 100644
index 0000000..591d8b5
--- /dev/null
+++ b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/db/DbAttributesBaseLoader.java
@@ -0,0 +1,107 @@
+/*****************************************************************
+ *   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/cf172fc9/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
new file mode 100644
index 0000000..fb342c9
--- /dev/null
+++ b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/db/DbAttributesLoader.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.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/cf172fc9/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
new file mode 100644
index 0000000..cd26db7
--- /dev/null
+++ b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/db/DbAttributesPerSchemaLoader.java
@@ -0,0 +1,130 @@
+/*****************************************************************
+ *   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 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;
+
+import org.apache.cayenne.dbsync.reverse.filters.PatternFilter;
+import org.apache.cayenne.dbsync.reverse.filters.TableFilter;
+import org.apache.cayenne.dba.DbAdapter;
+import org.apache.cayenne.map.DbAttribute;
+
+/**
+ * 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");
+
+				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.isInclude(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;
+	}
+}