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:52 UTC
[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
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;
+ }
+}