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;
+ }
+}