CAY-2215 move all DbImport code from cayenne-tools and cayenne-server modules to cayenne-dbsync module
Project: http://git-wip-us.apache.org/repos/asf/cayenne/repo Commit: http://git-wip-us.apache.org/repos/asf/cayenne/commit/660dd4b2 Tree: http://git-wip-us.apache.org/repos/asf/cayenne/tree/660dd4b2 Diff: http://git-wip-us.apache.org/repos/asf/cayenne/diff/660dd4b2 Branch: refs/heads/master Commit: 660dd4b28635edea0f52a279c51f1da34d198ecc Parents: 67bf710 Author: Nikita Timofeev <stari...@gmail.com> Authored: Wed Feb 1 12:26:29 2017 +0300 Committer: Nikita Timofeev <stari...@gmail.com> Committed: Wed Feb 1 12:26:29 2017 +0300 ---------------------------------------------------------------------- cayenne-dbsync/pom.xml | 8 +- .../configuration/DriverDataSourceFactory.java | 54 +++ .../reverse/configuration/ToolsModule.java | 107 +++++ .../reverse/dbimport/AntNestedElement.java | 43 ++ .../dbsync/reverse/dbimport/Catalog.java | 39 ++ .../dbsync/reverse/dbimport/DbImportAction.java | 30 ++ .../reverse/dbimport/DbImportConfiguration.java | 302 +++++++++++++ .../DbImportConfigurationValidator.java | 78 ++++ .../dbsync/reverse/dbimport/DbImportModule.java | 46 ++ .../reverse/dbimport/DefaultDbImportAction.java | 422 +++++++++++++++++++ .../dbsync/reverse/dbimport/ExcludeColumn.java | 32 ++ .../reverse/dbimport/ExcludeProcedure.java | 32 ++ .../dbsync/reverse/dbimport/ExcludeTable.java | 32 ++ .../reverse/dbimport/FilterContainer.java | 172 ++++++++ .../dbsync/reverse/dbimport/IncludeColumn.java | 32 ++ .../reverse/dbimport/IncludeProcedure.java | 32 ++ .../dbsync/reverse/dbimport/IncludeTable.java | 84 ++++ .../dbimport/ManyToManyCandidateEntity.java | 134 ++++++ .../dbsync/reverse/dbimport/PatternParam.java | 83 ++++ .../reverse/dbimport/ReverseEngineering.java | 210 +++++++++ .../cayenne/dbsync/reverse/dbimport/Schema.java | 39 ++ .../reverse/dbimport/SchemaContainer.java | 67 +++ .../dbsync/reverse/dbimport/package-info.java | 24 ++ .../reverse/filters/FiltersConfigBuilder.java | 20 +- .../reverse/configuration/ToolsModuleTest.java | 66 +++ .../reverse/dbimport/DbImportModuleTest.java | 41 ++ .../dbimport/DefaultDbImportActionTest.java | 356 ++++++++++++++++ .../dbimport/ManyToManyCandidateEntityTest.java | 116 +++++ .../dbimport/ReverseEngineeringUtils.java | 174 ++++++++ .../filters/FiltersConfigBuilderTest.java | 19 +- .../dbsync/reverse/filters/TableFilterTest.java | 1 - .../cayenne-relationship-optimisation.xml | 4 + .../dbimport/relationship-optimisation.map.xml | 43 ++ .../cayenne/dbimport/AntNestedElement.java | 42 -- .../org/apache/cayenne/dbimport/Catalog.java | 38 -- .../apache/cayenne/dbimport/ExcludeColumn.java | 31 -- .../cayenne/dbimport/ExcludeProcedure.java | 31 -- .../apache/cayenne/dbimport/ExcludeTable.java | 31 -- .../cayenne/dbimport/FilterContainer.java | 171 -------- .../apache/cayenne/dbimport/IncludeColumn.java | 31 -- .../cayenne/dbimport/IncludeProcedure.java | 31 -- .../apache/cayenne/dbimport/IncludeTable.java | 83 ---- .../apache/cayenne/dbimport/PatternParam.java | 82 ---- .../cayenne/dbimport/ReverseEngineering.java | 210 --------- .../org/apache/cayenne/dbimport/Schema.java | 38 -- .../cayenne/dbimport/SchemaContainer.java | 67 --- .../apache/cayenne/dbimport/package-info.java | 24 -- .../dbimport/ReverseEngineeringUtils.java | 173 -------- .../apache/cayenne/tools/DbGeneratorTask.java | 2 +- .../tools/DbImportConfigurationValidator.java | 77 ---- .../apache/cayenne/tools/DbImporterTask.java | 34 +- .../configuration/DriverDataSourceFactory.java | 53 --- .../tools/configuration/ToolsModule.java | 106 ----- .../cayenne/tools/dbimport/DbImportAction.java | 30 -- .../tools/dbimport/DbImportConfiguration.java | 302 ------------- .../cayenne/tools/dbimport/DbImportModule.java | 47 --- .../tools/dbimport/DefaultDbImportAction.java | 422 ------------------- .../dbimport/ManyToManyCandidateEntity.java | 133 ------ .../cayenne/tools/DbGeneratorTaskTest.java | 2 +- .../cayenne/tools/DbImporterTaskTest.java | 4 +- .../tools/configuration/ToolsModuleTest.java | 65 --- .../tools/dbimport/DbImportModuleTest.java | 40 -- .../dbimport/DefaultDbImportActionTest.java | 356 ---------------- .../dbimport/ManyToManyCandidateEntityTest.java | 115 ----- .../cayenne-relationship-optimisation.xml | 4 - .../dbimport/relationship-optimisation.map.xml | 43 -- .../modeler/dialog/db/load/DbLoaderContext.java | 14 +- .../modeler/dialog/db/load/LoadDataMapTask.java | 6 +- .../dialog/db/load/ModelerDbImportAction.java | 4 +- .../dialog/db/load/ModelerSyncModule.java | 2 +- .../modeler/dialog/db/merge/MergerOptions.java | 12 +- plugins/cayenne-maven-plugin/pom.xml | 2 +- .../apache/cayenne/tools/DbGeneratorMojo.java | 2 +- .../apache/cayenne/tools/DbImporterMojo.java | 11 +- .../tools/DbImporterMojoConfigurationTest.java | 8 +- .../cayenne/tools/DbImporterMojoTest.java | 8 +- plugins/maven-cayenne-plugin/pom.xml | 2 +- .../DbImporterOldMojoConfigurationTest.java | 8 +- 78 files changed, 2980 insertions(+), 2959 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/cayenne/blob/660dd4b2/cayenne-dbsync/pom.xml ---------------------------------------------------------------------- diff --git a/cayenne-dbsync/pom.xml b/cayenne-dbsync/pom.xml index 951babf..d94de3f 100644 --- a/cayenne-dbsync/pom.xml +++ b/cayenne-dbsync/pom.xml @@ -36,12 +36,18 @@ <artifactId>cayenne-server</artifactId> <version>${project.version}</version> </dependency> + <dependency> + <groupId>org.apache.cayenne</groupId> + <artifactId>cayenne-project</artifactId> + <version>${project.version}</version> + <scope>compile</scope> + </dependency> <dependency> <groupId>net.java.dev.inflector</groupId> <artifactId>inflector</artifactId> <scope>compile</scope> </dependency> - + <!-- Test dependencies --> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> http://git-wip-us.apache.org/repos/asf/cayenne/blob/660dd4b2/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/configuration/DriverDataSourceFactory.java ---------------------------------------------------------------------- diff --git a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/configuration/DriverDataSourceFactory.java b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/configuration/DriverDataSourceFactory.java new file mode 100644 index 0000000..d24f367 --- /dev/null +++ b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/configuration/DriverDataSourceFactory.java @@ -0,0 +1,54 @@ +/***************************************************************** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + ****************************************************************/ + +package org.apache.cayenne.dbsync.reverse.configuration; + +import java.sql.Driver; + +import javax.sql.DataSource; + +import org.apache.cayenne.configuration.DataNodeDescriptor; +import org.apache.cayenne.configuration.server.DataSourceFactory; +import org.apache.cayenne.conn.DataSourceInfo; +import org.apache.cayenne.datasource.DriverDataSource; +import org.apache.cayenne.di.AdhocObjectFactory; +import org.apache.cayenne.di.Inject; + +/** + * @since 4.0 + */ +public class DriverDataSourceFactory implements DataSourceFactory { + + private AdhocObjectFactory objectFactory; + + public DriverDataSourceFactory(@Inject AdhocObjectFactory objectFactory) { + this.objectFactory = objectFactory; + } + + public DataSource getDataSource(DataNodeDescriptor nodeDescriptor) throws Exception { + DataSourceInfo properties = nodeDescriptor.getDataSourceDescriptor(); + if (properties == null) { + throw new IllegalArgumentException("'nodeDescriptor' contains no datasource descriptor"); + } + + Driver driver = objectFactory.newInstance(Driver.class, properties.getJdbcDriver()); + return new DriverDataSource(driver, properties.getDataSourceUrl(), properties.getUserName(), + properties.getPassword()); + } +} http://git-wip-us.apache.org/repos/asf/cayenne/blob/660dd4b2/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/configuration/ToolsModule.java ---------------------------------------------------------------------- diff --git a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/configuration/ToolsModule.java b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/configuration/ToolsModule.java new file mode 100644 index 0000000..bc5762e --- /dev/null +++ b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/configuration/ToolsModule.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.configuration; + +import org.apache.cayenne.access.translator.batch.BatchTranslatorFactory; +import org.apache.cayenne.access.translator.batch.DefaultBatchTranslatorFactory; +import org.apache.cayenne.configuration.Constants; +import org.apache.cayenne.configuration.DefaultRuntimeProperties; +import org.apache.cayenne.configuration.RuntimeProperties; +import org.apache.cayenne.configuration.server.DataSourceFactory; +import org.apache.cayenne.configuration.server.DbAdapterFactory; +import org.apache.cayenne.configuration.server.DefaultDbAdapterFactory; +import org.apache.cayenne.configuration.server.ServerModule; +import org.apache.cayenne.dba.db2.DB2Sniffer; +import org.apache.cayenne.dba.derby.DerbySniffer; +import org.apache.cayenne.dba.firebird.FirebirdSniffer; +import org.apache.cayenne.dba.frontbase.FrontBaseSniffer; +import org.apache.cayenne.dba.h2.H2Sniffer; +import org.apache.cayenne.dba.hsqldb.HSQLDBSniffer; +import org.apache.cayenne.dba.ingres.IngresSniffer; +import org.apache.cayenne.dba.mysql.MySQLSniffer; +import org.apache.cayenne.dba.openbase.OpenBaseSniffer; +import org.apache.cayenne.dba.oracle.OracleSniffer; +import org.apache.cayenne.dba.postgres.PostgresSniffer; +import org.apache.cayenne.dba.sqlite.SQLiteSniffer; +import org.apache.cayenne.dba.sqlserver.SQLServerSniffer; +import org.apache.cayenne.dba.sybase.SybaseSniffer; +import org.apache.cayenne.di.AdhocObjectFactory; +import org.apache.cayenne.di.Binder; +import org.apache.cayenne.di.ClassLoaderManager; +import org.apache.cayenne.di.Key; +import org.apache.cayenne.di.Module; +import org.apache.cayenne.di.spi.DefaultAdhocObjectFactory; +import org.apache.cayenne.di.spi.DefaultClassLoaderManager; +import org.apache.cayenne.log.CommonsJdbcEventLogger; +import org.apache.cayenne.log.JdbcEventLogger; +import org.apache.cayenne.resource.ClassLoaderResourceLocator; +import org.apache.cayenne.resource.ResourceLocator; +import org.apache.commons.logging.Log; + +/** + * A DI module to bootstrap DI container for Cayenne Ant tasks and Maven + * plugins. + * + * @since 4.0 + */ +public class ToolsModule implements Module { + + private Log logger; + + public ToolsModule(Log logger) { + + if (logger == null) { + throw new NullPointerException("Null logger"); + } + + this.logger = logger; + } + + public void configure(Binder binder) { + + binder.bind(Log.class).toInstance(logger); + + // configure empty global stack properties + ServerModule.contributeProperties(binder); + + ServerModule.contributeDefaultTypes(binder); + ServerModule.contributeUserTypes(binder); + ServerModule.contributeTypeFactories(binder); + + binder.bind(ClassLoaderManager.class).to(DefaultClassLoaderManager.class); + binder.bind(AdhocObjectFactory.class).to(DefaultAdhocObjectFactory.class); + binder.bind(ResourceLocator.class).to(ClassLoaderResourceLocator.class); + binder.bind(Key.get(ResourceLocator.class, Constants.SERVER_RESOURCE_LOCATOR)).to(ClassLoaderResourceLocator.class); + + binder.bind(RuntimeProperties.class).to(DefaultRuntimeProperties.class); + binder.bind(BatchTranslatorFactory.class).to(DefaultBatchTranslatorFactory.class); + binder.bind(JdbcEventLogger.class).to(CommonsJdbcEventLogger.class); + + ServerModule.contributeAdapterDetectors(binder).add(FirebirdSniffer.class).add(OpenBaseSniffer.class) + .add(FrontBaseSniffer.class).add(IngresSniffer.class).add(SQLiteSniffer.class).add(DB2Sniffer.class) + .add(H2Sniffer.class).add(HSQLDBSniffer.class).add(SybaseSniffer.class).add(DerbySniffer.class) + .add(SQLServerSniffer.class).add(OracleSniffer.class).add(PostgresSniffer.class) + .add(MySQLSniffer.class); + + binder.bind(DbAdapterFactory.class).to(DefaultDbAdapterFactory.class); + binder.bind(DataSourceFactory.class).to(DriverDataSourceFactory.class); + } + +} http://git-wip-us.apache.org/repos/asf/cayenne/blob/660dd4b2/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbimport/AntNestedElement.java ---------------------------------------------------------------------- diff --git a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbimport/AntNestedElement.java b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbimport/AntNestedElement.java new file mode 100644 index 0000000..3964e07 --- /dev/null +++ b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbimport/AntNestedElement.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.dbimport; + +/** + * Additional class to handle <name> element under <catalog> and <schema> + * required for ant configuration + * + * @since 4.0. + */ +public class AntNestedElement { + + private String name; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public void addText(String str) { + name = str; + } +} http://git-wip-us.apache.org/repos/asf/cayenne/blob/660dd4b2/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbimport/Catalog.java ---------------------------------------------------------------------- diff --git a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbimport/Catalog.java b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbimport/Catalog.java new file mode 100644 index 0000000..3ed8755 --- /dev/null +++ b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbimport/Catalog.java @@ -0,0 +1,39 @@ +/***************************************************************** + * 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.dbimport; + +/** + * @since 4.0. + */ +public class Catalog extends SchemaContainer { + + public Catalog() { + } + + public Catalog(String name) { + setName(name); + } + + @Override + public StringBuilder toString(StringBuilder res, String prefix) { + res.append(prefix).append("Catalog: ").append(getName()).append("\n"); + return super.toString(res, prefix + " "); + } +} http://git-wip-us.apache.org/repos/asf/cayenne/blob/660dd4b2/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbimport/DbImportAction.java ---------------------------------------------------------------------- diff --git a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbimport/DbImportAction.java b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbimport/DbImportAction.java new file mode 100644 index 0000000..88f92c6 --- /dev/null +++ b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbimport/DbImportAction.java @@ -0,0 +1,30 @@ +/***************************************************************** + * 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.dbimport; + +/** + * An API of a strategy that can load DB schema and merge it to a new or an existing DataMap. + * + * @since 4.0 + */ +public interface DbImportAction { + + void execute(DbImportConfiguration config) throws Exception; + +} http://git-wip-us.apache.org/repos/asf/cayenne/blob/660dd4b2/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbimport/DbImportConfiguration.java ---------------------------------------------------------------------- diff --git a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbimport/DbImportConfiguration.java b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbimport/DbImportConfiguration.java new file mode 100644 index 0000000..2e568cb --- /dev/null +++ b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbimport/DbImportConfiguration.java @@ -0,0 +1,302 @@ +/***************************************************************** + * 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.dbimport; + +import org.apache.cayenne.CayenneRuntimeException; +import org.apache.cayenne.configuration.DataNodeDescriptor; +import org.apache.cayenne.conn.DataSourceInfo; +import org.apache.cayenne.dba.DbAdapter; +import org.apache.cayenne.dbsync.filter.NameFilter; +import org.apache.cayenne.dbsync.filter.NamePatternMatcher; +import org.apache.cayenne.dbsync.reverse.dbload.DefaultModelMergeDelegate; +import org.apache.cayenne.dbsync.reverse.dbload.ModelMergeDelegate; +import org.apache.cayenne.dbsync.naming.DbEntityNameStemmer; +import org.apache.cayenne.dbsync.naming.DefaultObjectNameGenerator; +import org.apache.cayenne.dbsync.naming.NoStemStemmer; +import org.apache.cayenne.dbsync.naming.ObjectNameGenerator; +import org.apache.cayenne.dbsync.naming.PatternStemmer; +import org.apache.cayenne.dbsync.reverse.dbload.DbLoaderConfiguration; +import org.apache.cayenne.dbsync.reverse.dbload.DbLoaderDelegate; +import org.apache.cayenne.dbsync.reverse.dbload.DefaultDbLoaderDelegate; +import org.apache.cayenne.dbsync.reverse.dbload.LoggingDbLoaderDelegate; +import org.apache.cayenne.dbsync.reverse.filters.FiltersConfig; +import org.apache.commons.logging.Log; + +import java.io.File; +import java.util.regex.Pattern; + +/** + * @since 4.0 + */ +public class DbImportConfiguration { + + private static final String DATA_MAP_LOCATION_SUFFIX = ".map.xml"; + + private final DataSourceInfo dataSourceInfo; + private final DbLoaderConfiguration dbLoaderConfiguration; + private File targetDataMap; + private String defaultPackage; + private String meaningfulPkTables; + private String adapter; + private boolean usePrimitives; + private Log logger; + private String namingStrategy; + private String stripFromTableNames; + private boolean forceDataMapCatalog; + private boolean forceDataMapSchema; + + public DbImportConfiguration() { + this.dataSourceInfo = new DataSourceInfo(); + this.dbLoaderConfiguration = new DbLoaderConfiguration(); + } + + public String getStripFromTableNames() { + return stripFromTableNames; + } + + public void setStripFromTableNames(String stripFromTableNames) { + this.stripFromTableNames = stripFromTableNames; + } + + public Log getLogger() { + return logger; + } + + public void setLogger(Log logger) { + this.logger = logger; + } + + /** + * Returns DataMap XML file representing the target of the DB import operation. + */ + public File getTargetDataMap() { + return targetDataMap; + } + + public void setTargetDataMap(File map) { + this.targetDataMap = map; + } + + /** + * Returns a default package for ObjEntity Java classes. + */ + public String getDefaultPackage() { + return defaultPackage; + } + + public void setDefaultPackage(String defaultPackage) { + this.defaultPackage = defaultPackage; + } + + public String getNamingStrategy() { + return namingStrategy; + } + + public void setNamingStrategy(String namingStrategy) { + this.namingStrategy = namingStrategy; + } + + /** + * Returns the name of a Java class implementing {@link DbAdapter}. This attribute is optional, the default is + * {@link org.apache.cayenne.dba.AutoAdapter}, i.e. Cayenne will try to guess the DB type. + */ + public String getAdapter() { + return adapter; + } + + public void setAdapter(String adapter) { + this.adapter = adapter; + } + + /** + * Returns a comma-separated list of Perl5 regular expressions that match + * table names for which {@link DbImportAction} should include ObjAttribute + * for PK. + */ + public String getMeaningfulPkTables() { + return meaningfulPkTables; + } + + public void setMeaningfulPkTables(String meaningfulPkTables) { + this.meaningfulPkTables = meaningfulPkTables; + } + + public boolean isUsePrimitives() { + return usePrimitives; + } + + public void setUsePrimitives(boolean usePrimitives) { + this.usePrimitives = usePrimitives; + } + + public NameFilter createMeaningfulPKFilter() { + + if (meaningfulPkTables == null) { + return NamePatternMatcher.EXCLUDE_ALL; + } + + // TODO: this filter can't handle table names with comma in them + String[] patternStrings = meaningfulPkTables.split(","); + Pattern[] patterns = new Pattern[patternStrings.length]; + for (int i = 0; i < patterns.length; i++) { + patterns[i] = Pattern.compile(patternStrings[i]); + } + + return new NamePatternMatcher(patterns, new Pattern[0]); + } + + public ObjectNameGenerator createNameGenerator() { + + // TODO: not a singleton; called from different places... + + // custom name generator + // TODO: support stemmer in non-standard generators... + // TODO: load via DI AdhocObjectFactory + String namingStrategy = getNamingStrategy(); + if (namingStrategy != null && !namingStrategy.equals(DefaultObjectNameGenerator.class.getName())) { + try { + return (ObjectNameGenerator) Class.forName(namingStrategy).newInstance(); + } catch (Exception e) { + throw new CayenneRuntimeException("Error creating name generator: " + namingStrategy, e); + } + } + + return new DefaultObjectNameGenerator(createStemmer()); + } + + protected DbEntityNameStemmer createStemmer() { + return (stripFromTableNames == null || stripFromTableNames.length() == 0) + ? NoStemStemmer.getInstance() + : new PatternStemmer(stripFromTableNames, false); + } + + public String getDriver() { + return dataSourceInfo.getJdbcDriver(); + } + + public void setDriver(String jdbcDriver) { + dataSourceInfo.setJdbcDriver(jdbcDriver); + } + + public String getPassword() { + return dataSourceInfo.getPassword(); + } + + public void setPassword(String password) { + dataSourceInfo.setPassword(password); + } + + public String getUsername() { + return dataSourceInfo.getUserName(); + } + + public void setUsername(String userName) { + dataSourceInfo.setUserName(userName); + } + + public String getUrl() { + return dataSourceInfo.getDataSourceUrl(); + } + + public void setUrl(String dataSourceUrl) { + dataSourceInfo.setDataSourceUrl(dataSourceUrl); + } + + public DataNodeDescriptor createDataNodeDescriptor() { + DataNodeDescriptor nodeDescriptor = new DataNodeDescriptor(); + nodeDescriptor.setAdapterType(getAdapter()); + nodeDescriptor.setDataSourceDescriptor(dataSourceInfo); + + return nodeDescriptor; + } + + public String getDataMapName() { + String name = targetDataMap.getName(); + if (!name.endsWith(DATA_MAP_LOCATION_SUFFIX)) { + throw new CayenneRuntimeException("DataMap file name must end with '%s': '%s'", DATA_MAP_LOCATION_SUFFIX, + name); + } + return name.substring(0, name.length() - DATA_MAP_LOCATION_SUFFIX.length()); + } + + public ModelMergeDelegate createMergeDelegate() { + return new DefaultModelMergeDelegate(); + } + + public DbLoaderDelegate createLoaderDelegate() { + if (getLogger() != null) { + return new LoggingDbLoaderDelegate(getLogger()); + } else { + return new DefaultDbLoaderDelegate(); + } + } + + /** + * Returns configuration that should be used for DB import stage when the schema is loaded from the database. + */ + public DbLoaderConfiguration getDbLoaderConfig() { + return dbLoaderConfiguration; + } + + public void setFiltersConfig(FiltersConfig filtersConfig) { + dbLoaderConfiguration.setFiltersConfig(filtersConfig); + } + + @Override + public String toString() { + StringBuilder res = new StringBuilder("Importer options:"); + for (String line : dbLoaderConfiguration.toString().split("\n")) { + res.append(" ").append(line).append("\n"); + } + + return res.toString(); + } + + public DataSourceInfo getDataSourceInfo() { + return dataSourceInfo; + } + + public void setSkipRelationshipsLoading(Boolean skipRelationshipsLoading) { + this.dbLoaderConfiguration.setSkipRelationshipsLoading(skipRelationshipsLoading); + } + + public void setSkipPrimaryKeyLoading(Boolean skipPrimaryKeyLoading) { + this.dbLoaderConfiguration.setSkipPrimaryKeyLoading(skipPrimaryKeyLoading); + } + + public void setTableTypes(String[] tableTypes) { + dbLoaderConfiguration.setTableTypes(tableTypes); + } + + public void setForceDataMapCatalog(boolean forceDataMapCatalog) { + this.forceDataMapCatalog = forceDataMapCatalog; + } + + public boolean isForceDataMapCatalog() { + return forceDataMapCatalog; + } + + public void setForceDataMapSchema(boolean forceDataMapSchema) { + this.forceDataMapSchema = forceDataMapSchema; + } + + public boolean isForceDataMapSchema() { + return forceDataMapSchema; + } +} http://git-wip-us.apache.org/repos/asf/cayenne/blob/660dd4b2/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbimport/DbImportConfigurationValidator.java ---------------------------------------------------------------------- diff --git a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbimport/DbImportConfigurationValidator.java b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbimport/DbImportConfigurationValidator.java new file mode 100644 index 0000000..c301290 --- /dev/null +++ b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbimport/DbImportConfigurationValidator.java @@ -0,0 +1,78 @@ +/***************************************************************** + * 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.dbimport; + +import org.apache.cayenne.configuration.DataNodeDescriptor; +import org.apache.cayenne.configuration.server.DataSourceFactory; +import org.apache.cayenne.configuration.server.DbAdapterFactory; +import org.apache.cayenne.dba.DbAdapter; +import org.apache.cayenne.di.Injector; + +import java.util.Collection; +import javax.sql.DataSource; + +/** + * @since 4.0 + */ +public class DbImportConfigurationValidator implements Cloneable { + private final ReverseEngineering reverseEngineering; + private final DbImportConfiguration config; + private final Injector injector; + + public DbImportConfigurationValidator(ReverseEngineering reverseEngineering, DbImportConfiguration config, Injector injector) { + this.reverseEngineering = reverseEngineering; + this.config = config; + this.injector = injector; + } + + public void validate() throws Exception { + DataNodeDescriptor dataNodeDescriptor = config.createDataNodeDescriptor(); + DbAdapter adapter; + + try { + DataSource dataSource = injector.getInstance(DataSourceFactory.class).getDataSource(dataNodeDescriptor); + adapter = injector.getInstance(DbAdapterFactory.class).createAdapter(dataNodeDescriptor, dataSource); + } catch (Exception ex) { + throw new Exception("Error creating DataSource or DbAdapter for DataNodeDescriptor (" + dataNodeDescriptor + ")", ex); + } + + if (adapter != null && !adapter.supportsCatalogsOnReverseEngineering() && !isReverseEngineeringCatalogsEmpty()) { + String message = "Your database does not support catalogs on reverse engineering. " + + "It allows to connect to only one at the moment. " + + "Please don't note catalogs in <dbimport> configuration."; + throw new Exception(message); + } + } + + private boolean isReverseEngineeringCatalogsEmpty() { + Collection<Catalog> catalogs = reverseEngineering.getCatalogs(); + if (catalogs == null || catalogs.isEmpty()) { + return true; + } + + for (Catalog catalog : catalogs) { + if (catalog.getName() != null) { + return false; + } + } + + return true; + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/cayenne/blob/660dd4b2/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbimport/DbImportModule.java ---------------------------------------------------------------------- diff --git a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbimport/DbImportModule.java b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbimport/DbImportModule.java new file mode 100644 index 0000000..f709886 --- /dev/null +++ b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbimport/DbImportModule.java @@ -0,0 +1,46 @@ +/***************************************************************** + * 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.dbimport; + +import org.apache.cayenne.configuration.ConfigurationNameMapper; +import org.apache.cayenne.configuration.DefaultConfigurationNameMapper; +import org.apache.cayenne.di.Binder; +import org.apache.cayenne.di.Module; +import org.apache.cayenne.map.MapLoader; +import org.apache.cayenne.project.FileProjectSaver; +import org.apache.cayenne.project.ProjectSaver; + +/** + * A DI module that bootstraps {@link DbImportAction}. + * Should be used in conjunction with {@link org.apache.cayenne.dbsync.reverse.configuration.ToolsModule} + * and {@link org.apache.cayenne.dbsync.DbSyncModule}. + * + * @since 4.0 + */ +public class DbImportModule implements Module { + + public void configure(Binder binder) { + binder.bind(DbImportAction.class).to(DefaultDbImportAction.class); + binder.bind(ProjectSaver.class).to(FileProjectSaver.class); + binder.bind(ConfigurationNameMapper.class).to(DefaultConfigurationNameMapper.class); + binder.bind(MapLoader.class).to(MapLoader.class); + } + +} http://git-wip-us.apache.org/repos/asf/cayenne/blob/660dd4b2/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbimport/DefaultDbImportAction.java ---------------------------------------------------------------------- diff --git a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbimport/DefaultDbImportAction.java b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbimport/DefaultDbImportAction.java new file mode 100644 index 0000000..3278dc4 --- /dev/null +++ b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbimport/DefaultDbImportAction.java @@ -0,0 +1,422 @@ +/***************************************************************** + * 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.dbimport; + +import org.apache.cayenne.configuration.ConfigurationTree; +import org.apache.cayenne.configuration.DataNodeDescriptor; +import org.apache.cayenne.configuration.server.DataSourceFactory; +import org.apache.cayenne.configuration.server.DbAdapterFactory; +import org.apache.cayenne.dba.DbAdapter; +import org.apache.cayenne.dbsync.filter.NameFilter; +import org.apache.cayenne.dbsync.merge.token.model.AbstractToModelToken; +import org.apache.cayenne.dbsync.merge.DataMapMerger; +import org.apache.cayenne.dbsync.merge.context.MergerContext; +import org.apache.cayenne.dbsync.merge.token.MergerToken; +import org.apache.cayenne.dbsync.reverse.dbload.ModelMergeDelegate; +import org.apache.cayenne.dbsync.reverse.dbload.ProxyModelMergeDelegate; +import org.apache.cayenne.dbsync.merge.factory.MergerTokenFactory; +import org.apache.cayenne.dbsync.merge.factory.MergerTokenFactoryProvider; +import org.apache.cayenne.dbsync.naming.ObjectNameGenerator; +import org.apache.cayenne.dbsync.reverse.dbload.DbLoader; +import org.apache.cayenne.dbsync.reverse.dbload.DbLoaderConfiguration; +import org.apache.cayenne.dbsync.reverse.filters.CatalogFilter; +import org.apache.cayenne.dbsync.reverse.filters.FiltersConfig; +import org.apache.cayenne.dbsync.reverse.filters.PatternFilter; +import org.apache.cayenne.di.Inject; +import org.apache.cayenne.map.DataMap; +import org.apache.cayenne.map.DbEntity; +import org.apache.cayenne.map.EntityResolver; +import org.apache.cayenne.map.MapLoader; +import org.apache.cayenne.map.ObjEntity; +import org.apache.cayenne.map.ObjRelationship; +import org.apache.cayenne.map.Procedure; +import org.apache.cayenne.project.Project; +import org.apache.cayenne.project.ProjectSaver; +import org.apache.cayenne.resource.URLResource; +import org.apache.cayenne.validation.SimpleValidationFailure; +import org.apache.cayenne.validation.ValidationFailure; +import org.apache.cayenne.validation.ValidationResult; +import org.apache.commons.logging.Log; +import org.xml.sax.InputSource; + +import javax.sql.DataSource; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.sql.Connection; +import java.util.Collection; +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; + +/** + * A default implementation of {@link DbImportAction} that can load DB schema and merge it to a new or an existing + * DataMap. + * + * @since 4.0 + */ +public class DefaultDbImportAction implements DbImportAction { + + private final ProjectSaver projectSaver; + private final Log logger; + private final DataSourceFactory dataSourceFactory; + private final DbAdapterFactory adapterFactory; + private final MapLoader mapLoader; + private final MergerTokenFactoryProvider mergerTokenFactoryProvider; + + public DefaultDbImportAction(@Inject Log logger, + @Inject ProjectSaver projectSaver, + @Inject DataSourceFactory dataSourceFactory, + @Inject DbAdapterFactory adapterFactory, + @Inject MapLoader mapLoader, + @Inject MergerTokenFactoryProvider mergerTokenFactoryProvider) { + this.logger = logger; + this.projectSaver = projectSaver; + this.dataSourceFactory = dataSourceFactory; + this.adapterFactory = adapterFactory; + this.mapLoader = mapLoader; + this.mergerTokenFactoryProvider = mergerTokenFactoryProvider; + } + + protected static List<MergerToken> sort(List<MergerToken> reverse) { + Collections.sort(reverse); + return reverse; + } + + /** + * 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<>(); + + 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); + } + + @Override + public void execute(DbImportConfiguration config) throws Exception { + + if (logger.isDebugEnabled()) { + logger.debug("DB connection: " + config.getDataSourceInfo()); + logger.debug(config); + } + + boolean hasChanges = false; + DataNodeDescriptor dataNodeDescriptor = config.createDataNodeDescriptor(); + DataSource dataSource = dataSourceFactory.getDataSource(dataNodeDescriptor); + DbAdapter adapter = adapterFactory.createAdapter(dataNodeDescriptor, dataSource); + ObjectNameGenerator objectNameGenerator = config.createNameGenerator(); + + DataMap sourceDataMap; + try (Connection connection = dataSource.getConnection()) { + sourceDataMap = load(config, adapter, connection); + } + + DataMap targetDataMap = existingTargetMap(config); + if (targetDataMap == null) { + + String path = config.getTargetDataMap() == null ? "null" : config.getTargetDataMap().getAbsolutePath() + "'"; + + logger.info(""); + logger.info("Map file does not exist. Loaded db model will be saved into '" + path); + + hasChanges = true; + targetDataMap = newTargetDataMap(config); + } + + // transform source DataMap before merging + transformSourceBeforeMerge(sourceDataMap, targetDataMap, config); + + MergerTokenFactory mergerTokenFactory = mergerTokenFactoryProvider.get(adapter); + + DbLoaderConfiguration loaderConfig = config.getDbLoaderConfig(); + List<MergerToken> tokens = DataMapMerger.builder(mergerTokenFactory) + .filters(loaderConfig.getFiltersConfig()) + .skipPKTokens(loaderConfig.isSkipPrimaryKeyLoading()) + .skipRelationshipsTokens(loaderConfig.isSkipRelationshipsLoading()) + .build() + .createMergeTokens(targetDataMap, sourceDataMap); + + hasChanges |= syncDataMapProperties(targetDataMap, config); + hasChanges |= applyTokens(config.createMergeDelegate(), + targetDataMap, + log(sort(reverse(mergerTokenFactory, tokens))), + objectNameGenerator, + config.createMeaningfulPKFilter(), + config.isUsePrimitives()); + hasChanges |= syncProcedures(targetDataMap, sourceDataMap, loaderConfig.getFiltersConfig()); + + if (hasChanges) { + saveLoaded(targetDataMap); + } + } + + + protected void transformSourceBeforeMerge(DataMap sourceDataMap, + DataMap targetDataMap, + DbImportConfiguration configuration) { + + if (configuration.isForceDataMapCatalog()) { + String catalog = targetDataMap.getDefaultCatalog(); + for (DbEntity e : sourceDataMap.getDbEntities()) { + e.setCatalog(catalog); + } + } + + if (configuration.isForceDataMapSchema()) { + String schema = targetDataMap.getDefaultSchema(); + for (DbEntity e : sourceDataMap.getDbEntities()) { + e.setSchema(schema); + } + } + + } + + private boolean syncDataMapProperties(DataMap targetDataMap, DbImportConfiguration config) { + + String defaultPackage = config.getDefaultPackage(); + if (defaultPackage == null || defaultPackage.trim().length() == 0) { + return false; + } + + if (defaultPackage.equals(targetDataMap.getDefaultPackage())) { + return false; + } + + targetDataMap.setDefaultPackage(defaultPackage); + return true; + } + + private void relationshipsSanity(DataMap executed) { + for (ObjEntity objEntity : executed.getObjEntities()) { + List<ObjRelationship> rels = new LinkedList<>(objEntity.getRelationships()); + for (ObjRelationship rel : rels) { + if (rel.getSourceEntity() == null || rel.getTargetEntity() == null) { + logger.error("Incorrect obj relationship source or target entity is null: " + rel); + + objEntity.removeRelationship(rel.getName()); + } + } + } + } + + private Collection<MergerToken> log(List<MergerToken> tokens) { + logger.info(""); + if (tokens.isEmpty()) { + logger.info("Detected changes: No changes to import."); + return tokens; + } + + logger.info("Detected changes: "); + for (MergerToken token : tokens) { + logger.info(String.format(" %-20s %s", token.getTokenName(), token.getTokenValue())); + } + logger.info(""); + + return tokens; + } + + protected DataMap existingTargetMap(DbImportConfiguration configuration) throws IOException { + + File file = configuration.getTargetDataMap(); + if (file != null && file.exists() && file.canRead()) { + DataMap dataMap = mapLoader.loadDataMap(new InputSource(file.getCanonicalPath())); + dataMap.setNamespace(new EntityResolver(Collections.singleton(dataMap))); + dataMap.setConfigurationSource(new URLResource(file.toURI().toURL())); + + return dataMap; + } + + return null; + } + + protected DataMap newTargetDataMap(DbImportConfiguration config) throws IOException { + + DataMap dataMap = new DataMap(); + + dataMap.setName(config.getDataMapName()); + dataMap.setConfigurationSource(new URLResource(config.getTargetDataMap().toURI().toURL())); + dataMap.setNamespace(new EntityResolver(Collections.singleton(dataMap))); + + // update map defaults + + // do not override default package of existing DataMap unless it is + // explicitly requested by the plugin caller + String defaultPackage = config.getDefaultPackage(); + if (defaultPackage != null && defaultPackage.length() > 0) { + dataMap.setDefaultPackage(defaultPackage); + } + + CatalogFilter[] catalogs = config.getDbLoaderConfig().getFiltersConfig().getCatalogs(); + if (catalogs.length > 0) { + // do not override default catalog of existing DataMap unless it is + // explicitly requested by the plugin caller, and the provided catalog is + // not a pattern + String catalog = catalogs[0].name; + if (catalog != null && catalog.length() > 0 && catalog.indexOf('%') < 0) { + dataMap.setDefaultCatalog(catalog); + } + + // do not override default schema of existing DataMap unless it is + // explicitly requested by the plugin caller, and the provided schema is + // not a pattern + String schema = catalogs[0].schemas[0].name; + if (schema != null && schema.length() > 0 && schema.indexOf('%') < 0) { + dataMap.setDefaultSchema(schema); + } + } + + return dataMap; + } + + private List<MergerToken> reverse(MergerTokenFactory mergerTokenFactory, Iterable<MergerToken> mergeTokens) + throws IOException { + + List<MergerToken> tokens = new LinkedList<>(); + for (MergerToken token : mergeTokens) { + if (token instanceof AbstractToModelToken) { + continue; + } + tokens.add(token.createReverse(mergerTokenFactory)); + } + return tokens; + } + + private boolean applyTokens(ModelMergeDelegate mergeDelegate, + DataMap targetDataMap, + Collection<MergerToken> tokens, + ObjectNameGenerator nameGenerator, + NameFilter meaningfulPKFilter, + boolean usingPrimitives) { + + if (tokens.isEmpty()) { + logger.info(""); + logger.info("Detected changes: No changes to import."); + return false; + } + + final Collection<ObjEntity> loadedObjEntities = new LinkedList<>(); + + mergeDelegate = new ProxyModelMergeDelegate(mergeDelegate) { + @Override + public void objEntityAdded(ObjEntity ent) { + loadedObjEntities.add(ent); + super.objEntityAdded(ent); + } + }; + + MergerContext mergerContext = MergerContext.builder(targetDataMap) + .delegate(mergeDelegate) + .nameGenerator(nameGenerator) + .usingPrimitives(usingPrimitives) + .meaningfulPKFilter(meaningfulPKFilter) + .build(); + + for (MergerToken token : tokens) { + try { + token.execute(mergerContext); + } catch (Throwable th) { + String message = "Migration Error. Can't apply changes from token: " + token.getTokenName() + + " (" + token.getTokenValue() + ")"; + + logger.error(message, th); + mergerContext.getValidationResult().addFailure(new SimpleValidationFailure(th, message)); + } + } + + ValidationResult failures = mergerContext.getValidationResult(); + if (failures.hasFailures()) { + logger.info("Migration Complete."); + logger.warn("Migration finished. The following problem(s) were encountered and ignored."); + for (ValidationFailure failure : failures.getFailures()) { + logger.warn(failure.toString()); + } + } else { + logger.info("Migration Complete Successfully."); + } + + flattenManyToManyRelationships(targetDataMap, loadedObjEntities, nameGenerator); + relationshipsSanity(targetDataMap); + return true; + } + + private boolean syncProcedures(DataMap targetDataMap, DataMap loadedDataMap, FiltersConfig filters) { + Collection<Procedure> procedures = loadedDataMap.getProcedures(); + if (procedures.isEmpty()) { + return false; + } + + boolean hasChanges = false; + for (Procedure procedure : procedures) { + PatternFilter proceduresFilter = filters.proceduresFilter(procedure.getCatalog(), procedure.getSchema()); + if (proceduresFilter == null || !proceduresFilter.isIncluded(procedure.getName())) { + continue; + } + + Procedure oldProcedure = targetDataMap.getProcedure(procedure.getName()); + // maybe we need to compare oldProcedure's and procedure's fully qualified names? + if (oldProcedure != null) { + targetDataMap.removeProcedure(procedure.getName()); + logger.info("Replace procedure " + procedure.getName()); + } else { + logger.info("Add new procedure " + procedure.getName()); + } + targetDataMap.addProcedure(procedure); + hasChanges = true; + } + return hasChanges; + } + + protected void saveLoaded(DataMap dataMap) throws FileNotFoundException { + ConfigurationTree<DataMap> projectRoot = new ConfigurationTree<>(dataMap); + Project project = new Project(projectRoot); + projectSaver.save(project); + } + + protected DataMap load(DbImportConfiguration config, + DbAdapter adapter, + Connection connection) throws Exception { + return createDbLoader(adapter, connection, config).load(); + } + + protected DbLoader createDbLoader(DbAdapter adapter, + Connection connection, + DbImportConfiguration config) { + return new DbLoader(adapter, connection, + config.getDbLoaderConfig(), + config.createLoaderDelegate(), + config.createNameGenerator()); + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/cayenne/blob/660dd4b2/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbimport/ExcludeColumn.java ---------------------------------------------------------------------- diff --git a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbimport/ExcludeColumn.java b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbimport/ExcludeColumn.java new file mode 100644 index 0000000..a57400a --- /dev/null +++ b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbimport/ExcludeColumn.java @@ -0,0 +1,32 @@ +/***************************************************************** + * 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.dbimport; + +/** + * @since 4.0. + */ +public class ExcludeColumn extends PatternParam { + public ExcludeColumn() { + } + + public ExcludeColumn(String pattern) { + super(pattern); + } +} http://git-wip-us.apache.org/repos/asf/cayenne/blob/660dd4b2/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbimport/ExcludeProcedure.java ---------------------------------------------------------------------- diff --git a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbimport/ExcludeProcedure.java b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbimport/ExcludeProcedure.java new file mode 100644 index 0000000..a42aa23 --- /dev/null +++ b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbimport/ExcludeProcedure.java @@ -0,0 +1,32 @@ +/***************************************************************** + * 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.dbimport; + +/** + * @since 4.0. + */ +public class ExcludeProcedure extends PatternParam { + public ExcludeProcedure() { + } + + public ExcludeProcedure(String pattern) { + super(pattern); + } +} http://git-wip-us.apache.org/repos/asf/cayenne/blob/660dd4b2/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbimport/ExcludeTable.java ---------------------------------------------------------------------- diff --git a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbimport/ExcludeTable.java b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbimport/ExcludeTable.java new file mode 100644 index 0000000..c55a5c4 --- /dev/null +++ b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbimport/ExcludeTable.java @@ -0,0 +1,32 @@ +/***************************************************************** + * 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.dbimport; + +/** + * @since 4.0. + */ +public class ExcludeTable extends PatternParam { + public ExcludeTable() { + } + + public ExcludeTable(String pattern) { + super(pattern); + } +} http://git-wip-us.apache.org/repos/asf/cayenne/blob/660dd4b2/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbimport/FilterContainer.java ---------------------------------------------------------------------- diff --git a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbimport/FilterContainer.java b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbimport/FilterContainer.java new file mode 100644 index 0000000..197c287 --- /dev/null +++ b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbimport/FilterContainer.java @@ -0,0 +1,172 @@ +/***************************************************************** + * 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.dbimport; + +import java.util.Collection; +import java.util.LinkedList; + +/** + * @since 4.0. + */ +abstract class FilterContainer { + + private String name; + + private final Collection<IncludeTable> includeTableCollection = new LinkedList<>(); + + private final Collection<ExcludeTable> excludeTableCollection = new LinkedList<>(); + + private final Collection<IncludeColumn> includeColumnCollection = new LinkedList<>(); + + private final Collection<ExcludeColumn> excludeColumnCollection = new LinkedList<>(); + + private final Collection<IncludeProcedure> includeProcedureCollection = new LinkedList<>(); + + private final Collection<ExcludeProcedure> excludeProcedureCollection = new LinkedList<>(); + + public Collection<IncludeTable> getIncludeTables() { + return includeTableCollection; + } + + public Collection<ExcludeTable> getExcludeTables() { + return excludeTableCollection; + } + + public Collection<IncludeColumn> getIncludeColumns() { + return includeColumnCollection; + } + + public Collection<ExcludeColumn> getExcludeColumns() { + return excludeColumnCollection; + } + + public Collection<IncludeProcedure> getIncludeProcedures() { + return includeProcedureCollection; + } + + public Collection<ExcludeProcedure> getExcludeProcedures() { + return excludeProcedureCollection; + } + + public void addIncludeColumn(IncludeColumn includeColumn) { + this.includeColumnCollection.add(includeColumn); + } + + public void addExcludeColumn(ExcludeColumn excludeColumn) { + this.excludeColumnCollection.add(excludeColumn); + } + + public void addIncludeTable(IncludeTable includeTable) { + this.includeTableCollection.add(includeTable); + } + + public void addExcludeTable(ExcludeTable excludeTable) { + this.excludeTableCollection.add(excludeTable); + } + + public void addIncludeProcedure(IncludeProcedure includeProcedure) { + this.includeProcedureCollection.add(includeProcedure); + } + + public void addExcludeProcedure(ExcludeProcedure excludeProcedure) { + this.excludeProcedureCollection.add(excludeProcedure); + } + + public void clearIncludeTables() { + includeTableCollection.clear(); + } + + public void clearExcludeTables() { + excludeTableCollection.clear(); + } + + public void clearIncludeProcedures() { + includeProcedureCollection.clear(); + } + + public void clearExcludeProcedures() { + excludeProcedureCollection.clear(); + } + + public void clearIncludeColumns() { + includeColumnCollection.clear(); + } + + public void clearExcludeColumns() { + excludeColumnCollection.clear(); + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public void set(String name) { + setName(name); + } + + public void addConfiguredName(AntNestedElement name) { + setName(name.getName()); + } + + public void addText(String name) { + if (name.trim().isEmpty()) { + return; + } + setName(name); + } + + public boolean isEmptyContainer() { + return includeColumnCollection.isEmpty() && excludeColumnCollection.isEmpty() + && includeTableCollection.isEmpty() && excludeTableCollection.isEmpty() + && includeProcedureCollection.isEmpty() && excludeProcedureCollection.isEmpty(); + } + + static boolean isBlank(Collection<?> collection) { + return collection == null || collection.isEmpty(); + } + + @Override + public String toString() { + return toString(new StringBuilder(), "").toString(); + } + + public StringBuilder toString(StringBuilder res, String prefix) { + appendCollection(res, prefix, includeTableCollection); + appendCollection(res, prefix, excludeTableCollection); + appendCollection(res, prefix, includeColumnCollection); + appendCollection(res, prefix, excludeColumnCollection); + appendCollection(res, prefix, includeProcedureCollection); + appendCollection(res, prefix, excludeProcedureCollection); + + return res; + } + + protected void appendCollection(StringBuilder res, String prefix, Collection<? extends PatternParam> collection) { + if (!isBlank(collection)) { + for (PatternParam item : collection) { + item.toString(res, prefix); + } + } + } +} http://git-wip-us.apache.org/repos/asf/cayenne/blob/660dd4b2/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbimport/IncludeColumn.java ---------------------------------------------------------------------- diff --git a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbimport/IncludeColumn.java b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbimport/IncludeColumn.java new file mode 100644 index 0000000..780eb86 --- /dev/null +++ b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbimport/IncludeColumn.java @@ -0,0 +1,32 @@ +/***************************************************************** + * 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.dbimport; + +/** + * @since 4.0. + */ +public class IncludeColumn extends PatternParam { + public IncludeColumn() { + } + + public IncludeColumn(String pattern) { + super(pattern); + } +} http://git-wip-us.apache.org/repos/asf/cayenne/blob/660dd4b2/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbimport/IncludeProcedure.java ---------------------------------------------------------------------- diff --git a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbimport/IncludeProcedure.java b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbimport/IncludeProcedure.java new file mode 100644 index 0000000..f3b9040 --- /dev/null +++ b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbimport/IncludeProcedure.java @@ -0,0 +1,32 @@ +/***************************************************************** + * 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.dbimport; + +/** + * @since 4.0. + */ +public class IncludeProcedure extends PatternParam { + public IncludeProcedure() { + } + + public IncludeProcedure(String pattern) { + super(pattern); + } +} http://git-wip-us.apache.org/repos/asf/cayenne/blob/660dd4b2/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbimport/IncludeTable.java ---------------------------------------------------------------------- diff --git a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbimport/IncludeTable.java b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbimport/IncludeTable.java new file mode 100644 index 0000000..b57e782 --- /dev/null +++ b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbimport/IncludeTable.java @@ -0,0 +1,84 @@ +/***************************************************************** + * 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.dbimport; + +import java.util.Collection; +import java.util.LinkedList; + +/** + * @since 4.0. + */ +public class IncludeTable extends PatternParam { + + private final Collection<IncludeColumn> includeColumns = new LinkedList<>(); + + private final Collection<ExcludeColumn> excludeColumns = new LinkedList<>(); + + public IncludeTable() { + } + + public IncludeTable(String pattern) { + super(pattern); + } + + public Collection<IncludeColumn> getIncludeColumns() { + return includeColumns; + } + + public void setIncludeColumns(Collection<IncludeColumn> includeColumns) { + this.includeColumns.addAll(includeColumns); + } + + public Collection<ExcludeColumn> getExcludeColumns() { + return excludeColumns; + } + + public void setExcludeColumns(Collection<ExcludeColumn> excludeColumns) { + this.excludeColumns.addAll(excludeColumns); + } + + public void addIncludeColumn(IncludeColumn includeColumn) { + this.includeColumns.add(includeColumn); + } + + public void addExcludeColumn(ExcludeColumn excludeColumn) { + this.excludeColumns.add(excludeColumn); + } + + @Override + public StringBuilder toString(StringBuilder res, String s) { + super.toString(res, s); + + String prefix = s + " "; + if (includeColumns != null && !includeColumns.isEmpty()) { + for (IncludeColumn includeColumn : includeColumns) { + includeColumn.toString(res, prefix); + } + } + + if (excludeColumns != null && !excludeColumns.isEmpty()) { + for (ExcludeColumn excludeColumn : excludeColumns) { + excludeColumn.toString(res, prefix); + } + } + + return res; + } +} http://git-wip-us.apache.org/repos/asf/cayenne/blob/660dd4b2/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbimport/ManyToManyCandidateEntity.java ---------------------------------------------------------------------- diff --git a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbimport/ManyToManyCandidateEntity.java b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbimport/ManyToManyCandidateEntity.java new file mode 100644 index 0000000..3c3cbf3 --- /dev/null +++ b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbimport/ManyToManyCandidateEntity.java @@ -0,0 +1,134 @@ +/***************************************************************** + * 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.dbimport; + +import org.apache.cayenne.dbsync.naming.NameBuilder; +import org.apache.cayenne.dbsync.naming.ObjectNameGenerator; +import org.apache.cayenne.map.DbRelationship; +import org.apache.cayenne.map.ObjEntity; +import org.apache.cayenne.map.ObjRelationship; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import java.util.ArrayList; +import java.util.List; + +/** + * An ObjEntity that may be removed as a result of flattenning relationships. + */ +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<>(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; + } + + ObjRelationship newRelationship = new ObjRelationship(); + newRelationship.setName(NameBuilder + .builder(newRelationship, srcEntity) + .baseName(nameGenerator.relationshipName(rel1, rel2)) + .name()); + + 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/660dd4b2/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbimport/PatternParam.java ---------------------------------------------------------------------- diff --git a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbimport/PatternParam.java b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbimport/PatternParam.java new file mode 100644 index 0000000..4208e64 --- /dev/null +++ b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbimport/PatternParam.java @@ -0,0 +1,83 @@ +/***************************************************************** + * 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.dbimport; + +/** + * @since 4.0. + */ +public class PatternParam { + + private String pattern; + + public PatternParam() { + } + + public PatternParam(String pattern) { + this.pattern = pattern; + } + + public String getPattern() { + return pattern; + } + + public void setPattern(String pattern) { + this.pattern = pattern; + } + + public void setName(String name) { + setPattern(name); + } + + /** + * Used by Maven plugin + */ + public void set(String pattern) { + setPattern(pattern); + } + + + /** + * Used by Ant task + */ + public void addText(String pattern) { + if (pattern.trim().isEmpty()) { + return; + } + + setPattern(pattern); + } + + /** + * used by Ant? + */ + public void addConfiguredPattern(AntNestedElement pattern) { + set(pattern.getName()); + } + + @Override + public String toString() { + return toString(new StringBuilder(), "").toString(); + } + + public StringBuilder toString(StringBuilder res, String s) { + res.append(s).append(getClass().getSimpleName()).append(": ").append(pattern).append("\n"); + return res; + } +}