From c1bfc81e0875dcbbe9ef7b60eafad0cdd82a4b73 Mon Sep 17 00:00:00 2001 From: chenson42 Date: Wed, 11 Jan 2012 19:36:32 +0000 Subject: [PATCH] state of flux - refactoring check-in for symmetric 3 --- symmetric/symmetric-assemble/TODO.txt | 29 +- symmetric/symmetric-assemble/pom.xml | 1 + symmetric/symmetric-core/pom.xml | 5 - .../symmetric/AbstractSymmetricEngine.java | 653 +++--- .../symmetric/ClientSymmetricEngine.java | 190 ++ .../jumpmind/symmetric/ISymmetricEngine.java | 26 +- .../symmetric/ITypedPropertiesFactory.java | 9 + .../SpringWireableSymmetricEngine.java | 68 - .../symmetric/StandaloneSymmetricEngine.java | 122 -- .../symmetric/SymmetricException.java | 2 - .../jumpmind/symmetric/common/Constants.java | 72 +- .../symmetric/common/ParameterConstants.java | 21 +- .../symmetric/common/TableConstants.java | 1 + .../db/AbstractEmbeddedSymmetricDialect.java | 10 +- .../db/AbstractSymmetricDialect.java | 441 ++-- .../symmetric/db/DataSourceFactoryBean.java | 108 - .../symmetric/db/ISymmetricDialect.java | 40 +- .../JdbcBatchPreparedStatementCallback.java | 107 - .../db/JdbcSymmetricDialectFactory.java | 121 ++ .../symmetric/db/SymmetricDialectFactory.java | 225 -- .../symmetric/db/db2/Db2SymmetricDialect.java | 46 +- .../db/db2/Db2v9SymmetricDialect.java | 20 +- .../db/db2/Db2zSeriesSymmetricDialect.java | 223 -- .../db/db2/Db2zSeriesTriggerText.java | 90 - .../db/derby/DerbySymmetricDialect.java | 38 +- .../db/firebird/FirebirdSymmetricDialect.java | 21 +- .../symmetric/db/h2/H2SymmetricDialect.java | 27 +- .../db/hsqldb/HsqlDbSymmetricDialect.java | 59 +- .../db/hsqldb2/HsqlDb2SymmetricDialect.java | 54 +- .../db/informix/InformixSymmetricDialect.java | 23 +- .../interbase/InterbaseSymmetricDialect.java | 42 +- .../db/mssql/MsSqlSymmetricDialect.java | 129 +- .../db/mysql/MySqlSymmetricDialect.java | 280 +-- .../db/oracle/OracleSymmetricDialect.java | 43 +- .../postgresql/GreenplumSymmetricDialect.java | 59 +- .../PostgreSqlSymmetricDialect.java | 35 +- .../db/sqlite/SqLiteSymmetricDialect.java | 130 -- .../db/sybase/SybaseSymmetricDialect.java | 51 +- .../symmetric/ext/ExtensionPointManager.java | 396 ++-- .../symmetric/ext/ISymmetricEngineAware.java | 14 + .../extract/DataExtractorContext.java | 137 -- .../symmetric/extract/IDataExtractor.java | 51 - .../symmetric/extract/IExtractorFilter.java | 38 - .../csv/AbstractStreamDataCommand.java | 189 -- .../symmetric/extract/csv/CsvExtractor.java | 133 -- .../symmetric/extract/csv/CsvExtractor10.java | 114 - .../symmetric/extract/csv/CsvExtractor13.java | 127 -- .../symmetric/extract/csv/CsvExtractor14.java | 137 -- .../symmetric/extract/csv/CsvExtractor16.java | 96 - .../extract/csv/IStreamDataCommand.java | 34 - .../extract/csv/StreamBshDataCommand.java | 41 - .../extract/csv/StreamConfigDataCommand.java | 62 - .../extract/csv/StreamCreateDataCommand.java | 41 - .../extract/csv/StreamDeleteDataCommand.java | 53 - .../extract/csv/StreamInsertDataCommand.java | 54 - .../extract/csv/StreamReloadDataCommand.java | 71 - .../extract/csv/StreamSQLDataCommand.java | 44 - .../extract/csv/StreamUpdateDataCommand.java | 55 - .../io/DefaultOfflineClientListener.java | 43 +- .../symmetric/io/ThresholdFileWriter.java | 136 -- .../jumpmind/symmetric/job/AbstractJob.java | 438 ++-- .../symmetric/job/DataGapPurgeJob.java | 47 +- .../job/DefaultOfflineServerListener.java | 32 +- .../jumpmind/symmetric/job/HeartbeatJob.java | 67 +- .../symmetric/job/IncomingPurgeJob.java | 6 +- .../jumpmind/symmetric/job/JobManager.java | 44 +- .../symmetric/job/OutgoingPurgeJob.java | 16 +- .../org/jumpmind/symmetric/job/PullJob.java | 26 +- .../symmetric/job/PushHeartbeatListener.java | 68 +- .../org/jumpmind/symmetric/job/PushJob.java | 6 +- .../org/jumpmind/symmetric/job/RouterJob.java | 18 +- .../symmetric/job/StatisticFlushJob.java | 9 +- .../symmetric/job/SyncTriggersJob.java | 15 +- .../jumpmind/symmetric/job/WatchdogJob.java | 27 +- .../load/ConfigurationChangedFilter.java | 97 +- .../symmetric/model/AbstractCsvData.java | 67 - .../org/jumpmind/symmetric/model/Data.java | 346 ++-- .../org/jumpmind/symmetric/model/DataRef.java | 58 - .../symmetric/model/TriggerHistory.java | 16 +- .../symmetric/route/AbstractDataRouter.java | 4 +- .../route/AbstractDataToRouteReader.java | 281 --- .../symmetric/route/BshDataRouter.java | 8 +- .../symmetric/route/ChannelRouterContext.java | 65 +- .../route/ColumnMatchDataRouter.java | 39 +- .../route/ConfigurationChangedDataRouter.java | 56 +- .../symmetric/route/DataGapDetector.java | 134 +- .../symmetric/route/DataGapRouteReader.java | 326 ++- .../symmetric/route/DataRefGapDetector.java | 133 -- .../symmetric/route/DataRefRouteReader.java | 59 - .../route/DataToRouteReaderFactory.java | 82 - .../route/LookupTableDataRouter.java | 254 ++- .../symmetric/route/SimpleRouterContext.java | 25 +- .../symmetric/route/SubSelectDataRouter.java | 63 +- .../symmetric/route/TriggerDataRouter.java | 58 - .../symmetric/security/PasswordFactory.java | 59 - .../symmetric/service/IClusterService.java | 2 - .../service/IConfigurationService.java | 8 +- .../service/IDataExtractorService.java | 25 +- .../symmetric/service/IDataService.java | 38 +- .../service/IIncomingBatchService.java | 3 - .../service/IModelRetrievalHandler.java | 43 - .../service/INotificationService.java | 28 - .../service/IOutgoingBatchService.java | 7 +- .../symmetric/service/IParameterService.java | 10 +- .../symmetric/service/IPullService.java | 2 +- .../symmetric/service/IPurgeService.java | 3 - .../symmetric/service/IPushService.java | 2 +- .../service/IRegistrationService.java | 18 +- .../symmetric/service/IRouterService.java | 2 +- .../symmetric/service/ISqlProvider.java | 26 - .../symmetric/service/ITransformService.java | 5 - .../symmetric/service/IUpgradeService.java | 35 - .../impl/AbstractOfflineDetectorService.java | 7 + .../service/impl/AbstractService.java | 87 +- .../service/impl/AcknowledgeService.java | 58 +- .../service/impl/BandwidthService.java | 44 +- .../service/impl/ClusterService.java | 43 +- .../service/impl/ConfigurationService.java | 902 ++++---- .../impl/ConfigurationServiceSqlMap.java | 3 + .../service/impl/DataExtractorService.java | 946 +++------ .../impl/DataExtractorServiceSqlMap.java | 15 - .../service/impl/DataLoaderService.java | 106 +- .../symmetric/service/impl/DataService.java | 1519 +++++++------- .../service/impl/DataServiceSqlMap.java | 9 - .../service/impl/IncomingBatchService.java | 213 +- .../symmetric/service/impl/NodeService.java | 1083 +++++----- .../service/impl/OutgoingBatchService.java | 264 ++- .../impl/OutgoingBatchServiceSqlMap.java | 4 +- .../service/impl/ParameterService.java | 149 +- .../service/impl/ParameterServiceSqlMap.java | 10 +- .../symmetric/service/impl/PullService.java | 28 +- .../symmetric/service/impl/PurgeService.java | 617 +++--- .../service/impl/PurgeServiceSqlMap.java | 38 +- .../symmetric/service/impl/PushService.java | 46 +- .../service/impl/RegistrationService.java | 115 +- .../impl/RegistrationServiceSqlMap.java | 5 +- .../symmetric/service/impl/RouterService.java | 131 +- .../service/impl/SecurityService.java | 24 +- .../service/impl/StatisticService.java | 123 +- .../service/impl/TransformService.java | 148 +- .../service/impl/TriggerRouterService.java | 1839 +++++++++-------- .../service/impl/UpgradeService.java | 121 -- .../jmx/IncomingManagementService.java | 38 - .../service/jmx/NodeManagementService.java | 758 +++---- .../service/jmx/NotificationService.java | 47 - .../jmx/OutgoingManagementService.java | 62 - .../jmx/ParameterManagementService.java | 148 +- .../symmetric/statistic/StatisticManager.java | 37 +- .../transport/AbstractTransportManager.java | 13 +- .../ConcurrentConnectionManager.java | 18 +- .../transport/TransportManagerFactory.java | 124 ++ .../TransportManagerFactoryBean.java | 134 -- .../transport/file/FileIncomingTransport.java | 81 - .../http/HttpBandwidthUrlSelector.java | 26 +- .../transport/http/HttpTransportManager.java | 61 +- .../internal/InternalTransportManager.java | 102 +- .../upgrade/AbstractSqlUpgradeTask.java | 93 - .../symmetric/upgrade/IUpgradeTask.java | 36 - .../upgrade/SqlDrivenUpgradeTask.java | 67 - .../symmetric/upgrade/SqlUpgradeTask.java | 87 - .../symmetric/upgrade/UpgradeConstants.java | 26 - .../org/jumpmind/symmetric/util/AppUtils.java | 13 - .../util/MaxRowsStatementCreator.java | 50 - .../symmetric/util/RandomTimeSlot.java | 108 +- .../org/jumpmind/symmetric/db/db2-zseries.xml | 20 - .../org/jumpmind/symmetric/db/db2.xml | 24 - .../org/jumpmind/symmetric/db/derby.xml | 16 - .../org/jumpmind/symmetric/db/firebird.xml | 16 - .../org/jumpmind/symmetric/db/greenplum.xml | 16 - .../org/jumpmind/symmetric/db/h2.xml | 16 - .../org/jumpmind/symmetric/db/hsqldb.xml | 16 - .../org/jumpmind/symmetric/db/hsqldb2.xml | 16 - .../org/jumpmind/symmetric/db/informix.xml | 16 - .../org/jumpmind/symmetric/db/interbase.xml | 16 - .../org/jumpmind/symmetric/db/mssql.xml | 16 - .../org/jumpmind/symmetric/db/mysql.xml | 16 - .../org/jumpmind/symmetric/db/oracle.xml | 17 - .../org/jumpmind/symmetric/db/postgresql.xml | 16 - .../org/jumpmind/symmetric/db/sqlite.xml | 16 - .../org/jumpmind/symmetric/db/sybase.xml | 16 - .../src/main/resources/symmetric-client.xml | 21 - .../src/main/resources/symmetric-database.xml | 84 - .../resources/symmetric-default.properties | 15 +- .../src/main/resources/symmetric-dialects.xml | 26 - .../src/main/resources/symmetric-empty.xml | 11 - .../main/resources/symmetric-extensions.xml | 49 - .../src/main/resources/symmetric-jmx.xml | 11 - .../src/main/resources/symmetric-jobs.xml | 102 - .../resources/symmetric-messages.properties | 91 +- .../main/resources/symmetric-properties.xml | 43 - .../src/main/resources/symmetric-routers.xml | 71 - .../src/main/resources/symmetric-services.xml | 412 ---- .../src/main/resources/symmetric-upgrade.xml | 9 - .../org/jumpmind/symmetric/db/GenSqlMap.java | 83 - .../ConfigurationChangedDataRouterTest.java | 2 +- .../service/impl}/MockNodeService.java | 2 +- .../http/HttpBandwidthBalancerTest.java} | 47 +- .../java/org/jumpmind/db/model/Table.java | 24 +- .../db/platform/DatabasePlatformSettings.java | 12 +- .../org/jumpmind/db/sql/AbstractSqlMap.java | 2 +- .../jumpmind/db/sql/AbstractSqlTemplate.java | 149 +- .../java/org/jumpmind/db/sql/ISqlMap.java | 7 + .../org/jumpmind/db/sql/ISqlRowMapper.java | 2 +- .../org/jumpmind/db/sql/ISqlTemplate.java | 46 +- .../org/jumpmind/db/sql/ISqlTransaction.java | 19 +- .../jumpmind/db/sql/NamedParameterUtils.java | 284 +++ .../java/org/jumpmind/db/sql/ParsedSql.java | 145 ++ .../main/java/org/jumpmind/db/sql/Row.java | 39 + .../java/org/jumpmind/db/sql/SqlList.java | 26 + .../java/org/jumpmind/db/sql/SqlToken.java | 21 + .../jumpmind/db/sql/mapper/DateMapper.java | 14 + .../jumpmind/db/sql/mapper/NumberMapper.java | 10 + .../jumpmind/symmetric/io/FileIoResource.java | 5 + .../org/jumpmind/symmetric/io/IoResource.java | 2 + .../symmetric/io/MemoryIoResource.java | 4 + .../jumpmind/symmetric/io/data/CsvData.java | 2 + .../reader/DatabaseCapturedCsvDataReader.java | 252 --- .../io/data/reader/DatabaseReader.java | 5 - .../io/data/reader/IBatchCsvDataSource.java | 22 + .../io/data/reader/SourcedCsvDataReader.java | 180 ++ .../io/data/reader/TextualCsvDataReader.java | 10 + .../io/data/writer/CsvDataWriter.java | 50 + .../platform/JdbcDatabasePlatformFactory.java | 3 - .../db/platform/db2/Db2JdbcSqlTemplate.java | 32 + .../jumpmind/db/platform/db2/Db2Platform.java | 5 + .../platform/derby/DerbyJdbcSqlTemplate.java | 31 + .../db/platform/derby/DerbyPlatform.java | 4 + .../firebird/FirebirdJdbcSqlTemplate.java | 26 + .../platform/firebird/FirebirdPlatform.java | 5 + .../greenplum/GreenplumJdbcSqlTemplate.java | 58 + .../db/platform/h2/H2JdbcSqlTemplate.java | 31 + .../jumpmind/db/platform/h2/H2Platform.java | 5 + .../hsqldb/HsqlDbJdbcSqlTemplate.java | 27 + .../db/platform/hsqldb/HsqlDbPlatform.java | 5 + .../hsqldb2/HsqlDb2JdbcSqlTemplate.java | 26 + .../db/platform/hsqldb2/HsqlDb2Platform.java | 5 + .../informix/InformixJdbcSqlTemplate.java | 21 + .../platform/informix/InformixPlatform.java | 5 + .../interbase/InterbaseJdbcSqlTemplate.java | 27 + .../platform/interbase/InterbasePlatform.java | 5 + .../platform/mssql/MsSqlJdbcSqlTemplate.java | 7 +- .../platform/mysql/MySqlJdbcSqlTemplate.java | 21 + .../db/platform/mysql/MySqlPlatform.java | 16 +- .../oracle/OracleJdbcSqlTemplate.java | 21 + .../db/platform/oracle/OraclePlatform.java | 4 +- ...ement.java => PostgreSqlDmlStatement.java} | 4 +- .../postgresql/PostgreSqlJdbcSqlTemplate.java | 27 + .../postgresql/PostgreSqlPlatform.java | 22 +- .../db/platform/sqlite/SqLiteBuilder.java | 271 --- .../db/platform/sqlite/SqLiteDdlReader.java | 94 - .../db/platform/sqlite/SqLitePlatform.java | 96 - .../sybase/SybaseJdbcSqlTemplate.java | 21 + .../db/platform/sybase/SybasePlatform.java | 5 + .../jumpmind/db/sql/jdbc/JdbcSqlTemplate.java | 184 +- .../db/sql/jdbc/JdbcSqlTransaction.java | 34 +- symmetric/symmetric-parent/pom.xml | 11 + .../jumpmind/symmetric/SymmetricLauncher.java | 96 +- .../symmetric/SymmetricWebServer.java | 1 + .../integrate/XmlPublisherDataRouter.java | 2 +- .../web/AbstractCompressionUriHandler.java | 7 + .../symmetric/web/AbstractUriHandler.java | 19 +- .../jumpmind/symmetric/web/AckUriHandler.java | 12 +- .../web/AuthenticationInterceptor.java | 8 +- .../web/BandwidthSamplerUriHandler.java | 6 + .../symmetric/web/BatchUriHandler.java | 8 + .../symmetric/web/InfoUriHandler.java | 18 +- .../web/NodeConcurrencyInterceptor.java | 19 +- .../symmetric/web/PingUriHandler.java | 7 + .../symmetric/web/PullUriHandler.java | 15 + .../symmetric/web/PushUriHandler.java | 26 +- .../symmetric/web/RegistrationUriHandler.java | 20 +- .../symmetric/web/ServerSymmetricEngine.java | 49 + .../jumpmind/symmetric/web/ServletUtils.java | 32 +- .../web/SymmetricContextListener.java | 1 - .../symmetric/web}/SymmetricEngineHolder.java | 17 +- .../symmetric/web/SymmetricServlet.java | 13 +- .../src/main/resources/symmetric-server.xml | 12 - .../src/main/resources/symmetric-web.xml | 91 - .../io/ThresholdFileWriterUnitTest.java | 58 - .../route/DataRefRouteReaderUnitTest.java | 97 - .../stress/AbstractMultiTierStressTest.java | 227 -- .../stress/H2MultiTierStressTest.java | 27 - .../stress/MSSQLMultiTierStressTest.java | 27 - .../symmetric/test/TestSetupUtil.java | 6 +- .../util/DefaultNodeIdGeneratorTest.java | 2 +- .../symmetric/web/MockNodeService.java | 31 - .../jumpmind/exception/SecurityException.java | 17 + .../src/main/java/org/jumpmind/log/Log.java | 4 + .../java/org/jumpmind/util/FormatUtils.java | 7 + 289 files changed, 9455 insertions(+), 15185 deletions(-) create mode 100644 symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/ClientSymmetricEngine.java create mode 100644 symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/ITypedPropertiesFactory.java delete mode 100644 symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/SpringWireableSymmetricEngine.java delete mode 100644 symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/StandaloneSymmetricEngine.java delete mode 100644 symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/db/DataSourceFactoryBean.java delete mode 100644 symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/db/JdbcBatchPreparedStatementCallback.java create mode 100644 symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/db/JdbcSymmetricDialectFactory.java delete mode 100644 symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/db/SymmetricDialectFactory.java delete mode 100644 symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/db/db2/Db2zSeriesSymmetricDialect.java delete mode 100644 symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/db/db2/Db2zSeriesTriggerText.java delete mode 100644 symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/db/sqlite/SqLiteSymmetricDialect.java create mode 100644 symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/ext/ISymmetricEngineAware.java delete mode 100644 symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/extract/DataExtractorContext.java delete mode 100644 symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/extract/IDataExtractor.java delete mode 100644 symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/extract/IExtractorFilter.java delete mode 100644 symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/extract/csv/AbstractStreamDataCommand.java delete mode 100644 symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/extract/csv/CsvExtractor.java delete mode 100644 symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/extract/csv/CsvExtractor10.java delete mode 100644 symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/extract/csv/CsvExtractor13.java delete mode 100644 symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/extract/csv/CsvExtractor14.java delete mode 100644 symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/extract/csv/CsvExtractor16.java delete mode 100644 symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/extract/csv/IStreamDataCommand.java delete mode 100644 symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/extract/csv/StreamBshDataCommand.java delete mode 100644 symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/extract/csv/StreamConfigDataCommand.java delete mode 100644 symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/extract/csv/StreamCreateDataCommand.java delete mode 100644 symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/extract/csv/StreamDeleteDataCommand.java delete mode 100644 symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/extract/csv/StreamInsertDataCommand.java delete mode 100644 symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/extract/csv/StreamReloadDataCommand.java delete mode 100644 symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/extract/csv/StreamSQLDataCommand.java delete mode 100644 symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/extract/csv/StreamUpdateDataCommand.java delete mode 100644 symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/io/ThresholdFileWriter.java delete mode 100644 symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/model/AbstractCsvData.java delete mode 100644 symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/model/DataRef.java delete mode 100644 symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/route/AbstractDataToRouteReader.java delete mode 100644 symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/route/DataRefGapDetector.java delete mode 100644 symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/route/DataRefRouteReader.java delete mode 100644 symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/route/DataToRouteReaderFactory.java delete mode 100644 symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/route/TriggerDataRouter.java delete mode 100644 symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/security/PasswordFactory.java delete mode 100644 symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/IModelRetrievalHandler.java delete mode 100644 symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/INotificationService.java delete mode 100644 symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/ISqlProvider.java delete mode 100644 symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/IUpgradeService.java delete mode 100644 symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/impl/DataExtractorServiceSqlMap.java delete mode 100644 symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/impl/UpgradeService.java delete mode 100644 symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/jmx/IncomingManagementService.java delete mode 100644 symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/jmx/NotificationService.java delete mode 100644 symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/jmx/OutgoingManagementService.java create mode 100644 symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/transport/TransportManagerFactory.java delete mode 100644 symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/transport/TransportManagerFactoryBean.java delete mode 100644 symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/transport/file/FileIncomingTransport.java delete mode 100644 symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/upgrade/AbstractSqlUpgradeTask.java delete mode 100644 symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/upgrade/IUpgradeTask.java delete mode 100644 symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/upgrade/SqlDrivenUpgradeTask.java delete mode 100644 symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/upgrade/SqlUpgradeTask.java delete mode 100644 symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/upgrade/UpgradeConstants.java delete mode 100644 symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/util/MaxRowsStatementCreator.java delete mode 100644 symmetric/symmetric-core/src/main/resources/org/jumpmind/symmetric/db/db2-zseries.xml delete mode 100644 symmetric/symmetric-core/src/main/resources/org/jumpmind/symmetric/db/db2.xml delete mode 100644 symmetric/symmetric-core/src/main/resources/org/jumpmind/symmetric/db/derby.xml delete mode 100644 symmetric/symmetric-core/src/main/resources/org/jumpmind/symmetric/db/firebird.xml delete mode 100644 symmetric/symmetric-core/src/main/resources/org/jumpmind/symmetric/db/greenplum.xml delete mode 100644 symmetric/symmetric-core/src/main/resources/org/jumpmind/symmetric/db/h2.xml delete mode 100644 symmetric/symmetric-core/src/main/resources/org/jumpmind/symmetric/db/hsqldb.xml delete mode 100644 symmetric/symmetric-core/src/main/resources/org/jumpmind/symmetric/db/hsqldb2.xml delete mode 100644 symmetric/symmetric-core/src/main/resources/org/jumpmind/symmetric/db/informix.xml delete mode 100644 symmetric/symmetric-core/src/main/resources/org/jumpmind/symmetric/db/interbase.xml delete mode 100644 symmetric/symmetric-core/src/main/resources/org/jumpmind/symmetric/db/mssql.xml delete mode 100644 symmetric/symmetric-core/src/main/resources/org/jumpmind/symmetric/db/mysql.xml delete mode 100644 symmetric/symmetric-core/src/main/resources/org/jumpmind/symmetric/db/oracle.xml delete mode 100644 symmetric/symmetric-core/src/main/resources/org/jumpmind/symmetric/db/postgresql.xml delete mode 100644 symmetric/symmetric-core/src/main/resources/org/jumpmind/symmetric/db/sqlite.xml delete mode 100644 symmetric/symmetric-core/src/main/resources/org/jumpmind/symmetric/db/sybase.xml delete mode 100644 symmetric/symmetric-core/src/main/resources/symmetric-client.xml delete mode 100644 symmetric/symmetric-core/src/main/resources/symmetric-database.xml delete mode 100644 symmetric/symmetric-core/src/main/resources/symmetric-dialects.xml delete mode 100644 symmetric/symmetric-core/src/main/resources/symmetric-empty.xml delete mode 100644 symmetric/symmetric-core/src/main/resources/symmetric-jobs.xml delete mode 100644 symmetric/symmetric-core/src/main/resources/symmetric-properties.xml delete mode 100644 symmetric/symmetric-core/src/main/resources/symmetric-routers.xml delete mode 100644 symmetric/symmetric-core/src/main/resources/symmetric-services.xml delete mode 100644 symmetric/symmetric-core/src/main/resources/symmetric-upgrade.xml delete mode 100644 symmetric/symmetric-core/src/test/java/org/jumpmind/symmetric/db/GenSqlMap.java rename symmetric/{symmetric-server/src/test/java/org/jumpmind/symmetric/service/mock => symmetric-core/src/test/java/org/jumpmind/symmetric/service/impl}/MockNodeService.java (96%) rename symmetric/{symmetric-server/src/test/java/org/jumpmind/symmetric/transport/http/HttpBandwidthBalancerUnitTest.java => symmetric-core/src/test/java/org/jumpmind/symmetric/transport/http/HttpBandwidthBalancerTest.java} (72%) create mode 100644 symmetric/symmetric-db/src/main/java/org/jumpmind/db/sql/ISqlMap.java create mode 100644 symmetric/symmetric-db/src/main/java/org/jumpmind/db/sql/NamedParameterUtils.java create mode 100644 symmetric/symmetric-db/src/main/java/org/jumpmind/db/sql/ParsedSql.java create mode 100644 symmetric/symmetric-db/src/main/java/org/jumpmind/db/sql/SqlList.java create mode 100644 symmetric/symmetric-db/src/main/java/org/jumpmind/db/sql/SqlToken.java create mode 100644 symmetric/symmetric-db/src/main/java/org/jumpmind/db/sql/mapper/DateMapper.java create mode 100644 symmetric/symmetric-db/src/main/java/org/jumpmind/db/sql/mapper/NumberMapper.java delete mode 100644 symmetric/symmetric-io/src/main/java/org/jumpmind/symmetric/io/data/reader/DatabaseCapturedCsvDataReader.java delete mode 100644 symmetric/symmetric-io/src/main/java/org/jumpmind/symmetric/io/data/reader/DatabaseReader.java create mode 100644 symmetric/symmetric-io/src/main/java/org/jumpmind/symmetric/io/data/reader/IBatchCsvDataSource.java create mode 100644 symmetric/symmetric-io/src/main/java/org/jumpmind/symmetric/io/data/reader/SourcedCsvDataReader.java create mode 100644 symmetric/symmetric-io/src/main/java/org/jumpmind/symmetric/io/data/writer/CsvDataWriter.java create mode 100644 symmetric/symmetric-jdbc/src/main/java/org/jumpmind/db/platform/db2/Db2JdbcSqlTemplate.java create mode 100644 symmetric/symmetric-jdbc/src/main/java/org/jumpmind/db/platform/derby/DerbyJdbcSqlTemplate.java create mode 100644 symmetric/symmetric-jdbc/src/main/java/org/jumpmind/db/platform/firebird/FirebirdJdbcSqlTemplate.java create mode 100644 symmetric/symmetric-jdbc/src/main/java/org/jumpmind/db/platform/greenplum/GreenplumJdbcSqlTemplate.java create mode 100644 symmetric/symmetric-jdbc/src/main/java/org/jumpmind/db/platform/h2/H2JdbcSqlTemplate.java create mode 100644 symmetric/symmetric-jdbc/src/main/java/org/jumpmind/db/platform/hsqldb/HsqlDbJdbcSqlTemplate.java create mode 100644 symmetric/symmetric-jdbc/src/main/java/org/jumpmind/db/platform/hsqldb2/HsqlDb2JdbcSqlTemplate.java create mode 100644 symmetric/symmetric-jdbc/src/main/java/org/jumpmind/db/platform/informix/InformixJdbcSqlTemplate.java create mode 100644 symmetric/symmetric-jdbc/src/main/java/org/jumpmind/db/platform/interbase/InterbaseJdbcSqlTemplate.java create mode 100644 symmetric/symmetric-jdbc/src/main/java/org/jumpmind/db/platform/mysql/MySqlJdbcSqlTemplate.java create mode 100644 symmetric/symmetric-jdbc/src/main/java/org/jumpmind/db/platform/oracle/OracleJdbcSqlTemplate.java rename symmetric/symmetric-jdbc/src/main/java/org/jumpmind/db/platform/postgresql/{PostgresDmlStatement.java => PostgreSqlDmlStatement.java} (95%) create mode 100644 symmetric/symmetric-jdbc/src/main/java/org/jumpmind/db/platform/postgresql/PostgreSqlJdbcSqlTemplate.java delete mode 100644 symmetric/symmetric-jdbc/src/main/java/org/jumpmind/db/platform/sqlite/SqLiteBuilder.java delete mode 100644 symmetric/symmetric-jdbc/src/main/java/org/jumpmind/db/platform/sqlite/SqLiteDdlReader.java delete mode 100644 symmetric/symmetric-jdbc/src/main/java/org/jumpmind/db/platform/sqlite/SqLitePlatform.java create mode 100644 symmetric/symmetric-jdbc/src/main/java/org/jumpmind/db/platform/sybase/SybaseJdbcSqlTemplate.java create mode 100644 symmetric/symmetric-server/src/main/java/org/jumpmind/symmetric/web/ServerSymmetricEngine.java rename symmetric/{symmetric-core/src/main/java/org/jumpmind/symmetric => symmetric-server/src/main/java/org/jumpmind/symmetric/web}/SymmetricEngineHolder.java (93%) delete mode 100644 symmetric/symmetric-server/src/main/resources/symmetric-server.xml delete mode 100644 symmetric/symmetric-server/src/main/resources/symmetric-web.xml delete mode 100644 symmetric/symmetric-server/src/test/java/org/jumpmind/symmetric/io/ThresholdFileWriterUnitTest.java delete mode 100644 symmetric/symmetric-server/src/test/java/org/jumpmind/symmetric/route/DataRefRouteReaderUnitTest.java delete mode 100644 symmetric/symmetric-server/src/test/java/org/jumpmind/symmetric/stress/AbstractMultiTierStressTest.java delete mode 100644 symmetric/symmetric-server/src/test/java/org/jumpmind/symmetric/stress/H2MultiTierStressTest.java delete mode 100644 symmetric/symmetric-server/src/test/java/org/jumpmind/symmetric/stress/MSSQLMultiTierStressTest.java delete mode 100644 symmetric/symmetric-server/src/test/java/org/jumpmind/symmetric/web/MockNodeService.java create mode 100644 symmetric/symmetric-util/src/main/java/org/jumpmind/exception/SecurityException.java diff --git a/symmetric/symmetric-assemble/TODO.txt b/symmetric/symmetric-assemble/TODO.txt index 9cfb06a54c..4a2c7c87c2 100644 --- a/symmetric/symmetric-assemble/TODO.txt +++ b/symmetric/symmetric-assemble/TODO.txt @@ -15,21 +15,32 @@ * Lookup/choose datawriter based on channel settings * clean up error handling in loader service * SqlScript for Informix - + * Implement a jdbc batch loader + * Use data processor for extract * Add dependency on spring-jdbc from symmetric-db (lob handlers and statement creators) * lob handling for extract + * Finish DataExtractorService data selector * map target tables from routers * integrate into data extractor service * verify stats capturing, outgoing batch updates - + * add transform writer + * add batch file management api + +* Hook up JMX + +* Clean up logging +* Use HttpClient? * Add table copy utility * Clean up service tests * Use data processor for streaming to file -* Implement batch mode -* What to do with SqlTemplate? Move sqltemplate into dbdialect +* Purge OK records instead of purging them at a later date +* Test batch inserts for router service +* Remove all references to data_ref ++ What to do with SqlTemplate? Move sqltemplate into dbdialect * Change the default server mode to multiserver -* Clean up symmetric.messages +* Clean up symmetric.messages +* SqlMap create constants for columns and table names Documentation * Change getting started to instruct user to update properties in the engines directory (for multiserver mode) @@ -37,7 +48,13 @@ Documentation 3.0 Change Notes: * The db.metadata.ignore.case property is no long available. All configured database names will be case sensitive +* db.spring.bean.name is no longer available +* datareload.batch.insert.transactional is no longer available +* routing.data.reader.type is no longer available. data_ref has been removed. +* jdbc datasources are no longer supported * All data loader properties will be configurable by channel * IDatabaseWriterFilter replaces IDataLoaderFilter * IDatabaseWriterFilter replaces IBatchListener -* db.default.schema is no longer used \ No newline at end of file +* db.default.schema is no longer used +* No longer stop purge from running if there wasn't an initial load +* Extensions no longer have services injected into them. If they need acccess to services, they should implement ISymmetricEngineAware \ No newline at end of file diff --git a/symmetric/symmetric-assemble/pom.xml b/symmetric/symmetric-assemble/pom.xml index f55577a1f9..bf1a7176c7 100644 --- a/symmetric/symmetric-assemble/pom.xml +++ b/symmetric/symmetric-assemble/pom.xml @@ -34,6 +34,7 @@ ../symmetric-jdbc ../symmetric-io ../symmetric-core + ../symmetric-client ../symmetric-server diff --git a/symmetric/symmetric-core/pom.xml b/symmetric/symmetric-core/pom.xml index 883c22d5ad..26c4a92fa5 100644 --- a/symmetric/symmetric-core/pom.xml +++ b/symmetric/symmetric-core/pom.xml @@ -23,11 +23,6 @@ org.jumpmind.symmetric symmetric-io - - org.jumpmind.symmetric - symmetric-jdbc - test - commons-dbcp commons-dbcp diff --git a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/AbstractSymmetricEngine.java b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/AbstractSymmetricEngine.java index 96de65f765..95be3e9195 100644 --- a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/AbstractSymmetricEngine.java +++ b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/AbstractSymmetricEngine.java @@ -1,46 +1,27 @@ -/* - * Licensed to JumpMind Inc under one or more contributor - * license agreements. See the NOTICE file distributed - * with this work for additional information regarding - * copyright ownership. JumpMind Inc licenses this file - * to you under the GNU Lesser General Public License (the - * "License"); you may not use this file except in compliance - * with the License. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see - * . - * - * 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.jumpmind.symmetric; -import java.sql.SQLException; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Properties; import java.util.Set; -import javax.sql.DataSource; - -import org.apache.commons.dbcp.BasicDataSource; import org.apache.commons.lang.StringUtils; import org.jumpmind.db.model.Table; +import org.jumpmind.db.platform.IDatabasePlatform; +import org.jumpmind.log.Log; +import org.jumpmind.log.LogFactory; +import org.jumpmind.properties.TypedProperties; import org.jumpmind.symmetric.common.Constants; import org.jumpmind.symmetric.common.DeploymentType; import org.jumpmind.symmetric.common.ParameterConstants; import org.jumpmind.symmetric.common.TableConstants; -import org.jumpmind.symmetric.common.logging.ILog; -import org.jumpmind.symmetric.common.logging.LogFactory; -import org.jumpmind.symmetric.config.PropertiesFactoryBean; import org.jumpmind.symmetric.db.ISymmetricDialect; +import org.jumpmind.symmetric.db.JdbcSymmetricDialectFactory; import org.jumpmind.symmetric.ext.IExtensionPointManager; +import org.jumpmind.symmetric.io.DefaultOfflineClientListener; +import org.jumpmind.symmetric.io.IOfflineClientListener; +import org.jumpmind.symmetric.job.DefaultOfflineServerListener; import org.jumpmind.symmetric.job.IJobManager; import org.jumpmind.symmetric.model.Node; import org.jumpmind.symmetric.model.NodeStatus; @@ -65,26 +46,108 @@ import org.jumpmind.symmetric.service.IStatisticService; import org.jumpmind.symmetric.service.ITransformService; import org.jumpmind.symmetric.service.ITriggerRouterService; -import org.jumpmind.symmetric.service.IUpgradeService; +import org.jumpmind.symmetric.service.impl.AcknowledgeService; +import org.jumpmind.symmetric.service.impl.BandwidthService; +import org.jumpmind.symmetric.service.impl.ClusterService; +import org.jumpmind.symmetric.service.impl.ConfigurationService; +import org.jumpmind.symmetric.service.impl.DataExtractorService; +import org.jumpmind.symmetric.service.impl.DataLoaderService; +import org.jumpmind.symmetric.service.impl.DataService; +import org.jumpmind.symmetric.service.impl.IncomingBatchService; +import org.jumpmind.symmetric.service.impl.NodeService; +import org.jumpmind.symmetric.service.impl.OutgoingBatchService; +import org.jumpmind.symmetric.service.impl.ParameterService; +import org.jumpmind.symmetric.service.impl.PullService; +import org.jumpmind.symmetric.service.impl.PurgeService; +import org.jumpmind.symmetric.service.impl.PushService; +import org.jumpmind.symmetric.service.impl.RegistrationService; +import org.jumpmind.symmetric.service.impl.RouterService; +import org.jumpmind.symmetric.service.impl.SecurityService; +import org.jumpmind.symmetric.service.impl.StatisticService; +import org.jumpmind.symmetric.service.impl.TransformService; +import org.jumpmind.symmetric.service.impl.TriggerRouterService; import org.jumpmind.symmetric.statistic.IStatisticManager; +import org.jumpmind.symmetric.statistic.StatisticManager; +import org.jumpmind.symmetric.transport.ConcurrentConnectionManager; +import org.jumpmind.symmetric.transport.IConcurrentConnectionManager; +import org.jumpmind.symmetric.transport.ITransportManager; +import org.jumpmind.symmetric.transport.TransportManagerFactory; import org.jumpmind.symmetric.util.AppUtils; -import org.springframework.context.ApplicationContext; -import org.springframework.jdbc.core.JdbcTemplate; - -public abstract class AbstractSymmetricEngine implements ISymmetricEngine { - protected ILog log = LogFactory.getLog(getClass()); +abstract public class AbstractSymmetricEngine implements ISymmetricEngine { private static Map registeredEnginesByUrl = new HashMap(); private static Map registeredEnginesByName = new HashMap(); - private ApplicationContext applicationContext; - private JdbcTemplate jdbcTemplate; + protected Log log = LogFactory.getLog(getClass()); + private boolean started = false; + private boolean starting = false; + private boolean setup = false; - private ISymmetricDialect symmetricDialect; - private IJobManager jobManager; + + protected ITypedPropertiesFactory propertiesFactory; + + protected IDatabasePlatform platform; + + protected ISecurityService securityService; + + protected IParameterService parameterService; + + protected ISymmetricDialect symmetricDialect; + + protected INodeService nodeService; + + protected IConfigurationService configurationService; + + protected IBandwidthService bandwidthService; + + protected DeploymentType deploymentType; + + protected IStatisticService statisticService; + + protected IStatisticManager statisticManager; + + protected IConcurrentConnectionManager concurrentConnectionManager; + + protected ITransportManager transportManager; + + protected IClusterService clusterService; + + protected IPurgeService purgeService; + + protected ITransformService transformService; + + protected ITriggerRouterService triggerRouterService; + + protected IOutgoingBatchService outgoingBatchService; + + protected IDataService dataService; + + protected IRouterService routerService; + + protected IDataExtractorService dataExtractorService; + + protected IRegistrationService registrationService; + + protected IDataLoaderService dataLoaderService; + + protected IIncomingBatchService incomingBatchService; + + protected IAcknowledgeService acknowledgeService; + + protected IPushService pushService; + + protected IPullService pullService; + + protected IJobManager jobManager; + + protected IExtensionPointManager extensionPointManger; + + abstract protected ITypedPropertiesFactory createTypedPropertiesFactory(); + + abstract protected IDatabasePlatform createDatabasePlatform(TypedProperties properties); protected AbstractSymmetricEngine() { } @@ -111,50 +174,149 @@ public static ISymmetricEngine findEngineByName(String name) { } } -/** - * Locate the one and only registered {@link StandaloneSymmetricEngine}. Use {@link #findEngineByName(String)} or - * {@link #findEngineByUrl(String) if there is more than on engine registered. - * @throws IllegalStateException This exception happens if more than one engine is - * registered - */ - public static ISymmetricEngine getEngine() { - int numberOfEngines = registeredEnginesByName.size(); - if (numberOfEngines == 0) { - return null; - } else if (numberOfEngines > 1) { - throw new IllegalStateException("More than one SymmetricEngine is currently registered"); - } else { - return registeredEnginesByName.values().iterator().next(); + protected void init() { + this.deploymentType = new DeploymentType(); + this.securityService = createSecurityService(); + this.propertiesFactory = createTypedPropertiesFactory(); + TypedProperties properties = this.propertiesFactory.reload(); + log = LogFactory.getLog("org.jumpmind." + + properties.get(ParameterConstants.ENGINE_NAME, "default")); + this.parameterService = new ParameterService(platform, propertiesFactory, properties.get( + ParameterConstants.RUNTIME_CONFIG_TABLE_PREFIX, "sym"), log); + + this.platform = createDatabasePlatform(properties); + this.platform.setDelimitedIdentifierModeOn(parameterService + .is(ParameterConstants.DB_FORCE_DELIMITED_IDENTIFIER_ON)); + this.platform.setDelimitedIdentifierModeOn(!parameterService + .is(ParameterConstants.DB_FORCE_DELIMITED_IDENTIFIER_OFF)); + this.platform.setClearCacheModelTimeoutInMs(parameterService + .getLong(ParameterConstants.CACHE_TIMEOUT_TABLES_IN_MS)); + + this.bandwidthService = new BandwidthService(parameterService, log); + this.symmetricDialect = new JdbcSymmetricDialectFactory(parameterService, platform, log) + .create(); + this.nodeService = new NodeService(parameterService, symmetricDialect); + this.configurationService = new ConfigurationService(parameterService, symmetricDialect, + nodeService); + this.statisticService = new StatisticService(parameterService, symmetricDialect); + this.statisticManager = new StatisticManager(parameterService, nodeService, + configurationService, statisticService); + this.concurrentConnectionManager = new ConcurrentConnectionManager(parameterService, + statisticManager); + this.clusterService = new ClusterService(parameterService, symmetricDialect); + this.purgeService = new PurgeService(parameterService, symmetricDialect, clusterService, + statisticManager); + this.transformService = new TransformService(parameterService, symmetricDialect); + this.triggerRouterService = new TriggerRouterService(parameterService, symmetricDialect, + clusterService, configurationService, statisticManager); + this.outgoingBatchService = new OutgoingBatchService(parameterService, symmetricDialect, + nodeService, configurationService); + this.dataService = new DataService(parameterService, symmetricDialect, deploymentType, + triggerRouterService, nodeService, purgeService, configurationService, + outgoingBatchService, statisticManager); + this.routerService = new RouterService(parameterService, symmetricDialect, clusterService, + dataService, configurationService, triggerRouterService, outgoingBatchService, + nodeService, statisticManager, transformService); + this.dataExtractorService = new DataExtractorService(parameterService, symmetricDialect, + outgoingBatchService, routerService, configurationService, triggerRouterService, + nodeService, statisticManager); + this.incomingBatchService = new IncomingBatchService(parameterService, symmetricDialect); + this.transportManager = new TransportManagerFactory(this).create(); + this.dataLoaderService = new DataLoaderService(parameterService, symmetricDialect, + incomingBatchService, configurationService, transportManager, statisticManager, + nodeService, transformService, triggerRouterService); + this.registrationService = new RegistrationService(parameterService, symmetricDialect, + nodeService, dataExtractorService, dataService, dataLoaderService, + transportManager, statisticManager); + this.acknowledgeService = new AcknowledgeService(parameterService, symmetricDialect, + outgoingBatchService, registrationService); + this.pushService = new PushService(parameterService, symmetricDialect, + dataExtractorService, acknowledgeService, transportManager, nodeService, + clusterService); + this.pullService = new PullService(parameterService, symmetricDialect, nodeService, + dataLoaderService, registrationService, clusterService); + this.jobManager = createJobManager(); + + this.nodeService.addOfflineServerListener(new DefaultOfflineServerListener(log, + statisticManager, nodeService, outgoingBatchService)); + + IOfflineClientListener defaultlistener = new DefaultOfflineClientListener(log, + parameterService, nodeService); + this.pullService.addOfflineListener(defaultlistener); + this.pushService.addOfflineListener(defaultlistener); + + this.extensionPointManger = createExtensionPointManager(); + this.extensionPointManger.register(); + + registerWithJMX(); + + registerHandleToEngine(); + + } + + protected static ISecurityService createSecurityService() { + // TODO check system property. integrate eric's changes + return new SecurityService(); + } + + abstract protected IJobManager createJobManager(); + + abstract protected void registerWithJMX(); + + abstract protected IExtensionPointManager createExtensionPointManager(); + + public String getSyncUrl() { + return parameterService.getSyncUrl(); + } + + public Properties getProperties() { + Properties p = new Properties(); + p.putAll(parameterService.getAllParameters()); + return p; + } + + public String getEngineName() { + return parameterService.getString(ParameterConstants.ENGINE_NAME); + } + + public void setup() { + AppUtils.cleanupTempFiles(); + getParameterService().rereadParameters(); + if (!setup) { + setupDatabase(false); + setup = true; } } + public void setupDatabase(boolean force) { + configurationService.autoConfigDatabase(force); + clusterService.initLockTable(); + } + public synchronized boolean start() { return start(true); } public synchronized boolean start(boolean startJobs) { - setup(); - if (isConfigured()) { if (!starting && !started) { try { starting = true; - Node node = getNodeService().findIdentity(); + Node node = nodeService.findIdentity(); if (node != null) { - log.info("RegisteredNodeStarting", node.getNodeGroupId(), node.getNodeId(), - node.getExternalId()); + log.info("Starting registered node [group=%s, id=%s, externalId=%s]", + node.getNodeGroupId(), node.getNodeId(), node.getExternalId()); } else { - log.info("UnregisteredNodeStarting", - getParameterService().getNodeGroupId(), getParameterService() - .getExternalId()); + log.info("Starting unregistered node [group=%s, externalId=%s]", + parameterService.getNodeGroupId(), parameterService.getExternalId()); } - getTriggerRouterService().syncTriggers(); + triggerRouterService.syncTriggers(); heartbeat(false); if (startJobs) { jobManager.startJobs(); } - log.info("SymmetricDSStarted"); + log.info("Started SymmetricDS"); started = true; } finally { starting = false; @@ -162,241 +324,77 @@ public synchronized boolean start(boolean startJobs) { } } else { - log.warn("SymmetricDSNotStarted"); + log.warn("Did not start SymmetricDS. It has not been configured properly"); } - log.info("SymmetricDSInfo", getDeploymentType().getDeploymentType(), getEngineName(), - Version.version(), getParameterService().getNodeGroupId(), getParameterService() - .getExternalId(), symmetricDialect.getName(), symmetricDialect.getVersion(), symmetricDialect - .getDriverName(), symmetricDialect.getDriverVersion()); + log.info( + "SymmetricDS: type=%s, name=%s, version=%s, groupId=%s, externalId=%s, databaseName=%s, databaseVersion=%s, driverName=%s, driverVersion=%s", + getDeploymentType().getDeploymentType(), getEngineName(), Version.version(), + getParameterService().getNodeGroupId(), getParameterService().getExternalId(), + symmetricDialect.getName(), symmetricDialect.getVersion(), + symmetricDialect.getDriverName(), symmetricDialect.getDriverVersion()); return started; } public synchronized void stop() { log.info("SymmetricDSClosing", getParameterService().getExternalId(), Version.version(), symmetricDialect.getName()); - jobManager.stopJobs(); - getRouterService().stop(); + if (jobManager != null) { + jobManager.stopJobs(); + } + routerService.stop(); started = false; starting = false; } public synchronized void destroy() { stop(); - jobManager.destroy(); + if (jobManager != null) { + jobManager.destroy(); + } getRouterService().destroy(); removeMeFromMap(registeredEnginesByName); removeMeFromMap(registeredEnginesByUrl); - DataSource ds = jdbcTemplate.getDataSource(); - if (ds instanceof BasicDataSource) { - try { - ((BasicDataSource) ds).close(); - } catch (SQLException ex) { - log.error(ex); - } - } - - applicationContext = null; - jdbcTemplate = null; - symmetricDialect = null; - } - - /** - * @param overridePropertiesResource1 - * Provide a Spring resource path to a properties file to be used - * for configuration - * @param overridePropertiesResource2 - * Provide a Spring resource path to a properties file to be used - * for configuration - */ - protected void init(ApplicationContext ctx, boolean isParentContext, - Properties overrideProperties, String overridePropertiesResource1, - String overridePropertiesResource2) { - // Setting system properties is probably not the best way to accomplish - // this setup. Synchronizing on the class so creating multiple engines - // is thread safe. - synchronized (this.getClass()) { - try { - if (overrideProperties != null) { - PropertiesFactoryBean.setLocalProperties(overrideProperties); - } - - if (!StringUtils.isBlank(overridePropertiesResource1)) { - System.setProperty(Constants.OVERRIDE_PROPERTIES_FILE_1, - overridePropertiesResource1); - } - - if (!StringUtils.isBlank(overridePropertiesResource2)) { - System.setProperty(Constants.OVERRIDE_PROPERTIES_FILE_2, - overridePropertiesResource2); - } - - if (isParentContext || ctx == null) { - init(createContext(ctx)); - } else { - init(ctx); - } - } finally { - PropertiesFactoryBean.clearLocalProperties(); - } - } - } - - protected void init(ApplicationContext applicationContext) { - this.applicationContext = applicationContext; - this.log = LogFactory.getLog(getParameterService()); - symmetricDialect = AppUtils.find(Constants.DB_DIALECT, this); - jobManager = AppUtils.find(Constants.JOB_MANAGER, this); - jdbcTemplate = AppUtils.find(Constants.JDBC_TEMPLATE, this); - - IExtensionPointManager extMgr = (IExtensionPointManager) this.applicationContext - .getBean(Constants.EXTENSION_MANAGER); - extMgr.register(); - - getDeploymentType().setEngineRegistered(true); - } - - protected abstract ApplicationContext createContext(ApplicationContext parentContext); - - private void removeMeFromMap(Map map) { - Set keys = new HashSet(map.keySet()); - for (String key : keys) { - if (map.get(key).equals(this)) { - map.remove(key); - } - } - } - - /** - * Register this instance of the engine so it can be found by other - * processes in the JVM. - * - * @see #findEngineByUrl(String) - */ - private void registerEngine() { - String url = getSyncUrl(); - ISymmetricEngine alreadyRegister = registeredEnginesByUrl.get(url); - if (alreadyRegister == null || alreadyRegister.equals(this)) { - if (url != null) { - registeredEnginesByUrl.put(url, this); - } - } else { - throw new IllegalStateException( - "Could not register engine. There was already an engine registered under the url: " - + getSyncUrl()); - } - - alreadyRegister = registeredEnginesByName.get(getEngineName()); - if (alreadyRegister == null || alreadyRegister.equals(this)) { - registeredEnginesByName.put(getEngineName(), this); - } else { - throw new IllegalStateException( - "Could not register engine. There was already an engine registered under the name: " - + getEngineName()); - } - - } - - public String getSyncUrl() { - Node node = getNodeService().findIdentity(); - if (node != null) { - return node.getSyncUrl(); - } else { - return getParameterService().getSyncUrl(); - } - } - - public Properties getProperties() { - Properties p = new Properties(); - p.putAll(getParameterService().getAllParameters()); - return p; - } - - public String getEngineName() { - return symmetricDialect.getEngineName(); - } - - public synchronized void setup() { - AppUtils.cleanupTempFiles(); - getParameterService().rereadParameters(); - if (!setup) { - setupDatabase(false); - setup = true; - } - registerEngine(); } public String reloadNode(String nodeId) { - return getDataService().reloadNode(nodeId); + return dataService.reloadNode(nodeId); } public String sendSQL(String nodeId, String catalogName, String schemaName, String tableName, String sql) { - return getDataService().sendSQL(nodeId, catalogName, schemaName, tableName, sql, false); + return dataService.sendSQL(nodeId, catalogName, schemaName, tableName, sql, false); } public RemoteNodeStatuses push() { - return getPushService().pushData(); + return pushService.pushData(); } public void syncTriggers() { - getTriggerRouterService().syncTriggers(); + triggerRouterService.syncTriggers(); } public NodeStatus getNodeStatus() { - return getNodeService().getNodeStatus(); + return nodeService.getNodeStatus(); } public RemoteNodeStatuses pull() { - return getPullService().pullData(); + return pullService.pullData(); } public void route() { - getRouterService().routeData(); + routerService.routeData(); } public void purge() { - if (!Boolean.TRUE.toString().equalsIgnoreCase( - getParameterService().getString(ParameterConstants.START_PURGE_JOB))) { - getPurgeService().purgeOutgoing(); - } else { - throw new UnsupportedOperationException( - "Cannot actuate a purge if it is already scheduled."); - } - } - - public void setupDatabase(boolean force) { - getConfigurationService().autoConfigDatabase(force); - if (getUpgradeService().isUpgradeNecessary()) { - if (getParameterService().is(ParameterConstants.AUTO_UPGRADE)) { - try { - if (getUpgradeService().isUpgradePossible()) { - getUpgradeService().upgrade(); - // rerun the auto configuration to make sure things are - // kosher after the upgrade - getConfigurationService().autoConfigDatabase(force); - } else { - throw new SymmetricException("SymmetricDSManualUpgradeNeeded", - getNodeService().findSymmetricVersion(), Version.version()); - } - } catch (RuntimeException ex) { - log.fatal("SymmetricDSUpgradeFailed", ex); - throw ex; - } - } else { - throw new SymmetricException("SymmetricDSUpgradeNeeded"); - } - } - - // lets do this every time init is called. - getClusterService().initLockTable(); + purgeService.purgeOutgoing(); + purgeService.purgeIncoming(); + purgeService.purgeDataGaps(); } public boolean isConfigured() { boolean configurationValid = false; - ISymmetricDialect symmetricDialect = getDbDialect(); - boolean isRegistrationServer = getNodeService().isRegistrationServer(); boolean isSelfConfigurable = isRegistrationServer @@ -405,8 +403,8 @@ public boolean isConfigured() { ParameterConstants.AUTO_CONFIGURE_REG_SVR_SQL_SCRIPT))); Table symNodeTable = symmetricDialect.getPlatform().getTableFromCache( - TableConstants.getTableName(symmetricDialect.getTablePrefix(), TableConstants.SYM_NODE), - false); + TableConstants.getTableName(parameterService.getTablePrefix(), + TableConstants.SYM_NODE), true); Node node = symNodeTable != null ? getNodeService().findIdentity() : null; @@ -418,31 +416,36 @@ public boolean isConfigured() { String registrationUrl = getParameterService().getRegistrationUrl(); if (!isSelfConfigurable && node == null && isRegistrationServer) { - log.warn("ValidationRegServerIsMissingConfiguration", + log.warn( + "This node is configured as a registration server, but it is missing its node_identity. It probably needs configured.", ParameterConstants.REGISTRATION_URL); } else if (!isSelfConfigurable && node == null && StringUtils.isBlank(getParameterService().getRegistrationUrl())) { - log.warn("ValidationSetRegistrationUrl", ParameterConstants.REGISTRATION_URL); + log.warn( + "Please set the property %s so this node may pull registration or manually insert configuration into the configuration tables", + ParameterConstants.REGISTRATION_URL); } else if (Constants.PLEASE_SET_ME.equals(getParameterService().getExternalId()) || Constants.PLEASE_SET_ME.equals(registrationUrl) || Constants.PLEASE_SET_ME.equals(getParameterService().getNodeGroupId())) { - log.warn("ValidationPleaseSetMe"); + log.warn("Please set the registration.url, node.group.id, and external.id for the node"); } else if (node != null && (!node.getExternalId().equals(getParameterService().getExternalId()) || !node .getNodeGroupId().equals(getParameterService().getNodeGroupId()))) { - log.warn("ValidationComparePropertiesToDatabase", node.getExternalId(), - getParameterService().getExternalId(), node.getNodeGroupId(), - getParameterService().getNodeGroupId()); + log.warn( + "The configured state does not match recorded database state. The recorded external id is %s while the configured external id is %s. The recorded node group id is %s while the configured node group id is %s", + node.getExternalId(), getParameterService().getExternalId(), + node.getNodeGroupId(), getParameterService().getNodeGroupId()); } else if (node != null && StringUtils.isBlank(getParameterService().getRegistrationUrl()) && StringUtils.isBlank(getParameterService().getSyncUrl())) { - log.warn("ValidationMakeSureSyncUrlIsSet"); + log.warn("The sync.url property must be set for the registration server. Otherwise, registering nodes will not be able to sync with it"); } else if (offlineNodeDetectionPeriodSeconds > 0 && offlineNodeDetectionPeriodSeconds <= heartbeatSeconds) { // Offline node detection is not disabled (-1) and the value is too // small (less than the heartbeat) - log.warn("ValidationOfflineSettings", + log.warn( + "The %s property must be a longer period of time than the %s property. Otherwise, nodes will be taken offline before the heartbeat job has a chance to run", ParameterConstants.OFFLINE_NODE_DETECTION_PERIOD_MINUTES, ParameterConstants.HEARTBEAT_SYNC_ON_PUSH_PERIOD_SEC); @@ -461,19 +464,19 @@ public boolean isConfigured() { } public void heartbeat(boolean force) { - getDataService().heartbeat(force); + dataService.heartbeat(force); } - public void openRegistration(String groupId, String externalId) { - getRegistrationService().openRegistration(groupId, externalId); + public void openRegistration(String nodeGroupId, String externalId) { + registrationService.openRegistration(nodeGroupId, externalId); } public void reOpenRegistration(String nodeId) { - getRegistrationService().reOpenRegistration(nodeId); + registrationService.reOpenRegistration(nodeId); } public boolean isRegistered() { - return getNodeService().findIdentity() != null; + return nodeService.findIdentity() != null; } public boolean isStarted() { @@ -484,115 +487,155 @@ public boolean isStarting() { return starting; } - public ApplicationContext getApplicationContext() { - return applicationContext; - } - public IConfigurationService getConfigurationService() { - return AppUtils.find(Constants.CONFIG_SERVICE, this); + return configurationService; } public IParameterService getParameterService() { - return AppUtils.find(Constants.PARAMETER_SERVICE, this); + return parameterService; } public INodeService getNodeService() { - return AppUtils.find(Constants.NODE_SERVICE, this); - } - - public DeploymentType getDeploymentType() { - return AppUtils.find(Constants.DEPLOYMENT_TYPE, this); + return nodeService; } public IRegistrationService getRegistrationService() { - return AppUtils.find(Constants.REGISTRATION_SERVICE, this); - } - - public IUpgradeService getUpgradeService() { - return AppUtils.find(Constants.UPGRADE_SERVICE, this); + return registrationService; } public IClusterService getClusterService() { - return AppUtils.find(Constants.CLUSTER_SERVICE, this); + return clusterService; } public IPurgeService getPurgeService() { - return AppUtils.find(Constants.PURGE_SERVICE, this); + return purgeService; } public IDataService getDataService() { - return AppUtils.find(Constants.DATA_SERVICE, this); + return dataService; } - public ISymmetricDialect getDbDialect() { + public ISymmetricDialect getSymmetricDialect() { return symmetricDialect; } public IJobManager getJobManager() { - return jobManager; + return this.jobManager; } public IOutgoingBatchService getOutgoingBatchService() { - return AppUtils.find(Constants.OUTGOING_BATCH_SERVICE, this); + return outgoingBatchService; } public IAcknowledgeService getAcknowledgeService() { - return AppUtils.find(Constants.ACKNOWLEDGE_SERVICE, this); + return this.acknowledgeService; } public IBandwidthService getBandwidthService() { - return AppUtils.find(Constants.BANDWIDTH_SERVICE, this); + return bandwidthService; } public IDataExtractorService getDataExtractorService() { - return AppUtils.find(Constants.DATAEXTRACTOR_SERVICE, this); + return this.dataExtractorService; } public IDataLoaderService getDataLoaderService() { - return AppUtils.find(Constants.DATALOADER_SERVICE, this); + return this.dataLoaderService; } public IIncomingBatchService getIncomingBatchService() { - return AppUtils.find(Constants.INCOMING_BATCH_SERVICE, this); + return this.incomingBatchService; } public IPullService getPullService() { - return AppUtils.find(Constants.PULL_SERVICE, this); + return this.pullService; } public IPushService getPushService() { - return AppUtils.find(Constants.PUSH_SERVICE, this); + return this.pushService; } public IRouterService getRouterService() { - return AppUtils.find(Constants.ROUTER_SERVICE, this); + return this.routerService; } public ISecurityService getSecurityService() { - return AppUtils.find(Constants.SECURITY_SERVICE, this); + return securityService; } - public IStatisticManager getStatisticManager() { - return AppUtils.find(Constants.STATISTIC_MANAGER, this); + public IStatisticService getStatisticService() { + return statisticService; } - public IStatisticService getStatisticService() { - return AppUtils.find(Constants.STATISTIC_SERVICE, this); + public IStatisticManager getStatisticManager() { + return statisticManager; } public ITriggerRouterService getTriggerRouterService() { - return AppUtils.find(Constants.TRIGGER_ROUTER_SERVICE, this); + return triggerRouterService; } - public DataSource getDataSource() { - return AppUtils.find(Constants.DATA_SOURCE, this); + public DeploymentType getDeploymentType() { + return deploymentType; } public ITransformService getTransformService() { - return AppUtils.find(Constants.TRANSFORM_SERVICE, this); + return this.transformService; + } + + public IConcurrentConnectionManager getConcurrentConnectionManager() { + return concurrentConnectionManager; } public String getTablePrefix() { - return getParameterService().getTablePrefix(); + return parameterService.getTablePrefix(); } -} \ No newline at end of file + + public ITransportManager getTransportManager() { + return transportManager; + } + + private void removeMeFromMap(Map map) { + Set keys = new HashSet(map.keySet()); + for (String key : keys) { + if (map.get(key).equals(this)) { + map.remove(key); + } + } + } + + /** + * Register this instance of the engine so it can be found by other + * processes in the JVM. + * + * @see #findEngineByUrl(String) + */ + private void registerHandleToEngine() { + String url = getSyncUrl(); + ISymmetricEngine alreadyRegister = registeredEnginesByUrl.get(url); + if (alreadyRegister == null || alreadyRegister.equals(this)) { + if (url != null) { + registeredEnginesByUrl.put(url, this); + } + } else { + throw new IllegalStateException( + "Could not register engine. There was already an engine registered under the url: " + + getSyncUrl()); + } + + alreadyRegister = registeredEnginesByName.get(getEngineName()); + if (alreadyRegister == null || alreadyRegister.equals(this)) { + registeredEnginesByName.put(getEngineName(), this); + } else { + throw new IllegalStateException( + "Could not register engine. There was already an engine registered under the name: " + + getEngineName()); + } + + } + + public Log getLog() { + return log; + } + +} diff --git a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/ClientSymmetricEngine.java b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/ClientSymmetricEngine.java new file mode 100644 index 0000000000..cc74d2c4e9 --- /dev/null +++ b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/ClientSymmetricEngine.java @@ -0,0 +1,190 @@ +package org.jumpmind.symmetric; + +import java.io.File; +import java.io.IOException; +import java.sql.Connection; +import java.sql.SQLException; + +import javax.sql.DataSource; + +import org.apache.commons.dbcp.BasicDataSource; +import org.apache.commons.lang.StringUtils; +import org.jumpmind.db.platform.DatabasePlatformSettings; +import org.jumpmind.db.platform.IDatabasePlatform; +import org.jumpmind.db.platform.JdbcDatabasePlatformFactory; +import org.jumpmind.db.sql.jdbc.JdbcSqlTemplate; +import org.jumpmind.exception.IoException; +import org.jumpmind.log.Log; +import org.jumpmind.log.LogFactory; +import org.jumpmind.properties.TypedProperties; +import org.jumpmind.symmetric.common.ParameterConstants; +import org.jumpmind.symmetric.common.SecurityConstants; +import org.jumpmind.symmetric.config.PropertiesFactoryBean; +import org.jumpmind.symmetric.ext.ExtensionPointManager; +import org.jumpmind.symmetric.ext.IExtensionPointManager; +import org.jumpmind.symmetric.job.IJobManager; +import org.jumpmind.symmetric.job.JobManager; +import org.jumpmind.symmetric.service.ISecurityService; +import org.jumpmind.symmetric.util.AppUtils; +import org.springframework.core.io.ClassPathResource; +import org.springframework.core.io.FileSystemResource; +import org.springframework.core.io.Resource; + +public class ClientSymmetricEngine extends AbstractSymmetricEngine { + + protected File propertiesFile; + + protected BasicDataSource dataSource; + + public ClientSymmetricEngine(File propertiesFile) { + this.propertiesFile = propertiesFile; + this.init(); + } + + public DataSource getDataSource() { + return ((JdbcSqlTemplate) platform.getSqlTemplate()).getDataSource(); + } + + public static BasicDataSource createBasicDataSource(File propsFile) { + return createBasicDataSource(LogFactory.getLog(ClientSymmetricEngine.class), + createTypedPropertiesFactory(propsFile).reload(), createSecurityService()); + } + + public static BasicDataSource createBasicDataSource(Log log, TypedProperties properties, + ISecurityService securityService) { + BasicDataSource dataSource = new BasicDataSource(); + dataSource.setDriverClassName(properties.get(ParameterConstants.DBPOOL_DRIVER, null)); + dataSource.setUrl(properties.get(ParameterConstants.DBPOOL_URL, null)); + String user = properties.get(ParameterConstants.DBPOOL_USER, ""); + if (user != null && user.startsWith(SecurityConstants.PREFIX_ENC)) { + user = securityService.decrypt(user.substring(SecurityConstants.PREFIX_ENC.length())); + } + dataSource.setUsername(user); + + String password = properties.get(ParameterConstants.DBPOOL_PASSWORD, ""); + if (password != null && password.startsWith(SecurityConstants.PREFIX_ENC)) { + password = securityService.decrypt(password.substring(SecurityConstants.PREFIX_ENC + .length())); + } + dataSource.setUsername(password); + dataSource.setInitialSize(properties.getInt(ParameterConstants.DBPOOL_INITIAL_SIZE, 5)); + dataSource.setMaxActive(properties.getInt(ParameterConstants.DBPOOL_MAX_ACTIVE, 20)); + dataSource.setMaxWait(properties.getInt(ParameterConstants.DBPOOL_MAX_WAIT, 5000)); + dataSource.setMinEvictableIdleTimeMillis(properties.getInt( + ParameterConstants.DBPOOL_MIN_EVICTABLE_IDLE_TIME_MILLIS, 60000)); + dataSource.setTimeBetweenEvictionRunsMillis(120000); + dataSource.setNumTestsPerEvictionRun(10); + dataSource.setValidationQuery(properties.get(ParameterConstants.DBPOOL_VALIDATION_QUERY, + null)); + + String connectionProperties = properties.get( + ParameterConstants.DBPOOL_CONNECTION_PROPERTIES, null); + if (StringUtils.isNotBlank(connectionProperties)) { + String[] tokens = connectionProperties.split(";"); + for (String property : tokens) { + String[] keyValue = property.split("="); + if (keyValue != null && keyValue.length > 1) { + log.info("Setting database connection property %s=%s", keyValue[0], keyValue[1]); + dataSource.addConnectionProperty(keyValue[0], keyValue[1]); + } + } + } + return dataSource; + + } + + @Override + protected IDatabasePlatform createDatabasePlatform(TypedProperties properties) { + createDataSource(properties); + waitForAvailableDatabase(); + return JdbcDatabasePlatformFactory.createNewPlatformInstance(this.dataSource, + createDatabasePlatformSettings(properties), log); + } + + protected DatabasePlatformSettings createDatabasePlatformSettings(TypedProperties properties) { + DatabasePlatformSettings settings = new DatabasePlatformSettings(); + settings.setFetchSize(properties.getInt(ParameterConstants.DB_FETCH_SIZE, 1000)); + settings.setQueryTimeout(properties.getInt(ParameterConstants.DB_QUERY_TIMEOUT_SECS, 300)); + settings.setBatchSize(properties.getInt(ParameterConstants.JDBC_EXECUTE_BATCH_SIZE, 100)); + return settings; + } + + protected void createDataSource(TypedProperties properties) { + this.dataSource = createBasicDataSource(log, properties, securityService); + } + + @Override + protected IExtensionPointManager createExtensionPointManager() { + return new ExtensionPointManager(log, this); + } + + @Override + protected IJobManager createJobManager() { + return new JobManager(log, this); + } + + protected void waitForAvailableDatabase() { + boolean success = false; + while (!success) { + Connection c = null; + try { + c = this.dataSource.getConnection(); + } catch (Exception ex) { + log.error( + "Could not get a connection to the database: %s. Waiting for 10 seconds before trying to connect to the database again.", + ex.getMessage()); + AppUtils.sleep(10000); + } finally { + JdbcSqlTemplate.close(c); + } + } + } + + @Override + protected ITypedPropertiesFactory createTypedPropertiesFactory() { + return createTypedPropertiesFactory(propertiesFile); + } + + protected static ITypedPropertiesFactory createTypedPropertiesFactory(final File propertiesFile) { + return new ITypedPropertiesFactory() { + public TypedProperties reload() { + PropertiesFactoryBean factoryBean = new PropertiesFactoryBean(); + factoryBean.setIgnoreResourceNotFound(true); + factoryBean.setSingleton(false); + factoryBean.setLocations(buildLocations(propertiesFile)); + try { + return new TypedProperties(factoryBean.getObject()); + } catch (IOException e) { + throw new IoException(e); + } + } + + protected Resource[] buildLocations(File properties) { + return new Resource[] { new ClassPathResource("/symmetric-default.properties"), + new ClassPathResource("/symmetric-console-default.properties"), + new FileSystemResource("../conf/symmetric.properties"), + new ClassPathResource("/symmetric.properties"), + new ClassPathResource("/symmetric-override.properties"), + new FileSystemResource(properties.getAbsolutePath()), }; + + } + }; + } + + @Override + public synchronized void destroy() { + super.destroy(); + if (dataSource != null) { + try { + dataSource.close(); + } catch (SQLException e) { + } + } + } + + @Override + protected void registerWithJMX() { + // TODO + } + +} diff --git a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/ISymmetricEngine.java b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/ISymmetricEngine.java index 676cfb43bd..0ff51491a9 100644 --- a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/ISymmetricEngine.java +++ b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/ISymmetricEngine.java @@ -21,8 +21,7 @@ import java.util.Properties; -import javax.sql.DataSource; - +import org.jumpmind.log.Log; import org.jumpmind.symmetric.common.DeploymentType; import org.jumpmind.symmetric.db.ISymmetricDialect; import org.jumpmind.symmetric.job.IJobManager; @@ -52,9 +51,9 @@ import org.jumpmind.symmetric.service.IStatisticService; import org.jumpmind.symmetric.service.ITransformService; import org.jumpmind.symmetric.service.ITriggerRouterService; -import org.jumpmind.symmetric.service.IUpgradeService; import org.jumpmind.symmetric.statistic.IStatisticManager; -import org.springframework.context.ApplicationContext; +import org.jumpmind.symmetric.transport.IConcurrentConnectionManager; +import org.jumpmind.symmetric.transport.ITransportManager; public interface ISymmetricEngine { @@ -198,13 +197,6 @@ public interface ISymmetricEngine { */ public void setupDatabase(boolean force); - /** - * Expose access to the Spring context. This is for advanced use only. - * - * @return the Spring application context that SymmetricDS runs in - */ - public ApplicationContext getApplicationContext(); - public IConfigurationService getConfigurationService(); public IParameterService getParameterService(); @@ -213,15 +205,13 @@ public interface ISymmetricEngine { public IRegistrationService getRegistrationService(); - public IUpgradeService getUpgradeService(); - public IClusterService getClusterService(); public IPurgeService getPurgeService(); public IDataService getDataService(); - public ISymmetricDialect getDbDialect(); + public ISymmetricDialect getSymmetricDialect(); public IJobManager getJobManager(); @@ -251,12 +241,16 @@ public interface ISymmetricEngine { public IStatisticManager getStatisticManager(); - public DataSource getDataSource(); - public DeploymentType getDeploymentType(); + public IConcurrentConnectionManager getConcurrentConnectionManager(); + public ITransformService getTransformService(); + public ITransportManager getTransportManager(); + public String getTablePrefix(); + + public Log getLog(); } \ No newline at end of file diff --git a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/ITypedPropertiesFactory.java b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/ITypedPropertiesFactory.java new file mode 100644 index 0000000000..01d0f61fd4 --- /dev/null +++ b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/ITypedPropertiesFactory.java @@ -0,0 +1,9 @@ +package org.jumpmind.symmetric; + +import org.jumpmind.properties.TypedProperties; + +public interface ITypedPropertiesFactory { + + public TypedProperties reload(); + +} diff --git a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/SpringWireableSymmetricEngine.java b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/SpringWireableSymmetricEngine.java deleted file mode 100644 index 0dd1fa0c55..0000000000 --- a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/SpringWireableSymmetricEngine.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Licensed to JumpMind Inc under one or more contributor - * license agreements. See the NOTICE file distributed - * with this work for additional information regarding - * copyright ownership. JumpMind Inc licenses this file - * to you under the GNU Lesser General Public License (the - * "License"); you may not use this file except in compliance - * with the License. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see - * . - * - * 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.jumpmind.symmetric; - -import java.util.Properties; - -import org.jumpmind.symmetric.common.Constants; -import org.springframework.beans.BeansException; -import org.springframework.context.ApplicationContext; -import org.springframework.context.ApplicationContextAware; -import org.springframework.context.support.ClassPathXmlApplicationContext; - -/** - * This is the preferred way to wire a SymmetricDS instance into an existing - * Spring context. It will create its own {@link ApplicationContext} as a child - * of the Spring {@link ApplicationContext} it is being wired into. - */ -public class SpringWireableSymmetricEngine extends AbstractSymmetricEngine implements ApplicationContextAware { - - private Properties properties; - - private String springXml = Constants.SERVER_SPRING_XML; - - public SpringWireableSymmetricEngine() { - } - - public void setProperties(Properties properties) { - this.properties = properties; - } - - public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { - this.init(applicationContext, true, properties, null, null); - } - - @Override - protected ApplicationContext createContext(ApplicationContext parentContext) { - return new ClassPathXmlApplicationContext(new String[] { springXml }, parentContext); - } - - /** - * @param springXml use {@link Constants#CLIENT_SPRING_XML} or {@link Constants#SERVER_SPRING_XML} - */ - public void setSpringXml(String springXml) { - this.springXml = springXml; - } - - public String getSpringXml() { - return springXml; - } - -} \ No newline at end of file diff --git a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/StandaloneSymmetricEngine.java b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/StandaloneSymmetricEngine.java deleted file mode 100644 index 982598a979..0000000000 --- a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/StandaloneSymmetricEngine.java +++ /dev/null @@ -1,122 +0,0 @@ -/* - * Licensed to JumpMind Inc under one or more contributor - * license agreements. See the NOTICE file distributed - * with this work for additional information regarding - * copyright ownership. JumpMind Inc licenses this file - * to you under the GNU Lesser General Public License (the - * "License"); you may not use this file except in compliance - * with the License. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see - * . - * - * 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.jumpmind.symmetric; - -import java.util.Properties; - -import org.jumpmind.symmetric.common.Constants; -import org.springframework.context.ApplicationContext; -import org.springframework.context.support.ClassPathXmlApplicationContext; - -/** - * This is the preferred way to create, configure, start and manage a - * client-only instance of SymmetricDS. The engine will bootstrap the - * symmetric.xml Spring context. - *

- * The SymmetricDS instance is configured by properties configuration files. By - * default the engine will look for and override existing properties with ones - * found in the properties files. SymmetricDS looks for: symmetric.properties in - * the classpath (it will use the first one it finds), and then for a - * symmetric.properties found in the user.home system property location. Next, - * if provided, in the constructor of the SymmetricEngine, it will locate and - * use the properties file passed to the engine. - *

- * When the engine is ready to be started, the {@link #start()} method should be - * called. It should only be called once. - */ -public class StandaloneSymmetricEngine extends AbstractSymmetricEngine { - - private String springXml = Constants.SERVER_SPRING_XML; - - /** - * Create a SymmetricDS instance using an existing - * {@link ApplicationContext} as the parent. This gives the SymmetricDS - * context access to beans in the parent context. - */ - public StandaloneSymmetricEngine(ApplicationContext parentContext, boolean isParentContext, - Properties overrideProperties, String overridePropertiesResource1, - String overridePropertiesResource2) { - init(parentContext, isParentContext, overrideProperties, overridePropertiesResource1, - overridePropertiesResource2); - } - - public StandaloneSymmetricEngine() { - this(null, false, null, null, null); - } - - public StandaloneSymmetricEngine(Properties overrideProperties) { - this(null, false, overrideProperties, null, null); - } - - /** - * @param overridePropertiesResource - * Pass in a reference to a Spring resource. For example, a - * reference to a properties file would be - * file://path/to/file.properties - */ - public StandaloneSymmetricEngine(String overridePropertiesResource) { - this(null, false, null, overridePropertiesResource, null); - } - - /** - * @param overridePropertiesResource1 - * Pass in a reference to a Spring resource. For example, a - * reference to a properties file would be - * file://path/to/file.properties - * @param overridePropertiesResource2 - * Pass in a reference to a Spring resource. For example, a - * reference to a properties file would be - * file://path/to/file.properties - */ - public StandaloneSymmetricEngine(String overridePropertiesResource1, - String overridePropertiesResource2) { - this(null, false, null, overridePropertiesResource1, overridePropertiesResource2); - } - - public StandaloneSymmetricEngine(ApplicationContext parentContext, boolean isParentContext) { - this(parentContext, isParentContext, null, null, null); - } - - public StandaloneSymmetricEngine(ApplicationContext parentContext, boolean isParentContext, - String overridePropertiesResource) { - this(parentContext, isParentContext, null, overridePropertiesResource, null); - } - - @Override - protected ApplicationContext createContext(ApplicationContext parentContext) { - return new ClassPathXmlApplicationContext(new String[] { springXml }, parentContext); - } - - /** - * @param springXml - * use {@link Constants#CLIENT_SPRING_XML} or - * {@link Constants#SERVER_SPRING_XML} - */ - public void setSpringXml(String springXml) { - this.springXml = springXml; - } - - public String getSpringXml() { - return springXml; - } - -} \ No newline at end of file diff --git a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/SymmetricException.java b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/SymmetricException.java index 699974b9e0..c887fcf2da 100644 --- a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/SymmetricException.java +++ b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/SymmetricException.java @@ -25,8 +25,6 @@ /** * This is a {@link RuntimeException} that supports using the SymmetricDS * {@link Message} infrastructure - * - * */ public class SymmetricException extends RuntimeException { diff --git a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/common/Constants.java b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/common/Constants.java index 99456ea8c7..8dba318b73 100644 --- a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/common/Constants.java +++ b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/common/Constants.java @@ -75,9 +75,7 @@ private Constants() { public static final String SYMMETRIC_ENGINE = "symmetricEngine"; - public static final String MBEAN_SERVER = "mbeanserver"; - - public static final String PROPERTIES = "symmetricProperties"; + public static final String MBEAN_SERVER = "mbeanserver"; public static final String CHANNEL_CONFIG = "config"; @@ -85,74 +83,6 @@ private Constants() { public static final String CHANNEL_DEFAULT = "default"; - public static final String DATA_SOURCE = "dataSource"; - - public static final String NODE_SERVICE = "nodeService"; - - public static final String ROUTER_SERVICE = "routingService"; - - public static final String DATALOADER_SERVICE = "dataLoaderService"; - - public static final String CLUSTER_SERVICE = "clusterService"; - - public static final String PARAMETER_SERVICE = "parameterService"; - - public static final String TRIGGER_ROUTER_SERVICE = "triggerRouterService"; - - public static final String DATALOADER = "dataLoader"; - - public static final String INCOMING_BATCH_SERVICE = "incomingBatchService"; - - public static final String DATAEXTRACTOR_SERVICE = "dataExtractorService"; - - public static final String CONFIG_SERVICE = "configurationService"; - - public static final String TRANSPORT_MANAGER = "transportManager"; - - public static final String EXTENSION_MANAGER = "extensionManager"; - - public static final String ACKNOWLEDGE_SERVICE = "acknowledgeService"; - - public static final String REGISTRATION_SERVICE = "registrationService"; - - public static final String UPGRADE_SERVICE = "upgradeService"; - - public static final String DATA_SERVICE = "dataService"; - - public static final String PUSH_SERVICE = "pushService"; - - public static final String PULL_SERVICE = "pullService"; - - public static final String BANDWIDTH_SERVICE = "bandwidthService"; - - public static final String ACK_RESOURCE_HANDLER = "ackUriHandler"; - - public static final String ALERT_RESOURCE_HANDLER = "alertUriHandler"; - - public static final String STATISTIC_MANAGER = "statisticManager"; - - public static final String STATISTIC_SERVICE = "statisticService"; - - public static final String SECURITY_SERVICE = "securityService"; - - public static final String PULL_URI_HANDLER = "pullUriHandler"; - - public static final String PUSH_URI_HANDLER = "pushUriHandler"; - - public static final String REGISTRATION_URI_HANDLER = "registrationUriHandler"; - - public static final String AUTHENTICATION_INTERCEPTOR = "authenticationInterceptor"; - - public static final String NODE_CONCURRENCY_INTERCEPTOR = "nodeConcurrencyInterceptor"; - - public static final String DEPLOYMENT_TYPE = "deploymentType"; - - public static final String CONCURRENT_CONNECTION_MANGER = "concurrentConnectionManager"; - - public static final String DB_DIALECT = "symmetricDialect"; - - public static final String JOB_MANAGER = "jobManager"; - public static final String PUSH_JOB_TIMER = "job.push"; public static final String PULL_JOB_TIMER = "job.pull"; diff --git a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/common/ParameterConstants.java b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/common/ParameterConstants.java index e32ce693f1..d4a5b8d0f5 100644 --- a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/common/ParameterConstants.java +++ b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/common/ParameterConstants.java @@ -25,8 +25,6 @@ import java.util.Set; import java.util.TreeSet; -import org.jumpmind.symmetric.common.logging.ILog; -import org.jumpmind.symmetric.common.logging.LogFactory; import org.jumpmind.symmetric.service.IParameterService; import org.jumpmind.symmetric.util.DefaultParameterParser; import org.jumpmind.symmetric.util.DefaultParameterParser.ParameterMetaData; @@ -37,8 +35,6 @@ */ final public class ParameterConstants { - static final ILog log = LogFactory.getLog(ParameterConstants.class); - public static final String ALL = "ALL"; private static Map parameterMetaData = new DefaultParameterParser().parse(); @@ -96,11 +92,11 @@ private ParameterConstants() { public final static String OUTGOING_BATCH_PEEK_AHEAD_BATCH_COMMIT_SIZE = "outgoing.batches.peek.ahead.batch.commit.size"; public final static String ROUTING_FLUSH_JDBC_BATCH_SIZE = "routing.flush.jdbc.batch.size"; + public final static String ROUTING_WAIT_FOR_DATA_TIMEOUT_SECONDS = "routing.wait.for.data.timeout.seconds"; public final static String ROUTING_MAX_GAPS_TO_QUALIFY_IN_SQL = "routing.max.gaps.to.qualify.in.sql"; public final static String ROUTING_PEEK_AHEAD_WINDOW = "routing.peek.ahead.window.after.max.size"; public final static String ROUTING_STALE_DATA_ID_GAP_TIME = "routing.stale.dataid.gap.time.ms"; public final static String ROUTING_LARGEST_GAP_SIZE = "routing.largest.gap.size"; - public final static String ROUTING_DATA_READER_TYPE = "routing.data.reader.type"; public final static String ROUTING_DATA_READER_TYPE_GAP_RETENTION_MINUTES = "routing.data.reader.type.gap.retention.period.minutes"; public final static String INCOMING_BATCH_SKIP_DUPLICATE_BATCHES_ENABLED = "incoming.batches.skip.duplicates"; @@ -115,8 +111,6 @@ private ParameterConstants() { public final static String DATA_LOADER_MAX_ROWS_BEFORE_COMMIT = "dataloader.max.rows.before.commit"; public final static String DATA_LOADER_TREAT_DATETIME_AS_VARCHAR = "db.treat.date.time.as.varchar.enabled"; - public final static String DATA_RELOAD_IS_BATCH_INSERT_TRANSACTIONAL = "datareload.batch.insert.transactional"; - public final static String DATA_EXTRACTOR_ENABLED = "dataextractor.enable"; public final static String DATA_EXTRACTOR_FLUSH_FOR_KEEP_ALIVE = "dataextractor.keepalive.period.ms"; public final static String DATA_EXTRACTOR_OLD_DATA_ENABLED = "dataextractor.old.data.enable"; @@ -156,11 +150,18 @@ private ParameterConstants() { public final static String DBPOOL_USER = "db.user"; public final static String DBPOOL_PASSWORD = "db.password"; public final static String DBPOOL_INITIAL_SIZE = "db.pool.initial.size"; + public final static String DBPOOL_MAX_ACTIVE = "db.pool.max.active"; + public final static String DBPOOL_MAX_WAIT = "db.pool.max.wait.millis"; + public final static String DBPOOL_MIN_EVICTABLE_IDLE_TIME_MILLIS = "db.pool.min.evictable.idle.millis"; public final static String DBPOOL_VALIDATION_QUERY = "db.validation.query"; + public final static String DBPOOL_CONNECTION_PROPERTIES = "db.connection.properties"; public final static String DB_NATIVE_EXTRACTOR = "db.native.extractor"; public final static String DB_METADATA_IGNORE_CASE = "db.metadata.ignore.case"; public final static String DB_QUERY_TIMEOUT_SECS = "db.sql.query.timeout.seconds"; + public final static String DB_FETCH_SIZE = "db.jdbc.streaming.results.fetch.size"; + public final static String DB_FORCE_DELIMITED_IDENTIFIER_ON = "db.force.delimited.identifier.mode.on"; + public final static String DB_FORCE_DELIMITED_IDENTIFIER_OFF = "db.force.delimited.identifier.mode.off"; public final static String RUNTIME_CONFIG_TABLE_PREFIX = "sync.table.prefix"; @@ -176,16 +177,18 @@ private ParameterConstants() { public final static String IP_FILTERS = "ip.filters"; - public final static String WEB_BATCH_SERVLET_ENABLE = "web.batch.servlet.enable"; + public final static String WEB_BATCH_URI_HANDLER_ENABLE = "web.batch.servlet.enable"; public final static String OFFLINE_NODE_DETECTION_PERIOD_MINUTES = "offline.node.detection.period.minutes"; public final static String HEARTBEAT_SYNC_ON_PUSH_PERIOD_SEC = "heartbeat.sync.on.push.period.sec"; + + public final static String HEARTBEAT_ENABLED = "heartbeat.sync.on.push.enabled"; public final static String STATISTIC_RECORD_ENABLE = "statistic.record.enable"; public final static String STORES_UPPERCASE_NAMES_IN_CATALOG = "stores.uppercase.names.in.catalog"; - public final static String DB_MASTER_COLLATION = "db.master.collation"; + public final static String DB_MASTER_COLLATION = "db.master.collation"; public static Map getParameterMetaData() { return parameterMetaData; diff --git a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/common/TableConstants.java b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/common/TableConstants.java index 701ff359ea..bf299142be 100644 --- a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/common/TableConstants.java +++ b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/common/TableConstants.java @@ -43,6 +43,7 @@ public class TableConstants { public static final String SYM_NODE_SECURITY = "node_security"; public static final String SYM_NODE_IDENTITY = "node_identity"; public static final String SYM_NODE_CHANNEL_CTL = "node_channel_ctl"; + public static final String SYM_NODE_GROUP_CHANNEL_WINDOW = "node_group_channel_window"; public static final String SYM_PARAMETER = "parameter"; public static String[] NODE_TABLES = { SYM_NODE, SYM_NODE_SECURITY, SYM_NODE_IDENTITY }; diff --git a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/db/AbstractEmbeddedSymmetricDialect.java b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/db/AbstractEmbeddedSymmetricDialect.java index 7b3aa8f467..c318eb2f3d 100644 --- a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/db/AbstractEmbeddedSymmetricDialect.java +++ b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/db/AbstractEmbeddedSymmetricDialect.java @@ -21,17 +21,21 @@ package org.jumpmind.symmetric.db; import org.jumpmind.db.model.Table; +import org.jumpmind.db.platform.IDatabasePlatform; import org.jumpmind.symmetric.model.Channel; import org.jumpmind.symmetric.model.Node; import org.jumpmind.symmetric.model.Trigger; import org.jumpmind.symmetric.model.TriggerHistory; import org.jumpmind.symmetric.model.TriggerRouter; +import org.jumpmind.symmetric.service.IParameterService; -/** - * - */ abstract public class AbstractEmbeddedSymmetricDialect extends AbstractSymmetricDialect implements ISymmetricDialect { + public AbstractEmbeddedSymmetricDialect(IParameterService parameterService, + IDatabasePlatform platform) { + super(parameterService, platform); + } + /** * All the templates have ' escaped because the SQL is inserted into a view. * When returning the raw SQL for use as SQL it needs to be un-escaped. diff --git a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/db/AbstractSymmetricDialect.java b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/db/AbstractSymmetricDialect.java index 200deeb939..11fb7a7e95 100644 --- a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/db/AbstractSymmetricDialect.java +++ b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/db/AbstractSymmetricDialect.java @@ -25,16 +25,7 @@ import java.io.StringReader; import java.io.StringWriter; import java.net.URL; -import java.sql.Connection; -import java.sql.DatabaseMetaData; -import java.sql.PreparedStatement; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.sql.Savepoint; -import java.sql.Statement; import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashSet; import java.util.List; import java.util.Set; @@ -50,8 +41,10 @@ import org.jumpmind.db.model.Table; import org.jumpmind.db.platform.IDatabasePlatform; import org.jumpmind.db.platform.IDdlBuilder; +import org.jumpmind.db.sql.ISqlTemplate; import org.jumpmind.db.sql.ISqlTransaction; import org.jumpmind.db.sql.SqlConstants; +import org.jumpmind.db.sql.SqlException; import org.jumpmind.db.sql.SqlScript; import org.jumpmind.db.util.BinaryEncoding; import org.jumpmind.symmetric.common.Constants; @@ -69,10 +62,6 @@ import org.jumpmind.symmetric.util.AppUtils; import org.jumpmind.util.FormatUtils; import org.springframework.dao.DataAccessException; -import org.springframework.jdbc.core.ConnectionCallback; -import org.springframework.jdbc.core.JdbcTemplate; -import org.springframework.jdbc.core.PreparedStatementCallback; -import org.springframework.jdbc.support.JdbcUtils; import org.springframework.jdbc.support.lob.LobHandler; /* @@ -84,18 +73,12 @@ abstract public class AbstractSymmetricDialect implements ISymmetricDialect { public static final int MAX_SYMMETRIC_SUPPORTED_TRIGGER_SIZE = 50; - protected JdbcTemplate jdbcTemplate; - protected IDatabasePlatform platform; protected TriggerText triggerText; protected IParameterService parameterService; - protected String tablePrefix; - - protected int streamingResultsFetchSize; - protected Boolean supportsGetGeneratedKeys; protected String databaseName; @@ -116,12 +99,21 @@ abstract public class AbstractSymmetricDialect implements ISymmetricDialect { protected boolean supportsTransactionViews = false; - protected int queryTimeoutInSeconds = 300; - - protected List databaseUpgradeListeners = new ArrayList(); - protected AbstractSymmetricDialect() { + public AbstractSymmetricDialect(IParameterService parameterService, + IDatabasePlatform platform) { + log.info("The DbDialect being used is %s", this.getClass().getName()); + this.parameterService = parameterService; + this.platform = platform; + ISqlTemplate sqlTemplate = this.platform.getSqlTemplate(); + this.databaseMajorVersion = sqlTemplate.getDatabaseMajorVersion(); + this.databaseMinorVersion = sqlTemplate.getDatabaseMinorVersion(); + this.databaseName = sqlTemplate.getDatabaseProductName(); + this.databaseProductVersion = sqlTemplate.getDatabaseProductVersion(); + this.driverName = sqlTemplate.getDriverName(); + this.driverVersion = sqlTemplate.getDriverVersion(); + this.initLobHandler(); } public String encodeForCsv(byte[] data) { @@ -146,10 +138,6 @@ public String toFormattedTimestamp(java.util.Date time) { return ts.toString(); } - protected boolean allowsNullForIdentityColumn() { - return true; - } - public boolean requiresAutoCommitFalseToSetFetchSize() { return false; } @@ -164,31 +152,6 @@ public int getMaxTriggerNameLength() { : MAX_SYMMETRIC_SUPPORTED_TRIGGER_SIZE; } - public void init(IDatabasePlatform pf, int queryTimeout, JdbcTemplate jdbcTemplate) { - log.info("DbDialectInUse", this.getClass().getName()); - this.jdbcTemplate = jdbcTemplate; - this.queryTimeoutInSeconds = queryTimeout; - this.jdbcTemplate.setQueryTimeout(queryTimeout); - this.platform = pf; - jdbcTemplate.execute(new ConnectionCallback() { - public Object doInConnection(Connection c) throws SQLException, DataAccessException { - DatabaseMetaData meta = c.getMetaData(); - databaseName = meta.getDatabaseProductName(); - databaseMajorVersion = meta.getDatabaseMajorVersion(); - databaseMinorVersion = meta.getDatabaseMinorVersion(); - databaseProductVersion = meta.getDatabaseProductVersion(); - driverName = meta.getDriverName(); - driverVersion = meta.getDriverVersion(); - return null; - } - }); - this.initLobHandler(); - } - - public int getQueryTimeoutInSeconds() { - return queryTimeoutInSeconds; - } - protected void initTablesAndFunctionsForSpecificDialect() { } @@ -212,11 +175,12 @@ final public boolean doesTriggerExist(String catalogName, String schema, String protected void createRequiredFunctions() { String[] functions = triggerText.getFunctionsToInstall(); for (int i = 0; i < functions.length; i++) { - String funcName = tablePrefix + "_" + functions[i]; - if (jdbcTemplate.queryForInt(triggerText.getFunctionInstalledSql(funcName, - platform.getDefaultSchema())) == 0) { - jdbcTemplate.update(triggerText.getFunctionSql(functions[i], funcName, - platform.getDefaultSchema())); + String funcName = this.parameterService.getTablePrefix() + "_" + functions[i]; + if (this.platform.getSqlTemplate().queryForInt( + triggerText.getFunctionInstalledSql(funcName, platform.getDefaultSchema())) == 0) { + this.platform.getSqlTemplate().update( + triggerText.getFunctionSql(functions[i], funcName, + platform.getDefaultSchema())); log.info("FunctionInstalled", funcName); } } @@ -252,8 +216,9 @@ public String createCsvDataSql(Trigger trigger, TriggerHistory triggerHistory, C this, trigger, triggerHistory, - platform.getTableFromCache(trigger.getSourceCatalogName(), trigger.getSourceSchemaName(), - trigger.getSourceTableName(), false), channel, whereClause).trim(); + platform.getTableFromCache(trigger.getSourceCatalogName(), + trigger.getSourceSchemaName(), trigger.getSourceTableName(), false), + channel, whereClause).trim(); } public String createCsvPrimaryKeySql(Trigger trigger, TriggerHistory triggerHistory, @@ -262,21 +227,14 @@ public String createCsvPrimaryKeySql(Trigger trigger, TriggerHistory triggerHist this, trigger, triggerHistory, - platform.getTableFromCache(trigger.getSourceCatalogName(), trigger.getSourceSchemaName(), - trigger.getSourceTableName(), false), channel, whereClause).trim(); + platform.getTableFromCache(trigger.getSourceCatalogName(), + trigger.getSourceSchemaName(), trigger.getSourceTableName(), false), + channel, whereClause).trim(); } public Set getSqlKeywords() { if (sqlKeywords == null) { - jdbcTemplate.execute(new ConnectionCallback() { - public Object doInConnection(Connection con) throws SQLException, - DataAccessException { - DatabaseMetaData metaData = con.getMetaData(); - sqlKeywords = new HashSet(Arrays.asList(metaData.getSQLKeywords() - .split(","))); - return null; - } - }); + this.sqlKeywords = this.platform.getSqlTemplate().getSqlKeywords(); } return sqlKeywords; } @@ -288,7 +246,7 @@ public void removeTrigger(StringBuilder sqlBuffer, String catalogName, String sc logSql(sql, sqlBuffer); if (parameterService.is(ParameterConstants.AUTO_SYNC_TRIGGERS)) { try { - jdbcTemplate.update(sql); + this.platform.getSqlTemplate().update(sql); } catch (Exception e) { log.warn("TriggerDoesNotExist"); } @@ -296,7 +254,7 @@ public void removeTrigger(StringBuilder sqlBuffer, String catalogName, String sc } final protected void logSql(String sql, StringBuilder sqlBuffer) { - if (sqlBuffer != null) { + if (sqlBuffer != null && StringUtils.isNotBlank(sql)) { sqlBuffer.append(sql); sqlBuffer.append(System.getProperty("line.separator")); sqlBuffer.append(System.getProperty("line.separator")); @@ -310,63 +268,68 @@ final protected void logSql(String sql, StringBuilder sqlBuffer) { public void createTrigger(final StringBuilder sqlBuffer, final DataEventType dml, final Trigger trigger, final TriggerHistory hist, final Channel channel, final String tablePrefix, final Table table) { - jdbcTemplate.execute(new ConnectionCallback() { - public Object doInConnection(Connection con) throws SQLException, DataAccessException { - log.info("TriggerCreating", hist.getTriggerNameForDmlType(dml), - trigger.getSourceTableName()); - - String previousCatalog = null; - String sourceCatalogName = trigger.getSourceCatalogName(); - String defaultCatalog = platform.getDefaultCatalog(); - String defaultSchema = platform.getDefaultSchema(); - try { - previousCatalog = switchCatalogForTriggerInstall(sourceCatalogName, con); - - String triggerSql = triggerText.createTriggerDDL(AbstractSymmetricDialect.this, dml, - trigger, hist, channel, tablePrefix, table, defaultCatalog, - defaultSchema); - - if (parameterService.is(ParameterConstants.AUTO_SYNC_TRIGGERS)) { - Statement stmt = con.createStatement(); - stmt.setQueryTimeout(jdbcTemplate.getQueryTimeout()); - try { - log.debug("Sql", triggerSql); - stmt.executeUpdate(triggerSql); - } catch (SQLException ex) { - log.error("TriggerCreateFailed", triggerSql); - throw ex; - } - String postTriggerDml = createPostTriggerDDL(dml, trigger, hist, channel, - tablePrefix, table); - if (postTriggerDml != null) { - try { - stmt.executeUpdate(postTriggerDml); - } catch (SQLException ex) { - log.error("PostTriggerCreateFailed", postTriggerDml); - throw ex; - } - } - stmt.close(); - } + log.info("Creating %s trigger for %s", hist.getTriggerNameForDmlType(dml), + trigger.getSourceTableName()); - logSql(triggerSql, sqlBuffer); + String previousCatalog = null; + String sourceCatalogName = trigger.getSourceCatalogName(); + String defaultCatalog = platform.getDefaultCatalog(); + String defaultSchema = platform.getDefaultSchema(); - } finally { + String triggerSql = triggerText.createTriggerDDL(AbstractSymmetricDialect.this, dml, + trigger, hist, channel, tablePrefix, table, defaultCatalog, defaultSchema); + + String postTriggerDml = createPostTriggerDDL(dml, trigger, hist, channel, tablePrefix, + table); + + if (parameterService.is(ParameterConstants.AUTO_SYNC_TRIGGERS)) { + ISqlTransaction transaction = null; + try { + transaction = this.platform.getSqlTemplate().startSqlTransaction(); + previousCatalog = switchCatalogForTriggerInstall(sourceCatalogName, transaction); + + try { + log.debug("Running: %s", triggerSql); + transaction.execute(triggerSql); + } catch (SqlException ex) { + log.error("Failed to create trigger: %s", triggerSql); + throw ex; + } + + if (StringUtils.isNotBlank(postTriggerDml)) { + try { + transaction.execute(postTriggerDml); + } catch (SqlException ex) { + log.error("Failed to create post trigger: %s", postTriggerDml); + throw ex; + } + } + transaction.commit(); + } catch (SqlException ex) { + transaction.rollback(); + throw ex; + } finally { + try { if (sourceCatalogName != null && !sourceCatalogName.equalsIgnoreCase(previousCatalog)) { - switchCatalogForTriggerInstall(previousCatalog, con); + switchCatalogForTriggerInstall(previousCatalog, transaction); } + } finally { + transaction.close(); } - return null; + } - }); + } + + logSql(triggerSql, sqlBuffer); + logSql(postTriggerDml, sqlBuffer); + } /* * Provide the option switch a connection's schema for trigger installation. */ - protected String switchCatalogForTriggerInstall(String catalog, Connection c) - throws SQLException { + protected String switchCatalogForTriggerInstall(String catalog, ISqlTransaction transaction) { return null; } @@ -384,8 +347,8 @@ public String getCreateSymmetricDDL() { } public String getCreateTableSQL(TriggerRouter triggerRouter) { - Table table = platform.getTableFromCache(null, triggerRouter.getTrigger().getSourceSchemaName(), - triggerRouter.getTrigger().getSourceTableName(), false); + Table table = platform.getTableFromCache(null, triggerRouter.getTrigger() + .getSourceSchemaName(), triggerRouter.getTrigger().getSourceTableName(), false); return platform.getDdlBuilder().createTable(table); } @@ -426,11 +389,11 @@ public void createTables(String xml) { public boolean doesDatabaseNeedConfigured() { return prefixConfigDatabase(readSymmetricSchemaFromXml()); - } + } protected boolean prefixConfigDatabase(Database targetTables) { try { - String tblPrefix = this.tablePrefix + "_"; + String tblPrefix = parameterService.getTablePrefix() + "_"; Table[] tables = targetTables.getTables(); @@ -439,7 +402,8 @@ protected boolean prefixConfigDatabase(Database targetTables) { table.setName(tblPrefix + table.getName()); fixForeignKeys(table, tblPrefix); fixIndexes(table, tblPrefix); - if (platform.getTableFromCache(platform.getDefaultCatalog(), platform.getDefaultSchema(), table.getName(), true) == null) { + if (platform.getTableFromCache(platform.getDefaultCatalog(), + platform.getDefaultSchema(), table.getName(), true) == null) { createTables = true; } } @@ -449,10 +413,10 @@ protected boolean prefixConfigDatabase(Database targetTables) { throw new RuntimeException(e); } } - + public Table getTable(Trigger trigger, boolean useCache) { - return platform.getTableFromCache(trigger.getSourceCatalogName(), trigger.getSourceSchemaName(), - trigger.getSourceTableName(), !useCache); + return platform.getTableFromCache(trigger.getSourceCatalogName(), + trigger.getSourceSchemaName(), trigger.getSourceTableName(), !useCache); } /* @@ -473,7 +437,7 @@ protected boolean createTablesIfNecessary() { } try { - log.info("TablesAutoUpdatingStart"); + log.info("Checking if SymmetricDS tables need created or altered"); Database modelFromDatabase = new Database(); Table[] tablesFromXml = modelFromXml.getTables(); @@ -488,28 +452,32 @@ protected boolean createTablesIfNecessary() { IDdlBuilder builder = platform.getDdlBuilder(); if (builder.isAlterDatabase(modelFromDatabase, modelFromXml)) { - log.info("TablesAutoUpdatingFoundTablesToAlter"); + log.info("There are SymmetricDS tables that needed altered"); String delimiter = platform.getPlatformInfo().getSqlCommandDelimiter(); for (IDatabaseUpgradeListener listener : databaseUpgradeListeners) { - String sql = listener.beforeUpgrade(this, tablePrefix, modelFromDatabase, - modelFromXml); - new SqlScript(sql, getPlatform().getSqlTemplate(), true, delimiter, null).execute(); + String sql = listener + .beforeUpgrade(this, this.parameterService.getTablePrefix(), + modelFromDatabase, modelFromXml); + new SqlScript(sql, getPlatform().getSqlTemplate(), true, delimiter, null) + .execute(); } String alterSql = builder.alterDatabase(modelFromDatabase, modelFromXml); - + if (log.isDebugEnabled()) { - log.debug("TablesAutoUpdatingAlterSql", alterSql); + log.debug("Alter SQL Generated: %s", alterSql); } - new SqlScript(alterSql, getPlatform().getSqlTemplate(), true, delimiter, null).execute(); + new SqlScript(alterSql, getPlatform().getSqlTemplate(), true, delimiter, null) + .execute(); for (IDatabaseUpgradeListener listener : databaseUpgradeListeners) { - String sql = listener.afterUpgrade(this, tablePrefix, modelFromXml); - new SqlScript(sql, getPlatform().getSqlTemplate(), true, delimiter, null).execute(); + String sql = listener.afterUpgrade(this, this.parameterService.getTablePrefix(), modelFromXml); + new SqlScript(sql, getPlatform().getSqlTemplate(), true, delimiter, null) + .execute(); } - log.info("TablesAutoUpdatingDone"); + log.info("Done with auto update of SymmetricDS tables"); return true; } else { return false; @@ -605,35 +573,19 @@ public String getProductVersion() { return databaseProductVersion; } - public boolean supportsGetGeneratedKeys() { - if (supportsGetGeneratedKeys == null) { - supportsGetGeneratedKeys = jdbcTemplate.execute(new ConnectionCallback() { - public Boolean doInConnection(Connection conn) throws SQLException, - DataAccessException { - return conn.getMetaData().supportsGetGeneratedKeys(); - } - }); - } - return supportsGetGeneratedKeys; - } - public boolean supportsTransactionViews() { return supportsTransactionViews; } - - public boolean supportsReturningKeys() { - return false; - } - - public String getSelectLastInsertIdSql(String sequenceName) { - throw new UnsupportedOperationException(); + + public long insertWithGeneratedKey(String sql, SequenceIdentifier sequenceId) { + return insertWithGeneratedKey(sql, sequenceId, null, null); } - public long insertWithGeneratedKey(final String sql, final SequenceIdentifier sequenceId) { - return insertWithGeneratedKey(jdbcTemplate, sql, sequenceId, null); + public long insertWithGeneratedKey(final String sql, final SequenceIdentifier identifier, Object... args) { + return platform.getSqlTemplate().insertWithGeneratedKey(sql, getSequenceKeyName(identifier), getSequenceKeyName(identifier), args, null); } - protected String getSequenceName(SequenceIdentifier identifier) { + public String getSequenceName(SequenceIdentifier identifier) { switch (identifier) { case OUTGOING_BATCH: return "sym_outgoing_batch_batch_id"; @@ -645,7 +597,7 @@ protected String getSequenceName(SequenceIdentifier identifier) { return null; } - protected String getSequenceKeyName(SequenceIdentifier identifier) { + public String getSequenceKeyName(SequenceIdentifier identifier) { switch (identifier) { case OUTGOING_BATCH: return "batch_id"; @@ -672,129 +624,6 @@ public Column[] orderColumns(String[] columnNames, Table table) { } return orderedColumns; } - - public long insertWithGeneratedKey(final String sql, final SequenceIdentifier sequenceId, - final PreparedStatementCallback callback) { - return insertWithGeneratedKey(jdbcTemplate, sql, sequenceId, callback); - } - - public long insertWithGeneratedKey(final JdbcTemplate jdbcTemplate, final String sql, - final SequenceIdentifier sequenceId, final PreparedStatementCallback callback) { - return jdbcTemplate.execute(new ConnectionCallback() { - public Long doInConnection(Connection conn) throws SQLException, DataAccessException { - - long key = 0; - PreparedStatement ps = null; - try { - boolean supportsGetGeneratedKeys = supportsGetGeneratedKeys(); - boolean supportsReturningKeys = supportsReturningKeys(); - if (allowsNullForIdentityColumn()) { - if (supportsGetGeneratedKeys) { - ps = conn.prepareStatement(sql, new int[] { 1 }); - } else if (supportsReturningKeys) { - ps = conn.prepareStatement(sql + " returning " - + getSequenceKeyName(sequenceId)); - } else { - ps = conn.prepareStatement(sql); - } - } else { - String replaceSql = sql.replaceFirst("\\(\\w*,", "(").replaceFirst( - "\\(null,", "("); - if (supportsGetGeneratedKeys) { - ps = conn.prepareStatement(replaceSql, Statement.RETURN_GENERATED_KEYS); - } else { - ps = conn.prepareStatement(replaceSql); - } - } - ps.setQueryTimeout(jdbcTemplate.getQueryTimeout()); - if (callback != null) { - callback.doInPreparedStatement(ps); - } - - ResultSet rs = null; - if (supportsGetGeneratedKeys) { - ps.executeUpdate(); - try { - rs = ps.getGeneratedKeys(); - if (rs.next()) { - key = rs.getLong(1); - } - } finally { - JdbcUtils.closeResultSet(rs); - } - } else if (supportsReturningKeys) { - try { - rs = ps.executeQuery(); - if (rs.next()) { - key = rs.getLong(1); - } - } finally { - JdbcUtils.closeResultSet(rs); - } - } else { - Statement st = null; - ps.executeUpdate(); - try { - st = conn.createStatement(); - rs = st.executeQuery(getSelectLastInsertIdSql(getSequenceName(sequenceId))); - if (rs.next()) { - key = rs.getLong(1); - } - } finally { - JdbcUtils.closeResultSet(rs); - JdbcUtils.closeStatement(st); - } - } - } finally { - JdbcUtils.closeStatement(ps); - } - return key; - } - }); - } - - public Object createSavepoint(JdbcTemplate jdbcTemplate) { - return jdbcTemplate.execute(new ConnectionCallback() { - public Object doInConnection(Connection con) throws SQLException, DataAccessException { - return con.setSavepoint(); - } - }); - } - - public Object createSavepointForFallback(JdbcTemplate jdbcTemplate) { - if (requiresSavepointForFallback()) { - return createSavepoint(jdbcTemplate); - } - return null; - } - - public void rollbackToSavepoint(JdbcTemplate jdbcTemplate, final Object savepoint) { - if (savepoint != null && savepoint instanceof Savepoint) { - jdbcTemplate.execute(new ConnectionCallback() { - public Object doInConnection(Connection con) throws SQLException, - DataAccessException { - con.rollback((Savepoint) savepoint); - return null; - } - }); - } - } - - public void releaseSavepoint(JdbcTemplate jdbcTemplate, final Object savepoint) { - if (savepoint != null && savepoint instanceof Savepoint) { - jdbcTemplate.execute(new ConnectionCallback() { - public Object doInConnection(Connection con) throws SQLException, - DataAccessException { - con.releaseSavepoint((Savepoint) savepoint); - return null; - } - }); - } - } - - public boolean requiresSavepointForFallback() { - return false; - } public void disableSyncTriggers(ISqlTransaction transaction) { disableSyncTriggers(transaction, null); @@ -816,31 +645,10 @@ public boolean isTransactionIdOverrideSupported() { return true; } - public void setTablePrefix(String tablePrefix) { - this.tablePrefix = tablePrefix; - } - - public int getStreamingResultsFetchSize() { - return streamingResultsFetchSize; - } - - public void setStreamingResultsFetchSize(int streamingResultsFetchSize) { - this.streamingResultsFetchSize = streamingResultsFetchSize; - } - public String getEngineName() { return parameterService.getString(ParameterConstants.ENGINE_NAME); } - public String getTablePrefix() { - return tablePrefix; - } - - public void setParameterService(IParameterService parameterService) { - this.parameterService = parameterService; - this.log = LogFactory.getLog(parameterService); - } - public boolean supportsOpenCursorsAcrossCommit() { return true; } @@ -864,7 +672,7 @@ public void truncateTable(String tableName) { int tryCount = 5; while (!success && tryCount > 0) { try { - jdbcTemplate.update("truncate table " + quote + tableName + quote); + platform.getSqlTemplate().update("truncate table " + quote + tableName + quote); success = true; } catch (DataAccessException ex) { log.warn(ex); @@ -894,10 +702,11 @@ public boolean areDatabaseTransactionsPendingSince(long time) { public long getDatabaseTime() { try { - String sql = "select current_timestamp from " + tablePrefix + "_node_identity"; + String sql = "select current_timestamp from " + this.parameterService.getTablePrefix() + + "_node_identity"; sql = FormatUtils.replaceTokens(sql, platform.getSqlScriptReplacementTokens(), false); - return jdbcTemplate.queryForObject(sql, java.util.Date.class).getTime(); - + return this.platform.getSqlTemplate().queryForObject(sql, java.util.Date.class) + .getTime(); } catch (Exception ex) { log.error(ex); return System.currentTimeMillis(); @@ -938,7 +747,7 @@ public String getDriverName() { public String getDriverVersion() { return driverVersion; - } + } public String massageForLob(String sql, Channel channel) { return sql; @@ -969,12 +778,18 @@ public void addDatabaseUpgradeListener(IDatabaseUpgradeListener listener) { */ protected void initLobHandler() { } - - public JdbcTemplate getJdbcTemplate() { - return jdbcTemplate; - } - + public TriggerText getTriggerText() { return triggerText; } + + protected void close(ISqlTransaction transaction) { + if (transaction != null) { + transaction.close(); + } + } + + public String getTablePrefix() { + return parameterService.getTablePrefix(); + } } \ No newline at end of file diff --git a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/db/DataSourceFactoryBean.java b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/db/DataSourceFactoryBean.java deleted file mode 100644 index 35decfaf2e..0000000000 --- a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/db/DataSourceFactoryBean.java +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Licensed to JumpMind Inc under one or more contributor - * license agreements. See the NOTICE file distributed - * with this work for additional information regarding - * copyright ownership. JumpMind Inc licenses this file - * to you under the GNU Lesser General Public License (the - * "License"); you may not use this file except in compliance - * with the License. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see - * . - * - * 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.jumpmind.symmetric.db; - -import javax.sql.DataSource; - -import org.apache.commons.dbcp.BasicDataSource; -import org.apache.commons.lang.StringUtils; -import org.jumpmind.symmetric.common.Constants; -import org.jumpmind.symmetric.common.logging.ILog; -import org.jumpmind.symmetric.common.logging.LogFactory; -import org.springframework.beans.BeansException; -import org.springframework.beans.factory.FactoryBean; -import org.springframework.context.ApplicationContext; -import org.springframework.context.ApplicationContextAware; - -/** - * Factory that will create either a jndiDataSource or a basicDataSource based - * on whether a JNDI name is provided. - */ -public class DataSourceFactoryBean implements FactoryBean, ApplicationContextAware { - - static final ILog log = LogFactory.getLog(DataSourceFactoryBean.class); - - private String jndiName; - - private String beanName; - - private ApplicationContext applicationContext; - - private String connectionProperties; - - public DataSource getObject() throws Exception { - DataSource dataSource = null; - if (jndiName == null || jndiName.trim().length() == 0) { - if (beanName.startsWith(Constants.PARENT_PROPERTY_PREFIX) - && applicationContext.getParent() != null) { - dataSource = (DataSource) applicationContext.getParent().getBean( - beanName.substring(Constants.PARENT_PROPERTY_PREFIX.length())); - } else { - dataSource = (DataSource) applicationContext.getBean(beanName); - } - } else { - dataSource = (DataSource) applicationContext.getBean("jndiDataSource"); - } - - applyConnectionProperties(dataSource); - return dataSource; - } - - protected void applyConnectionProperties(DataSource dataSource) { - if (StringUtils.isNotBlank(connectionProperties) && dataSource instanceof BasicDataSource) { - BasicDataSource bds = (BasicDataSource)dataSource; - String[] properties = connectionProperties.split(";"); - for (String property : properties) { - String[] keyValue = property.split("="); - if (keyValue != null && keyValue.length > 1) { - log.info("DatabaseSettingConnectionProperty", keyValue[0], keyValue[1]); - bds.addConnectionProperty(keyValue[0], keyValue[1]); - } - } - } - } - - public Class getObjectType() { - return DataSource.class; - } - - public boolean isSingleton() { - return true; - } - - public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { - this.applicationContext = applicationContext; - } - - public void setJndiName(String jndiName) { - this.jndiName = jndiName; - } - - public void setBeanName(String beanName) { - this.beanName = beanName; - } - - public void setConnectionProperties(String connectionProperties) { - this.connectionProperties = connectionProperties; - } - -} \ No newline at end of file diff --git a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/db/ISymmetricDialect.java b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/db/ISymmetricDialect.java index 976aaca962..297b5882a3 100644 --- a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/db/ISymmetricDialect.java +++ b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/db/ISymmetricDialect.java @@ -34,8 +34,6 @@ import org.jumpmind.symmetric.model.Trigger; import org.jumpmind.symmetric.model.TriggerHistory; import org.jumpmind.symmetric.model.TriggerRouter; -import org.springframework.jdbc.core.JdbcTemplate; -import org.springframework.jdbc.core.PreparedStatementCallback; import org.springframework.jdbc.support.lob.LobHandler; /* @@ -104,8 +102,6 @@ public void removeTrigger(StringBuilder sqlBuffer, String catalogName, String sc public boolean supportsTransactionId(); - public int getQueryTimeoutInSeconds(); - /* * Use this call to check to see if the implemented database dialect supports * a way to check on pending database transactions. @@ -129,8 +125,6 @@ public void removeTrigger(StringBuilder sqlBuffer, String catalogName, String sc public String getSourceNodeExpression(); - public int getStreamingResultsFetchSize(); - public String getCreateSymmetricDDL(); public String getCreateTableXML(TriggerRouter triggerRouter); @@ -148,31 +142,17 @@ public void removeTrigger(StringBuilder sqlBuffer, String catalogName, String sc */ public boolean isTransactionIdOverrideSupported(); - public void createTables(String xml); - - public boolean supportsGetGeneratedKeys(); - - public boolean supportsReturningKeys(); + public void createTables(String xml); public Table getTable(Trigger trigger, boolean useCache); - public String getSelectLastInsertIdSql(String sequenceName); - - public long insertWithGeneratedKey(final String sql, final SequenceIdentifier sequenceId); - - public long insertWithGeneratedKey(final String sql, final SequenceIdentifier sequenceId, - final PreparedStatementCallback psCallback); - - public long insertWithGeneratedKey(JdbcTemplate jdbcTemplate, final String sql, - final SequenceIdentifier sequenceId, final PreparedStatementCallback psCallback); - + public long insertWithGeneratedKey(final String sql, final SequenceIdentifier sequenceId); + + public long insertWithGeneratedKey(final String sql, final SequenceIdentifier identifier, Object... args); + + @Deprecated public Column[] orderColumns(String[] columnNames, Table table); - /* - * Get the string prepended to the Symmetric configuration tables. - */ - public String getTablePrefix(); - /* * Get the max number of data objects to load before processing. This parameter typically comes * from the {@link ParameterConstants#ROUTING_PEEK_AHEAD_WINDOW} parameter, unless the dialect chooses @@ -198,8 +178,6 @@ public long insertWithGeneratedKey(JdbcTemplate jdbcTemplate, final String sql, public long getDatabaseTime(); public boolean areDatabaseTransactionsPendingSince(long time); - - public boolean requiresAutoCommitFalseToSetFetchSize(); /* * A handler for data loading lobs. If specified, it will @@ -246,6 +224,10 @@ public long insertWithGeneratedKey(JdbcTemplate jdbcTemplate, final String sql, public String getDriverVersion(); - public JdbcTemplate getJdbcTemplate(); + public String getSequenceName(SequenceIdentifier identifier); + + public String getSequenceKeyName(SequenceIdentifier identifier); + + public String getTablePrefix(); } \ No newline at end of file diff --git a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/db/JdbcBatchPreparedStatementCallback.java b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/db/JdbcBatchPreparedStatementCallback.java deleted file mode 100644 index 467020cdcb..0000000000 --- a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/db/JdbcBatchPreparedStatementCallback.java +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Licensed to JumpMind Inc under one or more contributor - * license agreements. See the NOTICE file distributed - * with this work for additional information regarding - * copyright ownership. JumpMind Inc licenses this file - * to you under the GNU Lesser General Public License (the - * "License"); you may not use this file except in compliance - * with the License. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see - * . - * - * 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.jumpmind.symmetric.db; - -import java.lang.reflect.Method; -import java.sql.PreparedStatement; -import java.sql.SQLException; -import java.sql.Statement; - -import org.apache.commons.dbcp.DelegatingPreparedStatement; -import org.jumpmind.symmetric.common.logging.ILog; -import org.jumpmind.symmetric.common.logging.LogFactory; -import org.jumpmind.symmetric.db.oracle.OracleSymmetricDialect; -import org.springframework.dao.DataAccessException; -import org.springframework.jdbc.core.BatchPreparedStatementSetter; -import org.springframework.jdbc.core.PreparedStatementCallback; -import org.springframework.jdbc.support.JdbcUtils; - -public class JdbcBatchPreparedStatementCallback implements PreparedStatementCallback { - - static final ILog log = LogFactory.getLog(JdbcBatchPreparedStatementCallback.class); - static private boolean firstInitialization = true; - BatchPreparedStatementSetter pss; - ISymmetricDialect symmetricDialect; - int executeBatchSize; - - public JdbcBatchPreparedStatementCallback(ISymmetricDialect symmetricDialect, - BatchPreparedStatementSetter pss, int executeBatchSize) { - this.pss = pss; - this.symmetricDialect = symmetricDialect; - this.executeBatchSize = executeBatchSize; - } - - protected boolean setupForOracleBatching(PreparedStatement ps) { - boolean oracleStyle = false; - if (ps instanceof DelegatingPreparedStatement) { - DelegatingPreparedStatement dps = (DelegatingPreparedStatement) ps; - if (symmetricDialect instanceof OracleSymmetricDialect) { - try { - Class clazz = Class.forName("oracle.jdbc.OraclePreparedStatement"); - Statement delegate = dps.getDelegate(); - if (clazz.isInstance(delegate)) { - Method method = clazz.getMethod("setExecuteBatch", int.class); - method.invoke(delegate, executeBatchSize); - oracleStyle = true; - if (firstInitialization) { - log.info("OracleBatchingUsed", executeBatchSize); - firstInitialization = false; - } - } - } catch (Exception ex) { - log.warn(ex); - } - } - } - return oracleStyle; - } - - public Integer doInPreparedStatement(PreparedStatement ps) throws SQLException, - DataAccessException { - int rowsAffected = 0; - boolean oracleStyle = setupForOracleBatching(ps); - int batchSize = pss.getBatchSize(); - if (JdbcUtils.supportsBatchUpdates(ps.getConnection()) && symmetricDialect.supportsBatchUpdates()) { - for (int i = 0; i < batchSize; i++) { - pss.setValues(ps, i); - if (oracleStyle) { - rowsAffected += ps.executeUpdate(); - } else { - ps.addBatch(); - if (i % executeBatchSize == 0 || i == batchSize-1) { - int[] results = ps.executeBatch(); - for (int j : results) { - rowsAffected += j; - } - } - } - } - return rowsAffected; - } else { - for (int i = 0; i < batchSize; i++) { - pss.setValues(ps, i); - rowsAffected += ps.executeUpdate(); - } - return rowsAffected; - } - } - -} diff --git a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/db/JdbcSymmetricDialectFactory.java b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/db/JdbcSymmetricDialectFactory.java new file mode 100644 index 0000000000..b66253855e --- /dev/null +++ b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/db/JdbcSymmetricDialectFactory.java @@ -0,0 +1,121 @@ +/* + * Licensed to JumpMind Inc under one or more contributor + * license agreements. See the NOTICE file distributed + * with this work for additional information regarding + * copyright ownership. JumpMind Inc licenses this file + * to you under the GNU Lesser General Public License (the + * "License"); you may not use this file except in compliance + * with the License. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see + * . + * + * 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.jumpmind.symmetric.db; + +import org.jumpmind.db.platform.IDatabasePlatform; +import org.jumpmind.db.platform.db2.Db2Platform; +import org.jumpmind.db.platform.derby.DerbyPlatform; +import org.jumpmind.db.platform.firebird.FirebirdPlatform; +import org.jumpmind.db.platform.greenplum.GreenplumPlatform; +import org.jumpmind.db.platform.h2.H2Platform; +import org.jumpmind.db.platform.hsqldb.HsqlDbPlatform; +import org.jumpmind.db.platform.hsqldb2.HsqlDb2Platform; +import org.jumpmind.db.platform.informix.InformixPlatform; +import org.jumpmind.db.platform.interbase.InterbasePlatform; +import org.jumpmind.db.platform.mssql.MsSqlPlatform; +import org.jumpmind.db.platform.mysql.MySqlPlatform; +import org.jumpmind.db.platform.oracle.OraclePlatform; +import org.jumpmind.db.platform.postgresql.PostgreSqlPlatform; +import org.jumpmind.db.platform.sybase.SybasePlatform; +import org.jumpmind.log.Log; +import org.jumpmind.log.LogFactory; +import org.jumpmind.symmetric.db.db2.Db2SymmetricDialect; +import org.jumpmind.symmetric.db.db2.Db2v9SymmetricDialect; +import org.jumpmind.symmetric.db.derby.DerbySymmetricDialect; +import org.jumpmind.symmetric.db.firebird.FirebirdSymmetricDialect; +import org.jumpmind.symmetric.db.h2.H2SymmetricDialect; +import org.jumpmind.symmetric.db.hsqldb.HsqlDbSymmetricDialect; +import org.jumpmind.symmetric.db.hsqldb2.HsqlDb2SymmetricDialect; +import org.jumpmind.symmetric.db.informix.InformixSymmetricDialect; +import org.jumpmind.symmetric.db.interbase.InterbaseSymmetricDialect; +import org.jumpmind.symmetric.db.mssql.MsSqlSymmetricDialect; +import org.jumpmind.symmetric.db.mysql.MySqlSymmetricDialect; +import org.jumpmind.symmetric.db.oracle.OracleSymmetricDialect; +import org.jumpmind.symmetric.db.postgresql.GreenplumSymmetricDialect; +import org.jumpmind.symmetric.db.postgresql.PostgreSqlSymmetricDialect; +import org.jumpmind.symmetric.db.sybase.SybaseSymmetricDialect; +import org.jumpmind.symmetric.service.IParameterService; + +/** + * Factory class that is responsible for creating the appropriate + * {@link ISymmetricDialect} for the configured database. + */ +public class JdbcSymmetricDialectFactory { + + protected Log log = LogFactory.getLog(getClass()); + + private IParameterService parameterService; + + private IDatabasePlatform platform; + + public JdbcSymmetricDialectFactory(IParameterService parameterService, IDatabasePlatform platform, + Log log) { + this.parameterService = parameterService; + this.platform = platform; + this.log = log; + } + + public ISymmetricDialect create() { + + AbstractSymmetricDialect dialect = null; + + if (platform instanceof MySqlPlatform) { + dialect = new MySqlSymmetricDialect(parameterService, platform); + } else if (platform instanceof OraclePlatform) { + dialect = new OracleSymmetricDialect(parameterService, platform); + } else if (platform instanceof MsSqlPlatform) { + dialect = new MsSqlSymmetricDialect(parameterService, platform); + } else if (platform instanceof GreenplumPlatform) { + dialect = new GreenplumSymmetricDialect(parameterService, platform); + } else if (platform instanceof PostgreSqlPlatform) { + dialect = new PostgreSqlSymmetricDialect(parameterService, platform); + } else if (platform instanceof DerbyPlatform) { + dialect = new DerbySymmetricDialect(parameterService, platform); + } else if (platform instanceof H2Platform) { + dialect = new H2SymmetricDialect(parameterService, platform); + } else if (platform instanceof HsqlDbPlatform) { + dialect = new HsqlDbSymmetricDialect(parameterService, platform); + } else if (platform instanceof HsqlDb2Platform) { + dialect = new HsqlDb2SymmetricDialect(parameterService, platform); + } else if (platform instanceof InformixPlatform) { + dialect = new InformixSymmetricDialect(parameterService, platform); + } else if (platform instanceof Db2Platform) { + int dbMajorVersion = platform.getSqlTemplate().getDatabaseMajorVersion(); + int dbMinorVersion = platform.getSqlTemplate().getDatabaseMinorVersion(); + if (dbMajorVersion < 9 || (dbMajorVersion == 9 && dbMinorVersion < 5)) { + dialect = new Db2SymmetricDialect(parameterService, platform); + } else { + dialect = new Db2v9SymmetricDialect(parameterService, platform); + } + } else if (platform instanceof FirebirdPlatform) { + dialect = new FirebirdSymmetricDialect(parameterService, platform); + } else if (platform instanceof SybasePlatform) { + dialect = new SybaseSymmetricDialect(parameterService, platform); + } else if (platform instanceof InterbasePlatform) { + dialect = new InterbaseSymmetricDialect(parameterService, platform); + } else { + throw new DbNotSupportedException(); + } + return dialect; + } + +} \ No newline at end of file diff --git a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/db/SymmetricDialectFactory.java b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/db/SymmetricDialectFactory.java deleted file mode 100644 index 1244def72a..0000000000 --- a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/db/SymmetricDialectFactory.java +++ /dev/null @@ -1,225 +0,0 @@ -/* - * Licensed to JumpMind Inc under one or more contributor - * license agreements. See the NOTICE file distributed - * with this work for additional information regarding - * copyright ownership. JumpMind Inc licenses this file - * to you under the GNU Lesser General Public License (the - * "License"); you may not use this file except in compliance - * with the License. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see - * . - * - * 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.jumpmind.symmetric.db; - -import java.sql.Connection; -import java.sql.SQLException; - -import org.jumpmind.db.platform.DatabasePlatformSettings; -import org.jumpmind.db.platform.IDatabasePlatform; -import org.jumpmind.db.platform.JdbcDatabasePlatformFactory; -import org.jumpmind.db.platform.db2.Db2Platform; -import org.jumpmind.db.platform.derby.DerbyPlatform; -import org.jumpmind.db.platform.firebird.FirebirdPlatform; -import org.jumpmind.db.platform.greenplum.GreenplumPlatform; -import org.jumpmind.db.platform.h2.H2Platform; -import org.jumpmind.db.platform.hsqldb.HsqlDbPlatform; -import org.jumpmind.db.platform.hsqldb2.HsqlDb2Platform; -import org.jumpmind.db.platform.informix.InformixPlatform; -import org.jumpmind.db.platform.interbase.InterbasePlatform; -import org.jumpmind.db.platform.mssql.MsSqlPlatform; -import org.jumpmind.db.platform.mysql.MySqlPlatform; -import org.jumpmind.db.platform.oracle.OraclePlatform; -import org.jumpmind.db.platform.postgresql.PostgreSqlPlatform; -import org.jumpmind.db.platform.sqlite.SqLitePlatform; -import org.jumpmind.db.platform.sybase.SybasePlatform; -import org.jumpmind.symmetric.common.ParameterConstants; -import org.jumpmind.symmetric.common.logging.ILog; -import org.jumpmind.symmetric.common.logging.LogFactory; -import org.jumpmind.symmetric.service.IParameterService; -import org.springframework.beans.factory.BeanFactory; -import org.springframework.beans.factory.BeanFactoryAware; -import org.springframework.beans.factory.FactoryBean; -import org.springframework.dao.DataAccessException; -import org.springframework.jdbc.CannotGetJdbcConnectionException; -import org.springframework.jdbc.core.ConnectionCallback; -import org.springframework.jdbc.core.JdbcTemplate; - -/** - * Factory class that is responsible for creating the appropriate - * {@link ISymmetricDialect} for the configured database. - */ -public class SymmetricDialectFactory implements FactoryBean, BeanFactoryAware { - - private static final ILog log = LogFactory.getLog(SymmetricDialectFactory.class); - - private IParameterService parameterService; - - private String db2zSeriesProductVersion; - - private JdbcTemplate jdbcTemplate; - - private BeanFactory beanFactory; - - private int queryTimeout; - - private int fetchSize; - - private boolean forceDelimitedIdentifierModeOn = false; - - private boolean forceDelimitedIdentifierModeOff = false; - - private long tableCacheTimeoutInMs; - - public ISymmetricDialect getObject() throws Exception { - - waitForAvailableDatabase(); - - IDatabasePlatform pf = JdbcDatabasePlatformFactory.createNewPlatformInstance( - jdbcTemplate.getDataSource(), - new DatabasePlatformSettings(fetchSize, queryTimeout), - org.jumpmind.log.LogFactory.getLog("org.jumpmind." - + parameterService.getString(ParameterConstants.ENGINE_NAME))); - - if (forceDelimitedIdentifierModeOn) { - pf.setDelimitedIdentifierModeOn(true); - } - - if (forceDelimitedIdentifierModeOff) { - pf.setDelimitedIdentifierModeOn(false); - } - - pf.setClearCacheModelTimeoutInMs(tableCacheTimeoutInMs); - - AbstractSymmetricDialect dialect = null; - - if (pf instanceof MySqlPlatform) { - dialect = (AbstractSymmetricDialect) beanFactory.getBean("mysqlDialect"); - } else if (pf instanceof OraclePlatform) { - dialect = (AbstractSymmetricDialect) beanFactory.getBean("oracleDialect"); - } else if (pf instanceof MsSqlPlatform) { - dialect = (AbstractSymmetricDialect) beanFactory.getBean("msSqlDialect"); - } else if (pf instanceof GreenplumPlatform) { - dialect = (AbstractSymmetricDialect) beanFactory.getBean("greenplumDialect"); - } else if (pf instanceof PostgreSqlPlatform) { - dialect = (AbstractSymmetricDialect) beanFactory.getBean("postgresqlDialect"); - } else if (pf instanceof DerbyPlatform) { - dialect = (AbstractSymmetricDialect) beanFactory.getBean("derbyDialect"); - } else if (pf instanceof H2Platform) { - dialect = (AbstractSymmetricDialect) beanFactory.getBean("h2Dialect"); - } else if (pf instanceof SqLitePlatform) { - dialect = (AbstractSymmetricDialect) beanFactory.getBean("sqliteDialect"); - } else if (pf instanceof HsqlDbPlatform) { - dialect = (AbstractSymmetricDialect) beanFactory.getBean("hsqldbDialect"); - } else if (pf instanceof HsqlDb2Platform) { - dialect = (AbstractSymmetricDialect) beanFactory.getBean("hsqldb2Dialect"); - } else if (pf instanceof InformixPlatform) { - dialect = (AbstractSymmetricDialect) beanFactory.getBean("informixDialect"); - } else if (pf instanceof Db2Platform) { - String currentDbProductVersion = JdbcDatabasePlatformFactory - .getDatabaseProductVersion(jdbcTemplate.getDataSource()); - if (currentDbProductVersion.equals(db2zSeriesProductVersion)) { - dialect = (AbstractSymmetricDialect) beanFactory.getBean("db2zSeriesDialect"); - } else { - int dbMajorVersion = JdbcDatabasePlatformFactory - .getDatabaseMajorVersion(jdbcTemplate.getDataSource()); - int dbMinorVersion = JdbcDatabasePlatformFactory - .getDatabaseMinorVersion(jdbcTemplate.getDataSource()); - if (dbMajorVersion < 9 || (dbMajorVersion == 9 && dbMinorVersion < 5)) { - dialect = (AbstractSymmetricDialect) beanFactory.getBean("db2Dialect"); - } else { - dialect = (AbstractSymmetricDialect) beanFactory.getBean("db2v9Dialect"); - } - } - } else if (pf instanceof FirebirdPlatform) { - dialect = (AbstractSymmetricDialect) beanFactory.getBean("firebirdDialect"); - } else if (pf instanceof SybasePlatform) { - dialect = (AbstractSymmetricDialect) beanFactory.getBean("sybaseDialect"); - } else if (pf instanceof InterbasePlatform) { - dialect = (AbstractSymmetricDialect) beanFactory.getBean("interbaseDialect"); - } else { - throw new DbNotSupportedException(); - } - - dialect.init(pf, queryTimeout, jdbcTemplate); - return dialect; - } - - private void waitForAvailableDatabase() { - boolean success = false; - while (!success) { - try { - jdbcTemplate.execute(new ConnectionCallback() { - public Object doInConnection(Connection con) throws SQLException, - DataAccessException { - return null; - } - }); - success = true; - } catch (CannotGetJdbcConnectionException ex) { - log.error("DatabaseConnectionException", ex.getMessage()); - try { - Thread.sleep(10000); - } catch (InterruptedException e) { - } - } - } - } - - public Class getObjectType() { - return ISymmetricDialect.class; - } - - public boolean isSingleton() { - return true; - } - - public void setBeanFactory(BeanFactory beanFactory) { - this.beanFactory = beanFactory; - } - - public void setJdbcTemplate(JdbcTemplate jdbcTemplate) { - this.jdbcTemplate = jdbcTemplate; - } - - /** - * Sets the database product version for zOS db2 from the properties file - */ - public void setDb2zSeriesProductVersion(String version) { - this.db2zSeriesProductVersion = version; - } - - public void setQueryTimeout(int queryTimeout) { - this.queryTimeout = queryTimeout; - } - - public void setFetchSize(int fetchSize) { - this.fetchSize = fetchSize; - } - - public void setForceDelimitedIdentifierModeOn(boolean forceDelimitedIdentifierModeOn) { - this.forceDelimitedIdentifierModeOn = forceDelimitedIdentifierModeOn; - } - - public void setForceDelimitedIdentifierModeOff(boolean forceDelimitedIdentifierModeOff) { - this.forceDelimitedIdentifierModeOff = forceDelimitedIdentifierModeOff; - } - - public void setParameterService(IParameterService parameterService) { - this.parameterService = parameterService; - } - - public void setTableCacheTimeoutInMs(long tableCacheTimeoutInMs) { - this.tableCacheTimeoutInMs = tableCacheTimeoutInMs; - } - -} \ No newline at end of file diff --git a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/db/db2/Db2SymmetricDialect.java b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/db/db2/Db2SymmetricDialect.java index b55c54cdb4..b8d6dd1a83 100644 --- a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/db/db2/Db2SymmetricDialect.java +++ b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/db/db2/Db2SymmetricDialect.java @@ -21,39 +21,42 @@ package org.jumpmind.symmetric.db.db2; +import org.jumpmind.db.platform.IDatabasePlatform; import org.jumpmind.db.sql.ISqlTransaction; import org.jumpmind.db.util.BinaryEncoding; import org.jumpmind.symmetric.db.AbstractSymmetricDialect; import org.jumpmind.symmetric.db.ISymmetricDialect; import org.jumpmind.symmetric.model.Trigger; +import org.jumpmind.symmetric.service.IParameterService; /* * A dialect that is specific to DB2 databases */ public class Db2SymmetricDialect extends AbstractSymmetricDialect implements ISymmetricDialect { - public Db2SymmetricDialect() { + public Db2SymmetricDialect(IParameterService parameterService, IDatabasePlatform platform) { + super(parameterService, platform); this.triggerText = new Db2TriggerText(); } protected boolean createTablesIfNecessary() { boolean tablesCreated = super.createTablesIfNecessary(); if (tablesCreated) { - long triggerHistId = jdbcTemplate.queryForLong("select max(trigger_hist_id) from " - + tablePrefix + "_trigger_hist") + 1; - jdbcTemplate.update("alter table " + tablePrefix + long triggerHistId = platform.getSqlTemplate().queryForLong("select max(trigger_hist_id) from " + + parameterService.getTablePrefix() + "_trigger_hist") + 1; + platform.getSqlTemplate().update("alter table " + parameterService.getTablePrefix() + "_trigger_hist alter column trigger_hist_id restart with " + triggerHistId); - log.info("DB2ResettingAutoIncrementColumns", tablePrefix + "_trigger_hist"); - long outgoingBatchId = jdbcTemplate.queryForLong("select max(batch_id) from " - + tablePrefix + "_outgoing_batch") + 1; - jdbcTemplate.update("alter table " + tablePrefix + log.info("DB2ResettingAutoIncrementColumns", parameterService.getTablePrefix() + "_trigger_hist"); + long outgoingBatchId = platform.getSqlTemplate().queryForLong("select max(batch_id) from " + + parameterService.getTablePrefix() + "_outgoing_batch") + 1; + platform.getSqlTemplate().update("alter table " + parameterService.getTablePrefix() + "_outgoing_batch alter column batch_id restart with " + outgoingBatchId); - log.info("DB2ResettingAutoIncrementColumns", tablePrefix + "_outgoing_batch"); - long dataId = jdbcTemplate.queryForLong("select max(data_id) from " + tablePrefix + log.info("DB2ResettingAutoIncrementColumns", parameterService.getTablePrefix() + "_outgoing_batch"); + long dataId = platform.getSqlTemplate().queryForLong("select max(data_id) from " + parameterService.getTablePrefix() + "_data") + 1; - jdbcTemplate.update("alter table " + tablePrefix + platform.getSqlTemplate().update("alter table " + parameterService.getTablePrefix() + "_data alter column data_id restart with " + dataId); - log.info("DB2ResettingAutoIncrementColumns", tablePrefix + "_data"); + log.info("DB2ResettingAutoIncrementColumns", parameterService.getTablePrefix() + "_data"); } return tablesCreated; } @@ -63,7 +66,7 @@ protected boolean doesTriggerExistOnPlatform(String catalog, String schema, Stri String triggerName) { schema = schema == null ? (platform.getDefaultSchema() == null ? null : platform .getDefaultSchema()) : schema; - return jdbcTemplate.queryForInt( + return platform.getSqlTemplate().queryForInt( "select count(*) from syscat.triggers where trigname = ? and trigschema = ?", new Object[] { triggerName.toUpperCase(), schema.toUpperCase() }) > 0; } @@ -99,32 +102,17 @@ public String getTransactionTriggerExpression(String defaultCatalog, String defa return "null"; } - @Override - public String getSelectLastInsertIdSql(String sequenceName) { - return "values IDENTITY_VAL_LOCAL()"; - } - @Override public boolean supportsTransactionId() { return false; } - @Override - public boolean supportsGetGeneratedKeys() { - return false; - } - - @Override - protected boolean allowsNullForIdentityColumn() { - return false; - } - public void purge() { } @Override public void truncateTable(String tableName) { - jdbcTemplate.update("delete from " + tableName); + platform.getSqlTemplate().update("delete from " + tableName); } @Override diff --git a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/db/db2/Db2v9SymmetricDialect.java b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/db/db2/Db2v9SymmetricDialect.java index 96d2d876e8..ce11df3774 100644 --- a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/db/db2/Db2v9SymmetricDialect.java +++ b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/db/db2/Db2v9SymmetricDialect.java @@ -21,8 +21,11 @@ import java.net.URL; +import org.jumpmind.db.platform.IDatabasePlatform; +import org.jumpmind.db.sql.ISqlTransaction; import org.jumpmind.db.sql.SqlScript; import org.jumpmind.symmetric.db.ISymmetricDialect; +import org.jumpmind.symmetric.service.IParameterService; import org.springframework.jdbc.core.JdbcTemplate; public class Db2v9SymmetricDialect extends Db2SymmetricDialect implements ISymmetricDialect { @@ -31,10 +34,17 @@ public class Db2v9SymmetricDialect extends Db2SymmetricDialect implements ISymme static final String SYNC_TRIGGERS_DISABLED_NODE_VARIABLE = "sync_node_disabled"; + public Db2v9SymmetricDialect(IParameterService parameterService, IDatabasePlatform platform) { + super(parameterService, platform); + } + @Override protected void initTablesAndFunctionsForSpecificDialect() { + ISqlTransaction transaction = null; try { - enableSyncTriggers(jdbcTemplate); + transaction = platform.getSqlTemplate().startSqlTransaction(); + enableSyncTriggers(transaction); + transaction.commit(); } catch (Exception e) { try { log.info("EnvironmentVariablesCreating", SYNC_TRIGGERS_DISABLED_USER_VARIABLE, @@ -43,6 +53,8 @@ protected void initTablesAndFunctionsForSpecificDialect() { } catch (Exception ex) { log.error("DB2DialectInitializingError", ex); } + } finally { + close(transaction); } } @@ -57,9 +69,9 @@ public void disableSyncTriggers(JdbcTemplate jdbcTemplate, String nodeId) { } } - public void enableSyncTriggers(JdbcTemplate jdbcTemplate) { - jdbcTemplate.update("set " + SYNC_TRIGGERS_DISABLED_USER_VARIABLE + "=null"); - jdbcTemplate.update("set " + SYNC_TRIGGERS_DISABLED_NODE_VARIABLE + "=null"); + public void enableSyncTriggers(ISqlTransaction transaction) { + transaction.execute("set " + SYNC_TRIGGERS_DISABLED_USER_VARIABLE + "=null"); + transaction.execute("set " + SYNC_TRIGGERS_DISABLED_NODE_VARIABLE + "=null"); } public String getSyncTriggersExpression() { diff --git a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/db/db2/Db2zSeriesSymmetricDialect.java b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/db/db2/Db2zSeriesSymmetricDialect.java deleted file mode 100644 index 184b0c1ef4..0000000000 --- a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/db/db2/Db2zSeriesSymmetricDialect.java +++ /dev/null @@ -1,223 +0,0 @@ -/* - * Licensed to JumpMind Inc under one or more contributor - * license agreements. See the NOTICE file distributed - * with this work for additional information regarding - * copyright ownership. JumpMind Inc licenses this file - * to you under the GNU Lesser General Public License (the - * "License"); you may not use this file except in compliance - * with the License. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see - * . - * - * 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.jumpmind.symmetric.db.db2; - -import java.sql.Connection; -import java.sql.PreparedStatement; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.sql.Statement; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.jumpmind.db.sql.ISqlTransaction; -import org.jumpmind.db.util.BinaryEncoding; -import org.jumpmind.symmetric.db.AbstractSymmetricDialect; -import org.jumpmind.symmetric.db.ISymmetricDialect; -import org.jumpmind.symmetric.db.SequenceIdentifier; -import org.jumpmind.symmetric.model.Trigger; -import org.springframework.dao.DataAccessException; -import org.springframework.jdbc.core.ConnectionCallback; -import org.springframework.jdbc.core.PreparedStatementCallback; -import org.springframework.jdbc.support.JdbcUtils; - -public class Db2zSeriesSymmetricDialect extends AbstractSymmetricDialect implements - ISymmetricDialect { - - static final Log logger = LogFactory.getLog(Db2zSeriesSymmetricDialect.class); - - private String userName; - - public Db2zSeriesSymmetricDialect() { - this.triggerText = new Db2zSeriesTriggerText(); - } - - /* - * Returns the database user id - * - * @return String - */ - public String getUserName() { - return userName; - } - - /* - * Sets the database user id from properties file - * - * @param userName - */ - public void setUserName(String userName) { - this.userName = userName; - } - - @Override - protected boolean doesTriggerExistOnPlatform(String catalog, String schema, String tableName, - String triggerName) { - schema = schema == null ? (platform.getDefaultSchema() == null ? null : platform - .getDefaultSchema()) : schema; - return jdbcTemplate.queryForInt("SELECT COUNT(*) FROM SYSIBM.SYSTRIGGERS WHERE NAME = ?", - new Object[] { triggerName.toUpperCase() }) > 0; - } - - @Override - public boolean isBlobSyncSupported() { - return true; - } - - @Override - public boolean isClobSyncSupported() { - return true; - } - - @Override - public BinaryEncoding getBinaryEncoding() { - return BinaryEncoding.HEX; - } - - @Override - public String getTransactionTriggerExpression(String defaultCatalog, String defaultSchema, - Trigger trigger) { - return "nullif('','')"; - } - - @Override - public String getSelectLastInsertIdSql(String sequenceName) { - return "values IDENTITY_VAL_LOCAL()"; - } - - public boolean isNonBlankCharColumnSpacePadded() { - return true; - } - - public boolean isCharColumnSpaceTrimmed() { - return false; - } - - public boolean isEmptyStringNulled() { - return false; - } - - @Override - public boolean supportsGetGeneratedKeys() { - return true; - } - - @Override - protected boolean allowsNullForIdentityColumn() { - return false; - } - - public void purge() { - } - - public String getDefaultCatalog() { - return null; - } - - public void enableSyncTriggers(ISqlTransaction transaction) { - } - - public void disableSyncTriggers(ISqlTransaction transaction, String nodeId) { - } - - public String getSyncTriggersExpression() { - return ""; - } - - @Override - public long insertWithGeneratedKey(final String sql, final SequenceIdentifier sequenceId, - final PreparedStatementCallback callback) { - return (Long) jdbcTemplate.execute(new ConnectionCallback() { - public Long doInConnection(Connection conn) throws SQLException, DataAccessException { - - long key = 0; - PreparedStatement ps = null; - try { - boolean supportsGetGeneratedKeys = supportsGetGeneratedKeys(); - boolean supportsReturningKeys = supportsReturningKeys(); - if (allowsNullForIdentityColumn()) { - if (supportsGetGeneratedKeys) { - ps = conn.prepareStatement(sql, new int[] { 1 }); - } else if (supportsReturningKeys) { - ps = conn.prepareStatement(sql + " returning " - + getSequenceKeyName(sequenceId)); - } else { - ps = conn.prepareStatement(sql); - } - } else { - String replaceSql = sql.replaceFirst("\\(\\w*,", "(").replaceFirst( - "\\(null,", "("); - System.out.println("======================================"); - System.out.println(replaceSql); - System.out.println("======================================"); - if (supportsGetGeneratedKeys) { - ps = conn.prepareStatement(replaceSql, Statement.RETURN_GENERATED_KEYS); - } else { - ps = conn.prepareStatement(replaceSql); - } - } - ps.setQueryTimeout(jdbcTemplate.getQueryTimeout()); - if (callback != null) { - callback.doInPreparedStatement(ps); - } - - ResultSet rs = null; - if (supportsGetGeneratedKeys) { - ps.executeUpdate(); - try { - rs = ps.getGeneratedKeys(); - if (rs.next()) { - key = rs.getLong(1); - } - } finally { - JdbcUtils.closeResultSet(rs); - } - } else if (supportsReturningKeys) { - try { - rs = ps.executeQuery(); - if (rs.next()) { - key = rs.getLong(1); - } - } finally { - JdbcUtils.closeResultSet(rs); - } - } else { - Statement st = null; - ps.executeUpdate(); - try { - st = conn.createStatement(); - rs = st.executeQuery(getSelectLastInsertIdSql(getSequenceName(sequenceId))); - if (rs.next()) { - key = rs.getLong(1); - } - } finally { - JdbcUtils.closeResultSet(rs); - JdbcUtils.closeStatement(st); - } - } - } finally { - JdbcUtils.closeStatement(ps); - } - return key; - } - }); - } -} \ No newline at end of file diff --git a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/db/db2/Db2zSeriesTriggerText.java b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/db/db2/Db2zSeriesTriggerText.java deleted file mode 100644 index 55b6ffbcc8..0000000000 --- a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/db/db2/Db2zSeriesTriggerText.java +++ /dev/null @@ -1,90 +0,0 @@ -package org.jumpmind.symmetric.db.db2; - -import org.jumpmind.symmetric.db.TriggerText; -import java.util.HashMap; - -public class Db2zSeriesTriggerText extends TriggerText { - - public Db2zSeriesTriggerText() { - functionInstalledSql = "select count(*) from sysibm.sysfunctions where name = '$(functionName)'" ; - emptyColumnTemplate = "''" ; - stringColumnTemplate = "case when $(tableAlias).\"$(columnName)\" is null then '' when length($(tableAlias).\"$(columnName)\") = 0 then '' else '\"' || replace(replace($(tableAlias).\"$(columnName)\",'\\','\\\\'),'\"','\\\"') || '\"' end" ; - xmlColumnTemplate = null; - arrayColumnTemplate = null; - numberColumnTemplate = "case when $(tableAlias).\"$(columnName)\" is null then '' else '\"' || STRIP(char($(tableAlias).\"$(columnName)\")) || '\"' end" ; - datetimeColumnTemplate = "case when $(tableAlias).\"$(columnName)\" is null then '' else '\"' || STRIP(char(year($(tableAlias).\"$(columnName)\")))||'-'||substr(digits(month($(tableAlias).\"$(columnName)\")),9)||'-'||substr(digits(day($(tableAlias).\"$(columnName)\")),9)||' '||substr(digits(hour($(tableAlias).\"$(columnName)\")),9)||':'||substr(digits(minute($(tableAlias).\"$(columnName)\")),9)||':'||substr(digits(second($(tableAlias).\"$(columnName)\")),9)||'.'||STRIP(char(microsecond($(tableAlias).\"$(columnName)\"))) || '\"' end" ; - timeColumnTemplate = "case when $(tableAlias).\"$(columnName)\" is null then '' else '\"' || substr(digits(hour($(tableAlias).\"$(columnName)\")),9)||':'||substr(digits(minute($(tableAlias).\"$(columnName)\")),9)||':'||substr(digits(second($(tableAlias).\"$(columnName)\")),9)|| '\"' end" ; - dateColumnTemplate = "case when $(tableAlias).\"$(columnName)\" is null then '' else '\"' || STRIP(char(year($(tableAlias).\"$(columnName)\")))||'-'||substr(digits(month($(tableAlias).\"$(columnName)\")),9)||'-'||substr(digits(day($(tableAlias).\"$(columnName)\")),9)|| '\"' end" ; - clobColumnTemplate = "case when $(tableAlias).\"$(columnName)\" is null then '' else '\"' || cast($(tableAlias).\"$(columnName)\" as varchar(32672)) || '\"' end" ; - blobColumnTemplate = "case when $(tableAlias).\"$(columnName)\" is null then '' else hex(cast($(tableAlias).\"$(columnName)\" as varchar(16336) for bit data)) end" ; - wrappedBlobColumnTemplate = null; - booleanColumnTemplate = null; - triggerConcatCharacter = "||" ; - newTriggerValue = "new" ; - oldTriggerValue = "old" ; - oldColumnPrefix = "" ; - newColumnPrefix = "" ; - otherColumnTemplate = null; - - sqlTemplates = new HashMap(); - sqlTemplates.put("insertTriggerTemplate" , -"CREATE TRIGGER $(triggerName) " + -" AFTER INSERT ON $(schemaName)$(tableName) " + -" REFERENCING NEW AS NEW " + -" FOR EACH ROW MODE DB2SQL " + -" WHEN ($(syncOnInsertCondition)) " + -" BEGIN ATOMIC " + -" INSERT into $(defaultSchema)$(prefixName)_data " + -" (table_name, event_type, trigger_hist_id, row_data, create_time) " + -" VALUES('$(targetTableName)', 'I', $(triggerHistoryId), " + -" $(columns), " + -" CURRENT_TIMESTAMP); " + -" INSERT into $(defaultSchema)$(prefixName)_data_event " + -" (node_id, data_id, channel_id, transaction_id) " + -" SELECT node_id, IDENTITY_VAL_LOCAL(), '$(channelName)', " + -" $(txIdExpression) from $(prefixName)_node c " + -" where (c.node_group_id = '$(targetGroupId)' and c.sync_enabled = 1) $(nodeSelectWhere); " + -" END; " ); - sqlTemplates.put("updateTriggerTemplate" , -"CREATE TRIGGER $(triggerName) " + -" AFTER UPDATE ON $(schemaName)$(tableName) " + -" REFERENCING OLD AS OLD NEW AS NEW " + -" FOR EACH ROW MODE DB2SQL " + -" WHEN ($(syncOnUpdateCondition)) " + -" BEGIN ATOMIC " + -" INSERT into $(defaultSchema)$(prefixName)_data " + -" (table_name, event_type, trigger_hist_id, pk_data, row_data, old_data, create_time) " + -" VALUES('$(targetTableName)', 'U', $(triggerHistoryId), " + -" $(oldKeys), " + -" $(columns), " + -" $(oldColumns), " + -" CURRENT_TIMESTAMP); " + -" INSERT into $(defaultSchema)$(prefixName)_data_event " + -" (node_id, data_id, channel_id, transaction_id) " + -" SELECT node_id, IDENTITY_VAL_LOCAL(), '$(channelName)', " + -" $(txIdExpression) from $(prefixName)_node c " + -" where (c.node_group_id = '$(targetGroupId)' and c.sync_enabled = 1) $(nodeSelectWhere); " + -" END; " ); - sqlTemplates.put("deleteTriggerTemplate" , -"CREATE TRIGGER $(triggerName) " + -" AFTER DELETE ON $(schemaName)$(tableName) " + -" REFERENCING OLD AS OLD " + -" FOR EACH ROW MODE DB2SQL " + -" WHEN ($(syncOnDeleteCondition)) " + -" BEGIN ATOMIC " + -" INSERT into $(defaultSchema)$(prefixName)_data " + -" (table_name, event_type, trigger_hist_id, pk_data, create_time) " + -" VALUES ('$(targetTableName)', 'D', $(triggerHistoryId), " + -" $(oldKeys), " + -" CURRENT_TIMESTAMP); " + -" INSERT into $(defaultSchema)$(prefixName)_data_event " + -" (node_id, data_id, channel_id, transaction_id) " + -" SELECT node_id, IDENTITY_VAL_LOCAL(), '$(channelName)', " + -" $(txIdExpression) from $(prefixName)_node c " + -" where (c.node_group_id = '$(targetGroupId)' and c.sync_enabled = 1) $(nodeSelectWhere); " + -" END; " ); - sqlTemplates.put("initialLoadSqlTemplate" , -"select $(columns) from $(schemaName)$(tableName) t where $(whereClause) " ); - } - -} \ No newline at end of file diff --git a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/db/derby/DerbySymmetricDialect.java b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/db/derby/DerbySymmetricDialect.java index 79ec15ea5e..b35a1e6113 100644 --- a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/db/derby/DerbySymmetricDialect.java +++ b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/db/derby/DerbySymmetricDialect.java @@ -21,15 +21,18 @@ package org.jumpmind.symmetric.db.derby; +import org.jumpmind.db.platform.IDatabasePlatform; import org.jumpmind.db.sql.ISqlTransaction; import org.jumpmind.db.util.BinaryEncoding; import org.jumpmind.symmetric.db.AbstractSymmetricDialect; import org.jumpmind.symmetric.db.ISymmetricDialect; import org.jumpmind.symmetric.model.Trigger; +import org.jumpmind.symmetric.service.IParameterService; public class DerbySymmetricDialect extends AbstractSymmetricDialect implements ISymmetricDialect { - public DerbySymmetricDialect() { + public DerbySymmetricDialect(IParameterService parameterService, IDatabasePlatform platform) { + super(parameterService, platform); this.triggerText = new DerbyTriggerText(); } @@ -38,7 +41,7 @@ protected boolean doesTriggerExistOnPlatform(String catalog, String schema, Stri String triggerName) { schema = schema == null ? (platform.getDefaultSchema() == null ? null : platform .getDefaultSchema()) : schema; - return jdbcTemplate.queryForInt( + return platform.getSqlTemplate().queryForInt( "select count(*) from sys.systriggers where triggername = ?", new Object[] { triggerName.toUpperCase() }) > 0; } @@ -65,46 +68,31 @@ public BinaryEncoding getBinaryEncoding() { public void disableSyncTriggers(ISqlTransaction transaction, String nodeId) { transaction.queryForObject( - String.format("values %s_sync_triggers_set_disabled(1)", tablePrefix), + String.format("values %s_sync_triggers_set_disabled(1)", parameterService.getTablePrefix()), Integer.class); if (nodeId != null) { transaction.queryForObject( - String.format("values %s_sync_node_set_disabled('%s')", tablePrefix, nodeId), + String.format("values %s_sync_node_set_disabled('%s')", parameterService.getTablePrefix(), nodeId), String.class); } } public void enableSyncTriggers(ISqlTransaction transaction) { transaction.queryForObject( - String.format("values %s_sync_triggers_set_disabled(0)", tablePrefix), + String.format("values %s_sync_triggers_set_disabled(0)", parameterService.getTablePrefix()), Integer.class); - jdbcTemplate.queryForObject( - String.format("values %s_sync_node_set_disabled(null)", tablePrefix), String.class); + platform.getSqlTemplate().queryForObject( + String.format("values %s_sync_node_set_disabled(null)", parameterService.getTablePrefix()), String.class); } public String getSyncTriggersExpression() { - return String.format("%s_sync_triggers_disabled() = 0", tablePrefix); + return String.format("%s_sync_triggers_disabled() = 0", parameterService.getTablePrefix()); } @Override public String getTransactionTriggerExpression(String defaultCatalog, String defaultSchema, Trigger trigger) { - return String.format("%s_transaction_id()", tablePrefix); - } - - @Override - public String getSelectLastInsertIdSql(String sequenceName) { - return "values IDENTITY_VAL_LOCAL()"; - } - - @Override - public boolean supportsGetGeneratedKeys() { - return false; - } - - @Override - protected boolean allowsNullForIdentityColumn() { - return false; + return String.format("%s_transaction_id()", parameterService.getTablePrefix()); } public void purge() { @@ -112,7 +100,7 @@ public void purge() { @Override public void truncateTable(String tableName) { - jdbcTemplate.update("delete from " + tableName); + platform.getSqlTemplate().update("delete from " + tableName); } public boolean needsToSelectLobData() { diff --git a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/db/firebird/FirebirdSymmetricDialect.java b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/db/firebird/FirebirdSymmetricDialect.java index 6ef1cff45a..72249ccd12 100644 --- a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/db/firebird/FirebirdSymmetricDialect.java +++ b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/db/firebird/FirebirdSymmetricDialect.java @@ -19,11 +19,13 @@ * under the License. */ package org.jumpmind.symmetric.db.firebird; +import org.jumpmind.db.platform.IDatabasePlatform; import org.jumpmind.db.sql.ISqlTransaction; import org.jumpmind.db.util.BinaryEncoding; import org.jumpmind.symmetric.db.AbstractSymmetricDialect; import org.jumpmind.symmetric.db.ISymmetricDialect; import org.jumpmind.symmetric.model.Trigger; +import org.jumpmind.symmetric.service.IParameterService; import org.springframework.jdbc.UncategorizedSQLException; /* @@ -35,7 +37,8 @@ public class FirebirdSymmetricDialect extends AbstractSymmetricDialect implement static final String SYNC_TRIGGERS_DISABLED_NODE_VARIABLE = "sync_node_disabled"; - public FirebirdSymmetricDialect() { + public FirebirdSymmetricDialect(IParameterService parameterService, IDatabasePlatform platform) { + super(parameterService, platform); this.triggerText = new FirebirdTriggerText(); } @@ -43,7 +46,7 @@ public FirebirdSymmetricDialect() { protected void createRequiredFunctions() { super.createRequiredFunctions(); try { - jdbcTemplate.queryForInt("select char_length(sym_escape('')) from rdb$database"); + platform.getSqlTemplate().queryForInt("select char_length(sym_escape('')) from rdb$database"); } catch (UncategorizedSQLException e) { if (e.getSQLException().getErrorCode() == -804) { log.error("FirebirdSymUdfMissing"); @@ -54,7 +57,7 @@ protected void createRequiredFunctions() { @Override protected boolean doesTriggerExistOnPlatform(String catalogName, String schema, String tableName, String triggerName) { - return jdbcTemplate.queryForInt("select count(*) from rdb$triggers where rdb$trigger_name = ?", + return platform.getSqlTemplate().queryForInt("select count(*) from rdb$triggers where rdb$trigger_name = ?", new Object[] { triggerName.toUpperCase() }) > 0; } @@ -83,11 +86,6 @@ public String getTransactionTriggerExpression(String defaultCatalog, String defa return "current_transaction||''"; } - @Override - public boolean supportsReturningKeys() { - return true; - } - @Override public boolean isBlobSyncSupported() { return true; @@ -98,11 +96,6 @@ public BinaryEncoding getBinaryEncoding() { return BinaryEncoding.HEX; } - @Override - protected boolean allowsNullForIdentityColumn() { - return true; - } - public void purge() { } @@ -123,7 +116,7 @@ public boolean supportsTransactionId() { @Override public void truncateTable(String tableName) { - jdbcTemplate.update("delete from " + tableName); + platform.getSqlTemplate().update("delete from " + tableName); } } \ No newline at end of file diff --git a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/db/h2/H2SymmetricDialect.java b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/db/h2/H2SymmetricDialect.java index ab6cc3de89..b620d6bd40 100644 --- a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/db/h2/H2SymmetricDialect.java +++ b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/db/h2/H2SymmetricDialect.java @@ -20,6 +20,7 @@ package org.jumpmind.symmetric.db.h2; +import org.jumpmind.db.platform.IDatabasePlatform; import org.jumpmind.db.sql.ISqlTransaction; import org.jumpmind.db.util.BinaryEncoding; import org.jumpmind.symmetric.common.ParameterConstants; @@ -27,23 +28,25 @@ import org.jumpmind.symmetric.db.ISymmetricDialect; import org.jumpmind.symmetric.model.Trigger; import org.jumpmind.symmetric.model.TriggerHistory; +import org.jumpmind.symmetric.service.IParameterService; /* * Synchronization support for the H2 database platform. */ public class H2SymmetricDialect extends AbstractEmbeddedSymmetricDialect implements ISymmetricDialect { - public H2SymmetricDialect() { + public H2SymmetricDialect(IParameterService parameterService, IDatabasePlatform platform) { + super(parameterService, platform); this.triggerText = new H2TriggerText(); } @Override protected boolean doesTriggerExistOnPlatform(String catalogName, String schemaName, String tableName, String triggerName) { - boolean exists = (jdbcTemplate + boolean exists = (platform.getSqlTemplate() .queryForInt("select count(*) from INFORMATION_SCHEMA.TRIGGERS WHERE TRIGGER_NAME = ?", new Object[] { triggerName }) > 0) - && (jdbcTemplate.queryForInt("select count(*) from INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = ?", + && (platform.getSqlTemplate().queryForInt("select count(*) from INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = ?", new Object[] { String.format("%s_CONFIG", triggerName) }) > 0); if (!exists) { @@ -63,11 +66,11 @@ public void removeTrigger(StringBuilder sqlBuffer, String catalogName, String sc if (parameterService.is(ParameterConstants.AUTO_SYNC_TRIGGERS)) { try { - int count = jdbcTemplate.update(dropSql); + int count = platform.getSqlTemplate().update(dropSql); if (count > 0) { log.info("TriggerDropped", triggerName); } - count = jdbcTemplate.update(dropTable); + count = platform.getSqlTemplate().update(dropTable); if (count > 0) { log.info("TableDropped", triggerName); } @@ -109,29 +112,15 @@ public String getTransactionTriggerExpression(String defaultCatalog, String defa return "TRANSACTION_ID()"; } - @Override - public String getSelectLastInsertIdSql(String sequenceName) { - return "call IDENTITY()"; - } - @Override public BinaryEncoding getBinaryEncoding() { return BinaryEncoding.BASE64; } - @Override - public boolean supportsGetGeneratedKeys() { - return false; - } @Override public boolean supportsTransactionId() { return true; } - @Override - protected boolean allowsNullForIdentityColumn() { - return false; - } - } \ No newline at end of file diff --git a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/db/hsqldb/HsqlDbSymmetricDialect.java b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/db/hsqldb/HsqlDbSymmetricDialect.java index baa54e5e10..2010f107f3 100644 --- a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/db/hsqldb/HsqlDbSymmetricDialect.java +++ b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/db/hsqldb/HsqlDbSymmetricDialect.java @@ -29,28 +29,25 @@ import org.jumpmind.symmetric.db.ISymmetricDialect; import org.jumpmind.symmetric.model.Trigger; import org.jumpmind.symmetric.model.TriggerHistory; -import org.springframework.jdbc.core.JdbcTemplate; +import org.jumpmind.symmetric.service.IParameterService; public class HsqlDbSymmetricDialect extends AbstractEmbeddedSymmetricDialect implements ISymmetricDialect { public static String DUAL_TABLE = "DUAL"; - private boolean enforceStrictSize = true; - - public HsqlDbSymmetricDialect() { + private boolean enforceStrictSize = true; + + public HsqlDbSymmetricDialect(IParameterService parameterService, IDatabasePlatform platform) { + super(parameterService, platform); this.triggerText = new HsqlDbTriggerText(); - } - - @Override - public void init(IDatabasePlatform pf, int queryTimeout, final JdbcTemplate jdbcTemplate) { - super.init(pf, queryTimeout, jdbcTemplate); - jdbcTemplate.update("SET WRITE_DELAY 100 MILLIS"); - jdbcTemplate.update("SET PROPERTY \"hsqldb.default_table_type\" 'cached'"); - jdbcTemplate.update("SET PROPERTY \"sql.enforce_strict_size\" " + enforceStrictSize); + + platform.getSqlTemplate().update("SET WRITE_DELAY 100 MILLIS"); + platform.getSqlTemplate().update("SET PROPERTY \"hsqldb.default_table_type\" 'cached'"); + platform.getSqlTemplate().update("SET PROPERTY \"sql.enforce_strict_size\" " + enforceStrictSize); Runtime.getRuntime().addShutdownHook(new Thread() { @Override public void run() { - jdbcTemplate.update("SHUTDOWN"); + HsqlDbSymmetricDialect.this.platform.getSqlTemplate().update("SHUTDOWN"); } }); createDummyDualTable(); @@ -59,10 +56,10 @@ public void run() { @Override protected boolean doesTriggerExistOnPlatform(String catalogName, String schemaName, String tableName, String triggerName) { - boolean exists = (jdbcTemplate.queryForInt( + boolean exists = (platform.getSqlTemplate().queryForInt( "select count(*) from INFORMATION_SCHEMA.SYSTEM_TRIGGERS WHERE TRIGGER_NAME = ?", new Object[] { triggerName }) > 0) - || (jdbcTemplate.queryForInt( + || (platform.getSqlTemplate().queryForInt( "select count(*) from INFORMATION_SCHEMA.SYSTEM_TABLES WHERE TABLE_NAME = ?", new Object[] { String.format("%s_CONFIG", triggerName) }) > 0); return exists; @@ -75,9 +72,9 @@ protected boolean doesTriggerExistOnPlatform(String catalogName, String schemaNa private void createDummyDualTable() { Table table = platform.getTableFromCache(null, null, DUAL_TABLE, true); if (table == null) { - jdbcTemplate.update("CREATE MEMORY TABLE " + DUAL_TABLE + "(DUMMY VARCHAR(1))"); - jdbcTemplate.update("INSERT INTO " + DUAL_TABLE + " VALUES(NULL)"); - jdbcTemplate.update("SET TABLE " + DUAL_TABLE + " READONLY TRUE"); + platform.getSqlTemplate().update("CREATE MEMORY TABLE " + DUAL_TABLE + "(DUMMY VARCHAR(1))"); + platform.getSqlTemplate().update("INSERT INTO " + DUAL_TABLE + " VALUES(NULL)"); + platform.getSqlTemplate().update("SET TABLE " + DUAL_TABLE + " READONLY TRUE"); } } @@ -93,7 +90,7 @@ public void removeTrigger(StringBuilder sqlBuffer, String catalogName, String sc if (parameterService.is(ParameterConstants.AUTO_SYNC_TRIGGERS)) { try { - int count = jdbcTemplate.update(dropSql); + int count = platform.getSqlTemplate().update(dropSql); if (count > 0) { log.info("TriggerDropped", triggerName); } @@ -101,7 +98,7 @@ public void removeTrigger(StringBuilder sqlBuffer, String catalogName, String sc log.warn("TriggerDropError", triggerName, e.getMessage()); } try { - int count = jdbcTemplate.update(dropTable); + int count = platform.getSqlTemplate().update(dropTable); if (count > 0) { log.info("TableDropped", triggerName); } @@ -122,17 +119,17 @@ public boolean isClobSyncSupported() { } public void disableSyncTriggers(ISqlTransaction transaction, String nodeId) { - transaction.execute("CALL " + tablePrefix + "_set_session('sync_prevented','1')"); - transaction.execute("CALL " + tablePrefix + "_set_session('node_value','"+nodeId+"')"); + transaction.execute("CALL " + parameterService.getTablePrefix() + "_set_session('sync_prevented','1')"); + transaction.execute("CALL " + parameterService.getTablePrefix() + "_set_session('node_value','"+nodeId+"')"); } public void enableSyncTriggers(ISqlTransaction transaction) { - transaction.execute("CALL " + tablePrefix + "_set_session('sync_prevented',null)"); - transaction.execute("CALL " + tablePrefix + "_set_session('node_value',null)"); + transaction.execute("CALL " + parameterService.getTablePrefix() + "_set_session('sync_prevented',null)"); + transaction.execute("CALL " + parameterService.getTablePrefix() + "_set_session('node_value',null)"); } public String getSyncTriggersExpression() { - return " " + tablePrefix + "_get_session(''sync_prevented'') is null "; + return " " + parameterService.getTablePrefix() + "_get_session(''sync_prevented'') is null "; } /* @@ -144,11 +141,6 @@ public String getTransactionTriggerExpression(String defaultCatalog, String defa return "null"; } - @Override - public String getSelectLastInsertIdSql(String sequenceName) { - return "call IDENTITY()"; - } - @Override public BinaryEncoding getBinaryEncoding() { return BinaryEncoding.BASE64; @@ -171,14 +163,9 @@ public boolean supportsTransactionId() { return false; } - @Override - protected boolean allowsNullForIdentityColumn() { - return false; - } - @Override public void truncateTable(String tableName) { - jdbcTemplate.update("delete from " + tableName); + platform.getSqlTemplate().update("delete from " + tableName); } @Override diff --git a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/db/hsqldb2/HsqlDb2SymmetricDialect.java b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/db/hsqldb2/HsqlDb2SymmetricDialect.java index 7c1fc48d67..1cba003e20 100644 --- a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/db/hsqldb2/HsqlDb2SymmetricDialect.java +++ b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/db/hsqldb2/HsqlDb2SymmetricDialect.java @@ -16,7 +16,8 @@ * "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. */ + * under the License. + */ package org.jumpmind.symmetric.db.hsqldb2; @@ -28,29 +29,25 @@ import org.jumpmind.symmetric.db.ISymmetricDialect; import org.jumpmind.symmetric.model.Trigger; import org.jumpmind.symmetric.model.TriggerHistory; -import org.springframework.jdbc.core.JdbcTemplate; +import org.jumpmind.symmetric.service.IParameterService; public class HsqlDb2SymmetricDialect extends AbstractSymmetricDialect implements ISymmetricDialect { - public HsqlDb2SymmetricDialect() { + public HsqlDb2SymmetricDialect(IParameterService parameterService, IDatabasePlatform platform) { + super(parameterService, platform); this.triggerText = new HsqlDb2TriggerText(); + platform.getSqlTemplate().update("SET DATABASE DEFAULT TABLE TYPE CACHED"); } - - @Override - public void init(IDatabasePlatform pf, int queryTimeout, JdbcTemplate jdbcTemplate) { - super.init(pf, queryTimeout, jdbcTemplate); - jdbcTemplate.execute("SET DATABASE DEFAULT TABLE TYPE CACHED"); - } - + @Override protected boolean doesTriggerExistOnPlatform(String catalogName, String schemaName, String tableName, String triggerName) { - boolean exists = (jdbcTemplate.queryForInt( + boolean exists = (platform.getSqlTemplate().queryForInt( "select count(*) from INFORMATION_SCHEMA.TRIGGERS WHERE TRIGGER_NAME = ?", new Object[] { triggerName }) > 0); return exists; } - + @Override public void removeTrigger(StringBuilder sqlBuffer, String catalogName, String schemaName, String triggerName, String tableName, TriggerHistory oldHistory) { @@ -59,7 +56,7 @@ public void removeTrigger(StringBuilder sqlBuffer, String catalogName, String sc if (parameterService.is(ParameterConstants.AUTO_SYNC_TRIGGERS)) { try { - int count = jdbcTemplate.update(dropSql); + int count = platform.getSqlTemplate().update(dropSql); if (count > 0) { log.info("TriggerDropped", triggerName); } @@ -80,17 +77,21 @@ public boolean isClobSyncSupported() { } public void disableSyncTriggers(ISqlTransaction transaction, String nodeId) { - transaction.execute("CALL " + tablePrefix + "_set_session('sync_prevented','1')"); - transaction.execute("CALL " + tablePrefix + "_set_session('node_value','" + nodeId + "')"); + transaction.execute("CALL " + parameterService.getTablePrefix() + + "_set_session('sync_prevented','1')"); + transaction.execute("CALL " + parameterService.getTablePrefix() + + "_set_session('node_value','" + nodeId + "')"); } public void enableSyncTriggers(ISqlTransaction transaction) { - transaction.execute("CALL " + tablePrefix + "_set_session('sync_prevented',null)"); - transaction.execute("CALL " + tablePrefix + "_set_session('node_value',null)"); + transaction.execute("CALL " + parameterService.getTablePrefix() + + "_set_session('sync_prevented',null)"); + transaction.execute("CALL " + parameterService.getTablePrefix() + + "_set_session('node_value',null)"); } public String getSyncTriggersExpression() { - return " " + tablePrefix + "_get_session('sync_prevented') is null "; + return " " + parameterService.getTablePrefix() + "_get_session('sync_prevented') is null "; } /* @@ -99,15 +100,11 @@ public String getSyncTriggersExpression() { @Override public String getTransactionTriggerExpression(String defaultCatalog, String defaultSchema, Trigger trigger) { - // TODO A method is coming that will all access to the transaction id ... + // TODO A method is coming that will all access to the transaction id + // ... return "null"; } - @Override - public String getSelectLastInsertIdSql(String sequenceName) { - return "call IDENTITY()"; - } - @Override public BinaryEncoding getBinaryEncoding() { return BinaryEncoding.HEX; @@ -118,14 +115,9 @@ public boolean supportsTransactionId() { return false; } - @Override - protected boolean allowsNullForIdentityColumn() { - return false; - } - @Override public void truncateTable(String tableName) { - jdbcTemplate.update("delete from " + tableName); + platform.getSqlTemplate().update("delete from " + tableName); } public void purge() { @@ -135,5 +127,5 @@ public void purge() { public boolean canGapsOccurInCapturedDataIds() { return false; } - + } \ No newline at end of file diff --git a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/db/informix/InformixSymmetricDialect.java b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/db/informix/InformixSymmetricDialect.java index 58bf92aca8..2ec0b47b36 100644 --- a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/db/informix/InformixSymmetricDialect.java +++ b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/db/informix/InformixSymmetricDialect.java @@ -20,39 +20,41 @@ package org.jumpmind.symmetric.db.informix; +import org.jumpmind.db.platform.IDatabasePlatform; import org.jumpmind.db.sql.ISqlTransaction; import org.jumpmind.symmetric.db.AbstractSymmetricDialect; import org.jumpmind.symmetric.db.ISymmetricDialect; import org.jumpmind.symmetric.model.Trigger; +import org.jumpmind.symmetric.service.IParameterService; public class InformixSymmetricDialect extends AbstractSymmetricDialect implements ISymmetricDialect { - - public InformixSymmetricDialect() { + public InformixSymmetricDialect(IParameterService parameterService, IDatabasePlatform platform) { + super(parameterService, platform); this.triggerText = new InformixTriggerText(); } @Override protected boolean doesTriggerExistOnPlatform(String catalog, String schema, String tableName, String triggerName) { - return jdbcTemplate.queryForInt( + return platform.getSqlTemplate().queryForInt( "select count(*) from systriggers where lower(trigname) = ?", new Object[] { triggerName.toLowerCase() }) > 0; } public void disableSyncTriggers(ISqlTransaction transaction, String nodeId) { - transaction.execute("select " + tablePrefix + "_triggers_set_disabled('t'), " - + tablePrefix + "_node_set_disabled(?) from sysmaster:sysdual", + transaction.execute("select " + parameterService.getTablePrefix() + "_triggers_set_disabled('t'), " + + parameterService.getTablePrefix() + "_node_set_disabled(?) from sysmaster:sysdual", new Object[] { nodeId }); } public void enableSyncTriggers(ISqlTransaction transaction) { - transaction.execute("select " + tablePrefix + "_triggers_set_disabled('f'), " - + tablePrefix + "_node_set_disabled(null) from sysmaster:sysdual"); + transaction.execute("select " + parameterService.getTablePrefix() + "_triggers_set_disabled('f'), " + + parameterService.getTablePrefix() + "_node_set_disabled(null) from sysmaster:sysdual"); } public String getSyncTriggersExpression() { - return "not $(defaultSchema)" + tablePrefix + "_triggers_disabled()"; + return "not $(defaultSchema)" + parameterService.getTablePrefix() + "_triggers_disabled()"; } @Override @@ -83,11 +85,6 @@ public boolean isClobSyncSupported() { return false; } - @Override - public boolean allowsNullForIdentityColumn() { - return false; - } - public void purge() { } diff --git a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/db/interbase/InterbaseSymmetricDialect.java b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/db/interbase/InterbaseSymmetricDialect.java index f8e2aab5db..b98938156e 100644 --- a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/db/interbase/InterbaseSymmetricDialect.java +++ b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/db/interbase/InterbaseSymmetricDialect.java @@ -22,14 +22,16 @@ import java.util.List; +import org.jumpmind.db.platform.IDatabasePlatform; import org.jumpmind.db.sql.ISqlTransaction; +import org.jumpmind.db.sql.mapper.StringMapper; import org.jumpmind.db.util.BinaryEncoding; import org.jumpmind.symmetric.db.AbstractSymmetricDialect; import org.jumpmind.symmetric.db.ISymmetricDialect; import org.jumpmind.symmetric.db.SequenceIdentifier; import org.jumpmind.symmetric.model.Trigger; +import org.jumpmind.symmetric.service.IParameterService; import org.springframework.jdbc.UncategorizedSQLException; -import org.springframework.jdbc.core.SingleColumnRowMapper; /* * Database dialect for Interbase. @@ -46,19 +48,20 @@ public class InterbaseSymmetricDialect extends AbstractSymmetricDialect implemen static final String SYNC_TRIGGERS_DISABLED_NODE_VARIABLE = "sync_node_disabled"; - public InterbaseSymmetricDialect() { + public InterbaseSymmetricDialect(IParameterService parameterService, IDatabasePlatform platform) { + super(parameterService, platform); this.triggerText = new InterbaseTriggerText(); } @Override protected void initTablesAndFunctionsForSpecificDialect() { - String contextTableName = tablePrefix + "_" + CONTEXT_TABLE_NAME; + String contextTableName = parameterService.getTablePrefix() + "_" + CONTEXT_TABLE_NAME; try { - jdbcTemplate.queryForInt("select count(*) from " + contextTableName); + platform.getSqlTemplate().queryForInt("select count(*) from " + contextTableName); } catch (Exception e) { try { log.info("GlobalTempTableCreating", contextTableName); - jdbcTemplate.execute(String.format(CONTEXT_TABLE_CREATE, contextTableName)); + platform.getSqlTemplate().update(String.format(CONTEXT_TABLE_CREATE, contextTableName)); } catch (Exception ex) { log.error("InterbaseDialectInitializingError", ex); } @@ -69,7 +72,7 @@ protected void initTablesAndFunctionsForSpecificDialect() { protected void createRequiredFunctions() { super.createRequiredFunctions(); try { - jdbcTemplate.queryForObject("select sym_escape('') from rdb$database", String.class); + platform.getSqlTemplate().queryForObject("select sym_escape('') from rdb$database", String.class); } catch (UncategorizedSQLException e) { if (e.getSQLException().getErrorCode() == -804) { log.error("InterbaseSymUdfMissing"); @@ -80,12 +83,12 @@ protected void createRequiredFunctions() { @Override protected boolean doesTriggerExistOnPlatform(String catalogName, String schema, String tableName, String triggerName) { - return jdbcTemplate.queryForInt("select count(*) from rdb$triggers where rdb$trigger_name = ?", + return platform.getSqlTemplate().queryForInt("select count(*) from rdb$triggers where rdb$trigger_name = ?", new Object[] { triggerName.toUpperCase() }) > 0; } public void disableSyncTriggers(ISqlTransaction transaction, String nodeId) { - String contextTableName = tablePrefix + "_" + CONTEXT_TABLE_NAME; + String contextTableName = parameterService.getTablePrefix() + "_" + CONTEXT_TABLE_NAME; transaction.execute(String.format(CONTEXT_TABLE_INSERT, contextTableName), new Object[] { SYNC_TRIGGERS_DISABLED_USER_VARIABLE, "1" }); if (nodeId != null) { @@ -95,7 +98,7 @@ public void disableSyncTriggers(ISqlTransaction transaction, String nodeId) { } public void enableSyncTriggers(ISqlTransaction transaction) { - String contextTableName = tablePrefix + "_" + CONTEXT_TABLE_NAME; + String contextTableName = parameterService.getTablePrefix() + "_" + CONTEXT_TABLE_NAME; transaction.execute("delete from " + contextTableName); } @@ -104,7 +107,7 @@ public String getSyncTriggersExpression() { } @Override - protected String getSequenceName(SequenceIdentifier identifier) { + public String getSequenceName(SequenceIdentifier identifier) { switch (identifier) { case OUTGOING_BATCH: return "SYM_OUTGOING_BATCH_BATCH_ID"; @@ -121,11 +124,6 @@ public String getTransactionTriggerExpression(String defaultCatalog, String defa return "null"; } - @Override - public String getSelectLastInsertIdSql(String sequenceName) { - return "select gen_id(gen_" + sequenceName + ", 0) from rdb$database"; - } - @Override public boolean isBlobSyncSupported() { return true; @@ -136,11 +134,6 @@ public BinaryEncoding getBinaryEncoding() { return BinaryEncoding.HEX; } - @Override - protected boolean allowsNullForIdentityColumn() { - return true; - } - public void purge() { } @@ -168,16 +161,15 @@ public boolean supportsBatchUpdates() { @Override public void truncateTable(String tableName) { - jdbcTemplate.update("delete from " + tableName); + platform.getSqlTemplate().update("delete from " + tableName); } - - + @Override public void cleanupTriggers() { - List names = jdbcTemplate.query("select rdb$trigger_name from rdb$triggers where rdb$trigger_name like '"+tablePrefix.toUpperCase()+"_%'", new SingleColumnRowMapper()); + List names = platform.getSqlTemplate().query("select rdb$trigger_name from rdb$triggers where rdb$trigger_name like '"+parameterService.getTablePrefix().toUpperCase()+"_%'", new StringMapper()); int count = 0; for (String name : names) { - count += jdbcTemplate.update("drop trigger " + name); + count += platform.getSqlTemplate().update("drop trigger " + name); } log.info("RemovedTriggers", count); } diff --git a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/db/mssql/MsSqlSymmetricDialect.java b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/db/mssql/MsSqlSymmetricDialect.java index f8160e59a0..7d32474b67 100644 --- a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/db/mssql/MsSqlSymmetricDialect.java +++ b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/db/mssql/MsSqlSymmetricDialect.java @@ -27,15 +27,19 @@ import java.sql.SQLException; import java.sql.Statement; +import org.jumpmind.db.platform.IDatabasePlatform; import org.jumpmind.db.sql.ISqlTransaction; +import org.jumpmind.db.sql.SqlException; +import org.jumpmind.db.sql.jdbc.IConnectionCallback; +import org.jumpmind.db.sql.jdbc.JdbcSqlTemplate; +import org.jumpmind.db.sql.jdbc.JdbcSqlTransaction; import org.jumpmind.db.util.BinaryEncoding; import org.jumpmind.symmetric.common.ParameterConstants; import org.jumpmind.symmetric.db.AbstractSymmetricDialect; import org.jumpmind.symmetric.db.ISymmetricDialect; import org.jumpmind.symmetric.model.Trigger; import org.jumpmind.symmetric.model.TriggerHistory; -import org.springframework.dao.DataAccessException; -import org.springframework.jdbc.core.ConnectionCallback; +import org.jumpmind.symmetric.service.IParameterService; /* * This dialect was tested with the jTDS JDBC driver on SQL Server 2005. @@ -46,14 +50,10 @@ */ public class MsSqlSymmetricDialect extends AbstractSymmetricDialect implements ISymmetricDialect { - public MsSqlSymmetricDialect() { + public MsSqlSymmetricDialect(IParameterService parameterService, IDatabasePlatform platform) { + super(parameterService, platform); this.triggerText = new MsSqlTriggerText(); } - - @Override - protected boolean allowsNullForIdentityColumn() { - return false; - } @Override public void removeTrigger(StringBuilder sqlBuffer, final String catalogName, String schemaName, @@ -62,41 +62,46 @@ public void removeTrigger(StringBuilder sqlBuffer, final String catalogName, Str final String sql = "drop trigger " + schemaName + triggerName; logSql(sql, sqlBuffer); if (parameterService.is(ParameterConstants.AUTO_SYNC_TRIGGERS)) { - jdbcTemplate.execute(new ConnectionCallback() { - public Object doInConnection(Connection con) throws SQLException, - DataAccessException { - String previousCatalog = con.getCatalog(); - Statement stmt = null; - try { - if (catalogName != null) { - con.setCatalog(catalogName); - } - stmt = con.createStatement(); - stmt.execute(sql); - } catch (Exception e) { - log.warn("TriggerDropError", triggerName, e.getMessage()); - } finally { - if (catalogName != null) { - con.setCatalog(previousCatalog); + ((JdbcSqlTemplate) platform.getSqlTemplate()) + .execute(new IConnectionCallback() { + public Boolean execute(Connection con) throws SQLException { + String previousCatalog = con.getCatalog(); + Statement stmt = null; + try { + if (catalogName != null) { + con.setCatalog(catalogName); + } + stmt = con.createStatement(); + stmt.execute(sql); + } catch (Exception e) { + log.warn("TriggerDropError", triggerName, e.getMessage()); + } finally { + if (catalogName != null) { + con.setCatalog(previousCatalog); + } + try { + stmt.close(); + } catch (Exception e) { + } + } + return Boolean.FALSE; } - try { - stmt.close(); - } catch (Exception e) { - } - } - return Boolean.FALSE; - } - }); + }); } } @Override - protected String switchCatalogForTriggerInstall(String catalog, Connection c) - throws SQLException { + protected String switchCatalogForTriggerInstall(String catalog, ISqlTransaction transaction) { if (catalog != null) { - String previousCatalog = c.getCatalog(); - c.setCatalog(catalog); - return previousCatalog; + Connection c = ((JdbcSqlTransaction) transaction).getConnection(); + String previousCatalog; + try { + previousCatalog = c.getCatalog(); + c.setCatalog(catalog); + return previousCatalog; + } catch (SQLException e) { + throw new SqlException(e); + } } else { return null; } @@ -110,30 +115,31 @@ public BinaryEncoding getBinaryEncoding() { @Override protected boolean doesTriggerExistOnPlatform(final String catalogName, String schema, String tableName, final String triggerName) { - return jdbcTemplate.execute(new ConnectionCallback() { - public Boolean doInConnection(Connection con) throws SQLException, DataAccessException { - String previousCatalog = con.getCatalog(); - PreparedStatement stmt = con - .prepareStatement("select count(*) from sysobjects where type = 'TR' AND name = ?"); - try { - if (catalogName != null) { - con.setCatalog(catalogName); - } - stmt.setString(1, triggerName); - ResultSet rs = stmt.executeQuery(); - if (rs.next()) { - int count = rs.getInt(1); - return count > 0; - } - } finally { - if (catalogName != null) { - con.setCatalog(previousCatalog); + return ((JdbcSqlTemplate) platform.getSqlTemplate()) + .execute(new IConnectionCallback() { + public Boolean execute(Connection con) throws SQLException { + String previousCatalog = con.getCatalog(); + PreparedStatement stmt = con + .prepareStatement("select count(*) from sysobjects where type = 'TR' AND name = ?"); + try { + if (catalogName != null) { + con.setCatalog(catalogName); + } + stmt.setString(1, triggerName); + ResultSet rs = stmt.executeQuery(); + if (rs.next()) { + int count = rs.getInt(1); + return count > 0; + } + } finally { + if (catalogName != null) { + con.setCatalog(previousCatalog); + } + stmt.close(); + } + return Boolean.FALSE; } - stmt.close(); - } - return Boolean.FALSE; - } - }); + }); } public void disableSyncTriggers(ISqlTransaction transaction, String nodeId) { @@ -149,7 +155,8 @@ public void enableSyncTriggers(ISqlTransaction transaction) { } public String getSyncTriggersExpression() { - return "$(defaultCatalog)dbo." + tablePrefix + "_triggers_disabled() = 0"; + return "$(defaultCatalog)dbo." + parameterService.getTablePrefix() + + "_triggers_disabled() = 0"; } @Override diff --git a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/db/mysql/MySqlSymmetricDialect.java b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/db/mysql/MySqlSymmetricDialect.java index 2d7138c186..50b254bb66 100644 --- a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/db/mysql/MySqlSymmetricDialect.java +++ b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/db/mysql/MySqlSymmetricDialect.java @@ -16,15 +16,18 @@ * "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.jumpmind.symmetric.db.mysql; - + * under the License. + */ + +package org.jumpmind.symmetric.db.mysql; + import java.sql.Connection; import java.sql.SQLException; +import org.jumpmind.db.platform.IDatabasePlatform; import org.jumpmind.db.sql.ISqlTransaction; +import org.jumpmind.db.sql.SqlException; +import org.jumpmind.db.sql.jdbc.JdbcSqlTransaction; import org.jumpmind.db.util.BinaryEncoding; import org.jumpmind.symmetric.Version; import org.jumpmind.symmetric.common.ParameterConstants; @@ -32,136 +35,145 @@ import org.jumpmind.symmetric.db.ISymmetricDialect; import org.jumpmind.symmetric.model.Trigger; import org.jumpmind.symmetric.model.TriggerHistory; - -public class MySqlSymmetricDialect extends AbstractSymmetricDialect implements ISymmetricDialect { - - private static final String TRANSACTION_ID = "transaction_id"; - - static final String SYNC_TRIGGERS_DISABLED_USER_VARIABLE = "@sync_triggers_disabled"; - - static final String SYNC_TRIGGERS_DISABLED_NODE_VARIABLE = "@sync_node_disabled"; - - private String functionTemplateKeySuffix = null; - - public MySqlSymmetricDialect() { +import org.jumpmind.symmetric.service.IParameterService; + +public class MySqlSymmetricDialect extends AbstractSymmetricDialect implements ISymmetricDialect { + + private static final String TRANSACTION_ID = "transaction_id"; + + static final String SYNC_TRIGGERS_DISABLED_USER_VARIABLE = "@sync_triggers_disabled"; + + static final String SYNC_TRIGGERS_DISABLED_NODE_VARIABLE = "@sync_node_disabled"; + + private String functionTemplateKeySuffix = null; + + public MySqlSymmetricDialect(IParameterService parameterService, IDatabasePlatform platform) { + super(parameterService, platform); this.triggerText = new MySqlTriggerText(); + this.parameterService = parameterService; + } + + @Override + protected void initTablesAndFunctionsForSpecificDialect() { + int[] versions = Version.parseVersion(getProductVersion()); + if (getMajorVersion() == 5 + && (getMinorVersion() == 0 || (getMinorVersion() == 1 && versions[2] < 23))) { + this.functionTemplateKeySuffix = "_pre_5_1_23"; + } else { + this.functionTemplateKeySuffix = "_post_5_1_23"; + } + } + + @Override + public boolean supportsTransactionId() { + return true; + } + + @Override + protected void createRequiredFunctions() { + String[] functions = triggerText.getFunctionsToInstall(); + for (int i = 0; i < functions.length; i++) { + if (functions[i].endsWith(this.functionTemplateKeySuffix)) { + String funcName = parameterService.getTablePrefix() + + "_" + + functions[i].substring(0, functions[i].length() + - this.functionTemplateKeySuffix.length()); + if (platform.getSqlTemplate().queryForInt( + triggerText.getFunctionInstalledSql(funcName, platform.getDefaultSchema())) == 0) { + platform.getSqlTemplate().update( + triggerText.getFunctionSql(functions[i], funcName, + platform.getDefaultSchema())); + log.info("FunctionInstalled", funcName); + } + } + } + } + + @Override + protected boolean doesTriggerExistOnPlatform(String catalog, String schema, String tableName, + String triggerName) { + catalog = catalog == null ? (platform.getDefaultCatalog() == null ? null : platform + .getDefaultCatalog()) : catalog; + String checkCatalogSql = (catalog != null && catalog.length() > 0) ? " and trigger_schema='" + + catalog + "'" + : ""; + return platform + .getSqlTemplate() + .queryForInt( + "select count(*) from information_schema.triggers where trigger_name like ? and event_object_table like ?" + + checkCatalogSql, new Object[] { triggerName, tableName }) > 0; + } + + @Override + public void removeTrigger(StringBuilder sqlBuffer, String catalogName, String schemaName, + String triggerName, String tableName, TriggerHistory oldHistory) { + catalogName = catalogName == null ? "" : (catalogName + "."); + final String sql = "drop trigger " + catalogName + triggerName; + logSql(sql, sqlBuffer); + if (parameterService.is(ParameterConstants.AUTO_SYNC_TRIGGERS)) { + try { + platform.getSqlTemplate().update(sql); + } catch (Exception e) { + log.warn("TriggerDoesNotExist"); + } + } } - - @Override - protected void initTablesAndFunctionsForSpecificDialect() { - int[] versions = Version.parseVersion(getProductVersion()); - if (getMajorVersion() == 5 && (getMinorVersion() == 0 || (getMinorVersion() == 1 && versions[2] < 23))) { - this.functionTemplateKeySuffix = "_pre_5_1_23"; - } else { - this.functionTemplateKeySuffix = "_post_5_1_23"; - } + + public void disableSyncTriggers(ISqlTransaction transaction, String nodeId) { + transaction.execute("set " + SYNC_TRIGGERS_DISABLED_USER_VARIABLE + "=1"); + if (nodeId != null) { + transaction + .execute("set " + SYNC_TRIGGERS_DISABLED_NODE_VARIABLE + "='" + nodeId + "'"); + } + } + + public void enableSyncTriggers(ISqlTransaction transaction) { + transaction.execute("set " + SYNC_TRIGGERS_DISABLED_USER_VARIABLE + "=null"); + transaction.execute("set " + SYNC_TRIGGERS_DISABLED_NODE_VARIABLE + "=null"); + } + + public String getSyncTriggersExpression() { + return SYNC_TRIGGERS_DISABLED_USER_VARIABLE + " is null"; + } + + private final String getTransactionFunctionName() { + return platform.getDefaultCatalog() + "." + parameterService.getTablePrefix() + "_" + + TRANSACTION_ID; + } + + @Override + public String getTransactionTriggerExpression(String defaultCatalog, String defaultSchema, + Trigger trigger) { + return getTransactionFunctionName() + "()"; + } + + public void purge() { + } + + @Override + protected String switchCatalogForTriggerInstall(String catalog, ISqlTransaction transaction) { + if (catalog != null) { + Connection c = ((JdbcSqlTransaction) transaction).getConnection(); + String previousCatalog; + try { + previousCatalog = c.getCatalog(); + c.setCatalog(catalog); + return previousCatalog; + } catch (SQLException e) { + throw new SqlException(e); + } + } else { + return null; + } + } + + @Override + public BinaryEncoding getBinaryEncoding() { + return BinaryEncoding.HEX; + } + + @Override + protected String getDbSpecificDataHasChangedCondition(Trigger trigger) { + return "var_row_data != var_old_data"; } - - @Override - public boolean supportsTransactionId() { - return true; - } - - @Override - protected void createRequiredFunctions() { - String[] functions = triggerText.getFunctionsToInstall(); - for (int i = 0; i < functions.length; i++) { - if (functions[i].endsWith(this.functionTemplateKeySuffix)) { - String funcName = tablePrefix + "_" - + functions[i].substring(0, functions[i].length() - this.functionTemplateKeySuffix.length()); - if (jdbcTemplate.queryForInt(triggerText.getFunctionInstalledSql(funcName, platform.getDefaultSchema())) == 0) { - jdbcTemplate.update(triggerText.getFunctionSql(functions[i], funcName, platform.getDefaultSchema())); - log.info("FunctionInstalled", funcName); - } - } - } - } - - @Override - protected boolean doesTriggerExistOnPlatform(String catalog, String schema, String tableName, String triggerName) { - catalog = catalog == null ? (platform.getDefaultCatalog() == null ? null : platform.getDefaultCatalog()) : catalog; - String checkCatalogSql = (catalog != null && catalog.length() > 0) ? " and trigger_schema='" + catalog + "'" - : ""; - return jdbcTemplate.queryForInt( - "select count(*) from information_schema.triggers where trigger_name like ? and event_object_table like ?" - + checkCatalogSql, new Object[] { triggerName, tableName }) > 0; - } - - @Override - public void removeTrigger(StringBuilder sqlBuffer, String catalogName, String schemaName, String triggerName, - String tableName, TriggerHistory oldHistory) { - catalogName = catalogName == null ? "" : (catalogName + "."); - final String sql = "drop trigger " + catalogName + triggerName; - logSql(sql, sqlBuffer); - if (parameterService.is(ParameterConstants.AUTO_SYNC_TRIGGERS)) { - try { - jdbcTemplate.update(sql); - } catch (Exception e) { - log.warn("TriggerDoesNotExist"); - } - } - } - - public void disableSyncTriggers(ISqlTransaction transaction, String nodeId) { - transaction.execute("set " + SYNC_TRIGGERS_DISABLED_USER_VARIABLE + "=1"); - if (nodeId != null) { - transaction.execute("set " + SYNC_TRIGGERS_DISABLED_NODE_VARIABLE + "='" + nodeId + "'"); - } - } - - public void enableSyncTriggers(ISqlTransaction transaction) { - transaction.execute("set " + SYNC_TRIGGERS_DISABLED_USER_VARIABLE + "=null"); - transaction.execute("set " + SYNC_TRIGGERS_DISABLED_NODE_VARIABLE + "=null"); - } - - public String getSyncTriggersExpression() { - return SYNC_TRIGGERS_DISABLED_USER_VARIABLE + " is null"; - } - - private final String getTransactionFunctionName() { - return platform.getDefaultCatalog() + "." + tablePrefix + "_" + TRANSACTION_ID; - } - - @Override - public String getTransactionTriggerExpression(String defaultCatalog, String defaultSchema, Trigger trigger) { - return getTransactionFunctionName() + "()"; - } - - @Override - public String getSelectLastInsertIdSql(String sequenceName) { - return "select last_insert_id()"; - } - - public void purge() { - } - - @Override - protected String switchCatalogForTriggerInstall(String catalog, Connection c) throws SQLException { - if (catalog != null) { - String previousCatalog = c.getCatalog(); - c.setCatalog(catalog); - return previousCatalog; - } else { - return null; - } - } - - /* - * According to the documentation (and experience) the jdbc driver for mysql - * requires the fetch size to be as follows. - */ - @Override - public int getStreamingResultsFetchSize() { - return Integer.MIN_VALUE; - } - - @Override - public BinaryEncoding getBinaryEncoding() { - return BinaryEncoding.HEX; - } - - @Override - protected String getDbSpecificDataHasChangedCondition(Trigger trigger) { - return "var_row_data != var_old_data"; - } } \ No newline at end of file diff --git a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/db/oracle/OracleSymmetricDialect.java b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/db/oracle/OracleSymmetricDialect.java index 086fff7868..277aea59b8 100644 --- a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/db/oracle/OracleSymmetricDialect.java +++ b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/db/oracle/OracleSymmetricDialect.java @@ -38,9 +38,9 @@ import org.jumpmind.symmetric.model.Channel; import org.jumpmind.symmetric.model.Trigger; import org.jumpmind.symmetric.model.TriggerHistory; +import org.jumpmind.symmetric.service.IParameterService; import org.springframework.dao.DataAccessException; import org.springframework.jdbc.BadSqlGrammarException; -import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.support.lob.OracleLobHandler; import org.springframework.jdbc.support.nativejdbc.NativeJdbcExtractor; @@ -51,17 +51,13 @@ public class OracleSymmetricDialect extends AbstractSymmetricDialect implements static final String ORACLE_OBJECT_TYPE = "FUNCTION"; - String selectTriggerSql; + String selectTriggerSql = "from ALL_TRIGGERS where owner in (SELECT sys_context('USERENV', 'CURRENT_SCHEMA') FROM dual) and trigger_name like upper(?) and table_name like upper(?)"; - String selectTransactionsSql; - - public OracleSymmetricDialect() { - this.triggerText = new OracleTriggerText(); - } + String selectTransactionsSql = "select min(start_time) from gv$transaction"; - @Override - public void init(IDatabasePlatform pf, int queryTimeout, JdbcTemplate jdbcTemplate) { - super.init(pf, queryTimeout, jdbcTemplate); + public OracleSymmetricDialect(IParameterService parameterService, IDatabasePlatform platform) { + super(parameterService, platform); + this.triggerText = new OracleTriggerText(); try { areDatabaseTransactionsPendingSince(System.currentTimeMillis()); supportsTransactionViews = true; @@ -90,14 +86,15 @@ protected void initLobHandler() { public void createTrigger(StringBuilder sqlBuffer, DataEventType dml, Trigger trigger, TriggerHistory history, Channel channel, String tablePrefix, Table table) { try { - super.createTrigger(sqlBuffer, dml, trigger, history, channel, tablePrefix, table); + super.createTrigger(sqlBuffer, dml, trigger, history, channel, + parameterService.getTablePrefix(), table); } catch (BadSqlGrammarException ex) { if (ex.getSQLException().getErrorCode() == 4095) { try { // a trigger of the same name must already exist on a table log.warn( "TriggerAlreadyExists", - jdbcTemplate.queryForMap( + platform.getSqlTemplate().queryForMap( "select * " + selectTriggerSql, new Object[] { history.getTriggerNameForDmlType(dml), history.getSourceTableName() })); @@ -116,7 +113,7 @@ public BinaryEncoding getBinaryEncoding() { @Override public String getTransactionTriggerExpression(String defaultCatalog, String defaultSchema, Trigger trigger) { - return tablePrefix + "_" + "transaction_id()"; + return parameterService.getTablePrefix() + "_" + "transaction_id()"; } @Override @@ -125,7 +122,7 @@ public boolean supportsTransactionId() { } @Override - protected String getSequenceName(SequenceIdentifier identifier) { + public String getSequenceName(SequenceIdentifier identifier) { switch (identifier) { case OUTGOING_BATCH: return "SEQ_SYM_OUTGOIN_BATCH_BATCH_ID"; @@ -137,24 +134,19 @@ protected String getSequenceName(SequenceIdentifier identifier) { return null; } - @Override - public String getSelectLastInsertIdSql(String sequenceName) { - return "select " + sequenceName + ".currval from dual"; - } - @Override protected boolean doesTriggerExistOnPlatform(String catalog, String schema, String tableName, String triggerName) { - return jdbcTemplate.queryForInt("select count(*) " + selectTriggerSql, new Object[] { - triggerName, tableName }) > 0; + return platform.getSqlTemplate().queryForInt("select count(*) " + selectTriggerSql, + new Object[] { triggerName, tableName }) > 0; } public void purge() { - jdbcTemplate.update("purge recyclebin"); + platform.getSqlTemplate().update("purge recyclebin"); } protected String getSymmetricPackageName() { - return tablePrefix + "_pkg"; + return parameterService.getTablePrefix() + "_pkg"; } public void disableSyncTriggers(ISqlTransaction transaction, String nodeId) { @@ -171,12 +163,13 @@ public void enableSyncTriggers(ISqlTransaction transaction) { } public String getSyncTriggersExpression() { - return tablePrefix + "_trigger_disabled() is null"; + return parameterService.getTablePrefix() + "_trigger_disabled() is null"; } @Override public boolean areDatabaseTransactionsPendingSince(long time) { - String returnValue = jdbcTemplate.queryForObject(selectTransactionsSql, String.class); + String returnValue = platform.getSqlTemplate().queryForObject(selectTransactionsSql, + String.class); if (returnValue != null) { Date date; try { diff --git a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/db/postgresql/GreenplumSymmetricDialect.java b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/db/postgresql/GreenplumSymmetricDialect.java index b442d04504..d937ecaa97 100644 --- a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/db/postgresql/GreenplumSymmetricDialect.java +++ b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/db/postgresql/GreenplumSymmetricDialect.java @@ -1,64 +1,13 @@ package org.jumpmind.symmetric.db.postgresql; -import java.sql.Connection; -import java.sql.PreparedStatement; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.sql.Statement; - -import org.jumpmind.symmetric.db.SequenceIdentifier; -import org.springframework.dao.DataAccessException; -import org.springframework.jdbc.core.ConnectionCallback; -import org.springframework.jdbc.core.JdbcTemplate; -import org.springframework.jdbc.core.PreparedStatementCallback; -import org.springframework.jdbc.support.JdbcUtils; +import org.jumpmind.db.platform.IDatabasePlatform; +import org.jumpmind.symmetric.service.IParameterService; public class GreenplumSymmetricDialect extends PostgreSqlSymmetricDialect { - public GreenplumSymmetricDialect() { + public GreenplumSymmetricDialect(IParameterService parameterService, IDatabasePlatform platform) { + super(parameterService, platform); this.triggerText = new GreenplumTriggerText(); } - @Override - public boolean supportsGetGeneratedKeys() { - return false; - } - - @Override - public long insertWithGeneratedKey(final JdbcTemplate jdbcTemplate, final String sql, - final SequenceIdentifier sequenceId, final PreparedStatementCallback callback) { - return jdbcTemplate.execute(new ConnectionCallback() { - public Long doInConnection(Connection conn) throws SQLException, DataAccessException { - long key = 0; - PreparedStatement ps = null; - try { - Statement st = null; - ResultSet rs = null; - try { - st = conn.createStatement(); - rs = st.executeQuery("select nextval('" + getSequenceName(sequenceId) - + "_seq')"); - if (rs.next()) { - key = rs.getLong(1); - } - } finally { - JdbcUtils.closeResultSet(rs); - JdbcUtils.closeStatement(st); - } - - String replaceSql = sql.replaceFirst("\\(null,", "(" + key + ","); - ps = conn.prepareStatement(replaceSql); - ps.setQueryTimeout(jdbcTemplate.getQueryTimeout()); - if (callback != null) { - callback.doInPreparedStatement(ps); - } - ps.executeUpdate(); - } finally { - JdbcUtils.closeStatement(ps); - } - return key; - } - }); - } - } diff --git a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/db/postgresql/PostgreSqlSymmetricDialect.java b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/db/postgresql/PostgreSqlSymmetricDialect.java index 68d33b4d27..839a368310 100644 --- a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/db/postgresql/PostgreSqlSymmetricDialect.java +++ b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/db/postgresql/PostgreSqlSymmetricDialect.java @@ -29,7 +29,7 @@ import org.jumpmind.symmetric.db.ISymmetricDialect; import org.jumpmind.symmetric.model.Trigger; import org.jumpmind.symmetric.model.TriggerHistory; -import org.springframework.jdbc.core.JdbcTemplate; +import org.jumpmind.symmetric.service.IParameterService; /* * Support for PostgreSQL @@ -45,15 +45,11 @@ public class PostgreSqlSymmetricDialect extends AbstractSymmetricDialect impleme private boolean supportsTransactionId = false; private String transactionIdExpression = "null"; - - public PostgreSqlSymmetricDialect() { + + public PostgreSqlSymmetricDialect(IParameterService parameterService, IDatabasePlatform platform) { + super(parameterService, platform); this.triggerText = new PostgreSqlTriggerText(); } - - @Override - public void init(IDatabasePlatform pf, int queryTimeout, JdbcTemplate jdbcTemplate) { - super.init(pf, 0, jdbcTemplate); - } @Override protected void initTablesAndFunctionsForSpecificDialect() { @@ -84,7 +80,7 @@ public boolean requiresAutoCommitFalseToSetFetchSize() { @Override protected boolean doesTriggerExistOnPlatform(String catalogName, String schema, String tableName, String triggerName) { - return jdbcTemplate.queryForInt("select count(*) from information_schema.triggers where trigger_name = ? " + return platform.getSqlTemplate().queryForInt("select count(*) from information_schema.triggers where trigger_name = ? " + "and event_object_table = ? and trigger_schema = ?", new Object[] { triggerName.toLowerCase(), tableName, schema == null ? platform.getDefaultSchema() : schema }) > 0; } @@ -99,8 +95,8 @@ public void removeTrigger(StringBuilder sqlBuffer, String catalogName, String sc logSql(dropFunction, sqlBuffer); if (parameterService.is(ParameterConstants.AUTO_SYNC_TRIGGERS)) { try { - jdbcTemplate.update(dropSql); - jdbcTemplate.update(dropFunction); + platform.getSqlTemplate().update(dropSql); + platform.getSqlTemplate().update(dropFunction); } catch (Exception e) { log.warn("TriggerDoesNotExist"); } @@ -123,7 +119,7 @@ public void enableSyncTriggers(ISqlTransaction transaction) { } public String getSyncTriggersExpression() { - return "$(defaultSchema)" + tablePrefix + "_triggers_disabled() = 0"; + return "$(defaultSchema)" + parameterService.getTablePrefix() + "_triggers_disabled() = 0"; } @Override @@ -131,21 +127,6 @@ public String getTransactionTriggerExpression(String defaultCatalog, String defa return transactionIdExpression; } - @Override - public String getSelectLastInsertIdSql(String sequenceName) { - return "select currval('" + sequenceName + "_seq')"; - } - - @Override - public boolean requiresSavepointForFallback() { - return true; - } - - @Override - protected boolean allowsNullForIdentityColumn() { - return false; - } - @Override public boolean supportsTransactionId() { return supportsTransactionId; diff --git a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/db/sqlite/SqLiteSymmetricDialect.java b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/db/sqlite/SqLiteSymmetricDialect.java deleted file mode 100644 index b19ba6fd2f..0000000000 --- a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/db/sqlite/SqLiteSymmetricDialect.java +++ /dev/null @@ -1,130 +0,0 @@ -/* - * Licensed to JumpMind Inc under one or more contributor - * license agreements. See the NOTICE file distributed - * with this work for additional information regarding - * copyright ownership. JumpMind Inc licenses this file - * to you under the GNU Lesser General Public License (the - * "License"); you may not use this file except in compliance - * with the License. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see - * . - * - * 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.jumpmind.symmetric.db.sqlite; - -import java.sql.Connection; -import java.sql.SQLException; - -import org.jumpmind.db.sql.ISqlTransaction; -import org.jumpmind.db.sql.SqlConstants; -import org.jumpmind.db.util.BinaryEncoding; -import org.jumpmind.symmetric.common.ParameterConstants; -import org.jumpmind.symmetric.db.AbstractSymmetricDialect; -import org.jumpmind.symmetric.db.ISymmetricDialect; -import org.jumpmind.symmetric.model.Trigger; -import org.jumpmind.symmetric.model.TriggerHistory; - -public class SqLiteSymmetricDialect extends AbstractSymmetricDialect implements ISymmetricDialect { - - static final String SYNC_TRIGGERS_DISABLED_USER_VARIABLE = "@sync_triggers_disabled"; - - static final String SYNC_TRIGGERS_DISABLED_NODE_VARIABLE = "@sync_node_disabled"; - - public String toFormattedTimestamp(java.util.Date time) { - StringBuilder ts = new StringBuilder("datetime('"); - ts.append(SqlConstants.JDBC_TIMESTAMP_FORMATTER.format(time)); - ts.append("')"); - return ts.toString(); - } - - @Override - public boolean supportsTransactionId() { - return false; - } - - private final String getTransactionFunctionName() { - return null; - } - - @Override - protected boolean doesTriggerExistOnPlatform(String catalog, String schema, String tableName, String triggerName) { - catalog = catalog == null ? (platform.getDefaultCatalog() == null ? null : platform.getDefaultCatalog()) : catalog; - String checkCatalogSql = (catalog != null && catalog.length() > 0) ? " and trigger_schema='" + catalog + "'" - : ""; - return jdbcTemplate.queryForInt( - "select count(*) from sqlite_master where type='trigger' and name like ? and tbl_name like ?" - + checkCatalogSql, new Object[] { triggerName, tableName }) > 0; - } - - @Override - public void removeTrigger(StringBuilder sqlBuffer, String catalogName, String schemaName, String triggerName, - String tableName, TriggerHistory oldHistory) { - catalogName = catalogName == null ? "" : (catalogName + "."); - final String sql = "drop trigger " + catalogName + triggerName; - logSql(sql, sqlBuffer); - if (parameterService.is(ParameterConstants.AUTO_SYNC_TRIGGERS)) { - try { - jdbcTemplate.update(sql); - } catch (Exception e) { - log.warn("TriggerDoesNotExist"); - } - } - } - - public void disableSyncTriggers(ISqlTransaction transaction, String nodeId) { - // jdbcTemplate.update("set " + SYNC_TRIGGERS_DISABLED_USER_VARIABLE + "=1"); - // if (nodeId != null) { - // jdbcTemplate.update("set " + SYNC_TRIGGERS_DISABLED_NODE_VARIABLE + "='" + nodeId + "'"); - // } - } - - public void enableSyncTriggers(ISqlTransaction transaction) { -// jdbcTemplate.update("set " + SYNC_TRIGGERS_DISABLED_USER_VARIABLE + "=null"); - // jdbcTemplate.update("set " + SYNC_TRIGGERS_DISABLED_NODE_VARIABLE + "=null"); - } - - public String getSyncTriggersExpression() { - return SYNC_TRIGGERS_DISABLED_USER_VARIABLE + " is null"; - } - - - - @Override - public String getTransactionTriggerExpression(String defaultCatalog, String defaultSchema, Trigger trigger) { - return getTransactionFunctionName() + "()"; - } - - @Override - public String getSelectLastInsertIdSql(String sequenceName) { - return "select last_insert_id()"; - } - - public void purge() { - } - - @Override - protected String switchCatalogForTriggerInstall(String catalog, Connection c) throws SQLException { - if (catalog != null) { - String previousCatalog = c.getCatalog(); - c.setCatalog(catalog); - return previousCatalog; - } else { - return null; - } - } - - @Override - public BinaryEncoding getBinaryEncoding() { - return BinaryEncoding.HEX; - } - -} \ No newline at end of file diff --git a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/db/sybase/SybaseSymmetricDialect.java b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/db/sybase/SybaseSymmetricDialect.java index 14448864a1..54894caabe 100644 --- a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/db/sybase/SybaseSymmetricDialect.java +++ b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/db/sybase/SybaseSymmetricDialect.java @@ -28,15 +28,19 @@ import java.sql.SQLException; import java.sql.Statement; +import org.jumpmind.db.platform.IDatabasePlatform; import org.jumpmind.db.sql.ISqlTransaction; +import org.jumpmind.db.sql.SqlException; +import org.jumpmind.db.sql.jdbc.IConnectionCallback; +import org.jumpmind.db.sql.jdbc.JdbcSqlTemplate; +import org.jumpmind.db.sql.jdbc.JdbcSqlTransaction; import org.jumpmind.db.util.BinaryEncoding; import org.jumpmind.symmetric.common.ParameterConstants; import org.jumpmind.symmetric.db.AbstractSymmetricDialect; import org.jumpmind.symmetric.db.ISymmetricDialect; import org.jumpmind.symmetric.model.Trigger; import org.jumpmind.symmetric.model.TriggerHistory; -import org.springframework.dao.DataAccessException; -import org.springframework.jdbc.core.ConnectionCallback; +import org.jumpmind.symmetric.service.IParameterService; /* * Sybase dialect was tested with jconn4 JDBC driver. @@ -44,20 +48,13 @@ * * disk resize name = master, size = 16384 * create database symmetricclient on master = '30M' - * */ public class SybaseSymmetricDialect extends AbstractSymmetricDialect implements ISymmetricDialect { - - - - public SybaseSymmetricDialect() { + + public SybaseSymmetricDialect(IParameterService parameterService, IDatabasePlatform platform) { + super(parameterService, platform); this.triggerText = new SybaseTriggerText(); - } - - @Override - protected boolean allowsNullForIdentityColumn() { - return false; - } + } @Override public void removeTrigger(StringBuilder sqlBuffer, final String catalogName, String schemaName, @@ -66,8 +63,9 @@ public void removeTrigger(StringBuilder sqlBuffer, final String catalogName, Str final String sql = "drop trigger " + schemaName + triggerName; logSql(sql, sqlBuffer); if (parameterService.is(ParameterConstants.AUTO_SYNC_TRIGGERS)) { - jdbcTemplate.execute(new ConnectionCallback() { - public Object doInConnection(Connection con) throws SQLException, DataAccessException { + ((JdbcSqlTemplate) platform.getSqlTemplate()) + .execute(new IConnectionCallback() { + public Boolean execute(Connection con) throws SQLException { String previousCatalog = con.getCatalog(); Statement stmt = null; try { @@ -94,11 +92,17 @@ public Object doInConnection(Connection con) throws SQLException, DataAccessExce } @Override - protected String switchCatalogForTriggerInstall(String catalog, Connection c) throws SQLException { + protected String switchCatalogForTriggerInstall(String catalog, ISqlTransaction transaction) { if (catalog != null) { - String previousCatalog = c.getCatalog(); - c.setCatalog(catalog); - return previousCatalog; + Connection c = ((JdbcSqlTransaction) transaction).getConnection(); + String previousCatalog; + try { + previousCatalog = c.getCatalog(); + c.setCatalog(catalog); + return previousCatalog; + } catch (SQLException e) { + throw new SqlException(e); + } } else { return null; } @@ -112,8 +116,9 @@ public BinaryEncoding getBinaryEncoding() { @Override protected boolean doesTriggerExistOnPlatform(final String catalogName, String schema, String tableName, final String triggerName) { - return jdbcTemplate.execute(new ConnectionCallback() { - public Boolean doInConnection(Connection con) throws SQLException, DataAccessException { + return ((JdbcSqlTemplate) platform.getSqlTemplate()) + .execute(new IConnectionCallback() { + public Boolean execute(Connection con) throws SQLException { String previousCatalog = con.getCatalog(); PreparedStatement stmt = con .prepareStatement("select count(*) from sysobjects where type = 'TR' AND name = ?"); @@ -152,12 +157,12 @@ public void enableSyncTriggers(ISqlTransaction transaction) { } public String getSyncTriggersExpression() { - return "$(defaultCatalog)dbo."+tablePrefix+"_triggers_disabled(0) = 0"; + return "$(defaultCatalog)dbo."+parameterService.getTablePrefix()+"_triggers_disabled(0) = 0"; } @Override public String getTransactionTriggerExpression(String defaultCatalog, String defaultSchema, Trigger trigger) { - return platform.getDefaultCatalog() + ".dbo."+tablePrefix+"_txid(0)"; + return platform.getDefaultCatalog() + ".dbo."+parameterService.getTablePrefix()+"_txid(0)"; } @Override diff --git a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/ext/ExtensionPointManager.java b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/ext/ExtensionPointManager.java index 34768f2a99..c1c537fd43 100644 --- a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/ext/ExtensionPointManager.java +++ b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/ext/ExtensionPointManager.java @@ -16,8 +16,9 @@ * "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.jumpmind.symmetric.ext; + * under the License. + */ +package org.jumpmind.symmetric.ext; import java.util.ArrayList; import java.util.List; @@ -26,13 +27,12 @@ import org.jumpmind.extension.IBuiltInExtensionPoint; import org.jumpmind.extension.IExtensionPoint; -import org.jumpmind.symmetric.common.logging.ILog; -import org.jumpmind.symmetric.common.logging.LogFactory; +import org.jumpmind.log.Log; +import org.jumpmind.log.LogFactory; +import org.jumpmind.symmetric.ISymmetricEngine; import org.jumpmind.symmetric.config.INodeIdGenerator; import org.jumpmind.symmetric.config.IParameterFilter; import org.jumpmind.symmetric.config.ITriggerCreationListener; -import org.jumpmind.symmetric.db.ISymmetricDialect; -import org.jumpmind.symmetric.extract.IExtractorFilter; import org.jumpmind.symmetric.io.IOfflineClientListener; import org.jumpmind.symmetric.io.data.transform.IColumnTransform; import org.jumpmind.symmetric.io.data.writer.IDatabaseWriterFilter; @@ -41,280 +41,208 @@ import org.jumpmind.symmetric.route.IBatchAlgorithm; import org.jumpmind.symmetric.route.IDataRouter; import org.jumpmind.symmetric.security.INodePasswordFilter; -import org.jumpmind.symmetric.service.IAcknowledgeService; -import org.jumpmind.symmetric.service.IDataExtractorService; -import org.jumpmind.symmetric.service.IDataLoaderService; -import org.jumpmind.symmetric.service.IDataService; -import org.jumpmind.symmetric.service.INodeService; -import org.jumpmind.symmetric.service.IOfflineDetectorService; -import org.jumpmind.symmetric.service.IParameterService; -import org.jumpmind.symmetric.service.IRegistrationService; -import org.jumpmind.symmetric.service.IRouterService; -import org.jumpmind.symmetric.service.ITriggerRouterService; import org.jumpmind.symmetric.transport.IAcknowledgeEventListener; import org.jumpmind.symmetric.transport.ISyncUrlExtension; -import org.jumpmind.symmetric.transport.ITransportManager; import org.springframework.beans.BeansException; -import org.springframework.beans.factory.BeanFactory; -import org.springframework.beans.factory.BeanFactoryAware; import org.springframework.beans.factory.ListableBeanFactory; -import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; import org.springframework.context.ApplicationContext; - -/** - * This manager registers {@link IExtensionPoint}s defined both by SymmetricDS - * and others found in the {@link ApplicationContext}. - *

- * SymmetricDS reads in any Spring XML file found in the classpath of the - * application that matches the following pattern: +import org.springframework.context.support.ClassPathXmlApplicationContext; + +/** + * This manager registers {@link IExtensionPoint}s defined both by SymmetricDS + * and others found in the {@link ApplicationContext}. + *

+ * SymmetricDS reads in any Spring XML file found in the classpath of the + * application that matches the following pattern: * /META-INF/services/symmetric-*-ext.xml - */ -public class ExtensionPointManager implements IExtensionPointManager, BeanFactoryAware { - - private ILog log = LogFactory.getLog(getClass()); - - private IDataLoaderService dataLoaderService; - - private IDataService dataService; - - private IDataExtractorService dataExtractorService; - - private IParameterService parameterService; - - private INodeService nodeService; - - private IAcknowledgeService acknowledgeService; - - private List offlineDetectorServices; - - private IRegistrationService registrationService; - - private ITriggerRouterService triggerRouterService; - - private ITransportManager transportManager; - - private IRouterService routingService; - - private ISymmetricDialect symmetricDialect; - - private BeanFactory beanFactory; - + */ +public class ExtensionPointManager implements IExtensionPointManager { + + private Log log = LogFactory.getLog(getClass()); + private boolean initialized = false; - - private List extensionPoints = new ArrayList(); - - public void register() throws BeansException { - ConfigurableListableBeanFactory cfgBeanFactory = (ConfigurableListableBeanFactory) beanFactory; - if (!initialized) { - Map extensions = new TreeMap(); - extensions.putAll(cfgBeanFactory.getBeansOfType(IExtensionPoint.class)); - if (cfgBeanFactory.getParentBeanFactory() != null - && cfgBeanFactory.getParentBeanFactory() instanceof ListableBeanFactory) { - extensions.putAll(((ListableBeanFactory) cfgBeanFactory.getParentBeanFactory()) - .getBeansOfType(IExtensionPoint.class)); - } - for (String beanName : extensions.keySet()) { + + private ISymmetricEngine engine; + + private List extensionPoints = new ArrayList(); + + public ExtensionPointManager(Log log, ISymmetricEngine engine) { + this.log = log; + this.engine = engine; + } + + public void register() throws BeansException { + + ApplicationContext cfgBeanFactory = new ClassPathXmlApplicationContext( + "classpath://symmetric-extensions.xml"); + if (!initialized) { + Map extensions = new TreeMap(); + extensions.putAll(cfgBeanFactory.getBeansOfType(IExtensionPoint.class)); + if (cfgBeanFactory.getParentBeanFactory() != null + && cfgBeanFactory.getParentBeanFactory() instanceof ListableBeanFactory) { + extensions.putAll(((ListableBeanFactory) cfgBeanFactory.getParentBeanFactory()) + .getBeansOfType(IExtensionPoint.class)); + } + for (String beanName : extensions.keySet()) { IExtensionPoint ext = extensions.get(beanName); - boolean registered = false; - if (ext.isAutoRegister()) { - boolean registerExtension = false; - if (ext instanceof INodeGroupExtensionPoint) { - String nodeGroupId = parameterService.getNodeGroupId(); - INodeGroupExtensionPoint nodeExt = (INodeGroupExtensionPoint) ext; - String[] ids = nodeExt.getNodeGroupIdsToApplyTo(); - if (ids != null) { - for (String targetNodeGroupId : ids) { - if (nodeGroupId.equals(targetNodeGroupId)) { - registerExtension = true; - } - } - } else { - registerExtension = true; - } - } else { - registerExtension = true; - } - - if (registerExtension) { - registered = registerExtension(beanName, ext); - } + if (ext instanceof ISymmetricEngineAware) { + ((ISymmetricEngineAware) ext).setSymmetricEngine(engine); + } + boolean registered = false; + if (ext.isAutoRegister()) { + boolean registerExtension = false; + if (ext instanceof INodeGroupExtensionPoint) { + String nodeGroupId = engine.getParameterService().getNodeGroupId(); + INodeGroupExtensionPoint nodeExt = (INodeGroupExtensionPoint) ext; + String[] ids = nodeExt.getNodeGroupIdsToApplyTo(); + if (ids != null) { + for (String targetNodeGroupId : ids) { + if (nodeGroupId.equals(targetNodeGroupId)) { + registerExtension = true; + } + } + } else { + registerExtension = true; + } + } else { + registerExtension = true; + } + + if (registerExtension) { + registered = registerExtension(beanName, ext); + } } - + if (!registered) { extensionPoints.add(new ExtensionPointMetaData(ext, beanName, null, false)); - } - } - this.initialized = true; - } - - } - + } + } + this.initialized = true; + } + + } + public List getExtensionPoints() { return new ArrayList(extensionPoints); - } - + } + protected boolean registerExtension(String beanName, IExtensionPoint ext) { boolean installed = false; - if (ext instanceof IBuiltInExtensionPoint) { - log.debug("ExtensionRegistering", beanName, ext.getClass().getSimpleName()); - } else { - log.info("ExtensionRegistering", beanName, ext.getClass().getSimpleName()); - } - + if (ext instanceof IBuiltInExtensionPoint) { + log.debug("ExtensionRegistering", beanName, ext.getClass().getSimpleName()); + } else { + log.info("ExtensionRegistering", beanName, ext.getClass().getSimpleName()); + } + if (ext instanceof ISyncUrlExtension) { installed = true; - extensionPoints.add(new ExtensionPointMetaData(ext, beanName, ISyncUrlExtension.class, true)); - transportManager.addExtensionSyncUrlHandler(beanName, (ISyncUrlExtension) ext); - } - + extensionPoints.add(new ExtensionPointMetaData(ext, beanName, ISyncUrlExtension.class, + true)); + engine.getTransportManager().addExtensionSyncUrlHandler(beanName, + (ISyncUrlExtension) ext); + } + if (ext instanceof INodePasswordFilter) { installed = true; - extensionPoints.add(new ExtensionPointMetaData(ext, beanName, INodePasswordFilter.class, true)); - nodeService.setNodePasswordFilter((INodePasswordFilter) ext); - registrationService.setNodePasswordFilter((INodePasswordFilter) ext); - } - + extensionPoints.add(new ExtensionPointMetaData(ext, beanName, + INodePasswordFilter.class, true)); + engine.getNodeService().setNodePasswordFilter((INodePasswordFilter) ext); + engine.getRegistrationService().setNodePasswordFilter((INodePasswordFilter) ext); + } + if (ext instanceof IAcknowledgeEventListener) { installed = true; - extensionPoints.add(new ExtensionPointMetaData(ext, beanName, IAcknowledgeEventListener.class, true)); - acknowledgeService.addAcknowledgeEventListener((IAcknowledgeEventListener) ext); - } - + extensionPoints.add(new ExtensionPointMetaData(ext, beanName, + IAcknowledgeEventListener.class, true)); + engine.getAcknowledgeService().addAcknowledgeEventListener( + (IAcknowledgeEventListener) ext); + } + if (ext instanceof ITriggerCreationListener) { installed = true; - extensionPoints.add(new ExtensionPointMetaData(ext, beanName, ITriggerCreationListener.class, true)); - triggerRouterService.addTriggerCreationListeners((ITriggerCreationListener) ext); - } - + extensionPoints.add(new ExtensionPointMetaData(ext, beanName, + ITriggerCreationListener.class, true)); + engine.getTriggerRouterService().addTriggerCreationListeners( + (ITriggerCreationListener) ext); + } + if (ext instanceof IDatabaseWriterFilter) { installed = true; - extensionPoints.add(new ExtensionPointMetaData(ext, beanName, IDatabaseWriterFilter.class, true)); - dataLoaderService.addDatabaseWriterFilter((IDatabaseWriterFilter) ext); - } - + extensionPoints.add(new ExtensionPointMetaData(ext, beanName, + IDatabaseWriterFilter.class, true)); + engine.getDataLoaderService().addDatabaseWriterFilter((IDatabaseWriterFilter) ext); + } + if (ext instanceof IHeartbeatListener) { installed = true; - extensionPoints.add(new ExtensionPointMetaData(ext, beanName, IHeartbeatListener.class, true)); - dataService.addHeartbeatListener((IHeartbeatListener) ext); - } - + extensionPoints.add(new ExtensionPointMetaData(ext, beanName, IHeartbeatListener.class, + true)); + engine.getDataService().addHeartbeatListener((IHeartbeatListener) ext); + } + if (ext instanceof IReloadListener) { installed = true; - extensionPoints.add(new ExtensionPointMetaData(ext, beanName, IReloadListener.class, true)); - dataService.addReloadListener((IReloadListener) ext); - } - + extensionPoints.add(new ExtensionPointMetaData(ext, beanName, IReloadListener.class, + true)); + engine.getDataService().addReloadListener((IReloadListener) ext); + } + if (ext instanceof IParameterFilter) { installed = true; - extensionPoints.add(new ExtensionPointMetaData(ext, beanName, IParameterFilter.class, true)); - parameterService.setParameterFilter((IParameterFilter) ext); - } - - if (ext instanceof IExtractorFilter) { - installed = true; - extensionPoints.add(new ExtensionPointMetaData(ext, beanName, IExtractorFilter.class, true)); - dataExtractorService.addExtractorFilter((IExtractorFilter) ext); - } - + extensionPoints.add(new ExtensionPointMetaData(ext, beanName, IParameterFilter.class, + true)); + engine.getParameterService().setParameterFilter((IParameterFilter) ext); + } + if (ext instanceof INodeIdGenerator) { installed = true; - extensionPoints.add(new ExtensionPointMetaData(ext, beanName, INodeIdGenerator.class, true)); - nodeService.setNodeIdGenerator((INodeIdGenerator) ext); - } - + extensionPoints.add(new ExtensionPointMetaData(ext, beanName, INodeIdGenerator.class, + true)); + engine.getNodeService().setNodeIdGenerator((INodeIdGenerator) ext); + } + if (ext instanceof IDataRouter) { installed = true; - extensionPoints.add(new ExtensionPointMetaData(ext, beanName, IDataRouter.class, true)); - routingService.addDataRouter(beanName, (IDataRouter) ext); - } - + extensionPoints.add(new ExtensionPointMetaData(ext, beanName, IDataRouter.class, true)); + engine.getRouterService().addDataRouter(beanName, (IDataRouter) ext); + } + if (ext instanceof IBatchAlgorithm) { installed = true; - extensionPoints.add(new ExtensionPointMetaData(ext, beanName, IBatchAlgorithm.class, true)); - routingService.addBatchAlgorithm(beanName, (IBatchAlgorithm) ext); - } - - if (ext instanceof IOfflineClientListener) { - for (IOfflineDetectorService service : offlineDetectorServices) { - installed = true; - extensionPoints.add(new ExtensionPointMetaData(ext, beanName, IOfflineClientListener.class, true)); - service.addOfflineListener((IOfflineClientListener) ext); - } - } - + extensionPoints.add(new ExtensionPointMetaData(ext, beanName, IBatchAlgorithm.class, + true)); + engine.getRouterService().addBatchAlgorithm(beanName, (IBatchAlgorithm) ext); + } + + if (ext instanceof IOfflineClientListener) { + installed = true; + extensionPoints.add(new ExtensionPointMetaData(ext, beanName, + IOfflineClientListener.class, true)); + engine.getPushService().addOfflineListener((IOfflineClientListener) ext); + engine.getPullService().addOfflineListener((IOfflineClientListener) ext); + } + if (ext instanceof IOfflineServerListener) { installed = true; - extensionPoints.add(new ExtensionPointMetaData(ext, beanName, IOfflineServerListener.class, true)); - nodeService.addOfflineServerListener((IOfflineServerListener) ext); - } - + extensionPoints.add(new ExtensionPointMetaData(ext, beanName, + IOfflineServerListener.class, true)); + engine.getNodeService().addOfflineServerListener((IOfflineServerListener) ext); + } + if (ext instanceof IExtraConfigTables) { - triggerRouterService.addExtraConfigTables((IExtraConfigTables)ext); + engine.getTriggerRouterService().addExtraConfigTables((IExtraConfigTables) ext); } - + if (ext instanceof IDatabaseUpgradeListener) { - symmetricDialect.addDatabaseUpgradeListener((IDatabaseUpgradeListener)ext); + engine.getSymmetricDialect().addDatabaseUpgradeListener((IDatabaseUpgradeListener) ext); } - + if (ext instanceof IColumnTransform) { - IColumnTransform t = (IColumnTransform)ext; + IColumnTransform t = (IColumnTransform) ext; TransformWriter.addColumnTransform(t); } - return installed; - } - - public void setDataLoaderService(IDataLoaderService dataLoaderService) { - this.dataLoaderService = dataLoaderService; - } - - public void setDataService(IDataService dataService) { - this.dataService = dataService; - } - - public void setDataExtractorService(IDataExtractorService dataExtractorService) { - this.dataExtractorService = dataExtractorService; - } - - public void setParameterService(IParameterService parameterService) { - this.parameterService = parameterService; - this.log = LogFactory.getLog(parameterService); - } - - public void setNodeService(INodeService nodeService) { - this.nodeService = nodeService; - } - - public void setAcknowledgeService(IAcknowledgeService acknowledgeService) { - this.acknowledgeService = acknowledgeService; - } - - public void setRegistrationService(IRegistrationService registrationService) { - this.registrationService = registrationService; - } - - public void setTransportManager(ITransportManager transportManager) { - this.transportManager = transportManager; - } - - public void setRoutingService(IRouterService routingService) { - this.routingService = routingService; - } - - public void setTriggerRouterService(ITriggerRouterService triggerService) { - this.triggerRouterService = triggerService; - } - - public void setOfflineDetectorServices(List offlineDetectorServices) { - this.offlineDetectorServices = offlineDetectorServices; - } - - public void setBeanFactory(BeanFactory beanFactory) throws BeansException { - this.beanFactory = beanFactory; + return installed; } - - public void setSymmetricDialect(ISymmetricDialect symmetricDialect) { - this.symmetricDialect = symmetricDialect; - } - + } \ No newline at end of file diff --git a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/ext/ISymmetricEngineAware.java b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/ext/ISymmetricEngineAware.java new file mode 100644 index 0000000000..3efd51bbe8 --- /dev/null +++ b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/ext/ISymmetricEngineAware.java @@ -0,0 +1,14 @@ +package org.jumpmind.symmetric.ext; + +import org.jumpmind.symmetric.ISymmetricEngine; + +/** + * If an extension point needs access to SymmetricDS services it should + * implement this interface and access the apis via the {@link ISymmetricEngine} + * interface. + */ +public interface ISymmetricEngineAware { + + public void setSymmetricEngine(ISymmetricEngine engine); + +} diff --git a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/extract/DataExtractorContext.java b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/extract/DataExtractorContext.java deleted file mode 100644 index c03c5ada1f..0000000000 --- a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/extract/DataExtractorContext.java +++ /dev/null @@ -1,137 +0,0 @@ -/* - * Licensed to JumpMind Inc under one or more contributor - * license agreements. See the NOTICE file distributed - * with this work for additional information regarding - * copyright ownership. JumpMind Inc licenses this file - * to you under the GNU Lesser General Public License (the - * "License"); you may not use this file except in compliance - * with the License. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see - * . - * - * 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.jumpmind.symmetric.extract; - -import java.util.Collection; -import java.util.HashMap; -import java.util.Map; - -import org.jumpmind.db.util.BinaryEncoding; -import org.jumpmind.symmetric.common.Constants; -import org.jumpmind.symmetric.db.ISymmetricDialect; -import org.jumpmind.symmetric.model.OutgoingBatch; -import org.jumpmind.symmetric.service.INodeService; -import org.jumpmind.util.Context; -import org.springframework.jdbc.core.JdbcTemplate; - -/** - * Holds the current state of a data extraction - */ -public class DataExtractorContext extends Context implements Cloneable { - - private Map historyRecordsWritten = new HashMap(); - private String lastTriggerHistoryId; - private String lastRouterId; - private OutgoingBatch batch; - private IDataExtractor dataExtractor; - private ISymmetricDialect symmetricDialect; - private JdbcTemplate jdbcTemplate; - private INodeService nodeService; - - public DataExtractorContext copy(IDataExtractor extractor) { - this.dataExtractor = extractor; - DataExtractorContext newVersion; - try { - newVersion = (DataExtractorContext) super.clone(); - newVersion.historyRecordsWritten = new HashMap(); - newVersion.context = new HashMap(); - return newVersion; - } catch (CloneNotSupportedException e) { - throw new RuntimeException(e); - } - } - - public long getBatchId() { - return batch != null ? batch.getBatchId() : Constants.UNROUTED_BATCH_ID; - } - - public BinaryEncoding getBinaryEncoding() { - return symmetricDialect.getBinaryEncoding(); - } - - public Map getContextCache() { - return context; - } - - public JdbcTemplate getJdbcTemplate() { - return jdbcTemplate; - } - - public String getSourceNodeId() { - return nodeService.findIdentityNodeId(); - } - - public Collection getHistoryRecordsWritten() { - return historyRecordsWritten.values(); - } - - public void addHistoryRecordWritten(String tableName, String triggerHistoryId) { - this.historyRecordsWritten.put(tableName, triggerHistoryId); - } - - public void setLastTriggerHistoryId(String triggerHistoryId) { - lastTriggerHistoryId = triggerHistoryId; - } - - public void setLastRouterId(String lastRouterId) { - this.lastRouterId = lastRouterId; - } - - public boolean isLastDataFromSameTriggerAndRouter(String currentTriggerHistoryId, String currentRouterId) { - return lastTriggerHistoryId != null && lastTriggerHistoryId.equals(currentTriggerHistoryId) && lastRouterId != null && lastRouterId.equals(currentRouterId); - } - - public OutgoingBatch getBatch() { - return batch; - } - - public void setBatch(OutgoingBatch batch) { - this.batch = batch; - } - - public IDataExtractor getDataExtractor() { - return dataExtractor; - } - - public void incrementDataEventCount() { - if (batch != null) { - batch.incrementDataEventCount(); - } - } - - public void incrementByteCount(int size) { - if (batch != null) { - batch.incrementByteCount(size); - } - } - - public void setSymmetricDialect(ISymmetricDialect symmetricDialect) { - this.symmetricDialect = symmetricDialect; - } - - public void setJdbcTemplate(JdbcTemplate jdbcTemplate) { - this.jdbcTemplate = jdbcTemplate; - } - - public void setNodeService(INodeService nodeService) { - this.nodeService = nodeService; - } - -} \ No newline at end of file diff --git a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/extract/IDataExtractor.java b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/extract/IDataExtractor.java deleted file mode 100644 index 0d784b5b02..0000000000 --- a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/extract/IDataExtractor.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Licensed to JumpMind Inc under one or more contributor - * license agreements. See the NOTICE file distributed - * with this work for additional information regarding - * copyright ownership. JumpMind Inc licenses this file - * to you under the GNU Lesser General Public License (the - * "License"); you may not use this file except in compliance - * with the License. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see - * . - * - * 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.jumpmind.symmetric.extract; - -import java.io.IOException; -import java.io.Writer; - -import org.jumpmind.symmetric.model.Data; -import org.jumpmind.symmetric.model.OutgoingBatch; - -/** - * Interface that is responsible for writing captured data to the transport format - */ -public interface IDataExtractor { - - public void init(Writer writer, DataExtractorContext context) throws IOException; - - public void begin(OutgoingBatch batch, Writer writer) throws IOException; - - public void preprocessTable(Data data, String routerId, Writer out, DataExtractorContext context) throws IOException; - - public void commit(OutgoingBatch batch, Writer writer) throws IOException; - - public void write(Writer writer, Data data, String routerId, DataExtractorContext context) throws IOException; - - /** - * Give an opportunity to swap out the table name with a different one for backward compatibility - * purposes. - */ - public String getLegacyTableName(String currentTableName); - -} \ No newline at end of file diff --git a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/extract/IExtractorFilter.java b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/extract/IExtractorFilter.java deleted file mode 100644 index 496cdf92c3..0000000000 --- a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/extract/IExtractorFilter.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Licensed to JumpMind Inc under one or more contributor - * license agreements. See the NOTICE file distributed - * with this work for additional information regarding - * copyright ownership. JumpMind Inc licenses this file - * to you under the GNU Lesser General Public License (the - * "License"); you may not use this file except in compliance - * with the License. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see - * . - * - * 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.jumpmind.symmetric.extract; - -import org.jumpmind.extension.IExtensionPoint; -import org.jumpmind.symmetric.model.Data; - -/** - * This extension point is called after data has been extracted, but before it - * has been streamed. It has the ability to inspect each row of data to take - * some action and indicate, if necessary, that the row should not be streamed. - */ -public interface IExtractorFilter extends IExtensionPoint { - - /** - * @return true if the row should be extracted - */ - public boolean filterData(Data data, String routerId, DataExtractorContext ctx); - -} \ No newline at end of file diff --git a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/extract/csv/AbstractStreamDataCommand.java b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/extract/csv/AbstractStreamDataCommand.java deleted file mode 100644 index aa396d905a..0000000000 --- a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/extract/csv/AbstractStreamDataCommand.java +++ /dev/null @@ -1,189 +0,0 @@ -/* - * Licensed to JumpMind Inc under one or more contributor - * license agreements. See the NOTICE file distributed - * with this work for additional information regarding - * copyright ownership. JumpMind Inc licenses this file - * to you under the GNU Lesser General Public License (the - * "License"); you may not use this file except in compliance - * with the License. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see - * . - * - * 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.jumpmind.symmetric.extract.csv; - -import java.sql.ResultSet; -import java.sql.SQLException; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; - -import org.apache.commons.lang.ArrayUtils; -import org.jumpmind.db.model.Column; -import org.jumpmind.db.model.Table; -import org.jumpmind.symmetric.SymmetricException; -import org.jumpmind.symmetric.common.logging.ILog; -import org.jumpmind.symmetric.common.logging.LogFactory; -import org.jumpmind.symmetric.db.ISymmetricDialect; -import org.jumpmind.symmetric.extract.DataExtractorContext; -import org.jumpmind.symmetric.io.data.CsvUtils; -import org.jumpmind.symmetric.model.Data; -import org.jumpmind.symmetric.model.Trigger; -import org.jumpmind.symmetric.model.TriggerHistory; -import org.jumpmind.symmetric.model.TriggerRouter; -import org.jumpmind.symmetric.service.ITriggerRouterService; -import org.jumpmind.util.CollectionUtils; -import org.springframework.dao.IncorrectResultSizeDataAccessException; -import org.springframework.jdbc.core.JdbcTemplate; -import org.springframework.jdbc.core.RowMapper; -import org.springframework.jdbc.support.lob.DefaultLobHandler; -import org.springframework.jdbc.support.lob.LobHandler; - -abstract class AbstractStreamDataCommand implements IStreamDataCommand { - - protected static final String DELIMITER = CsvUtils.DELIMITER; - - protected final ILog log = LogFactory.getLog(getClass()); - - protected ITriggerRouterService triggerRouterService; - - protected ISymmetricDialect symmetricDialect; - - protected void selectAndEnhanceWithLobsIfEnabled(Data data, DataExtractorContext context) { - TriggerHistory triggerHistory = data.getTriggerHistory(); - if (triggerHistory != null) { - Trigger trigger = findTrigger(triggerHistory); - if (trigger != null) { - Table table = symmetricDialect.getTable(trigger, true); - if (table != null) { - if (trigger.isUseStreamLobs()) { - final List lobColumns = getLobColumns(table); - if (lobColumns.size() > 0) { - try { - final String[] columnNames = triggerHistory.getParsedColumnNames(); - final String[] rowData = data.toParsedRowData(); - Column[] orderedColumns = symmetricDialect - .orderColumns(columnNames, table); - Object[] objectValues = symmetricDialect.getPlatform().getObjectValues( - symmetricDialect.getBinaryEncoding(), rowData, orderedColumns); - Map columnDataMap = CollectionUtils.toMap(columnNames, - objectValues); - Column[] pkColumns = table.getPrimaryKeyColumns(); - String sql = buildSelect(table, lobColumns, pkColumns); - JdbcTemplate template = context.getJdbcTemplate(); - Object[] args = new Object[pkColumns.length]; - int[] types = new int[pkColumns.length]; - for (int i = 0; i < pkColumns.length; i++) { - args[i] = columnDataMap.get(pkColumns[i].getName()); - types[i] = pkColumns[i].getTypeCode(); - } - template.query(sql, args, types, new RowMapper() { - public Object mapRow(ResultSet rs, int rowNum) - throws SQLException { - LobHandler lobHandler = symmetricDialect.getLobHandler(); - if (lobHandler == null) { - // If there isn't a lob handler already defined for a platform - // then use the default. - lobHandler = new DefaultLobHandler(); - } - for (Column col : lobColumns) { - String valueForCsv = null; - if (symmetricDialect.getPlatform().isBlob(col.getTypeCode())) { - byte[] blobBytes = lobHandler.getBlobAsBytes(rs, - col.getName()); - valueForCsv = symmetricDialect.encodeForCsv(blobBytes); - } else { - String clobText = lobHandler.getClobAsString(rs, - col.getName()); - valueForCsv = clobText; - } - int index = ArrayUtils.indexOf(columnNames, - col.getName()); - rowData[index] = valueForCsv; - } - return null; - } - }); - data.setRowData(CsvUtils.escapeCsvData(rowData)); - } catch (IncorrectResultSizeDataAccessException ex) { - // Row could have been deleted by the time we - // get around to extracting - log.warn("DataExtractorRowMissingCannotGetLobData", - data.getRowData()); - } catch (Exception ex) { - throw new SymmetricException("DataExtractorTroubleExtractingLobData", ex, data.getRowData()); - } - - } - } - } - } - } - } - - protected Trigger findTrigger(TriggerHistory triggerHistory) { - Trigger trigger = null; - if (triggerHistory != null && triggerRouterService != null) { - Map> cache = triggerRouterService - .getTriggerRoutersForCurrentNode(false); - if (cache != null) { - List trList = cache.get(triggerHistory.getTriggerId()); - if (trList != null && trList.size() > 0) { - trigger = trList.get(0).getTrigger(); - } - } - } - return trigger; - } - - protected String buildSelect(Table table, List lobColumns, Column[] pkColumns) { - StringBuilder sql = new StringBuilder("select "); - String quote = symmetricDialect.getPlatform().getPlatformInfo().getIdentifierQuoteString(); - for (Column col : lobColumns) { - sql.append(quote); - sql.append(col.getName()); - sql.append(quote); - sql.append(","); - } - sql.delete(sql.length() - 1, sql.length()); - sql.append(" from "); - sql.append(table.getFullyQualifiedTableName()); - sql.append(" where "); - for (Column col : pkColumns) { - sql.append(quote); - sql.append(col.getName()); - sql.append(quote); - sql.append("=? and "); - } - sql.delete(sql.length() - 5, sql.length()); - return sql.toString(); - } - - protected List getLobColumns(Table table) { - List lobColumns = new ArrayList(1); - Column[] allColumns = table.getColumns(); - for (Column column : allColumns) { - if (symmetricDialect.getPlatform().isLob(column.getTypeCode())) { - lobColumns.add(column); - } - } - return lobColumns; - } - - public void setTriggerRouterService(ITriggerRouterService triggerRouterService) { - this.triggerRouterService = triggerRouterService; - } - - public void setSymmetricDialect(ISymmetricDialect symmetricDialect) { - this.symmetricDialect = symmetricDialect; - } - -} \ No newline at end of file diff --git a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/extract/csv/CsvExtractor.java b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/extract/csv/CsvExtractor.java deleted file mode 100644 index d7e8514b01..0000000000 --- a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/extract/csv/CsvExtractor.java +++ /dev/null @@ -1,133 +0,0 @@ -/* - * Licensed to JumpMind Inc under one or more contributor - * license agreements. See the NOTICE file distributed - * with this work for additional information regarding - * copyright ownership. JumpMind Inc licenses this file - * to you under the GNU Lesser General Public License (the - * "License"); you may not use this file except in compliance - * with the License. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see - * . - * - * 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.jumpmind.symmetric.extract.csv; - -import java.io.IOException; -import java.io.Writer; - -import org.apache.commons.lang.StringUtils; -import org.jumpmind.symmetric.common.ParameterConstants; -import org.jumpmind.symmetric.extract.DataExtractorContext; -import org.jumpmind.symmetric.extract.IDataExtractor; -import org.jumpmind.symmetric.io.data.CsvConstants; -import org.jumpmind.symmetric.io.data.CsvUtils; -import org.jumpmind.symmetric.io.data.DataEventType; -import org.jumpmind.symmetric.model.Data; -import org.jumpmind.symmetric.model.OutgoingBatch; -import org.jumpmind.symmetric.model.Router; -import org.jumpmind.symmetric.service.ITriggerRouterService; -import org.jumpmind.util.FormatUtils; - -/** - * @see IDataExtractor - */ -public class CsvExtractor extends CsvExtractor16 { - - protected ITriggerRouterService triggerRouterService; - - public void init(Writer writer, DataExtractorContext context) throws IOException { - super.init(writer, context); - CsvUtils.write(writer, CsvConstants.BINARY, CsvUtils.DELIMITER, symmetricDialect.getBinaryEncoding().name()); - CsvUtils.writeLineFeed(writer); - } - - @Override - public void begin(OutgoingBatch batch, Writer writer) throws IOException { - CsvUtils.write(writer, CsvConstants.CHANNEL, CsvUtils.DELIMITER, batch.getChannelId()); - CsvUtils.writeLineFeed(writer); - CsvUtils.write(writer, CsvConstants.BATCH, CsvUtils.DELIMITER, Long.toString(batch.getBatchId())); - CsvUtils.writeLineFeed(writer); - } - - /** - * Writes the table metadata out to a stream only if it hasn't already been - * written out before - * @param out - * @param tableName - */ - @Override - public void preprocessTable(Data data, String routerId, Writer out, DataExtractorContext context) throws IOException { - if (data.getTriggerHistory() == null) { - throw new RuntimeException("Missing trigger_hist for table " + data.getTableName() - + ": try running syncTriggers() or restarting SymmetricDS"); - } else if (!data.getTriggerHistory().getSourceTableName().toLowerCase().equals(data.getTableName().toLowerCase())) { - throw new RuntimeException(String.format("The table name captured in the data table (%1$s) does not match the table name recorded in the trigger_hist table (%2$s). Please drop the symmetric triggers on %1$s and restart the server", data.getTableName(), data.getTriggerHistory().getSourceTableName() )); - } - - String triggerHistoryId = Integer.toString(data.getTriggerHistory().getTriggerHistoryId()).intern(); - if (!context.getHistoryRecordsWritten().contains(triggerHistoryId)) { - writeTable(data, routerId, out, context); - String keyCsv = data.getTriggerHistory().getPkColumnNames(); - if (StringUtils.isNotBlank(keyCsv)) { - context.incrementByteCount(CsvUtils.write(out, CsvConstants.KEYS, ", ", keyCsv)); - } else { - context.incrementByteCount(CsvUtils.write(out, CsvConstants.KEYS)); - } - CsvUtils.writeLineFeed(out); - context.incrementByteCount(CsvUtils.write(out, CsvConstants.COLUMNS, ", ", data.getTriggerHistory().getColumnNames())); - CsvUtils.writeLineFeed(out); - context.addHistoryRecordWritten(data.getTableName(), triggerHistoryId); - } else if (!context.isLastDataFromSameTriggerAndRouter(triggerHistoryId, routerId)) { - writeTable(data, routerId, out, context); - } - - if ((data.getEventType() == DataEventType.UPDATE || data.getEventType() == DataEventType.DELETE) - && data.getOldData() != null - && parameterService.is(ParameterConstants.DATA_EXTRACTOR_OLD_DATA_ENABLED)) { - context.incrementByteCount(CsvUtils.write(out, CsvConstants.OLD, ", ", - data.getOldData())); - CsvUtils.writeLineFeed(out); - } - context.setLastRouterId(routerId); - context.setLastTriggerHistoryId(triggerHistoryId); - } - - protected void writeTable(Data data, String routerId, Writer out, DataExtractorContext context) throws IOException { - Router router = triggerRouterService.getActiveRouterByIdForCurrentNode(routerId, false); - String schemaName = router == null ? "" : getTargetName(router - .getTargetSchemaName()); - context.incrementByteCount(CsvUtils.write(out, CsvConstants.SCHEMA, ", ", schemaName)); - CsvUtils.writeLineFeed(out); - String catalogName = router == null ? "" : getTargetName(router.getTargetCatalogName()); - context.incrementByteCount(CsvUtils.write(out, CsvConstants.CATALOG, ", ", catalogName)); - CsvUtils.writeLineFeed(out); - String tableName = (router == null || router.getTargetTableName() == null) ? data.getTableName() : - getTargetName(router.getTargetTableName()); - context.incrementByteCount(CsvUtils.write(out, CsvConstants.TABLE, ", ", tableName)); - CsvUtils.writeLineFeed(out); - } - - protected String getTargetName(String name) { - String catalogName = name == null ? "" : name; - if (StringUtils.isNotBlank(catalogName)) { - catalogName = FormatUtils.replaceTokens(catalogName, parameterService.getReplacementValues(), true); - } - return catalogName; - } - - public void setTriggerRouterService(ITriggerRouterService triggerRouterService) { - this.triggerRouterService = triggerRouterService; - } - - public String getLegacyTableName(String currentTableName){ - return currentTableName; - } - -} \ No newline at end of file diff --git a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/extract/csv/CsvExtractor10.java b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/extract/csv/CsvExtractor10.java deleted file mode 100644 index ddcd06c48c..0000000000 --- a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/extract/csv/CsvExtractor10.java +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Licensed to JumpMind Inc under one or more contributor - * license agreements. See the NOTICE file distributed - * with this work for additional information regarding - * copyright ownership. JumpMind Inc licenses this file - * to you under the GNU Lesser General Public License (the - * "License"); you may not use this file except in compliance - * with the License. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see - * . - * - * 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.jumpmind.symmetric.extract.csv; - -import java.io.IOException; -import java.io.Writer; -import java.util.Map; - -import org.jumpmind.symmetric.common.ParameterConstants; -import org.jumpmind.symmetric.extract.DataExtractorContext; -import org.jumpmind.symmetric.extract.IDataExtractor; -import org.jumpmind.symmetric.io.data.CsvConstants; -import org.jumpmind.symmetric.io.data.CsvUtils; -import org.jumpmind.symmetric.model.Data; -import org.jumpmind.symmetric.model.OutgoingBatch; -import org.jumpmind.symmetric.service.IParameterService; - -public class CsvExtractor10 implements IDataExtractor { - - private Map dictionary = null; - - private IParameterService parameterService; - - private String tablePrefix; - - public void init(Writer writer, DataExtractorContext context) throws IOException { - CsvUtils.write(writer, CsvConstants.NODEID, CsvUtils.DELIMITER, parameterService - .getString(ParameterConstants.EXTERNAL_ID)); - CsvUtils.writeLineFeed(writer); - } - - public void begin(OutgoingBatch batch, Writer writer) throws IOException { - CsvUtils.write(writer, CsvConstants.BATCH, CsvUtils.DELIMITER, Long.toString(batch.getBatchId())); - CsvUtils.writeLineFeed(writer); - } - - public void commit(OutgoingBatch batch, Writer writer) throws IOException { - CsvUtils.write(writer, CsvConstants.COMMIT, CsvUtils.DELIMITER, Long.toString(batch.getBatchId())); - CsvUtils.writeLineFeed(writer); - } - - public void write(Writer writer, Data data, String routerId, DataExtractorContext context) throws IOException { - preprocessTable(data, routerId, writer, context); - dictionary.get(data.getEventType().getCode()).execute(writer, data, routerId, context); - } - - /** - * Writes the table metadata out to a stream only if it hasn't already been - * written out before - * @param out - * @param tableName - */ - public void preprocessTable(Data data, String routerId, Writer out, DataExtractorContext context) throws IOException { - - String historyId = Integer.toString(data.getTriggerHistory().getTriggerHistoryId()).intern(); - if (!context.getHistoryRecordsWritten().contains(historyId)) { - CsvUtils.write(out, "table, ", data.getTableName()); - CsvUtils.writeLineFeed(out); - CsvUtils.write(out, "keys, ", data.getTriggerHistory().getPkColumnNames()); - CsvUtils.writeLineFeed(out); - String columns = data.getTriggerHistory().getColumnNames(); - if (data.getTableName().equalsIgnoreCase(tablePrefix + "_node_security")) { - // In 1.4 the column named changed to "node_password", but old - // clients need "password" - columns = columns.replaceFirst(",node_password,", ",password,"); - columns = columns.replaceFirst(",NODE_PASSWORD,", ",PASSWORD,"); - } - CsvUtils.write(out, "columns, ", columns); - CsvUtils.writeLineFeed(out); - context.addHistoryRecordWritten(data.getTableName(), historyId); - } else if (!context.isLastDataFromSameTriggerAndRouter(historyId, routerId)) { - CsvUtils.write(out, "table, ", data.getTableName()); - CsvUtils.writeLineFeed(out); - } - - context.setLastRouterId(routerId); - context.setLastTriggerHistoryId(historyId); - } - - public void setDictionary(Map dictionary) { - this.dictionary = dictionary; - } - - public void setTablePrefix(String tablePrefix) { - this.tablePrefix = tablePrefix; - } - - public void setParameterService(IParameterService parameterService) { - this.parameterService = parameterService; - } - - public String getLegacyTableName(String currentTableName) { - return currentTableName; - } -} \ No newline at end of file diff --git a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/extract/csv/CsvExtractor13.java b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/extract/csv/CsvExtractor13.java deleted file mode 100644 index 553ccdb3ca..0000000000 --- a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/extract/csv/CsvExtractor13.java +++ /dev/null @@ -1,127 +0,0 @@ -/* - * Licensed to JumpMind Inc under one or more contributor - * license agreements. See the NOTICE file distributed - * with this work for additional information regarding - * copyright ownership. JumpMind Inc licenses this file - * to you under the GNU Lesser General Public License (the - * "License"); you may not use this file except in compliance - * with the License. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see - * . - * - * 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.jumpmind.symmetric.extract.csv; - -import java.io.IOException; -import java.io.Writer; -import java.util.Map; - -import org.jumpmind.symmetric.common.ParameterConstants; -import org.jumpmind.symmetric.db.ISymmetricDialect; -import org.jumpmind.symmetric.extract.DataExtractorContext; -import org.jumpmind.symmetric.extract.IDataExtractor; -import org.jumpmind.symmetric.io.data.CsvConstants; -import org.jumpmind.symmetric.io.data.CsvUtils; -import org.jumpmind.symmetric.model.Data; -import org.jumpmind.symmetric.model.OutgoingBatch; -import org.jumpmind.symmetric.service.IParameterService; - -public class CsvExtractor13 implements IDataExtractor { - - private Map dictionary = null; - - private IParameterService parameterService; - - private ISymmetricDialect symmetricDialect; - - private String tablePrefix; - - public void init(Writer writer, DataExtractorContext context) throws IOException { - CsvUtils.write(writer, CsvConstants.NODEID, CsvUtils.DELIMITER, parameterService - .getString(ParameterConstants.EXTERNAL_ID)); - CsvUtils.writeLineFeed(writer); - } - - public void begin(OutgoingBatch batch, Writer writer) throws IOException { - CsvUtils.write(writer, CsvConstants.BATCH, CsvUtils.DELIMITER, Long.toString(batch.getBatchId())); - CsvUtils.writeLineFeed(writer); - CsvUtils.write(writer, CsvConstants.BINARY, CsvUtils.DELIMITER, symmetricDialect.getBinaryEncoding() - .name()); - CsvUtils.writeLineFeed(writer); - } - - public void commit(OutgoingBatch batch, Writer writer) throws IOException { - CsvUtils.write(writer, CsvConstants.COMMIT, CsvUtils.DELIMITER, Long.toString(batch.getBatchId())); - CsvUtils.writeLineFeed(writer); - } - - public void write(Writer writer, Data data, String routerId, DataExtractorContext context) throws IOException { - preprocessTable(data, routerId, writer, context); - dictionary.get(data.getEventType().getCode()).execute(writer, data, routerId, context); - } - - /** - * Writes the table metadata out to a stream only if it hasn't already been - * written out before - * @param out - * @param tableName - */ - public void preprocessTable(Data data, String routerId, Writer out, DataExtractorContext context) throws IOException { - - if (data.getTriggerHistory() == null) { - throw new RuntimeException("Missing trigger_hist for table " + data.getTableName() - + ": try running syncTriggers() or restarting SymmetricDS"); - } - String historyId = Integer.toString(data.getTriggerHistory().getTriggerHistoryId()).intern(); - if (!context.getHistoryRecordsWritten().contains(historyId)) { - CsvUtils.write(out, "table, ", data.getTableName()); - CsvUtils.writeLineFeed(out); - CsvUtils.write(out, "keys, ", data.getTriggerHistory().getPkColumnNames()); - CsvUtils.writeLineFeed(out); - String columns = data.getTriggerHistory().getColumnNames(); - if (data.getTableName().equalsIgnoreCase(tablePrefix + "_node_security")) { - // In 1.4 the column named changed to "node_password", but old - // clients need "password" - columns = columns.replaceFirst(",node_password,", ",password,"); - columns = columns.replaceFirst(",NODE_PASSWORD,", ",PASSWORD,"); - } - CsvUtils.write(out, "columns, ", columns); - CsvUtils.writeLineFeed(out); - context.addHistoryRecordWritten(data.getTableName(), historyId); - } else if (!context.isLastDataFromSameTriggerAndRouter(historyId, routerId)) { - CsvUtils.write(out, "table, ", data.getTableName()); - CsvUtils.writeLineFeed(out); - } - - context.setLastRouterId(routerId); - context.setLastTriggerHistoryId(historyId); - } - - public void setDictionary(Map dictionary) { - this.dictionary = dictionary; - } - - public void setSymmetricDialect(ISymmetricDialect symmetricDialect) { - this.symmetricDialect = symmetricDialect; - } - - public void setTablePrefix(String tablePrefix) { - this.tablePrefix = tablePrefix; - } - - public void setParameterService(IParameterService parameterService) { - this.parameterService = parameterService; - } - public String getLegacyTableName(String currentTableName) { - return currentTableName; - } -} \ No newline at end of file diff --git a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/extract/csv/CsvExtractor14.java b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/extract/csv/CsvExtractor14.java deleted file mode 100644 index c538dbe450..0000000000 --- a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/extract/csv/CsvExtractor14.java +++ /dev/null @@ -1,137 +0,0 @@ -/* - * Licensed to JumpMind Inc under one or more contributor - * license agreements. See the NOTICE file distributed - * with this work for additional information regarding - * copyright ownership. JumpMind Inc licenses this file - * to you under the GNU Lesser General Public License (the - * "License"); you may not use this file except in compliance - * with the License. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see - * . - * - * 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.jumpmind.symmetric.extract.csv; - -import java.io.IOException; -import java.io.Writer; -import java.util.HashMap; -import java.util.Map; - -import org.jumpmind.symmetric.common.ParameterConstants; -import org.jumpmind.symmetric.db.ISymmetricDialect; -import org.jumpmind.symmetric.extract.DataExtractorContext; -import org.jumpmind.symmetric.extract.IDataExtractor; -import org.jumpmind.symmetric.io.data.CsvConstants; -import org.jumpmind.symmetric.io.data.CsvUtils; -import org.jumpmind.symmetric.model.Data; -import org.jumpmind.symmetric.model.Node; -import org.jumpmind.symmetric.model.OutgoingBatch; -import org.jumpmind.symmetric.service.INodeService; -import org.jumpmind.symmetric.service.IParameterService; - -/** - * @see IDataExtractor - */ -public class CsvExtractor14 implements IDataExtractor { - - private Map legacyTableMapping = new HashMap(); - - protected Map dictionary = null; - - protected IParameterService parameterService; - - protected ISymmetricDialect symmetricDialect; - - protected INodeService nodeService; - - public CsvExtractor14() { - legacyTableMapping.put("sym_trigger", "sym_trigger_old"); - } - - public void init(Writer writer, DataExtractorContext context) throws IOException { - Node nodeIdentity = nodeService.findIdentity(); - String nodeId = (nodeIdentity == null) ? parameterService.getString(ParameterConstants.EXTERNAL_ID) - : nodeIdentity.getNodeId(); - context.incrementByteCount(CsvUtils.write(writer, CsvConstants.NODEID, CsvUtils.DELIMITER, nodeId)); - CsvUtils.writeLineFeed(writer); - } - - public void begin(OutgoingBatch batch, Writer writer) throws IOException { - batch.incrementByteCount(CsvUtils.write(writer, CsvConstants.BATCH, CsvUtils.DELIMITER, Long.toString(batch.getBatchId()))); - CsvUtils.writeLineFeed(writer); - batch.incrementByteCount(CsvUtils.write(writer, CsvConstants.BINARY, CsvUtils.DELIMITER, symmetricDialect.getBinaryEncoding().name())); - CsvUtils.writeLineFeed(writer); - } - - public void commit(OutgoingBatch batch, Writer writer) throws IOException { - batch.incrementByteCount(CsvUtils.write(writer, CsvConstants.COMMIT, CsvUtils.DELIMITER, Long.toString(batch.getBatchId()))); - CsvUtils.writeLineFeed(writer); - } - - public void write(Writer writer, Data data, String routerId, DataExtractorContext context) throws IOException { - preprocessTable(data, routerId, writer, context); - dictionary.get(data.getEventType().getCode()).execute(writer, data, routerId, context); - } - - /** - * Writes the table metadata out to a stream only if it hasn't already been - * written out before - * @param out - * @param tableName - */ - public void preprocessTable(Data data, String routerId, Writer out, DataExtractorContext context) throws IOException { - if (data.getTriggerHistory() != null) { - String historyId = Integer.toString(data.getTriggerHistory().getTriggerHistoryId()).intern(); - if (!context.getHistoryRecordsWritten().contains(historyId)) { - CsvUtils.write(out, CsvConstants.TABLE, ", ", data.getTableName()); - CsvUtils.writeLineFeed(out); - CsvUtils.write(out, CsvConstants.KEYS, ", ", data.getTriggerHistory().getPkColumnNames()); - CsvUtils.writeLineFeed(out); - CsvUtils.write(out, CsvConstants.COLUMNS, ", ", data.getTriggerHistory().getColumnNames()); - CsvUtils.writeLineFeed(out); - context.addHistoryRecordWritten(data.getTableName(), historyId); - } else if (!context.isLastDataFromSameTriggerAndRouter(historyId, routerId)) { - CsvUtils.write(out, CsvConstants.TABLE, ", ", data.getTableName()); - CsvUtils.writeLineFeed(out); - } - - context.setLastRouterId(routerId); - context.setLastTriggerHistoryId(historyId); - } - } - - public void setDictionary(Map dictionary) { - this.dictionary = dictionary; - } - - public void setSymmetricDialect(ISymmetricDialect symmetricDialect) { - this.symmetricDialect = symmetricDialect; - } - - public void setParameterService(IParameterService parameterService) { - this.parameterService = parameterService; - } - - public void setNodeService(INodeService nodeService) { - this.nodeService = nodeService; - } - - public String getLegacyTableName(String currentTableName) { - String result = currentTableName; - - if (legacyTableMapping.get(currentTableName.toLowerCase()) != null) { - result = legacyTableMapping.get(currentTableName.toLowerCase()); - } - return result; - } - -} \ No newline at end of file diff --git a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/extract/csv/CsvExtractor16.java b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/extract/csv/CsvExtractor16.java deleted file mode 100644 index fa3acf8ac5..0000000000 --- a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/extract/csv/CsvExtractor16.java +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Licensed to JumpMind Inc under one or more contributor - * license agreements. See the NOTICE file distributed - * with this work for additional information regarding - * copyright ownership. JumpMind Inc licenses this file - * to you under the GNU Lesser General Public License (the - * "License"); you may not use this file except in compliance - * with the License. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see - * . - * - * 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.jumpmind.symmetric.extract.csv; - -import java.io.IOException; -import java.io.Writer; - -import org.jumpmind.symmetric.SymmetricException; -import org.jumpmind.symmetric.common.ParameterConstants; -import org.jumpmind.symmetric.extract.DataExtractorContext; -import org.jumpmind.symmetric.extract.IDataExtractor; -import org.jumpmind.symmetric.io.data.CsvConstants; -import org.jumpmind.symmetric.io.data.CsvUtils; -import org.jumpmind.symmetric.io.data.DataEventType; -import org.jumpmind.symmetric.model.Data; - -/** - * @see IDataExtractor - */ -public class CsvExtractor16 extends CsvExtractor14 { - - @Override - public void write(Writer writer, Data data, String routerId, DataExtractorContext context) - throws IOException { - IStreamDataCommand cmd = dictionary.get(data.getEventType().getCode()); - if (cmd == null) { - throw new SymmetricException("DataExtractorCouldNotFindStreamCommand", data.getEventType().getCode()); - } else if (cmd.isTriggerHistoryRequired()) { - preprocessTable(data, routerId, writer, context); - } - cmd.execute(writer, data, routerId, context); - } - - /** - * Writes the table metadata out to a stream only if it hasn't already been - * written out before - * - * @param out - * @param tableName - */ - @Override - public void preprocessTable(Data data, String routerId, Writer out, DataExtractorContext context) - throws IOException { - if (data.getTriggerHistory() == null) { - throw new RuntimeException("Missing trigger_hist for table " + data.getTableName() - + ": try running syncTriggers() or restarting SymmetricDS"); - } else if (!data.getTriggerHistory().getSourceTableName().toLowerCase().equals( - data.getTableName().toLowerCase())) { - throw new RuntimeException( - String - .format( - "The table name captured in the data table (%1$s) does not match the table name recorded in the trigger_hist table (%2$s). Please drop the symmetric triggers on %1$s and restart the server", - data.getTableName(), data.getTriggerHistory().getSourceTableName())); - } - String triggerHistId = Integer.toString(data.getTriggerHistory().getTriggerHistoryId()).intern(); - if (!context.getHistoryRecordsWritten().contains(triggerHistId)) { - context.incrementByteCount(CsvUtils.write(out, CsvConstants.TABLE, ", ", data.getTableName())); - CsvUtils.writeLineFeed(out); - context.incrementByteCount(CsvUtils.write(out, CsvConstants.KEYS, ", ", data.getTriggerHistory().getPkColumnNames())); - CsvUtils.writeLineFeed(out); - context.incrementByteCount(CsvUtils.write(out, CsvConstants.COLUMNS, ", ", data.getTriggerHistory().getColumnNames())); - CsvUtils.writeLineFeed(out); - context.addHistoryRecordWritten(data.getTableName(), triggerHistId); - } else if (!context.isLastDataFromSameTriggerAndRouter(triggerHistId, routerId)) { - context.incrementByteCount(CsvUtils.write(out, CsvConstants.TABLE, ", ", data.getTableName())); - CsvUtils.writeLineFeed(out); - } - - if (data.getEventType() == DataEventType.UPDATE && data.getOldData() != null && parameterService.is(ParameterConstants.DATA_EXTRACTOR_OLD_DATA_ENABLED)) { - CsvUtils.write(out, CsvConstants.OLD, ", ", data.getOldData()); - CsvUtils.writeLineFeed(out); - } - context.setLastRouterId(routerId); - context.setLastTriggerHistoryId(triggerHistId); - } - -} \ No newline at end of file diff --git a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/extract/csv/IStreamDataCommand.java b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/extract/csv/IStreamDataCommand.java deleted file mode 100644 index 71eabe2ffc..0000000000 --- a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/extract/csv/IStreamDataCommand.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Licensed to JumpMind Inc under one or more contributor - * license agreements. See the NOTICE file distributed - * with this work for additional information regarding - * copyright ownership. JumpMind Inc licenses this file - * to you under the GNU Lesser General Public License (the - * "License"); you may not use this file except in compliance - * with the License. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see - * . - * - * 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.jumpmind.symmetric.extract.csv; - -import java.io.IOException; -import java.io.Writer; - -import org.jumpmind.symmetric.extract.DataExtractorContext; -import org.jumpmind.symmetric.model.Data; - -interface IStreamDataCommand { - void execute(Writer out, Data data, String routerId, DataExtractorContext context) - throws IOException; - - boolean isTriggerHistoryRequired(); -} \ No newline at end of file diff --git a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/extract/csv/StreamBshDataCommand.java b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/extract/csv/StreamBshDataCommand.java deleted file mode 100644 index 19231dd65a..0000000000 --- a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/extract/csv/StreamBshDataCommand.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Licensed to JumpMind Inc under one or more contributor - * license agreements. See the NOTICE file distributed - * with this work for additional information regarding - * copyright ownership. JumpMind Inc licenses this file - * to you under the GNU Lesser General Public License (the - * "License"); you may not use this file except in compliance - * with the License. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see - * . - * - * 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.jumpmind.symmetric.extract.csv; - -import java.io.IOException; -import java.io.Writer; - -import org.jumpmind.symmetric.extract.DataExtractorContext; -import org.jumpmind.symmetric.io.data.CsvUtils; -import org.jumpmind.symmetric.model.Data; - -class StreamBshDataCommand extends AbstractStreamDataCommand { - - public void execute(Writer writer, Data data, String routerId, DataExtractorContext context) throws IOException { - CsvUtils.writeBsh(data.getRowData(), writer); - } - - public boolean isTriggerHistoryRequired() { - return false; - } - -} \ No newline at end of file diff --git a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/extract/csv/StreamConfigDataCommand.java b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/extract/csv/StreamConfigDataCommand.java deleted file mode 100644 index a5cbe1d7b4..0000000000 --- a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/extract/csv/StreamConfigDataCommand.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Licensed to JumpMind Inc under one or more contributor - * license agreements. See the NOTICE file distributed - * with this work for additional information regarding - * copyright ownership. JumpMind Inc licenses this file - * to you under the GNU Lesser General Public License (the - * "License"); you may not use this file except in compliance - * with the License. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see - * . - * - * 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.jumpmind.symmetric.extract.csv; - -import java.io.Writer; -import java.io.IOException; - -import org.jumpmind.symmetric.extract.DataExtractorContext; -import org.jumpmind.symmetric.model.Data; -import org.jumpmind.symmetric.model.Node; -import org.jumpmind.symmetric.service.IDataExtractorService; -import org.jumpmind.symmetric.service.INodeService; - -/** - * Stream node configuration data if the appropriate data event type is - * encountered. - * - * - */ -class StreamConfigDataCommand extends AbstractStreamDataCommand { - - private IDataExtractorService dataExtractorService; - - private INodeService nodeService; - - public void execute(Writer writer, Data data, String routerId, DataExtractorContext context) throws IOException { - Node node = nodeService.findNode(context.getBatch().getNodeId()); - dataExtractorService.extractConfiguration(node, writer, context); - writer.flush(); - } - - public void setDataExtractorService(IDataExtractorService dataExtractorService) { - this.dataExtractorService = dataExtractorService; - } - - public void setNodeService(INodeService nodeService) { - this.nodeService = nodeService; - } - - public boolean isTriggerHistoryRequired() { - return false; - } - -} \ No newline at end of file diff --git a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/extract/csv/StreamCreateDataCommand.java b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/extract/csv/StreamCreateDataCommand.java deleted file mode 100644 index 3a8734584f..0000000000 --- a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/extract/csv/StreamCreateDataCommand.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Licensed to JumpMind Inc under one or more contributor - * license agreements. See the NOTICE file distributed - * with this work for additional information regarding - * copyright ownership. JumpMind Inc licenses this file - * to you under the GNU Lesser General Public License (the - * "License"); you may not use this file except in compliance - * with the License. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see - * . - * - * 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.jumpmind.symmetric.extract.csv; - -import java.io.IOException; -import java.io.Writer; - -import org.jumpmind.symmetric.extract.DataExtractorContext; -import org.jumpmind.symmetric.io.data.CsvConstants; -import org.jumpmind.symmetric.io.data.CsvUtils; -import org.jumpmind.symmetric.model.Data; - -public class StreamCreateDataCommand extends AbstractStreamDataCommand { - - public void execute(Writer writer, Data data, String routerId, DataExtractorContext context) throws IOException { - context.incrementByteCount(CsvUtils.write(writer, CsvConstants.CREATE, DELIMITER, data.getRowData())); - CsvUtils.writeLineFeed(writer); - context.incrementDataEventCount(); - } - - public boolean isTriggerHistoryRequired() { - return false; - } -} \ No newline at end of file diff --git a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/extract/csv/StreamDeleteDataCommand.java b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/extract/csv/StreamDeleteDataCommand.java deleted file mode 100644 index 9172b298aa..0000000000 --- a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/extract/csv/StreamDeleteDataCommand.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Licensed to JumpMind Inc under one or more contributor - * license agreements. See the NOTICE file distributed - * with this work for additional information regarding - * copyright ownership. JumpMind Inc licenses this file - * to you under the GNU Lesser General Public License (the - * "License"); you may not use this file except in compliance - * with the License. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see - * . - * - * 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.jumpmind.symmetric.extract.csv; - -import java.io.IOException; -import java.io.Writer; - -import org.apache.commons.lang.StringUtils; -import org.jumpmind.symmetric.extract.DataExtractorContext; -import org.jumpmind.symmetric.io.data.CsvConstants; -import org.jumpmind.symmetric.io.data.CsvUtils; -import org.jumpmind.symmetric.model.Data; - -/** - * Command to stream an {@link CsvConstants#DELETE} DML action - */ -class StreamDeleteDataCommand extends AbstractStreamDataCommand { - - public void execute(Writer out, Data data, String routerId, DataExtractorContext context) - throws IOException { - String rowData = data.getPkData(); - if (!StringUtils.isBlank(rowData)) { - context.incrementByteCount(CsvUtils.write(out, CsvConstants.DELETE, DELIMITER, rowData)); - } else { - context.incrementByteCount(CsvUtils.write(out, CsvConstants.DELETE)); - } - CsvUtils.writeLineFeed(out); - context.incrementDataEventCount(); - } - - public boolean isTriggerHistoryRequired() { - return true; - } -} \ No newline at end of file diff --git a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/extract/csv/StreamInsertDataCommand.java b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/extract/csv/StreamInsertDataCommand.java deleted file mode 100644 index 279a1243f0..0000000000 --- a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/extract/csv/StreamInsertDataCommand.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Licensed to JumpMind Inc under one or more contributor - * license agreements. See the NOTICE file distributed - * with this work for additional information regarding - * copyright ownership. JumpMind Inc licenses this file - * to you under the GNU Lesser General Public License (the - * "License"); you may not use this file except in compliance - * with the License. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see - * . - * - * 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.jumpmind.symmetric.extract.csv; - -import java.io.IOException; -import java.io.Writer; - -import org.apache.commons.lang.StringUtils; -import org.jumpmind.symmetric.extract.DataExtractorContext; -import org.jumpmind.symmetric.io.data.CsvConstants; -import org.jumpmind.symmetric.io.data.CsvUtils; -import org.jumpmind.symmetric.model.Data; - -/** - * Command to stream an {@link CsvConstants#INSERT} DML action - */ -class StreamInsertDataCommand extends AbstractStreamDataCommand { - - public void execute(Writer writer, Data data, String routerId, DataExtractorContext context) throws IOException { - selectAndEnhanceWithLobsIfEnabled(data, context); - String rowData = data.getRowData(); - if (!StringUtils.isBlank(rowData)) { - context.incrementByteCount(CsvUtils.write(writer, CsvConstants.INSERT, DELIMITER, - rowData)); - CsvUtils.writeLineFeed(writer); - context.incrementDataEventCount(); - } else { - log.error("DataExtractorMissingRowData", data.getDataId()); - } - } - - public boolean isTriggerHistoryRequired() { - return true; - } -} \ No newline at end of file diff --git a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/extract/csv/StreamReloadDataCommand.java b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/extract/csv/StreamReloadDataCommand.java deleted file mode 100644 index 5db73cedd4..0000000000 --- a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/extract/csv/StreamReloadDataCommand.java +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Licensed to JumpMind Inc under one or more contributor - * license agreements. See the NOTICE file distributed - * with this work for additional information regarding - * copyright ownership. JumpMind Inc licenses this file - * to you under the GNU Lesser General Public License (the - * "License"); you may not use this file except in compliance - * with the License. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see - * . - * - * 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.jumpmind.symmetric.extract.csv; - -import java.io.IOException; -import java.io.Writer; - -import org.jumpmind.symmetric.extract.DataExtractorContext; -import org.jumpmind.symmetric.model.Data; -import org.jumpmind.symmetric.model.Node; -import org.jumpmind.symmetric.model.TriggerRouter; -import org.jumpmind.symmetric.service.IDataExtractorService; -import org.jumpmind.symmetric.service.INodeService; - -/** - * Extract an initial load according to a reload command event. - */ -class StreamReloadDataCommand extends AbstractStreamDataCommand { - - private IDataExtractorService dataExtractorService; - - private INodeService nodeService; - - public void execute(Writer out, Data data, String routerId, DataExtractorContext context) throws IOException { - String triggerId = data.getTriggerHistory().getTriggerId(); - TriggerRouter triggerRouter = triggerRouterService.findTriggerRouterById(triggerId, routerId); - if (triggerRouter != null) { - // The initial_load_select can be overridden - if (data.getRowData() != null) { - triggerRouter.setInitialLoadSelect(data.getRowData()); - } - Node node = nodeService.findNode(context.getBatch().getNodeId()); - dataExtractorService.extractInitialLoadWithinBatchFor(node, triggerRouter, out, context, data.getTriggerHistory()); - out.flush(); - } else { - log.error("TriggerRouterUnavailable", triggerId, routerId); - } - } - - public void setDataExtractorService(IDataExtractorService dataExtractorService) { - this.dataExtractorService = dataExtractorService; - } - - public void setNodeService(INodeService nodeService) { - this.nodeService = nodeService; - } - - public boolean isTriggerHistoryRequired() { - return true; - } - -} \ No newline at end of file diff --git a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/extract/csv/StreamSQLDataCommand.java b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/extract/csv/StreamSQLDataCommand.java deleted file mode 100644 index 3c9da7f9ee..0000000000 --- a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/extract/csv/StreamSQLDataCommand.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Licensed to JumpMind Inc under one or more contributor - * license agreements. See the NOTICE file distributed - * with this work for additional information regarding - * copyright ownership. JumpMind Inc licenses this file - * to you under the GNU Lesser General Public License (the - * "License"); you may not use this file except in compliance - * with the License. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see - * . - * - * 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.jumpmind.symmetric.extract.csv; - -import java.io.IOException; -import java.io.Writer; - -import org.jumpmind.symmetric.extract.DataExtractorContext; -import org.jumpmind.symmetric.io.data.CsvUtils; -import org.jumpmind.symmetric.model.Data; - -/** - * Write a SQL statement out to the CSV that will be executed during the data load - */ -class StreamSQLDataCommand extends AbstractStreamDataCommand { - - public void execute(Writer writer, Data data, String routerId, DataExtractorContext context) throws IOException { - CsvUtils.writeSql(data.getRowData(), writer); - } - - public boolean isTriggerHistoryRequired() { - return true; - } - -} \ No newline at end of file diff --git a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/extract/csv/StreamUpdateDataCommand.java b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/extract/csv/StreamUpdateDataCommand.java deleted file mode 100644 index e404b8f920..0000000000 --- a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/extract/csv/StreamUpdateDataCommand.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Licensed to JumpMind Inc under one or more contributor - * license agreements. See the NOTICE file distributed - * with this work for additional information regarding - * copyright ownership. JumpMind Inc licenses this file - * to you under the GNU Lesser General Public License (the - * "License"); you may not use this file except in compliance - * with the License. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see - * . - * - * 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.jumpmind.symmetric.extract.csv; - -import java.io.IOException; -import java.io.Writer; - -import org.apache.commons.lang.StringUtils; -import org.jumpmind.symmetric.extract.DataExtractorContext; -import org.jumpmind.symmetric.io.data.CsvConstants; -import org.jumpmind.symmetric.io.data.CsvUtils; -import org.jumpmind.symmetric.model.Data; - -/** - * Command to stream an {@link CsvConstants#UPDATE} DML action - */ -class StreamUpdateDataCommand extends AbstractStreamDataCommand { - - public void execute(Writer out, Data data, String routerId, DataExtractorContext context) - throws IOException { - selectAndEnhanceWithLobsIfEnabled(data, context); - String rowData = data.getRowData(); - if (!StringUtils.isBlank(rowData)) { - context.incrementByteCount(CsvUtils.write(out, CsvConstants.UPDATE, DELIMITER, rowData, - DELIMITER, data.getPkData())); - CsvUtils.writeLineFeed(out); - context.incrementDataEventCount(); - } else { - log.error("DataExtractorMissingRowData", data.getDataId()); - } - } - - public boolean isTriggerHistoryRequired() { - return true; - } -} \ No newline at end of file diff --git a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/io/DefaultOfflineClientListener.java b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/io/DefaultOfflineClientListener.java index 6179052b49..8f894fb906 100644 --- a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/io/DefaultOfflineClientListener.java +++ b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/io/DefaultOfflineClientListener.java @@ -21,12 +21,11 @@ package org.jumpmind.symmetric.io; import org.jumpmind.extension.IBuiltInExtensionPoint; -import org.jumpmind.symmetric.common.logging.ILog; -import org.jumpmind.symmetric.common.logging.LogFactory; -import org.jumpmind.symmetric.model.Node; -import org.jumpmind.symmetric.service.INodeService; -import org.jumpmind.symmetric.service.IParameterService; -import org.jumpmind.symmetric.service.impl.NodeService; +import org.jumpmind.log.Log; +import org.jumpmind.log.LogFactory; +import org.jumpmind.symmetric.model.Node; +import org.jumpmind.symmetric.service.INodeService; +import org.jumpmind.symmetric.service.IParameterService; /** * Default implementation of an {@link IOfflineClientListener}. When the listener detects @@ -34,47 +33,45 @@ */ public class DefaultOfflineClientListener implements IOfflineClientListener, IBuiltInExtensionPoint { - protected ILog log = LogFactory.getLog(getClass()); + protected Log log = LogFactory.getLog(getClass()); protected IParameterService parameterService; - protected INodeService nodeService; - - + protected INodeService nodeService; + + public DefaultOfflineClientListener(Log log, IParameterService parameterService, + INodeService nodeService) { + this.log = log; + this.parameterService = parameterService; + this.nodeService = nodeService; + } + public void busy(Node remoteNode) { - log.warn("TransportFailedConnectionBusy"); + log.warn("The server was too busy to accept the connection"); } public void notAuthenticated(Node remoteNode) { - log.warn("AuthenticationFailed"); + log.warn("Could not authenticate with node"); } public void unknownError(Node remoteNode, Exception ex) { } public void offline(Node remoteNode) { - log.warn("TransportFailedConnectionUnavailable", + log.warn("Could not connect to the transport: %s", (remoteNode.getSyncUrl() == null ? parameterService.getRegistrationUrl() : remoteNode .getSyncUrl())); } public void syncDisabled(Node remoteNode) { - log.warn("SyncDisabled"); + log.warn("Synchronization is disabled on the server node"); nodeService.deleteIdentity(); } public void registrationRequired(Node remoteNode) { - log.warn("RegistrationRequired"); + log.warn("Registration is required before this operation can complete"); } public boolean isAutoRegister() { return true; } - public void setNodeService(NodeService nodeService) { - this.nodeService = nodeService; - } - - public void setParameterService(IParameterService parameterService) { - this.parameterService = parameterService; - this.log = LogFactory.getLog(parameterService); - } } \ No newline at end of file diff --git a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/io/ThresholdFileWriter.java b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/io/ThresholdFileWriter.java deleted file mode 100644 index f8a2b7feba..0000000000 --- a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/io/ThresholdFileWriter.java +++ /dev/null @@ -1,136 +0,0 @@ -/* - * Licensed to JumpMind Inc under one or more contributor - * license agreements. See the NOTICE file distributed - * with this work for additional information regarding - * copyright ownership. JumpMind Inc licenses this file - * to you under the GNU Lesser General Public License (the - * "License"); you may not use this file except in compliance - * with the License. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see - * . - * - * 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.jumpmind.symmetric.io; - -import java.io.BufferedReader; -import java.io.BufferedWriter; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStreamReader; -import java.io.OutputStreamWriter; -import java.io.StringReader; -import java.io.Writer; - -import org.jumpmind.symmetric.util.AppUtils; - -/** - * Write to an internal buffer up until the threshold. When the threshold is - * reached, flush the buffer to the file and write to the file from that point - * forward. - */ -public class ThresholdFileWriter extends Writer { - - private File file; - - private String tempFileCategory; - - private BufferedWriter fileWriter; - - private StringBuilder buffer; - - private long threshhold; - - /** - * @param threshold The number of bytes at which to start writing to a file - * @param file The file to write to after the threshold has been reached - */ - public ThresholdFileWriter(long threshold, File file) { - this.file = file; - this.buffer = new StringBuilder(); - this.threshhold = threshold; - } - - /** - * @param threshold The number of bytes at which to start writing to a file - * @param tempFileCategory uses {@link AppUtils#createTempFile(String)} with this argument as the parameter - * @see AppUtils#createTempFile(String) - */ - public ThresholdFileWriter(long threshold, String tempFileCategory) { - this.tempFileCategory = tempFileCategory; - this.buffer = new StringBuilder(); - this.threshhold = threshold; - } - - public File getFile() { - return file; - } - - public void setFile(File file) { - this.file = file; - } - - @Override - public void close() throws IOException { - if (fileWriter != null) { - fileWriter.close(); - fileWriter = null; - } - } - - @Override - public void flush() throws IOException { - if (fileWriter != null) { - fileWriter.flush(); - } - } - - @Override - public void write(char[] cbuf, int off, int len) throws IOException { - if (fileWriter != null) { - fileWriter.write(cbuf, off, len); - } else if (len + buffer.length() > threshhold) { - if (file == null) { - file = AppUtils.createTempFile(tempFileCategory == null ? "threshold.file.writer" : tempFileCategory); - } - fileWriter = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file), "UTF-8")); - fileWriter.write(buffer.toString()); - fileWriter.write(cbuf, off, len); - fileWriter.flush(); - } else { - buffer.append(new String(cbuf), off, len); - } - } - - public BufferedReader getReader() throws IOException { - if (file != null && file.exists()) { - return new BufferedReader(new InputStreamReader(new FileInputStream(file), "UTF-8")); - } else { - return new BufferedReader(new StringReader(buffer.toString())); - } - } - - public void reset() { - this.file = null; - this.fileWriter = null; - buffer.setLength(0); - } - - public void delete() { - if (file != null && file.exists()) { - file.delete(); - } - file = null; - buffer.setLength(0); - } - -} \ No newline at end of file diff --git a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/job/AbstractJob.java b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/job/AbstractJob.java index 22ee15f800..beee12ee34 100644 --- a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/job/AbstractJob.java +++ b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/job/AbstractJob.java @@ -16,92 +16,82 @@ * "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.jumpmind.symmetric.job; - + * under the License. + */ +package org.jumpmind.symmetric.job; + import java.util.Date; import java.util.concurrent.ScheduledFuture; -import javax.sql.DataSource; - import org.apache.commons.lang.StringUtils; +import org.jumpmind.log.Log; +import org.jumpmind.log.LogFactory; import org.jumpmind.symmetric.ISymmetricEngine; -import org.jumpmind.symmetric.StandaloneSymmetricEngine; import org.jumpmind.symmetric.common.Constants; -import org.jumpmind.symmetric.common.ParameterConstants; -import org.jumpmind.symmetric.common.logging.ILog; -import org.jumpmind.symmetric.common.logging.LogFactory; -import org.jumpmind.symmetric.service.IParameterService; -import org.jumpmind.symmetric.service.IRegistrationService; -import org.jumpmind.symmetric.statistic.IStatisticManager; import org.jumpmind.symmetric.util.RandomTimeSlot; -import org.springframework.beans.factory.BeanNameAware; import org.springframework.jmx.export.annotation.ManagedAttribute; import org.springframework.jmx.export.annotation.ManagedMetric; import org.springframework.jmx.export.annotation.ManagedOperation; import org.springframework.jmx.export.annotation.ManagedResource; import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; import org.springframework.scheduling.support.CronTrigger; - -@ManagedResource(description = "The management interface for a job") -abstract public class AbstractJob implements Runnable, BeanNameAware, IJob { - - protected DataSource dataSource; - - protected ILog log = LogFactory.getLog(getClass()); - - protected IParameterService parameterService; - - private String jobName; - - private boolean requiresRegistration = true; - - private IRegistrationService registrationService; - - private boolean paused = false; - - private Date lastFinishTime; - - private boolean running = false; - - private long lastExecutionTimeInMs; - + +@ManagedResource(description = "The management interface for a job") +abstract public class AbstractJob implements Runnable, IJob { + + protected Log log = LogFactory.getLog(getClass()); + + private String jobName; + + private boolean requiresRegistration = true; + + private boolean paused = false; + + private Date lastFinishTime; + + private boolean running = false; + + private long lastExecutionTimeInMs; + private long totalExecutionTimeInMs; - - private long lastExecutionProcessCount = 0; - - private long numberOfRuns; - - private boolean started; - - private long timeBetweenRunsInMs = -1; - - private String cronExpression; - + + private long lastExecutionProcessCount = 0; + + private long numberOfRuns; + + private boolean started; + + private long timeBetweenRunsInMs = -1; + + private String cronExpression; + private boolean hasNotRegisteredMessageBeenLogged = false; - + private ThreadPoolTaskScheduler taskScheduler; - - private String autoStartParameterName; - + private ScheduledFuture scheduledJob; - - private RandomTimeSlot randomTimeSlot; - + + private RandomTimeSlot randomTimeSlot; + private boolean autoStartConfigured; - protected IStatisticManager statisticManager; + protected ISymmetricEngine engine; - protected void init() { - this.autoStartConfigured = parameterService.is(autoStartParameterName); - this.cronExpression = parameterService.getString(jobName + ".cron", null); - this.timeBetweenRunsInMs = parameterService.getInt(jobName + ".period.time.ms", -1); + protected AbstractJob(String jobName, boolean requiresRegistration, boolean autoStartRequired, ISymmetricEngine engine, ThreadPoolTaskScheduler taskScheduler) { + this.engine = engine; + this.taskScheduler = taskScheduler; + this.jobName = jobName; + this.requiresRegistration = requiresRegistration; + this.autoStartConfigured = autoStartRequired; + this.cronExpression = engine.getParameterService().getString(jobName + ".cron", null); + this.timeBetweenRunsInMs = engine.getParameterService().getInt(jobName + ".period.time.ms", -1); + this.randomTimeSlot = new RandomTimeSlot(engine.getParameterService()); } - + public boolean isAutoStartConfigured() { return autoStartConfigured; - } - + } + public void start() { if (this.scheduledJob == null) { log.info("JobStarting", jobName); @@ -122,7 +112,7 @@ public void start() { } } } - + public boolean stop() { boolean success = false; if (this.scheduledJob != null) { @@ -130,201 +120,163 @@ public boolean stop() { this.scheduledJob = null; if (success) { log.info("JobCancelled", jobName); - started = false; + started = false; } else { log.warn("JobFailedToCancel", jobName); } } return success; } - - public String getName() { - return jobName; - } - - @ManagedOperation(description = "Run this job is it isn't already running") - public boolean invoke() { - return invoke(true); - } - - public boolean invoke(boolean force) { - boolean ran = false; - try { - ISymmetricEngine engine = StandaloneSymmetricEngine.findEngineByName(parameterService - .getString(ParameterConstants.ENGINE_NAME)); - - if (engine == null) { - log.info("SymmetricEngineMissing", jobName); - } else if (engine.isStarted()) { - if (!paused || force) { - if (!running) { - running = true; - synchronized (this) { - ran = true; + + public String getName() { + return jobName; + } + + @ManagedOperation(description = "Run this job is it isn't already running") + public boolean invoke() { + return invoke(true); + } + + public boolean invoke(boolean force) { + boolean ran = false; + try { + if (engine == null) { + log.info("SymmetricEngineMissing", jobName); + } else if (engine.isStarted()) { + if (!paused || force) { + if (!running) { + running = true; + synchronized (this) { + ran = true; long startTime = System.currentTimeMillis(); - long processCount = 0; - try { - if (!requiresRegistration - || (requiresRegistration && registrationService - .isRegisteredWithServer())) { - hasNotRegisteredMessageBeenLogged = false; - processCount = doJob(); - } else { - if (!hasNotRegisteredMessageBeenLogged) { - log.warn("SymmetricEngineNotRegistered", getName()); - hasNotRegisteredMessageBeenLogged = true; - } - } - } finally { + long processCount = 0; + try { + if (!requiresRegistration + || (requiresRegistration && engine.getRegistrationService() + .isRegisteredWithServer())) { + hasNotRegisteredMessageBeenLogged = false; + processCount = doJob(); + } else { + if (!hasNotRegisteredMessageBeenLogged) { + log.warn("SymmetricEngineNotRegistered", getName()); + hasNotRegisteredMessageBeenLogged = true; + } + } + } finally { lastFinishTime = new Date(); lastExecutionProcessCount = processCount; - long endTime = System.currentTimeMillis(); - lastExecutionTimeInMs = endTime - startTime; + long endTime = System.currentTimeMillis(); + lastExecutionTimeInMs = endTime - startTime; totalExecutionTimeInMs += lastExecutionTimeInMs; - if (lastExecutionProcessCount > 0 || lastExecutionTimeInMs > Constants.LONG_OPERATION_THRESHOLD) { - statisticManager.addJobStats(jobName, startTime, endTime, lastExecutionProcessCount); - } - numberOfRuns++; - running = false; - } - } - } - } - } else { - log.info("SymmetricEngineNotStarted"); - } - } catch (final Throwable ex) { - log.error(ex); - } - - return ran; - } - - - /* - * This method is called from the job - */ - public void run() { - invoke(false); - } - - abstract long doJob() throws Exception; - - public void setBeanName(final String beanName) { - this.jobName = beanName; - } - - public void setDataSource(final DataSource dataSource) { - this.dataSource = dataSource; - } - - public void setParameterService(IParameterService parameterService) { - this.parameterService = parameterService; - this.log = LogFactory.getLog(parameterService); - } - - public void setRequiresRegistration(boolean requiresRegistration) { - this.requiresRegistration = requiresRegistration; - } - - public void setRegistrationService(IRegistrationService registrationService) { - this.registrationService = registrationService; - } - - @ManagedOperation(description = "Pause this job") - public void pause() { - setPaused(true); - } - - @ManagedOperation(description = "Resume the job") - public void unpause() { - setPaused(false); - } - - public void setPaused(boolean paused) { - this.paused = paused; - } - - @ManagedAttribute(description = "If true, this job has been paused") - public boolean isPaused() { - return paused; - } - - @ManagedAttribute(description = "If true, this job has been started") - public boolean isStarted() { - return started; - } - - @ManagedMetric(description = "The amount of time this job spent in execution during it's last run") - public long getLastExecutionTimeInMs() { - return lastExecutionTimeInMs; + if (lastExecutionProcessCount > 0 + || lastExecutionTimeInMs > Constants.LONG_OPERATION_THRESHOLD) { + engine.getStatisticManager().addJobStats(jobName, startTime, endTime, + lastExecutionProcessCount); + } + numberOfRuns++; + running = false; + } + } + } + } + } else { + log.info("SymmetricEngineNotStarted"); + } + } catch (final Throwable ex) { + log.error(ex); + } + + return ran; } - + + /* + * This method is called from the job + */ + public void run() { + invoke(false); + } + + abstract long doJob() throws Exception; + + @ManagedOperation(description = "Pause this job") + public void pause() { + setPaused(true); + } + + @ManagedOperation(description = "Resume the job") + public void unpause() { + setPaused(false); + } + + public void setPaused(boolean paused) { + this.paused = paused; + } + + @ManagedAttribute(description = "If true, this job has been paused") + public boolean isPaused() { + return paused; + } + + @ManagedAttribute(description = "If true, this job has been started") + public boolean isStarted() { + return started; + } + + @ManagedMetric(description = "The amount of time this job spent in execution during it's last run") + public long getLastExecutionTimeInMs() { + return lastExecutionTimeInMs; + } + @ManagedMetric(description = "The count of elements this job processed during it's last run") public long getLastExecutionProcessCount() { return lastExecutionProcessCount; - } - - @ManagedAttribute(description = "The last time this job completed execution") - public Date getLastFinishTime() { - return lastFinishTime; - } - - @ManagedAttribute(description = "If true, the job is already running") - public boolean isRunning() { - return running; - } - - @ManagedMetric(description = "The number of times this job has been run during the lifetime of the JVM") - public long getNumberOfRuns() { - return numberOfRuns; - } - - @ManagedMetric(description = "The total amount of time this job has spent in execution during the lifetime of the JVM") - public long getTotalExecutionTimeInMs() { - return totalExecutionTimeInMs; - } - - @ManagedMetric(description = "The total amount of time this job has spend in execution during the lifetime of the JVM") - public long getAverageExecutionTimeInMs() { - if (numberOfRuns > 0) { - return totalExecutionTimeInMs / numberOfRuns; - } else { - return 0; - } - } - - public void setCronExpression(String cronExpression) { - this.cronExpression = cronExpression; - } - - @ManagedAttribute(description = "If set, this is the cron expression that governs when the job will run") - public String getCronExpression() { - return cronExpression; - } - - public void setTimeBetweenRunsInMs(long timeBetweenRunsInMs) { - this.timeBetweenRunsInMs = timeBetweenRunsInMs; - } - - @ManagedAttribute(description = "If the cron expression isn't set. This is the amount of time that will pass before the periodic job runs again.") - public long getTimeBetweenRunsInMs() { - return timeBetweenRunsInMs; } - - public void setTaskScheduler(ThreadPoolTaskScheduler taskScheduler) { - this.taskScheduler = taskScheduler; + + @ManagedAttribute(description = "The last time this job completed execution") + public Date getLastFinishTime() { + return lastFinishTime; } - - public void setAutoStartParameterName(String autoStartParameterName) { - this.autoStartParameterName = autoStartParameterName; + + @ManagedAttribute(description = "If true, the job is already running") + public boolean isRunning() { + return running; } - - public void setRandomTimeSlot(RandomTimeSlot randomTimeSlot) { - this.randomTimeSlot = randomTimeSlot; + + @ManagedMetric(description = "The number of times this job has been run during the lifetime of the JVM") + public long getNumberOfRuns() { + return numberOfRuns; } - - public void setStatisticManager(IStatisticManager statisticManager) { - this.statisticManager = statisticManager; - } + + @ManagedMetric(description = "The total amount of time this job has spent in execution during the lifetime of the JVM") + public long getTotalExecutionTimeInMs() { + return totalExecutionTimeInMs; + } + + @ManagedMetric(description = "The total amount of time this job has spend in execution during the lifetime of the JVM") + public long getAverageExecutionTimeInMs() { + if (numberOfRuns > 0) { + return totalExecutionTimeInMs / numberOfRuns; + } else { + return 0; + } + } + + public void setCronExpression(String cronExpression) { + this.cronExpression = cronExpression; + } + + @ManagedAttribute(description = "If set, this is the cron expression that governs when the job will run") + public String getCronExpression() { + return cronExpression; + } + + public void setTimeBetweenRunsInMs(long timeBetweenRunsInMs) { + this.timeBetweenRunsInMs = timeBetweenRunsInMs; + } + + @ManagedAttribute(description = "If the cron expression isn't set. This is the amount of time that will pass before the periodic job runs again.") + public long getTimeBetweenRunsInMs() { + return timeBetweenRunsInMs; + } + } \ No newline at end of file diff --git a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/job/DataGapPurgeJob.java b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/job/DataGapPurgeJob.java index 00d061afe5..2a432ba244 100644 --- a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/job/DataGapPurgeJob.java +++ b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/job/DataGapPurgeJob.java @@ -16,39 +16,36 @@ * "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.jumpmind.symmetric.job; - + * under the License. + */ + +package org.jumpmind.symmetric.job; + +import org.jumpmind.symmetric.ISymmetricEngine; import org.jumpmind.symmetric.service.ClusterConstants; -import org.jumpmind.symmetric.service.IPurgeService; - +import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; + /* * Background job that is responsible for purging already synchronized data */ -public class DataGapPurgeJob extends AbstractJob { - - private IPurgeService purgeService; - - public DataGapPurgeJob() { - } - - @Override - public long doJob() throws Exception { - return purgeService.purgeDataGaps(); +public class DataGapPurgeJob extends AbstractJob { + + public DataGapPurgeJob(ISymmetricEngine engine, ThreadPoolTaskScheduler taskScheduler) { + super("job.purge.datagaps", true, engine.getParameterService().is("start.purge.job"), + engine, taskScheduler); + } + + @Override + public long doJob() throws Exception { + return engine.getPurgeService().purgeDataGaps(); } - + public String getClusterLockName() { return ClusterConstants.PURGE_DATA_GAPS; } - + public boolean isClusterable() { return true; - } - - public void setPurgeService(IPurgeService service) { - this.purgeService = service; - } - + } + } \ No newline at end of file diff --git a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/job/DefaultOfflineServerListener.java b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/job/DefaultOfflineServerListener.java index 3f0656e1f0..788ba3c760 100644 --- a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/job/DefaultOfflineServerListener.java +++ b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/job/DefaultOfflineServerListener.java @@ -21,9 +21,9 @@ package org.jumpmind.symmetric.job; -import org.jumpmind.extension.IBuiltInExtensionPoint; -import org.jumpmind.symmetric.common.logging.ILog; -import org.jumpmind.symmetric.common.logging.LogFactory; +import org.jumpmind.extension.IBuiltInExtensionPoint; +import org.jumpmind.log.Log; +import org.jumpmind.log.LogFactory; import org.jumpmind.symmetric.ext.IOfflineServerListener; import org.jumpmind.symmetric.model.Node; import org.jumpmind.symmetric.service.INodeService; @@ -36,12 +36,20 @@ public class DefaultOfflineServerListener implements IOfflineServerListener, IBuiltInExtensionPoint { - protected static final ILog log = LogFactory.getLog(DefaultOfflineServerListener.class); + protected Log log = LogFactory.getLog(DefaultOfflineServerListener.class); protected IStatisticManager statisticManager; protected INodeService nodeService; - protected IOutgoingBatchService outgoingBatchService; - + protected IOutgoingBatchService outgoingBatchService; + + public DefaultOfflineServerListener(Log log, IStatisticManager statisticManager, + INodeService nodeService, IOutgoingBatchService outgoingBatchService) { + this.log = log; + this.statisticManager = statisticManager; + this.nodeService = nodeService; + this.outgoingBatchService = outgoingBatchService; + } + /* * Handle a client node that was determined to be offline. * Syncing is disabled for the node, node security is deleted, and cleanup processing is done for @@ -58,18 +66,6 @@ public void clientNodeOffline(Node node) { public boolean isAutoRegister() { return true; - } - - public void setNodeService(INodeService nodeService) { - this.nodeService = nodeService; - } - - public void setOutgoingBatchService(IOutgoingBatchService outgoingBatchService) { - this.outgoingBatchService = outgoingBatchService; - } - - public void setStatisticManager(IStatisticManager statisticManager) { - this.statisticManager = statisticManager; } } \ No newline at end of file diff --git a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/job/HeartbeatJob.java b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/job/HeartbeatJob.java index 09fc02ee1b..dde78e0d9d 100644 --- a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/job/HeartbeatJob.java +++ b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/job/HeartbeatJob.java @@ -16,52 +16,45 @@ * "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.jumpmind.symmetric.job; - -import org.jumpmind.symmetric.service.ClusterConstants; -import org.jumpmind.symmetric.service.IClusterService; -import org.jumpmind.symmetric.service.IDataService; - + * under the License. + */ + +package org.jumpmind.symmetric.job; + +import org.jumpmind.symmetric.ISymmetricEngine; +import org.jumpmind.symmetric.service.ClusterConstants; +import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; + /* * Background job that is responsible for updating this node's heart beat time. */ -public class HeartbeatJob extends AbstractJob { - - private IDataService dataService; - - private IClusterService clusterService; - - @Override - public long doJob() throws Exception { - if (clusterService.lock(getClusterLockName())) { - try { - dataService.heartbeat(false); - return -1l; - } finally { - clusterService.unlock(getClusterLockName()); - } +public class HeartbeatJob extends AbstractJob { + + public HeartbeatJob(ISymmetricEngine engine, ThreadPoolTaskScheduler taskScheduler) { + super("job.heartbeat", false, engine.getParameterService().is("start.heartbeat.job"), + engine, taskScheduler); + } + + @Override + public long doJob() throws Exception { + if (engine.getClusterService().lock(getClusterLockName())) { + try { + engine.getDataService().heartbeat(false); + return -1l; + } finally { + engine.getClusterService().unlock(getClusterLockName()); + } } else { return -1l; - } + } } - + public String getClusterLockName() { return ClusterConstants.HEARTBEAT; } - + public boolean isClusterable() { return true; - } - - public void setDataService(IDataService dataService) { - this.dataService = dataService; - } - - public void setClusterService(IClusterService clusterService) { - this.clusterService = clusterService; - } - + } + } \ No newline at end of file diff --git a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/job/IncomingPurgeJob.java b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/job/IncomingPurgeJob.java index 7e6fd27b06..ced56e1e82 100644 --- a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/job/IncomingPurgeJob.java +++ b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/job/IncomingPurgeJob.java @@ -21,8 +21,10 @@ package org.jumpmind.symmetric.job; +import org.jumpmind.symmetric.ISymmetricEngine; import org.jumpmind.symmetric.service.ClusterConstants; import org.jumpmind.symmetric.service.IPurgeService; +import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; /* * Background job that is responsible for purging already synchronized data @@ -31,7 +33,9 @@ public class IncomingPurgeJob extends AbstractJob { private IPurgeService purgeService; - public IncomingPurgeJob() { + public IncomingPurgeJob(ISymmetricEngine engine, ThreadPoolTaskScheduler taskScheduler) { + super("job.purge.incoming", true, engine.getParameterService().is("start.purge.job"), + engine, taskScheduler); } @Override diff --git a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/job/JobManager.java b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/job/JobManager.java index 6563fc6fc1..71d2e84386 100644 --- a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/job/JobManager.java +++ b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/job/JobManager.java @@ -19,11 +19,12 @@ * under the License. */ package org.jumpmind.symmetric.job; +import java.util.ArrayList; import java.util.List; -import org.jumpmind.symmetric.common.logging.ILog; -import org.jumpmind.symmetric.common.logging.LogFactory; -import org.jumpmind.symmetric.service.IParameterService; +import org.jumpmind.log.Log; +import org.jumpmind.log.LogFactory; +import org.jumpmind.symmetric.ISymmetricEngine; import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; /* @@ -31,12 +32,33 @@ */ public class JobManager implements IJobManager { - ILog log = LogFactory.getLog(JobManager.class); + Log log = LogFactory.getLog(JobManager.class); private List jobs; private ThreadPoolTaskScheduler taskScheduler; + public JobManager(Log log, ISymmetricEngine engine) { + this.log = log; + + this.taskScheduler = new ThreadPoolTaskScheduler(); + this.taskScheduler.setThreadNamePrefix(String.format("%s-job-", engine.getParameterService().getEngineName())); + this.taskScheduler.setPoolSize(20); + + this.jobs = new ArrayList(); + this.jobs.add(new RouterJob(engine, taskScheduler)); + this.jobs.add(new PushJob(engine, taskScheduler)); + this.jobs.add(new PullJob(engine, taskScheduler)); + this.jobs.add(new OutgoingPurgeJob(engine, taskScheduler)); + this.jobs.add(new IncomingPurgeJob(engine, taskScheduler)); + this.jobs.add(new DataGapPurgeJob(engine, taskScheduler)); + this.jobs.add(new StatisticFlushJob(engine, taskScheduler)); + this.jobs.add(new SyncTriggersJob(engine, taskScheduler)); + this.jobs.add(new HeartbeatJob(engine, taskScheduler)); + this.jobs.add(new WatchdogJob(engine, taskScheduler)); + + } + public IJob getJob(String name) { for (IJob job : jobs) { if (job.getName().equals(name)) { @@ -55,7 +77,7 @@ public synchronized void startJobs() { if (job.isAutoStartConfigured()) { job.start(); } else { - log.info("JobNoAutoStart", job.getName()); + log.info("Job %s not configured for auto start", job.getName()); } } } @@ -73,19 +95,7 @@ public synchronized void destroy () { } } - public void setJobs(List jobs) { - this.jobs = jobs; - } - public List getJobs() { return jobs; } - - public void setTaskScheduler(ThreadPoolTaskScheduler taskScheduler) { - this.taskScheduler = taskScheduler; - } - - public void setParameterService(IParameterService parameterService) { - this.log = LogFactory.getLog(parameterService); - } } \ No newline at end of file diff --git a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/job/OutgoingPurgeJob.java b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/job/OutgoingPurgeJob.java index e24072688c..f0fb891f7c 100644 --- a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/job/OutgoingPurgeJob.java +++ b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/job/OutgoingPurgeJob.java @@ -21,22 +21,22 @@ package org.jumpmind.symmetric.job; +import org.jumpmind.symmetric.ISymmetricEngine; import org.jumpmind.symmetric.service.ClusterConstants; -import org.jumpmind.symmetric.service.IPurgeService; +import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; /* * Background job that is responsible for purging already synchronized data */ public class OutgoingPurgeJob extends AbstractJob { - private IPurgeService purgeService; - - public OutgoingPurgeJob() { + public OutgoingPurgeJob(ISymmetricEngine engine, ThreadPoolTaskScheduler taskScheduler) { + super("job.purge.outgoing", true, engine.getParameterService().is("start.purge.job"), + engine, taskScheduler); } - @Override public long doJob() throws Exception { - return purgeService.purgeOutgoing(); + return engine.getPurgeService().purgeOutgoing(); } public String getClusterLockName() { @@ -46,9 +46,5 @@ public String getClusterLockName() { public boolean isClusterable() { return true; } - - public void setPurgeService(IPurgeService service) { - this.purgeService = service; - } } \ No newline at end of file diff --git a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/job/PullJob.java b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/job/PullJob.java index dca66ac7ea..2834883b18 100644 --- a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/job/PullJob.java +++ b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/job/PullJob.java @@ -19,32 +19,33 @@ * under the License. */ package org.jumpmind.symmetric.job; +import org.jumpmind.symmetric.ISymmetricEngine; import org.jumpmind.symmetric.model.RemoteNodeStatuses; import org.jumpmind.symmetric.service.ClusterConstants; -import org.jumpmind.symmetric.service.INodeService; -import org.jumpmind.symmetric.service.IPullService; +import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; /* * Background job that pulls data from remote nodes and then loads it. */ public class PullJob extends AbstractJob { - - private IPullService pullService; + + public PullJob(ISymmetricEngine engine, ThreadPoolTaskScheduler taskScheduler) { + super("job.pull", false, engine.getParameterService().is("start.pull.job"), + engine, taskScheduler); + } - private INodeService nodeService; - @Override public long doJob() throws Exception { - RemoteNodeStatuses statuses = pullService.pullData(); + RemoteNodeStatuses statuses = engine.getPullService().pullData(); // Re-pull immediately if we are in the middle of an initial load // so that the initial load completes as quickly as possible. // only process - while (nodeService.isDataLoadStarted() && + while (engine.getNodeService().isDataLoadStarted() && !statuses.errorOccurred() && statuses.wasBatchProcessed()) { log.info("DataPullingInReloadMode"); - statuses = pullService.pullData(); + statuses = engine.getPullService().pullData(); } return statuses.getDataProcessedCount(); @@ -58,11 +59,4 @@ public boolean isClusterable() { return true; } - public void setPullService(IPullService service) { - this.pullService = service; - } - - public void setNodeService(INodeService nodeService) { - this.nodeService = nodeService; - } } \ No newline at end of file diff --git a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/job/PushHeartbeatListener.java b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/job/PushHeartbeatListener.java index 3d90f872db..0115d82c27 100644 --- a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/job/PushHeartbeatListener.java +++ b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/job/PushHeartbeatListener.java @@ -16,35 +16,40 @@ * "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. */ + * under the License. + */ package org.jumpmind.symmetric.job; -import java.util.List; import java.util.Set; -import org.jumpmind.extension.IBuiltInExtensionPoint; -import org.jumpmind.symmetric.common.Constants; +import org.jumpmind.symmetric.common.ParameterConstants; import org.jumpmind.symmetric.db.ISymmetricDialect; import org.jumpmind.symmetric.ext.IHeartbeatListener; import org.jumpmind.symmetric.model.Node; import org.jumpmind.symmetric.service.IDataService; import org.jumpmind.symmetric.service.INodeService; -import org.jumpmind.symmetric.service.IOutgoingBatchService; +import org.jumpmind.symmetric.service.IParameterService; -public class PushHeartbeatListener implements IHeartbeatListener, IBuiltInExtensionPoint { +public class PushHeartbeatListener implements IHeartbeatListener { - private boolean enabled; private IDataService dataService; private INodeService nodeService; - private IOutgoingBatchService outgoingBatchService; - private long timeBetweenHeartbeats; private ISymmetricDialect symmetricDialect; + private IParameterService parameterService; + + public PushHeartbeatListener(IParameterService parameterService, IDataService dataService, + INodeService nodeService, ISymmetricDialect symmetricDialect) { + this.parameterService = parameterService; + this.dataService = dataService; + this.nodeService = nodeService; + this.symmetricDialect = symmetricDialect; + } public void heartbeat(Node me, Set children) { - if (enabled) { + if (parameterService.is(ParameterConstants.HEARTBEAT_ENABLED)) { // don't send new heart beat events if we haven't sent // the last ones ... - if (!nodeService.isRegistrationServer() && !isUnsentDataPresentOnConfigChannel()) { + if (!nodeService.isRegistrationServer()) { if (!symmetricDialect.getPlatform().getPlatformInfo().isTriggersSupported()) { dataService.insertHeartbeatEvent(me, false); for (Node node : children) { @@ -54,48 +59,13 @@ public void heartbeat(Node me, Set children) { } } } - - protected boolean isUnsentDataPresentOnConfigChannel() { - boolean isUnsentDataOnChannel = false; - List nodes = nodeService.findNodesToPushTo(); - if (nodes != null) { - for (Node node : nodes) { - isUnsentDataOnChannel |= outgoingBatchService.isUnsentDataOnChannelForNode( - Constants.CHANNEL_CONFIG, node.getNodeId()); - } - } - return isUnsentDataOnChannel; - } - + public long getTimeBetweenHeartbeatsInSeconds() { - return this.timeBetweenHeartbeats; - } - - public void setTimeBetweenHeartbeats(long timeBetweenHeartbeats) { - this.timeBetweenHeartbeats = timeBetweenHeartbeats; + return parameterService.getLong(ParameterConstants.HEARTBEAT_SYNC_ON_PUSH_PERIOD_SEC, 600); } public boolean isAutoRegister() { - return enabled; + return true; } - public void setDataService(IDataService dataService) { - this.dataService = dataService; - } - - public void setNodeService(INodeService nodeService) { - this.nodeService = nodeService; - } - - public void setOutgoingBatchService(IOutgoingBatchService outgoingBatchService) { - this.outgoingBatchService = outgoingBatchService; - } - - public void setEnabled(boolean enabled) { - this.enabled = enabled; - } - - public void setSymmetricDialect(ISymmetricDialect symmetricDialect) { - this.symmetricDialect = symmetricDialect; - } } \ No newline at end of file diff --git a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/job/PushJob.java b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/job/PushJob.java index 200d02ea9d..8cccca9195 100644 --- a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/job/PushJob.java +++ b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/job/PushJob.java @@ -21,8 +21,10 @@ package org.jumpmind.symmetric.job; +import org.jumpmind.symmetric.ISymmetricEngine; import org.jumpmind.symmetric.service.ClusterConstants; import org.jumpmind.symmetric.service.IPushService; +import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; /* * Background job that is responsible for pushing data to linked nodes. @@ -31,7 +33,9 @@ public class PushJob extends AbstractJob { private IPushService pushService; - public PushJob() { + public PushJob(ISymmetricEngine engine, ThreadPoolTaskScheduler taskScheduler) { + super("job.push", true, engine.getParameterService().is("start.push.job"), + engine, taskScheduler); } public void setPushService(IPushService service) { diff --git a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/job/RouterJob.java b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/job/RouterJob.java index c56fe3c9c6..00d5270899 100644 --- a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/job/RouterJob.java +++ b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/job/RouterJob.java @@ -20,26 +20,24 @@ package org.jumpmind.symmetric.job; +import org.jumpmind.symmetric.ISymmetricEngine; import org.jumpmind.symmetric.service.ClusterConstants; -import org.jumpmind.symmetric.service.IRouterService; +import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; /* * This job calls {@link IRouterService#routeData()} - * - * */ public class RouterJob extends AbstractJob { - - IRouterService routingService; - @Override - long doJob() throws Exception { - return routingService.routeData(); + public RouterJob(ISymmetricEngine engine, ThreadPoolTaskScheduler taskScheduler) { + super("job.routing", true, engine.getParameterService().is("start.route.job"), + engine, taskScheduler); } - public void setRoutingService(IRouterService routingService) { - this.routingService = routingService; + @Override + long doJob() throws Exception { + return engine.getRouterService().routeData(); } public String getClusterLockName() { diff --git a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/job/StatisticFlushJob.java b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/job/StatisticFlushJob.java index 7352e65976..5b07812213 100644 --- a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/job/StatisticFlushJob.java +++ b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/job/StatisticFlushJob.java @@ -20,6 +20,9 @@ package org.jumpmind.symmetric.job; + +import org.jumpmind.symmetric.ISymmetricEngine; +import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; /* @@ -27,12 +30,14 @@ */ public class StatisticFlushJob extends AbstractJob { - public StatisticFlushJob() { + public StatisticFlushJob(ISymmetricEngine engine, ThreadPoolTaskScheduler taskScheduler) { + super("job.stat.flush", true, engine.getParameterService().is("start.stat.flush.job"), + engine, taskScheduler); } @Override public long doJob() throws Exception { - statisticManager.flush(); + engine.getStatisticManager().flush(); return -1l; } diff --git a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/job/SyncTriggersJob.java b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/job/SyncTriggersJob.java index 91ed1775ce..36785558a6 100644 --- a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/job/SyncTriggersJob.java +++ b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/job/SyncTriggersJob.java @@ -21,29 +21,26 @@ package org.jumpmind.symmetric.job; +import org.jumpmind.symmetric.ISymmetricEngine; import org.jumpmind.symmetric.service.ClusterConstants; -import org.jumpmind.symmetric.service.ITriggerRouterService; +import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; /* * Background job that checks to see if triggers need to be regenerated. */ public class SyncTriggersJob extends AbstractJob { - private ITriggerRouterService triggerRouterService; - - public SyncTriggersJob() { + public SyncTriggersJob(ISymmetricEngine engine, ThreadPoolTaskScheduler taskScheduler) { + super("job.synctriggers", true, engine.getParameterService().is("start.synctriggers.job"), + engine, taskScheduler); } @Override public long doJob() throws Exception { - triggerRouterService.syncTriggers(); + engine.getTriggerRouterService().syncTriggers(); return -1l; } - public void setTriggerRouterService(ITriggerRouterService triggerService) { - this.triggerRouterService = triggerService; - } - public String getClusterLockName() { return ClusterConstants.SYNCTRIGGERS; } diff --git a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/job/WatchdogJob.java b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/job/WatchdogJob.java index fd716ebc7a..5b817a5b26 100644 --- a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/job/WatchdogJob.java +++ b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/job/WatchdogJob.java @@ -21,42 +21,35 @@ package org.jumpmind.symmetric.job; +import org.jumpmind.symmetric.ISymmetricEngine; import org.jumpmind.symmetric.service.ClusterConstants; -import org.jumpmind.symmetric.service.IClusterService; -import org.jumpmind.symmetric.service.INodeService; +import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; /* * Background job that is responsible for checking on node health. It will * disable nodes that have been offline for a configurable period of time. */ public class WatchdogJob extends AbstractJob { - - private INodeService nodeService; - - private IClusterService clusterService; + + public WatchdogJob(ISymmetricEngine engine, ThreadPoolTaskScheduler taskScheduler) { + super("job.watchdog", false, engine.getParameterService().is("start.watchdog.job"), + engine, taskScheduler); + } @Override public long doJob() throws Exception { - if (clusterService.lock(ClusterConstants.WATCHDOG)) { + if (engine.getClusterService().lock(ClusterConstants.WATCHDOG)) { synchronized (this) { try { - nodeService.checkForOfflineNodes(); + engine.getNodeService().checkForOfflineNodes(); } finally { - clusterService.unlock(ClusterConstants.WATCHDOG); + engine.getClusterService().unlock(ClusterConstants.WATCHDOG); } } } return -1l; } - public void setNodeService(INodeService nodeService) { - this.nodeService = nodeService; - } - - public void setClusterService(IClusterService clusterService) { - this.clusterService = clusterService; - } - public String getClusterLockName() { return ClusterConstants.WATCHDOG; } diff --git a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/load/ConfigurationChangedFilter.java b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/load/ConfigurationChangedFilter.java index c8d7a92762..fcff6d0afe 100644 --- a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/load/ConfigurationChangedFilter.java +++ b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/load/ConfigurationChangedFilter.java @@ -16,16 +16,17 @@ * "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. */ + * under the License. + */ package org.jumpmind.symmetric.load; import org.jumpmind.db.model.Table; import org.jumpmind.extension.IBuiltInExtensionPoint; +import org.jumpmind.log.Log; +import org.jumpmind.log.LogFactory; import org.jumpmind.symmetric.common.ParameterConstants; import org.jumpmind.symmetric.common.TableConstants; -import org.jumpmind.symmetric.common.logging.ILog; -import org.jumpmind.symmetric.common.logging.LogFactory; import org.jumpmind.symmetric.io.data.CsvData; import org.jumpmind.symmetric.io.data.DataContext; import org.jumpmind.symmetric.io.data.IDataReader; @@ -41,30 +42,37 @@ * has changed. If it has, it will take the correct action to apply the * configuration change to the current node. */ -public class ConfigurationChangedFilter extends DatabaseWriterFilterAdapter - implements IBuiltInExtensionPoint { +public class ConfigurationChangedFilter extends DatabaseWriterFilterAdapter implements + IBuiltInExtensionPoint { + + static final Log log = LogFactory.getLog(ConfigurationChangedFilter.class); - static final ILog log = LogFactory.getLog(ConfigurationChangedFilter.class); + final String CTX_KEY_RESYNC_NEEDED = "Resync." + + ConfigurationChangedFilter.class.getSimpleName() + hashCode(); - final String CTX_KEY_RESYNC_NEEDED = "Resync." + ConfigurationChangedFilter.class.getSimpleName() + hashCode(); + final String CTX_KEY_FLUSH_CHANNELS_NEEDED = "FlushChannels." + + ConfigurationChangedFilter.class.getSimpleName() + hashCode(); - final String CTX_KEY_FLUSH_CHANNELS_NEEDED = "FlushChannels." + ConfigurationChangedFilter.class.getSimpleName() - + hashCode(); - - final String CTX_KEY_FLUSH_TRANSFORMS_NEEDED = "FlushTransforms." + ConfigurationChangedFilter.class.getSimpleName() - + hashCode(); + final String CTX_KEY_FLUSH_TRANSFORMS_NEEDED = "FlushTransforms." + + ConfigurationChangedFilter.class.getSimpleName() + hashCode(); private IParameterService parameterService; private IConfigurationService configurationService; - + private ITriggerRouterService triggerRouterService; - + private ITransformService transformService; - private String tablePrefix; - - + public ConfigurationChangedFilter(IParameterService parameterService, + IConfigurationService configurationService, ITriggerRouterService triggerRouterService, + ITransformService transformService) { + this.parameterService = parameterService; + this.configurationService = configurationService; + this.triggerRouterService = triggerRouterService; + this.transformService = transformService; + } + @Override public void afterWrite( DataContext context, Table table, CsvData data) { @@ -73,56 +81,61 @@ public void afterWrite( recordTransformFlushNeeded(context, table); } - private void recordSyncNeeded(DataContext context, Table table) { + private void recordSyncNeeded( + DataContext context, Table table) { if (isSyncTriggersNeeded(table)) { context.put(CTX_KEY_RESYNC_NEEDED, true); } } - private void recordChannelFlushNeeded(DataContext context, Table table) { + private void recordChannelFlushNeeded( + DataContext context, Table table) { if (isChannelFlushNeeded(table)) { context.put(CTX_KEY_FLUSH_CHANNELS_NEEDED, true); } } - - private void recordTransformFlushNeeded(DataContext context, Table table) { + + private void recordTransformFlushNeeded( + DataContext context, Table table) { if (isTransformFlushNeeded(table)) { context.put(CTX_KEY_FLUSH_TRANSFORMS_NEEDED, true); } } private boolean isSyncTriggersNeeded(Table table) { - return matchesTable(table, TableConstants.SYM_TRIGGER) - || matchesTable(table, TableConstants.SYM_ROUTER) - || matchesTable(table, TableConstants.SYM_TRIGGER_ROUTER) - || matchesTable(table, TableConstants.SYM_NODE_GROUP_LINK); + return matchesTable(table, TableConstants.SYM_TRIGGER) + || matchesTable(table, TableConstants.SYM_ROUTER) + || matchesTable(table, TableConstants.SYM_TRIGGER_ROUTER) + || matchesTable(table, TableConstants.SYM_NODE_GROUP_LINK); } private boolean isChannelFlushNeeded(Table table) { return matchesTable(table, TableConstants.SYM_CHANNEL); } - + private boolean isTransformFlushNeeded(Table table) { - return matchesTable(table, TableConstants.SYM_TRANSFORM_COLUMN) || - matchesTable(table, TableConstants.SYM_TRANSFORM_TABLE); + return matchesTable(table, TableConstants.SYM_TRANSFORM_COLUMN) + || matchesTable(table, TableConstants.SYM_TRANSFORM_TABLE); } private boolean matchesTable(Table table, String tableSuffix) { if (table != null && table.getName() != null) { - return table.getName().equalsIgnoreCase(TableConstants.getTableName(tablePrefix, tableSuffix)); + return table.getName().equalsIgnoreCase( + TableConstants.getTableName(parameterService.getTablePrefix(), tableSuffix)); } else { return false; } } - + @Override - public void batchCommitted(DataContext context) { + public void batchCommitted( + DataContext context) { if (context.get(CTX_KEY_FLUSH_CHANNELS_NEEDED) != null) { log.info("ChannelFlushed"); configurationService.reloadChannels(); } if (context.get(CTX_KEY_RESYNC_NEEDED) != null - && parameterService.is(ParameterConstants.AUTO_SYNC_CONFIGURATION) + && parameterService.is(ParameterConstants.AUTO_SYNC_CONFIGURATION) && parameterService.is(ParameterConstants.AUTO_SYNC_TRIGGERS)) { log.info("ConfigurationChanged"); triggerRouterService.syncTriggers(); @@ -134,24 +147,4 @@ public void batchCommitted(DataCo } } - public void setParameterService(IParameterService parameterService) { - this.parameterService = parameterService; - } - - public void setTablePrefix(String tablePrefix) { - this.tablePrefix = tablePrefix; - } - - public void setTriggerRouterService(ITriggerRouterService triggerService) { - this.triggerRouterService = triggerService; - } - - public void setConfigurationService(IConfigurationService configurationService) { - this.configurationService = configurationService; - } - - public void setTransformService(ITransformService transformService) { - this.transformService = transformService; - } - } \ No newline at end of file diff --git a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/model/AbstractCsvData.java b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/model/AbstractCsvData.java deleted file mode 100644 index 00708f6903..0000000000 --- a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/model/AbstractCsvData.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Licensed to JumpMind Inc under one or more contributor - * license agreements. See the NOTICE file distributed - * with this work for additional information regarding - * copyright ownership. JumpMind Inc licenses this file - * to you under the GNU Lesser General Public License (the - * "License"); you may not use this file except in compliance - * with the License. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see - * . - * - * 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.jumpmind.symmetric.model; - -import java.io.IOException; -import java.io.StringReader; -import java.util.HashMap; -import java.util.Map; - -import org.apache.commons.lang.StringUtils; -import org.jumpmind.symmetric.csv.CsvReader; -import org.jumpmind.symmetric.io.data.CsvUtils; - - -/** - * - */ -abstract class AbstractCsvData { - - private Map parsedCsvData = null; - - // TODO This could probably become more efficient - protected String[] getData(String key, String data) { - if (!StringUtils.isBlank(data)) { - try { - if (parsedCsvData == null) { - parsedCsvData = new HashMap(2); - } - if (parsedCsvData.containsKey(key)) { - return parsedCsvData.get(key); - } else { - CsvReader csvReader = CsvUtils.getCsvReader(new StringReader(data)); - if (csvReader.readRecord()) { - String[] values = csvReader.getValues(); - parsedCsvData.put(key, values); - return values; - } else { - throw new IllegalStateException(String.format("Could not parse the data passed in: %s", data)); - } - } - } catch (IOException e) { - throw new RuntimeException(e); - } - } else { - return null; - } - } - -} \ No newline at end of file diff --git a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/model/Data.java b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/model/Data.java index b95303927a..d7d4491e01 100644 --- a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/model/Data.java +++ b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/model/Data.java @@ -16,217 +16,169 @@ * "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.jumpmind.symmetric.model; - + * under the License. + */ +package org.jumpmind.symmetric.model; + import java.io.Serializable; -import java.util.Date; +import java.util.Date; +import org.jumpmind.symmetric.io.data.CsvData; import org.jumpmind.symmetric.io.data.DataEventType; - -/** + +/** * This is the data that changed due to a data sync trigger firing. - */ -public class Data extends AbstractCsvData implements Serializable { - + */ +public class Data extends CsvData implements Serializable { + private static final long serialVersionUID = 1L; - /** - * Primary key - */ - private long dataId; - - private String tableName; - - private DataEventType eventType; - - /** - * Comma delimited row data. - */ - private String rowData; - - /** - * Comma delimited primary key data. - */ - private String pkData; - - /** - * To support column-level sync and conflict resolution. Comma delimited old - * row data from an update. - */ - - private String oldData; - - /** - * This is a reference to the triggerHistory row the trigger referred to - * when the data event fired. - */ - private TriggerHistory triggerHistory; - - private String channelId; - - private String transactionId; - - private String sourceNodeId; - - private String externalData; - - /** - * This is populated by the trigger when the event happens. It will be - * useful for research. - */ - private Date createTime; - - public Data(long dataId, String pkData, String rowData, - DataEventType eventType, String tableName, Date createTime, - TriggerHistory triggerHistory, String channelId, - String transactionId, String sourceNodeId) { - super(); - this.dataId = dataId; - this.pkData = pkData; - this.rowData = rowData; - this.eventType = eventType; - this.tableName = tableName; - this.createTime = createTime; - this.triggerHistory = triggerHistory; - this.channelId = channelId; - this.transactionId = transactionId; - this.sourceNodeId = sourceNodeId; - } - - public Data(String tableName, DataEventType eventType, String rowData, - String pkData, TriggerHistory triggerHistory, String channelId, - String transactionId, String sourceNodeId) { - this.tableName = tableName; - this.eventType = eventType; - this.rowData = rowData; - this.pkData = pkData; - this.triggerHistory = triggerHistory; - this.channelId = channelId; - this.transactionId = transactionId; - this.sourceNodeId = sourceNodeId; - } - - public Data() { - } - - public String[] toParsedRowData() { - return getData("rowData", rowData); - } - - public String[] toParsedOldData() { - return getData("oldData", oldData); - } - - public String[] toParsedPkData() { - return getData("pkData", pkData); - } - - public long getDataId() { - return dataId; - } - - public void setDataId(long dataId) { - this.dataId = dataId; - } - - public String getTableName() { - return tableName; - } - - public void setTableName(String tableName) { - this.tableName = tableName; - } - - public DataEventType getEventType() { - return eventType; - } - - public void setEventType(DataEventType eventType) { - this.eventType = eventType; - } - - public String getRowData() { - return rowData; - } - - public void setRowData(String rowData) { - this.rowData = rowData; - } - - public String getPkData() { - return pkData; - } - - public void setPkData(String pkData) { - this.pkData = pkData; - } - - public String getOldData() { - return oldData; - } - - public void setOldData(String oldData) { - this.oldData = oldData; - } - - public TriggerHistory getTriggerHistory() { - return triggerHistory; - } - - public void setTriggerHistory(TriggerHistory triggerHistory) { - this.triggerHistory = triggerHistory; - } - - public String getChannelId() { - return channelId; - } - - public void setChannelId(String channelId) { - this.channelId = channelId; - } - - public String getTransactionId() { - return transactionId; - } - - public void setTransactionId(String transactionId) { - this.transactionId = transactionId; - } - - public String getSourceNodeId() { - return sourceNodeId; - } - - public void setSourceNodeId(String sourceNodeId) { - this.sourceNodeId = sourceNodeId; - } - - public String getExternalData() { - return externalData; - } - - public void setExternalData(String externalData) { - this.externalData = externalData; - } - - public Date getCreateTime() { - return createTime; - } - - public void setCreateTime(Date createTime) { - this.createTime = createTime; + /** + * This is a reference to the triggerHistory row the trigger referred to + * when the data event fired. + */ + private TriggerHistory triggerHistory; + + public Data(long dataId, String pkData, String rowData, DataEventType eventType, + String tableName, Date createTime, TriggerHistory triggerHistory, String channelId, + String transactionId, String sourceNodeId) { + super(); + this.setDataId(dataId); + this.setPkData(pkData); + this.setRowData(rowData); + this.setDataEventType(eventType); + this.setTableName(tableName); + this.setCreateTime(createTime); + this.setChannelId(channelId); + this.setTransactionId(transactionId); + this.setSourceNodeId(sourceNodeId); + this.triggerHistory = triggerHistory; + } + + public Data(String tableName, DataEventType eventType, String rowData, String pkData, + TriggerHistory triggerHistory, String channelId, String transactionId, + String sourceNodeId) { + this(-1, pkData, rowData, eventType, tableName, new Date(), triggerHistory, channelId, + transactionId, sourceNodeId); + } + + public Data() { + } + + public String[] toParsedRowData() { + return getParsedData(ROW_DATA); + } + + public String[] toParsedOldData() { + return getParsedData(OLD_DATA); + } + + public String[] toParsedPkData() { + return getParsedData(PK_DATA); + } + + public long getDataId() { + Long dataId = getAttribute(ATTRIBUTE_DATA_ID); + if (dataId != null) { + return dataId; + } else { + return -1l; + } + } + + public void setDataId(long dataId) { + putAttribute(ATTRIBUTE_DATA_ID, dataId); + } + + public String getTableName() { + return getAttribute(ATTRIBUTE_TABLE_NAME); + } + + public void setTableName(String tableName) { + putAttribute(ATTRIBUTE_TABLE_NAME, tableName); } + public String getRowData() { + return getCsvData(ROW_DATA); + } + + public void setRowData(String rowData) { + putCsvData(ROW_DATA, rowData); + } + + public String getPkData() { + return getCsvData(PK_DATA); + } + + public void setPkData(String pkData) { + putCsvData(PK_DATA, pkData); + } + + public String getOldData() { + return getCsvData(OLD_DATA); + } + + public void setOldData(String oldData) { + putCsvData(OLD_DATA, oldData); + } + + public TriggerHistory getTriggerHistory() { + return triggerHistory; + } + + public void setTriggerHistory(TriggerHistory triggerHistory) { + this.triggerHistory = triggerHistory; + } + + public String getChannelId() { + return getAttribute(ATTRIBUTE_CHANNEL_ID); + } + + public void setChannelId(String channelId) { + putAttribute(ATTRIBUTE_CHANNEL_ID, channelId); + } + + public String getTransactionId() { + return getAttribute(ATTRIBUTE_TX_ID); + } + + public void setTransactionId(String transactionId) { + putAttribute(ATTRIBUTE_TX_ID, transactionId); + } + + public String getSourceNodeId() { + return getAttribute(ATTRIBUTE_SOURCE_NODE_ID); + } + + public void setSourceNodeId(String sourceNodeId) { + putAttribute(ATTRIBUTE_SOURCE_NODE_ID, sourceNodeId); + } + + public String getExternalData() { + return getAttribute(ATTRIBUTE_SOURCE_NODE_ID); + } + + public void setExternalData(String externalData) { + putAttribute(ATTRIBUTE_EXTERNAL_DATA, externalData); + } + + public Date getCreateTime() { + return getAttribute(ATTRIBUTE_CREATE_TIME); + } + + public void setCreateTime(Date createTime) { + putAttribute(ATTRIBUTE_CREATE_TIME, createTime); + } + public String getPkDataFor(String columnName) { String[] pkData = toParsedPkData(); String[] keyNames = triggerHistory.getParsedPkColumnNames(); for (int i = 0; i < keyNames.length; i++) { if (columnName.equals(keyNames[i])) { return pkData[i]; - } + } } return null; - } - + } + } \ No newline at end of file diff --git a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/model/DataRef.java b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/model/DataRef.java deleted file mode 100644 index 2f4c3d02e5..0000000000 --- a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/model/DataRef.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Licensed to JumpMind Inc under one or more contributor - * license agreements. See the NOTICE file distributed - * with this work for additional information regarding - * copyright ownership. JumpMind Inc licenses this file - * to you under the GNU Lesser General Public License (the - * "License"); you may not use this file except in compliance - * with the License. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see - * . - * - * 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.jumpmind.symmetric.model; - -import java.io.Serializable; -import java.util.Date; - -/** - * - */ -public class DataRef implements Serializable { - - private static final long serialVersionUID = 1L; - - private long refDataId; - private Date refTime; - - public DataRef(long refDataid, Date refTime) { - super(); - this.refDataId = refDataid; - this.refTime = refTime; - } - - public void setRefDataId(long refDataid) { - this.refDataId = refDataid; - } - - public long getRefDataId() { - return refDataId; - } - - public void setRefTime(Date refTime) { - this.refTime = refTime; - } - - public Date getRefTime() { - return refTime; - } - -} \ No newline at end of file diff --git a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/model/TriggerHistory.java b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/model/TriggerHistory.java index a3abe85d59..ebb507dda7 100644 --- a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/model/TriggerHistory.java +++ b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/model/TriggerHistory.java @@ -37,7 +37,7 @@ * (as may be the case when distributing events to remote locations), then we * still have the history of what the columns and primary keys were at the time. */ -public class TriggerHistory extends AbstractCsvData implements Serializable { +public class TriggerHistory implements Serializable { private static final long serialVersionUID = 1L; @@ -54,8 +54,12 @@ public class TriggerHistory extends AbstractCsvData implements Serializable { private Date createTime; private String columnNames; + + private String[] parsedColumnNames; private String pkColumnNames; + + private String[] parsedPkColumnNames; private String nameForInsertTrigger; @@ -169,11 +173,17 @@ public String getTriggerNameForDmlType(DataEventType type) { } public String[] getParsedColumnNames() { - return getData("columnNames", columnNames); + if (parsedColumnNames == null && columnNames != null) { + parsedColumnNames = columnNames.split(","); + } + return parsedColumnNames; } public String[] getParsedPkColumnNames() { - return getData("pkColumnNames", pkColumnNames); + if (parsedPkColumnNames == null && pkColumnNames != null) { + parsedPkColumnNames = pkColumnNames.split(","); + } + return parsedPkColumnNames; } public int getTableHash() { diff --git a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/route/AbstractDataRouter.java b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/route/AbstractDataRouter.java index 9023271539..2c62449980 100644 --- a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/route/AbstractDataRouter.java +++ b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/route/AbstractDataRouter.java @@ -58,7 +58,7 @@ public void contextCommitted(SimpleRouterContext context) { protected Map getDataMap(DataMetaData dataMetaData) { Map data = null; - DataEventType dml = dataMetaData.getData().getEventType(); + DataEventType dml = dataMetaData.getData().getDataEventType(); switch (dml) { case UPDATE: data = new HashMap(dataMetaData.getTable().getColumnCount() * 2); @@ -126,7 +126,7 @@ protected Map getPkDataAsString(DataMetaData dataMetaData) { protected Map getDataObjectMap(DataMetaData dataMetaData, ISymmetricDialect symmetricDialect) { Map data = null; - DataEventType dml = dataMetaData.getData().getEventType(); + DataEventType dml = dataMetaData.getData().getDataEventType(); switch (dml) { case UPDATE: data = new HashMap(dataMetaData.getTable().getColumnCount() * 2); diff --git a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/route/AbstractDataToRouteReader.java b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/route/AbstractDataToRouteReader.java deleted file mode 100644 index 783c64f6bb..0000000000 --- a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/route/AbstractDataToRouteReader.java +++ /dev/null @@ -1,281 +0,0 @@ -/* - * Licensed to JumpMind Inc under one or more contributor - * license agreements. See the NOTICE file distributed - * with this work for additional information regarding - * copyright ownership. JumpMind Inc licenses this file - * to you under the GNU Lesser General Public License (the - * "License"); you may not use this file except in compliance - * with the License. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see - * . - * - * 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.jumpmind.symmetric.route; - -import java.sql.Connection; -import java.sql.PreparedStatement; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; -import java.util.concurrent.BlockingQueue; -import java.util.concurrent.LinkedBlockingQueue; -import java.util.concurrent.TimeUnit; - -import org.apache.commons.lang.NotImplementedException; -import org.apache.commons.lang.StringUtils; -import org.jumpmind.symmetric.SymmetricException; -import org.jumpmind.symmetric.common.Constants; -import org.jumpmind.symmetric.common.logging.ILog; -import org.jumpmind.symmetric.db.ISymmetricDialect; -import org.jumpmind.symmetric.model.Channel; -import org.jumpmind.symmetric.model.Data; -import org.jumpmind.symmetric.service.IDataService; -import org.jumpmind.symmetric.service.ISqlProvider; -import org.jumpmind.symmetric.util.AppUtils; -import org.springframework.dao.DataAccessException; -import org.springframework.jdbc.core.ConnectionCallback; -import org.springframework.jdbc.core.JdbcTemplate; -import org.springframework.jdbc.support.JdbcUtils; - -/** - * This class is responsible for reading data for the purpose of routing. It - * reads ahead and tries to keep a blocking queue populated for the main job thread - * to process. - */ -abstract public class AbstractDataToRouteReader implements IDataToRouteReader { - - protected ILog log; - - protected BlockingQueue dataQueue; - - protected ISqlProvider sqlProvider; - - protected JdbcTemplate jdbcTemplate; - - protected ChannelRouterContext context; - - protected IDataService dataService; - - protected boolean reading = true; - - protected ISymmetricDialect symmetricDialect; - - public AbstractDataToRouteReader(ILog log, ISqlProvider sqlProvider, - ChannelRouterContext context, IDataService dataService) { - this.log = log; - this.jdbcTemplate = dataService != null ? dataService.getJdbcTemplate() : null; - this.symmetricDialect = dataService != null ? dataService.getSymmetricDialect() : null; - this.dataQueue = new LinkedBlockingQueue( - symmetricDialect != null ? symmetricDialect.getRouterDataPeekAheadCount() : 1000); - this.sqlProvider = sqlProvider; - this.context = context; - this.dataService = dataService; - } - - public Data take() { - Data data = null; - try { - int queryTimeout = jdbcTemplate.getQueryTimeout(); - data = dataQueue.poll(queryTimeout < 3600 ? 3600 : queryTimeout, TimeUnit.SECONDS); - } catch (InterruptedException e) { - log.warn(e); - } - - if (data == null) { - throw new SymmetricException("RouterDataReaderNotResponding"); - } else if (data instanceof EOD) { - data = null; - } - return data; - } - - /** - * Start out by selecting only the rows that need routed. - */ - protected PreparedStatement prepareStatment(Connection c) throws SQLException { - throw new NotImplementedException(); - } - - protected String getSql(String sqlName, Channel channel) { - String select = sqlProvider.getSql(sqlName); - if (!channel.isUseOldDataToRoute()) { - select = select.replace("d.old_data", "''"); - } - if (!channel.isUseRowDataToRoute()) { - select = select.replace("d.row_data", "''"); - } - if (!channel.isUsePkDataToRoute()) { - select = select.replace("d.pk_data", "''"); - } - return symmetricDialect == null ? select : symmetricDialect.massageDataExtractionSql(select, channel); - } - - public void run() { - try { - execute(); - } catch (Throwable ex) { - log.error(ex); - } - } - - protected void execute() { - jdbcTemplate.execute(new ConnectionCallback() { - public Integer doInConnection(Connection c) throws SQLException, DataAccessException { - int dataCount = 0; - PreparedStatement ps = null; - ResultSet rs = null; - boolean autoCommit = c.getAutoCommit(); - try { - if (symmetricDialect.requiresAutoCommitFalseToSetFetchSize()) { - c.setAutoCommit(false); - } - - long maxDataToRoute = context.getChannel().getMaxDataToRoute(); - int peekAheadCount = symmetricDialect.getRouterDataPeekAheadCount(); - String lastTransactionId = null; - List peekAheadQueue = new ArrayList(peekAheadCount); - boolean nontransactional = context.getChannel().getBatchAlgorithm().equals("nontransactional"); - - ps = prepareStatment(c); - rs = executeQuery(ps); - - boolean moreData = true; - while (dataCount <= maxDataToRoute || lastTransactionId != null) { - if (moreData) { - moreData = fillPeekAheadQueue(peekAheadQueue, peekAheadCount, rs); - } - - if ((lastTransactionId == null || nontransactional) && peekAheadQueue.size() > 0) { - Data data = peekAheadQueue.remove(0); - copyToQueue(data); - dataCount++; - lastTransactionId = data.getTransactionId(); - } else if (lastTransactionId != null && peekAheadQueue.size() > 0) { - Iterator datas = peekAheadQueue.iterator(); - int dataWithSameTransactionIdCount = 0; - while (datas.hasNext()) { - Data data = datas.next(); - if (lastTransactionId.equals(data.getTransactionId())) { - dataWithSameTransactionIdCount++; - datas.remove(); - copyToQueue(data); - dataCount++; - } - } - - if (dataWithSameTransactionIdCount == 0) { - lastTransactionId = null; - } - - } else if (peekAheadQueue.size() == 0) { - // we've reached the end of the result set - break; - } - } - - return dataCount; - - } finally { - JdbcUtils.closeResultSet(rs); - JdbcUtils.closeStatement(ps); - rs = null; - ps = null; - - if (symmetricDialect.requiresAutoCommitFalseToSetFetchSize()) { - c.commit(); - c.setAutoCommit(autoCommit); - } - - copyToQueue(new EOD()); - reading = false; - - } - } - }); - } - - protected boolean fillPeekAheadQueue(List peekAheadQueue, int peekAheadCount, ResultSet rs) - throws SQLException { - boolean moreData = true; - int toRead = peekAheadCount - peekAheadQueue.size(); - int dataCount = 0; - long ts = System.currentTimeMillis(); - while (reading && dataCount < toRead) { - if (rs.next()) { - if (process(rs)) { - Data data = dataService.readData(rs); - context.setLastDataIdForTransactionId(data); - peekAheadQueue.add(data); - dataCount++; - context.incrementStat(System.currentTimeMillis() - ts, - ChannelRouterContext.STAT_READ_DATA_MS); - } else { - context.incrementStat(System.currentTimeMillis() - ts, - ChannelRouterContext.STAT_REREAD_DATA_MS); - } - - ts = System.currentTimeMillis(); - } else { - moreData = false; - break; - } - - } - return moreData; - } - - protected ResultSet executeQuery(PreparedStatement ps) throws SQLException { - long ts = System.currentTimeMillis(); - ResultSet rs = ps.executeQuery(); - long executeTimeInMs = System.currentTimeMillis() - ts; - context.incrementStat(executeTimeInMs, ChannelRouterContext.STAT_QUERY_TIME_MS); - if (executeTimeInMs > Constants.LONG_OPERATION_THRESHOLD) { - log.warn("RoutedDataSelectedInTime", executeTimeInMs, context.getChannel() - .getChannelId()); - } else if (log.isDebugEnabled()) { - log.debug("RoutedDataSelectedInTime", executeTimeInMs, context.getChannel() - .getChannelId()); - } - return rs; - } - - protected void copyToQueue(Data data) { - long ts = System.currentTimeMillis(); - while (!dataQueue.offer(data) && reading) { - AppUtils.sleep(50); - } - context.incrementStat(System.currentTimeMillis() - ts, - ChannelRouterContext.STAT_ENQUEUE_DATA_MS); - } - - public boolean isReading() { - return reading; - } - - public void setReading(boolean reading) { - this.reading = reading; - } - - public BlockingQueue getDataQueue() { - return dataQueue; - } - - protected boolean process(ResultSet rs) throws SQLException { - return StringUtils.isBlank(rs.getString(13)); - } - - class EOD extends Data { - private static final long serialVersionUID = 1L; - } - -} \ No newline at end of file diff --git a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/route/BshDataRouter.java b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/route/BshDataRouter.java index a62c52be1d..788e782026 100644 --- a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/route/BshDataRouter.java +++ b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/route/BshDataRouter.java @@ -46,6 +46,10 @@ public class BshDataRouter extends AbstractDataRouter { protected ISymmetricDialect symmetricDialect; final String INTERPRETER_KEY = String.format("%d.BshInterpreter", hashCode()); + + public BshDataRouter(ISymmetricDialect symmetricDialect) { + this.symmetricDialect = symmetricDialect; + } public Set routeToNodes(SimpleRouterContext context, DataMetaData dataMetaData, Set nodes, boolean initialLoad) { @@ -110,8 +114,4 @@ protected void bind(Interpreter interpreter, DataMetaData dataMetaData, Set batchesByNodes = new HashMap(); private Map> availableNodes = new HashMap>(); private Set usedDataRouters = new HashSet(); - private Connection connection; + private ISqlTransaction sqlTransaction; private boolean needsCommitted = false; private long createdTimeInMs = System.currentTimeMillis(); private long lastDataIdProcessed; private Map transactionIdDataIds = new HashMap(); private List dataEventsToSend = new ArrayList(); - private boolean oldAutoCommitSetting = false; - public ChannelRouterContext(String nodeId, NodeChannel channel, DataSource dataSource) + public ChannelRouterContext(String nodeId, NodeChannel channel, ISqlTransaction transaction) throws SQLException { - this.connection = dataSource.getConnection(); - this.oldAutoCommitSetting = this.connection.getAutoCommit(); - this.connection.setAutoCommit(false); - this.init(new JdbcTemplate(new SingleConnectionDataSource(connection, true)), channel, - nodeId); + super(nodeId, channel); + this.sqlTransaction = transaction; + this.sqlTransaction.setInBatchMode(true); } public List getDataEventList() { return dataEventsToSend; } - + public void clearDataEventsList() { dataEventsToSend.clear(); } - + public void addDataEvent(long dataId, long batchId, String routerId) { dataEventsToSend.add(new DataEvent(dataId, batchId, routerId)); } - + public Map getBatchesByNodes() { return batchesByNodes; } @@ -98,14 +92,14 @@ public Map> getAvailableNodes() { return availableNodes; } - public void commit() throws SQLException { + public void commit() { try { - connection.commit(); + sqlTransaction.commit(); } finally { - clearState(); + clearState(); } } - + protected void clearState() { this.usedDataRouters.clear(); this.encountedTransactionBoundary = false; @@ -116,9 +110,9 @@ protected void clearState() { public void rollback() { try { - connection.rollback(); - } catch (SQLException e) { - LogFactory.getLog(getClass()).warn(e); + sqlTransaction.rollback(); + } catch (SqlException e) { + log.warn(e); } finally { clearState(); } @@ -126,12 +120,12 @@ public void rollback() { public void cleanup() { try { - this.connection.commit(); - this.connection.setAutoCommit(oldAutoCommitSetting); + this.sqlTransaction.commit(); } catch (Exception ex) { log.warn(ex); + } finally { + this.sqlTransaction.close(); } - JdbcUtils.closeConnection(this.connection); } public void setNeedsCommitted(boolean b) { @@ -172,8 +166,13 @@ public void recordTransactionBoundaryEncountered(Data data) { public void setLastDataIdProcessed(long lastDataIdProcessed) { this.lastDataIdProcessed = lastDataIdProcessed; } - + public long getLastDataIdProcessed() { return lastDataIdProcessed; } + + public ISqlTransaction getSqlTransaction() { + return sqlTransaction; + } + } \ No newline at end of file diff --git a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/route/ColumnMatchDataRouter.java b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/route/ColumnMatchDataRouter.java index cfe4d44912..40bed8fdd2 100644 --- a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/route/ColumnMatchDataRouter.java +++ b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/route/ColumnMatchDataRouter.java @@ -20,17 +20,17 @@ package org.jumpmind.symmetric.route; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import org.apache.commons.lang.StringUtils; -import org.jumpmind.symmetric.common.TokenConstants; -import org.jumpmind.symmetric.model.DataMetaData; -import org.jumpmind.symmetric.model.Node; -import org.jumpmind.symmetric.model.Router; -import org.jumpmind.symmetric.service.IRegistrationService; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.apache.commons.lang.StringUtils; +import org.jumpmind.symmetric.common.TokenConstants; +import org.jumpmind.symmetric.model.DataMetaData; +import org.jumpmind.symmetric.model.Node; +import org.jumpmind.symmetric.model.Router; +import org.jumpmind.symmetric.service.IConfigurationService; /** * This data router is invoked when the router_type='column'. The @@ -74,11 +74,18 @@ public class ColumnMatchDataRouter extends AbstractDataRouter implements IDataRo private static final String NULL_VALUE = "NULL"; - private IRegistrationService registrationService; + private IConfigurationService configurationService; final static String EXPRESSION_KEY = String.format("%s.Expression.", ColumnMatchDataRouter.class - .getName()); + .getName()); + + public ColumnMatchDataRouter() { + } + public ColumnMatchDataRouter(IConfigurationService configurationService) { + this.configurationService = configurationService; + } + public Set routeToNodes(SimpleRouterContext routingContext, DataMetaData dataMetaData, Set nodes, boolean initialLoad) { Set nodeIds = null; @@ -196,16 +203,12 @@ protected Map getRedirectMap(SimpleRouterContext ctx) { Map redirectMap = (Map) ctx.getContextCache().get( CTX_CACHE_KEY); if (redirectMap == null) { - redirectMap = registrationService.getRegistrationRedirectMap(); + redirectMap = configurationService.getRegistrationRedirectMap(); ctx.getContextCache().put(CTX_CACHE_KEY, redirectMap); } return redirectMap; } - public void setRegistrationService(IRegistrationService registrationService) { - this.registrationService = registrationService; - } - class Expression { boolean equals; String[] tokens; diff --git a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/route/ConfigurationChangedDataRouter.java b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/route/ConfigurationChangedDataRouter.java index 61eb642e3f..d44231a572 100644 --- a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/route/ConfigurationChangedDataRouter.java +++ b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/route/ConfigurationChangedDataRouter.java @@ -28,7 +28,6 @@ import org.apache.commons.lang.StringUtils; import org.jumpmind.symmetric.common.ParameterConstants; import org.jumpmind.symmetric.common.TableConstants; -import org.jumpmind.symmetric.common.logging.LogFactory; import org.jumpmind.symmetric.io.data.DataEventType; import org.jumpmind.symmetric.model.DataMetaData; import org.jumpmind.symmetric.model.NetworkedNode; @@ -53,8 +52,6 @@ public class ConfigurationChangedDataRouter extends AbstractDataRouter implement public final static String KEY = "symconfig"; - protected String tablePrefix; - protected IConfigurationService configurationService; protected INodeService nodeService; @@ -64,6 +61,22 @@ public class ConfigurationChangedDataRouter extends AbstractDataRouter implement protected IParameterService parameterService; protected ITransformService transformService; + + protected String tablePrefix; + + public ConfigurationChangedDataRouter() { + } + + public ConfigurationChangedDataRouter(IConfigurationService configurationService, + INodeService nodeService, ITriggerRouterService triggerRouterService, + IParameterService parameterService, ITransformService transformService) { + this.configurationService = configurationService; + this.nodeService = nodeService; + this.triggerRouterService = triggerRouterService; + this.parameterService = parameterService; + this.tablePrefix = parameterService.getTablePrefix(); + this.transformService = transformService; + } public Set routeToNodes(SimpleRouterContext routingContext, DataMetaData dataMetaData, Set possibleTargetNodes, boolean initialLoad) { @@ -138,7 +151,7 @@ public Set routeToNodes(SimpleRouterContext routingContext, * so, then don't propagate the change. */ protected boolean didNodeSecurityChangeForNodeInitialization(DataMetaData dataMetaData) { - if (tableMatches(dataMetaData, TableConstants.SYM_NODE_SECURITY) && dataMetaData.getData().getEventType() == DataEventType.UPDATE) { + if (tableMatches(dataMetaData, TableConstants.SYM_NODE_SECURITY) && dataMetaData.getData().getDataEventType() == DataEventType.UPDATE) { Map oldData = getOldDataAsString("", dataMetaData); Map newData = getNewDataAsString("", dataMetaData); if (newData.get("REGISTRATION_ENABLED") != null && @@ -238,46 +251,21 @@ private boolean isLinked(String nodeIdInQuestion, Node nodeThatCouldBeRoutedTo, @Override public void contextCommitted(SimpleRouterContext routingContext) { if (routingContext.getContextCache().get(CTX_KEY_FLUSH_CHANNELS_NEEDED) != null) { - log.info("ChannelFlushed"); + log.info("Channels flushed because new channels came through the dataloader"); configurationService.reloadChannels(); } if (routingContext.getContextCache().get(CTX_KEY_RESYNC_NEEDED) != null && parameterService.is(ParameterConstants.AUTO_SYNC_TRIGGERS)) { - log.info("ConfigurationChanged"); + log.info("About to syncTriggers because new configuration came through the dataloader"); triggerRouterService.syncTriggers(); } if (routingContext.getContextCache().get(CTX_KEY_FLUSH_TRANSFORMS_NEEDED) != null && parameterService.is(ParameterConstants.AUTO_SYNC_CONFIGURATION)) { - log.info("ConfigurationChanged"); + log.info("About to refresh the cache of transformation because new configuration come through the dataloader"); transformService.resetCache(); } } - public void setTablePrefix(String tablePrefix) { - this.tablePrefix = tablePrefix; - } - - public void setConfigurationService(IConfigurationService configurationService) { - this.configurationService = configurationService; - } - - public void setNodeService(INodeService nodeService) { - this.nodeService = nodeService; - } - - public void setTriggerRouterService(ITriggerRouterService triggerRouterService) { - this.triggerRouterService = triggerRouterService; - } - - public void setParameterService(IParameterService parameterService) { - this.parameterService = parameterService; - log = LogFactory.getLog(parameterService); - } - - public void setTransformService(ITransformService transformService) { - this.transformService = transformService; - } - private boolean tableMatches(DataMetaData dataMetaData, String tableName) { boolean matches = false; if (dataMetaData.getTable().getName() @@ -286,5 +274,9 @@ private boolean tableMatches(DataMetaData dataMetaData, String tableName) { } return matches; } + + public void setTablePrefix(String tablePrefix) { + this.tablePrefix = tablePrefix; + } } diff --git a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/route/DataGapDetector.java b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/route/DataGapDetector.java index b6aa62f4d2..48cf645c80 100644 --- a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/route/DataGapDetector.java +++ b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/route/DataGapDetector.java @@ -21,23 +21,19 @@ package org.jumpmind.symmetric.route; -import java.sql.ResultSet; -import java.sql.SQLException; import java.util.ArrayList; import java.util.Date; import java.util.List; +import org.jumpmind.db.sql.ISqlMap; +import org.jumpmind.db.sql.ISqlTemplate; +import org.jumpmind.db.sql.mapper.NumberMapper; +import org.jumpmind.log.Log; import org.jumpmind.symmetric.common.ParameterConstants; -import org.jumpmind.symmetric.common.logging.ILog; -import org.jumpmind.symmetric.common.logging.LogFactory; import org.jumpmind.symmetric.db.ISymmetricDialect; import org.jumpmind.symmetric.model.DataGap; import org.jumpmind.symmetric.service.IDataService; import org.jumpmind.symmetric.service.IParameterService; -import org.jumpmind.symmetric.service.ISqlProvider; -import org.springframework.dao.DataAccessException; -import org.springframework.jdbc.core.JdbcTemplate; -import org.springframework.jdbc.core.ResultSetExtractor; /** * Responsible for managing gaps in data ids to ensure that all captured data is @@ -45,28 +41,26 @@ */ public class DataGapDetector implements IDataToRouteGapDetector { - final ILog log = LogFactory.getLog(getClass()); + private Log log; private IDataService dataService; private IParameterService parameterService; - private JdbcTemplate jdbcTemplate; - private ISymmetricDialect symmetricDialect; - private ISqlProvider sqlProvider; + private ISqlMap sqlMap; public DataGapDetector() { } - public DataGapDetector(IDataService dataService, IParameterService parameterService, - JdbcTemplate jdbcTemplate, ISymmetricDialect symmetricDialect, ISqlProvider sqlProvider) { + public DataGapDetector(Log log, IDataService dataService, IParameterService parameterService, + ISymmetricDialect symmetricDialect, ISqlMap sqlMap) { + this.log = log; this.dataService = dataService; this.parameterService = parameterService; - this.jdbcTemplate = jdbcTemplate; + this.sqlMap = sqlMap; this.symmetricDialect = symmetricDialect; - this.sqlProvider = sqlProvider; } public void afterRouting() { @@ -86,75 +80,65 @@ public void beforeRouting() { .getInt(ParameterConstants.ROUTING_LARGEST_GAP_SIZE); for (final DataGap dataGap : gaps) { final boolean lastGap = dataGap.equals(gaps.get(gaps.size() - 1)); - String sql = sqlProvider.getSql("selectDistinctDataIdFromDataEventUsingGapsSql"); + String sql = sqlMap.getSql("selectDistinctDataIdFromDataEventUsingGapsSql"); + ISqlTemplate sqlTemplate = symmetricDialect.getPlatform().getSqlTemplate(); Object[] params = new Object[] { dataGap.getStartId(), dataGap.getEndId() }; - lastDataId = jdbcTemplate.query(sql, params, new ResultSetExtractor() { - public Long extractData(ResultSet rs) throws SQLException, DataAccessException { - long lastDataId = -1; - while (rs.next()) { - long dataId = rs.getLong(1); - if (lastDataId == -1 && dataGap.getStartId() < dataId) { - // there was a new gap at the start - dataService.insertDataGap(new DataGap(dataGap.getStartId(), dataId - 1)); - } else if (lastDataId != -1 && lastDataId + dataIdIncrementBy != dataId - && lastDataId != dataId) { - // found a gap somewhere in the existing gap - dataService.insertDataGap(new DataGap(lastDataId + 1, dataId - 1)); - } - lastDataId = dataId; - } + lastDataId = -1; + List ids = sqlTemplate.query(sql, new NumberMapper(), params); + for (Number number : ids) { + long dataId = number.longValue(); + if (lastDataId == -1 && dataGap.getStartId() < dataId) { + // there was a new gap at the start + dataService.insertDataGap(new DataGap(dataGap.getStartId(), dataId - 1)); + } else if (lastDataId != -1 && lastDataId + dataIdIncrementBy != dataId + && lastDataId != dataId) { + // found a gap somewhere in the existing gap + dataService.insertDataGap(new DataGap(lastDataId + 1, dataId - 1)); + } + lastDataId = dataId; + } - // if we found data in the gap - if (lastDataId != -1) { - if (!lastGap && lastDataId < dataGap.getEndId()) { - dataService.insertDataGap(new DataGap(lastDataId + 1, dataGap - .getEndId())); - } - dataService.updateDataGap(dataGap, DataGap.Status.OK); - - // if we did not find data in the gap and it was not the - // last gap - } else if (!lastGap) { - if (dataService.countDataInRange(dataGap.getStartId() - 1, - dataGap.getEndId() + 1) == 0) { - if (symmetricDialect.supportsTransactionViews()) { - long transactionViewClockSyncThresholdInMs = parameterService - .getLong( - ParameterConstants.DBDIALECT_ORACLE_TRANSACTION_VIEW_CLOCK_SYNC_THRESHOLD_MS, - 60000); - Date createTime = dataService.findCreateTimeOfData(dataGap - .getEndId() + 1); - if (createTime != null - && !symmetricDialect - .areDatabaseTransactionsPendingSince(createTime - .getTime() - + transactionViewClockSyncThresholdInMs)) { - if (dataService.countDataInRange(dataGap.getStartId() - 1, - dataGap.getEndId() + 1) == 0) { - log.info("RouterSkippingDataIdsNoTransactions", - dataGap.getStartId(), dataGap.getEndId()); - dataService.updateDataGap(dataGap, DataGap.Status.SK); - } - } - } else if (isDataGapExpired(dataGap.getEndId() + 1)) { - log.info("RouterSkippingDataIdsGapExpired", dataGap.getStartId(), - dataGap.getEndId()); + // if we found data in the gap + if (lastDataId != -1) { + if (!lastGap && lastDataId < dataGap.getEndId()) { + dataService.insertDataGap(new DataGap(lastDataId + 1, dataGap.getEndId())); + } + dataService.updateDataGap(dataGap, DataGap.Status.OK); + + // if we did not find data in the gap and it was not the + // last gap + } else if (!lastGap) { + if (dataService.countDataInRange(dataGap.getStartId() - 1, dataGap.getEndId() + 1) == 0) { + if (symmetricDialect.supportsTransactionViews()) { + long transactionViewClockSyncThresholdInMs = parameterService + .getLong( + ParameterConstants.DBDIALECT_ORACLE_TRANSACTION_VIEW_CLOCK_SYNC_THRESHOLD_MS, + 60000); + Date createTime = dataService.findCreateTimeOfData(dataGap.getEndId() + 1); + if (createTime != null + && !symmetricDialect.areDatabaseTransactionsPendingSince(createTime + .getTime() + transactionViewClockSyncThresholdInMs)) { + if (dataService.countDataInRange(dataGap.getStartId() - 1, + dataGap.getEndId() + 1) == 0) { + log.info("RouterSkippingDataIdsNoTransactions", + dataGap.getStartId(), dataGap.getEndId()); dataService.updateDataGap(dataGap, DataGap.Status.SK); } - } else { - dataService.checkForAndUpdateMissingChannelIds( - dataGap.getStartId() - 1, dataGap.getEndId() + 1); } + } else if (isDataGapExpired(dataGap.getEndId() + 1)) { + log.info("RouterSkippingDataIdsGapExpired", dataGap.getStartId(), + dataGap.getEndId()); + dataService.updateDataGap(dataGap, DataGap.Status.SK); } - - return lastDataId; + } else { + dataService.checkForAndUpdateMissingChannelIds(dataGap.getStartId() - 1, + dataGap.getEndId() + 1); } - - }); + } } if (lastDataId != -1) { - dataService.insertDataGap(new DataGap(lastDataId + 1, lastDataId + maxDataToSelect)); + dataService.insertDataGap(new DataGap(lastDataId + 1, lastDataId + maxDataToSelect)); } long updateTimeInMs = System.currentTimeMillis() - ts; diff --git a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/route/DataGapRouteReader.java b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/route/DataGapRouteReader.java index 26f3a79b07..06f81eb66e 100644 --- a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/route/DataGapRouteReader.java +++ b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/route/DataGapRouteReader.java @@ -20,17 +20,35 @@ */ package org.jumpmind.symmetric.route; -import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; +import java.util.ArrayList; +import java.util.Iterator; import java.util.List; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.TimeUnit; +import org.hsqldb.types.Types; +import org.jumpmind.db.sql.ISqlMap; +import org.jumpmind.db.sql.ISqlReadCursor; +import org.jumpmind.db.sql.ISqlRowMapper; +import org.jumpmind.db.sql.ISqlTemplate; +import org.jumpmind.db.sql.Row; +import org.jumpmind.log.Log; +import org.jumpmind.symmetric.SymmetricException; +import org.jumpmind.symmetric.common.Constants; import org.jumpmind.symmetric.common.ParameterConstants; -import org.jumpmind.symmetric.common.logging.ILog; +import org.jumpmind.symmetric.db.ISymmetricDialect; +import org.jumpmind.symmetric.io.data.CsvData; +import org.jumpmind.symmetric.io.data.DataEventType; +import org.jumpmind.symmetric.model.Channel; +import org.jumpmind.symmetric.model.Data; import org.jumpmind.symmetric.model.DataGap; import org.jumpmind.symmetric.service.IDataService; -import org.jumpmind.symmetric.service.ISqlProvider; +import org.jumpmind.symmetric.service.IParameterService; +import org.jumpmind.symmetric.util.AppUtils; import org.jumpmind.util.FormatUtils; /** @@ -38,55 +56,212 @@ * reads ahead and tries to keep a blocking queue populated for another thread * to process. */ -public class DataGapRouteReader extends AbstractDataToRouteReader { +public class DataGapRouteReader implements IDataToRouteReader { private static final String SELECT_DATA_USING_GAPS_SQL = "selectDataUsingGapsSql"; - + protected List dataGaps; - + protected DataGap currentGap; - public DataGapRouteReader(ILog log, ISqlProvider sqlProvider, ChannelRouterContext context, - IDataService dataService) { - super(log, sqlProvider, context, dataService); + protected Log log; + + protected BlockingQueue dataQueue; + + protected ChannelRouterContext context; + + protected IDataService dataService; + + protected IParameterService parameterService; + + protected ISymmetricDialect symmetricDialect; + + protected ISqlMap sqlMap; + + protected boolean reading = true; + + public DataGapRouteReader(Log log, ISqlMap sqlMap, ChannelRouterContext context, + IDataService dataService, ISymmetricDialect symmetricDialect, + IParameterService parameterService) { + this.log = log; + this.sqlMap = sqlMap; + this.symmetricDialect = symmetricDialect; + this.dataQueue = new LinkedBlockingQueue( + symmetricDialect != null ? symmetricDialect.getRouterDataPeekAheadCount() : 1000); + this.context = context; + this.dataService = dataService; + this.parameterService = parameterService; + } + + public void run() { + try { + execute(); + } catch (Throwable ex) { + log.error(ex); + } + } + + protected void execute() { + + ISqlReadCursor cursor = null; + try { + int dataCount = 0; + + long maxDataToRoute = context.getChannel().getMaxDataToRoute(); + int peekAheadCount = symmetricDialect.getRouterDataPeekAheadCount(); + String lastTransactionId = null; + List peekAheadQueue = new ArrayList(peekAheadCount); + boolean nontransactional = context.getChannel().getBatchAlgorithm() + .equals("nontransactional"); + + cursor = prepareCursor(); + + boolean moreData = true; + while (dataCount <= maxDataToRoute || lastTransactionId != null) { + if (moreData) { + moreData = fillPeekAheadQueue(peekAheadQueue, peekAheadCount, cursor); + } + + if ((lastTransactionId == null || nontransactional) && peekAheadQueue.size() > 0) { + Data data = peekAheadQueue.remove(0); + copyToQueue(data); + dataCount++; + lastTransactionId = data.getTransactionId(); + } else if (lastTransactionId != null && peekAheadQueue.size() > 0) { + Iterator datas = peekAheadQueue.iterator(); + int dataWithSameTransactionIdCount = 0; + while (datas.hasNext()) { + Data data = datas.next(); + if (lastTransactionId.equals(data.getTransactionId())) { + dataWithSameTransactionIdCount++; + datas.remove(); + copyToQueue(data); + dataCount++; + } + } + + if (dataWithSameTransactionIdCount == 0) { + lastTransactionId = null; + } + + } else if (peekAheadQueue.size() == 0) { + // we've reached the end of the result set + break; + } + } + + } catch (Throwable ex) { + log.error(ex); + } finally { + copyToQueue(new EOD()); + reading = false; + if (cursor != null) { + cursor.close(); + } + + } + + } + + protected boolean process(Data data) { + long dataId = data.getDataId(); + if (currentGap != null && dataId >= currentGap.getStartId()) { + if (dataId <= currentGap.getEndId()) { + return true; + } else { + // past current gap. move to next gap + if (dataGaps.size() > 0) { + currentGap = dataGaps.remove(0); + return process(data); + } else { + currentGap = null; + return false; + } + } + } else { + return false; + } + } + + public Data take() { + Data data = null; + try { + int timeout = parameterService.getInt( + ParameterConstants.ROUTING_WAIT_FOR_DATA_TIMEOUT_SECONDS, 330); + data = dataQueue.poll(timeout, TimeUnit.SECONDS); + } catch (InterruptedException e) { + log.warn(e); + } + + if (data == null) { + throw new SymmetricException("RouterDataReaderNotResponding"); + } else if (data instanceof EOD) { + data = null; + } + return data; } - - @Override - protected PreparedStatement prepareStatment(Connection c) throws SQLException { - int numberOfGapsToQualify = dataService.getParameterService().getInt( + + protected ISqlReadCursor prepareCursor() { + int numberOfGapsToQualify = parameterService.getInt( ParameterConstants.ROUTING_MAX_GAPS_TO_QUALIFY_IN_SQL, 100); - + this.dataGaps = dataService.findDataGaps(); String channelId = context.getChannel().getChannelId(); + String sql = qualifyUsingDataGaps(dataGaps, numberOfGapsToQualify, getSql(SELECT_DATA_USING_GAPS_SQL, context.getChannel().getChannel())); - PreparedStatement ps = c.prepareStatement(sql, ResultSet.TYPE_FORWARD_ONLY, - ResultSet.CONCUR_READ_ONLY); - ps.setQueryTimeout(jdbcTemplate.getQueryTimeout()); - ps.setFetchSize(jdbcTemplate.getFetchSize()); - ps.setString(1, channelId); - for (int i = 0; i < numberOfGapsToQualify && i < dataGaps.size(); i++) { + + ISqlTemplate sqlTemplate = symmetricDialect.getPlatform().getSqlTemplate(); + + int numberOfArgs = 1 + (numberOfGapsToQualify < dataGaps.size() ? numberOfGapsToQualify + : dataGaps.size()); + Object[] args = new Object[numberOfArgs]; + int[] types = new int[numberOfArgs]; + args[0] = channelId; + types[0] = Types.VARCHAR; + + for (int i = 0; i < numberOfGapsToQualify && i < dataGaps.size(); i++) { DataGap gap = dataGaps.get(i); - ps.setLong(i*2 + 2, gap.getStartId()); - if ((i+1) == numberOfGapsToQualify && (i+1) < dataGaps.size()) { - // there were more gaps than we are going to use in the SQL. use + args[i * 2 + 1] = gap.getStartId(); + types[i * 2 + 1] = Types.NUMERIC; + if ((i + 1) == numberOfGapsToQualify && (i + 1) < dataGaps.size()) { + // there were more gaps than we are going to use in the SQL. use // the last gap as the end data id for the last range - ps.setLong(i*2 + 3, dataGaps.get(dataGaps.size()-1).getEndId()); + args[i * 2 + 2] = dataGaps.get(dataGaps.size() - 1).getEndId(); } else { - ps.setLong(i*2 + 3, gap.getEndId()); + args[i * 2 + 2] = gap.getEndId(); } + types[i * 2 + 2] = Types.NUMERIC; } - + this.currentGap = dataGaps.remove(0); - return ps; + + return sqlTemplate.queryForCursor(sql, new ISqlRowMapper() { + public Data mapRow(Row row) { + Data data = new Data(); + data.putCsvData(CsvData.ROW_DATA, row.getString("ROW_DATA")); + data.putCsvData(CsvData.PK_DATA, row.getString("PK_DATA")); + data.putCsvData(CsvData.OLD_DATA, row.getString("OLD_DATA")); + data.putAttribute(CsvData.ATTRIBUTE_CHANNEL_ID, row.getString("CHANNEL_ID")); + data.putAttribute(CsvData.ATTRIBUTE_TX_ID, row.getString("TRANSACTION_ID")); + data.setDataEventType(DataEventType.getEventType(row.getString("EVENT_TYPE"))); + data.putAttribute(CsvData.ATTRIBUTE_TABLE_ID, row.getInt("TRIGGER_HIST_ID")); + data.putAttribute(CsvData.ATTRIBUTE_SOURCE_NODE_ID, row.getString("SOURCE_NODE_ID")); + data.putAttribute(CsvData.ATTRIBUTE_ROUTER_ID, row.getString("ROUTER_ID")); + data.putAttribute(CsvData.ATTRIBUTE_EXTERNAL_DATA, row.getString("EXTERNAL_DATA")); + data.putAttribute(CsvData.ATTRIBUTE_DATA_ID, row.getLong("DATA_ID")); + return data; + } + }, args, types); + } protected String qualifyUsingDataGaps(List dataGaps, int numberOfGapsToQualify, String sql) { StringBuilder gapClause = new StringBuilder(); for (int i = 0; i < numberOfGapsToQualify && i < dataGaps.size(); i++) { - if (i==0) { + if (i == 0) { gapClause.append(" and ("); } else { gapClause.append(" or "); @@ -96,27 +271,90 @@ protected String qualifyUsingDataGaps(List dataGaps, int numberOfGapsTo gapClause.append(")"); return FormatUtils.replace("dataRange", gapClause.toString(), sql); } - - @Override - protected boolean process(ResultSet rs) throws SQLException { - long dataId = rs.getLong(1); - if (currentGap != null && dataId >= currentGap.getStartId()) { - if (dataId <= currentGap.getEndId()) { - return true; - } else { - // past current gap. move to next gap - if (dataGaps.size() > 0) { - currentGap = dataGaps.remove(0); - return process(rs); + + protected String getSql(String sqlName, Channel channel) { + String select = sqlMap.getSql(sqlName); + if (!channel.isUseOldDataToRoute()) { + select = select.replace("d.old_data", "''"); + } + if (!channel.isUseRowDataToRoute()) { + select = select.replace("d.row_data", "''"); + } + if (!channel.isUsePkDataToRoute()) { + select = select.replace("d.pk_data", "''"); + } + return symmetricDialect == null ? select : symmetricDialect.massageDataExtractionSql( + select, channel); + } + + protected boolean fillPeekAheadQueue(List peekAheadQueue, int peekAheadCount, + ISqlReadCursor cursor) throws SQLException { + boolean moreData = true; + int toRead = peekAheadCount - peekAheadQueue.size(); + int dataCount = 0; + long ts = System.currentTimeMillis(); + while (reading && dataCount < toRead) { + Data data = cursor.next(); + if (data != null) { + if (process(data)) { + context.setLastDataIdForTransactionId(data); + peekAheadQueue.add(data); + dataCount++; + context.incrementStat(System.currentTimeMillis() - ts, + ChannelRouterContext.STAT_READ_DATA_MS); } else { - currentGap = null; - return false; + context.incrementStat(System.currentTimeMillis() - ts, + ChannelRouterContext.STAT_REREAD_DATA_MS); } + + ts = System.currentTimeMillis(); + } else { + moreData = false; + break; } - } else { - return false; + + } + return moreData; + } + + protected ResultSet executeQuery(PreparedStatement ps) throws SQLException { + long ts = System.currentTimeMillis(); + ResultSet rs = ps.executeQuery(); + long executeTimeInMs = System.currentTimeMillis() - ts; + context.incrementStat(executeTimeInMs, ChannelRouterContext.STAT_QUERY_TIME_MS); + if (executeTimeInMs > Constants.LONG_OPERATION_THRESHOLD) { + log.warn("RoutedDataSelectedInTime", executeTimeInMs, context.getChannel() + .getChannelId()); + } else if (log.isDebugEnabled()) { + log.debug("RoutedDataSelectedInTime", executeTimeInMs, context.getChannel() + .getChannelId()); + } + return rs; + } + + protected void copyToQueue(Data data) { + long ts = System.currentTimeMillis(); + while (!dataQueue.offer(data) && reading) { + AppUtils.sleep(50); } + context.incrementStat(System.currentTimeMillis() - ts, + ChannelRouterContext.STAT_ENQUEUE_DATA_MS); + } + + public boolean isReading() { + return reading; + } + + public void setReading(boolean reading) { + this.reading = reading; } + public BlockingQueue getDataQueue() { + return dataQueue; + } + + class EOD extends Data { + private static final long serialVersionUID = 1L; + } } \ No newline at end of file diff --git a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/route/DataRefGapDetector.java b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/route/DataRefGapDetector.java deleted file mode 100644 index 065eb465a9..0000000000 --- a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/route/DataRefGapDetector.java +++ /dev/null @@ -1,133 +0,0 @@ -/* - * Licensed to JumpMind Inc under one or more contributor - * license agreements. See the NOTICE file distributed - * with this work for additional information regarding - * copyright ownership. JumpMind Inc licenses this file - * to you under the GNU Lesser General Public License (the - * "License"); you may not use this file except in compliance - * with the License. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see - * . - * - * 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.jumpmind.symmetric.route; - -import java.sql.ResultSet; -import java.sql.SQLException; -import java.sql.Types; -import java.util.Date; - -import org.jumpmind.symmetric.common.ParameterConstants; -import org.jumpmind.symmetric.common.logging.ILog; -import org.jumpmind.symmetric.common.logging.LogFactory; -import org.jumpmind.symmetric.db.ISymmetricDialect; -import org.jumpmind.symmetric.model.DataRef; -import org.jumpmind.symmetric.service.IDataService; -import org.jumpmind.symmetric.service.IParameterService; -import org.jumpmind.symmetric.service.ISqlProvider; -import org.springframework.dao.DataAccessException; -import org.springframework.jdbc.core.JdbcTemplate; -import org.springframework.jdbc.core.ResultSetExtractor; - -/** - * - */ -public class DataRefGapDetector implements IDataToRouteGapDetector { - - final ILog log = LogFactory.getLog(getClass()); - - private IDataService dataService; - - private IParameterService parameterService; - - private JdbcTemplate jdbcTemplate; - - private ISymmetricDialect symmetricDialect; - - private ISqlProvider sqlProvider; - - public DataRefGapDetector(IDataService dataService, IParameterService parameterService, - JdbcTemplate jdbcTemplate, ISymmetricDialect symmetricDialect, ISqlProvider sqlProvider) { - this.dataService = dataService; - this.parameterService = parameterService; - this.jdbcTemplate = jdbcTemplate; - this.symmetricDialect = symmetricDialect; - this.sqlProvider = sqlProvider; - } - - public void beforeRouting() { - } - - public void afterRouting() { - // reselect the DataRef just in case somebody updated it manually during - // routing - final DataRef ref = dataService.getDataRef(); - long ts = System.currentTimeMillis(); - final int dataIdIncrementBy = parameterService.getInt(ParameterConstants.DATA_ID_INCREMENT_BY); - long lastDataId = (Long) jdbcTemplate.query(sqlProvider.getSql("selectDistinctDataIdFromDataEventSql"), - new Object[] { ref.getRefDataId() }, new int[] { Types.NUMERIC }, - new ResultSetExtractor() { - public Long extractData(ResultSet rs) throws SQLException, DataAccessException { - long lastDataId = ref.getRefDataId(); - while (rs.next()) { - long dataId = rs.getLong(1); - if (lastDataId == -1 || lastDataId + dataIdIncrementBy == dataId - || lastDataId == dataId) { - lastDataId = dataId; - } else { - if (dataService.countDataInRange(lastDataId, dataId) == 0) { - if (symmetricDialect.supportsTransactionViews()) { - if (!symmetricDialect - .areDatabaseTransactionsPendingSince(dataService - .findCreateTimeOfData(dataId).getTime() + 5000)) { - if (dataService.countDataInRange(lastDataId, dataId) == 0) { - log.info("RouterSkippingDataIdsNoTransactions", lastDataId, dataId); - lastDataId = dataId; - } - } - } else if (isDataGapExpired(dataId)) { - log.info("RouterSkippingDataIdsGapExpired", lastDataId, - dataId); - lastDataId = dataId; - } else { - break; - } - } else { - // detected a gap! - break; - } - } - } - return lastDataId; - } - }); - long updateTimeInMs = System.currentTimeMillis() - ts; - if (updateTimeInMs > 10000) { - log.info("RoutedGapDetectionTime", updateTimeInMs); - } - if (ref.getRefDataId() != lastDataId) { - dataService.saveDataRef(new DataRef(lastDataId, new Date())); - } - } - - protected boolean isDataGapExpired(long dataId) { - long gapTimoutInMs = parameterService - .getLong(ParameterConstants.ROUTING_STALE_DATA_ID_GAP_TIME); - Date createTime = dataService.findCreateTimeOfEvent(dataId); - if (createTime != null && System.currentTimeMillis() - createTime.getTime() > gapTimoutInMs) { - return true; - } else { - return false; - } - } - - -} \ No newline at end of file diff --git a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/route/DataRefRouteReader.java b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/route/DataRefRouteReader.java deleted file mode 100644 index 728e34f73a..0000000000 --- a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/route/DataRefRouteReader.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Licensed to JumpMind Inc under one or more contributor - * license agreements. See the NOTICE file distributed - * with this work for additional information regarding - * copyright ownership. JumpMind Inc licenses this file - * to you under the GNU Lesser General Public License (the - * "License"); you may not use this file except in compliance - * with the License. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see - * . - * - * 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.jumpmind.symmetric.route; - -import java.sql.Connection; -import java.sql.PreparedStatement; -import java.sql.ResultSet; -import java.sql.SQLException; - -import org.jumpmind.symmetric.common.logging.ILog; -import org.jumpmind.symmetric.model.DataRef; -import org.jumpmind.symmetric.service.IDataService; -import org.jumpmind.symmetric.service.ISqlProvider; - -/** - * This class is responsible for reading data for the purpose of routing. It - * reads ahead and tries to keep a blocking queue populated for other threads to - * process. - */ -public class DataRefRouteReader extends AbstractDataToRouteReader { - - public static final String SELECT_DATA_TO_BATCH_SQL = "selectDataToBatchSql"; - - public DataRefRouteReader(ILog log, ISqlProvider sqlProvider, ChannelRouterContext context, - IDataService dataService) { - super(log, sqlProvider, context, dataService); - } - - @Override - protected PreparedStatement prepareStatment(Connection c) throws SQLException { - DataRef dataRef = dataService.getDataRef(); - String channelId = context.getChannel().getChannelId(); - PreparedStatement ps = c.prepareStatement(getSql(SELECT_DATA_TO_BATCH_SQL, context.getChannel().getChannel()), - ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY); - ps.setQueryTimeout(jdbcTemplate.getQueryTimeout()); - ps.setFetchSize(jdbcTemplate.getFetchSize()); - ps.setString(1, channelId); - ps.setLong(2, dataRef.getRefDataId()); - return ps; - } - -} \ No newline at end of file diff --git a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/route/DataToRouteReaderFactory.java b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/route/DataToRouteReaderFactory.java deleted file mode 100644 index 9024f543cf..0000000000 --- a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/route/DataToRouteReaderFactory.java +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Licensed to JumpMind Inc under one or more contributor - * license agreements. See the NOTICE file distributed - * with this work for additional information regarding - * copyright ownership. JumpMind Inc licenses this file - * to you under the GNU Lesser General Public License (the - * "License"); you may not use this file except in compliance - * with the License. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see - * . - * - * 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.jumpmind.symmetric.route; - -import org.jumpmind.db.sql.AbstractSqlMap; -import org.jumpmind.symmetric.common.ParameterConstants; -import org.jumpmind.symmetric.service.IDataService; -import org.jumpmind.symmetric.service.ISqlProvider; -import org.jumpmind.symmetric.service.impl.AbstractService; -import org.jumpmind.symmetric.service.impl.RouterServiceSqlMap; - -/** - * Factory that creates and initializes the correct {@link IDataToRouteReader}. - */ -public class DataToRouteReaderFactory extends AbstractService implements ISqlProvider { - - public static final String GAP_DETECTOR_TYPE_GAP = "gap"; - public static final String GAP_DETECTOR_TYPE_REF = "ref"; - - private IDataService dataService; - - public IDataToRouteReader getDataToRouteReader(ChannelRouterContext context) { - String type = parameterService.getString(ParameterConstants.ROUTING_DATA_READER_TYPE); - if (type == null || type.equals(GAP_DETECTOR_TYPE_REF)) { - return new DataRefRouteReader(log, this, context, dataService); - } else if (type == null || type.equals(GAP_DETECTOR_TYPE_GAP)) { - return new DataGapRouteReader(log, this, context, dataService); - } else { - throw unsupportedType(type); - } - } - - public IDataToRouteGapDetector getDataToRouteGapDetector() { - String type = parameterService.getString(ParameterConstants.ROUTING_DATA_READER_TYPE); - if (type == null || type.equals(GAP_DETECTOR_TYPE_REF)) { - return new DataRefGapDetector(dataService, parameterService, jdbcTemplate, symmetricDialect, - this); - } else if (type == null || type.equals(GAP_DETECTOR_TYPE_GAP)) { - return new DataGapDetector(dataService, parameterService, jdbcTemplate, symmetricDialect, this); - } else { - throw unsupportedType(type); - } - } - - public boolean isUsingDataRef() { - String type = parameterService.getString(ParameterConstants.ROUTING_DATA_READER_TYPE); - return type == null || type.equals(GAP_DETECTOR_TYPE_REF); - } - - private RuntimeException unsupportedType(String type) { - return new UnsupportedOperationException("The data to route type of '" + type - + "' is not supported"); - } - - @Override - public AbstractSqlMap createSqlMap() { - return new RouterServiceSqlMap(symmetricDialect.getPlatform(), createReplacementTokens()); - } - - public void setDataService(IDataService dataService) { - this.dataService = dataService; - } - -} \ No newline at end of file diff --git a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/route/LookupTableDataRouter.java b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/route/LookupTableDataRouter.java index 7cd8cea70a..c27faef9cc 100644 --- a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/route/LookupTableDataRouter.java +++ b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/route/LookupTableDataRouter.java @@ -16,136 +16,128 @@ * "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.jumpmind.symmetric.route; - -import java.sql.ResultSet; -import java.sql.SQLException; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; - -import org.apache.commons.lang.StringUtils; -import org.jumpmind.symmetric.common.logging.ILog; -import org.jumpmind.symmetric.common.logging.LogFactory; -import org.jumpmind.symmetric.model.DataMetaData; -import org.jumpmind.symmetric.model.Node; -import org.jumpmind.symmetric.model.Router; -import org.springframework.jdbc.core.JdbcTemplate; -import org.springframework.jdbc.core.RowCallbackHandler; - -/** + * under the License. + */ + +package org.jumpmind.symmetric.route; + +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +import org.apache.commons.lang.StringUtils; +import org.jumpmind.db.sql.ISqlTemplate; +import org.jumpmind.db.sql.mapper.StringMapper; +import org.jumpmind.symmetric.common.logging.ILog; +import org.jumpmind.symmetric.common.logging.LogFactory; +import org.jumpmind.symmetric.db.ISymmetricDialect; +import org.jumpmind.symmetric.model.DataMetaData; +import org.jumpmind.symmetric.model.Node; +import org.jumpmind.symmetric.model.Router; + +/** * A data router that uses a lookup table to map data to nodes - */ -public class LookupTableDataRouter extends AbstractDataRouter implements IDataRouter { - - final static ILog log = LogFactory.getLog(LookupTableDataRouter.class); - - public final static String PARAM_TABLE = "LOOKUP_TABLE"; - public final static String PARAM_KEY_COLUMN = "KEY_COLUMN"; - public final static String PARAM_MAPPED_KEY_COLUMN = "LOOKUP_KEY_COLUMN"; - public final static String PARAM_EXTERNAL_ID_COLUMN = "EXTERNAL_ID_COLUMN"; - - final static String EXPRESSION_KEY = String.format("%s.Expression.", - LookupTableDataRouter.class.getName()); - - final static String LOOKUP_TABLE_KEY = String.format("%s.Table.", LookupTableDataRouter.class - .getName()); - - private JdbcTemplate jdbcTemplate; - - public Set routeToNodes(SimpleRouterContext routingContext, - DataMetaData dataMetaData, Set nodes, boolean initialLoad) { - - Set nodeIds = null; - Router router = dataMetaData.getTriggerRouter().getRouter(); - Map params = getParams(router, routingContext); - Map dataMap = getDataMap(dataMetaData); - boolean validExpression = params.containsKey(PARAM_TABLE) - && params.containsKey(PARAM_KEY_COLUMN) && params.containsKey(PARAM_MAPPED_KEY_COLUMN) - && params.containsKey(PARAM_EXTERNAL_ID_COLUMN); - if (validExpression) { - Map> lookupTable = getLookupTable(params, router, routingContext); - String column = params.get(PARAM_KEY_COLUMN); - String keyData = dataMap.get(column); - Set externalIds = lookupTable.get(keyData); - if (externalIds != null) { - for (Node node : nodes) { - if (externalIds.contains(node.getExternalId())) { - nodeIds = addNodeId(node.getNodeId(), nodeIds, nodes); - } - } - } - - } else { - log.warn("RouterIllegalLookupTableExpression", router.getRouterExpression()); - } - - return nodeIds; - - } - - /** - * Cache parsed expressions in the context to minimize the amount of parsing - * we have to do when we have lots of throughput. - */ - @SuppressWarnings("unchecked") - protected Map getParams(Router router, SimpleRouterContext routingContext) { - final String KEY = EXPRESSION_KEY + router.getRouterId(); - Map params = (Map) routingContext.getContextCache() - .get(KEY); - if (params == null) { - params = new HashMap(); - routingContext.getContextCache().put(KEY, params); - String routerExpression = router.getRouterExpression(); - if (!StringUtils.isBlank(routerExpression)) { - String[] expTokens = routerExpression.split("\r\n|\r|\n"); - if (expTokens != null) { - for (String t : expTokens) { - if (!StringUtils.isBlank(t)) { - String[] tokens = t.split("="); - if (tokens.length >= 2) { - params.put(tokens[0], tokens[1]); - } - } - } - } - } - } - return params; - } - - @SuppressWarnings("unchecked") - protected Map> getLookupTable(Map params, Router router, - SimpleRouterContext routingContext) { - final String CTX_CACHE_KEY = LOOKUP_TABLE_KEY + "." + params.get("TABLENAME"); - Map> lookupMap = (Map>) routingContext.getContextCache().get( - CTX_CACHE_KEY); - if (lookupMap == null) { - final Map> fillMap = new HashMap>(); - jdbcTemplate.query(String.format("select %s, %s from %s", params.get(PARAM_MAPPED_KEY_COLUMN), - params.get(PARAM_EXTERNAL_ID_COLUMN), params.get(PARAM_TABLE)), - new RowCallbackHandler() { - public void processRow(ResultSet rs) throws SQLException { - String key = rs.getString(1); - Set set = fillMap.get(key); - if (set == null) { - set = new HashSet(); - fillMap.put(key, set); - } - set.add(rs.getString(2)); - } - }); - lookupMap = fillMap; - routingContext.getContextCache().put(CTX_CACHE_KEY, lookupMap); - } - return lookupMap; - } - - public void setJdbcTemplate(JdbcTemplate jdbcTemplate) { - this.jdbcTemplate = jdbcTemplate; - } - + */ +public class LookupTableDataRouter extends AbstractDataRouter implements IDataRouter { + + final static ILog log = LogFactory.getLog(LookupTableDataRouter.class); + + public final static String PARAM_TABLE = "LOOKUP_TABLE"; + public final static String PARAM_KEY_COLUMN = "KEY_COLUMN"; + public final static String PARAM_MAPPED_KEY_COLUMN = "LOOKUP_KEY_COLUMN"; + public final static String PARAM_EXTERNAL_ID_COLUMN = "EXTERNAL_ID_COLUMN"; + + final static String EXPRESSION_KEY = String.format("%s.Expression.", + LookupTableDataRouter.class.getName()); + + final static String LOOKUP_TABLE_KEY = String.format("%s.Table.", + LookupTableDataRouter.class.getName()); + + private ISymmetricDialect symmetricDialect; + + public LookupTableDataRouter(ISymmetricDialect symmetricDialect) { + this.symmetricDialect = symmetricDialect; + } + + public Set routeToNodes(SimpleRouterContext routingContext, DataMetaData dataMetaData, + Set nodes, boolean initialLoad) { + + Set nodeIds = null; + Router router = dataMetaData.getTriggerRouter().getRouter(); + Map params = getParams(router, routingContext); + Map dataMap = getDataMap(dataMetaData); + boolean validExpression = params.containsKey(PARAM_TABLE) + && params.containsKey(PARAM_KEY_COLUMN) + && params.containsKey(PARAM_MAPPED_KEY_COLUMN) + && params.containsKey(PARAM_EXTERNAL_ID_COLUMN); + if (validExpression) { + Map> lookupTable = getLookupTable(params, router, routingContext); + String column = params.get(PARAM_KEY_COLUMN); + String keyData = dataMap.get(column); + Set externalIds = lookupTable.get(keyData); + if (externalIds != null) { + for (Node node : nodes) { + if (externalIds.contains(node.getExternalId())) { + nodeIds = addNodeId(node.getNodeId(), nodeIds, nodes); + } + } + } + + } else { + log.warn("RouterIllegalLookupTableExpression", router.getRouterExpression()); + } + + return nodeIds; + + } + + /** + * Cache parsed expressions in the context to minimize the amount of parsing + * we have to do when we have lots of throughput. + */ + @SuppressWarnings("unchecked") + protected Map getParams(Router router, SimpleRouterContext routingContext) { + final String KEY = EXPRESSION_KEY + router.getRouterId(); + Map params = (Map) routingContext.getContextCache() + .get(KEY); + if (params == null) { + params = new HashMap(); + routingContext.getContextCache().put(KEY, params); + String routerExpression = router.getRouterExpression(); + if (!StringUtils.isBlank(routerExpression)) { + String[] expTokens = routerExpression.split("\r\n|\r|\n"); + if (expTokens != null) { + for (String t : expTokens) { + if (!StringUtils.isBlank(t)) { + String[] tokens = t.split("="); + if (tokens.length >= 2) { + params.put(tokens[0], tokens[1]); + } + } + } + } + } + } + return params; + } + + @SuppressWarnings("unchecked") + protected Map> getLookupTable(Map params, Router router, + SimpleRouterContext routingContext) { + final String CTX_CACHE_KEY = LOOKUP_TABLE_KEY + "." + params.get("TABLENAME"); + Map> lookupMap = (Map>) routingContext + .getContextCache().get(CTX_CACHE_KEY); + if (lookupMap == null) { + ISqlTemplate template = symmetricDialect.getPlatform().getSqlTemplate(); + final Map> fillMap = new HashMap>(); + template.queryForMap(String.format("select %s, %s from %s", + params.get(PARAM_MAPPED_KEY_COLUMN), params.get(PARAM_EXTERNAL_ID_COLUMN), + params.get(PARAM_TABLE)), new StringMapper(), params + .get(PARAM_MAPPED_KEY_COLUMN)); + lookupMap = fillMap; + routingContext.getContextCache().put(CTX_CACHE_KEY, lookupMap); + } + return lookupMap; + } + } \ No newline at end of file diff --git a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/route/SimpleRouterContext.java b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/route/SimpleRouterContext.java index 232958aa2f..12b5eae90e 100644 --- a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/route/SimpleRouterContext.java +++ b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/route/SimpleRouterContext.java @@ -28,33 +28,26 @@ import java.util.TreeSet; import org.jumpmind.db.util.BinaryEncoding; +import org.jumpmind.log.Log; import org.jumpmind.symmetric.common.Constants; -import org.jumpmind.symmetric.common.logging.ILog; import org.jumpmind.symmetric.model.NodeChannel; import org.jumpmind.util.Context; -import org.springframework.jdbc.core.JdbcTemplate; public class SimpleRouterContext extends Context { protected NodeChannel channel; - protected JdbcTemplate jdbcTemplate; protected boolean encountedTransactionBoundary = false; protected Map stats = new HashMap(); protected String nodeId; - public SimpleRouterContext(String nodeId, JdbcTemplate jdbcTemplate, NodeChannel channel) { - this.init(jdbcTemplate, channel, nodeId); + public SimpleRouterContext() { } - - protected SimpleRouterContext() { - } - - protected void init(JdbcTemplate jdbcTemplate, NodeChannel channel, String nodeId) { - this.channel = channel; - this.jdbcTemplate = jdbcTemplate; + + public SimpleRouterContext(String nodeId, NodeChannel channel) { this.nodeId = nodeId; + this.channel = channel; } - + public BinaryEncoding getBinaryEncoding() { return null; } @@ -75,10 +68,6 @@ public Map getContextCache() { return this.context; } - public JdbcTemplate getJdbcTemplate() { - return this.jdbcTemplate; - } - public void setEncountedTransactionBoundary(boolean encountedTransactionBoundary) { this.encountedTransactionBoundary = encountedTransactionBoundary; } @@ -104,7 +93,7 @@ synchronized public long getStat(String name) { return val; } - synchronized public void logStats(ILog log, long totalTimeInMs) { + synchronized public void logStats(Log log, long totalTimeInMs) { boolean infoLevel = totalTimeInMs > Constants.LONG_OPERATION_THRESHOLD; Set keys = new TreeSet(stats.keySet()); StringBuilder statsPrintout = new StringBuilder(channel.getChannelId()); diff --git a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/route/SubSelectDataRouter.java b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/route/SubSelectDataRouter.java index 10f5718b7b..1eaaa998a6 100644 --- a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/route/SubSelectDataRouter.java +++ b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/route/SubSelectDataRouter.java @@ -16,7 +16,8 @@ * "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. */ + * under the License. + */ package org.jumpmind.symmetric.route; @@ -26,18 +27,20 @@ import java.util.Set; import org.apache.commons.lang.StringUtils; +import org.jumpmind.db.sql.ISqlTemplate; +import org.jumpmind.db.sql.mapper.StringMapper; import org.jumpmind.symmetric.db.ISymmetricDialect; import org.jumpmind.symmetric.model.DataMetaData; import org.jumpmind.symmetric.model.Node; import org.jumpmind.symmetric.model.TriggerRouter; -import org.springframework.jdbc.core.JdbcTemplate; -import org.springframework.jdbc.core.SingleColumnRowMapper; -import org.springframework.jdbc.core.simple.SimpleJdbcTemplate; +import org.jumpmind.util.FormatUtils; /** - * This data router is invoked when the router_type is 'subselect'. The router_expression is always a SQL expression - * that is used to find the list of nodes a row of data will be routed to. This router should never be used for high throughput - * tables because it makes a call back to the database for each row that is routed. + * This data router is invoked when the router_type is 'subselect'. The + * router_expression is always a SQL expression that is used to find the list of + * nodes a row of data will be routed to. This router should never be used for + * high throughput tables because it makes a call back to the database for each + * row that is routed. *

* The query that is used to select the nodes is as follows: *

@@ -45,35 +48,41 @@ * select c.node_id from $[sym.sync.table.prefix]_node c where c.node_group_id=:NODE_GROUP_ID and c.sync_enabled=1 and ... * *

- * The SQL expression designated in the router_expression is appended to the above SQL statement. Current and old column values can be - * passed into the sub select expression. For example, say you had an EMPLOYEE table and a PASSWORD table. When the password changes you want - * to route the password to the HOME_STORE that is stored on the EMPLOYEE table. The sub select expression might look like: + * The SQL expression designated in the router_expression is appended to the + * above SQL statement. Current and old column values can be passed into the sub + * select expression. For example, say you had an EMPLOYEE table and a PASSWORD + * table. When the password changes you want to route the password to the + * HOME_STORE that is stored on the EMPLOYEE table. The sub select expression + * might look like: *

* * c.external_id in (select home_store from employee where employee_id in (:EMPLOYEE_ID, :OLD_EMPLOYEE_ID)) * - * - * */ public class SubSelectDataRouter extends AbstractDataRouter { - private String sql; - - private JdbcTemplate jdbcTemplate; + private static final String SQL = "select c.node_id from $(prefixName)_node c where c.node_group_id=:NODE_GROUP_ID and c.sync_enabled=1 and "; private ISymmetricDialect symmetricDialect; - public Set routeToNodes(SimpleRouterContext routingContext, DataMetaData dataMetaData, Set nodes, - boolean initialLoad) { + public SubSelectDataRouter(ISymmetricDialect symmetricDialect) { + this.symmetricDialect = symmetricDialect; + } + + public Set routeToNodes(SimpleRouterContext routingContext, DataMetaData dataMetaData, + Set nodes, boolean initialLoad) { + String sql = FormatUtils.replaceToken(SQL, "prefixName", symmetricDialect.getTablePrefix(), + true); TriggerRouter trigger = dataMetaData.getTriggerRouter(); String subSelect = trigger.getRouter().getRouterExpression(); Set nodeIds = null; if (!StringUtils.isBlank(subSelect)) { - SimpleJdbcTemplate simpleTemplate = new SimpleJdbcTemplate(jdbcTemplate); Map sqlParams = getDataObjectMap(dataMetaData, symmetricDialect); - sqlParams.put("NODE_GROUP_ID", trigger.getRouter().getNodeGroupLink().getTargetNodeGroupId()); - List ids = simpleTemplate.query(String.format("%s%s", sql, subSelect), - new SingleColumnRowMapper(), sqlParams); + sqlParams.put("NODE_GROUP_ID", trigger.getRouter().getNodeGroupLink() + .getTargetNodeGroupId()); + ISqlTemplate template = symmetricDialect.getPlatform().getSqlTemplate(); + List ids = template.query(String.format("%s%s", sql, subSelect), + new StringMapper(), sqlParams); if (ids != null) { nodeIds = new HashSet(ids); } @@ -83,16 +92,4 @@ public Set routeToNodes(SimpleRouterContext routingContext, DataMetaData return nodeIds; } - public void setSql(String sql) { - this.sql = sql; - } - - public void setJdbcTemplate(JdbcTemplate jdbcTemplate) { - this.jdbcTemplate = jdbcTemplate; - } - - public void setSymmetricDialect(ISymmetricDialect symmetricDialect) { - this.symmetricDialect = symmetricDialect; - } - } \ No newline at end of file diff --git a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/route/TriggerDataRouter.java b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/route/TriggerDataRouter.java deleted file mode 100644 index f8357dd6b7..0000000000 --- a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/route/TriggerDataRouter.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Licensed to JumpMind Inc under one or more contributor - * license agreements. See the NOTICE file distributed - * with this work for additional information regarding - * copyright ownership. JumpMind Inc licenses this file - * to you under the GNU Lesser General Public License (the - * "License"); you may not use this file except in compliance - * with the License. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see - * . - * - * 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.jumpmind.symmetric.route; - -import java.util.Set; - -import org.jumpmind.symmetric.Version; -import org.jumpmind.symmetric.model.DataMetaData; -import org.jumpmind.symmetric.model.Node; -import org.jumpmind.symmetric.util.AbstractVersion; - -/** - * This is a router that is tied to the trigger table. It prevents triggers from - * being routed to pre-2.0 versions of SymmetricDS. - */ -public class TriggerDataRouter extends ConfigurationChangedDataRouter { - - public Set routeToNodes(SimpleRouterContext context, DataMetaData dataMetaData, - Set nodes, boolean initialLoad) { - Set nodeIds = super.routeToNodes(context, dataMetaData, nodes, initialLoad); - if (!initialLoad) { - for (Node node : nodes) { - String version = node.getSymmetricVersion(); - if (version != null) { - int max = Version.parseVersion(version)[AbstractVersion.MAJOR_INDEX]; - if (max < 2) { - nodeIds.remove(node.getNodeId()); - } - } - } - return nodeIds; - } else { - return nodeIds; - } - } - - public boolean isAutoRegister() { - return false; - } - -} \ No newline at end of file diff --git a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/security/PasswordFactory.java b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/security/PasswordFactory.java deleted file mode 100644 index 4145c2db0c..0000000000 --- a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/security/PasswordFactory.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Licensed to JumpMind Inc under one or more contributor - * license agreements. See the NOTICE file distributed - * with this work for additional information regarding - * copyright ownership. JumpMind Inc licenses this file - * to you under the GNU Lesser General Public License (the - * "License"); you may not use this file except in compliance - * with the License. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see - * . - * - * 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.jumpmind.symmetric.security; - -import org.jumpmind.symmetric.common.SecurityConstants; -import org.jumpmind.symmetric.service.ISecurityService; -import org.springframework.beans.factory.FactoryBean; - -/** - * Used to protect database user and password from casual observation in the properties file - */ -public class PasswordFactory implements FactoryBean { - - private ISecurityService securityService; - - private String password; - - public String getObject() throws Exception { - if (password != null && password.startsWith(SecurityConstants.PREFIX_ENC)) { - return securityService.decrypt(password.substring(SecurityConstants.PREFIX_ENC.length())); - } - return password; - } - - public Class getObjectType() { - return String.class; - } - - public boolean isSingleton() { - return false; - } - - public void setPassword(String password) { - this.password = password; - } - - public void setSecurityService(ISecurityService securityService) { - this.securityService = securityService; - } -} \ No newline at end of file diff --git a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/IClusterService.java b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/IClusterService.java index 473242d123..66d2e75bdf 100644 --- a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/IClusterService.java +++ b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/IClusterService.java @@ -42,8 +42,6 @@ public interface IClusterService { public String getServerId(); - public void setServerId(String serverId); - public boolean isClusteringEnabled(); public Map findLocks(); diff --git a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/IConfigurationService.java b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/IConfigurationService.java index 59b3c8be91..ed66f97399 100644 --- a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/IConfigurationService.java +++ b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/IConfigurationService.java @@ -22,6 +22,7 @@ package org.jumpmind.symmetric.service; import java.util.List; +import java.util.Map; import org.jumpmind.symmetric.model.Channel; import org.jumpmind.symmetric.model.ChannelMap; @@ -95,6 +96,11 @@ public interface IConfigurationService { */ public ChannelMap getSuspendIgnoreChannelLists(String nodeId); - public ChannelMap getSuspendIgnoreChannelLists(); + public ChannelMap getSuspendIgnoreChannelLists(); + + /** + * @return a map of nodes to redirect to that is keyed by a list of external_ids that should be redirected. + */ + public Map getRegistrationRedirectMap(); } \ No newline at end of file diff --git a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/IDataExtractorService.java b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/IDataExtractorService.java index 15b2a389c6..e145f27dd7 100644 --- a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/IDataExtractorService.java +++ b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/IDataExtractorService.java @@ -20,33 +20,24 @@ package org.jumpmind.symmetric.service; -import java.io.IOException; -import java.io.OutputStream; -import java.io.Writer; +import java.io.IOException; +import java.io.OutputStream; +import java.io.Writer; import java.util.List; - -import org.jumpmind.symmetric.extract.DataExtractorContext; -import org.jumpmind.symmetric.extract.IExtractorFilter; -import org.jumpmind.symmetric.model.Node; + +import org.jumpmind.symmetric.model.Node; import org.jumpmind.symmetric.model.OutgoingBatch; -import org.jumpmind.symmetric.model.TriggerHistory; -import org.jumpmind.symmetric.model.TriggerRouter; -import org.jumpmind.symmetric.transport.IOutgoingTransport; +import org.jumpmind.symmetric.transport.IOutgoingTransport; /** * This service provides an API to extract and stream data from a source database. */ public interface IDataExtractorService { - public void extractConfiguration(Node node, Writer writer, DataExtractorContext ctx, String... tablesToExclude) throws IOException; - public void extractConfigurationStandalone(Node node, OutputStream out, String... tablesToExclude) throws IOException; public void extractConfigurationStandalone(Node node, Writer out, String... tablesToExclude) throws IOException; - public void extractInitialLoadWithinBatchFor(Node node, TriggerRouter trigger, Writer writer, - DataExtractorContext ctx, TriggerHistory triggerHistory); - /** * @return a list of batches that were extracted */ @@ -55,8 +46,4 @@ public void extractInitialLoadWithinBatchFor(Node node, TriggerRouter trigger, W public boolean extractBatchRange(IOutgoingTransport transport, String startBatchId, String endBatchId) throws IOException; - public boolean extractBatchRange(IExtractListener handler, String startBatchId, String endBatchId) throws IOException; - - public void addExtractorFilter(IExtractorFilter extractorFilter); - } \ No newline at end of file diff --git a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/IDataService.java b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/IDataService.java index 6e29687764..ebe34f94ba 100644 --- a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/IDataService.java +++ b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/IDataService.java @@ -25,18 +25,15 @@ import java.util.List; import java.util.Map; -import org.jumpmind.symmetric.db.ISymmetricDialect; +import org.jumpmind.db.sql.ISqlTransaction; import org.jumpmind.symmetric.ext.IHeartbeatListener; -import org.jumpmind.symmetric.io.data.DataEventType; import org.jumpmind.symmetric.load.IReloadListener; import org.jumpmind.symmetric.model.Data; import org.jumpmind.symmetric.model.DataEvent; import org.jumpmind.symmetric.model.DataGap; -import org.jumpmind.symmetric.model.DataRef; import org.jumpmind.symmetric.model.Node; import org.jumpmind.symmetric.model.Trigger; import org.jumpmind.symmetric.model.TriggerRouter; -import org.springframework.jdbc.core.JdbcTemplate; /** * This service provides an API to access and update {@link Data}. @@ -74,18 +71,12 @@ public interface IDataService { */ public void heartbeat(boolean force); - public void insertHeartbeatEvent(Node node, boolean isReload); - - public long insertData(Data data); - - public void insertDataEvent(long dataId, long batchId, String routerId); - - public void insertDataEvent(JdbcTemplate template, long dataId, long batchId, String routerId); - - public void insertDataEvents(JdbcTemplate template, List events); + public void insertHeartbeatEvent(Node node, boolean isReload); + + public long insertData(Data data); + + public void insertDataEvents(ISqlTransaction transaction, List events); - public void insertDataEventAndOutgoingBatch(long dataId, String channelId, String nodeId, DataEventType eventType, String routerId, boolean isLoad); - public void insertDataAndDataEventAndOutgoingBatch(Data data, String channelId, List nodes, String routerId, boolean isLoad); public void insertDataAndDataEventAndOutgoingBatch(Data data, String nodeId, String routerId, boolean isLoad); @@ -105,10 +96,6 @@ public interface IDataService { public void checkForAndUpdateMissingChannelIds(long firstDataId, long lastDataId); - public void saveDataRef(DataRef dataRef); - - public DataRef getDataRef(); - public List findDataGapsByStatus(DataGap.Status status); public List findDataGaps(); @@ -137,21 +124,12 @@ public interface IDataService { public List listDataIds(long batchId, boolean descending); - public List listData(long batchId, long startDataId, String channelId, boolean descending, int maxRowsToRetrieve); - - public void handleDataSelect(final long batchId, final long startDataId, final String channelId, final boolean descending, - final IModelRetrievalHandler handler); + public List listData(long batchId, long startDataId, String channelId, boolean descending, int maxRowsToRetrieve); public void insertDataGap(DataGap gap); public void updateDataGap(DataGap gap, DataGap.Status status); public long findMaxDataId(); - - public IParameterService getParameterService(); - - public ISymmetricDialect getSymmetricDialect(); - - public JdbcTemplate getJdbcTemplate(); - + } \ No newline at end of file diff --git a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/IIncomingBatchService.java b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/IIncomingBatchService.java index ae829f1c05..91629a5fc1 100644 --- a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/IIncomingBatchService.java +++ b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/IIncomingBatchService.java @@ -25,7 +25,6 @@ import java.util.List; import org.jumpmind.symmetric.model.IncomingBatch; -import org.springframework.jdbc.core.JdbcTemplate; /** * This service provides an API to access to the incoming batch table. @@ -42,8 +41,6 @@ public interface IIncomingBatchService { public void insertIncomingBatch(IncomingBatch batch); - public int updateIncomingBatch(JdbcTemplate jdbcTemplate, IncomingBatch batch); - public int updateIncomingBatch(IncomingBatch batch); public List listIncomingBatchTimes(List nodeIds, List channels, diff --git a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/IModelRetrievalHandler.java b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/IModelRetrievalHandler.java deleted file mode 100644 index 765898f2b9..0000000000 --- a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/IModelRetrievalHandler.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Licensed to JumpMind Inc under one or more contributor - * license agreements. See the NOTICE file distributed - * with this work for additional information regarding - * copyright ownership. JumpMind Inc licenses this file - * to you under the GNU Lesser General Public License (the - * "License"); you may not use this file except in compliance - * with the License. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see - * . - * - * 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.jumpmind.symmetric.service; - -import java.io.IOException; - -/** - * A callback interface for retrieving data that allows the handler to interrupt the - * retrieval process. - */ -public interface IModelRetrievalHandler { - - /** - * @param model1 - * The model object that has just been retrieved - * @param model2 - * Supplemental model information that has just been retrieved - * @param count - * The number of model items that have been retrieved. The count starts at 1. - * @return true if the client should continue to retrieve model data, false - * if it should stop processing. - */ - public boolean retrieved(T model1, S model2, int count) throws IOException; - -} diff --git a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/INotificationService.java b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/INotificationService.java deleted file mode 100644 index f67657c5e2..0000000000 --- a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/INotificationService.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Licensed to JumpMind Inc under one or more contributor - * license agreements. See the NOTICE file distributed - * with this work for additional information regarding - * copyright ownership. JumpMind Inc licenses this file - * to you under the GNU Lesser General Public License (the - * "License"); you may not use this file except in compliance - * with the License. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see - * . - * - * 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.jumpmind.symmetric.service; - -import javax.management.Notification; - -public interface INotificationService { - - public void sendNotification(Notification event); - -} \ No newline at end of file diff --git a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/IOutgoingBatchService.java b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/IOutgoingBatchService.java index 127d3120e5..0cb9ea8e56 100644 --- a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/IOutgoingBatchService.java +++ b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/IOutgoingBatchService.java @@ -23,6 +23,7 @@ import java.util.List; +import org.jumpmind.db.sql.ISqlTransaction; import org.jumpmind.symmetric.model.Node; import org.jumpmind.symmetric.model.OutgoingBatch; import org.jumpmind.symmetric.model.OutgoingBatchSummary; @@ -54,8 +55,10 @@ public interface IOutgoingBatchService { public void updateOutgoingBatch(OutgoingBatch batch); public void updateOutgoingBatches(List batches); - - public void insertOutgoingBatch(OutgoingBatch outgoingBatch); + + public void insertOutgoingBatch(OutgoingBatch outgoingBatch); + + public void insertOutgoingBatch(ISqlTransaction transaction, OutgoingBatch outgoingBatch); public int countOutgoingBatchesInError(); diff --git a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/IParameterService.java b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/IParameterService.java index 16713e6f7f..940307f35c 100644 --- a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/IParameterService.java +++ b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/IParameterService.java @@ -26,6 +26,7 @@ import java.util.List; import java.util.Map; +import org.jumpmind.properties.TypedProperties; import org.jumpmind.symmetric.config.IParameterFilter; import org.jumpmind.symmetric.model.DatabaseParameter; @@ -68,9 +69,9 @@ public interface IParameterService { public List getDatabaseParametersFor(String paramKey); - public Map getDatabaseParametersByNodeGroupId(String nodeGroupId); + public TypedProperties getDatabaseParametersByNodeGroupId(String nodeGroupId); - public Map getAllParameters(); + public TypedProperties getAllParameters(); public void setParameterFilter(IParameterFilter f); @@ -97,5 +98,8 @@ public interface IParameterService { */ public String getSyncUrl(); - public String getTablePrefix(); + public String getTablePrefix(); + + public String getEngineName(); + } \ No newline at end of file diff --git a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/IPullService.java b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/IPullService.java index 7329e86ac3..1d4c01ef51 100644 --- a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/IPullService.java +++ b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/IPullService.java @@ -29,7 +29,7 @@ * Service API that is responsible for pulling data from the list of configured * {@link Node}s that are configured to {@link NodeGroupLinkAction#W} */ -public interface IPullService { +public interface IPullService extends IOfflineDetectorService { public RemoteNodeStatuses pullData(); diff --git a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/IPurgeService.java b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/IPurgeService.java index 84557a395f..bb8d61d0a9 100644 --- a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/IPurgeService.java +++ b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/IPurgeService.java @@ -20,8 +20,6 @@ package org.jumpmind.symmetric.service; import java.util.Calendar; - -import org.springframework.transaction.annotation.Transactional; /** * This service provides an API to kick off purge processes with or @@ -44,7 +42,6 @@ public interface IPurgeService { public long purgeIncoming(Calendar retentionCutoff); - @Transactional public void purgeAllIncomingEventsForNode(String nodeId); } \ No newline at end of file diff --git a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/IPushService.java b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/IPushService.java index 2bfb0ec9b6..b23a1a7294 100644 --- a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/IPushService.java +++ b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/IPushService.java @@ -29,7 +29,7 @@ * Service API that is responsible for pushing data to the list of configured * {@link Node}s that are configured to {@link NodeGroupLinkAction#P} */ -public interface IPushService { +public interface IPushService extends IOfflineDetectorService { /** * Attempt to push data, if any has been captured, to nodes that the diff --git a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/IRegistrationService.java b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/IRegistrationService.java index 2ea3cc0d9e..8ace2d5a73 100644 --- a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/IRegistrationService.java +++ b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/IRegistrationService.java @@ -21,14 +21,13 @@ package org.jumpmind.symmetric.service; -import java.io.IOException; -import java.io.OutputStream; +import java.io.IOException; +import java.io.OutputStream; import java.util.List; -import java.util.Map; - -import org.jumpmind.symmetric.model.Node; + +import org.jumpmind.symmetric.model.Node; import org.jumpmind.symmetric.model.RegistrationRequest; -import org.jumpmind.symmetric.security.INodePasswordFilter; +import org.jumpmind.symmetric.security.INodePasswordFilter; /** * This service provides an API that deals with {@link Node} registration @@ -103,12 +102,7 @@ public interface IRegistrationService { /** * Add an entry to the registation_redirect table so that if a node tries to register here. It will be redirected to the correct node. */ - public void saveRegistrationRedirect(String externalIdToRedirect, String nodeIdToRedirectTo); - - /** - * @return a map of nodes to redirect to that is keyed by a list of external_ids that should be redirected. - */ - public Map getRegistrationRedirectMap(); + public void saveRegistrationRedirect(String externalIdToRedirect, String nodeIdToRedirectTo); public String getRedirectionUrlFor(String externalId); diff --git a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/IRouterService.java b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/IRouterService.java index b188a6716c..65dc66cc81 100644 --- a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/IRouterService.java +++ b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/IRouterService.java @@ -37,7 +37,7 @@ * * @since 2.0 */ -public interface IRouterService extends ISqlProvider { +public interface IRouterService { public long routeData(); diff --git a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/ISqlProvider.java b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/ISqlProvider.java deleted file mode 100644 index bd285ddd79..0000000000 --- a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/ISqlProvider.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Licensed to JumpMind Inc under one or more contributor - * license agreements. See the NOTICE file distributed - * with this work for additional information regarding - * copyright ownership. JumpMind Inc licenses this file - * to you under the GNU Lesser General Public License (the - * "License"); you may not use this file except in compliance - * with the License. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see - * . - * - * 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.jumpmind.symmetric.service; - -public interface ISqlProvider { - - public String getSql(String... keys); - -} \ No newline at end of file diff --git a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/ITransformService.java b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/ITransformService.java index 582211ac29..2fd92388ce 100644 --- a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/ITransformService.java +++ b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/ITransformService.java @@ -22,11 +22,6 @@ public List findTransformsFor(NodeGroupLink link, public void deleteTransformTable(String transformTableId); - public void saveTransformColumn(TransformColumn transformColumn); - - public void deleteTransformColumn(String transformTableId, Boolean includeOn, - String targetColumnName); - public void resetCache(); } diff --git a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/IUpgradeService.java b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/IUpgradeService.java deleted file mode 100644 index 21f6a9ac84..0000000000 --- a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/IUpgradeService.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Licensed to JumpMind Inc under one or more contributor - * license agreements. See the NOTICE file distributed - * with this work for additional information regarding - * copyright ownership. JumpMind Inc licenses this file - * to you under the GNU Lesser General Public License (the - * "License"); you may not use this file except in compliance - * with the License. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see - * . - * - * 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.jumpmind.symmetric.service; - -/** - * - */ -public interface IUpgradeService { - - public boolean isUpgradeNecessary(); - - public boolean isUpgradePossible(); - - public void upgrade(); - -} \ No newline at end of file diff --git a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/impl/AbstractOfflineDetectorService.java b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/impl/AbstractOfflineDetectorService.java index d3eb70a567..a986080528 100644 --- a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/impl/AbstractOfflineDetectorService.java +++ b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/impl/AbstractOfflineDetectorService.java @@ -28,11 +28,13 @@ import java.util.List; import org.apache.commons.lang.exception.ExceptionUtils; +import org.jumpmind.symmetric.db.ISymmetricDialect; import org.jumpmind.symmetric.io.IOfflineClientListener; import org.jumpmind.symmetric.model.Node; import org.jumpmind.symmetric.model.RemoteNodeStatus; import org.jumpmind.symmetric.model.RemoteNodeStatus.Status; import org.jumpmind.symmetric.service.IOfflineDetectorService; +import org.jumpmind.symmetric.service.IParameterService; import org.jumpmind.symmetric.service.RegistrationRequiredException; import org.jumpmind.symmetric.transport.AuthenticationException; import org.jumpmind.symmetric.transport.ConnectionRejectedException; @@ -44,6 +46,11 @@ public abstract class AbstractOfflineDetectorService extends AbstractService implements IOfflineDetectorService { private List offlineListeners; + + public AbstractOfflineDetectorService(IParameterService parameterService, + ISymmetricDialect symmetricDialect) { + super(parameterService, symmetricDialect); + } public void setOfflineListeners(List listeners) { this.offlineListeners = listeners; diff --git a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/impl/AbstractService.java b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/impl/AbstractService.java index 23571b7dcf..cda0acfacd 100644 --- a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/impl/AbstractService.java +++ b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/impl/AbstractService.java @@ -26,48 +26,38 @@ import java.util.List; import java.util.Map; -import javax.sql.DataSource; - import org.apache.commons.lang.exception.ExceptionUtils; -import org.jumpmind.db.sql.AbstractSqlMap; -import org.jumpmind.symmetric.common.logging.ILog; -import org.jumpmind.symmetric.common.logging.LogFactory; +import org.jumpmind.db.sql.ISqlMap; +import org.jumpmind.db.sql.ISqlTemplate; +import org.jumpmind.db.sql.ISqlTransaction; +import org.jumpmind.log.Log; +import org.jumpmind.log.LogFactory; import org.jumpmind.symmetric.db.ISymmetricDialect; import org.jumpmind.symmetric.service.IParameterService; import org.jumpmind.symmetric.service.IService; -import org.jumpmind.symmetric.service.ISqlProvider; -import org.springframework.jdbc.core.JdbcTemplate; -import org.springframework.jdbc.core.simple.SimpleJdbcTemplate; -import org.springframework.transaction.support.TransactionTemplate; -abstract public class AbstractService implements IService, ISqlProvider { +abstract public class AbstractService implements IService { - protected ILog log = LogFactory.getLog(getClass()); + protected Log log = LogFactory.getLog(getClass()); protected IParameterService parameterService; - protected JdbcTemplate jdbcTemplate; - - protected TransactionTemplate newTransactionTemplate; - - protected DataSource dataSource; - - protected ISymmetricDialect symmetricDialect; + protected ISymmetricDialect symmetricDialect; + + protected ISqlTemplate sqlTemplate; protected String tablePrefix; - private AbstractSqlMap sqlMap; - - public void setJdbcTemplate(JdbcTemplate jdbc) { - this.jdbcTemplate = jdbc; + private ISqlMap sqlMap; + + public AbstractService(IParameterService parameterService, ISymmetricDialect symmetricDialect) { + this.symmetricDialect = symmetricDialect; + this.parameterService = parameterService; + this.sqlTemplate = symmetricDialect.getPlatform().getSqlTemplate(); } - public JdbcTemplate getJdbcTemplate() { - return jdbcTemplate; - } - - protected SimpleJdbcTemplate getSimpleTemplate() { - return new SimpleJdbcTemplate(jdbcTemplate); + public ISqlTemplate getJdbcTemplate() { + return symmetricDialect.getPlatform().getSqlTemplate(); } synchronized public void synchronize(Runnable runnable) { @@ -93,48 +83,31 @@ protected SQLException unwrapSqlException(Throwable e) { return null; } - final protected AbstractSqlMap getSqlMap() { + final protected ISqlMap getSqlMap() { if (sqlMap == null) { sqlMap = createSqlMap(); } return sqlMap; } - abstract protected AbstractSqlMap createSqlMap(); + abstract protected ISqlMap createSqlMap(); - protected Map createReplacementTokens() { + protected Map createSqlReplacementTokens() { + return createSqlReplacementTokens(this.tablePrefix); + } + + protected static Map createSqlReplacementTokens(String tablePrefix) { Map map = new HashMap(); - map.put("prefixName", this.tablePrefix); + map.put("prefixName", tablePrefix); return map; - } + } public String getSql(String... keys) { return getSqlMap().getSql(keys); } - public void setTablePrefix(String tablePrefix) { - this.tablePrefix = tablePrefix; - } - - public void setParameterService(IParameterService parameterService) { - this.parameterService = parameterService; - this.log = LogFactory.getLog(parameterService); - } - public IParameterService getParameterService() { return parameterService; - } - - public void setNewTransactionTemplate(TransactionTemplate transactionTemplate) { - this.newTransactionTemplate = transactionTemplate; - } - - public void setDataSource(DataSource dataSource) { - this.dataSource = dataSource; - } - - public void setSymmetricDialect(ISymmetricDialect symmetricDialect) { - this.symmetricDialect = symmetricDialect; } public ISymmetricDialect getSymmetricDialect() { @@ -143,6 +116,12 @@ public ISymmetricDialect getSymmetricDialect() { public String getTablePrefix() { return tablePrefix; + } + + protected void close(ISqlTransaction transaction) { + if (transaction != null) { + transaction.close(); + } } } \ No newline at end of file diff --git a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/impl/AcknowledgeService.java b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/impl/AcknowledgeService.java index bbac27f555..0349ecbc14 100644 --- a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/impl/AcknowledgeService.java +++ b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/impl/AcknowledgeService.java @@ -20,21 +20,20 @@ */ package org.jumpmind.symmetric.service.impl; -import java.sql.ResultSet; -import java.sql.SQLException; import java.util.ArrayList; import java.util.List; import org.jumpmind.db.sql.AbstractSqlMap; +import org.jumpmind.db.sql.mapper.NumberMapper; +import org.jumpmind.symmetric.db.ISymmetricDialect; import org.jumpmind.symmetric.model.BatchInfo; import org.jumpmind.symmetric.model.OutgoingBatch; import org.jumpmind.symmetric.model.OutgoingBatch.Status; import org.jumpmind.symmetric.service.IAcknowledgeService; import org.jumpmind.symmetric.service.IOutgoingBatchService; +import org.jumpmind.symmetric.service.IParameterService; import org.jumpmind.symmetric.service.IRegistrationService; import org.jumpmind.symmetric.transport.IAcknowledgeEventListener; -import org.springframework.jdbc.core.RowCallbackHandler; -import org.springframework.transaction.annotation.Transactional; /** * @see IAcknowledgeService @@ -47,13 +46,20 @@ public class AcknowledgeService extends AbstractService implements IAcknowledgeS private IRegistrationService registrationService; + public AcknowledgeService(IParameterService parameterService, + ISymmetricDialect symmetricDialect, IOutgoingBatchService outgoingBatchService, + IRegistrationService registrationService) { + super(parameterService, symmetricDialect); + this.outgoingBatchService = outgoingBatchService; + this.registrationService = registrationService; + } + @Override protected AbstractSqlMap createSqlMap() { return new AcknowledgeServiceSqlMap(symmetricDialect.getPlatform(), - createReplacementTokens()); + createSqlReplacementTokens()); } - @Transactional public void ack(final BatchInfo batch) { if (batchEventListeners != null) { @@ -87,10 +93,12 @@ public void ack(final BatchInfo batch) { outgoingBatch.setLoadMillis(batch.getDatabaseMillis()); if (!batch.isOk() && batch.getErrorLine() != 0) { - CallBackHandler handler = new CallBackHandler(batch.getErrorLine()); - jdbcTemplate.query(getSql("selectDataIdSql"), - new Object[] { outgoingBatch.getBatchId() }, handler); - outgoingBatch.setFailedDataId(handler.getDataId()); + List ids = sqlTemplate.query(getSql("selectDataIdSql"), + new NumberMapper(), outgoingBatch.getBatchId()); + if (ids.size() >= batch.getErrorLine()) { + outgoingBatch.setFailedDataId(ids.get((int) batch.getErrorLine() - 1) + .longValue()); + } outgoingBatch.setSqlCode(batch.getSqlCode()); outgoingBatch.setSqlState(batch.getSqlState()); outgoingBatch.setSqlMessage(batch.getSqlMessage()); @@ -108,36 +116,6 @@ public void ack(final BatchInfo batch) { } } - class CallBackHandler implements RowCallbackHandler { - int index = 0; - - long dataId = -1; - - long rowNumber; - - CallBackHandler(long rowNumber) { - this.rowNumber = rowNumber; - } - - public void processRow(ResultSet rs) throws SQLException { - if (++index == rowNumber) { - dataId = rs.getLong(1); - } - } - - public long getDataId() { - return dataId; - } - } - - public void setOutgoingBatchService(IOutgoingBatchService outgoingBatchService) { - this.outgoingBatchService = outgoingBatchService; - } - - public void setRegistrationService(IRegistrationService registrationService) { - this.registrationService = registrationService; - } - public void addAcknowledgeEventListener(IAcknowledgeEventListener statusChangeListner) { if (batchEventListeners == null) { diff --git a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/impl/BandwidthService.java b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/impl/BandwidthService.java index f05de776bd..8568e8d717 100644 --- a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/impl/BandwidthService.java +++ b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/impl/BandwidthService.java @@ -16,7 +16,8 @@ * "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. */ + * under the License. + */ package org.jumpmind.symmetric.service.impl; @@ -27,7 +28,8 @@ import java.net.URL; import org.apache.commons.io.IOUtils; -import org.jumpmind.db.sql.AbstractSqlMap; +import org.jumpmind.log.Log; +import org.jumpmind.log.LogFactory; import org.jumpmind.symmetric.common.ParameterConstants; import org.jumpmind.symmetric.service.IBandwidthService; import org.jumpmind.symmetric.service.IParameterService; @@ -37,30 +39,33 @@ /** * @see IBandwidthService */ -public class BandwidthService extends AbstractService implements IBandwidthService { - +public class BandwidthService implements IBandwidthService { + + protected Log log = LogFactory.getLog(getClass()); + private IParameterService parameterService; + public BandwidthService(IParameterService parameterService, Log log) { + this.parameterService = parameterService; + this.log = log; + } + public double getDownloadKbpsFor(String syncUrl, long sampleSize, long maxTestDuration) { double downloadSpeed = -1d; try { BandwidthTestResults bw = getDownloadResultsFor(syncUrl, sampleSize, maxTestDuration); downloadSpeed = (int) bw.getKbps(); } catch (SocketTimeoutException e) { - log.warn("SocketTimeOut", syncUrl); + log.warn("Socket timeout while attempting to contact %s", syncUrl); } catch (Exception e) { log.error(e); } return downloadSpeed; } - - public void setParameterService(IParameterService parameterService) { - this.parameterService = parameterService; - } - protected BandwidthTestResults getDownloadResultsFor(String syncUrl, long sampleSize, long maxTestDuration) - throws IOException { + protected BandwidthTestResults getDownloadResultsFor(String syncUrl, long sampleSize, + long maxTestDuration) throws IOException { byte[] buffer = new byte[1024]; InputStream is = null; try { @@ -69,7 +74,7 @@ protected BandwidthTestResults getDownloadResultsFor(String syncUrl, long sample bw.start(); HttpURLConnection conn = (HttpURLConnection) u.openConnection(); setBasicAuthIfNeeded(conn); - + conn.connect(); is = conn.getInputStream(); int r; @@ -78,7 +83,7 @@ protected BandwidthTestResults getDownloadResultsFor(String syncUrl, long sample } is.close(); bw.stop(); - log.info("BandwidthCalculated", syncUrl, bw.getKbps()); + log.info("%s was calculated to have a download bandwidth of %s kbps", syncUrl, bw.getKbps()); return bw; } finally { IOUtils.closeQuietly(is); @@ -87,14 +92,11 @@ protected BandwidthTestResults getDownloadResultsFor(String syncUrl, long sample protected void setBasicAuthIfNeeded(HttpURLConnection conn) { if (parameterService != null) { - HttpTransportManager.setBasicAuthIfNeeded(conn, - parameterService.getString(ParameterConstants.TRANSPORT_HTTP_BASIC_AUTH_USERNAME), - parameterService.getString(ParameterConstants.TRANSPORT_HTTP_BASIC_AUTH_PASSWORD)); + HttpTransportManager.setBasicAuthIfNeeded(conn, parameterService + .getString(ParameterConstants.TRANSPORT_HTTP_BASIC_AUTH_USERNAME), + parameterService + .getString(ParameterConstants.TRANSPORT_HTTP_BASIC_AUTH_PASSWORD)); } } - - @Override - protected AbstractSqlMap createSqlMap() { - return null; - } + } \ No newline at end of file diff --git a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/impl/ClusterService.java b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/impl/ClusterService.java index 39352f1104..b7038e4f3e 100644 --- a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/impl/ClusterService.java +++ b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/impl/ClusterService.java @@ -30,8 +30,6 @@ import static org.jumpmind.symmetric.service.ClusterConstants.ROUTE; import static org.jumpmind.symmetric.service.ClusterConstants.SYNCTRIGGERS; -import java.sql.ResultSet; -import java.sql.SQLException; import java.util.Calendar; import java.util.Date; import java.util.HashMap; @@ -39,14 +37,15 @@ import org.apache.commons.lang.time.DateUtils; import org.jumpmind.db.sql.AbstractSqlMap; +import org.jumpmind.db.sql.ISqlRowMapper; +import org.jumpmind.db.sql.Row; import org.jumpmind.symmetric.common.ParameterConstants; +import org.jumpmind.symmetric.db.ISymmetricDialect; import org.jumpmind.symmetric.model.Lock; import org.jumpmind.symmetric.service.IClusterService; +import org.jumpmind.symmetric.service.IParameterService; import org.jumpmind.symmetric.util.AppUtils; import org.springframework.dao.DataIntegrityViolationException; -import org.springframework.jdbc.core.RowMapper; -import org.springframework.transaction.annotation.Propagation; -import org.springframework.transaction.annotation.Transactional; /** * @see IClusterService @@ -54,6 +53,10 @@ public class ClusterService extends AbstractService implements IClusterService { protected String serverId = AppUtils.getServerId(); + + public ClusterService(IParameterService parameterService, ISymmetricDialect dialect) { + super(parameterService, dialect); + } public void initLockTable() { initLockTable(ROUTE); @@ -69,7 +72,7 @@ public void initLockTable() { public void initLockTable(final String action) { try { - jdbcTemplate.update(getSql("insertLockSql"), new Object[] { action }); + sqlTemplate.update(getSql("insertLockSql"), new Object[] { action }); log.debug("LockInserted", action); } catch (final DataIntegrityViolationException ex) { @@ -78,10 +81,9 @@ public void initLockTable(final String action) { } public void clearAllLocks() { - jdbcTemplate.update(getSql("clearAllLocksSql")); + sqlTemplate.update(getSql("clearAllLocksSql")); } - @Transactional(propagation = Propagation.REQUIRES_NEW) public boolean lock(final String action) { if (isClusteringEnabled()) { final Date timeout = DateUtils.add(new Date(), Calendar.MILLISECOND, @@ -94,21 +96,21 @@ public boolean lock(final String action) { protected boolean lock(String action, Date timeToBreakLock, Date timeLockAquired, String serverId) { - return jdbcTemplate.update(getSql("aquireLockSql"), new Object[] { serverId, + return sqlTemplate.update(getSql("aquireLockSql"), new Object[] { serverId, timeLockAquired, action, timeToBreakLock, serverId }) == 1; } public Map findLocks() { final Map locks = new HashMap(); if (isClusteringEnabled()) { - jdbcTemplate.query(getSql("findLocksSql"), new RowMapper() { - public Lock mapRow(ResultSet rs, int rowNum) throws SQLException { + sqlTemplate.query(getSql("findLocksSql"), new ISqlRowMapper() { + public Lock mapRow(Row rs) { Lock lock = new Lock(); - lock.setLockAction(rs.getString(1)); - lock.setLockingServerId(rs.getString(2)); - lock.setLockTime(rs.getTimestamp(3)); - lock.setLastLockingServerId(rs.getString(4)); - lock.setLastLockTime(rs.getTimestamp(5)); + lock.setLockAction(rs.getString("lock_action")); + lock.setLockingServerId(rs.getString("locking_server_id")); + lock.setLockTime(rs.getDateTime("lock_time")); + lock.setLastLockingServerId(rs.getString("last_locking_server_id")); + lock.setLastLockTime(rs.getDateTime("last_lock_time")); locks.put(lock.getLockAction(), lock); return lock; } @@ -117,15 +119,10 @@ public Lock mapRow(ResultSet rs, int rowNum) throws SQLException { return locks; } - public void setServerId(String serverId) { - this.serverId = serverId; - } - public String getServerId() { return serverId; } - @Transactional(propagation = Propagation.REQUIRES_NEW) public void unlock(final String action) { if (isClusteringEnabled()) { if (!unlock(action, serverId)) { @@ -135,7 +132,7 @@ public void unlock(final String action) { } protected boolean unlock(String action, String serverId) { - return jdbcTemplate.update(getSql("releaseLockSql"), new Object[] { serverId, action, + return sqlTemplate.update(getSql("releaseLockSql"), new Object[] { serverId, action, serverId }) > 0; } @@ -161,6 +158,6 @@ public void clearInfiniteLock(String action) { @Override protected AbstractSqlMap createSqlMap() { return new ClusterServiceSqlMap(symmetricDialect.getPlatform(), - createReplacementTokens()); + createSqlReplacementTokens()); } } \ No newline at end of file diff --git a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/impl/ConfigurationService.java b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/impl/ConfigurationService.java index f2ed213f5d..4a55d76b96 100644 --- a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/impl/ConfigurationService.java +++ b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/impl/ConfigurationService.java @@ -16,74 +16,85 @@ * "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.jumpmind.symmetric.service.impl; - -import java.io.File; -import java.io.InputStreamReader; -import java.net.MalformedURLException; -import java.net.URL; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.util.Date; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; - -import org.apache.commons.lang.StringUtils; + * under the License. + */ +package org.jumpmind.symmetric.service.impl; + +import java.io.File; +import java.io.InputStreamReader; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.ArrayList; +import java.util.Date; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import org.apache.commons.lang.StringUtils; import org.jumpmind.db.io.DatabaseIO; import org.jumpmind.db.model.Database; import org.jumpmind.db.platform.IDatabasePlatform; import org.jumpmind.db.sql.AbstractSqlMap; +import org.jumpmind.db.sql.ISqlRowMapper; +import org.jumpmind.db.sql.Row; import org.jumpmind.db.sql.SqlScript; -import org.jumpmind.symmetric.common.ParameterConstants; -import org.jumpmind.symmetric.model.Channel; -import org.jumpmind.symmetric.model.ChannelMap; -import org.jumpmind.symmetric.model.Node; -import org.jumpmind.symmetric.model.NodeChannel; +import org.jumpmind.symmetric.common.Constants; +import org.jumpmind.symmetric.common.ParameterConstants; +import org.jumpmind.symmetric.db.ISymmetricDialect; +import org.jumpmind.symmetric.model.Channel; +import org.jumpmind.symmetric.model.ChannelMap; +import org.jumpmind.symmetric.model.Node; +import org.jumpmind.symmetric.model.NodeChannel; import org.jumpmind.symmetric.model.NodeGroup; -import org.jumpmind.symmetric.model.NodeGroupChannelWindow; -import org.jumpmind.symmetric.model.NodeGroupLink; -import org.jumpmind.symmetric.model.NodeGroupLinkAction; -import org.jumpmind.symmetric.model.NodeSecurity; -import org.jumpmind.symmetric.service.IConfigurationService; -import org.jumpmind.symmetric.service.INodeService; -import org.springframework.dao.DataAccessException; +import org.jumpmind.symmetric.model.NodeGroupChannelWindow; +import org.jumpmind.symmetric.model.NodeGroupLink; +import org.jumpmind.symmetric.model.NodeGroupLinkAction; +import org.jumpmind.symmetric.model.NodeSecurity; +import org.jumpmind.symmetric.service.IConfigurationService; +import org.jumpmind.symmetric.service.INodeService; +import org.jumpmind.symmetric.service.IParameterService; import org.springframework.dao.DataIntegrityViolationException; -import org.springframework.jdbc.core.ResultSetExtractor; -import org.springframework.jdbc.core.RowMapper; - + /** * @see IConfigurationService */ -public class ConfigurationService extends AbstractService implements IConfigurationService { - - private INodeService nodeService; - - private Map> nodeChannelCache; - - private long nodeChannelCacheTime; - - private List defaultChannels; - - public ConfigurationService() { - } - - public void saveNodeGroupLink(NodeGroupLink link) { +public class ConfigurationService extends AbstractService implements IConfigurationService { + + private INodeService nodeService; + + private Map> nodeChannelCache; + + private long nodeChannelCacheTime; + + private List defaultChannels; + + public ConfigurationService(IParameterService parameterService, ISymmetricDialect dialect, + INodeService nodeService) { + super(parameterService, dialect); + this.nodeService = nodeService; + this.defaultChannels = new ArrayList(); + this.defaultChannels.add(new Channel(Constants.CHANNEL_CONFIG, 0, 100, 100, true, 0)); + this.defaultChannels.add(new Channel(Constants.CHANNEL_RELOAD, 1, 1, 1, true, 0)); + this.defaultChannels.add(new Channel(Constants.CHANNEL_DEFAULT, 99999, 1000, 100, true, 0)); + } + + public void saveNodeGroupLink(NodeGroupLink link) { if (!doesNodeGroupExist(link.getSourceNodeGroupId())) { saveNodeGroup(new NodeGroup(link.getSourceNodeGroupId())); } - + if (!doesNodeGroupExist(link.getTargetNodeGroupId())) { saveNodeGroup(new NodeGroup(link.getTargetNodeGroupId())); } - - if (jdbcTemplate.update(getSql("updateNodeGroupLinkSql"), link.getDataEventAction().name(), link.getSourceNodeGroupId(), link.getTargetNodeGroupId()) == 0) { - jdbcTemplate.update(getSql("insertNodeGroupLinkSql"), link.getDataEventAction().name(), link.getSourceNodeGroupId(), link.getTargetNodeGroupId()); + + if (sqlTemplate.update(getSql("updateNodeGroupLinkSql"), link.getDataEventAction().name(), + link.getSourceNodeGroupId(), link.getTargetNodeGroupId()) == 0) { + sqlTemplate.update(getSql("insertNodeGroupLinkSql"), link.getDataEventAction().name(), + link.getSourceNodeGroupId(), link.getTargetNodeGroupId()); } } - + public boolean doesNodeGroupExist(String nodeGroupId) { boolean exists = false; List groups = getNodeGroups(); @@ -92,368 +103,380 @@ public boolean doesNodeGroupExist(String nodeGroupId) { } return exists; } - + public void saveNodeGroup(NodeGroup group) { - if (jdbcTemplate.update(getSql("updateNodeGroupSql"), group.getDescription(), group.getNodeGroupId()) == 0) { - jdbcTemplate.update(getSql("insertNodeGroupSql"), group.getDescription(), group.getNodeGroupId()); + if (sqlTemplate.update(getSql("updateNodeGroupSql"), group.getDescription(), + group.getNodeGroupId()) == 0) { + sqlTemplate.update(getSql("insertNodeGroupSql"), group.getDescription(), + group.getNodeGroupId()); } } - + public void deleteNodeGroup(String nodeGroupId) { - jdbcTemplate.update(getSql("deleteNodeGroupSql"), nodeGroupId); + sqlTemplate.update(getSql("deleteNodeGroupSql"), nodeGroupId); } - + public void deleteNodeGroupLink(NodeGroupLink link) { - jdbcTemplate.update(getSql("deleteNodeGroupLinkSql"), link.getSourceNodeGroupId(), link.getTargetNodeGroupId()); - } - - public List getNodeGroups() { - return jdbcTemplate.query(getSql("selectNodeGroupsSql"), new NodeGroupMapper()); - } - - public List getNodeGroupLinks() { - return jdbcTemplate.query(getSql("groupsLinksSql"), new NodeGroupLinkMapper()); - } - - public List getNodeGroupLinksFor(String sourceNodeGroupId) { - return jdbcTemplate.query(getSql("groupsLinksForSql"), new Object[] { sourceNodeGroupId }, - new NodeGroupLinkMapper()); - } - - public NodeGroupLink getNodeGroupLinkFor(String sourceNodeGroupId, String targetNodeGroupId) { - List links = getNodeGroupLinksFor(sourceNodeGroupId); - Iterator it = links.iterator(); - while (it.hasNext()) { - NodeGroupLink nodeGroupLink = (NodeGroupLink) it.next(); - if (!nodeGroupLink.getTargetNodeGroupId().equals(targetNodeGroupId)) { - it.remove(); - } - } - return links.size() > 0 ? links.get(0) : null; - } - + sqlTemplate.update(getSql("deleteNodeGroupLinkSql"), link.getSourceNodeGroupId(), + link.getTargetNodeGroupId()); + } + + public List getNodeGroups() { + return sqlTemplate.query(getSql("selectNodeGroupsSql"), new NodeGroupMapper()); + } + + public List getNodeGroupLinks() { + return sqlTemplate.query(getSql("groupsLinksSql"), new NodeGroupLinkMapper()); + } + + public List getNodeGroupLinksFor(String sourceNodeGroupId) { + return sqlTemplate.query(getSql("groupsLinksForSql"), new NodeGroupLinkMapper(), + sourceNodeGroupId); + } + + public NodeGroupLink getNodeGroupLinkFor(String sourceNodeGroupId, String targetNodeGroupId) { + List links = getNodeGroupLinksFor(sourceNodeGroupId); + Iterator it = links.iterator(); + while (it.hasNext()) { + NodeGroupLink nodeGroupLink = (NodeGroupLink) it.next(); + if (!nodeGroupLink.getTargetNodeGroupId().equals(targetNodeGroupId)) { + it.remove(); + } + } + return links.size() > 0 ? links.get(0) : null; + } + public boolean isChannelInUse(String channelId) { - return jdbcTemplate.queryForInt(getSql("isChannelInUseSql"), channelId) > 0; - } - - public void saveChannel(Channel channel, boolean reloadChannels) { - if (0 == jdbcTemplate.update(getSql("updateChannelSql"), new Object[] { - channel.getProcessingOrder(), channel.getMaxBatchSize(), - channel.getMaxBatchToSend(), channel.getMaxDataToRoute(), - channel.isUseOldDataToRoute() ? 1 : 0, channel.isUseRowDataToRoute() ? 1 : 0, - channel.isUsePkDataToRoute() ? 1 : 0, - channel.isContainsBigLob() ? 1 : 0, - channel.isEnabled() ? 1 : 0, channel.getBatchAlgorithm(), - channel.getExtractPeriodMillis(), channel.getChannelId() })) { - jdbcTemplate.update(getSql("insertChannelSql"), new Object[] { channel.getChannelId(), - channel.getProcessingOrder(), channel.getMaxBatchSize(), - channel.getMaxBatchToSend(), channel.getMaxDataToRoute(), - channel.isUseOldDataToRoute() ? 1 : 0, channel.isUseRowDataToRoute() ? 1 : 0, - channel.isUsePkDataToRoute() ? 1 : 0, - channel.isContainsBigLob() ? 1 : 0, - channel.isEnabled() ? 1 : 0, channel.getBatchAlgorithm(), - channel.getExtractPeriodMillis() }); - } - if (reloadChannels) { - reloadChannels(); - } - } - - public void saveChannel(NodeChannel nodeChannel, boolean reloadChannels) { - saveChannel(nodeChannel.getChannel(), reloadChannels); - } - - public void saveNodeChannel(NodeChannel nodeChannel, boolean reloadChannels) { - saveChannel(nodeChannel.getChannel(), false); - saveNodeChannelControl(nodeChannel, reloadChannels); - } - - public void saveNodeChannelControl(NodeChannel nodeChannel, boolean reloadChannels) { - if (0 == jdbcTemplate.update(getSql("updateNodeChannelControlSql"), new Object[] { - nodeChannel.isSuspendEnabled() ? 1 : 0, nodeChannel.isIgnoreEnabled() ? 1 : 0, - nodeChannel.getLastExtractedTime(), nodeChannel.getNodeId(), - nodeChannel.getChannelId() })) { - jdbcTemplate.update(getSql("insertNodeChannelControlSql"), new Object[] { - nodeChannel.getNodeId(), nodeChannel.getChannelId(), - nodeChannel.isSuspendEnabled() ? 1 : 0, nodeChannel.isIgnoreEnabled() ? 1 : 0, - nodeChannel.getLastExtractedTime() }); - } - if (reloadChannels) { - reloadChannels(); - } - } - + return sqlTemplate.queryForInt(getSql("isChannelInUseSql"), channelId) > 0; + } + + public void saveChannel(Channel channel, boolean reloadChannels) { + if (0 == sqlTemplate.update( + getSql("updateChannelSql"), + new Object[] { channel.getProcessingOrder(), channel.getMaxBatchSize(), + channel.getMaxBatchToSend(), channel.getMaxDataToRoute(), + channel.isUseOldDataToRoute() ? 1 : 0, + channel.isUseRowDataToRoute() ? 1 : 0, + channel.isUsePkDataToRoute() ? 1 : 0, channel.isContainsBigLob() ? 1 : 0, + channel.isEnabled() ? 1 : 0, channel.getBatchAlgorithm(), + channel.getExtractPeriodMillis(), channel.getChannelId() })) { + sqlTemplate.update( + getSql("insertChannelSql"), + new Object[] { channel.getChannelId(), channel.getProcessingOrder(), + channel.getMaxBatchSize(), channel.getMaxBatchToSend(), + channel.getMaxDataToRoute(), channel.isUseOldDataToRoute() ? 1 : 0, + channel.isUseRowDataToRoute() ? 1 : 0, + channel.isUsePkDataToRoute() ? 1 : 0, + channel.isContainsBigLob() ? 1 : 0, channel.isEnabled() ? 1 : 0, + channel.getBatchAlgorithm(), channel.getExtractPeriodMillis() }); + } + if (reloadChannels) { + reloadChannels(); + } + } + + public void saveChannel(NodeChannel nodeChannel, boolean reloadChannels) { + saveChannel(nodeChannel.getChannel(), reloadChannels); + } + + public void saveNodeChannel(NodeChannel nodeChannel, boolean reloadChannels) { + saveChannel(nodeChannel.getChannel(), false); + saveNodeChannelControl(nodeChannel, reloadChannels); + } + + public void saveNodeChannelControl(NodeChannel nodeChannel, boolean reloadChannels) { + if (0 == sqlTemplate.update( + getSql("updateNodeChannelControlSql"), + new Object[] { nodeChannel.isSuspendEnabled() ? 1 : 0, + nodeChannel.isIgnoreEnabled() ? 1 : 0, nodeChannel.getLastExtractedTime(), + nodeChannel.getNodeId(), nodeChannel.getChannelId() })) { + sqlTemplate.update( + getSql("insertNodeChannelControlSql"), + new Object[] { nodeChannel.getNodeId(), nodeChannel.getChannelId(), + nodeChannel.isSuspendEnabled() ? 1 : 0, + nodeChannel.isIgnoreEnabled() ? 1 : 0, + nodeChannel.getLastExtractedTime() }); + } + if (reloadChannels) { + reloadChannels(); + } + } + public void deleteChannel(Channel channel) { - jdbcTemplate.update(getSql("deleteNodeChannelSql"), new Object[] { channel.getChannelId() }); - jdbcTemplate.update(getSql("deleteChannelSql"), new Object[] { channel.getChannelId() }); - reloadChannels(); - } - - public NodeChannel getNodeChannel(String channelId, boolean refreshExtractMillis) { - return getNodeChannel(channelId, nodeService.findIdentityNodeId(), refreshExtractMillis); - } - - public NodeChannel getNodeChannel(String channelId, String nodeId, boolean refreshExtractMillis) { - List channels = getNodeChannels(nodeId, refreshExtractMillis); - for (NodeChannel nodeChannel : channels) { - if (nodeChannel.getChannelId().equals(channelId)) { - return nodeChannel; - } - } - return null; - } - - public List getNodeChannels(boolean refreshExtractMillis) { - return getNodeChannels(nodeService.findIdentityNodeId(), refreshExtractMillis); - } - - public List getNodeChannels(final String nodeId, boolean refreshExtractMillis) { - boolean loaded = false; - long channelCacheTimeoutInMs = parameterService - .getLong(ParameterConstants.CACHE_TIMEOUT_CHANNEL_IN_MS); - List nodeChannels = nodeChannelCache != null ? nodeChannelCache.get(nodeId) : null; - if (System.currentTimeMillis() - nodeChannelCacheTime >= channelCacheTimeoutInMs - || nodeChannels == null) { - synchronized (this) { - if (System.currentTimeMillis() - nodeChannelCacheTime >= channelCacheTimeoutInMs - || nodeChannelCache == null || nodeChannelCache.get(nodeId) == null || nodeChannels == null) { - if (System.currentTimeMillis() - nodeChannelCacheTime >= channelCacheTimeoutInMs - || nodeChannelCache == null) { - nodeChannelCache = new HashMap>(); - nodeChannelCacheTime = System.currentTimeMillis(); - } - nodeChannels = jdbcTemplate.query(getSql("selectChannelsSql"), - new Object[] { nodeId }, new RowMapper() { - public NodeChannel mapRow(java.sql.ResultSet rs, int arg1) - throws SQLException { - NodeChannel nodeChannel = new NodeChannel(); - nodeChannel.setChannelId(rs.getString(1)); - nodeChannel.setNodeId(nodeId); - // note that 2 is intentionally missing here. - nodeChannel.setIgnoreEnabled(isSet(rs.getObject(3))); - nodeChannel.setSuspendEnabled(isSet(rs.getObject(4))); - nodeChannel.setProcessingOrder(rs.getInt(5)); - nodeChannel.setMaxBatchSize(rs.getInt(6)); - nodeChannel.setEnabled(rs.getBoolean(7)); - nodeChannel.setMaxBatchToSend(rs.getInt(8)); - nodeChannel.setMaxDataToRoute(rs.getInt(9)); - nodeChannel.setUseOldDataToRoute(rs.getBoolean(10)); - nodeChannel.setUseRowDataToRoute(rs.getBoolean(11)); - nodeChannel.setUsePkDataToRoute(rs.getBoolean(12)); - nodeChannel.setContainsBigLobs(rs.getBoolean(13)); - nodeChannel.setBatchAlgorithm(rs.getString(14)); - nodeChannel.setLastExtractedTime(rs.getTimestamp(15)); - nodeChannel.setExtractPeriodMillis(rs.getLong(16)); - return nodeChannel; - }; - }); - nodeChannelCache.put(nodeId, nodeChannels); - loaded = true; - } - } - } - - if (!loaded && refreshExtractMillis) { - // need to read last extracted time from database regardless of - // whether we used the cache or not. - // locate the nodes in the cache, and update it. - final Map nodeChannelsMap = new HashMap(); - - for (NodeChannel nc : nodeChannels) { - nodeChannelsMap.put(nc.getChannelId(), nc); - } - - jdbcTemplate.query(getSql("selectNodeChannelControlLastExtractTimeSql"), - new Object[] { nodeId }, new ResultSetExtractor() { - public Object extractData(ResultSet rs) throws SQLException, - DataAccessException { - if (rs.next()) { - String channelId = rs.getString(1); - Date extractTime = rs.getTimestamp(2); - nodeChannelsMap.get(channelId) - .setLastExtractedTime(extractTime); - } - return null; - }; - }); - - } - - return nodeChannels; - } - - public void reloadChannels() { - synchronized (this) { - nodeChannelCache = null; - } - } - - public NodeGroupLinkAction getDataEventActionByGroupLinkId(String sourceGroupId, - String targetGroupId) { - String code = (String) jdbcTemplate.queryForObject(getSql("selectDataEventActionsByIdSql"), - new Object[] { sourceGroupId, targetGroupId }, String.class); - - return NodeGroupLinkAction.fromCode(code); - } - - public void autoConfigDatabase(boolean force) { - if (parameterService.is(ParameterConstants.AUTO_CONFIGURE_DATABASE) || force) { - log.info("SymmetricDSDatabaseInitializing"); - symmetricDialect.initTablesAndFunctions(); - autoConfigChannels(); - autoConfigRegistrationServer(); - parameterService.rereadParameters(); - log.info("SymmetricDSDatabaseInitialized"); - } else { - log.info("SymmetricDSDatabaseNotAutoConfig"); - } - } - - protected void autoConfigChannels() { - if (defaultChannels != null) { - reloadChannels(); - List channels = getNodeChannels(false); - for (Channel defaultChannel : defaultChannels) { - if (!defaultChannel.isInList(channels)) { - log.info("ChannelAutoConfiguring", defaultChannel.getChannelId()); - saveChannel(defaultChannel, true); - } else { - log.debug("ChannelExists", defaultChannel.getChannelId()); - } - } - reloadChannels(); - } - } - - protected void autoConfigRegistrationServer() { - Node node = nodeService.findIdentity(); - - if (node == null) { - buildTablesFromDdlUtilXmlIfProvided(); - loadFromScriptIfProvided(); + sqlTemplate.update(getSql("deleteNodeChannelSql"), new Object[] { channel.getChannelId() }); + sqlTemplate.update(getSql("deleteChannelSql"), new Object[] { channel.getChannelId() }); + reloadChannels(); + } + + public NodeChannel getNodeChannel(String channelId, boolean refreshExtractMillis) { + return getNodeChannel(channelId, nodeService.findIdentityNodeId(), refreshExtractMillis); + } + + public NodeChannel getNodeChannel(String channelId, String nodeId, boolean refreshExtractMillis) { + List channels = getNodeChannels(nodeId, refreshExtractMillis); + for (NodeChannel nodeChannel : channels) { + if (nodeChannel.getChannelId().equals(channelId)) { + return nodeChannel; + } + } + return null; + } + + public List getNodeChannels(boolean refreshExtractMillis) { + return getNodeChannels(nodeService.findIdentityNodeId(), refreshExtractMillis); + } + + public List getNodeChannels(final String nodeId, boolean refreshExtractMillis) { + boolean loaded = false; + long channelCacheTimeoutInMs = parameterService + .getLong(ParameterConstants.CACHE_TIMEOUT_CHANNEL_IN_MS); + List nodeChannels = nodeChannelCache != null ? nodeChannelCache.get(nodeId) + : null; + if (System.currentTimeMillis() - nodeChannelCacheTime >= channelCacheTimeoutInMs + || nodeChannels == null) { + synchronized (this) { + if (System.currentTimeMillis() - nodeChannelCacheTime >= channelCacheTimeoutInMs + || nodeChannelCache == null || nodeChannelCache.get(nodeId) == null + || nodeChannels == null) { + if (System.currentTimeMillis() - nodeChannelCacheTime >= channelCacheTimeoutInMs + || nodeChannelCache == null) { + nodeChannelCache = new HashMap>(); + nodeChannelCacheTime = System.currentTimeMillis(); + } + nodeChannels = sqlTemplate.query(getSql("selectChannelsSql"), + new ISqlRowMapper() { + public NodeChannel mapRow(Row row) { + NodeChannel nodeChannel = new NodeChannel(); + nodeChannel.setChannelId(row.getString("channel_id")); + nodeChannel.setNodeId(nodeId); + // note that 2 is intentionally missing + // here. + nodeChannel.setIgnoreEnabled(row.getBoolean("ignore_enabled")); + nodeChannel.setSuspendEnabled(row.getBoolean("suspend_enabled")); + nodeChannel.setProcessingOrder(row.getInt("processing_order")); + nodeChannel.setMaxBatchSize(row.getInt("max_batch_size")); + nodeChannel.setEnabled(row.getBoolean("enabled")); + nodeChannel.setMaxBatchToSend(row.getInt("max_batch_to_send")); + nodeChannel.setMaxDataToRoute(row.getInt("max_data_to_route")); + nodeChannel.setUseOldDataToRoute(row + .getBoolean("use_old_data_to_route")); + nodeChannel.setUseRowDataToRoute(row + .getBoolean("use_row_data_to_route")); + nodeChannel.setUsePkDataToRoute(row + .getBoolean("use_pk_data_to_route")); + nodeChannel.setContainsBigLobs(row + .getBoolean("contains_big_lobs")); + nodeChannel.setBatchAlgorithm(row.getString("batch_algorithm")); + nodeChannel.setLastExtractedTime(row + .getDateTime("last_extracted_time")); + nodeChannel.setExtractPeriodMillis(row + .getLong("extract_period_millis")); + return nodeChannel; + }; + }, nodeId); + nodeChannelCache.put(nodeId, nodeChannels); + loaded = true; + } + } + } + + if (!loaded && refreshExtractMillis) { + // need to read last extracted time from database regardless of + // whether we used the cache or not. + // locate the nodes in the cache, and update it. + final Map nodeChannelsMap = new HashMap(); + + for (NodeChannel nc : nodeChannels) { + nodeChannelsMap.put(nc.getChannelId(), nc); + } + + sqlTemplate.query(getSql("selectNodeChannelControlLastExtractTimeSql"), + new ISqlRowMapper() { + public Object mapRow(Row row) { + String channelId = row.getString("channel_id"); + Date extractTime = row.getDateTime("last_extract_time"); + nodeChannelsMap.get(channelId).setLastExtractedTime(extractTime); + return null; + }; + }, nodeId); + + } + + return nodeChannels; + } + + public void reloadChannels() { + synchronized (this) { + nodeChannelCache = null; } - - node = nodeService.findIdentity(); - - if (node == null && StringUtils.isBlank(parameterService.getRegistrationUrl()) - && parameterService.is(ParameterConstants.AUTO_INSERT_REG_SVR_IF_NOT_FOUND, false)) { - log.info("AutoConfigRegistrationService"); - String nodeGroupId = parameterService.getNodeGroupId(); + } + + public NodeGroupLinkAction getDataEventActionByGroupLinkId(String sourceGroupId, + String targetGroupId) { + String code = (String) sqlTemplate.queryForObject(getSql("selectDataEventActionsByIdSql"), + String.class, sourceGroupId, targetGroupId); + return NodeGroupLinkAction.fromCode(code); + } + + public void autoConfigDatabase(boolean force) { + if (parameterService.is(ParameterConstants.AUTO_CONFIGURE_DATABASE) || force) { + log.info("SymmetricDSDatabaseInitializing"); + symmetricDialect.initTablesAndFunctions(); + autoConfigChannels(); + autoConfigRegistrationServer(); + parameterService.rereadParameters(); + log.info("SymmetricDSDatabaseInitialized"); + } else { + log.info("SymmetricDSDatabaseNotAutoConfig"); + } + } + + protected void autoConfigChannels() { + if (defaultChannels != null) { + reloadChannels(); + List channels = getNodeChannels(false); + for (Channel defaultChannel : defaultChannels) { + if (!defaultChannel.isInList(channels)) { + log.info("ChannelAutoConfiguring", defaultChannel.getChannelId()); + saveChannel(defaultChannel, true); + } else { + log.debug("ChannelExists", defaultChannel.getChannelId()); + } + } + reloadChannels(); + } + } + + protected void autoConfigRegistrationServer() { + Node node = nodeService.findIdentity(); + + if (node == null) { + buildTablesFromDdlUtilXmlIfProvided(); + loadFromScriptIfProvided(); + } + + node = nodeService.findIdentity(); + + if (node == null && StringUtils.isBlank(parameterService.getRegistrationUrl()) + && parameterService.is(ParameterConstants.AUTO_INSERT_REG_SVR_IF_NOT_FOUND, false)) { + log.info("AutoConfigRegistrationService"); + String nodeGroupId = parameterService.getNodeGroupId(); String nodeId = parameterService.getExternalId(); try { nodeService.insertNode(nodeId, nodeGroupId, nodeId, nodeId); } catch (DataIntegrityViolationException ex) { log.warn("AutoConfigNodeIdAlreadyExists", nodeId); - } - nodeService.insertNodeIdentity(nodeId); - node = nodeService.findIdentity(); - node.setSyncUrl(parameterService.getSyncUrl()); - node.setSyncEnabled(true); - node.setHeartbeatTime(new Date()); + } + nodeService.insertNodeIdentity(nodeId); + node = nodeService.findIdentity(); + node.setSyncUrl(parameterService.getSyncUrl()); + node.setSyncEnabled(true); + node.setHeartbeatTime(new Date()); nodeService.updateNode(node); - nodeService.insertNodeGroup(node.getNodeGroupId(), null); - NodeSecurity nodeSecurity = nodeService.findNodeSecurity(nodeId, true); - nodeSecurity.setInitialLoadTime(new Date()); - nodeSecurity.setRegistrationTime(new Date()); - nodeSecurity.setInitialLoadEnabled(false); - nodeSecurity.setRegistrationEnabled(false); - nodeService.updateNodeSecurity(nodeSecurity); - } - } - - private boolean buildTablesFromDdlUtilXmlIfProvided() { - boolean loaded = false; - String xml = parameterService - .getString(ParameterConstants.AUTO_CONFIGURE_REG_SVR_DDLUTIL_XML); - if (!StringUtils.isBlank(xml)) { - File file = new File(xml); - URL fileUrl = null; - if (file.isFile()) { - try { - fileUrl = file.toURI().toURL(); - } catch (MalformedURLException e) { - throw new RuntimeException(e); - } - } else { - fileUrl = getClass().getResource(xml); - } - - if (fileUrl != null) { - try { - log.info("DatabaseSchemaBuilding", xml); - Database database = new DatabaseIO().read(new InputStreamReader(fileUrl - .openStream())); + nodeService.insertNodeGroup(node.getNodeGroupId(), null); + NodeSecurity nodeSecurity = nodeService.findNodeSecurity(nodeId, true); + nodeSecurity.setInitialLoadTime(new Date()); + nodeSecurity.setRegistrationTime(new Date()); + nodeSecurity.setInitialLoadEnabled(false); + nodeSecurity.setRegistrationEnabled(false); + nodeService.updateNodeSecurity(nodeSecurity); + } + } + + private boolean buildTablesFromDdlUtilXmlIfProvided() { + boolean loaded = false; + String xml = parameterService + .getString(ParameterConstants.AUTO_CONFIGURE_REG_SVR_DDLUTIL_XML); + if (!StringUtils.isBlank(xml)) { + File file = new File(xml); + URL fileUrl = null; + if (file.isFile()) { + try { + fileUrl = file.toURI().toURL(); + } catch (MalformedURLException e) { + throw new RuntimeException(e); + } + } else { + fileUrl = getClass().getResource(xml); + } + + if (fileUrl != null) { + try { + log.info("DatabaseSchemaBuilding", xml); + Database database = new DatabaseIO().read(new InputStreamReader(fileUrl + .openStream())); IDatabasePlatform platform = symmetricDialect.getPlatform(); - platform.createDatabase(database, true, true); - loaded = true; - } catch (Exception e) { - log.error(e); - } - } - } - return loaded; - } - - /** - * Give the end user the option to provide a script that will load a - * registration server with an initial SymmetricDS setup. - * - * Look first on the file system, then in the classpath for the SQL file. - * - * @return true if the script was executed - */ - private boolean loadFromScriptIfProvided() { - boolean loaded = false; - String sqlScript = parameterService - .getString(ParameterConstants.AUTO_CONFIGURE_REG_SVR_SQL_SCRIPT); - if (!StringUtils.isBlank(sqlScript)) { - File file = new File(sqlScript); - URL fileUrl = null; - if (file.isFile()) { - try { - fileUrl = file.toURI().toURL(); - } catch (MalformedURLException e) { - throw new RuntimeException(e); - } - } else { - fileUrl = getClass().getResource(sqlScript); - if (fileUrl == null) { - fileUrl = Thread.currentThread().getContextClassLoader().getResource(sqlScript); - } - } - - if (fileUrl != null) { - new SqlScript(fileUrl, symmetricDialect.getPlatform().getSqlTemplate(), true).execute(); - loaded = true; - } - } - return loaded; - } - - public List getNodeGroupChannelWindows(String nodeGroupId, - String channelId) { - return (List) jdbcTemplate.query( - getSql("selectNodeGroupChannelWindowSql"), new Object[] { nodeGroupId, channelId }, - new NodeGroupChannelWindowMapper()); - } - - public ChannelMap getSuspendIgnoreChannelLists(final String nodeId) { - ChannelMap map = new ChannelMap(); - List ncs = getNodeChannels(nodeId, true); - - if (ncs != null) { - for (NodeChannel nc : ncs) { - if (nc.isSuspendEnabled()) { - map.addSuspendChannels(nc.getChannelId()); - } - if (nc.isIgnoreEnabled()) { - map.addIgnoreChannels(nc.getChannelId()); - } - } - } - return map; - } - + platform.createDatabase(database, true, true); + loaded = true; + } catch (Exception e) { + log.error(e); + } + } + } + return loaded; + } + + /** + * Give the end user the option to provide a script that will load a + * registration server with an initial SymmetricDS setup. + * + * Look first on the file system, then in the classpath for the SQL file. + * + * @return true if the script was executed + */ + private boolean loadFromScriptIfProvided() { + boolean loaded = false; + String sqlScript = parameterService + .getString(ParameterConstants.AUTO_CONFIGURE_REG_SVR_SQL_SCRIPT); + if (!StringUtils.isBlank(sqlScript)) { + File file = new File(sqlScript); + URL fileUrl = null; + if (file.isFile()) { + try { + fileUrl = file.toURI().toURL(); + } catch (MalformedURLException e) { + throw new RuntimeException(e); + } + } else { + fileUrl = getClass().getResource(sqlScript); + if (fileUrl == null) { + fileUrl = Thread.currentThread().getContextClassLoader().getResource(sqlScript); + } + } + + if (fileUrl != null) { + new SqlScript(fileUrl, symmetricDialect.getPlatform().getSqlTemplate(), true) + .execute(); + loaded = true; + } + } + return loaded; + } + + public List getNodeGroupChannelWindows(String nodeGroupId, + String channelId) { + return (List) sqlTemplate.query( + getSql("selectNodeGroupChannelWindowSql"), new NodeGroupChannelWindowMapper(), + nodeGroupId, channelId); + } + + public ChannelMap getSuspendIgnoreChannelLists(final String nodeId) { + ChannelMap map = new ChannelMap(); + List ncs = getNodeChannels(nodeId, true); + + if (ncs != null) { + for (NodeChannel nc : ncs) { + if (nc.isSuspendEnabled()) { + map.addSuspendChannels(nc.getChannelId()); + } + if (nc.isIgnoreEnabled()) { + map.addIgnoreChannels(nc.getChannelId()); + } + } + } + return map; + } + public Channel getChannel(String channelId) { NodeChannel nodeChannel = getNodeChannel(channelId, false); if (nodeChannel != null) { @@ -461,56 +484,53 @@ public Channel getChannel(String channelId) { } else { return null; } - } - - public ChannelMap getSuspendIgnoreChannelLists() { - return getSuspendIgnoreChannelLists(nodeService.findIdentityNodeId()); - } - + + public ChannelMap getSuspendIgnoreChannelLists() { + return getSuspendIgnoreChannelLists(nodeService.findIdentityNodeId()); + + } + @Override protected AbstractSqlMap createSqlMap() { return new ConfigurationServiceSqlMap(symmetricDialect.getPlatform(), - createReplacementTokens()); - } - - public void setDefaultChannels(List defaultChannels) { - this.defaultChannels = defaultChannels; - } - - public void setNodeService(INodeService nodeService) { - this.nodeService = nodeService; - } - - class NodeGroupChannelWindowMapper implements RowMapper { - public NodeGroupChannelWindow mapRow(ResultSet rs, int rowNum) throws SQLException { - NodeGroupChannelWindow window = new NodeGroupChannelWindow(); - window.setNodeGroupId(rs.getString(1)); - window.setChannelId(rs.getString(2)); - window.setStartTime(rs.getTime(3)); - window.setEndTime(rs.getTime(4)); - window.setEnabled(rs.getBoolean(5)); - return window; - } - } - - class NodeGroupLinkMapper implements RowMapper { - public NodeGroupLink mapRow(ResultSet rs, int num) throws SQLException { - NodeGroupLink link = new NodeGroupLink(); - link.setSourceNodeGroupId(rs.getString(1)); - link.setTargetNodeGroupId(rs.getString(2)); - link.setDataEventAction(NodeGroupLinkAction.fromCode(rs.getString(3))); - return link; - } - } - - class NodeGroupMapper implements RowMapper { - public NodeGroup mapRow(ResultSet rs, int num) throws SQLException { + createSqlReplacementTokens()); + } + + class NodeGroupChannelWindowMapper implements ISqlRowMapper { + public NodeGroupChannelWindow mapRow(Row row) { + NodeGroupChannelWindow window = new NodeGroupChannelWindow(); + window.setNodeGroupId(row.getString("node_group_id")); + window.setChannelId(row.getString("channel_id")); + window.setStartTime(row.getTime("start_time")); + window.setEndTime(row.getTime("end_time")); + window.setEnabled(row.getBoolean("enabled")); + return window; + } + } + + class NodeGroupLinkMapper implements ISqlRowMapper { + public NodeGroupLink mapRow(Row row) { + NodeGroupLink link = new NodeGroupLink(); + link.setSourceNodeGroupId(row.getString("source_node_group_id")); + link.setTargetNodeGroupId(row.getString("target_node_group_id")); + link.setDataEventAction(NodeGroupLinkAction.fromCode(row.getString("data_event_action"))); + return link; + } + } + + class NodeGroupMapper implements ISqlRowMapper { + public NodeGroup mapRow(Row row) { NodeGroup group = new NodeGroup(); - group.setNodeGroupId(rs.getString(1)); - group.setDescription(rs.getString(2)); + group.setNodeGroupId(row.getString("node_group_id")); + group.setDescription(row.getString("description")); return group; } - } - + } + + public Map getRegistrationRedirectMap() { + return this.sqlTemplate.queryForMap(getSql("getRegistrationRedirectSql"), + "registrant_external_id", "registration_node_id"); + } + } \ No newline at end of file diff --git a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/impl/ConfigurationServiceSqlMap.java b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/impl/ConfigurationServiceSqlMap.java index 5d31fb2b4a..6f373334dd 100644 --- a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/impl/ConfigurationServiceSqlMap.java +++ b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/impl/ConfigurationServiceSqlMap.java @@ -89,6 +89,9 @@ public ConfigurationServiceSqlMap(IDatabasePlatform platform, Map extractedBatchesHandle = new HashMap(); - private List extractorFilters; + private Set extractingNodes = new HashSet(); - private IStatisticManager statisticManager; + public DataExtractorService(IParameterService parameterService, + ISymmetricDialect symmetricDialect, IOutgoingBatchService outgoingBatchService, + IRouterService routingService, IConfigurationService configurationService, + ITriggerRouterService triggerRouterService, INodeService nodeService, + IStatisticManager statisticManager) { + super(parameterService, symmetricDialect); + this.outgoingBatchService = outgoingBatchService; + this.routerService = routingService; + this.configurationService = configurationService; + this.triggerRouterService = triggerRouterService; + this.nodeService = nodeService; + this.statisticManager = statisticManager; + } - private Map extractedBatchesHandle = new HashMap(); - - private Set extractingNodes = new HashSet(); + @Override + protected AbstractSqlMap createSqlMap() { + return null; + } /** * @see DataExtractorService#extractConfigurationStandalone(Node, Writer) @@ -142,65 +138,36 @@ public void extractConfigurationStandalone(Node node, OutputStream out, */ public void extractConfigurationStandalone(Node node, Writer writer, String... tablesToExclude) throws IOException { - try { - OutgoingBatch batch = new OutgoingBatch(node.getNodeId(), Constants.CHANNEL_CONFIG, - Status.NE); - if (Version.isOlderThanVersion(node.getSymmetricVersion(), - UpgradeConstants.VERSION_FOR_NEW_REGISTRATION_PROTOCOL)) { - outgoingBatchService.insertOutgoingBatch(batch); - // acknowledge right away, because the acknowledgment is not - // built into the registration protocol. - acknowledgeService.ack(batch.getBatchInfo()); - } else { - batch.setBatchId(BatchInfo.VIRTUAL_BATCH_FOR_REGISTRATION); - } - - final IDataExtractor dataExtractor = getDataExtractor(node.getSymmetricVersion()); - final DataExtractorContext ctxCopy = clonableContext.copy(dataExtractor); - - dataExtractor.init(writer, ctxCopy); - - dataExtractor.begin(batch, writer); - - extractConfiguration(node, writer, ctxCopy, tablesToExclude); + Batch batch = new Batch(BatchInfo.VIRTUAL_BATCH_FOR_REGISTRATION, Constants.CHANNEL_CONFIG, + symmetricDialect.getBinaryEncoding(), node.getNodeId()); - dataExtractor.commit(batch, writer); - - } finally { - writer.flush(); - } - } - - public void extractConfiguration(Node node, Writer writer, DataExtractorContext ctx, - String... tablesToExclude) throws IOException { NodeGroupLink nodeGroupLink = new NodeGroupLink(parameterService.getNodeGroupId(), node.getNodeGroupId()); + List triggerRouters = triggerRouterService.getTriggerRoutersForRegistration( StringUtils.isBlank(node.getSymmetricVersion()) ? Version.version() : node .getSymmetricVersion(), nodeGroupLink, tablesToExclude); - final IDataExtractor dataExtractor = ctx != null ? ctx.getDataExtractor() - : getDataExtractor(node.getSymmetricVersion()); - - if (node.isVersionGreaterThanOrEqualTo(1, 5, 0)) { - for (int i = triggerRouters.size() - 1; i >= 0; i--) { - TriggerRouter triggerRouter = triggerRouters.get(i); - TriggerHistory triggerHistory = triggerRouterService - .getNewestTriggerHistoryForTrigger(triggerRouter.getTrigger() - .getTriggerId()); - if (triggerHistory == null) { - triggerHistory = new TriggerHistory(symmetricDialect.getTable( - triggerRouter.getTrigger(), false), triggerRouter.getTrigger()); - triggerHistory.setTriggerHistoryId(Integer.MAX_VALUE - i); - } - StringBuilder sql = new StringBuilder(symmetricDialect.createPurgeSqlFor(node, - triggerRouter)); - addPurgeCriteriaToConfigurationTables(triggerRouter.getTrigger() - .getSourceTableName(), sql); - String sourceTable = triggerHistory.getSourceTableName(); - Data data = new Data(1, null, sql.toString(), DataEventType.SQL, sourceTable, null, - triggerHistory, triggerRouter.getTrigger().getChannelId(), null, null); - dataExtractor.write(writer, data, triggerRouter.getRouter().getRouterId(), ctx); + + List initialLoadEvents = new ArrayList( + triggerRouters.size()); + + for (int i = triggerRouters.size() - 1; i >= 0; i--) { + TriggerRouter triggerRouter = triggerRouters.get(i); + TriggerHistory triggerHistory = triggerRouterService + .getNewestTriggerHistoryForTrigger(triggerRouter.getTrigger().getTriggerId()); + if (triggerHistory == null) { + triggerHistory = new TriggerHistory(symmetricDialect.getTable( + triggerRouter.getTrigger(), false), triggerRouter.getTrigger()); + triggerHistory.setTriggerHistoryId(Integer.MAX_VALUE - i); } + StringBuilder sql = new StringBuilder(symmetricDialect.createPurgeSqlFor(node, + triggerRouter)); + addPurgeCriteriaToConfigurationTables(triggerRouter.getTrigger().getSourceTableName(), + sql); + String sourceTable = triggerHistory.getSourceTableName(); + Data data = new Data(1, null, sql.toString(), DataEventType.SQL, sourceTable, null, + triggerHistory, triggerRouter.getTrigger().getChannelId(), null, null); + initialLoadEvents.add(new InitialLoadEvent(data)); } for (int i = 0; i < triggerRouters.size(); i++) { @@ -208,31 +175,41 @@ public void extractConfiguration(Node node, Writer writer, DataExtractorContext TriggerHistory triggerHistory = triggerRouterService .getNewestTriggerHistoryForTrigger(triggerRouter.getTrigger().getTriggerId()); if (triggerHistory == null) { - triggerHistory = new TriggerHistory(symmetricDialect.getTable(triggerRouter.getTrigger(), - false), triggerRouter.getTrigger()); + triggerHistory = new TriggerHistory(symmetricDialect.getTable( + triggerRouter.getTrigger(), false), triggerRouter.getTrigger()); triggerHistory.setTriggerHistoryId(Integer.MAX_VALUE - i); } if (!triggerRouter.getTrigger().getSourceTableName() .endsWith(TableConstants.SYM_NODE_IDENTITY)) { - writeInitialLoad(node, triggerRouter, triggerHistory, writer, ctx); + initialLoadEvents.add(new InitialLoadEvent(node, triggerRouter, triggerHistory)); } else { Data data = new Data(1, null, node.getNodeId(), DataEventType.INSERT, triggerHistory.getSourceTableName(), null, triggerHistory, triggerRouter .getTrigger().getChannelId(), null, null); - dataExtractor.write(writer, data, triggerRouter.getRouter().getRouterId(), ctx); + initialLoadEvents.add(new InitialLoadEvent(data)); } } + InitialLoadSource source = new InitialLoadSource(batch, initialLoadEvents); + SourcedCsvDataReader dataReader = new SourcedCsvDataReader( + this.symmetricDialect.getPlatform(), source); + CsvDataWriter dataWriter = new CsvDataWriter(writer); + DataProcessor processor = new DataProcessor( + dataReader, dataWriter); + processor.process(); + if (triggerRouters.size() == 0) { - log.error("RegistrationEmpty", node); + log.error("%s attempted registration, but was sent an empty configuration", node); } + } private void addPurgeCriteriaToConfigurationTables(String sourceTableName, StringBuilder sql) { - if ((TableConstants.getTableName(symmetricDialect.getTablePrefix(), TableConstants.SYM_NODE) + if ((TableConstants + .getTableName(parameterService.getTablePrefix(), TableConstants.SYM_NODE) .equalsIgnoreCase(sourceTableName)) - || TableConstants.getTableName(symmetricDialect.getTablePrefix(), + || TableConstants.getTableName(parameterService.getTablePrefix(), TableConstants.SYM_NODE_SECURITY).equalsIgnoreCase(sourceTableName)) { Node me = nodeService.findIdentity(); if (me != null) { @@ -241,210 +218,6 @@ private void addPurgeCriteriaToConfigurationTables(String sourceTableName, Strin } } - private IDataExtractor getDataExtractor(String version) { - String beanName = Constants.DATA_EXTRACTOR; - // Version 1.4.1-appaji accepts "old" token, so it's like a 1.5 version - if (version != null) { - int[] versions = Version.parseVersion(version); - if (versions[0] == 1) { - if (versions[1] <= 2) { - beanName += "10"; - } else if (versions[1] <= 3) { - beanName += "13"; - } else if (versions[1] <= 4 && !version.equals("1.4.1-appaji")) { - beanName += "14"; - } else if (versions[1] <= 7) { - beanName += "16"; - } - } - } - return (IDataExtractor) beanFactory.getBean(beanName); - } - - public void extractInitialLoadWithinBatchFor(Node node, final TriggerRouter trigger, - Writer writer, DataExtractorContext ctx, TriggerHistory triggerHistory) { - writeInitialLoad(node, trigger, triggerHistory, writer, ctx); - } - - /** - * @param batch - * If null, then assume this 'initial load' is part of another - * batch. - */ - /** - * @param node - * @param triggerRouter - * @param triggerHistory - * @param writer - * @param ctx - */ - protected void writeInitialLoad(final Node node, final TriggerRouter triggerRouter, - TriggerHistory triggerHistory, final Writer writer, final DataExtractorContext ctx) { - - triggerHistory = triggerHistory != null ? triggerHistory : triggerRouterService - .getNewestTriggerHistoryForTrigger(triggerRouter.getTrigger().getTriggerId()); - - final boolean newExtractorCreated = ctx == null || ctx.getDataExtractor() == null; - - final IDataExtractor dataExtractor = !newExtractorCreated ? ctx.getDataExtractor() - : getDataExtractor(node.getSymmetricVersion()); - - String tableNameToSend = dataExtractor.getLegacyTableName(triggerRouter.getTrigger().getSourceTableName()); - - // The table to use for the SQL may be different than the configured - // table if there is a legacy table that is swapped out by the dataExtractor. - Table tableForSql = symmetricDialect.getPlatform().getTableFromCache(triggerRouter.getTrigger().getSourceCatalogName(), - triggerRouter.getTrigger().getSourceSchemaName(), tableNameToSend, - false); - - if (tableForSql == null) { - throw new RuntimeException( - String.format("Could not find the table, %s, to extract", Table - .getFullyQualifiedTableName(triggerRouter.getTrigger() - .getSourceCatalogName(), triggerRouter.getTrigger() - .getSourceSchemaName(), tableNameToSend))); - } - - final String sql = symmetricDialect.createInitialLoadSqlFor(node, triggerRouter, tableForSql, - triggerHistory, - configurationService.getChannel(triggerRouter.getTrigger().getChannelId())); - - log.debug("Sql", sql); - - if (!tableForSql.getName().equals(triggerHistory.getSourceTableName())) { - // This is to make legacy tables backwards compatible - String tableName = triggerHistory.getSourceTableName(); - triggerHistory = new TriggerHistory(tableForSql, triggerRouter.getTrigger()); - triggerHistory.setSourceTableName(tableName); - } - - final TriggerHistory triggerHistory2Use = triggerHistory; - - jdbcTemplate.execute(new ConnectionCallback() { - public Object doInConnection(Connection conn) throws SQLException, DataAccessException { - try { - OutgoingBatch batch = ctx.getBatch(); - Table table = symmetricDialect.getTable(triggerRouter.getTrigger(), true); - NodeChannel channel = batch != null ? configurationService.getNodeChannel( - batch.getChannelId(), false) : new NodeChannel(triggerRouter - .getTrigger().getChannelId()); - Set oneNodeSet = new HashSet(); - oneNodeSet.add(node); - - boolean autoCommitFlag = conn.getAutoCommit(); - PreparedStatement st = null; - ResultSet rs = null; - try { - - if (symmetricDialect.requiresAutoCommitFalseToSetFetchSize()) { - conn.setAutoCommit(false); - } - - st = conn.prepareStatement(sql, java.sql.ResultSet.TYPE_FORWARD_ONLY, - java.sql.ResultSet.CONCUR_READ_ONLY); - st.setQueryTimeout(jdbcTemplate.getQueryTimeout()); - st.setFetchSize(symmetricDialect.getStreamingResultsFetchSize()); - long ts = System.currentTimeMillis(); - rs = st.executeQuery(); - long executeTimeInMs = System.currentTimeMillis() - ts; - if (executeTimeInMs > Constants.LONG_OPERATION_THRESHOLD) { - log.warn( - "LongRunningOperation", - "selecting initial load to extract for batch " - + batch.getBatchId(), executeTimeInMs); - } - final DataExtractorContext ctxCopy = ctx == null ? clonableContext - .copy(dataExtractor) : ctx; - if (newExtractorCreated) { - dataExtractor.init(writer, ctxCopy); - dataExtractor.begin(batch, writer); - } - SimpleRouterContext routingContext = new SimpleRouterContext(node - .getNodeId(), jdbcTemplate, channel); - int dataNotRouted = 0; - int dataRouted = 0; - ts = System.currentTimeMillis(); - boolean useReloadChannel = parameterService - .is(ParameterConstants.INITIAL_LOAD_USE_RELOAD_CHANNEL); - while (rs.next()) { - Data data = new Data(0, null, rs.getString(1), DataEventType.INSERT, - triggerHistory2Use.getSourceTableName(), null, - triggerHistory2Use, useReloadChannel ? Constants.CHANNEL_RELOAD - : triggerRouter.getTrigger().getChannelId(), null, null); - boolean writeData = true; - String routerId = triggerRouter.getRouter().getRouterId(); - if (extractorFilters != null) { - for (IExtractorFilter filter : extractorFilters) { - if (!filter.filterData(data, routerId, ctx)) { - writeData = false; - break; - } - } - } - DataMetaData dataMetaData = new DataMetaData(data, table, - triggerRouter, channel); - writeData &= !StringUtils.isBlank(triggerRouter.getInitialLoadSelect()) - || routingService.shouldDataBeRouted(routingContext, - dataMetaData, oneNodeSet, true); - if (writeData) { -// List transformedData = transformDataExtractor.transformData( -// data, routerId, ctx); -// if (transformedData != null) { -// for (Data data2 : transformedData) { -// dataExtractor.write(writer, data2, routerId, ctxCopy); -// dataRouted++; -// } -// } else - { - dataExtractor.write(writer, data, routerId, ctxCopy); - dataRouted++; - } - - } else { - dataNotRouted++; - } - - executeTimeInMs = System.currentTimeMillis() - ts; - if (executeTimeInMs > DateUtils.MILLIS_PER_MINUTE * 10) { - log.warn("LongRunningOperation", "initial load extracted " - + (dataRouted + dataNotRouted) + " data so far for batch " - + batch.getBatchId(), executeTimeInMs); - ts = System.currentTimeMillis(); - } - - } - if (dataNotRouted > 0) { - log.info("RouterInitialLoadNotRouted", dataNotRouted, triggerRouter - .getTrigger().getSourceTableName()); - } - if (newExtractorCreated) { - dataExtractor.commit(batch, writer); - } - } finally { - if (symmetricDialect.requiresAutoCommitFalseToSetFetchSize()) { - conn.commit(); - conn.setAutoCommit(autoCommitFlag); - } - JdbcUtils.closeResultSet(rs); - JdbcUtils.closeStatement(st); - } - return null; - } catch (SQLException e) { - throw new RuntimeException(e.getSQLState() + "Error during SQL: " + sql, e); - } catch (Exception e) { - throw new RuntimeException("Error during SQL: " + sql, e); - } - } - }); - } - - private ExtractStreamHandler createExtractStreamHandler(IDataExtractor dataExtractor, - Writer extractWriter) throws IOException { - return new ExtractStreamHandler(dataExtractor, new DataExtractorStatisticsWriter( - statisticManager, extractWriter, StatisticConstants.FLUSH_SIZE_BYTES, - StatisticConstants.FLUSH_SIZE_LINES)); - } - private List filterBatchesForExtraction(OutgoingBatches batches, ChannelMap suspendIgnoreChannelsList) { @@ -486,14 +259,15 @@ public List extract(Node node, IOutgoingTransport targetTransport List activeBatches = null; - if (!extractingNodes.contains(node.getNodeId())) { + if (!extractingNodes.contains(node.getNodeId())) { try { extractingNodes.add(node.getNodeId()); - - IDataExtractor dataExtractor = getDataExtractor(node.getSymmetricVersion()); + // make sure that data is routed before extracting if the route + // job + // is not configured to start automatically if (!parameterService.is(ParameterConstants.START_ROUTE_JOB)) { - routingService.routeData(); + routerService.routeData(); } OutgoingBatches batches = outgoingBatchService.getOutgoingBatches(node); @@ -506,29 +280,28 @@ public List extract(Node node, IOutgoingTransport targetTransport if (activeBatches.size() > 0) { - Writer extractWriter = null; - BufferedWriter networkWriter = null; - boolean streamToFileEnabled = parameterService .is(ParameterConstants.STREAM_TO_FILE_ENABLED); - ThresholdFileWriter fileWriter = new ThresholdFileWriter( - parameterService - .getLong(ParameterConstants.STREAM_TO_FILE_THRESHOLD), - "extract"); + IDataWriter extractWriter = null; if (streamToFileEnabled) { - extractWriter = new BufferedWriter(fileWriter); - networkWriter = targetTransport.open(); + long memoryThresholdInBytes = parameterService + .getLong(ParameterConstants.STREAM_TO_FILE_THRESHOLD); + extractWriter = new FileCsvDataWriter(new File( + System.getProperty("java.io.tmpdir")), memoryThresholdInBytes, + new ICsvDataWriterListener() { + public void start(Batch batch) { + } + + public void end(Batch batch, IoResource resource) { + extractedBatchesHandle.put(batch.getBatchId(), resource); + } + }); } else { - extractWriter = targetTransport.open(); + extractWriter = new CsvDataWriter(targetTransport.open()); } - ExtractStreamHandler handler = createExtractStreamHandler(dataExtractor, - extractWriter); - - handler.init(); - OutgoingBatch currentBatch = null; try { final long maxBytesToSync = parameterService @@ -536,101 +309,101 @@ public List extract(Node node, IOutgoingTransport targetTransport long bytesSentCount = 0; int batchesSentCount = 0; for (OutgoingBatch outgoingBatch : activeBatches) { - try { - if (System.currentTimeMillis() - batchesSelectedAtMs > MS_PASSED_BEFORE_BATCH_REQUERIED) { - outgoingBatch = outgoingBatchService - .findOutgoingBatch(outgoingBatch.getBatchId()); + if (System.currentTimeMillis() - batchesSelectedAtMs > MS_PASSED_BEFORE_BATCH_REQUERIED) { + outgoingBatch = outgoingBatchService + .findOutgoingBatch(outgoingBatch.getBatchId()); + } + + currentBatch = outgoingBatch; + + if (outgoingBatch.getStatus() != Status.OK) { + IoResource previouslyExtracted = extractedBatchesHandle + .get(currentBatch.getBatchId()); + if (previouslyExtracted != null && previouslyExtracted.exists()) { + log.info("DataExtractorUsingAlreadyExtractedBatch", + currentBatch.getBatchId()); + } else { + outgoingBatch.setStatus(OutgoingBatch.Status.QY); + outgoingBatch.setExtractCount(outgoingBatch + .getExtractCount() + 1); + outgoingBatchService.updateOutgoingBatch(outgoingBatch); + + IDataReader dataReader = new SourcedCsvDataReader( + symmetricDialect.getPlatform(), + new SelectBatchSource(outgoingBatch)); + + new DataProcessor(dataReader, + extractWriter).process(); } - currentBatch = outgoingBatch; + if (System.currentTimeMillis() + - outgoingBatch.getLastUpdatedTime().getTime() > MS_PASSED_BEFORE_BATCH_REQUERIED) { + outgoingBatch = outgoingBatchService + .findOutgoingBatch(currentBatch.getBatchId()); + outgoingBatch.setExtractMillis(currentBatch + .getExtractMillis()); + currentBatch = outgoingBatch; + } if (outgoingBatch.getStatus() != Status.OK) { - fileWriter.reset(); - File previouslyExtracted = extractedBatchesHandle - .get(currentBatch.getBatchId()); - if (previouslyExtracted != null - && previouslyExtracted.exists()) { - log.info("DataExtractorUsingAlreadyExtractedBatch", - currentBatch.getBatchId()); - fileWriter.setFile(previouslyExtracted); - } else { - outgoingBatch.setStatus(OutgoingBatch.Status.QY); - outgoingBatch.setExtractCount(outgoingBatch - .getExtractCount() + 1); - outgoingBatchService.updateOutgoingBatch(outgoingBatch); - databaseExtract(node, outgoingBatch, handler, - networkWriter); + outgoingBatch.setStatus(OutgoingBatch.Status.SE); + outgoingBatch + .setSentCount(outgoingBatch.getSentCount() + 1); + outgoingBatchService.updateOutgoingBatch(outgoingBatch); + + IoResource extractedBatch = extractedBatchesHandle + .get(outgoingBatch.getBatchId()); + if (extractedBatch != null) { + IDataReader dataReader = new TextualCsvDataReader( + extractedBatch.open()); + IDataWriter dataWriter = new CsvDataWriter( + targetTransport.open()); + new DataProcessor(dataReader, + dataWriter).process(); } if (System.currentTimeMillis() - outgoingBatch.getLastUpdatedTime().getTime() > MS_PASSED_BEFORE_BATCH_REQUERIED) { outgoingBatch = outgoingBatchService .findOutgoingBatch(currentBatch.getBatchId()); - outgoingBatch.setExtractMillis(currentBatch - .getExtractMillis()); currentBatch = outgoingBatch; } if (outgoingBatch.getStatus() != Status.OK) { - outgoingBatch.setStatus(OutgoingBatch.Status.SE); + outgoingBatch.setStatus(OutgoingBatch.Status.LD); outgoingBatch - .setSentCount(outgoingBatch.getSentCount() + 1); + .setLoadCount(outgoingBatch.getLoadCount() + 1); outgoingBatchService.updateOutgoingBatch(outgoingBatch); - File file = fileWriter.getFile(); - if (file != null) { - extractedBatchesHandle.put( - currentBatch.getBatchId(), file); - } - - fileWriter.close(); + bytesSentCount += outgoingBatch.getByteCount(); + batchesSentCount++; - networkTransfer(fileWriter.getReader(), networkWriter); - - if (System.currentTimeMillis() - - outgoingBatch.getLastUpdatedTime().getTime() > MS_PASSED_BEFORE_BATCH_REQUERIED) { - outgoingBatch = outgoingBatchService - .findOutgoingBatch(currentBatch - .getBatchId()); - currentBatch = outgoingBatch; + if (bytesSentCount >= maxBytesToSync) { + log.info( + "DataExtractorReachedMaxNumberOfBytesToSync", + batchesSentCount, bytesSentCount); + break; } - if (outgoingBatch.getStatus() != Status.OK) { - outgoingBatch.setStatus(OutgoingBatch.Status.LD); - outgoingBatch.setLoadCount(outgoingBatch - .getLoadCount() + 1); - outgoingBatchService - .updateOutgoingBatch(outgoingBatch); - - bytesSentCount += outgoingBatch.getByteCount(); - batchesSentCount++; - - if (bytesSentCount >= maxBytesToSync) { - log.info( - "DataExtractorReachedMaxNumberOfBytesToSync", - batchesSentCount, bytesSentCount); - break; - } - } } - } - } finally { - // It doesn't hurt anything to call close - // and delete a second time - fileWriter.close(); - - } - } - - for (OutgoingBatch outgoingBatch : activeBatches) { - File file = extractedBatchesHandle.remove(outgoingBatch.getBatchId()); - if (file != null && file.exists()) { - fileWriter.delete(); } + } - + + // TODO should be deleting handles here or when the + // ack comes back + // for (OutgoingBatch outgoingBatch : activeBatches) + // { + // File file = + // extractedBatchesHandle.remove(outgoingBatch + // .getBatchId()); + // if (file != null && file.exists()) { + // fileWriter.delete(); + // } + // } + } catch (Exception e) { SQLException se = unwrapSqlException(e); if (currentBatch != null) { @@ -659,8 +432,6 @@ public List extract(Node node, IOutgoingTransport targetTransport throw new RuntimeException(e); } - } finally { - handler.done(); } // Next, we update the node channel controls to the @@ -685,265 +456,210 @@ public List extract(Node node, IOutgoingTransport targetTransport } - protected void networkTransfer(BufferedReader reader, BufferedWriter writer) throws IOException { - if (reader != null && writer != null) { - CsvReader csvReader = CsvUtils.getCsvReader(reader); - String channelId = null; - long lineCount = 0; - long byteCount = 0; - try { - String nextLine = null; - while (csvReader.readRecord()) { - nextLine = csvReader.getRawRecord(); - if (nextLine != null) { - lineCount++; - byteCount += nextLine.length(); - if (nextLine.startsWith(CsvConstants.CHANNEL)) { - String[] csv = StringUtils.split(nextLine, ","); - if (csv.length > 1) { - if (channelId != null) { - statisticManager.incrementDataBytesSent(channelId, byteCount); - statisticManager.incrementDataSent(channelId, lineCount); - } - channelId = csv[1].trim(); - byteCount = 0; - lineCount = 0; - } - } - writer.write(nextLine); - CsvUtils.writeLineFeed(writer); + public boolean extractBatchRange(IOutgoingTransport transport, String startBatchId, + String endBatchId) throws IOException { + // TODO + return false; + } - if (!StringUtils.isBlank(channelId)) { - if (byteCount > StatisticConstants.FLUSH_SIZE_BYTES) { - statisticManager.incrementDataBytesSent(channelId, byteCount); - byteCount = 0; - } + class InitialLoadEvent { - if (lineCount > StatisticConstants.FLUSH_SIZE_LINES) { - statisticManager.incrementDataSent(channelId, lineCount); - lineCount = 0; - } - } - } - } + private TriggerRouter triggerRouter; + private TriggerHistory triggerHistory; + private Node node; + private Data data; - writer.flush(); + public InitialLoadEvent(Node node, TriggerRouter triggerRouter, + TriggerHistory triggerHistory) { + this.node = node; + this.triggerRouter = triggerRouter; + this.triggerHistory = triggerHistory != null ? triggerHistory : triggerRouterService + .getNewestTriggerHistoryForTrigger(triggerRouter.getTrigger().getTriggerId()); + } - } finally { - csvReader.close(); - IOUtils.closeQuietly(reader); - if (!StringUtils.isBlank(channelId)) { - if (byteCount > 0) { - statisticManager.incrementDataBytesSent(channelId, byteCount); - } + public InitialLoadEvent(Data data) { + this.data = data; + this.triggerHistory = data.getTriggerHistory(); + } - if (lineCount > 0) { - statisticManager.incrementDataSent(channelId, lineCount); - } - } - } + public TriggerHistory getTriggerHistory() { + return triggerHistory; } - } - /** - * Allow a handler callback to do the work so we can route the extracted - * data to other types of handlers for processing. - */ - protected void databaseExtract(Node node, OutgoingBatch batch, final IExtractListener handler, - BufferedWriter keepaliveWriter) throws IOException { - batch.resetStats(); - long ts = System.currentTimeMillis(); - handler.startBatch(batch); - selectEventDataToExtract(handler, batch, keepaliveWriter); - handler.endBatch(batch); - batch.setExtractMillis(System.currentTimeMillis() - ts); - } + public TriggerRouter getTriggerRouter() { + return triggerRouter; + } - public boolean extractBatchRange(IOutgoingTransport transport, String startBatchId, - String endBatchId) throws IOException { - IDataExtractor dataExtractor = getDataExtractor(null); - ExtractStreamHandler handler = createExtractStreamHandler(dataExtractor, transport.open()); - ; - return extractBatchRange(handler, startBatchId, endBatchId); - } + public Data getData() { + return data; + } - private boolean areNumeric(String... data) { - if (data != null) { - for (String string : data) { - try { - Long.parseLong(string); - } catch (NumberFormatException e) { - return false; - } - } + public Node getNode() { + return node; } - return true; - } - public boolean extractBatchRange(final IExtractListener handler, String startBatchId, - String endBatchId) throws IOException { - if (areNumeric(startBatchId, endBatchId)) { - OutgoingBatches batches = outgoingBatchService.getOutgoingBatchRange(startBatchId, - endBatchId); - - if (batches != null && batches.getBatches() != null && batches.getBatches().size() > 0) { - try { - handler.init(); - for (final OutgoingBatch batch : batches.getBatches()) { - handler.startBatch(batch); - selectEventDataToExtract(handler, batch, null); - handler.endBatch(batch); - } - } finally { - handler.done(); - } - return true; - } + public boolean containsData() { + return data != null; } - return false; - } - private void selectEventDataToExtract(final IExtractListener handler, - final OutgoingBatch batch, final BufferedWriter keepAliveWriter) { - final long flushForKeepAliveInMs = parameterService.getLong( - ParameterConstants.DATA_EXTRACTOR_FLUSH_FOR_KEEP_ALIVE, -1); - dataService.handleDataSelect(batch.getBatchId(), -1, batch.getChannelId(), false, - new IModelRetrievalHandler() { - long lastKeepAliveFlush = System.currentTimeMillis(); - String nodeId = nodeService.findIdentityNodeId(); - - public boolean retrieved(Data data, String routerId, int count) - throws IOException { - handler.dataExtracted(data, routerId); - if (flushForKeepAliveInMs > 0 - && System.currentTimeMillis() - lastKeepAliveFlush > flushForKeepAliveInMs - && keepAliveWriter != null) { - CsvUtils.write(keepAliveWriter, CsvConstants.NODEID, - CsvUtils.DELIMITER, nodeId); - CsvUtils.writeLineFeed(keepAliveWriter); - keepAliveWriter.flush(); - lastKeepAliveFlush = System.currentTimeMillis(); - } - return true; - } - }); - } - - @Override - protected AbstractSqlMap createSqlMap() { - return new DataExtractorServiceSqlMap(symmetricDialect.getPlatform(), - createReplacementTokens()); } - public void setOutgoingBatchService(IOutgoingBatchService batchBuilderService) { - this.outgoingBatchService = batchBuilderService; - } + class SelectBatchSource implements IBatchCsvDataSource { - public void setContext(DataExtractorContext context) { - this.clonableContext = context; - } + public SelectBatchSource(OutgoingBatch outgoingBatch) { + // TODO Auto-generated constructor stub + } - public void setConfigurationService(IConfigurationService configurationService) { - this.configurationService = configurationService; - } + public Batch getBatch() { + // TODO Auto-generated method stub + return null; + } - class ExtractStreamHandler implements IExtractListener { + public Table getTable() { + // TODO Auto-generated method stub + return null; + } - IDataExtractor dataExtractor; + public CsvData next() { + // TODO symmetricDialect.massageDataExtractionSql + // TODO Auto-generated method stub + return null; + } - DataExtractorContext context; + public boolean requiresLobsSelectedFromSource() { + // TODO Auto-generated method stub + return false; + } - DataExtractorStatisticsWriter writer; + public void close() { - ExtractStreamHandler(IDataExtractor dataExtractor, DataExtractorStatisticsWriter writer) - throws IOException { - this.dataExtractor = dataExtractor; - this.writer = writer; } - - public void dataExtracted(Data data, String routerId) throws IOException { - if (extractorFilters != null) { - for (IExtractorFilter filter : extractorFilters) { - if (!filter.filterData(data, routerId, context)) { - // short circuit the extract if instructed - return; - } + + class CsvDataRowMapper implements ISqlRowMapper { + public CsvData mapRow(Row row) { + CsvData data = new CsvData(); + data.putCsvData(CsvData.ROW_DATA, row.getString("ROW_DATA")); + data.putCsvData(CsvData.PK_DATA, row.getString("PK_DATA")); + //if (extractOldData) + { + data.putCsvData(CsvData.OLD_DATA, row.getString("OLD_DATA")); } + + data.putAttribute(CsvData.ATTRIBUTE_CHANNEL_ID, row.getString("CHANNEL_ID")); + data.putAttribute(CsvData.ATTRIBUTE_TX_ID, row.getString("TRANSACTION_ID")); + data.setDataEventType(DataEventType.getEventType(row.getString("EVENT_TYPE"))); + data.putAttribute(CsvData.ATTRIBUTE_TABLE_ID, row.getInt("TRIGGER_HIST_ID")); + data.putAttribute(CsvData.ATTRIBUTE_SOURCE_NODE_ID, row.getString("SOURCE_NODE_ID")); + data.putAttribute(CsvData.ATTRIBUTE_ROUTER_ID, row.getString("ROUTER_ID")); + data.putAttribute(CsvData.ATTRIBUTE_EXTERNAL_DATA, row.getString("EXTERNAL_DATA")); + data.putAttribute(CsvData.ATTRIBUTE_DATA_ID, row.getLong("DATA_ID")); + return data; } -// try { -// List transformedData = transformDataExtractor.transformData( -// data, routerId, context); -// if (transformedData != null) { -// for (Data data2 : transformedData) { -// dataExtractor.write(writer, data2, routerId, context); -// } -// } else -// { - dataExtractor.write(writer, data, routerId, context); -// } -// } catch (IgnoreRowException e) { -// // Ignore the row -// } - } - - public void done() throws IOException { } - public void endBatch(OutgoingBatch batch) throws IOException { - dataExtractor.commit(batch, writer); - writer.flush(); - } + } + + class InitialLoadSource implements IBatchCsvDataSource { + + private Batch batch; + + private Table currentTable; - public void init() throws IOException { - this.context = DataExtractorService.this.clonableContext.copy(dataExtractor); - dataExtractor.init(writer, context); + private List initialLoadEventsToSend; + + private InitialLoadEvent currentInitialLoadEvent; + + private ISqlReadCursor cursor; + + public InitialLoadSource(Batch batch, List initialLoadEvents) { + this.initialLoadEventsToSend = new ArrayList(initialLoadEvents); + this.batch = batch; } - public void startBatch(OutgoingBatch batch) throws IOException { - context.setBatch(batch); - writer.setChannelId(batch.getChannelId()); - dataExtractor.begin(batch, writer); + public Batch getBatch() { + return batch; } - } + public Table getTable() { + return currentTable; + } - public void setBeanFactory(BeanFactory beanFactory) throws BeansException { - this.beanFactory = beanFactory; - } + public CsvData next() { + CsvData data = null; + if (this.currentInitialLoadEvent == null && initialLoadEventsToSend.size() > 0) { + this.currentInitialLoadEvent = initialLoadEventsToSend.remove(0); + TriggerHistory history = this.currentInitialLoadEvent.getTriggerHistory(); + String catalogName = history.getSourceCatalogName(); + String schemaName = history.getSourceSchemaName(); + String tableName = history.getSourceTableName(); + this.currentTable = symmetricDialect.getPlatform().getTableFromCache(catalogName, + schemaName, tableName, false); + if (this.currentTable == null) { + throw new RuntimeException(String.format( + "Could not find the table, %s, to extract", + Table.getFullyQualifiedTableName(catalogName, schemaName, tableName))); + } + this.currentTable = currentTable.copy(); + this.currentTable.orderColumns(history.getParsedColumnNames()); + if (this.currentInitialLoadEvent.containsData()) { + data = this.currentInitialLoadEvent.getData(); + this.currentInitialLoadEvent = null; + } else { + TriggerRouter triggerRouter = this.currentInitialLoadEvent.getTriggerRouter(); + this.startNewCursor(history, triggerRouter); + } + } - public void addExtractorFilter(IExtractorFilter extractorFilter) { - if (this.extractorFilters == null) { - this.extractorFilters = new ArrayList(); - } - this.extractorFilters.add(extractorFilter); - } + if (this.cursor != null) { + data = this.cursor.next(); + if (data == null) { + this.cursor.close(); + data = next(); + } + } - public void setExtractorFilters(List extractorFilters) { - this.extractorFilters = extractorFilters; - } + // TODO use router to filter out events that may not need routed - public void setAcknowledgeService(IAcknowledgeService acknowledgeService) { - this.acknowledgeService = acknowledgeService; - } + return data; + } - public void setNodeService(INodeService nodeService) { - this.nodeService = nodeService; - } + protected void closeCursor() { + if (this.cursor != null) { + this.cursor.close(); + this.cursor = null; + this.currentInitialLoadEvent = null; + } + } - public void setRoutingService(IRouterService routingService) { - this.routingService = routingService; - } + protected void startNewCursor(final TriggerHistory triggerHistory, + TriggerRouter triggerRouter) { + String initialLoadSql = symmetricDialect.createInitialLoadSqlFor( + this.currentInitialLoadEvent.getNode(), triggerRouter, this.currentTable, + triggerHistory, + configurationService.getChannel(triggerRouter.getTrigger().getChannelId())); + this.cursor = sqlTemplate.queryForCursor(initialLoadSql, new ISqlRowMapper() { + public Data mapRow(Row rs) { + return new Data(0, null, rs.stringValue(), DataEventType.INSERT, triggerHistory + .getSourceTableName(), null, triggerHistory, batch.getChannelId(), + null, null); + } + }); + } - public void setDataService(IDataService dataService) { - this.dataService = dataService; - } + public boolean requiresLobsSelectedFromSource() { + if (this.currentInitialLoadEvent != null + && this.currentInitialLoadEvent.getTriggerRouter() != null) { + return this.currentInitialLoadEvent.getTriggerRouter().getTrigger() + .isUseStreamLobs(); + } else { + return false; + } + } - public void setTriggerRouterService(ITriggerRouterService triggerService) { - this.triggerRouterService = triggerService; - } + public void close() { + closeCursor(); + } - public void setStatisticManager(IStatisticManager statisticManager) { - this.statisticManager = statisticManager; } } \ No newline at end of file diff --git a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/impl/DataExtractorServiceSqlMap.java b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/impl/DataExtractorServiceSqlMap.java deleted file mode 100644 index 1d09b77dbc..0000000000 --- a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/impl/DataExtractorServiceSqlMap.java +++ /dev/null @@ -1,15 +0,0 @@ -package org.jumpmind.symmetric.service.impl; - -import org.jumpmind.db.platform.IDatabasePlatform; -import org.jumpmind.db.sql.AbstractSqlMap; -import java.util.Map; - -public class DataExtractorServiceSqlMap extends AbstractSqlMap { - - public DataExtractorServiceSqlMap(IDatabasePlatform platform, - Map replacementTokens) { - super(platform, replacementTokens); - - } - -} \ No newline at end of file diff --git a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/impl/DataLoaderService.java b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/impl/DataLoaderService.java index 2ffeb2378e..cb32a2643c 100644 --- a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/impl/DataLoaderService.java +++ b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/impl/DataLoaderService.java @@ -34,24 +34,28 @@ import java.util.List; import java.util.Map; -import org.apache.commons.io.IOUtils; import org.apache.commons.lang.StringUtils; import org.jumpmind.db.sql.AbstractSqlMap; import org.jumpmind.db.sql.ISqlTransaction; import org.jumpmind.symmetric.common.Constants; import org.jumpmind.symmetric.common.ParameterConstants; import org.jumpmind.symmetric.db.ISymmetricDialect; -import org.jumpmind.symmetric.io.ThresholdFileWriter; +import org.jumpmind.symmetric.io.IoResource; import org.jumpmind.symmetric.io.data.Batch; import org.jumpmind.symmetric.io.data.DataContext; import org.jumpmind.symmetric.io.data.DataProcessor; import org.jumpmind.symmetric.io.data.IDataProcessorListener; +import org.jumpmind.symmetric.io.data.IDataReader; +import org.jumpmind.symmetric.io.data.IDataWriter; import org.jumpmind.symmetric.io.data.reader.TextualCsvDataReader; import org.jumpmind.symmetric.io.data.transform.TransformPoint; import org.jumpmind.symmetric.io.data.transform.TransformTable; import org.jumpmind.symmetric.io.data.writer.DatabaseWriterSettings; +import org.jumpmind.symmetric.io.data.writer.FileCsvDataWriter; +import org.jumpmind.symmetric.io.data.writer.ICsvDataWriterListener; import org.jumpmind.symmetric.io.data.writer.IDatabaseWriterFilter; import org.jumpmind.symmetric.io.data.writer.TransformDatabaseWriter; +import org.jumpmind.symmetric.load.ConfigurationChangedFilter; import org.jumpmind.symmetric.model.BatchInfo; import org.jumpmind.symmetric.model.ChannelMap; import org.jumpmind.symmetric.model.IncomingBatch; @@ -64,7 +68,9 @@ import org.jumpmind.symmetric.service.IDataLoaderService; import org.jumpmind.symmetric.service.IIncomingBatchService; import org.jumpmind.symmetric.service.INodeService; +import org.jumpmind.symmetric.service.IParameterService; import org.jumpmind.symmetric.service.ITransformService; +import org.jumpmind.symmetric.service.ITriggerRouterService; import org.jumpmind.symmetric.service.RegistrationNotOpenException; import org.jumpmind.symmetric.service.RegistrationRequiredException; import org.jumpmind.symmetric.service.impl.TransformService.TransformTableNodeGroupLink; @@ -75,7 +81,6 @@ import org.jumpmind.symmetric.transport.ITransportManager; import org.jumpmind.symmetric.transport.SyncDisabledException; import org.jumpmind.symmetric.transport.TransportException; -import org.jumpmind.symmetric.transport.file.FileIncomingTransport; import org.jumpmind.symmetric.transport.http.HttpTransportManager; import org.jumpmind.symmetric.transport.internal.InternalIncomingTransport; import org.jumpmind.symmetric.util.AppUtils; @@ -88,8 +93,6 @@ */ public class DataLoaderService extends AbstractService implements IDataLoaderService { - private ISymmetricDialect symmetricDialect; - private IIncomingBatchService incomingBatchService; private IConfigurationService configurationService; @@ -103,7 +106,24 @@ public class DataLoaderService extends AbstractService implements IDataLoaderSer private INodeService nodeService; private ITransformService transformService; - + + public DataLoaderService(IParameterService parameterService, + ISymmetricDialect symmetricDialect, IIncomingBatchService incomingBatchService, + IConfigurationService configurationService, ITransportManager transportManager, + IStatisticManager statisticManager, INodeService nodeService, + ITransformService transformService, ITriggerRouterService triggerRouterService) { + super(parameterService, symmetricDialect); + this.incomingBatchService = incomingBatchService; + this.configurationService = configurationService; + this.transportManager = transportManager; + this.statisticManager = statisticManager; + this.nodeService = nodeService; + this.transformService = transformService; + this.filters = new ArrayList(); + this.filters.add(new ConfigurationChangedFilter(parameterService, configurationService, + triggerRouterService, transformService)); + } + @Override protected AbstractSqlMap createSqlMap() { return null; @@ -217,13 +237,28 @@ protected List loadDataAndReturnBatches(String sourceNodeId, IIncomingTransport transport) throws IOException { ManageIncomingBatchListener listener = new ManageIncomingBatchListener(); try { + final List readersForDatabaseLoader = new ArrayList(); long totalNetworkMillis = System.currentTimeMillis(); if (parameterService.is(ParameterConstants.STREAM_TO_FILE_ENABLED)) { - transport = writeToFile(transport); + IDataReader dataReader = new TextualCsvDataReader(transport.open()); + long memoryThresholdInBytes = parameterService + .getLong(ParameterConstants.STREAM_TO_FILE_THRESHOLD); + IDataWriter dataWriter = new FileCsvDataWriter(new File( + System.getProperty("java.io.tmpdir")), memoryThresholdInBytes, + new ICsvDataWriterListener() { + public void start(Batch batch) { + } + + public void end(Batch batch, IoResource resource) { + readersForDatabaseLoader.add(new TextualCsvDataReader(resource)); + } + }); + new DataProcessor(dataReader, dataWriter).process(); totalNetworkMillis = System.currentTimeMillis() - totalNetworkMillis; + } else { + readersForDatabaseLoader.add(new TextualCsvDataReader(transport.open())); } - TextualCsvDataReader reader = new TextualCsvDataReader(transport.open()); DatabaseWriterSettings settings = buildDatabaseWriterSettings(); TransformTable[] transforms = null; @@ -235,12 +270,15 @@ protected List loadDataAndReturnBatches(String sourceNodeId, transforms = transformsList != null ? transformsList .toArray(new TransformTable[transformsList.size()]) : null; } - TransformDatabaseWriter writer = new TransformDatabaseWriter(symmetricDialect.getPlatform(), - settings, null, transforms, filters.toArray(new IDatabaseWriterFilter[filters - .size()])); - DataProcessor processor = new DataProcessor( - reader, writer, listener); - processor.process(); + TransformDatabaseWriter writer = new TransformDatabaseWriter( + symmetricDialect.getPlatform(), settings, null, transforms, + filters.toArray(new IDatabaseWriterFilter[filters.size()])); + + for (IDataReader reader : readersForDatabaseLoader) { + DataProcessor processor = new DataProcessor( + reader, writer, listener); + processor.process(); + } List batchesProcessed = listener.getBatchesProcessed(); @@ -256,13 +294,6 @@ protected List loadDataAndReturnBatches(String sourceNodeId, } } - if (transport instanceof FileIncomingTransport && batchesProcessed.size() == 0) { - File incomingFile = ((FileIncomingTransport) transport).getFile(); - if (incomingFile != null && incomingFile.exists()) { - log.warn("LoaderNoBatchesLoadedWarning", incomingFile.length()); - } - } - } catch (RegistrationRequiredException ex) { throw ex; } catch (ConnectException ex) { @@ -326,19 +357,6 @@ protected void estimateNetworkMillis(List list, long totalNetwork } } - protected IIncomingTransport writeToFile(IIncomingTransport transport) throws IOException { - ThresholdFileWriter writer = null; - try { - writer = new ThresholdFileWriter( - parameterService.getLong(ParameterConstants.STREAM_TO_FILE_THRESHOLD), "load"); - IOUtils.copy(transport.open(), writer); - } finally { - IOUtils.closeQuietly(writer); - transport.close(); - } - return new FileIncomingTransport(writer); - } - /** * Load database from input stream and write acknowledgment to output * stream. This is used for a "push" request with a response of an @@ -394,18 +412,17 @@ public void setConfigurationService(IConfigurationService configurationService) } class ManageIncomingBatchListener implements - IDataProcessorListener { + IDataProcessorListener { private List batchesProcessed = new ArrayList(); private IncomingBatch currentBatch; - public void beforeBatchEnd(DataContext context) { + public void beforeBatchEnd(DataContext context) { enableSyncTriggers(context); } - public boolean beforeBatchStarted( - DataContext context) { + public boolean beforeBatchStarted(DataContext context) { this.currentBatch = null; Batch batch = context.getBatch(); if (parameterService.is(ParameterConstants.DATA_LOADER_ENABLED) @@ -421,13 +438,13 @@ public boolean beforeBatchStarted( return false; } - public void afterBatchStarted(DataContext context) { + public void afterBatchStarted(DataContext context) { Batch batch = context.getBatch(); - symmetricDialect.disableSyncTriggers(context.getWriter().getDatabaseWriter().getTransaction(), - batch.getSourceNodeId()); + symmetricDialect.disableSyncTriggers(context.getWriter().getDatabaseWriter() + .getTransaction(), batch.getSourceNodeId()); } - public void batchSuccessful(DataContext context) { + public void batchSuccessful(DataContext context) { Batch batch = context.getBatch(); this.currentBatch.setValues(context.getReader().getStatistics().get(batch), context .getWriter().getStatistics().get(batch), true); @@ -441,8 +458,7 @@ public void batchSuccessful(DataContext context) { + protected void enableSyncTriggers(DataContext context) { try { ISqlTransaction transaction = context.getWriter().getDatabaseWriter() .getTransaction(); @@ -454,7 +470,7 @@ protected void enableSyncTriggers( } } - public void batchInError(DataContext context, + public void batchInError(DataContext context, Exception ex) { Batch batch = context.getBatch(); this.currentBatch.setValues(context.getReader().getStatistics().get(batch), context diff --git a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/impl/DataService.java b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/impl/DataService.java index 5306f838f1..6932d4a1da 100644 --- a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/impl/DataService.java +++ b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/impl/DataService.java @@ -16,17 +16,15 @@ * "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.jumpmind.symmetric.service.impl; - + * under the License. + */ + +package org.jumpmind.symmetric.service.impl; + import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.OutputStreamWriter; -import java.sql.Connection; import java.sql.DataTruncation; -import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Types; @@ -41,9 +39,12 @@ import java.util.Set; import org.apache.commons.lang.StringUtils; -import org.apache.commons.lang.time.DateUtils; import org.jumpmind.db.model.Table; import org.jumpmind.db.sql.AbstractSqlMap; +import org.jumpmind.db.sql.ISqlRowMapper; +import org.jumpmind.db.sql.ISqlTransaction; +import org.jumpmind.db.sql.Row; +import org.jumpmind.db.sql.mapper.NumberMapper; import org.jumpmind.symmetric.Version; import org.jumpmind.symmetric.common.Constants; import org.jumpmind.symmetric.common.DeploymentType; @@ -51,16 +52,16 @@ import org.jumpmind.symmetric.common.ParameterConstants; import org.jumpmind.symmetric.common.TableConstants; import org.jumpmind.symmetric.csv.CsvWriter; -import org.jumpmind.symmetric.db.JdbcBatchPreparedStatementCallback; +import org.jumpmind.symmetric.db.ISymmetricDialect; import org.jumpmind.symmetric.db.SequenceIdentifier; import org.jumpmind.symmetric.ext.IHeartbeatListener; import org.jumpmind.symmetric.io.data.CsvUtils; import org.jumpmind.symmetric.io.data.DataEventType; +import org.jumpmind.symmetric.job.PushHeartbeatListener; import org.jumpmind.symmetric.load.IReloadListener; import org.jumpmind.symmetric.model.Data; import org.jumpmind.symmetric.model.DataEvent; import org.jumpmind.symmetric.model.DataGap; -import org.jumpmind.symmetric.model.DataRef; import org.jumpmind.symmetric.model.Node; import org.jumpmind.symmetric.model.NodeGroupLink; import org.jumpmind.symmetric.model.NodeGroupLinkAction; @@ -71,413 +72,418 @@ import org.jumpmind.symmetric.model.TriggerRouter; import org.jumpmind.symmetric.service.IConfigurationService; import org.jumpmind.symmetric.service.IDataService; -import org.jumpmind.symmetric.service.IModelRetrievalHandler; import org.jumpmind.symmetric.service.INodeService; import org.jumpmind.symmetric.service.IOutgoingBatchService; +import org.jumpmind.symmetric.service.IParameterService; import org.jumpmind.symmetric.service.IPurgeService; import org.jumpmind.symmetric.service.ITriggerRouterService; import org.jumpmind.symmetric.statistic.IStatisticManager; import org.jumpmind.symmetric.util.AppUtils; -import org.springframework.dao.DataAccessException; import org.springframework.dao.DataIntegrityViolationException; import org.springframework.dao.EmptyResultDataAccessException; -import org.springframework.jdbc.core.BatchPreparedStatementSetter; -import org.springframework.jdbc.core.ConnectionCallback; -import org.springframework.jdbc.core.JdbcTemplate; -import org.springframework.jdbc.core.PreparedStatementCallback; -import org.springframework.jdbc.core.RowMapper; -import org.springframework.jdbc.core.SingleColumnRowMapper; -import org.springframework.jdbc.support.JdbcUtils; -import org.springframework.transaction.TransactionStatus; -import org.springframework.transaction.annotation.Transactional; -import org.springframework.transaction.support.TransactionCallback; - + /** * @see IDataService */ -public class DataService extends AbstractService implements IDataService { +public class DataService extends AbstractService implements IDataService { private DeploymentType deploymentType; - - private ITriggerRouterService triggerRouterService; - - private INodeService nodeService; - - private IPurgeService purgeService; - - private IConfigurationService configurationService; - - private IOutgoingBatchService outgoingBatchService; - - private List reloadListeners; - + + private ITriggerRouterService triggerRouterService; + + private INodeService nodeService; + + private IPurgeService purgeService; + + private IConfigurationService configurationService; + + private IOutgoingBatchService outgoingBatchService; + + private List reloadListeners; + private List heartbeatListeners; - - private IStatisticManager statisticManager; - - protected Map lastHeartbeatTimestamps = new HashMap(); + + private IStatisticManager statisticManager; + + public DataService(IParameterService parameterService, ISymmetricDialect symmetricDialect, + DeploymentType deploymentType, ITriggerRouterService triggerRouterService, + INodeService nodeService, IPurgeService purgeService, + IConfigurationService configurationService, IOutgoingBatchService outgoingBatchService, + IStatisticManager statisticManager) { + super(parameterService, symmetricDialect); + this.deploymentType = deploymentType; + this.triggerRouterService = triggerRouterService; + this.nodeService = nodeService; + this.purgeService = purgeService; + this.configurationService = configurationService; + this.outgoingBatchService = outgoingBatchService; + this.statisticManager = statisticManager; + this.reloadListeners = new ArrayList(); + this.heartbeatListeners = new ArrayList(); + this.heartbeatListeners.add(new PushHeartbeatListener(parameterService, this, nodeService, + symmetricDialect)); + } + + protected Map lastHeartbeatTimestamps = new HashMap(); @Override protected AbstractSqlMap createSqlMap() { - return new DataServiceSqlMap(symmetricDialect.getPlatform(), - createReplacementTokens()); - } - - @Transactional - public void insertReloadEvent(final Node targetNode, final TriggerRouter triggerRouter) { - insertReloadEvent(targetNode, triggerRouter, null); - } - - @Transactional - public void insertReloadEvent(final Node targetNode, final TriggerRouter triggerRouter, - final String overrideInitialLoadSelect) { - TriggerHistory history = lookupTriggerHistory(triggerRouter.getTrigger()); - // initial_load_select for table can be overridden by populating the - // row_data - Data data = new Data(history.getSourceTableName(), DataEventType.RELOAD, - overrideInitialLoadSelect != null ? overrideInitialLoadSelect : triggerRouter - .getInitialLoadSelect(), null, history, triggerRouter.getTrigger().getChannelId(), null, - null); - insertDataAndDataEventAndOutgoingBatch(data, targetNode.getNodeId(), triggerRouter - .getRouter().getRouterId(), true); - } - - private TriggerHistory lookupTriggerHistory(Trigger trigger) { - TriggerHistory history = triggerRouterService.getNewestTriggerHistoryForTrigger(trigger - .getTriggerId()); - - if (history == null) { - triggerRouterService.syncTriggers(); - history = triggerRouterService.getNewestTriggerHistoryForTrigger(trigger - .getTriggerId()); - } - - if (history == null) { - throw new RuntimeException("Cannot find history for trigger " + trigger.getTriggerId() - + ", " + trigger.getSourceTableName()); - } - return history; - } - - public void insertPurgeEvent(final Node targetNode, final TriggerRouter triggerRouter, boolean isLoad) { - String sql = symmetricDialect.createPurgeSqlFor(targetNode, triggerRouter); - TriggerHistory history = triggerRouterService.getNewestTriggerHistoryForTrigger(triggerRouter.getTrigger() + return new DataServiceSqlMap(symmetricDialect.getPlatform(), createSqlReplacementTokens()); + } + + public void insertReloadEvent(final Node targetNode, final TriggerRouter triggerRouter) { + insertReloadEvent(targetNode, triggerRouter, null); + } + + public void insertReloadEvent(final Node targetNode, final TriggerRouter triggerRouter, + final String overrideInitialLoadSelect) { + TriggerHistory history = lookupTriggerHistory(triggerRouter.getTrigger()); + // initial_load_select for table can be overridden by populating the + // row_data + Data data = new Data(history.getSourceTableName(), DataEventType.RELOAD, + overrideInitialLoadSelect != null ? overrideInitialLoadSelect + : triggerRouter.getInitialLoadSelect(), null, history, triggerRouter + .getTrigger().getChannelId(), null, null); + insertDataAndDataEventAndOutgoingBatch(data, targetNode.getNodeId(), triggerRouter + .getRouter().getRouterId(), true); + } + + private TriggerHistory lookupTriggerHistory(Trigger trigger) { + TriggerHistory history = triggerRouterService.getNewestTriggerHistoryForTrigger(trigger .getTriggerId()); - Data data = new Data(history.getSourceTableName(), DataEventType.SQL, CsvUtils - .escapeCsvData(sql), null, history, triggerRouter.getTrigger().getChannelId(), null, null); + + if (history == null) { + triggerRouterService.syncTriggers(); + history = triggerRouterService + .getNewestTriggerHistoryForTrigger(trigger.getTriggerId()); + } + + if (history == null) { + throw new RuntimeException("Cannot find history for trigger " + trigger.getTriggerId() + + ", " + trigger.getSourceTableName()); + } + return history; + } + + public void insertPurgeEvent(final Node targetNode, final TriggerRouter triggerRouter, + boolean isLoad) { + String sql = symmetricDialect.createPurgeSqlFor(targetNode, triggerRouter); + TriggerHistory history = triggerRouterService + .getNewestTriggerHistoryForTrigger(triggerRouter.getTrigger().getTriggerId()); + Data data = new Data(history.getSourceTableName(), DataEventType.SQL, + CsvUtils.escapeCsvData(sql), null, history, triggerRouter.getTrigger() + .getChannelId(), null, null); + insertDataAndDataEventAndOutgoingBatch(data, targetNode.getNodeId(), triggerRouter + .getRouter().getRouterId(), isLoad); + } + + public void insertSqlEvent(final Node targetNode, final Trigger trigger, String sql, + boolean isLoad) { + TriggerHistory history = triggerRouterService.getNewestTriggerHistoryForTrigger(trigger + .getTriggerId()); + Data data = new Data(history.getSourceTableName(), DataEventType.SQL, + CsvUtils.escapeCsvData(sql), null, history, trigger.getChannelId(), null, null); insertDataAndDataEventAndOutgoingBatch(data, targetNode.getNodeId(), - triggerRouter.getRouter().getRouterId(), isLoad); - } - - public void insertSqlEvent(final Node targetNode, final Trigger trigger, String sql, boolean isLoad) { - TriggerHistory history = triggerRouterService.getNewestTriggerHistoryForTrigger(trigger - .getTriggerId()); - Data data = new Data(history.getSourceTableName(), DataEventType.SQL, CsvUtils - .escapeCsvData(sql), null, history, trigger.getChannelId(), null, null); - insertDataAndDataEventAndOutgoingBatch(data, targetNode.getNodeId(), - Constants.UNKNOWN_ROUTER_ID, isLoad); - } - + Constants.UNKNOWN_ROUTER_ID, isLoad); + } + private TriggerHistory findTriggerHistoryForGenericSync() { - String triggerTableName = TableConstants.getTableName(tablePrefix, TableConstants.SYM_TRIGGER); - TriggerHistory history = triggerRouterService.findTriggerHistory(triggerTableName.toUpperCase()); + String triggerTableName = TableConstants.getTableName(tablePrefix, + TableConstants.SYM_TRIGGER); + TriggerHistory history = triggerRouterService.findTriggerHistory(triggerTableName + .toUpperCase()); if (history == null) { history = triggerRouterService.findTriggerHistory(triggerTableName); } return history; - } - + } + public void insertSqlEvent(final Node targetNode, String sql, boolean isLoad) { TriggerHistory history = findTriggerHistoryForGenericSync(); - Data data = new Data(history.getSourceTableName(), DataEventType.SQL, CsvUtils.escapeCsvData(sql), null, - history, Constants.CHANNEL_CONFIG, null, null); - insertDataAndDataEventAndOutgoingBatch(data, targetNode.getNodeId(), - Constants.UNKNOWN_ROUTER_ID, isLoad); - } - - public int countDataInRange(long firstDataId, long secondDataId) { - return jdbcTemplate.queryForInt(getSql("countDataInRangeSql"), firstDataId, secondDataId); - } - + Data data = new Data(history.getSourceTableName(), DataEventType.SQL, + CsvUtils.escapeCsvData(sql), null, history, Constants.CHANNEL_CONFIG, null, null); + insertDataAndDataEventAndOutgoingBatch(data, targetNode.getNodeId(), + Constants.UNKNOWN_ROUTER_ID, isLoad); + } + + public int countDataInRange(long firstDataId, long secondDataId) { + return sqlTemplate.queryForInt(getSql("countDataInRangeSql"), firstDataId, secondDataId); + } + public void checkForAndUpdateMissingChannelIds(long firstDataId, long lastDataId) { - int numberUpdated = jdbcTemplate.update(getSql("checkForAndUpdateMissingChannelIdSql"), Constants.CHANNEL_DEFAULT, - firstDataId, lastDataId); + int numberUpdated = sqlTemplate.update(getSql("checkForAndUpdateMissingChannelIdSql"), + Constants.CHANNEL_DEFAULT, firstDataId, lastDataId); if (numberUpdated > 0) { - log.warn("DataFoundWithWrongChannelIds", numberUpdated, firstDataId, lastDataId, Constants.CHANNEL_DEFAULT); - } - } - - public void insertCreateEvent(final Node targetNode, final TriggerRouter triggerRouter, - String xml, boolean isLoad) { - TriggerHistory history = triggerRouterService - .getNewestTriggerHistoryForTrigger(triggerRouter.getTrigger().getTriggerId()); - Data data = new Data(triggerRouter.getTrigger().getSourceTableName(), DataEventType.CREATE, - CsvUtils.escapeCsvData(xml), null, history, - parameterService.is(ParameterConstants.INITIAL_LOAD_USE_RELOAD_CHANNEL) && isLoad ? Constants.CHANNEL_RELOAD : triggerRouter.getTrigger().getChannelId(), null, null); - try { - insertDataAndDataEventAndOutgoingBatch(data, targetNode.getNodeId(), + log.warn("DataFoundWithWrongChannelIds", numberUpdated, firstDataId, lastDataId, + Constants.CHANNEL_DEFAULT); + } + } + + public void insertCreateEvent(final Node targetNode, final TriggerRouter triggerRouter, + String xml, boolean isLoad) { + TriggerHistory history = triggerRouterService + .getNewestTriggerHistoryForTrigger(triggerRouter.getTrigger().getTriggerId()); + Data data = new Data( + triggerRouter.getTrigger().getSourceTableName(), + DataEventType.CREATE, + CsvUtils.escapeCsvData(xml), + null, + history, + parameterService.is(ParameterConstants.INITIAL_LOAD_USE_RELOAD_CHANNEL) && isLoad ? Constants.CHANNEL_RELOAD + : triggerRouter.getTrigger().getChannelId(), null, null); + try { + insertDataAndDataEventAndOutgoingBatch(data, targetNode.getNodeId(), Constants.UNKNOWN_ROUTER_ID, isLoad); } catch (DataIntegrityViolationException e) { if (e.getRootCause() != null && e.getRootCause() instanceof DataTruncation) { log.error("InitialLoadCreateDataTruncation"); } throw e; - } - } - - public long insertData(final Data data) { - long id = symmetricDialect.insertWithGeneratedKey(getSql("insertIntoDataSql"), - SequenceIdentifier.DATA, new PreparedStatementCallback() { - public Object doInPreparedStatement(PreparedStatement ps) throws SQLException, - DataAccessException { - ps.setString(1, data.getTableName()); - ps.setString(2, data.getEventType().getCode()); - ps.setString(3, data.getRowData()); - ps.setString(4, data.getPkData()); - ps.setString(5, data.getOldData()); - ps.setLong(6, data.getTriggerHistory() != null ? data.getTriggerHistory() - .getTriggerHistoryId() : -1); - ps.setString(7, data.getChannelId()); - return null; - } - }); - data.setDataId(id); - return id; - } - - public void insertDataEvent(DataEvent dataEvent) { - this.insertDataEvent(jdbcTemplate, dataEvent.getDataId(), dataEvent.getBatchId(), dataEvent - .getRouterId()); - } - - public void insertDataEvent(long dataId, long batchId, String routerId) { - this.insertDataEvent(jdbcTemplate, dataId, batchId, routerId); - } - - public void insertDataEvent(JdbcTemplate template, long dataId, long batchId, String routerId) { - try { - template.update(getSql("insertIntoDataEventSql"), new Object[] { dataId, batchId, - StringUtils.isBlank(routerId) ? Constants.UNKNOWN_ROUTER_ID : routerId }, + } + } + + public long insertData(Data data) { + ISqlTransaction transaction = null; + long dataId = -1; + try { + transaction = sqlTemplate.startSqlTransaction(); + dataId = insertData(transaction, data); + transaction.commit(); + return dataId; + } finally { + close(transaction); + } + } + + protected long insertData(ISqlTransaction transaction, final Data data) { + long id = transaction.insertWithGeneratedKey(getSql("insertIntoDataSql"), symmetricDialect + .getSequenceKeyName(SequenceIdentifier.DATA), symmetricDialect + .getSequenceName(SequenceIdentifier.DATA), data.getTableName(), data + .getDataEventType().getCode(), data.getRowData(), data.getPkData(), data + .getOldData(), data.getTriggerHistory() != null ? data.getTriggerHistory() + .getTriggerHistoryId() : -1, data.getChannelId()); + data.setDataId(id); + return id; + } + + protected void insertDataEvent(ISqlTransaction transaction, DataEvent dataEvent) { + this.insertDataEvent(transaction, dataEvent.getDataId(), dataEvent.getBatchId(), + dataEvent.getRouterId()); + } + + protected void insertDataEvent(ISqlTransaction transaction, long dataId, long batchId, + String routerId) { + try { + transaction.execute(getSql("insertIntoDataEventSql"), new Object[] { dataId, batchId, + StringUtils.isBlank(routerId) ? Constants.UNKNOWN_ROUTER_ID : routerId }, new int[] { Types.NUMERIC, Types.NUMERIC, Types.VARCHAR }); - } catch (RuntimeException ex) { - log.error("DataEventInsertFailed", ex, dataId, batchId, routerId); - throw ex; - } + } catch (RuntimeException ex) { + log.error("Could not insert a data event: data_id=%d batch_id=%d router_id=%s", ex, + dataId, batchId, routerId); + throw ex; + } } - - public void insertDataEvents(JdbcTemplate template, final List events) { + + public void insertDataEvents(ISqlTransaction transaction, final List events) { if (events.size() > 0) { - JdbcBatchPreparedStatementCallback callback = new JdbcBatchPreparedStatementCallback( - symmetricDialect, new BatchPreparedStatementSetter() { - - public void setValues(PreparedStatement ps, int i) throws SQLException { - DataEvent event = events.get(i); - ps.setLong(1, event.getDataId()); - ps.setLong(2, event.getBatchId()); - ps - .setString( - 3, - StringUtils.isBlank(event.getRouterId()) ? Constants.UNKNOWN_ROUTER_ID - : event.getRouterId()); - } - - public int getBatchSize() { - return events.size(); - } - }, parameterService.getInt(ParameterConstants.JDBC_EXECUTE_BATCH_SIZE)); - - template.execute(getSql("insertIntoDataEventSql"), callback); - } - - } - public void insertDataAndDataEventAndOutgoingBatch(Data data, String channelId, - List nodes, String routerId, boolean isLoad) { - long dataId = insertData(data); - for (Node node : nodes) { - insertDataEventAndOutgoingBatch(dataId, channelId, node.getNodeId(), data.getEventType(), routerId, isLoad); - } - } - - public void insertDataAndDataEventAndOutgoingBatch(Data data, String nodeId, String routerId, boolean isLoad) { - long dataId = insertData(data); - insertDataEventAndOutgoingBatch(dataId, data.getChannelId(), nodeId, data.getEventType(), routerId, isLoad); - } - - public void insertDataEventAndOutgoingBatch(long dataId, String channelId, String nodeId, DataEventType eventType, - String routerId, boolean isLoad) { - OutgoingBatch outgoingBatch = new OutgoingBatch(nodeId, parameterService.is(ParameterConstants.INITIAL_LOAD_USE_RELOAD_CHANNEL) && isLoad ? Constants.CHANNEL_RELOAD : channelId, Status.NE); - outgoingBatch.setLoadFlag(isLoad); - outgoingBatch.incrementEventCount(eventType); - outgoingBatchService.insertOutgoingBatch(outgoingBatch); - insertDataEvent(new DataEvent(dataId, outgoingBatch.getBatchId(), routerId)); - } - - public String reloadNode(String nodeId) { - Node targetNode = nodeService.findNode(nodeId); - if (targetNode == null) { - return Message.get("NodeUnknown", nodeId); - } - if (nodeService.setInitialLoadEnabled(nodeId, true)) { - return Message.get("NodeInitialLoadOpened", nodeId); - } else { - return Message.get("NodeInitialLoadFailed", nodeId); - } - } - - public void insertReloadEvents(Node targetNode) { - - // outgoing data events are pointless because we are reloading all data - outgoingBatchService.markAllAsSentForNode(targetNode); - - if (parameterService.is(ParameterConstants.DATA_RELOAD_IS_BATCH_INSERT_TRANSACTIONAL)) { - newTransactionTemplate.execute(new TransactionalInsertReloadEventsDelegate(targetNode)); - } else { - new TransactionalInsertReloadEventsDelegate(targetNode).doInTransaction(null); - } - - // remove all incoming events from the node are starting a reload for. - purgeService.purgeAllIncomingEventsForNode(targetNode.getNodeId()); - - } - - class TransactionalInsertReloadEventsDelegate implements TransactionCallback { - - Node targetNode; - - public TransactionalInsertReloadEventsDelegate(Node targetNode) { - this.targetNode = targetNode; - } - - public Object doInTransaction(TransactionStatus status) { - - Node sourceNode = nodeService.findIdentity(); - - if (reloadListeners != null) { - for (IReloadListener listener : reloadListeners) { - listener.beforeReload(targetNode); - } - } - - // insert node security so the client doing the initial load knows - // that an initial load is currently happening - insertNodeSecurityUpdate(targetNode, true); - - List triggerRouters = new ArrayList(triggerRouterService - .getAllTriggerRoutersForReloadForCurrentNode(sourceNode.getNodeGroupId(), - targetNode.getNodeGroupId())); - - for (Iterator iterator = triggerRouters.iterator(); iterator.hasNext();) { - TriggerRouter triggerRouter = iterator.next(); - Trigger trigger = triggerRouter.getTrigger(); - Table table = symmetricDialect.getPlatform().getTableFromCache(trigger.getSourceCatalogName(), trigger - .getSourceSchemaName(), trigger.getSourceTableName(), true); - if (table == null) { - log.warn("TriggerTableMissing",trigger.qualifiedSourceTableName()); - iterator.remove(); - } - } - - if (parameterService.is(ParameterConstants.INITIAL_LOAD_CREATE_SCHEMA_BEFORE_RELOAD)) { - for (TriggerRouter triggerRouter : triggerRouters) { - String xml = symmetricDialect.getCreateTableXML(triggerRouter); - insertCreateEvent(targetNode, triggerRouter, xml, true); - } - } - - if (parameterService.is(ParameterConstants.INITIAL_LOAD_DELETE_BEFORE_RELOAD)) { - for (ListIterator iterator = triggerRouters - .listIterator(triggerRouters.size()); iterator.hasPrevious();) { - TriggerRouter triggerRouter = iterator.previous(); - insertPurgeEvent(targetNode, triggerRouter, true); - } - } - - for (TriggerRouter trigger : triggerRouters) { - insertReloadEvent(targetNode, trigger); - } - - if (reloadListeners != null) { - for (IReloadListener listener : reloadListeners) { - listener.afterReload(targetNode); - } - } - - nodeService.setInitialLoadEnabled(targetNode.getNodeId(), false); - - // don't mark this batch as a load batch so it is forced to go last - insertNodeSecurityUpdate(targetNode, - parameterService.is(ParameterConstants.INITIAL_LOAD_USE_RELOAD_CHANNEL)); + for (DataEvent dataEvent : events) { + insertDataEvent(transaction, dataEvent); + } + } + } + + public void insertDataAndDataEventAndOutgoingBatch(Data data, String channelId, + List nodes, String routerId, boolean isLoad) { + ISqlTransaction transaction = null; + try { + transaction = sqlTemplate.startSqlTransaction(); + long dataId = insertData(transaction, data); + for (Node node : nodes) { + insertDataEventAndOutgoingBatch(transaction, dataId, channelId, node.getNodeId(), + data.getDataEventType(), routerId, isLoad); + } + transaction.commit(); + } finally { + close(transaction); + } + } + + public void insertDataAndDataEventAndOutgoingBatch(Data data, String nodeId, String routerId, + boolean isLoad) { + ISqlTransaction transaction = null; + try { + transaction = sqlTemplate.startSqlTransaction(); + long dataId = insertData(transaction, data); + insertDataEventAndOutgoingBatch(transaction, dataId, data.getChannelId(), nodeId, + data.getDataEventType(), routerId, isLoad); + transaction.commit(); + } finally { + close(transaction); + } + } + + protected void insertDataEventAndOutgoingBatch(ISqlTransaction transaction, long dataId, + String channelId, String nodeId, DataEventType eventType, String routerId, + boolean isLoad) { + OutgoingBatch outgoingBatch = new OutgoingBatch( + nodeId, + parameterService.is(ParameterConstants.INITIAL_LOAD_USE_RELOAD_CHANNEL) && isLoad ? Constants.CHANNEL_RELOAD + : channelId, Status.NE); + outgoingBatch.setLoadFlag(isLoad); + outgoingBatch.incrementEventCount(eventType); + outgoingBatchService.insertOutgoingBatch(transaction, outgoingBatch); + insertDataEvent(transaction, new DataEvent(dataId, outgoingBatch.getBatchId(), routerId)); + } + + public String reloadNode(String nodeId) { + Node targetNode = nodeService.findNode(nodeId); + if (targetNode == null) { + return Message.get("NodeUnknown", nodeId); + } + if (nodeService.setInitialLoadEnabled(nodeId, true)) { + return Message.get("NodeInitialLoadOpened", nodeId); + } else { + return Message.get("NodeInitialLoadFailed", nodeId); + } + } + + public void insertReloadEvents(Node targetNode) { + + // TODO transactional? + { + // outgoing data events are pointless because we are reloading all + // data + outgoingBatchService.markAllAsSentForNode(targetNode); + + Node sourceNode = nodeService.findIdentity(); + + if (reloadListeners != null) { + for (IReloadListener listener : reloadListeners) { + listener.beforeReload(targetNode); + } + } + + // insert node security so the client doing the initial load knows + // that an initial load is currently happening + insertNodeSecurityUpdate(targetNode, true); + + List triggerRouters = new ArrayList( + triggerRouterService.getAllTriggerRoutersForReloadForCurrentNode( + sourceNode.getNodeGroupId(), targetNode.getNodeGroupId())); + + for (Iterator iterator = triggerRouters.iterator(); iterator.hasNext();) { + TriggerRouter triggerRouter = iterator.next(); + Trigger trigger = triggerRouter.getTrigger(); + Table table = symmetricDialect.getPlatform().getTableFromCache( + trigger.getSourceCatalogName(), trigger.getSourceSchemaName(), + trigger.getSourceTableName(), true); + if (table == null) { + log.warn("TriggerTableMissing", trigger.qualifiedSourceTableName()); + iterator.remove(); + } + } + + if (parameterService.is(ParameterConstants.INITIAL_LOAD_CREATE_SCHEMA_BEFORE_RELOAD)) { + for (TriggerRouter triggerRouter : triggerRouters) { + String xml = symmetricDialect.getCreateTableXML(triggerRouter); + insertCreateEvent(targetNode, triggerRouter, xml, true); + } + } + + if (parameterService.is(ParameterConstants.INITIAL_LOAD_DELETE_BEFORE_RELOAD)) { + for (ListIterator iterator = triggerRouters + .listIterator(triggerRouters.size()); iterator.hasPrevious();) { + TriggerRouter triggerRouter = iterator.previous(); + insertPurgeEvent(targetNode, triggerRouter, true); + } + } + + for (TriggerRouter trigger : triggerRouters) { + insertReloadEvent(targetNode, trigger); + } + + if (reloadListeners != null) { + for (IReloadListener listener : reloadListeners) { + listener.afterReload(targetNode); + } + } + + nodeService.setInitialLoadEnabled(targetNode.getNodeId(), false); + + // don't mark this batch as a load batch so it is forced to go last + insertNodeSecurityUpdate(targetNode, + parameterService.is(ParameterConstants.INITIAL_LOAD_USE_RELOAD_CHANNEL)); statisticManager.incrementNodesLoaded(1); - - return null; - } - } - - private void insertNodeSecurityUpdate(Node node, boolean isReload) { - Data data = createData(null, null, tablePrefix + "_node_security", " t.node_id = '" - + node.getNodeId() + "'"); - if (data != null) { - insertDataAndDataEventAndOutgoingBatch(data, node.getNodeId(), - Constants.UNKNOWN_ROUTER_ID, isReload); - } - } - - @Transactional - public void sendScript(String nodeId, String script, boolean isLoad) { + + // remove all incoming events from the node are starting a reload + // for. + purgeService.purgeAllIncomingEventsForNode(targetNode.getNodeId()); + + } + + } + + private void insertNodeSecurityUpdate(Node node, boolean isReload) { + Data data = createData(null, null, tablePrefix + "_node_security", + " t.node_id = '" + node.getNodeId() + "'"); + if (data != null) { + insertDataAndDataEventAndOutgoingBatch(data, node.getNodeId(), + Constants.UNKNOWN_ROUTER_ID, isReload); + } + } + + public void sendScript(String nodeId, String script, boolean isLoad) { Node targetNode = nodeService.findNode(nodeId); - TriggerHistory history = findTriggerHistoryForGenericSync(); - Data data = new Data(history.getSourceTableName(), DataEventType.BSH, CsvUtils.escapeCsvData(script), null, - history, Constants.CHANNEL_CONFIG, null, null); - insertDataAndDataEventAndOutgoingBatch(data, targetNode.getNodeId(), - Constants.UNKNOWN_ROUTER_ID, isLoad); - } - - @Transactional - public String sendSQL(String nodeId, String catalogName, String schemaName, String tableName, - String sql, boolean isLoad) { - Node sourceNode = nodeService.findIdentity(); - Node targetNode = nodeService.findNode(nodeId); - if (targetNode == null) { - // TODO message bundle - return "Unknown node " + nodeId; - } - - Set triggerRouters = triggerRouterService.getTriggerRouterForTableForCurrentNode( - catalogName, schemaName, tableName, true); - if (triggerRouters == null || triggerRouters.size() == 0) { - // TODO message bundle - return "Trigger for table " + tableName + " does not exist from node " - + sourceNode.getNodeGroupId(); - } - - insertSqlEvent(targetNode, triggerRouters.iterator().next().getTrigger(), sql, isLoad); - // TODO message bundle - return "Successfully create SQL event for node " + targetNode.getNodeId(); - } - - @Transactional - public String reloadTable(String nodeId, String catalogName, String schemaName, String tableName) { - return reloadTable(nodeId, catalogName, schemaName, tableName, null); - } - - @Transactional - public String reloadTable(String nodeId, String catalogName, String schemaName, - String tableName, String overrideInitialLoadSelect) { - Node sourceNode = nodeService.findIdentity(); - Node targetNode = nodeService.findNode(nodeId); - if (targetNode == null) { - // TODO message bundle - return "Unknown node " + nodeId; - } - - Set triggerRouters = triggerRouterService.getTriggerRouterForTableForCurrentNode( - catalogName, schemaName, tableName, true); - if (triggerRouters == null || triggerRouters.size() == 0) { - // TODO message bundle - return "Trigger for table " + tableName + " does not exist from node " - + sourceNode.getNodeGroupId(); - } + TriggerHistory history = findTriggerHistoryForGenericSync(); + Data data = new Data(history.getSourceTableName(), DataEventType.BSH, + CsvUtils.escapeCsvData(script), null, history, Constants.CHANNEL_CONFIG, null, null); + insertDataAndDataEventAndOutgoingBatch(data, targetNode.getNodeId(), + Constants.UNKNOWN_ROUTER_ID, isLoad); + } + + public String sendSQL(String nodeId, String catalogName, String schemaName, String tableName, + String sql, boolean isLoad) { + Node sourceNode = nodeService.findIdentity(); + Node targetNode = nodeService.findNode(nodeId); + if (targetNode == null) { + // TODO message bundle + return "Unknown node " + nodeId; + } + + Set triggerRouters = triggerRouterService + .getTriggerRouterForTableForCurrentNode(catalogName, schemaName, tableName, true); + if (triggerRouters == null || triggerRouters.size() == 0) { + // TODO message bundle + return "Trigger for table " + tableName + " does not exist from node " + + sourceNode.getNodeGroupId(); + } + + insertSqlEvent(targetNode, triggerRouters.iterator().next().getTrigger(), sql, isLoad); + // TODO message bundle + return "Successfully create SQL event for node " + targetNode.getNodeId(); + } + + public String reloadTable(String nodeId, String catalogName, String schemaName, String tableName) { + return reloadTable(nodeId, catalogName, schemaName, tableName, null); + } + + public String reloadTable(String nodeId, String catalogName, String schemaName, + String tableName, String overrideInitialLoadSelect) { + Node sourceNode = nodeService.findIdentity(); + Node targetNode = nodeService.findNode(nodeId); + if (targetNode == null) { + // TODO message bundle + return "Unknown node " + nodeId; + } + + Set triggerRouters = triggerRouterService + .getTriggerRouterForTableForCurrentNode(catalogName, schemaName, tableName, true); + if (triggerRouters == null || triggerRouters.size() == 0) { + // TODO message bundle + return "Trigger for table " + tableName + " does not exist from node " + + sourceNode.getNodeGroupId(); + } for (TriggerRouter triggerRouter : triggerRouters) { if (parameterService.is(ParameterConstants.INITIAL_LOAD_CREATE_SCHEMA_BEFORE_RELOAD)) { @@ -488,466 +494,363 @@ public String reloadTable(String nodeId, String catalogName, String schemaName, } insertReloadEvent(targetNode, triggerRouter, overrideInitialLoadSelect); - } - // TODO message bundle - return "Successfully created event to reload table " + tableName + " for node " - + targetNode.getNodeId(); - } - - /** - * Because we can't add a trigger on the _node table, we are artificially - * generating heartbeat events. - * - * @param node - */ - public void insertHeartbeatEvent(Node node, boolean isReload) { - String tableName = TableConstants.getTableName(tablePrefix, TableConstants.SYM_NODE); - List links = configurationService.getNodeGroupLinksFor(parameterService - .getNodeGroupId()); - for (NodeGroupLink nodeGroupLink : links) { - if (nodeGroupLink.getDataEventAction() == NodeGroupLinkAction.P) { - Set triggerRouters = triggerRouterService - .getTriggerRouterForTableForCurrentNode(nodeGroupLink, null, null, tableName, false); - if (triggerRouters != null && triggerRouters.size() > 0) { - Data data = createData(triggerRouters.iterator().next().getTrigger(), String.format( - " t.node_id = '%s'", node.getNodeId())); - if (data != null) { - insertData(data); - } else { - log.warn("TableGeneratingEventsFailure", tableName); - } - } else { - log.warn("TableGeneratingEventsFailure", tableName); - } - } - } - } - - public Data createData(String catalogName, String schemaName, String tableName) { - return createData(catalogName, schemaName, tableName, null); - } - - public Data createData(String catalogName, String schemaName, String tableName, - String whereClause) { - Data data = null; - Set triggerRouters = triggerRouterService.getTriggerRouterForTableForCurrentNode( - catalogName, schemaName, tableName, false); - if (triggerRouters != null && triggerRouters.size() > 0) { - data = createData(triggerRouters.iterator().next().getTrigger(), whereClause); - } - return data; - } - - public Data createData(Trigger trigger, String whereClause) { - Data data = null; + } + // TODO message bundle + return "Successfully created event to reload table " + tableName + " for node " + + targetNode.getNodeId(); + } + + /** + * Because we can't add a trigger on the _node table, we are artificially + * generating heartbeat events. + * + * @param node + */ + public void insertHeartbeatEvent(Node node, boolean isReload) { + String tableName = TableConstants.getTableName(tablePrefix, TableConstants.SYM_NODE); + List links = configurationService.getNodeGroupLinksFor(parameterService + .getNodeGroupId()); + for (NodeGroupLink nodeGroupLink : links) { + if (nodeGroupLink.getDataEventAction() == NodeGroupLinkAction.P) { + Set triggerRouters = triggerRouterService + .getTriggerRouterForTableForCurrentNode(nodeGroupLink, null, null, + tableName, false); + if (triggerRouters != null && triggerRouters.size() > 0) { + Data data = createData(triggerRouters.iterator().next().getTrigger(), + String.format(" t.node_id = '%s'", node.getNodeId())); + if (data != null) { + insertData(data); + } else { + log.warn("TableGeneratingEventsFailure", tableName); + } + } else { + log.warn("TableGeneratingEventsFailure", tableName); + } + } + } + } + + public Data createData(String catalogName, String schemaName, String tableName) { + return createData(catalogName, schemaName, tableName, null); + } + + public Data createData(String catalogName, String schemaName, String tableName, + String whereClause) { + Data data = null; + Set triggerRouters = triggerRouterService + .getTriggerRouterForTableForCurrentNode(catalogName, schemaName, tableName, false); + if (triggerRouters != null && triggerRouters.size() > 0) { + data = createData(triggerRouters.iterator().next().getTrigger(), whereClause); + } + return data; + } + + public Data createData(Trigger trigger, String whereClause) { + Data data = null; if (trigger != null) { - TriggerHistory triggerHistory = triggerRouterService.getNewestTriggerHistoryForTrigger(trigger - .getTriggerId()); + TriggerHistory triggerHistory = triggerRouterService + .getNewestTriggerHistoryForTrigger(trigger.getTriggerId()); if (triggerHistory == null) { - triggerHistory = triggerRouterService.findTriggerHistory(trigger.getSourceTableName()); + triggerHistory = triggerRouterService.findTriggerHistory(trigger + .getSourceTableName()); if (triggerHistory == null) { - triggerHistory = triggerRouterService.findTriggerHistory(trigger.getSourceTableName() - .toUpperCase()); + triggerHistory = triggerRouterService.findTriggerHistory(trigger + .getSourceTableName().toUpperCase()); } } if (triggerHistory != null) { - - String rowData = null; - String pkData = null; - if (whereClause != null) { - rowData = (String) jdbcTemplate.queryForObject(symmetricDialect.createCsvDataSql(trigger, triggerHistory, - configurationService.getChannel(trigger.getChannelId()), - whereClause), String.class); - if (rowData != null) { - rowData = rowData.trim(); - } - pkData = (String) jdbcTemplate.queryForObject(symmetricDialect.createCsvPrimaryKeySql( - trigger, triggerHistory, configurationService.getChannel(trigger.getChannelId()), whereClause), String.class); - if (pkData != null) { - pkData = pkData.trim(); - } - } - data = new Data(trigger.getSourceTableName(), DataEventType.UPDATE, rowData, - pkData, triggerHistory, trigger - .getChannelId(), null, null); - } - } - return data; - } - - public DataRef getDataRef() { - List refs = getSimpleTemplate().query(getSql("findDataRefSql"), - new RowMapper() { - public DataRef mapRow(ResultSet rs, int rowNum) throws SQLException { - return new DataRef(rs.getLong(1), rs.getDate(2)); - } - }); - if (refs.size() > 0) { - return refs.get(0); - } else { - return new DataRef(-1, new Date()); - } - } - - public List findDataGapsByStatus(DataGap.Status status) { - return getSimpleTemplate().query(getSql("findDataGapsByStatusSql"), - new RowMapper() { - public DataGap mapRow(ResultSet rs, int rowNum) throws SQLException { - return new DataGap(rs.getLong(1), rs.getLong(2), rs.getTimestamp(3)); - } - }, status.name()); - } - - public List findDataGaps() { - final long maxDataToSelect = parameterService.getInt(ParameterConstants.ROUTING_LARGEST_GAP_SIZE); - List gaps = findDataGapsByStatus(DataGap.Status.GP); + + String rowData = null; + String pkData = null; + if (whereClause != null) { + rowData = (String) sqlTemplate.queryForObject(symmetricDialect + .createCsvDataSql(trigger, triggerHistory, + configurationService.getChannel(trigger.getChannelId()), + whereClause), String.class); + if (rowData != null) { + rowData = rowData.trim(); + } + pkData = (String) sqlTemplate.queryForObject(symmetricDialect + .createCsvPrimaryKeySql(trigger, triggerHistory, + configurationService.getChannel(trigger.getChannelId()), + whereClause), String.class); + if (pkData != null) { + pkData = pkData.trim(); + } + } + data = new Data(trigger.getSourceTableName(), DataEventType.UPDATE, rowData, + pkData, triggerHistory, trigger.getChannelId(), null, null); + } + } + return data; + } + + public List findDataGapsByStatus(DataGap.Status status) { + return sqlTemplate.query(getSql("findDataGapsByStatusSql"), new ISqlRowMapper() { + public DataGap mapRow(Row rs) { + return new DataGap(rs.getLong("start_id"), rs.getLong("end_id"), rs + .getDateTime("create_time")); + } + }, status.name()); + } + + public List findDataGaps() { + final long maxDataToSelect = parameterService + .getInt(ParameterConstants.ROUTING_LARGEST_GAP_SIZE); + List gaps = findDataGapsByStatus(DataGap.Status.GP); boolean lastGapExists = false; for (DataGap dataGap : gaps) { - lastGapExists |= dataGap.gapSize() >= maxDataToSelect-1; - } - - if (!lastGapExists) { + lastGapExists |= dataGap.gapSize() >= maxDataToSelect - 1; + } + + if (!lastGapExists) { long maxDataId = findMaxDataEventDataId(); if (maxDataId > 0) { maxDataId++; - } - insertDataGap(new DataGap(maxDataId, maxDataId+maxDataToSelect)); - gaps = findDataGaps(); - } - return gaps; - - } - + } + insertDataGap(new DataGap(maxDataId, maxDataId + maxDataToSelect)); + gaps = findDataGaps(); + } + return gaps; + + } + public long findMaxDataEventDataId() { - return jdbcTemplate.queryForLong(getSql("selectMaxDataEventDataIdSql")); - } - + return sqlTemplate.queryForLong(getSql("selectMaxDataEventDataIdSql")); + } + public void insertDataGap(DataGap gap) { try { - jdbcTemplate.update(getSql("insertDataGapSql"), new Object[] { DataGap.Status.GP.name(), - AppUtils.getHostName(), gap.getStartId(), gap.getEndId() }, new int[] { - Types.VARCHAR, Types.VARCHAR, Types.NUMERIC, Types.NUMERIC }); + sqlTemplate.update(getSql("insertDataGapSql"), new Object[] { DataGap.Status.GP.name(), + AppUtils.getHostName(), gap.getStartId(), gap.getEndId() }, new int[] { + Types.VARCHAR, Types.VARCHAR, Types.NUMERIC, Types.NUMERIC }); } catch (DataIntegrityViolationException ex) { log.warn("GapAlreadyExisted", gap.getStartId(), gap.getEndId()); - updateDataGap(gap, DataGap.Status.GP); - } - } - - public void updateDataGap(DataGap gap, DataGap.Status status) { - jdbcTemplate.update( - getSql("updateDataGapSql"), - new Object[] { status.name(), AppUtils.getHostName(), gap.getStartId(), + updateDataGap(gap, DataGap.Status.GP); + } + } + + public void updateDataGap(DataGap gap, DataGap.Status status) { + sqlTemplate.update( + getSql("updateDataGapSql"), + new Object[] { status.name(), AppUtils.getHostName(), gap.getStartId(), gap.getEndId() }, new int[] { Types.VARCHAR, Types.VARCHAR, Types.NUMERIC, Types.NUMERIC }); - } - - public void saveDataRef(DataRef dataRef) { - if (0 >= jdbcTemplate.update(getSql("updateDataRefSql"), new Object[] { - dataRef.getRefDataId(), dataRef.getRefTime() }, new int[] { Types.NUMERIC, - Types.TIMESTAMP })) { - jdbcTemplate.update(getSql("insertDataRefSql"), new Object[] { dataRef.getRefDataId(), - dataRef.getRefTime() }, new int[] { Types.NUMERIC, Types.TIMESTAMP }); - } - } - - public Date findCreateTimeOfEvent(long dataId) { - try { - return (Date) jdbcTemplate.queryForObject(getSql("findDataEventCreateTimeSql"), - new Object[] { dataId }, new int[] { Types.NUMERIC }, Date.class); - } catch (EmptyResultDataAccessException ex) { - return null; - } - } - - public Date findCreateTimeOfData(long dataId) { - try { - return (Date) jdbcTemplate.queryForObject(getSql("findDataCreateTimeSql"), - new Object[] { dataId }, new int[] { Types.NUMERIC }, Date.class); - } catch (EmptyResultDataAccessException ex) { - return null; - } - } - - public Map getRowDataAsMap(Data data) { - Map map = new HashMap(); - String[] columnNames = CsvUtils.tokenizeCsvData(data.getTriggerHistory().getColumnNames()); - String[] columnData = CsvUtils.tokenizeCsvData(data.getRowData()); - for (int i = 0; i < columnNames.length; i++) { - map.put(columnNames[i].toLowerCase(), columnData[i]); - } - return map; - } - - public void setRowDataFromMap(Data data, Map map) { - String[] columnNames = CsvUtils.tokenizeCsvData(data.getTriggerHistory().getColumnNames()); - ByteArrayOutputStream out = new ByteArrayOutputStream(); - CsvWriter writer = new CsvWriter(new OutputStreamWriter(out), ','); - writer.setEscapeMode(CsvWriter.ESCAPE_MODE_BACKSLASH); - for (String columnName : columnNames) { - try { - writer.write(map.get(columnName.toLowerCase()), true); - } catch (IOException e) { - } - } - writer.close(); - data.setRowData(out.toString()); - } - - /** - * Get a list of {@link IHeartbeatListener}s that are ready for a heartbeat - * according to - * {@link IHeartbeatListener#getTimeBetweenHeartbeatsInSeconds()} - * - * @param force - * if true, then return the entire list of - * {@link IHeartbeatListener}s - */ - protected List getHeartbeatListeners(boolean force) { - if (force) { - return this.heartbeatListeners; - } else { - List listeners = new ArrayList(); - if (listeners != null) { - long ts = System.currentTimeMillis(); - for (IHeartbeatListener iHeartbeatListener : this.heartbeatListeners) { - Long lastHeartbeatTimestamp = lastHeartbeatTimestamps.get(iHeartbeatListener); - if (lastHeartbeatTimestamp == null - || lastHeartbeatTimestamp <= ts - - (iHeartbeatListener.getTimeBetweenHeartbeatsInSeconds() * 1000)) { - listeners.add(iHeartbeatListener); - } - } - } - return listeners; - } - } - - protected void updateLastHeartbeatTime(List listeners) { - if (listeners != null) { - Long ts = System.currentTimeMillis(); - for (IHeartbeatListener iHeartbeatListener : listeners) { - lastHeartbeatTimestamps.put(iHeartbeatListener, ts); - } - } - } - - /** - * @see IDataService#heartbeat() - */ - @Transactional - public void heartbeat(boolean force) { - List listeners = getHeartbeatListeners(force); - if (listeners.size() > 0) { - Node me = nodeService.findIdentity(); - if (me != null) { - log.info("NodeVersionUpdating"); - Calendar now = Calendar.getInstance(); + } + + public Date findCreateTimeOfEvent(long dataId) { + try { + return sqlTemplate.queryForObject(getSql("findDataEventCreateTimeSql"), Date.class, + new Object[] { dataId }, new int[] { Types.NUMERIC }); + } catch (EmptyResultDataAccessException ex) { + return null; + } + } + + public Date findCreateTimeOfData(long dataId) { + try { + return sqlTemplate.queryForObject(getSql("findDataCreateTimeSql"), Date.class, + new Object[] { dataId }, new int[] { Types.NUMERIC }); + } catch (EmptyResultDataAccessException ex) { + return null; + } + } + + public Map getRowDataAsMap(Data data) { + Map map = new HashMap(); + String[] columnNames = CsvUtils.tokenizeCsvData(data.getTriggerHistory().getColumnNames()); + String[] columnData = CsvUtils.tokenizeCsvData(data.getRowData()); + for (int i = 0; i < columnNames.length; i++) { + map.put(columnNames[i].toLowerCase(), columnData[i]); + } + return map; + } + + public void setRowDataFromMap(Data data, Map map) { + String[] columnNames = CsvUtils.tokenizeCsvData(data.getTriggerHistory().getColumnNames()); + ByteArrayOutputStream out = new ByteArrayOutputStream(); + CsvWriter writer = new CsvWriter(new OutputStreamWriter(out), ','); + writer.setEscapeMode(CsvWriter.ESCAPE_MODE_BACKSLASH); + for (String columnName : columnNames) { + try { + writer.write(map.get(columnName.toLowerCase()), true); + } catch (IOException e) { + } + } + writer.close(); + data.setRowData(out.toString()); + } + + /** + * Get a list of {@link IHeartbeatListener}s that are ready for a heartbeat + * according to + * {@link IHeartbeatListener#getTimeBetweenHeartbeatsInSeconds()} + * + * @param force + * if true, then return the entire list of + * {@link IHeartbeatListener}s + */ + protected List getHeartbeatListeners(boolean force) { + if (force) { + return this.heartbeatListeners; + } else { + List listeners = new ArrayList(); + if (listeners != null) { + long ts = System.currentTimeMillis(); + for (IHeartbeatListener iHeartbeatListener : this.heartbeatListeners) { + Long lastHeartbeatTimestamp = lastHeartbeatTimestamps.get(iHeartbeatListener); + if (lastHeartbeatTimestamp == null + || lastHeartbeatTimestamp <= ts + - (iHeartbeatListener.getTimeBetweenHeartbeatsInSeconds() * 1000)) { + listeners.add(iHeartbeatListener); + } + } + } + return listeners; + } + } + + protected void updateLastHeartbeatTime(List listeners) { + if (listeners != null) { + Long ts = System.currentTimeMillis(); + for (IHeartbeatListener iHeartbeatListener : listeners) { + lastHeartbeatTimestamps.put(iHeartbeatListener, ts); + } + } + } + + /** + * @see IDataService#heartbeat() + */ + public void heartbeat(boolean force) { + List listeners = getHeartbeatListeners(force); + if (listeners.size() > 0) { + Node me = nodeService.findIdentity(); + if (me != null) { + log.info("NodeVersionUpdating"); + Calendar now = Calendar.getInstance(); now.set(Calendar.MILLISECOND, 0); - me.setDeploymentType(deploymentType.getDeploymentType()); - me.setHeartbeatTime(now.getTime()); - me.setTimezoneOffset(AppUtils.getTimezoneOffset()); - me.setSymmetricVersion(Version.version()); - me.setDatabaseType(symmetricDialect.getName()); - me.setDatabaseVersion(symmetricDialect.getVersion()); - me.setBatchInErrorCount(outgoingBatchService - .countOutgoingBatchesInError()); - if (parameterService.is(ParameterConstants.AUTO_UPDATE_NODE_VALUES)) { - log.info("NodeConfigurationUpdating"); - me.setSchemaVersion(parameterService - .getString(ParameterConstants.SCHEMA_VERSION)); - me.setExternalId(parameterService.getExternalId()); - me.setNodeGroupId(parameterService.getNodeGroupId()); - if (!StringUtils.isBlank(parameterService.getSyncUrl())) { - me.setSyncUrl(parameterService.getSyncUrl()); - } - } - - nodeService.updateNode(me); - nodeService.updateNodeHostForCurrentNode(); - log.info("NodeVersionUpdated"); - - Set children = nodeService.findNodesThatOriginatedFromNodeId(me.getNodeId()); - for (IHeartbeatListener l : listeners) { - l.heartbeat(me, children); - } - - updateLastHeartbeatTime(listeners); - - } else { - log.debug("HeartbeatUpdatingFailureNodeNotConfigured"); - } - } - } - - public void setReloadListeners(List listeners) { - this.reloadListeners = listeners; - } - - public void addReloadListener(IReloadListener listener) { - if (reloadListeners == null) { - reloadListeners = new ArrayList(); - } - reloadListeners.add(listener); - } - - public boolean removeReloadListener(IReloadListener listener) { - if (reloadListeners != null) { - return reloadListeners.remove(listener); - } else { - return false; - } - } - - public void setHeartbeatListeners(List listeners) { - this.heartbeatListeners = listeners; - } - - public void addHeartbeatListener(IHeartbeatListener listener) { - if (heartbeatListeners == null) { - heartbeatListeners = new ArrayList(); - } - heartbeatListeners.add(listener); - } - - public boolean removeHeartbeatListener(IHeartbeatListener listener) { - if (heartbeatListeners != null) { - return heartbeatListeners.remove(listener); - } else { - return false; - } - } - + me.setDeploymentType(deploymentType.getDeploymentType()); + me.setHeartbeatTime(now.getTime()); + me.setTimezoneOffset(AppUtils.getTimezoneOffset()); + me.setSymmetricVersion(Version.version()); + me.setDatabaseType(symmetricDialect.getName()); + me.setDatabaseVersion(symmetricDialect.getVersion()); + me.setBatchInErrorCount(outgoingBatchService.countOutgoingBatchesInError()); + if (parameterService.is(ParameterConstants.AUTO_UPDATE_NODE_VALUES)) { + log.info("NodeConfigurationUpdating"); + me.setSchemaVersion(parameterService + .getString(ParameterConstants.SCHEMA_VERSION)); + me.setExternalId(parameterService.getExternalId()); + me.setNodeGroupId(parameterService.getNodeGroupId()); + if (!StringUtils.isBlank(parameterService.getSyncUrl())) { + me.setSyncUrl(parameterService.getSyncUrl()); + } + } + + nodeService.updateNode(me); + nodeService.updateNodeHostForCurrentNode(); + log.info("NodeVersionUpdated"); + + Set children = nodeService.findNodesThatOriginatedFromNodeId(me.getNodeId()); + for (IHeartbeatListener l : listeners) { + l.heartbeat(me, children); + } + + updateLastHeartbeatTime(listeners); + + } else { + log.debug("HeartbeatUpdatingFailureNodeNotConfigured"); + } + } + } + + public void setReloadListeners(List listeners) { + this.reloadListeners = listeners; + } + + public void addReloadListener(IReloadListener listener) { + if (reloadListeners == null) { + reloadListeners = new ArrayList(); + } + reloadListeners.add(listener); + } + + public boolean removeReloadListener(IReloadListener listener) { + if (reloadListeners != null) { + return reloadListeners.remove(listener); + } else { + return false; + } + } + + public void setHeartbeatListeners(List listeners) { + this.heartbeatListeners = listeners; + } + + public void addHeartbeatListener(IHeartbeatListener listener) { + if (heartbeatListeners == null) { + heartbeatListeners = new ArrayList(); + } + heartbeatListeners.add(listener); + } + + public boolean removeHeartbeatListener(IHeartbeatListener listener) { + if (heartbeatListeners != null) { + return heartbeatListeners.remove(listener); + } else { + return false; + } + } + private final String getOrderByDataId(boolean descending) { return descending ? " order by d.data_id desc" : "order by d.data_id asc"; } - + public List listDataIds(long batchId, boolean descending) { - return jdbcTemplate.query(getSql("selectEventDataIdsSql", getOrderByDataId(descending)), new Object[] {batchId}, new SingleColumnRowMapper()); + return sqlTemplate.query(getSql("selectEventDataIdsSql", getOrderByDataId(descending)), + new NumberMapper(), batchId); } - - public List listData(long batchId, long startDataId, String channelId, boolean descending, final int maxRowsToRetrieve) { + + public List listData(long batchId, long startDataId, String channelId, + boolean descending, final int maxRowsToRetrieve) { final List list = new ArrayList(maxRowsToRetrieve); - handleDataSelect(batchId, startDataId, channelId, descending, new IModelRetrievalHandler() { - public boolean retrieved(Data data, String routerId, int count) throws IOException { - list.add(data); - return count < maxRowsToRetrieve; - } - }); + // TODO + // handleDataSelect(batchId, startDataId, channelId, descending, + // new IModelRetrievalHandler() { + // public boolean retrieved(Data data, String routerId, int count) + // throws IOException { + // list.add(data); + // return count < maxRowsToRetrieve; + // } + // }); return list; - } - - public void handleDataSelect(final long batchId, final long startDataId, final String channelId, final boolean descending, - final IModelRetrievalHandler handler) { - jdbcTemplate.execute(new ConnectionCallback() { - public Object doInConnection(Connection conn) throws SQLException, DataAccessException { - ResultSet rs = null; - PreparedStatement ps = null; - boolean autoCommitFlag = conn.getAutoCommit(); - try { - if (symmetricDialect.requiresAutoCommitFalseToSetFetchSize()) { - conn.setAutoCommit(false); - } - String orderBy = getOrderByDataId(descending); - String startAtDataIdSql = startDataId >= 0l ? (descending ? " and d.data_id <= ? " : " and d.data_id >= ? ") : ""; - String sql = symmetricDialect.massageDataExtractionSql(getSql("selectEventDataToExtractSql", startAtDataIdSql, orderBy), - configurationService.getNodeChannel(channelId, false).getChannel()); - ps = conn.prepareStatement(sql, - ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY); - ps.setQueryTimeout(jdbcTemplate.getQueryTimeout()); - ps.setFetchSize(symmetricDialect.getStreamingResultsFetchSize()); - ps.setLong(1, batchId); - if (StringUtils.isNotBlank(startAtDataIdSql)) { - ps.setLong(2, startDataId); - } - long ts = System.currentTimeMillis(); - rs = ps.executeQuery(); - long executeTimeInMs = System.currentTimeMillis()-ts; - if (executeTimeInMs > Constants.LONG_OPERATION_THRESHOLD) { - log.warn("LongRunningOperation", "selecting data to extract", executeTimeInMs); - } - int count = 0; - boolean continueReading = true; - ts = System.currentTimeMillis(); - while (rs.next() && continueReading) { - try { - continueReading = handler.retrieved(readData(rs), rs.getString(13), ++count); - } catch (RuntimeException e) { - throw e; - } catch (Exception e) { - throw new RuntimeException(e); - } - - executeTimeInMs = System.currentTimeMillis()-ts; - if (executeTimeInMs > DateUtils.MILLIS_PER_MINUTE * 10) { - log.warn("LongRunningOperation", "extracted " + count + " data for batch " + batchId, executeTimeInMs); - ts = System.currentTimeMillis(); - } - } - } finally { - if (symmetricDialect.requiresAutoCommitFalseToSetFetchSize()) { - conn.commit(); - conn.setAutoCommit(autoCommitFlag); - } - JdbcUtils.closeResultSet(rs); - JdbcUtils.closeStatement(ps); - } - return null; - } - }); - } - - public Data readData(ResultSet results) throws SQLException { - Data data = new Data(); - data.setDataId(results.getLong(1)); - data.setTableName(results.getString(2)); - data.setEventType(DataEventType.getEventType(results.getString(3))); - data.setRowData(results.getString(4)); - data.setPkData(results.getString(5)); - data.setOldData(results.getString(6)); - data.setCreateTime(results.getDate(7)); - int histId = results.getInt(8); + } + + public Data readData(ResultSet results) throws SQLException { + Data data = new Data(); + data.setDataId(results.getLong(1)); + data.setTableName(results.getString(2)); + data.setDataEventType(DataEventType.getEventType(results.getString(3))); + data.setRowData(results.getString(4)); + data.setPkData(results.getString(5)); + data.setOldData(results.getString(6)); + data.setCreateTime(results.getDate(7)); + int histId = results.getInt(8); data.setTriggerHistory(triggerRouterService.getTriggerHistory(histId)); if (data.getTriggerHistory() == null) { data.setTriggerHistory(new TriggerHistory(histId)); - } - data.setChannelId(results.getString(9)); - data.setTransactionId(results.getString(10)); - data.setSourceNodeId(results.getString(11)); - data.setExternalData(results.getString(12)); - // Be careful adding more columns. Callers might not be expecting them! - return data; - } - + } + data.setChannelId(results.getString(9)); + data.setTransactionId(results.getString(10)); + data.setSourceNodeId(results.getString(11)); + data.setExternalData(results.getString(12)); + // Be careful adding more columns. Callers might not be expecting them! + return data; + } + public long findMaxDataId() { - return jdbcTemplate.queryForLong(getSql("selectMaxDataIdSql")); - } - - - public void setTriggerRouterService(ITriggerRouterService triggerService) { - this.triggerRouterService = triggerService; - } - - public void setNodeService(INodeService nodeService) { - this.nodeService = nodeService; - } - - public void setPurgeService(IPurgeService purgeService) { - this.purgeService = purgeService; - } - - public void setOutgoingBatchService(IOutgoingBatchService outgoingBatchService) { - this.outgoingBatchService = outgoingBatchService; - } - - public void setConfigurationService(IConfigurationService configurationService) { - this.configurationService = configurationService; - } - - public void setStatisticManager(IStatisticManager statisticManager) { - this.statisticManager = statisticManager; + return sqlTemplate.queryForLong(getSql("selectMaxDataIdSql")); } - - public void setDeploymentType(DeploymentType deploymentType) { - this.deploymentType = deploymentType; - } + } \ No newline at end of file diff --git a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/impl/DataServiceSqlMap.java b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/impl/DataServiceSqlMap.java index eec3be7701..2a27d1f632 100644 --- a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/impl/DataServiceSqlMap.java +++ b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/impl/DataServiceSqlMap.java @@ -45,15 +45,6 @@ public DataServiceSqlMap(IDatabasePlatform platform, Map replace putSql("findDataCreateTimeSql" ,"" + "select create_time from $(prefixName)_data where data_id=? " ); - putSql("updateDataRefSql" ,"" + -"update $(prefixName)_data_ref set ref_data_id=?, ref_time=? " ); - - putSql("insertDataRefSql" ,"" + -"insert into $(prefixName)_data_ref (ref_data_id, ref_time) values(?,?) " ); - - putSql("findDataRefSql" ,"" + -"select ref_data_id, ref_time from $(prefixName)_data_ref " ); - putSql("findDataGapsByStatusSql" ,"" + "select start_id, end_id, create_time from $(prefixName)_data_gap where status=? order by start_id asc " ); diff --git a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/impl/IncomingBatchService.java b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/impl/IncomingBatchService.java index 85c0d94239..68f91fd061 100644 --- a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/impl/IncomingBatchService.java +++ b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/impl/IncomingBatchService.java @@ -16,11 +16,10 @@ * "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.jumpmind.symmetric.service.impl; - -import java.sql.ResultSet; -import java.sql.SQLException; + * under the License. + */ +package org.jumpmind.symmetric.service.impl; + import java.util.ArrayList; import java.util.Date; import java.util.HashMap; @@ -29,52 +28,51 @@ import org.apache.commons.lang.StringUtils; import org.jumpmind.db.sql.AbstractSqlMap; +import org.jumpmind.db.sql.ISqlRowMapper; +import org.jumpmind.db.sql.Row; +import org.jumpmind.db.sql.mapper.DateMapper; import org.jumpmind.symmetric.common.ParameterConstants; +import org.jumpmind.symmetric.db.ISymmetricDialect; import org.jumpmind.symmetric.model.IncomingBatch; import org.jumpmind.symmetric.model.IncomingBatch.Status; import org.jumpmind.symmetric.service.IIncomingBatchService; +import org.jumpmind.symmetric.service.IParameterService; import org.jumpmind.symmetric.util.AppUtils; -import org.jumpmind.symmetric.util.MaxRowsStatementCreator; -import org.springframework.dao.DataAccessException; import org.springframework.dao.DataIntegrityViolationException; -import org.springframework.dao.EmptyResultDataAccessException; -import org.springframework.jdbc.core.JdbcTemplate; -import org.springframework.jdbc.core.ResultSetExtractor; -import org.springframework.jdbc.core.RowMapper; -import org.springframework.jdbc.core.SingleColumnRowMapper; -import org.springframework.jdbc.core.namedparam.MapSqlParameterSource; -import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; import org.springframework.transaction.annotation.Transactional; - + /** * @see IIncomingBatchService */ -public class IncomingBatchService extends AbstractService implements IIncomingBatchService { - - public IncomingBatch findIncomingBatch(long batchId, String nodeId) { - try { - return (IncomingBatch) jdbcTemplate.queryForObject(getSql("selectIncomingBatchPrefixSql","findIncomingBatchSql"), new Object[] { batchId, - nodeId }, new IncomingBatchMapper()); - } catch (EmptyResultDataAccessException e) { - return null; - } +public class IncomingBatchService extends AbstractService implements IIncomingBatchService { + + public IncomingBatchService(IParameterService parameterService, + ISymmetricDialect symmetricDialect) { + super(parameterService, symmetricDialect); + } + + public IncomingBatch findIncomingBatch(long batchId, String nodeId) { + return sqlTemplate.queryForObject( + getSql("selectIncomingBatchPrefixSql", "findIncomingBatchSql"), + new IncomingBatchMapper(), batchId, nodeId); } - + @Override protected AbstractSqlMap createSqlMap() { return new IncomingBatchServiceSqlMap(symmetricDialect.getPlatform(), - createReplacementTokens()); + createSqlReplacementTokens()); } - + public int countIncomingBatchesInError() { - return jdbcTemplate.queryForInt(getSql("countIncomingBatchesErrorsSql")); - } - - public List findIncomingBatchErrors(int maxRows) { - return (List) jdbcTemplate.query(new MaxRowsStatementCreator( - getSql("selectIncomingBatchPrefixSql","findIncomingBatchErrorsSql"), maxRows), new IncomingBatchMapper()); + return sqlTemplate.queryForInt(getSql("countIncomingBatchesErrorsSql")); + } + + public List findIncomingBatchErrors(int maxRows) { + return sqlTemplate.query( + getSql("selectIncomingBatchPrefixSql", "findIncomingBatchErrorsSql"), maxRows, + new IncomingBatchMapper()); } - + public List listIncomingBatchTimes(List nodeIds, List channels, List statuses, Date startAtCreateTime) { if (nodeIds != null && nodeIds.size() > 0 && channels != null && channels.size() > 0 @@ -84,15 +82,15 @@ public List listIncomingBatchTimes(List nodeIds, List chan params.put("CHANNELS", channels); params.put("STATUSES", toStringList(statuses)); params.put("CREATE_TIME", startAtCreateTime); - NamedParameterJdbcTemplate template = new NamedParameterJdbcTemplate(jdbcTemplate); - return template.query(getSql("selectCreateTimePrefixSql", containsOnlyErrorStatus(statuses) ? - "listIncomingBatchesInErrorSql" : "listIncomingBatchesSql"), - params, new SingleColumnRowMapper()); + String sql = getSql("selectCreateTimePrefixSql", + containsOnlyErrorStatus(statuses) ? "listIncomingBatchesInErrorSql" + : "listIncomingBatchesSql"); + return sqlTemplate.query(sql, new DateMapper(), params); } else { return new ArrayList(0); } } - + @Transactional public void markIncomingBatchesOk(String nodeId) { List batches = listIncomingBatchesInErrorFor(nodeId); @@ -100,13 +98,15 @@ public void markIncomingBatchesOk(String nodeId) { incomingBatch.setErrorFlag(false); incomingBatch.setStatus(Status.OK); updateIncomingBatch(incomingBatch); - } + } } - + public List listIncomingBatchesInErrorFor(String nodeId) { - return jdbcTemplate.query(getSql("selectIncomingBatchPrefixSql","listIncomingBatchesInErrorForNodeSql"), new IncomingBatchMapper(), nodeId); + return sqlTemplate.query( + getSql("selectIncomingBatchPrefixSql", "listIncomingBatchesInErrorForNodeSql"), + new IncomingBatchMapper(), nodeId); } - + public List listIncomingBatches(List nodeIds, List channels, List statuses, Date startAtCreateTime, final int maxRowsToRetrieve) { if (nodeIds != null && nodeIds.size() > 0 && channels != null && channels.size() > 0 @@ -117,35 +117,20 @@ public List listIncomingBatches(List nodeIds, List> extractor = new ResultSetExtractor>() { - IncomingBatchMapper rowMapper = new IncomingBatchMapper(); + String sql = getSql("selectIncomingBatchPrefixSql", + containsOnlyErrorStatus(statuses) ? "listIncomingBatchesInErrorSql" + : "listIncomingBatchesSql"); - public List extractData(ResultSet rs) throws SQLException, - DataAccessException { - List list = new ArrayList(maxRowsToRetrieve); - int count = 0; - while (rs.next() && count < maxRowsToRetrieve) { - list.add(rowMapper.mapRow(rs, ++count)); - } - return list; - } - }; - - List list = template.query( - getSql("selectIncomingBatchPrefixSql", containsOnlyErrorStatus(statuses) ? - "listIncomingBatchesInErrorSql" : "listIncomingBatchesSql"), - new MapSqlParameterSource(params), extractor); - return list; + return sqlTemplate.query(sql, maxRowsToRetrieve, new IncomingBatchMapper(), params); } else { return new ArrayList(0); } - } - + } + protected boolean containsOnlyErrorStatus(List statuses) { return statuses.size() == 1 && statuses.get(0) == IncomingBatch.Status.ER; - } - + } + protected List toStringList(List statuses) { List statusStrings = new ArrayList(statuses.size()); for (Status status : statuses) { @@ -153,8 +138,8 @@ protected List toStringList(List statuses) { } return statusStrings; - } - + } + public boolean acquireIncomingBatch(IncomingBatch batch) { boolean okayToProcess = true; if (batch.isPersistable()) { @@ -168,11 +153,12 @@ public boolean acquireIncomingBatch(IncomingBatch batch) { } if (batch.isRetry()) { - if (existingBatch.getStatus() == Status.ER || existingBatch.getStatus() == Status.LD + if (existingBatch.getStatus() == Status.ER + || existingBatch.getStatus() == Status.LD || !parameterService .is(ParameterConstants.INCOMING_BATCH_SKIP_DUPLICATE_BATCHES_ENABLED)) { okayToProcess = true; - existingBatch.setStatus(Status.LD); + existingBatch.setStatus(Status.LD); log.warn("BatchRetrying", batch.getNodeBatchId()); } else { okayToProcess = false; @@ -184,13 +170,13 @@ public boolean acquireIncomingBatch(IncomingBatch batch) { } } return okayToProcess; - } - + } + public void insertIncomingBatch(IncomingBatch batch) { if (batch.isPersistable()) { batch.setLastUpdatedHostName(AppUtils.getServerId()); batch.setLastUpdatedTime(new Date()); - jdbcTemplate.update( + sqlTemplate.update( getSql("insertIncomingBatchSql"), new Object[] { Long.valueOf(batch.getBatchId()), batch.getNodeId(), batch.getChannelId(), batch.getStatus().name(), @@ -203,13 +189,9 @@ public void insertIncomingBatch(IncomingBatch batch) { StringUtils.abbreviate(batch.getSqlMessage(), 1000), batch.getLastUpdatedHostName(), batch.getLastUpdatedTime() }); } - } + } public int updateIncomingBatch(IncomingBatch batch) { - return updateIncomingBatch(this.jdbcTemplate, batch); - } - - public int updateIncomingBatch(JdbcTemplate template, IncomingBatch batch) { int count = 0; if (batch.isPersistable()) { if (batch.getStatus() == IncomingBatch.Status.ER) { @@ -219,47 +201,48 @@ public int updateIncomingBatch(JdbcTemplate template, IncomingBatch batch) { } batch.setLastUpdatedHostName(AppUtils.getServerId()); batch.setLastUpdatedTime(new Date()); - count = template.update( + count = sqlTemplate.update( getSql("updateIncomingBatchSql"), - new Object[] { batch.getStatus().name(), batch.isErrorFlag() ? 1 : 0, batch.getNetworkMillis(), - batch.getFilterMillis(), batch.getDatabaseMillis(), - batch.getFailedRowNumber(), batch.getByteCount(), - batch.getStatementCount(), batch.getFallbackInsertCount(), - batch.getFallbackUpdateCount(), batch.getMissingDeleteCount(), - batch.getSkipCount(), batch.getSqlState(), batch.getSqlCode(), + new Object[] { batch.getStatus().name(), batch.isErrorFlag() ? 1 : 0, + batch.getNetworkMillis(), batch.getFilterMillis(), + batch.getDatabaseMillis(), batch.getFailedRowNumber(), + batch.getByteCount(), batch.getStatementCount(), + batch.getFallbackInsertCount(), batch.getFallbackUpdateCount(), + batch.getMissingDeleteCount(), batch.getSkipCount(), + batch.getSqlState(), batch.getSqlCode(), StringUtils.abbreviate(batch.getSqlMessage(), 1000), batch.getLastUpdatedHostName(), batch.getLastUpdatedTime(), Long.valueOf(batch.getBatchId()), batch.getNodeId() }); } return count; - } - - class IncomingBatchMapper implements RowMapper { - public IncomingBatch mapRow(ResultSet rs, int num) throws SQLException { - IncomingBatch batch = new IncomingBatch(); - batch.setBatchId(rs.getLong(1)); - batch.setNodeId(rs.getString(2)); - batch.setChannelId(rs.getString(3)); - batch.setStatus(IncomingBatch.Status.valueOf(rs.getString(4))); - batch.setNetworkMillis(rs.getLong(5)); - batch.setFilterMillis(rs.getLong(6)); - batch.setDatabaseMillis(rs.getLong(7)); - batch.setFailedRowNumber(rs.getLong(8)); - batch.setByteCount(rs.getLong(9)); - batch.setStatementCount(rs.getLong(10)); - batch.setFallbackInsertCount(rs.getLong(11)); - batch.setFallbackUpdateCount(rs.getLong(12)); - batch.setMissingDeleteCount(rs.getLong(13)); - batch.setSkipCount(rs.getLong(14)); - batch.setSqlState(rs.getString(15)); - batch.setSqlCode(rs.getInt(16)); - batch.setSqlMessage(rs.getString(17)); - batch.setLastUpdatedHostName(rs.getString(18)); - batch.setLastUpdatedTime(rs.getTimestamp(19)); - batch.setCreateTime(rs.getTimestamp(20)); - batch.setErrorFlag(rs.getBoolean(21)); - return batch; - } - } - + } + + class IncomingBatchMapper implements ISqlRowMapper { + public IncomingBatch mapRow(Row rs) { + IncomingBatch batch = new IncomingBatch(); + batch.setBatchId(rs.getLong("batch_id")); + batch.setNodeId(rs.getString("node_id")); + batch.setChannelId(rs.getString("channel_id")); + batch.setStatus(IncomingBatch.Status.valueOf(rs.getString("status"))); + batch.setNetworkMillis(rs.getLong("network_millis")); + batch.setFilterMillis(rs.getLong("filter_millis")); + batch.setDatabaseMillis(rs.getLong("database_millis")); + batch.setFailedRowNumber(rs.getLong("failed_row_number")); + batch.setByteCount(rs.getLong("byte_count")); + batch.setStatementCount(rs.getLong("statement_count")); + batch.setFallbackInsertCount(rs.getLong("fallback_insert_count")); + batch.setFallbackUpdateCount(rs.getLong("fallback_update_count")); + batch.setMissingDeleteCount(rs.getLong("missing_delete_count")); + batch.setSkipCount(rs.getLong("skip_count")); + batch.setSqlState(rs.getString("sql_state")); + batch.setSqlCode(rs.getInt("sql_code")); + batch.setSqlMessage(rs.getString("sql_message")); + batch.setLastUpdatedHostName(rs.getString("last_update_host_name")); + batch.setLastUpdatedTime(rs.getDateTime("last_update_time")); + batch.setCreateTime(rs.getDateTime("create_time")); + batch.setErrorFlag(rs.getBoolean("error_flag")); + return batch; + } + } + } \ No newline at end of file diff --git a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/impl/NodeService.java b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/impl/NodeService.java index f3218b220a..2f0657a4a7 100644 --- a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/impl/NodeService.java +++ b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/impl/NodeService.java @@ -16,11 +16,10 @@ * "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.jumpmind.symmetric.service.impl; - -import java.sql.ResultSet; -import java.sql.SQLException; + * under the License. + */ +package org.jumpmind.symmetric.service.impl; + import java.sql.Types; import java.util.ArrayList; import java.util.Collection; @@ -34,8 +33,12 @@ import org.apache.commons.lang.StringUtils; import org.jumpmind.db.sql.AbstractSqlMap; +import org.jumpmind.db.sql.ISqlRowMapper; +import org.jumpmind.db.sql.Row; +import org.jumpmind.db.sql.mapper.StringMapper; import org.jumpmind.symmetric.common.ParameterConstants; import org.jumpmind.symmetric.config.INodeIdGenerator; +import org.jumpmind.symmetric.db.ISymmetricDialect; import org.jumpmind.symmetric.ext.IOfflineServerListener; import org.jumpmind.symmetric.model.NetworkedNode; import org.jumpmind.symmetric.model.Node; @@ -45,313 +48,329 @@ import org.jumpmind.symmetric.model.NodeStatus; import org.jumpmind.symmetric.security.INodePasswordFilter; import org.jumpmind.symmetric.service.INodeService; +import org.jumpmind.symmetric.service.IParameterService; import org.jumpmind.symmetric.util.AppUtils; import org.springframework.dao.CannotAcquireLockException; -import org.springframework.dao.DataAccessException; import org.springframework.dao.DataIntegrityViolationException; import org.springframework.dao.EmptyResultDataAccessException; -import org.springframework.jdbc.core.ResultSetExtractor; -import org.springframework.jdbc.core.RowMapper; - + /** * @see INodeService */ -public class NodeService extends AbstractService implements INodeService { - - private Node cachedNodeIdentity; - - private Map securityCache; - - private long securityCacheTime; - - private INodeIdGenerator nodeIdGenerator; - - private INodePasswordFilter nodePasswordFilter; - - private NodeHost nodeHostForCurrentNode = null; - - private long offlineNodeDetectionMinutes; - +public class NodeService extends AbstractService implements INodeService { + + private Node cachedNodeIdentity; + + private Map securityCache; + + private long securityCacheTime; + + private INodeIdGenerator nodeIdGenerator; + + private INodePasswordFilter nodePasswordFilter; + + private NodeHost nodeHostForCurrentNode = null; + + private long offlineNodeDetectionMinutes; + private List offlineServerListeners; - + + public NodeService(IParameterService parameterService, ISymmetricDialect dialect) { + super(parameterService, dialect); + } + @Override protected AbstractSqlMap createSqlMap() { - return new NodeServiceSqlMap(symmetricDialect.getPlatform(), - createReplacementTokens()); - } - - public String findSymmetricVersion() { - try { - return (String) jdbcTemplate.queryForObject(getSql("findSymmetricVersionSql"), String.class); - } catch (EmptyResultDataAccessException ex) { - return null; - } - } - - public String findIdentityNodeId() { - Node node = findIdentity(); - return node != null ? node.getNodeId() : null; - } - - public Collection findEnabledNodesFromNodeGroup(String nodeGroupId) { - return jdbcTemplate.query(getSql("selectNodePrefixSql","findEnabledNodesFromNodeGroupSql"), new Object[] { nodeGroupId }, new NodeRowMapper()); - } - + return new NodeServiceSqlMap(symmetricDialect.getPlatform(), createSqlReplacementTokens()); + } + + public String findSymmetricVersion() { + try { + return (String) sqlTemplate.queryForObject(getSql("findSymmetricVersionSql"), + String.class); + } catch (EmptyResultDataAccessException ex) { + return null; + } + } + + public String findIdentityNodeId() { + Node node = findIdentity(); + return node != null ? node.getNodeId() : null; + } + + public Collection findEnabledNodesFromNodeGroup(String nodeGroupId) { + return sqlTemplate.query( + getSql("selectNodePrefixSql", "findEnabledNodesFromNodeGroupSql"), + new NodeRowMapper(), new Object[] { nodeGroupId }); + } + public Set findNodesThatOriginatedFromNodeId(String originalNodeId) { return findNodesThatOriginatedFromNodeId(originalNodeId, true); } - + public Collection findNodesWithOpenRegistration() { - return jdbcTemplate.query(getSql("selectNodePrefixSql","findNodesWithOpenRegistrationSql"), new NodeRowMapper()); - } - - public Set findNodesThatOriginatedFromNodeId(String originalNodeId, boolean recursive) { - Set all = new HashSet(); - List list = jdbcTemplate.query(getSql("selectNodePrefixSql","findNodesCreatedByMeSql"), new Object[] { originalNodeId }, new NodeRowMapper()); - if (list.size() > 0) { + return sqlTemplate.query( + getSql("selectNodePrefixSql", "findNodesWithOpenRegistrationSql"), + new NodeRowMapper()); + } + + public Set findNodesThatOriginatedFromNodeId(String originalNodeId, boolean recursive) { + Set all = new HashSet(); + List list = sqlTemplate.query( + getSql("selectNodePrefixSql", "findNodesCreatedByMeSql"), new NodeRowMapper(), + originalNodeId); + if (list.size() > 0) { all.addAll(list); if (recursive) { for (Node node : list) { all.addAll(findNodesThatOriginatedFromNodeId(node.getNodeId())); } - } - } - return all; - } - - /** - * Lookup a node in the database, which contains information for syncing - * with it. - */ - public Node findNode(String id) { - List list = jdbcTemplate.query(getSql("selectNodePrefixSql","findNodeSql"), - new Object[] { id }, new NodeRowMapper()); - return (Node) getFirstEntry(list); - } - - public Node findNodeByExternalId(String nodeGroupId, String externalId) { - List list = jdbcTemplate.query(getSql("selectNodePrefixSql","findNodeByExternalIdSql"), - new Object[] { nodeGroupId, externalId }, new NodeRowMapper()); - return (Node) getFirstEntry(list); - } - - public void ignoreNodeChannelForExternalId(boolean enabled, String channelId, String nodeGroupId, String externalId) { - Node node = findNodeByExternalId(nodeGroupId, externalId); - if (jdbcTemplate.update(getSql("nodeChannelControlIgnoreSql"), new Object[] { enabled ? 1 : 0, - node.getNodeId(), channelId }) == 0) { - jdbcTemplate.update(getSql("insertNodeChannelControlSql"), new Object[] { node.getNodeId(), channelId, - enabled ? 1 : 0, 0 }); - } - } - - public boolean isRegistrationEnabled(String nodeId) { - NodeSecurity nodeSecurity = findNodeSecurity(nodeId); - if (nodeSecurity != null) { - return nodeSecurity.isRegistrationEnabled(); - } - return false; - } - - /** - * Lookup a node_security in the database, which contains private - * information used to authenticate. - */ - public NodeSecurity findNodeSecurity(String id) { - return findNodeSecurity(id, false); - } - + } + } + return all; + } + + /** + * Lookup a node in the database, which contains information for syncing + * with it. + */ + public Node findNode(String id) { + List list = sqlTemplate.query(getSql("selectNodePrefixSql", "findNodeSql"), + new NodeRowMapper(), id); + return (Node) getFirstEntry(list); + } + + public Node findNodeByExternalId(String nodeGroupId, String externalId) { + List list = sqlTemplate.query( + getSql("selectNodePrefixSql", "findNodeByExternalIdSql"), new NodeRowMapper(), + nodeGroupId, externalId); + return (Node) getFirstEntry(list); + } + + public void ignoreNodeChannelForExternalId(boolean enabled, String channelId, + String nodeGroupId, String externalId) { + Node node = findNodeByExternalId(nodeGroupId, externalId); + if (sqlTemplate.update(getSql("nodeChannelControlIgnoreSql"), new Object[] { + enabled ? 1 : 0, node.getNodeId(), channelId }) == 0) { + sqlTemplate.update(getSql("insertNodeChannelControlSql"), + new Object[] { node.getNodeId(), channelId, enabled ? 1 : 0, 0 }); + } + } + + public boolean isRegistrationEnabled(String nodeId) { + NodeSecurity nodeSecurity = findNodeSecurity(nodeId); + if (nodeSecurity != null) { + return nodeSecurity.isRegistrationEnabled(); + } + return false; + } + + /** + * Lookup a node_security in the database, which contains private + * information used to authenticate. + */ + public NodeSecurity findNodeSecurity(String id) { + return findNodeSecurity(id, false); + } + public List findNodeHosts(String nodeId) { - return jdbcTemplate.query(getSql("selectNodeHostPrefixSql", "selectNodeHostByNodeIdSql"), new NodeHostRowMapper(), nodeId); - } - - public void updateNodeHostForCurrentNode() { - if (nodeHostForCurrentNode == null) { - nodeHostForCurrentNode = new NodeHost(findIdentityNodeId()); - } - nodeHostForCurrentNode.refresh(); - Object[] params = new Object[] { - nodeHostForCurrentNode.getIpAddress(), - nodeHostForCurrentNode.getOsUser(), - nodeHostForCurrentNode.getOsName(), - nodeHostForCurrentNode.getOsArch(), - nodeHostForCurrentNode.getOsVersion(), - nodeHostForCurrentNode.getAvailableProcessors(), - nodeHostForCurrentNode.getFreeMemoryBytes(), - nodeHostForCurrentNode.getTotalMemoryBytes(), - nodeHostForCurrentNode.getMaxMemoryBytes(), - nodeHostForCurrentNode.getJavaVersion(), - nodeHostForCurrentNode.getJavaVendor(), - nodeHostForCurrentNode.getSymmetricVersion(), - nodeHostForCurrentNode.getTimezoneOffset(), - nodeHostForCurrentNode.getHeartbeatTime(), - nodeHostForCurrentNode.getLastRestartTime(), - nodeHostForCurrentNode.getNodeId(), - nodeHostForCurrentNode.getHostName() - }; - if (jdbcTemplate.update(getSql("updateNodeHostSql"), params) == 0) { - jdbcTemplate.update(getSql("insertNodeHostSql"), params); - } - } - - public NodeSecurity findNodeSecurity(String nodeId, boolean createIfNotFound) { - try { - if (nodeId != null) { - List list = jdbcTemplate.query(getSql("findNodeSecuritySql"), new Object[] { nodeId }, - new int[] { Types.VARCHAR }, new NodeSecurityRowMapper()); - NodeSecurity security = (NodeSecurity) getFirstEntry(list); - if (security == null && createIfNotFound) { - insertNodeSecurity(nodeId); - security = findNodeSecurity(nodeId, false); - } - return security; - } else { - log.debug("FindNodeSecurityNodeNull"); - return null; - } - } catch (DataIntegrityViolationException ex) { - log.error("NodeSecurityMissing", nodeId); - throw ex; - } - } - - public void deleteNodeSecurity(String nodeId) { - jdbcTemplate.update(getSql("deleteNodeSecuritySql"), new Object[] { nodeId }); - } - + return sqlTemplate.query(getSql("selectNodeHostPrefixSql", "selectNodeHostByNodeIdSql"), + new NodeHostRowMapper(), nodeId); + } + + public void updateNodeHostForCurrentNode() { + if (nodeHostForCurrentNode == null) { + nodeHostForCurrentNode = new NodeHost(findIdentityNodeId()); + } + nodeHostForCurrentNode.refresh(); + Object[] params = new Object[] { nodeHostForCurrentNode.getIpAddress(), + nodeHostForCurrentNode.getOsUser(), nodeHostForCurrentNode.getOsName(), + nodeHostForCurrentNode.getOsArch(), nodeHostForCurrentNode.getOsVersion(), + nodeHostForCurrentNode.getAvailableProcessors(), + nodeHostForCurrentNode.getFreeMemoryBytes(), + nodeHostForCurrentNode.getTotalMemoryBytes(), + nodeHostForCurrentNode.getMaxMemoryBytes(), + nodeHostForCurrentNode.getJavaVersion(), nodeHostForCurrentNode.getJavaVendor(), + nodeHostForCurrentNode.getSymmetricVersion(), + nodeHostForCurrentNode.getTimezoneOffset(), + nodeHostForCurrentNode.getHeartbeatTime(), + nodeHostForCurrentNode.getLastRestartTime(), nodeHostForCurrentNode.getNodeId(), + nodeHostForCurrentNode.getHostName() }; + if (sqlTemplate.update(getSql("updateNodeHostSql"), params) == 0) { + sqlTemplate.update(getSql("insertNodeHostSql"), params); + } + } + + public NodeSecurity findNodeSecurity(String nodeId, boolean createIfNotFound) { + try { + if (nodeId != null) { + List list = sqlTemplate.query(getSql("findNodeSecuritySql"), + new NodeSecurityRowMapper(), new Object[] { nodeId }, + new int[] { Types.VARCHAR }); + NodeSecurity security = (NodeSecurity) getFirstEntry(list); + if (security == null && createIfNotFound) { + insertNodeSecurity(nodeId); + security = findNodeSecurity(nodeId, false); + } + return security; + } else { + log.debug("FindNodeSecurityNodeNull"); + return null; + } + } catch (DataIntegrityViolationException ex) { + log.error("NodeSecurityMissing", nodeId); + throw ex; + } + } + + public void deleteNodeSecurity(String nodeId) { + sqlTemplate.update(getSql("deleteNodeSecuritySql"), new Object[] { nodeId }); + } + public void deleteNode(String nodeId) { - jdbcTemplate.update(getSql("deleteNodeSql"), new Object[] { nodeId }); - } - - public void insertNodeSecurity(String id) { - flushNodeAuthorizedCache(); - String password = nodeIdGenerator.generatePassword(this, new Node(id, null, null)); - password = filterPasswordOnSaveIfNeeded(password); - jdbcTemplate.update(getSql("insertNodeSecuritySql"), new Object[] { id, password, findIdentity().getNodeId() }); - } - - public void insertNodeIdentity(String nodeId) { - jdbcTemplate.update(getSql("insertNodeIdentitySql"), nodeId); - } - - public void deleteIdentity() { - jdbcTemplate.execute(getSql("deleteNodeIdentitySql")); - cachedNodeIdentity = null; - } - - public void insertNode(String nodeId, String nodeGroupdId, String externalId, String createdAtNodeId) { - jdbcTemplate.update(getSql("insertNodeSql"), new Object[] { nodeId, nodeGroupdId, - externalId, createdAtNodeId, AppUtils.getTimezoneOffset() }); - } - - public void insertNodeGroup(String groupId, String description) { - if (jdbcTemplate.queryForInt(getSql("doesNodeGroupExistSql"), groupId) == 0) { - jdbcTemplate.update(getSql("insertNodeGroupSql"), description, groupId); - } - } - - public boolean updateNode(Node node) { - boolean updated = jdbcTemplate.update(getSql("updateNodeSql"), new Object[] { node.getNodeGroupId(), - node.getExternalId(), node.getDatabaseType(), node.getDatabaseVersion(), node.getSchemaVersion(), - node.getSymmetricVersion(), node.getSyncUrl(), node.getHeartbeatTime(), node.isSyncEnabled() ? 1 : 0, - node.getTimezoneOffset(), node.getBatchToSendCount(), node.getBatchInErrorCount(), node.getCreatedAtNodeId(), node.getDeploymentType(), node.getNodeId() }, new int[] { Types.VARCHAR, - Types.VARCHAR, Types.VARCHAR, Types.VARCHAR, Types.VARCHAR, Types.VARCHAR, Types.VARCHAR, - Types.TIMESTAMP, Types.INTEGER, Types.VARCHAR, Types.INTEGER, Types.INTEGER, Types.VARCHAR, Types.VARCHAR, Types.VARCHAR }) == 1; - return updated; - } - - protected T getFirstEntry(List list) { - if (list != null && list.size() > 0) { - return list.get(0); - } - return null; - } - - public Map findAllNodeSecurity(boolean useCache) { - long maxSecurityCacheTime = parameterService - .getLong(ParameterConstants.CACHE_TIMEOUT_NODE_SECURITY_IN_MS); - Map all = securityCache; - if (all == null || System.currentTimeMillis() - securityCacheTime >= maxSecurityCacheTime - || securityCacheTime == 0 || !useCache) { - all = (Map) jdbcTemplate.query( - getSql("findAllNodeSecuritySql"), new NodeSecurityResultSetExtractor()); - securityCache = all; - securityCacheTime = System.currentTimeMillis(); - } - return all; - } - - /** - * Check that the given node and password match in the node_security table. - * A node must authenticate before it's allowed to sync data. - */ - public boolean isNodeAuthorized(String nodeId, String password) { - Map nodeSecurities = findAllNodeSecurity(true); - NodeSecurity nodeSecurity = nodeSecurities.get(nodeId); - if (nodeSecurity != null - && ((nodeSecurity.getNodePassword() != null && !nodeSecurity.getNodePassword().equals("") && nodeSecurity - .getNodePassword().equals(password)) || nodeSecurity.isRegistrationEnabled())) { - return true; - } - return false; - } - - public void flushNodeAuthorizedCache() { - securityCacheTime = 0; - } - + sqlTemplate.update(getSql("deleteNodeSql"), new Object[] { nodeId }); + } + + public void insertNodeSecurity(String id) { + flushNodeAuthorizedCache(); + String password = nodeIdGenerator.generatePassword(this, new Node(id, null, null)); + password = filterPasswordOnSaveIfNeeded(password); + sqlTemplate.update(getSql("insertNodeSecuritySql"), new Object[] { id, password, + findIdentity().getNodeId() }); + } + + public void insertNodeIdentity(String nodeId) { + sqlTemplate.update(getSql("insertNodeIdentitySql"), nodeId); + } + + public void deleteIdentity() { + sqlTemplate.update(getSql("deleteNodeIdentitySql")); + cachedNodeIdentity = null; + } + + public void insertNode(String nodeId, String nodeGroupdId, String externalId, + String createdAtNodeId) { + sqlTemplate.update(getSql("insertNodeSql"), new Object[] { nodeId, nodeGroupdId, + externalId, createdAtNodeId, AppUtils.getTimezoneOffset() }); + } + + public void insertNodeGroup(String groupId, String description) { + if (sqlTemplate.queryForInt(getSql("doesNodeGroupExistSql"), groupId) == 0) { + sqlTemplate.update(getSql("insertNodeGroupSql"), description, groupId); + } + } + + public boolean updateNode(Node node) { + boolean updated = sqlTemplate.update( + getSql("updateNodeSql"), + new Object[] { node.getNodeGroupId(), node.getExternalId(), node.getDatabaseType(), + node.getDatabaseVersion(), node.getSchemaVersion(), + node.getSymmetricVersion(), node.getSyncUrl(), node.getHeartbeatTime(), + node.isSyncEnabled() ? 1 : 0, node.getTimezoneOffset(), + node.getBatchToSendCount(), node.getBatchInErrorCount(), + node.getCreatedAtNodeId(), node.getDeploymentType(), node.getNodeId() }, + new int[] { Types.VARCHAR, Types.VARCHAR, Types.VARCHAR, Types.VARCHAR, + Types.VARCHAR, Types.VARCHAR, Types.VARCHAR, Types.TIMESTAMP, + Types.INTEGER, Types.VARCHAR, Types.INTEGER, Types.INTEGER, Types.VARCHAR, + Types.VARCHAR, Types.VARCHAR }) == 1; + return updated; + } + + protected T getFirstEntry(List list) { + if (list != null && list.size() > 0) { + return list.get(0); + } + return null; + } + + public Map findAllNodeSecurity(boolean useCache) { + long maxSecurityCacheTime = parameterService + .getLong(ParameterConstants.CACHE_TIMEOUT_NODE_SECURITY_IN_MS); + Map all = securityCache; + if (all == null || System.currentTimeMillis() - securityCacheTime >= maxSecurityCacheTime + || securityCacheTime == 0 || !useCache) { + all = (Map) sqlTemplate.queryForMap( + getSql("findAllNodeSecuritySql"), new NodeSecurityRowMapper(), "node_id"); + securityCache = all; + securityCacheTime = System.currentTimeMillis(); + } + return all; + } + + /** + * Check that the given node and password match in the node_security table. + * A node must authenticate before it's allowed to sync data. + */ + public boolean isNodeAuthorized(String nodeId, String password) { + Map nodeSecurities = findAllNodeSecurity(true); + NodeSecurity nodeSecurity = nodeSecurities.get(nodeId); + if (nodeSecurity != null + && ((nodeSecurity.getNodePassword() != null + && !nodeSecurity.getNodePassword().equals("") && nodeSecurity + .getNodePassword().equals(password)) || nodeSecurity + .isRegistrationEnabled())) { + return true; + } + return false; + } + + public void flushNodeAuthorizedCache() { + securityCacheTime = 0; + } + public Node getCachedIdentity() { return cachedNodeIdentity; - } - - public Node findIdentity() { - return findIdentity(true); - } - - public Node findIdentity(boolean useCache) { - if (cachedNodeIdentity == null || useCache == false) { - List list = jdbcTemplate.query(getSql("selectNodePrefixSql","findNodeIdentitySql"), - new NodeRowMapper()); - cachedNodeIdentity = (Node) getFirstEntry(list); - } - return cachedNodeIdentity; - } - - public List findNodesToPull() { - return findSourceNodesFor(NodeGroupLinkAction.W); - } - - public List findNodesToPushTo() { - return findTargetNodesFor(NodeGroupLinkAction.P); - } - - public List findSourceNodesFor(NodeGroupLinkAction eventAction) { - Node node = findIdentity(); - if (node != null) { - return jdbcTemplate.query(getSql("selectNodePrefixSql","findNodesWhoTargetMeSql"), new Object[] { - node.getNodeGroupId(), eventAction.name() }, new NodeRowMapper()); - } else { - return Collections.emptyList(); - } - } - - public List findTargetNodesFor(NodeGroupLinkAction eventAction) { - Node node = findIdentity(); - if (node != null) { - return jdbcTemplate.query(getSql("selectNodePrefixSql","findNodesWhoITargetSql"), new Object[] { - node.getNodeGroupId(), eventAction.name() }, new NodeRowMapper()); - } else { - return Collections.emptyList(); - } - } - - public List findAllExternalIds() { - return jdbcTemplate.queryForList(getSql("selectExternalIdsSql"), String.class); - } - + } + + public Node findIdentity() { + return findIdentity(true); + } + + public Node findIdentity(boolean useCache) { + if (cachedNodeIdentity == null || useCache == false) { + List list = sqlTemplate.query( + getSql("selectNodePrefixSql", "findNodeIdentitySql"), new NodeRowMapper()); + cachedNodeIdentity = (Node) getFirstEntry(list); + } + return cachedNodeIdentity; + } + + public List findNodesToPull() { + return findSourceNodesFor(NodeGroupLinkAction.W); + } + + public List findNodesToPushTo() { + return findTargetNodesFor(NodeGroupLinkAction.P); + } + + public List findSourceNodesFor(NodeGroupLinkAction eventAction) { + Node node = findIdentity(); + if (node != null) { + return sqlTemplate.query(getSql("selectNodePrefixSql", "findNodesWhoTargetMeSql"), + new NodeRowMapper(), node.getNodeGroupId(), eventAction.name()); + } else { + return Collections.emptyList(); + } + } + + public List findTargetNodesFor(NodeGroupLinkAction eventAction) { + Node node = findIdentity(); + if (node != null) { + return sqlTemplate.query(getSql("selectNodePrefixSql", "findNodesWhoITargetSql"), + new NodeRowMapper(), node.getNodeGroupId(), eventAction.name()); + } else { + return Collections.emptyList(); + } + } + + public List findAllExternalIds() { + return sqlTemplate.query(getSql("selectExternalIdsSql"), new StringMapper()); + } + public List findAllNodes() { - return jdbcTemplate.query(getSql("selectNodePrefixSql"), new NodeRowMapper()); + return sqlTemplate.query(getSql("selectNodePrefixSql"), new NodeRowMapper()); } - + public Map findAllNodesAsMap() { List nodes = findAllNodes(); Map nodeMap = new HashMap(nodes.size()); @@ -360,7 +379,7 @@ public Map findAllNodesAsMap() { } return nodeMap; } - + public NetworkedNode getRootNetworkedNode() { Map nodes = findAllNodesAsMap(); Map leaves = new HashMap(nodes.size()); @@ -374,264 +393,260 @@ public NetworkedNode getRootNetworkedNode() { } } return nodeLeaf.getRoot(); - } - - public boolean updateNodeSecurity(NodeSecurity security) { - flushNodeAuthorizedCache(); - security.setNodePassword(filterPasswordOnSaveIfNeeded(security.getNodePassword())); - return jdbcTemplate.update(getSql("updateNodeSecuritySql"), new Object[] { security.getNodePassword(), - security.isRegistrationEnabled() ? 1 : 0, security.getRegistrationTime(), - security.isInitialLoadEnabled() ? 1 : 0, security.getInitialLoadTime(), security.getCreatedAtNodeId(), - security.getNodeId() }, new int[] { Types.VARCHAR, Types.INTEGER, Types.TIMESTAMP, Types.INTEGER, - Types.TIMESTAMP, Types.VARCHAR, Types.VARCHAR }) == 1; - } - - public boolean setInitialLoadEnabled(String nodeId, boolean initialLoadEnabled) { - NodeSecurity nodeSecurity = findNodeSecurity(nodeId, true); - if (nodeSecurity != null) { - nodeSecurity.setInitialLoadEnabled(initialLoadEnabled); - if (initialLoadEnabled) { - nodeSecurity.setInitialLoadTime(null); - } else { - nodeSecurity.setInitialLoadTime(new Date()); - } - return updateNodeSecurity(nodeSecurity); - } - return false; - } - - public boolean isExternalIdRegistered(String nodeGroupId, String externalId) { - return jdbcTemplate.queryForInt(getSql("isNodeRegisteredSql"), new Object[] { nodeGroupId, externalId }) > 0; - } - - public INodeIdGenerator getNodeIdGenerator() { - return nodeIdGenerator; - } - - public void setNodeIdGenerator(INodeIdGenerator nodeIdGenerator) { - this.nodeIdGenerator = nodeIdGenerator; - } - - public boolean isDataLoadCompleted() { - return getNodeStatus() == NodeStatus.DATA_LOAD_COMPLETED; - } - - public boolean isDataLoadStarted() { - return getNodeStatus() == NodeStatus.DATA_LOAD_STARTED; - } - - public boolean isRegistrationServer() { - return StringUtils.isBlank(parameterService.getRegistrationUrl()) || parameterService.getRegistrationUrl().equals(parameterService.getSyncUrl()); - } - - public NodeStatus getNodeStatus() { - long ts = System.currentTimeMillis(); - try { - class DataLoadStatus { - int initialLoadEnabled; - Date initialLoadTime; - } - - List results = jdbcTemplate.query(getSql("getDataLoadStatusSql"), new RowMapper() { - public DataLoadStatus mapRow(java.sql.ResultSet rs, int arg1) throws java.sql.SQLException { - DataLoadStatus status = new DataLoadStatus(); - status.initialLoadEnabled = rs.getInt(1); - status.initialLoadTime = rs.getTimestamp(2); - return status; - } - }); - - if (results.size() > 0) { - DataLoadStatus status = results.get(0); - if (status.initialLoadEnabled == 1) { - return NodeStatus.DATA_LOAD_STARTED; - } else if (status.initialLoadTime != null) { - return NodeStatus.DATA_LOAD_COMPLETED; - } - } - return NodeStatus.DATA_LOAD_NOT_STARTED; - } catch (CannotAcquireLockException ex) { - log.error("LockAcquiringFailed", (System.currentTimeMillis() - ts)); - return NodeStatus.STATUS_UNKNOWN; - } - } - - public void setNodePasswordFilter(INodePasswordFilter nodePasswordFilter) { - this.nodePasswordFilter = nodePasswordFilter; - } - - private String filterPasswordOnSaveIfNeeded(String password) { - String s = password; - if (nodePasswordFilter != null) { - s = nodePasswordFilter.onNodeSecuritySave(password); - } - return s; - } - - private String filterPasswordOnRenderIfNeeded(String password) { - String s = password; - if (nodePasswordFilter != null) { - s = nodePasswordFilter.onNodeSecurityRender(password); - } - return s; - } - - public void checkForOfflineNodes() { - // Only check for offline nodes if there is a listener and the - // offline detection period is a positive value. The default value - // of -1 disables the feature. - if (offlineServerListeners != null && getOfflineNodeDetectionMinutes() > 0) { - - List list = findOfflineNodes(); - if (list.size() > 0) { - fireOffline(list); - } - } - } - + } + + public boolean updateNodeSecurity(NodeSecurity security) { + flushNodeAuthorizedCache(); + security.setNodePassword(filterPasswordOnSaveIfNeeded(security.getNodePassword())); + return sqlTemplate.update(getSql("updateNodeSecuritySql"), + new Object[] { security.getNodePassword(), + security.isRegistrationEnabled() ? 1 : 0, security.getRegistrationTime(), + security.isInitialLoadEnabled() ? 1 : 0, security.getInitialLoadTime(), + security.getCreatedAtNodeId(), security.getNodeId() }, new int[] { + Types.VARCHAR, Types.INTEGER, Types.TIMESTAMP, Types.INTEGER, + Types.TIMESTAMP, Types.VARCHAR, Types.VARCHAR }) == 1; + } + + public boolean setInitialLoadEnabled(String nodeId, boolean initialLoadEnabled) { + NodeSecurity nodeSecurity = findNodeSecurity(nodeId, true); + if (nodeSecurity != null) { + nodeSecurity.setInitialLoadEnabled(initialLoadEnabled); + if (initialLoadEnabled) { + nodeSecurity.setInitialLoadTime(null); + } else { + nodeSecurity.setInitialLoadTime(new Date()); + } + return updateNodeSecurity(nodeSecurity); + } + return false; + } + + public boolean isExternalIdRegistered(String nodeGroupId, String externalId) { + return sqlTemplate.queryForInt(getSql("isNodeRegisteredSql"), new Object[] { nodeGroupId, + externalId }) > 0; + } + + public INodeIdGenerator getNodeIdGenerator() { + return nodeIdGenerator; + } + + public void setNodeIdGenerator(INodeIdGenerator nodeIdGenerator) { + this.nodeIdGenerator = nodeIdGenerator; + } + + public boolean isDataLoadCompleted() { + return getNodeStatus() == NodeStatus.DATA_LOAD_COMPLETED; + } + + public boolean isDataLoadStarted() { + return getNodeStatus() == NodeStatus.DATA_LOAD_STARTED; + } + + public boolean isRegistrationServer() { + return StringUtils.isBlank(parameterService.getRegistrationUrl()) + || parameterService.getRegistrationUrl().equals(parameterService.getSyncUrl()); + } + + public NodeStatus getNodeStatus() { + long ts = System.currentTimeMillis(); + try { + class DataLoadStatus { + int initialLoadEnabled; + Date initialLoadTime; + } + + List results = sqlTemplate.query(getSql("getDataLoadStatusSql"), + new ISqlRowMapper() { + public DataLoadStatus mapRow(Row rs) { + DataLoadStatus status = new DataLoadStatus(); + status.initialLoadEnabled = rs.getInt("initial_load_enabled"); + status.initialLoadTime = rs.getDateTime("initial_load_time"); + return status; + } + }); + + if (results.size() > 0) { + DataLoadStatus status = results.get(0); + if (status.initialLoadEnabled == 1) { + return NodeStatus.DATA_LOAD_STARTED; + } else if (status.initialLoadTime != null) { + return NodeStatus.DATA_LOAD_COMPLETED; + } + } + return NodeStatus.DATA_LOAD_NOT_STARTED; + } catch (CannotAcquireLockException ex) { + log.error("LockAcquiringFailed", (System.currentTimeMillis() - ts)); + return NodeStatus.STATUS_UNKNOWN; + } + } + + public void setNodePasswordFilter(INodePasswordFilter nodePasswordFilter) { + this.nodePasswordFilter = nodePasswordFilter; + } + + private String filterPasswordOnSaveIfNeeded(String password) { + String s = password; + if (nodePasswordFilter != null) { + s = nodePasswordFilter.onNodeSecuritySave(password); + } + return s; + } + + private String filterPasswordOnRenderIfNeeded(String password) { + String s = password; + if (nodePasswordFilter != null) { + s = nodePasswordFilter.onNodeSecurityRender(password); + } + return s; + } + + public void checkForOfflineNodes() { + // Only check for offline nodes if there is a listener and the + // offline detection period is a positive value. The default value + // of -1 disables the feature. + if (offlineServerListeners != null && getOfflineNodeDetectionMinutes() > 0) { + + List list = findOfflineNodes(); + if (list.size() > 0) { + fireOffline(list); + } + } + } + public List findOfflineNodes() { return findOfflineNodes(getOfflineNodeDetectionMinutes()); - } - - public List findOfflineNodes(long minutesOffline) { - List offlineNodeList = new ArrayList(); - Node myNode = findIdentity(); - - if (myNode != null) { - long offlineNodeDetectionMillis = minutesOffline*60*1000; - - List list = jdbcTemplate.query(getSql("selectNodePrefixSql","findOfflineNodesSql"), - new Object[] { myNode.getNodeId(), myNode.getNodeId()}, - new NodeRowMapper()); - - for (Node node: list) { - // Take the timezone of the client node into account when checking the hearbeat time. - Date clientNodeCurrentTime = null; - if (node.getTimezoneOffset() != null) { - clientNodeCurrentTime = AppUtils.getLocalDateForOffset(node.getTimezoneOffset()); - } else { - clientNodeCurrentTime = new Date(); - } - long cutOffTimeMillis = clientNodeCurrentTime.getTime() - offlineNodeDetectionMillis; - if (node.getHeartbeatTime() == null || node.getHeartbeatTime().getTime() < cutOffTimeMillis) { - offlineNodeList.add(node); - } - } - } - - return offlineNodeList; - } - - public long getOfflineNodeDetectionMinutes() { - return offlineNodeDetectionMinutes; - } - - public void setOfflineNodeDetectionMinutes(long offlineNodeDetectionMinutes) { - this.offlineNodeDetectionMinutes = offlineNodeDetectionMinutes; - } - - public void setOfflineServerListeners(List listeners) { - this.offlineServerListeners = listeners; - } - - public void addOfflineServerListener(IOfflineServerListener listener) { - if (offlineServerListeners == null) { - offlineServerListeners = new ArrayList(); - } - offlineServerListeners.add(listener); - } - - public boolean removeOfflineServerListener(IOfflineServerListener listener) { - if (offlineServerListeners != null) { - return offlineServerListeners.remove(listener); - } else { - return false; - } - } - - protected void fireOffline(List offlineClientNodeList) { - if (offlineServerListeners != null) { - for (IOfflineServerListener listener : offlineServerListeners) { - for (Node node : offlineClientNodeList) { - listener.clientNodeOffline(node); - } - } - } - } - - - class NodeRowMapper implements RowMapper { - public Node mapRow(ResultSet rs, int num) throws SQLException { - Node node = new Node(); - node.setNodeId(rs.getString(1)); - node.setNodeGroupId(rs.getString(2)); - node.setExternalId(rs.getString(3)); - node.setSyncEnabled(rs.getBoolean(4)); - node.setSyncUrl(rs.getString(5)); - node.setSchemaVersion(rs.getString(6)); - node.setDatabaseType(rs.getString(7)); - node.setDatabaseVersion(rs.getString(8)); - node.setSymmetricVersion(rs.getString(9)); - node.setCreatedAtNodeId(rs.getString(10)); - node.setHeartbeatTime(rs.getTimestamp(11)); - node.setTimezoneOffset(rs.getString(12)); - node.setBatchToSendCount(rs.getInt(13)); - node.setBatchInErrorCount(rs.getInt(14)); - node.setDeploymentType(rs.getString(15)); - return node; + } + + public List findOfflineNodes(long minutesOffline) { + List offlineNodeList = new ArrayList(); + Node myNode = findIdentity(); + + if (myNode != null) { + long offlineNodeDetectionMillis = minutesOffline * 60 * 1000; + + List list = sqlTemplate.query( + getSql("selectNodePrefixSql", "findOfflineNodesSql"), new NodeRowMapper(), + myNode.getNodeId(), myNode.getNodeId()); + + for (Node node : list) { + // Take the timezone of the client node into account when + // checking the hearbeat time. + Date clientNodeCurrentTime = null; + if (node.getTimezoneOffset() != null) { + clientNodeCurrentTime = AppUtils + .getLocalDateForOffset(node.getTimezoneOffset()); + } else { + clientNodeCurrentTime = new Date(); + } + long cutOffTimeMillis = clientNodeCurrentTime.getTime() + - offlineNodeDetectionMillis; + if (node.getHeartbeatTime() == null + || node.getHeartbeatTime().getTime() < cutOffTimeMillis) { + offlineNodeList.add(node); + } + } } + + return offlineNodeList; } - - class NodeSecurityRowMapper implements RowMapper { - public NodeSecurity mapRow(ResultSet rs, int num) throws SQLException { - NodeSecurity nodeSecurity = new NodeSecurity(); - nodeSecurity.setNodeId(rs.getString(1)); - nodeSecurity.setNodePassword(filterPasswordOnRenderIfNeeded(rs.getString(2))); - nodeSecurity.setRegistrationEnabled(rs.getBoolean(3)); - nodeSecurity.setRegistrationTime(rs.getTimestamp(4)); - nodeSecurity.setInitialLoadEnabled(rs.getBoolean(5)); - nodeSecurity.setInitialLoadTime(rs.getTimestamp(6)); - nodeSecurity.setCreatedAtNodeId(rs.getString(7)); - return nodeSecurity; + + public long getOfflineNodeDetectionMinutes() { + return offlineNodeDetectionMinutes; + } + + public void setOfflineNodeDetectionMinutes(long offlineNodeDetectionMinutes) { + this.offlineNodeDetectionMinutes = offlineNodeDetectionMinutes; + } + + public void setOfflineServerListeners(List listeners) { + this.offlineServerListeners = listeners; + } + + public void addOfflineServerListener(IOfflineServerListener listener) { + if (offlineServerListeners == null) { + offlineServerListeners = new ArrayList(); } + offlineServerListeners.add(listener); } - class NodeSecurityResultSetExtractor implements ResultSetExtractor> { - public Map extractData(ResultSet rs) throws SQLException, DataAccessException { - Map result = new HashMap(); - NodeSecurityRowMapper mapper = new NodeSecurityRowMapper(); + public boolean removeOfflineServerListener(IOfflineServerListener listener) { + if (offlineServerListeners != null) { + return offlineServerListeners.remove(listener); + } else { + return false; + } + } - while (rs.next()) { - NodeSecurity nodeSecurity = (NodeSecurity) mapper.mapRow(rs, 0); - result.put(nodeSecurity.getNodeId(), nodeSecurity); + protected void fireOffline(List offlineClientNodeList) { + if (offlineServerListeners != null) { + for (IOfflineServerListener listener : offlineServerListeners) { + for (Node node : offlineClientNodeList) { + listener.clientNodeOffline(node); + } } - return result; } } - - class NodeHostRowMapper implements RowMapper { - public NodeHost mapRow(ResultSet rs, int rowNum) throws SQLException { + + class NodeRowMapper implements ISqlRowMapper { + public Node mapRow(Row rs) { + Node node = new Node(); + node.setNodeId(rs.getString("node_id")); + node.setNodeGroupId(rs.getString("node_group_id")); + node.setExternalId(rs.getString("external_id")); + node.setSyncEnabled(rs.getBoolean("sync_enabled")); + node.setSyncUrl(rs.getString("sync_url")); + node.setSchemaVersion(rs.getString("schema_version")); + node.setDatabaseType(rs.getString("database_type")); + node.setDatabaseVersion(rs.getString("database_version")); + node.setSymmetricVersion(rs.getString("symmetric_version")); + node.setCreatedAtNodeId(rs.getString("created_at_node_id")); + node.setHeartbeatTime(rs.getDateTime("heartbeat_time")); + node.setTimezoneOffset(rs.getString("timezone_offset")); + node.setBatchToSendCount(rs.getInt("batch_to_send_count")); + node.setBatchInErrorCount(rs.getInt("batch_in_error_count")); + node.setDeploymentType(rs.getString("deployment_type")); + return node; + } + } + + class NodeSecurityRowMapper implements ISqlRowMapper { + public NodeSecurity mapRow(Row rs) { + NodeSecurity nodeSecurity = new NodeSecurity(); + nodeSecurity.setNodeId(rs.getString("node_id")); + nodeSecurity.setNodePassword(filterPasswordOnRenderIfNeeded(rs + .getString("node_password"))); + nodeSecurity.setRegistrationEnabled(rs.getBoolean("registration_enabled")); + nodeSecurity.setRegistrationTime(rs.getDateTime("registration_time")); + nodeSecurity.setInitialLoadEnabled(rs.getBoolean("initial_load_enabled")); + nodeSecurity.setInitialLoadTime(rs.getDateTime("initial_load_time")); + nodeSecurity.setCreatedAtNodeId(rs.getString("created_at_node_id")); + return nodeSecurity; + } + } + + class NodeHostRowMapper implements ISqlRowMapper { + public NodeHost mapRow(Row rs) { NodeHost nodeHost = new NodeHost(); - nodeHost.setNodeId(rs.getString(1)); - nodeHost.setHostName(rs.getString(2)); - nodeHost.setIpAddress(rs.getString(3)); - nodeHost.setOsUser(rs.getString(4)); - nodeHost.setOsName(rs.getString(5)); - nodeHost.setOsArch(rs.getString(6)); - nodeHost.setOsVersion(rs.getString(7)); - nodeHost.setAvailableProcessors(rs.getInt(8)); - nodeHost.setFreeMemoryBytes(rs.getLong(9)); - nodeHost.setTotalMemoryBytes(rs.getLong(10)); - nodeHost.setMaxMemoryBytes(rs.getLong(11)); - nodeHost.setJavaVersion(rs.getString(12)); - nodeHost.setJavaVendor(rs.getString(13)); - nodeHost.setSymmetricVersion(rs.getString(14)); - nodeHost.setTimezoneOffset(rs.getString(15)); - nodeHost.setHeartbeatTime(rs.getTimestamp(16)); - nodeHost.setLastRestartTime(rs.getTimestamp(17)); - nodeHost.setCreateTime(rs.getTimestamp(18)); + nodeHost.setNodeId(rs.getString("node_id")); + nodeHost.setHostName(rs.getString("host_name")); + nodeHost.setIpAddress(rs.getString("ip_address")); + nodeHost.setOsUser(rs.getString("os_user")); + nodeHost.setOsName(rs.getString("os_name")); + nodeHost.setOsArch(rs.getString("os_arch")); + nodeHost.setOsVersion(rs.getString("os_version")); + nodeHost.setAvailableProcessors(rs.getInt("available_processors")); + nodeHost.setFreeMemoryBytes(rs.getLong("free_memory_bytes")); + nodeHost.setTotalMemoryBytes(rs.getLong("total_memory_bytes")); + nodeHost.setMaxMemoryBytes(rs.getLong("max_memory_bytes")); + nodeHost.setJavaVersion(rs.getString("java_version")); + nodeHost.setJavaVendor(rs.getString("java_vendor")); + nodeHost.setSymmetricVersion(rs.getString("symmetric_version")); + nodeHost.setTimezoneOffset(rs.getString("timezone_offset")); + nodeHost.setHeartbeatTime(rs.getDateTime("heartbeat_time")); + nodeHost.setLastRestartTime(rs.getDateTime("last_restart_time")); + nodeHost.setCreateTime(rs.getDateTime("create_time")); return nodeHost; } - } - + } + } \ No newline at end of file diff --git a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/impl/OutgoingBatchService.java b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/impl/OutgoingBatchService.java index ad138e184a..87c19fda22 100644 --- a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/impl/OutgoingBatchService.java +++ b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/impl/OutgoingBatchService.java @@ -21,20 +21,22 @@ package org.jumpmind.symmetric.service.impl; -import java.sql.PreparedStatement; -import java.sql.ResultSet; -import java.sql.SQLException; import java.sql.Types; import java.util.ArrayList; import java.util.Date; -import java.util.HashMap; import java.util.List; -import java.util.Map; import org.apache.commons.lang.StringUtils; import org.jumpmind.db.sql.AbstractSqlMap; +import org.jumpmind.db.sql.ISqlRowMapper; +import org.jumpmind.db.sql.ISqlTransaction; +import org.jumpmind.db.sql.Row; +import org.jumpmind.db.sql.SqlList; +import org.jumpmind.db.sql.SqlToken; +import org.jumpmind.db.sql.mapper.StringMapper; import org.jumpmind.symmetric.common.Constants; import org.jumpmind.symmetric.common.ParameterConstants; +import org.jumpmind.symmetric.db.ISymmetricDialect; import org.jumpmind.symmetric.db.SequenceIdentifier; import org.jumpmind.symmetric.model.Node; import org.jumpmind.symmetric.model.NodeChannel; @@ -46,15 +48,8 @@ import org.jumpmind.symmetric.service.IConfigurationService; import org.jumpmind.symmetric.service.INodeService; import org.jumpmind.symmetric.service.IOutgoingBatchService; +import org.jumpmind.symmetric.service.IParameterService; import org.jumpmind.symmetric.util.AppUtils; -import org.jumpmind.symmetric.util.MaxRowsStatementCreator; -import org.springframework.dao.DataAccessException; -import org.springframework.jdbc.core.PreparedStatementCallback; -import org.springframework.jdbc.core.ResultSetExtractor; -import org.springframework.jdbc.core.RowMapper; -import org.springframework.jdbc.core.namedparam.MapSqlParameterSource; -import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; -import org.springframework.jdbc.core.simple.SimpleJdbcTemplate; import org.springframework.transaction.annotation.Transactional; /** @@ -65,11 +60,19 @@ public class OutgoingBatchService extends AbstractService implements IOutgoingBa private INodeService nodeService; private IConfigurationService configurationService; - + + public OutgoingBatchService(IParameterService parameterService, + ISymmetricDialect symmetricDialect, INodeService nodeService, + IConfigurationService configurationService) { + super(parameterService, symmetricDialect); + this.nodeService = nodeService; + this.configurationService = configurationService; + } + @Override protected AbstractSqlMap createSqlMap() { return new OutgoingBatchServiceSqlMap(symmetricDialect.getPlatform(), - createReplacementTokens()); + createSqlReplacementTokens()); } @Transactional @@ -86,7 +89,7 @@ public void markAllAsSentForNode(Node node) { } public void updateAbandonedRoutingBatches() { - jdbcTemplate.update(getSql("updateOutgoingBatchesStatusSql"), Status.NE.name(), + sqlTemplate.update(getSql("updateOutgoingBatchesStatusSql"), Status.NE.name(), Status.RT.name()); } @@ -99,7 +102,7 @@ public void updateOutgoingBatches(List outgoingBatches) { public void updateOutgoingBatch(OutgoingBatch outgoingBatch) { outgoingBatch.setLastUpdatedTime(new Date()); outgoingBatch.setLastUpdatedHostName(AppUtils.getServerId()); - jdbcTemplate + sqlTemplate .update(getSql("updateOutgoingBatchSql"), new Object[] { outgoingBatch.getStatus().name(), outgoingBatch.isLoadFlag() ? 1 : 0, @@ -129,29 +132,32 @@ public void updateOutgoingBatch(OutgoingBatch outgoingBatch) { } public void insertOutgoingBatch(final OutgoingBatch outgoingBatch) { + ISqlTransaction transaction = null; + try { + transaction = sqlTemplate.startSqlTransaction(); + insertOutgoingBatch(transaction, outgoingBatch); + transaction.commit(); + } finally { + close(transaction); + } + } + + public void insertOutgoingBatch(ISqlTransaction transaction, OutgoingBatch outgoingBatch) { outgoingBatch.setLastUpdatedHostName(AppUtils.getServerId()); - long batchId = symmetricDialect.insertWithGeneratedKey(jdbcTemplate, - getSql("insertOutgoingBatchSql"), SequenceIdentifier.OUTGOING_BATCH, - new PreparedStatementCallback() { - public Object doInPreparedStatement(PreparedStatement ps) throws SQLException, - DataAccessException { - ps.setString(1, outgoingBatch.getNodeId()); - ps.setString(2, outgoingBatch.getChannelId()); - ps.setString(3, outgoingBatch.getStatus().name()); - ps.setInt(4, outgoingBatch.isLoadFlag() ? 1 : 0); - ps.setLong(5, outgoingBatch.getReloadEventCount()); - ps.setLong(6, outgoingBatch.getOtherEventCount()); - ps.setString(7, outgoingBatch.getLastUpdatedHostName()); - return null; - } - }); + long batchId = transaction.insertWithGeneratedKey(getSql("insertOutgoingBatchSql"), + symmetricDialect.getSequenceKeyName(SequenceIdentifier.OUTGOING_BATCH), + symmetricDialect.getSequenceName(SequenceIdentifier.OUTGOING_BATCH), outgoingBatch + .getNodeId(), outgoingBatch.getChannelId(), outgoingBatch.getStatus() + .name(), outgoingBatch.isLoadFlag() ? 1 : 0, outgoingBatch + .getReloadEventCount(), outgoingBatch.getOtherEventCount(), outgoingBatch + .getLastUpdatedHostName()); outgoingBatch.setBatchId(batchId); } public OutgoingBatch findOutgoingBatch(long batchId) { - List list = (List) jdbcTemplate.query( + List list = (List) sqlTemplate.query( getSql("selectOutgoingBatchPrefixSql", "findOutgoingBatchSql"), - new Object[] { batchId }, new int[] { Types.NUMERIC }, new OutgoingBatchMapper()); + new OutgoingBatchMapper(), new Object[] { batchId }, new int[] { Types.NUMERIC }); if (list != null && list.size() > 0) { return list.get(0); } else { @@ -160,21 +166,19 @@ public OutgoingBatch findOutgoingBatch(long batchId) { } public int countOutgoingBatchesInError() { - return jdbcTemplate.queryForInt(getSql("countOutgoingBatchesErrorsSql")); + return sqlTemplate.queryForInt(getSql("countOutgoingBatchesErrorsSql")); } public int countOutgoingBatches(List nodeIds, List channels, List statuses) { if (nodeIds.size() > 0 && channels.size() > 0 && statuses.size() > 0) { - Map params = new HashMap(); - params.put("NODES", nodeIds); - params.put("CHANNELS", channels); - params.put("STATUSES", toStringList(statuses)); - return new SimpleJdbcTemplate(dataSource) + return sqlTemplate .queryForInt( getSql("selectCountBatchesPrefixSql", containsOnlyErrorStatus(statuses) ? "selectOutgoingBatchByChannelWithErrorSql" - : "selectOutgoingBatchByChannelAndStatusSql"), params); + : "selectOutgoingBatchByChannelAndStatusSql"), + new SqlList(":NODES", nodeIds), new SqlList(":CHANNELS", channels), + toStringList(":STATUSES", statuses)); } else { return 0; } @@ -183,39 +187,23 @@ public int countOutgoingBatches(List nodeIds, List channels, public List listOutgoingBatches(List nodeIds, List channels, List statuses, long startAtBatchId, final int maxRowsToRetrieve) { if (nodeIds.size() > 0 && channels.size() > 0 && statuses.size() > 0) { - Map params = new HashMap(); - params.put("NODES", nodeIds); - params.put("CHANNELS", channels); - params.put("STATUSES", toStringList(statuses)); String startAtBatchIdSql = null; + List args = new ArrayList(); + args.add(new SqlList(":NODES", nodeIds)); + args.add(new SqlList(":CHANNELS", channels)); + args.add(toStringList(":STATUSES", statuses)); + if (startAtBatchId > 0) { - params.put("BATCH_ID", startAtBatchId); + args.add(new SqlToken(":BATCH_ID", startAtBatchId)); startAtBatchIdSql = " and batch_id < :BATCH_ID "; } + String sql = getSql("selectOutgoingBatchPrefixSql", + containsOnlyErrorStatus(statuses) ? "selectOutgoingBatchByChannelWithErrorSql" + : "selectOutgoingBatchByChannelAndStatusSql", startAtBatchIdSql, + " order by batch_id desc"); - NamedParameterJdbcTemplate template = new NamedParameterJdbcTemplate(dataSource); - ResultSetExtractor> extractor = new ResultSetExtractor>() { - OutgoingBatchMapper rowMapper = new OutgoingBatchMapper(); - - public List extractData(ResultSet rs) throws SQLException, - DataAccessException { - List list = new ArrayList(maxRowsToRetrieve); - int count = 0; - while (rs.next() && count < maxRowsToRetrieve) { - list.add(rowMapper.mapRow(rs, ++count)); - } - return list; - } - }; - - List list = template - .query(getSql( - "selectOutgoingBatchPrefixSql", - containsOnlyErrorStatus(statuses) ? "selectOutgoingBatchByChannelWithErrorSql" - : "selectOutgoingBatchByChannelAndStatusSql", - startAtBatchIdSql, " order by batch_id desc"), - new MapSqlParameterSource(params), extractor); - return list; + return sqlTemplate.query(sql, maxRowsToRetrieve, new OutgoingBatchMapper(), + args.toArray(new Object[args.size()]), null); } else { return new ArrayList(0); } @@ -225,8 +213,8 @@ protected boolean containsOnlyErrorStatus(List statuses) { return statuses.size() == 1 && statuses.get(0) == OutgoingBatch.Status.ER; } - protected List toStringList(List statuses) { - List statusStrings = new ArrayList(statuses.size()); + protected SqlList toStringList(String replacementToken, List statuses) { + SqlList statusStrings = new SqlList(replacementToken, statuses.size()); for (Status status : statuses) { statusStrings.add(status.name()); } @@ -242,27 +230,14 @@ protected List toStringList(List statuses) { */ public OutgoingBatches getOutgoingBatches(Node node) { long ts = System.currentTimeMillis(); - final int maxNumberOfBatchesToSelect = parameterService.getInt(ParameterConstants.OUTGOING_BATCH_MAX_BATCHES_TO_SELECT, 1000); - List list = (List) jdbcTemplate.query( + final int maxNumberOfBatchesToSelect = parameterService.getInt( + ParameterConstants.OUTGOING_BATCH_MAX_BATCHES_TO_SELECT, 1000); + List list = (List) sqlTemplate.query( getSql("selectOutgoingBatchPrefixSql", "selectOutgoingBatchSql"), + maxNumberOfBatchesToSelect, new OutgoingBatchMapper(), new Object[] { node.getNodeId(), OutgoingBatch.Status.NE.name(), OutgoingBatch.Status.QY.name(), OutgoingBatch.Status.SE.name(), - OutgoingBatch.Status.LD.name(), OutgoingBatch.Status.ER.name() }, - new ResultSetExtractor>() { - RowMapper mapper = new OutgoingBatchMapper(); - - public List extractData(ResultSet rs) throws SQLException { - List results = new ArrayList(); - int rowNum = 0; - while (rs.next()) { - results.add(this.mapper.mapRow(rs, rowNum++)); - if (rowNum >= maxNumberOfBatchesToSelect) { - break; - } - } - return results; - } - }); + OutgoingBatch.Status.LD.name(), OutgoingBatch.Status.ER.name() }, null); OutgoingBatches batches = new OutgoingBatches(list); @@ -293,17 +268,17 @@ public List extractData(ResultSet rs) throws SQLException { public OutgoingBatches getOutgoingBatchRange(String startBatchId, String endBatchId) { OutgoingBatches batches = new OutgoingBatches(); - batches.setBatches(jdbcTemplate.query( + batches.setBatches(sqlTemplate.query( getSql("selectOutgoingBatchPrefixSql", "selectOutgoingBatchRangeSql"), - new Object[] { Long.parseLong(startBatchId), Long.parseLong(endBatchId) }, new OutgoingBatchMapper())); + new OutgoingBatchMapper(), Long.parseLong(startBatchId), Long.parseLong(endBatchId))); return batches; } public OutgoingBatches getOutgoingBatchErrors(int maxRows) { OutgoingBatches batches = new OutgoingBatches(); - batches.setBatches(jdbcTemplate.query( - new MaxRowsStatementCreator(getSql("selectOutgoingBatchPrefixSql", - "selectOutgoingBatchErrorsSql"), maxRows), new OutgoingBatchMapper())); + batches.setBatches(sqlTemplate.query( + getSql("selectOutgoingBatchPrefixSql", "selectOutgoingBatchErrorsSql"), maxRows, + new OutgoingBatchMapper(), null, null)); return batches; } @@ -319,8 +294,8 @@ public boolean areAllLoadBatchesComplete(String nodeId) { return false; } - List statuses = (List) jdbcTemplate.queryForList( - getSql("initialLoadStatusSql"), new Object[] { nodeId, 1 }, String.class); + List statuses = (List) sqlTemplate.query(getSql("initialLoadStatusSql"), + new StringMapper(), nodeId, 1); if (statuses == null || statuses.size() == 0) { throw new RuntimeException("The initial load has not been started for " + nodeId); } @@ -334,7 +309,7 @@ public boolean areAllLoadBatchesComplete(String nodeId) { } public boolean isUnsentDataOnChannelForNode(String channelId, String nodeId) { - int unsentCount = jdbcTemplate.queryForInt(getSql("unsentBatchesForNodeIdChannelIdSql"), + int unsentCount = sqlTemplate.queryForInt(getSql("unsentBatchesForNodeIdChannelIdSql"), new Object[] { nodeId, channelId }); if (unsentCount > 0) { return true; @@ -345,63 +320,62 @@ public boolean isUnsentDataOnChannelForNode(String channelId, String nodeId) { } public List findOutgoingBatchSummary(Status... statuses) { - List statusList = new ArrayList(); - for (Status status : statuses) { - statusList.add(status.name()); + Object[] args = new Object[statuses.length]; + StringBuilder inList = new StringBuilder(); + for (int i = 0; i < statuses.length; i++) { + args[i] = statuses[i].name(); + inList.append("?,"); } - Map params = new HashMap(); - params.put("STATUS_LIST", statusList); - return getSimpleTemplate().query(getSql("selectOutgoingBatchSummaryByStatusSql"), - new OutgoingBatchSummaryMapper(), params); + + String sql = getSql("selectOutgoingBatchSummaryByStatusSql").replace(":STATUS_LIST", + inList.substring(0, inList.length() - 1)); + + return sqlTemplate.query(sql, new OutgoingBatchSummaryMapper(), args); } - class OutgoingBatchSummaryMapper implements RowMapper { - public OutgoingBatchSummary mapRow(ResultSet rs, int rowNum) throws SQLException { + class OutgoingBatchSummaryMapper implements ISqlRowMapper { + public OutgoingBatchSummary mapRow(Row rs) { OutgoingBatchSummary summary = new OutgoingBatchSummary(); - summary.setBatchCount(rs.getInt(1)); - summary.setDataCount(rs.getInt(2)); - summary.setStatus(Status.valueOf(rs.getString(3))); - summary.setNodeId(rs.getString(4)); - summary.setOldestBatchCreateTime(rs.getTimestamp(5)); + summary.setBatchCount(rs.getInt("batches")); + summary.setDataCount(rs.getInt("data")); + summary.setStatus(Status.valueOf(rs.getString("status"))); + summary.setNodeId(rs.getString("node_id")); + summary.setOldestBatchCreateTime(rs.getDateTime("oldest_batch_time")); return summary; } } - class OutgoingBatchMapper implements RowMapper { - public OutgoingBatchMapper() { - - } - - public OutgoingBatch mapRow(ResultSet rs, int num) throws SQLException { + class OutgoingBatchMapper implements ISqlRowMapper { + public OutgoingBatch mapRow(Row rs) { OutgoingBatch batch = new OutgoingBatch(); - batch.setNodeId(rs.getString(1)); - batch.setChannelId(rs.getString(2)); - batch.setStatus(rs.getString(3)); - batch.setByteCount(rs.getLong(4)); - batch.setExtractCount(rs.getLong(5)); - batch.setSentCount(rs.getLong(6)); - batch.setLoadCount(rs.getLong(7)); - batch.setDataEventCount(rs.getLong(8)); - batch.setReloadEventCount(rs.getLong(9)); - batch.setInsertEventCount(rs.getLong(10)); - batch.setUpdateEventCount(rs.getLong(11)); - batch.setDeleteEventCount(rs.getLong(12)); - batch.setOtherEventCount(rs.getLong(13)); - batch.setRouterMillis(rs.getLong(14)); - batch.setNetworkMillis(rs.getLong(15)); - batch.setFilterMillis(rs.getLong(16)); - batch.setLoadMillis(rs.getLong(17)); - batch.setExtractMillis(rs.getLong(18)); - batch.setSqlState(rs.getString(19)); - batch.setSqlCode(rs.getInt(20)); - batch.setSqlMessage(rs.getString(21)); - batch.setFailedDataId(rs.getLong(22)); - batch.setLastUpdatedHostName(rs.getString(23)); - batch.setLastUpdatedTime(rs.getTimestamp(24)); - batch.setCreateTime(rs.getTimestamp(25)); - batch.setBatchId(rs.getLong(26)); - batch.setLoadFlag(rs.getBoolean(27)); - batch.setErrorFlag(rs.getBoolean(28)); + batch.setNodeId(rs.getString("node_id")); + batch.setChannelId(rs.getString("channel_id")); + batch.setStatus(rs.getString("status")); + batch.setByteCount(rs.getLong("byte_count")); + batch.setExtractCount(rs.getLong("extract_count")); + batch.setSentCount(rs.getLong("sent_count")); + batch.setLoadCount(rs.getLong("load_count")); + batch.setDataEventCount(rs.getLong("data_event_count")); + batch.setReloadEventCount(rs.getLong("reload_event_count")); + batch.setInsertEventCount(rs.getLong("insert_event_count")); + batch.setUpdateEventCount(rs.getLong("update_event_count")); + batch.setDeleteEventCount(rs.getLong("delete_event_count")); + batch.setOtherEventCount(rs.getLong("other_event_count")); + batch.setRouterMillis(rs.getLong("router_millis")); + batch.setNetworkMillis(rs.getLong("network_millis")); + batch.setFilterMillis(rs.getLong("filter_millis")); + batch.setLoadMillis(rs.getLong("load_millis")); + batch.setExtractMillis(rs.getLong("extract_millis")); + batch.setSqlState(rs.getString("sql_state")); + batch.setSqlCode(rs.getInt("sql_code")); + batch.setSqlMessage(rs.getString("sql_message")); + batch.setFailedDataId(rs.getLong("failed_data_id")); + batch.setLastUpdatedHostName(rs.getString("last_update_host_name")); + batch.setLastUpdatedTime(rs.getDateTime("last_update_time")); + batch.setCreateTime(rs.getDateTime("create_time")); + batch.setBatchId(rs.getLong("batch_id")); + batch.setLoadFlag(rs.getBoolean("load_flag")); + batch.setErrorFlag(rs.getBoolean("error_flag")); return batch; } } diff --git a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/impl/OutgoingBatchServiceSqlMap.java b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/impl/OutgoingBatchServiceSqlMap.java index 4792121f44..aba8b2b200 100644 --- a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/impl/OutgoingBatchServiceSqlMap.java +++ b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/impl/OutgoingBatchServiceSqlMap.java @@ -54,8 +54,8 @@ public OutgoingBatchServiceSqlMap(IDatabasePlatform platform, Map parameters; + protected Log log = LogFactory.getLog(getClass()); - private BeanFactory beanFactory; + private TypedProperties parameters; private long cacheTimeoutInMs = 0; @@ -63,18 +62,25 @@ public class ParameterService extends AbstractService implements IParameterServi private Properties systemProperties; private boolean initialized = false; + + private String tablePrefix; - public ParameterService() { - systemProperties = (Properties) System.getProperties().clone(); - } + private ITypedPropertiesFactory factory; - @Override - protected AbstractSqlMap createSqlMap() { - return new ParameterServiceSqlMap(null, createReplacementTokens()); - } + private ParameterServiceSqlMap sql; + + private ISqlTemplate jdbcTemplate; + + public ParameterService(IDatabasePlatform platform, ITypedPropertiesFactory factory, + String tablePrefix, Log log) { + this.log = log; + this.systemProperties = (Properties) System.getProperties().clone(); + this.tablePrefix = tablePrefix; + this.factory = factory; + this.sql = new ParameterServiceSqlMap(null, + AbstractService.createSqlReplacementTokens(tablePrefix)); + this.jdbcTemplate = platform.getSqlTemplate(); - public void setBeanFactory(BeanFactory beanFactory) throws BeansException { - this.beanFactory = beanFactory; } public BigDecimal getDecimal(String key, BigDecimal defaultVal) { @@ -139,7 +145,7 @@ public String getString(String key, String defaultVal) { String value = null; if (StringUtils.isBlank(value)) { - value = getParameters().get(key); + value = getParameters().get(key, defaultVal); } if (this.parameterFilter != null) { @@ -158,14 +164,13 @@ public void saveParameter(String key, Object paramValue) { } public void saveParameter(String externalId, String nodeGroupId, String key, Object paramValue) { - paramValue = paramValue != null ? paramValue.toString() : null; - int count = jdbcTemplate.update(getSql("updateParameterSql"), new Object[] { paramValue, - externalId, nodeGroupId, key }); + int count = jdbcTemplate.update(sql.getSql("updateParameterSql"), new Object[] { + paramValue, externalId, nodeGroupId, key }); if (count == 0) { - jdbcTemplate.update(getSql("insertParameterSql"), new Object[] { externalId, + jdbcTemplate.update(sql.getSql("insertParameterSql"), new Object[] { externalId, nodeGroupId, key, paramValue }); } @@ -173,7 +178,7 @@ public void saveParameter(String externalId, String nodeGroupId, String key, Obj } public void deleteParameter(String externalId, String nodeGroupId, String key) { - jdbcTemplate.update(getSql("deleteParameterSql"), externalId, nodeGroupId, key); + jdbcTemplate.update(sql.getSql("deleteParameterSql"), externalId, nodeGroupId, key); rereadParameters(); } @@ -190,57 +195,44 @@ public synchronized void rereadParameters() { getParameters(); } - /** - * Every time we pull the properties out of the bean factory they should get - * reread from the file system. - */ - private Properties rereadFileParameters() { - return (Properties) beanFactory.getBean(Constants.PROPERTIES); - } - - private Map rereadDatabaseParameters(Properties p) { + private TypedProperties rereadDatabaseParameters(Properties p) { try { - Map map = rereadDatabaseParameters(ParameterConstants.ALL, + TypedProperties properties = rereadDatabaseParameters(ParameterConstants.ALL, ParameterConstants.ALL); - map.putAll(rereadDatabaseParameters(ParameterConstants.ALL, + properties.putAll(rereadDatabaseParameters(ParameterConstants.ALL, p.getProperty(ParameterConstants.NODE_GROUP_ID))); - map.putAll(rereadDatabaseParameters(p.getProperty(ParameterConstants.EXTERNAL_ID), + properties.putAll(rereadDatabaseParameters( + p.getProperty(ParameterConstants.EXTERNAL_ID), p.getProperty(ParameterConstants.NODE_GROUP_ID))); - return map; + return properties; } catch (Exception ex) { if (initialized) { - log.warn("DatabaseParametersReadingFailed"); + log.warn("Could not read database parameters. We will try again later"); } - return new HashMap(); + return new TypedProperties(); } } - private Map rereadDatabaseParameters(String externalId, String nodeGroupId) { - final Map map = new HashMap(); - jdbcTemplate.query(getSql("selectParametersSql"), new Object[] { externalId, nodeGroupId }, - new RowMapper() { - public Object mapRow(ResultSet rs, int rowNum) throws SQLException { - map.put(rs.getString(1), rs.getString(2)); - return null; - } - }); - return map; + private TypedProperties rereadDatabaseParameters(String externalId, String nodeGroupId) { + final TypedProperties properties = new TypedProperties(); + jdbcTemplate.query(sql.getSql("selectParametersSql"), new ISqlRowMapper() { + public Object mapRow(Row row) { + properties.setProperty(row.getString("param_key"), row.getString("param_value")); + return null; + } + }, externalId, nodeGroupId); + return properties; } - private Map rereadApplicationParameters() { - final Map map = new HashMap(); - Properties p = rereadFileParameters(); + private TypedProperties rereadApplicationParameters() { + TypedProperties p = this.factory.reload(); p.putAll(systemProperties); - for (Object key : p.keySet()) { - map.put((String) key, p.getProperty((String) key)); - } - map.putAll(rereadDatabaseParameters(p)); + p.putAll(rereadDatabaseParameters(p)); initialized = true; - return map; - + return p; } - private Map getParameters() { + private TypedProperties getParameters() { if (parameters == null || lastTimeParameterWereCached == null || (cacheTimeoutInMs > 0 && lastTimeParameterWereCached.getTime() < (System @@ -252,7 +244,7 @@ private Map getParameters() { return parameters; } - public Map getAllParameters() { + public TypedProperties getAllParameters() { return getParameters(); } @@ -269,22 +261,15 @@ public String getExternalId() { } public String getSyncUrl() { - String value = getWithHostName(ParameterConstants.SYNC_URL); - if (StringUtils.isBlank(value)) { - value = getWithHostName("my.url"); - if (!StringUtils.isBlank(value)) { - log.warn("DeprecatedPropertyMsg", "my.url", ParameterConstants.SYNC_URL); - } - } - return value; + return getWithHostName(ParameterConstants.SYNC_URL); } public List getDatabaseParametersFor(String paramKey) { - return jdbcTemplate.query(getSql("selectParametersByKeySql"), + return jdbcTemplate.query(sql.getSql("selectParametersByKeySql"), new DatabaseParameterMapper(), paramKey); } - public Map getDatabaseParametersByNodeGroupId(String nodeGroupId) { + public TypedProperties getDatabaseParametersByNodeGroupId(String nodeGroupId) { return rereadDatabaseParameters(ParameterConstants.ALL, nodeGroupId); } @@ -318,13 +303,21 @@ public Map getReplacementValues() { replacementValues.put("externalId", getExternalId()); replacementValues.put("nodeGroupId", getNodeGroupId()); return replacementValues; - } + } - class DatabaseParameterMapper implements RowMapper { - public DatabaseParameter mapRow(ResultSet rs, int rowNum) throws SQLException { - return new DatabaseParameter(rs.getString(1), rs.getString(2), rs.getString(3), - rs.getString(4)); + class DatabaseParameterMapper implements ISqlRowMapper { + public DatabaseParameter mapRow(Row row) { + return new DatabaseParameter(row.getString("param_key"), row.getString("param_value"), + row.getString("external_id"), row.getString("node_group_id")); } } + public String getTablePrefix() { + return this.tablePrefix; + } + + public String getEngineName() { + return getString(ParameterConstants.ENGINE_NAME, "SymmetricDS"); + } + } \ No newline at end of file diff --git a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/impl/ParameterServiceSqlMap.java b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/impl/ParameterServiceSqlMap.java index b3f92cdff2..cb8616a070 100644 --- a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/impl/ParameterServiceSqlMap.java +++ b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/impl/ParameterServiceSqlMap.java @@ -11,23 +11,23 @@ public ParameterServiceSqlMap(IDatabasePlatform platform, Map re putSql("updateParameterSql" ,"" + "update $(prefixName)_parameter set param_value=? where external_id=? and node_group_id=? " + -" and param_key=? " ); +" and param_key=? " ); putSql("insertParameterSql" ,"" + "insert into $(prefixName)_parameter (external_id, node_group_id, param_key, param_value) " + -" values(?, ?, ?, ?) " ); +" values(?, ?, ?, ?) " ); putSql("selectParametersSql" ,"" + "select param_key, param_value from $(prefixName)_parameter where external_id=? and " + -" node_group_id=? " ); +" node_group_id=? " ); putSql("selectParametersByKeySql" ,"" + "select param_key, param_value, external_id, node_group_id from $(prefixName)_parameter where param_key=? " + -" order by node_group_id, external_id " ); +" order by node_group_id, external_id " ); putSql("deleteParameterSql" ,"" + "delete from $(prefixName)_parameter where external_id=? and " + -" node_group_id=? and param_key=? " ); +" node_group_id=? and param_key=? " ); } diff --git a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/impl/PullService.java b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/impl/PullService.java index 75f848fcb8..11e49338d7 100644 --- a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/impl/PullService.java +++ b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/impl/PullService.java @@ -27,6 +27,7 @@ import java.util.List; import org.jumpmind.db.sql.AbstractSqlMap; +import org.jumpmind.symmetric.db.ISymmetricDialect; import org.jumpmind.symmetric.model.Node; import org.jumpmind.symmetric.model.RemoteNodeStatus; import org.jumpmind.symmetric.model.RemoteNodeStatuses; @@ -34,6 +35,7 @@ import org.jumpmind.symmetric.service.IClusterService; import org.jumpmind.symmetric.service.IDataLoaderService; import org.jumpmind.symmetric.service.INodeService; +import org.jumpmind.symmetric.service.IParameterService; import org.jumpmind.symmetric.service.IPullService; import org.jumpmind.symmetric.service.IRegistrationService; import org.jumpmind.symmetric.transport.AuthenticationException; @@ -54,6 +56,16 @@ public class PullService extends AbstractOfflineDetectorService implements IPull private IClusterService clusterService; + public PullService(IParameterService parameterService, ISymmetricDialect symmetricDialect, + INodeService nodeService, IDataLoaderService dataLoaderService, + IRegistrationService registrationService, IClusterService clusterService) { + super(parameterService, symmetricDialect); + this.nodeService = nodeService; + this.dataLoaderService = dataLoaderService; + this.registrationService = registrationService; + this.clusterService = clusterService; + } + @Override protected AbstractSqlMap createSqlMap() { return null; @@ -122,20 +134,4 @@ synchronized public RemoteNodeStatuses pullData() { return statuses; } - public void setNodeService(INodeService nodeService) { - this.nodeService = nodeService; - } - - public void setDataLoaderService(IDataLoaderService dataLoaderService) { - this.dataLoaderService = dataLoaderService; - } - - public void setRegistrationService(IRegistrationService registrationService) { - this.registrationService = registrationService; - } - - public void setClusterService(IClusterService clusterService) { - this.clusterService = clusterService; - } - } \ No newline at end of file diff --git a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/impl/PurgeService.java b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/impl/PurgeService.java index 6f0068ddd8..325417545e 100644 --- a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/impl/PurgeService.java +++ b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/impl/PurgeService.java @@ -16,340 +16,343 @@ * "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.jumpmind.symmetric.service.impl; - -import java.sql.ResultSet; -import java.sql.SQLException; -import java.sql.Timestamp; -import java.sql.Types; -import java.text.SimpleDateFormat; -import java.util.Calendar; -import java.util.Date; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import org.apache.commons.lang.time.DateUtils; + * under the License. + */ + +package org.jumpmind.symmetric.service.impl; + +import java.sql.Timestamp; +import java.text.SimpleDateFormat; +import java.util.Calendar; +import java.util.Date; +import java.util.List; + +import org.apache.commons.lang.time.DateUtils; import org.jumpmind.db.sql.AbstractSqlMap; -import org.jumpmind.symmetric.common.ParameterConstants; -import org.jumpmind.symmetric.model.NodeStatus; -import org.jumpmind.symmetric.service.ClusterConstants; -import org.jumpmind.symmetric.service.IClusterService; -import org.jumpmind.symmetric.service.INodeService; -import org.jumpmind.symmetric.service.IPurgeService; +import org.jumpmind.db.sql.ISqlRowMapper; +import org.jumpmind.db.sql.Row; +import org.jumpmind.symmetric.common.ParameterConstants; +import org.jumpmind.symmetric.db.ISymmetricDialect; +import org.jumpmind.symmetric.service.ClusterConstants; +import org.jumpmind.symmetric.service.IClusterService; +import org.jumpmind.symmetric.service.IParameterService; +import org.jumpmind.symmetric.service.IPurgeService; import org.jumpmind.symmetric.statistic.IStatisticManager; -import org.springframework.jdbc.core.RowMapper; -import org.springframework.jdbc.core.namedparam.MapSqlParameterSource; - + /** - * @see IPurgeService + * @see IPurgeService */ -public class PurgeService extends AbstractService implements IPurgeService { - - private static final String PARAM_MAX = "MAX"; - - private static final String PARAM_MIN = "MIN"; - - private static final String PARAM_CUTOFF_TIME = "CUTOFF_TIME"; - - private IClusterService clusterService; - - private INodeService nodeService; - +public class PurgeService extends AbstractService implements IPurgeService { + + enum MinMaxDeleteSql { + DATA, DATA_EVENT, OUTGOING_BATCH, STRANDED_DATA + }; + + private IClusterService clusterService; + private IStatisticManager statisticManager; - + + public PurgeService(IParameterService parameterService, ISymmetricDialect symmetricDialect, + IClusterService clusterService, IStatisticManager statisticManager) { + super(parameterService, symmetricDialect); + this.clusterService = clusterService; + this.statisticManager = statisticManager; + } + @Override protected AbstractSqlMap createSqlMap() { - return new PurgeServiceSqlMap(symmetricDialect.getPlatform(), - createReplacementTokens()); - } - + return new PurgeServiceSqlMap(symmetricDialect.getPlatform(), createSqlReplacementTokens()); + } + public long purgeOutgoing() { - long rowsPurged = 0; - if (nodeService.isRegistrationServer() || nodeService.getNodeStatus() == NodeStatus.DATA_LOAD_COMPLETED) { - Calendar retentionCutoff = Calendar.getInstance(); - retentionCutoff.add(Calendar.MINUTE, -parameterService.getInt(ParameterConstants.PURGE_RETENTION_MINUTES)); - rowsPurged += purgeOutgoing(retentionCutoff); - } else { - log.warn("DataPurgeSkippingNoInitialLoad"); - } - return rowsPurged; + long rowsPurged = 0; + Calendar retentionCutoff = Calendar.getInstance(); + retentionCutoff.add(Calendar.MINUTE, + -parameterService.getInt(ParameterConstants.PURGE_RETENTION_MINUTES)); + rowsPurged += purgeOutgoing(retentionCutoff); + return rowsPurged; } - + public long purgeIncoming() { long rowsPurged = 0; - if (nodeService.isRegistrationServer() || nodeService.getNodeStatus() == NodeStatus.DATA_LOAD_COMPLETED) { - Calendar retentionCutoff = Calendar.getInstance(); - retentionCutoff.add(Calendar.MINUTE, -parameterService.getInt(ParameterConstants.PURGE_RETENTION_MINUTES)); - rowsPurged += purgeIncoming(retentionCutoff); - } else { - log.warn("DataPurgeSkippingNoInitialLoad"); - } + Calendar retentionCutoff = Calendar.getInstance(); + retentionCutoff.add(Calendar.MINUTE, + -parameterService.getInt(ParameterConstants.PURGE_RETENTION_MINUTES)); + rowsPurged += purgeIncoming(retentionCutoff); return rowsPurged; } - public long purgeDataGaps() { long rowsPurged = 0; - if (nodeService.isRegistrationServer() || nodeService.getNodeStatus() == NodeStatus.DATA_LOAD_COMPLETED) { - Calendar retentionCutoff = Calendar.getInstance(); - retentionCutoff.add(Calendar.MINUTE, -parameterService - .getInt(ParameterConstants.ROUTING_DATA_READER_TYPE_GAP_RETENTION_MINUTES)); - rowsPurged += purgeDataGaps(retentionCutoff); - - } else { - log.warn("DataPurgeSkippingNoInitialLoad"); - } + Calendar retentionCutoff = Calendar.getInstance(); + retentionCutoff.add(Calendar.MINUTE, -parameterService + .getInt(ParameterConstants.ROUTING_DATA_READER_TYPE_GAP_RETENTION_MINUTES)); + rowsPurged += purgeDataGaps(retentionCutoff); return rowsPurged; - } - + } + public long purgeDataGaps(Calendar retentionCutoff) { - long rowsPurged = -1l; - try { - if (clusterService.lock(ClusterConstants.PURGE_DATA_GAPS)) { - try { - log.info("DataPurgeDataGapsRunning"); - rowsPurged = jdbcTemplate.update(getSql("deleteFromDataGapsSql"), new Object[] { retentionCutoff - .getTime() }); - log.info("DataPurgeDataGapsRun", rowsPurged); - } finally { - clusterService.unlock(ClusterConstants.PURGE_DATA_GAPS); - log.info("DataPurgeDataGapsCompleted"); - } - - } else { - log.warn("DataPurgeDataGapsRunningFailedLock"); - } - } catch (Exception ex) { - log.error(ex); - } - return rowsPurged; - } - + long rowsPurged = -1l; + try { + if (clusterService.lock(ClusterConstants.PURGE_DATA_GAPS)) { + try { + log.info("The data gap purge process is about to run"); + rowsPurged = sqlTemplate.update(getSql("deleteFromDataGapsSql"), + new Object[] { retentionCutoff.getTime() }); + log.info("Purged %d data gap rows", rowsPurged); + } finally { + clusterService.unlock(ClusterConstants.PURGE_DATA_GAPS); + log.info("The data gap purge process has completed"); + } + + } else { + log.warn("Did not run the data gap purge process because the cluster service has it locked"); + } + } catch (Exception ex) { + log.error(ex); + } + return rowsPurged; + } + public long purgeOutgoing(Calendar retentionCutoff) { - long rowsPurged = 0; - try { - if (clusterService.lock(ClusterConstants.PURGE_OUTGOING)) { - try { - log.info("DataPurgeOutgoingRunning", SimpleDateFormat.getDateTimeInstance().format( - retentionCutoff.getTime())); - rowsPurged += purgeStrandedBatches(); - rowsPurged += purgeDataRows(retentionCutoff); - rowsPurged += purgeOutgoingBatch(retentionCutoff); - } finally { - clusterService.unlock(ClusterConstants.PURGE_OUTGOING); - log.info("DataPurgeOutgoingCompleted"); - } - } else { - log.info("DataPurgeOutgoingRunningFailedLock"); - } - } catch (Exception ex) { - log.error(ex); + long rowsPurged = 0; + try { + if (clusterService.lock(ClusterConstants.PURGE_OUTGOING)) { + try { + log.info("The outgoing purge process is about to run for data older than %s", + SimpleDateFormat.getDateTimeInstance() + .format(retentionCutoff.getTime())); + rowsPurged += purgeStrandedBatches(); + rowsPurged += purgeDataRows(retentionCutoff); + rowsPurged += purgeOutgoingBatch(retentionCutoff); + } finally { + clusterService.unlock(ClusterConstants.PURGE_OUTGOING); + log.info("The outgoing purge process has completed"); + } + } else { + log.info("Could not get a lock to run an outgoing purge"); + } + } catch (Exception ex) { + log.error(ex); } - return rowsPurged; - } - - private long purgeOutgoingBatch(final Calendar time) { - log.info("DataPurgeOutgoingRange"); - long[] minMax = queryForMinMax(getSql("selectOutgoingBatchRangeSql"), new Object[] { time.getTime() }); - int maxNumOfBatchIdsToPurgeInTx = parameterService.getInt(ParameterConstants.PURGE_MAX_NUMBER_OF_BATCH_IDS); - int maxNumOfDataEventsToPurgeInTx = parameterService - .getInt(ParameterConstants.PURGE_MAX_NUMBER_OF_EVENT_BATCH_IDS); - int dataEventsPurgedCount = purgeByMinMax(minMax, getSql("deleteDataEventSql"), time.getTime(), maxNumOfDataEventsToPurgeInTx); - statisticManager.incrementPurgedDataEventRows(dataEventsPurgedCount); - int outgoingbatchPurgedCount = purgeByMinMax(minMax, getSql("deleteOutgoingBatchSql"), time.getTime(), maxNumOfBatchIdsToPurgeInTx); - statisticManager.incrementPurgedBatchOutgoingRows(outgoingbatchPurgedCount); + return rowsPurged; + } + + private long purgeOutgoingBatch(final Calendar time) { + log.info("Getting range for outgoing batch"); + long[] minMax = queryForMinMax(getSql("selectOutgoingBatchRangeSql"), + new Object[] { time.getTime() }); + int maxNumOfBatchIdsToPurgeInTx = parameterService + .getInt(ParameterConstants.PURGE_MAX_NUMBER_OF_BATCH_IDS); + int maxNumOfDataEventsToPurgeInTx = parameterService + .getInt(ParameterConstants.PURGE_MAX_NUMBER_OF_EVENT_BATCH_IDS); + int dataEventsPurgedCount = purgeByMinMax(minMax, MinMaxDeleteSql.DATA, time.getTime(), + maxNumOfDataEventsToPurgeInTx); + statisticManager.incrementPurgedDataEventRows(dataEventsPurgedCount); + int outgoingbatchPurgedCount = purgeByMinMax(minMax, MinMaxDeleteSql.OUTGOING_BATCH, + time.getTime(), maxNumOfBatchIdsToPurgeInTx); + statisticManager.incrementPurgedBatchOutgoingRows(outgoingbatchPurgedCount); long unroutedPurgedCount = purgeUnroutedDataEvents(time.getTime()); - return dataEventsPurgedCount + outgoingbatchPurgedCount + unroutedPurgedCount; - } - - private long purgeStrandedBatches() { - int updateStrandedBatchesCount = getSimpleTemplate().update(getSql("updateStrandedBatches")); - if (updateStrandedBatchesCount > 0) { - log.info("DataPurgeUpdatedStrandedBatches", updateStrandedBatchesCount); - statisticManager.incrementPurgedBatchOutgoingRows(updateStrandedBatchesCount); - } - return updateStrandedBatchesCount; - } - - private long purgeUnroutedDataEvents(Date time) { - Map params = new HashMap(); - params.put(PARAM_CUTOFF_TIME, new Timestamp(time.getTime())); - int unroutedDataEventCount = getSimpleTemplate().update(getSql("deleteUnroutedDataEventSql"), params); + return dataEventsPurgedCount + outgoingbatchPurgedCount + unroutedPurgedCount; + } + + private long purgeStrandedBatches() { + int updateStrandedBatchesCount = sqlTemplate.update(getSql("updateStrandedBatches")); + if (updateStrandedBatchesCount > 0) { + log.info( + "Set the status to OK for %d batches that no longer are associated with valid nodes", + updateStrandedBatchesCount); + statisticManager.incrementPurgedBatchOutgoingRows(updateStrandedBatchesCount); + } + return updateStrandedBatchesCount; + } + + private long purgeUnroutedDataEvents(Date time) { + int unroutedDataEventCount = sqlTemplate.update(getSql("deleteUnroutedDataEventSql"), + new Timestamp(time.getTime())); if (unroutedDataEventCount > 0) { - statisticManager.incrementPurgedDataEventRows(unroutedDataEventCount); - log.info("DataPurgeTableCompleted", unroutedDataEventCount, "unrouted data_event"); + statisticManager.incrementPurgedDataEventRows(unroutedDataEventCount); + log.info("Done purging %d of %s rows", unroutedDataEventCount, "unrouted data_event"); } - return unroutedDataEventCount; - } - - private long purgeDataRows(final Calendar time) { - log.info("DataPurgeRowsRange"); - long[] minMax = queryForMinMax(getSql("selectDataRangeSql"), new Object[0]); - int maxNumOfDataIdsToPurgeInTx = parameterService.getInt(ParameterConstants.PURGE_MAX_NUMBER_OF_DATA_IDS); - int dataDeletedCount = purgeByMinMax(minMax, getSql("deleteDataSql"), time.getTime(), maxNumOfDataIdsToPurgeInTx); - statisticManager.incrementPurgedDataRows(dataDeletedCount); - int strandedDeletedCount = purgeByMinMax(minMax, getSql("deleteStrandedData"), time.getTime(), maxNumOfDataIdsToPurgeInTx); + return unroutedDataEventCount; + } + + private long purgeDataRows(final Calendar time) { + log.info("Getting range for data"); + long[] minMax = queryForMinMax(getSql("selectDataRangeSql"), new Object[0]); + int maxNumOfDataIdsToPurgeInTx = parameterService + .getInt(ParameterConstants.PURGE_MAX_NUMBER_OF_DATA_IDS); + int dataDeletedCount = purgeByMinMax(minMax, MinMaxDeleteSql.DATA, time.getTime(), + maxNumOfDataIdsToPurgeInTx); + statisticManager.incrementPurgedDataRows(dataDeletedCount); + int strandedDeletedCount = purgeByMinMax(minMax, MinMaxDeleteSql.STRANDED_DATA, + time.getTime(), maxNumOfDataIdsToPurgeInTx); statisticManager.incrementPurgedDataRows(strandedDeletedCount); - return dataDeletedCount + strandedDeletedCount; - - } - - private long[] queryForMinMax(String sql, Object[] params) { - long[] minMax = (long[]) jdbcTemplate.queryForObject(sql, params, new RowMapper() { - public long[] mapRow(ResultSet rs, int row) throws SQLException { - return new long[] { rs.getLong(1), rs.getLong(2) }; - } - }); - return minMax; - } - - private int purgeByMinMax(long[] minMax, String deleteSql, Date retentionTime, int maxNumtoPurgeinTx) { - long minId = minMax[0]; - long purgeUpToId = minMax[1]; - long ts = System.currentTimeMillis(); - int totalCount = 0; - int totalDeleteStmts = 0; - String tableName = deleteSql.trim().split("\\s")[2]; - log.info("DataPurgeTableStarting", tableName); - - MapSqlParameterSource parameterSource = new MapSqlParameterSource(); - parameterSource.registerSqlType(PARAM_CUTOFF_TIME, Types.TIMESTAMP); - parameterSource.registerSqlType(PARAM_MIN, Types.NUMERIC); - parameterSource.registerSqlType(PARAM_MAX, Types.NUMERIC); - parameterSource.addValue(PARAM_CUTOFF_TIME, new Timestamp(retentionTime.getTime())); - - while (minId <= purgeUpToId) { - totalDeleteStmts++; - long maxId = minId + maxNumtoPurgeinTx; - if (maxId > purgeUpToId) { - maxId = purgeUpToId; - } - - parameterSource.addValue(PARAM_MIN, minId); - parameterSource.addValue(PARAM_MAX, maxId); - - totalCount += getSimpleTemplate().update(deleteSql, parameterSource); - - if (totalCount > 0 && (System.currentTimeMillis() - ts > DateUtils.MILLIS_PER_MINUTE * 5)) { - log.info("DataPurgeTableRunning", totalCount, tableName, totalDeleteStmts); - ts = System.currentTimeMillis(); - } - minId = maxId + 1; - } - log.info("DataPurgeTableCompleted", totalCount, tableName); - return totalCount; - } - + return dataDeletedCount + strandedDeletedCount; + + } + + private long[] queryForMinMax(String sql, Object... params) { + long[] minMax = sqlTemplate.queryForObject(sql, new ISqlRowMapper() { + public long[] mapRow(Row rs) { + return new long[] { rs.getLong("min_id"), rs.getLong("max_id") }; + } + }, params); + return minMax; + } + + private int purgeByMinMax(long[] minMax, MinMaxDeleteSql identifier, Date retentionTime, + int maxNumtoPurgeinTx) { + long minId = minMax[0]; + long purgeUpToId = minMax[1]; + long ts = System.currentTimeMillis(); + int totalCount = 0; + int totalDeleteStmts = 0; + Timestamp cutoffTime = new Timestamp(retentionTime.getTime()); + log.info("About to purge %s", identifier.toString().toLowerCase()); + while (minId <= purgeUpToId) { + totalDeleteStmts++; + long maxId = minId + maxNumtoPurgeinTx; + if (maxId > purgeUpToId) { + maxId = purgeUpToId; + } + + String deleteSql = null; + Object[] args = null; + + switch (identifier) { + case DATA: + deleteSql = getSql("deleteDataSql"); + args = new Object[] { minId, maxId, cutoffTime, minId, maxId, minId, maxId }; + break; + case DATA_EVENT: + deleteSql = getSql("deleteDataEventSql"); + args = new Object[] { minId, maxId, minId, maxId }; + break; + case OUTGOING_BATCH: + deleteSql = getSql("deleteOutgoingBatchSql"); + args = new Object[] { minId, maxId, minId, maxId }; + break; + case STRANDED_DATA: + deleteSql = getSql("deleteStrandedData"); + args = new Object[] { minId, maxId, cutoffTime, minId, maxId, minId, maxId }; + break; + } + + totalCount += sqlTemplate.update(deleteSql, args); + + if (totalCount > 0 + && (System.currentTimeMillis() - ts > DateUtils.MILLIS_PER_MINUTE * 5)) { + log.info("Purged %d of %s rows so far using %d statements", totalCount, identifier + .toString().toLowerCase(), totalDeleteStmts); + ts = System.currentTimeMillis(); + } + minId = maxId + 1; + } + log.info("Done purging %d of %s rows", totalCount, identifier.toString().toLowerCase()); + return totalCount; + } + public long purgeIncoming(Calendar retentionCutoff) { - long purgedRowCount = 0; - try { - if (clusterService.lock(ClusterConstants.PURGE_INCOMING)) { - try { - log.info("DataPurgeIncomingRunning"); - purgedRowCount = purgeIncomingBatch(retentionCutoff); - } finally { - clusterService.unlock(ClusterConstants.PURGE_INCOMING); - log.info("DataPurgeIncomingCompleted"); - } - } else { - log.info("DataPurgeIncomingRunningFailed"); - } - } catch (Exception ex) { - log.error(ex); + long purgedRowCount = 0; + try { + if (clusterService.lock(ClusterConstants.PURGE_INCOMING)) { + try { + log.info("The incoming purge process is about to run"); + purgedRowCount = purgeIncomingBatch(retentionCutoff); + } finally { + clusterService.unlock(ClusterConstants.PURGE_INCOMING); + log.info("The incoming purge process has completed"); + } + } else { + log.info("Could not get a lock to run an incoming purge"); + } + } catch (Exception ex) { + log.error(ex); } - return purgedRowCount; - } - - private long purgeIncomingBatch(final Calendar time) { - log.info("DataPurgeIncomingRange"); - List nodeBatchRangeList = jdbcTemplate.query(getSql("selectIncomingBatchRangeSql"), - new Object[] { time.getTime() }, new RowMapper() { - public NodeBatchRange mapRow(ResultSet rs, int rowNum) throws SQLException { - return new NodeBatchRange(rs.getString(1), rs.getLong(2), rs.getLong(3)); - } - }); - int incomingBatchesPurgedCount = purgeByNodeBatchRangeList(getSql("deleteIncomingBatchSql"), nodeBatchRangeList); + return purgedRowCount; + } + + private long purgeIncomingBatch(final Calendar time) { + log.info("Getting range for incoming batch"); + List nodeBatchRangeList = sqlTemplate.query( + getSql("selectIncomingBatchRangeSql"), new ISqlRowMapper() { + public NodeBatchRange mapRow(Row rs) { + return new NodeBatchRange(rs.getString("node_id"), rs + .getLong("min_batch_id"), rs.getLong("max_batch_id")); + } + }, time.getTime()); + int incomingBatchesPurgedCount = purgeByNodeBatchRangeList( + getSql("deleteIncomingBatchSql"), nodeBatchRangeList); statisticManager.incrementPurgedBatchIncomingRows(incomingBatchesPurgedCount); - return incomingBatchesPurgedCount; - } - - private int purgeByNodeBatchRangeList(String deleteSql, List nodeBatchRangeList) { - long ts = System.currentTimeMillis(); - int totalCount = 0; - int totalDeleteStmts = 0; - String tableName = deleteSql.trim().split("\\s")[2]; - log.info("DataPurgeTableStarting", tableName); - - for (NodeBatchRange nodeBatchRange : nodeBatchRangeList) { - int maxNumOfDataIdsToPurgeInTx = parameterService.getInt(ParameterConstants.PURGE_MAX_NUMBER_OF_BATCH_IDS); - long minBatchId = nodeBatchRange.getMinBatchId(); - long purgeUpToBatchId = nodeBatchRange.getMaxBatchId(); - - while (minBatchId <= purgeUpToBatchId) { - totalDeleteStmts++; - long maxBatchId = minBatchId + maxNumOfDataIdsToPurgeInTx; - if (maxBatchId > purgeUpToBatchId) { - maxBatchId = purgeUpToBatchId; - } - totalCount += jdbcTemplate.update(deleteSql, new Object[] { minBatchId, maxBatchId, - nodeBatchRange.getNodeId() }); - minBatchId = maxBatchId + 1; - } - - if (totalCount > 0 && (System.currentTimeMillis() - ts > DateUtils.MILLIS_PER_MINUTE * 5)) { - log.info("DataPurgeTableRunning", totalCount, tableName, totalDeleteStmts); - ts = System.currentTimeMillis(); - } - } - log.info("DataPurgeTableCompleted", totalCount, tableName); - return totalCount; - } - - class NodeBatchRange { - private String nodeId; - - private long minBatchId; - - private long maxBatchId; - - public NodeBatchRange(String nodeId, long minBatchId, long maxBatchId) { - this.nodeId = nodeId; - this.minBatchId = minBatchId; - this.maxBatchId = maxBatchId; - } - - public String getNodeId() { - return nodeId; - } - - public long getMaxBatchId() { - return maxBatchId; - } - - public long getMinBatchId() { - return minBatchId; - } - } - - public void purgeAllIncomingEventsForNode(String nodeId) { - int count = jdbcTemplate.update(getSql("deleteIncomingBatchByNodeSql"), new Object[] { nodeId }); - log.info("DataPurgeIncomingAllCompleted", count, nodeId); - } - - public void setClusterService(IClusterService clusterService) { - this.clusterService = clusterService; - } - - public void setNodeService(INodeService nodeService) { - this.nodeService = nodeService; + return incomingBatchesPurgedCount; } - - public void setStatisticManager(IStatisticManager statisticManager) { - this.statisticManager = statisticManager; + + private int purgeByNodeBatchRangeList(String deleteSql, List nodeBatchRangeList) { + long ts = System.currentTimeMillis(); + int totalCount = 0; + int totalDeleteStmts = 0; + String tableName = deleteSql.trim().split("\\s")[2]; + log.info("About to purge %s", tableName); + + for (NodeBatchRange nodeBatchRange : nodeBatchRangeList) { + int maxNumOfDataIdsToPurgeInTx = parameterService + .getInt(ParameterConstants.PURGE_MAX_NUMBER_OF_BATCH_IDS); + long minBatchId = nodeBatchRange.getMinBatchId(); + long purgeUpToBatchId = nodeBatchRange.getMaxBatchId(); + + while (minBatchId <= purgeUpToBatchId) { + totalDeleteStmts++; + long maxBatchId = minBatchId + maxNumOfDataIdsToPurgeInTx; + if (maxBatchId > purgeUpToBatchId) { + maxBatchId = purgeUpToBatchId; + } + totalCount += sqlTemplate.update(deleteSql, new Object[] { minBatchId, maxBatchId, + nodeBatchRange.getNodeId() }); + minBatchId = maxBatchId + 1; + } + + if (totalCount > 0 + && (System.currentTimeMillis() - ts > DateUtils.MILLIS_PER_MINUTE * 5)) { + log.info("Purged %d of %s rows so far using %d statements", totalCount, tableName, + totalDeleteStmts); + ts = System.currentTimeMillis(); + } + } + log.info("Done purging %d of %s rows", totalCount, tableName); + return totalCount; + } + + class NodeBatchRange { + private String nodeId; + + private long minBatchId; + + private long maxBatchId; + + public NodeBatchRange(String nodeId, long minBatchId, long maxBatchId) { + this.nodeId = nodeId; + this.minBatchId = minBatchId; + this.maxBatchId = maxBatchId; + } + + public String getNodeId() { + return nodeId; + } + + public long getMaxBatchId() { + return maxBatchId; + } + + public long getMinBatchId() { + return minBatchId; + } + } + + public void purgeAllIncomingEventsForNode(String nodeId) { + int count = sqlTemplate.update(getSql("deleteIncomingBatchByNodeSql"), + new Object[] { nodeId }); + log.info("Purged all %d incoming batch for node %s", count, nodeId); } - + } \ No newline at end of file diff --git a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/impl/PurgeServiceSqlMap.java b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/impl/PurgeServiceSqlMap.java index 2ed3c125b2..366e915d3a 100644 --- a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/impl/PurgeServiceSqlMap.java +++ b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/impl/PurgeServiceSqlMap.java @@ -10,25 +10,25 @@ public PurgeServiceSqlMap(IDatabasePlatform platform, Map replac super(platform, replacementTokens); putSql("selectOutgoingBatchRangeSql" ,"" + -"select min(batch_id), max(batch_id) from $(prefixName)_outgoing_batch where " + +"select min(batch_id) as min_id, max(batch_id) as max_id from $(prefixName)_outgoing_batch where " + " create_time < ? and status in ('OK','IG') and batch_id < (select max(batch_id) from $(prefixName)_outgoing_batch) " ); putSql("deleteOutgoingBatchSql" ,"" + "delete from $(prefixName)_outgoing_batch where status in ('OK','IG') and batch_id between :MIN " + " and :MAX and batch_id not in (select batch_id from $(prefixName)_data_event where batch_id between :MIN " + -" and :MAX) " ); +" and :MAX) " ); putSql("deleteDataEventSql" ,"" + "delete from $(prefixName)_data_event where batch_id not in (select batch_id from " + " $(prefixName)_outgoing_batch where batch_id between :MIN and :MAX and status not in ('OK','IG')) " + -" and batch_id between :MIN and :MAX " ); +" and batch_id between :MIN and :MAX " ); putSql("deleteUnroutedDataEventSql" ,"" + "delete from $(prefixName)_data_event where " + -" batch_id=-1 and create_time < :CUTOFF_TIME " ); +" batch_id=-1 and create_time < ? " ); putSql("selectDataRangeSql" ,"" + -"select min(data_id), max(data_id) from $(prefixName)_data where data_id < (select max(data_id) from $(prefixName)_data) " ); +"select min(data_id) as min_id, max(data_id) as max_id from $(prefixName)_data where data_id < (select max(data_id) from $(prefixName)_data) " ); putSql("updateStrandedBatches" ,"" + "update $(prefixName)_outgoing_batch set status='OK' where node_id not " + @@ -36,34 +36,34 @@ public PurgeServiceSqlMap(IDatabasePlatform platform, Map replac putSql("deleteStrandedData" ,"" + "delete from $(prefixName)_data where " + -" data_id between :MIN and :MAX and " + +" data_id between :MIN and :MAX and " + " data_id < (select max(ref_data_id) from $(prefixName)_data_ref) and " + -" create_time < :CUTOFF_TIME and " + +" create_time < :CUTOFF_TIME and " + " data_id not in (select e.data_id from $(prefixName)_data_event e where " + -" e.data_id between :MIN and :MAX) " ); +" e.data_id between :MIN and :MAX) " ); putSql("deleteDataSql" ,"" + "delete from $(prefixName)_data where " + -" data_id between :MIN and :MAX and " + -" create_time < :CUTOFF_TIME and " + +" data_id between :MIN and :MAX and " + +" create_time < :CUTOFF_TIME and " + " data_id in (select e.data_id from $(prefixName)_data_event e where " + -" e.data_id between :MIN and :MAX) " + -" and " + -" data_id not in " + +" e.data_id between :MIN and :MAX) " + +" and " + +" data_id not in " + " (select e.data_id from $(prefixName)_data_event e where " + -" e.data_id between :MIN and :MAX and " + -" (e.data_id is null or " + -" e.batch_id in " + +" e.data_id between :MIN and :MAX and " + +" (e.data_id is null or " + +" e.batch_id in " + " (select batch_id from $(prefixName)_outgoing_batch where " + -" status not in ('OK','IG')))) " ); +" status not in ('OK','IG')))) " ); putSql("selectIncomingBatchRangeSql" ,"" + -"select node_id, min(batch_id), max(batch_id) from $(prefixName)_incoming_batch where " + +"select node_id, min(batch_id) as min_id, max(batch_id) as max_id from $(prefixName)_incoming_batch where " + " create_time < ? and status = 'OK' group by node_id " ); putSql("deleteIncomingBatchSql" ,"" + "delete from $(prefixName)_incoming_batch where batch_id between ? and ? and node_id = " + -" ? and status = 'OK' " ); +" ? and status = 'OK' " ); putSql("deleteFromDataGapsSql" ,"" + "delete from $(prefixName)_data_gap where last_update_time < ? and status != 'GP' " ); diff --git a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/impl/PushService.java b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/impl/PushService.java index 4edf2ab186..7b0d23c5ce 100644 --- a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/impl/PushService.java +++ b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/impl/PushService.java @@ -28,6 +28,7 @@ import org.apache.commons.lang.StringUtils; import org.jumpmind.db.sql.AbstractSqlMap; +import org.jumpmind.symmetric.db.ISymmetricDialect; import org.jumpmind.symmetric.model.BatchInfo; import org.jumpmind.symmetric.model.Node; import org.jumpmind.symmetric.model.NodeSecurity; @@ -39,6 +40,7 @@ import org.jumpmind.symmetric.service.IClusterService; import org.jumpmind.symmetric.service.IDataExtractorService; import org.jumpmind.symmetric.service.INodeService; +import org.jumpmind.symmetric.service.IParameterService; import org.jumpmind.symmetric.service.IPushService; import org.jumpmind.symmetric.service.RegistrationRequiredException; import org.jumpmind.symmetric.transport.AuthenticationException; @@ -53,16 +55,28 @@ */ public class PushService extends AbstractOfflineDetectorService implements IPushService { - private IDataExtractorService extractor; + private IDataExtractorService dataExtractorService; - private IAcknowledgeService ackService; + private IAcknowledgeService acknowledgeService; private ITransportManager transportManager; private INodeService nodeService; - private IClusterService clusterService; - + private IClusterService clusterService; + + public PushService(IParameterService parameterService, ISymmetricDialect symmetricDialect, + IDataExtractorService dataExtractorService, IAcknowledgeService acknowledgeService, + ITransportManager transportManager, INodeService nodeService, + IClusterService clusterService) { + super(parameterService, symmetricDialect); + this.dataExtractorService = dataExtractorService; + this.acknowledgeService = acknowledgeService; + this.transportManager = transportManager; + this.nodeService = nodeService; + this.clusterService = clusterService; + } + synchronized public RemoteNodeStatuses pushData() { RemoteNodeStatuses statuses = new RemoteNodeStatuses(); @@ -107,7 +121,7 @@ private RemoteNodeStatus pushToNode(Node remote, Node identity, NodeSecurity ide transport = transportManager.getPushTransport(remote, identity, identitySecurity .getNodePassword(), parameterService.getRegistrationUrl()); - List extractedBatches = extractor.extract(remote, transport); + List extractedBatches = dataExtractorService.extract(remote, transport); if (extractedBatches.size() > 0) { log.info("DataSent", remote); BufferedReader reader = transport.readResponse(); @@ -127,7 +141,7 @@ private RemoteNodeStatus pushToNode(Node remote, Node identity, NodeSecurity ide for (BatchInfo batchInfo : batches) { log.debug("DataAckSaving", batchInfo.getBatchId(), (batchInfo.isOk() ? "OK" : "error")); - ackService.ack(batchInfo); + acknowledgeService.ack(batchInfo); } status.updateOutgoingStatus(extractedBatches, batches); @@ -174,24 +188,4 @@ protected AbstractSqlMap createSqlMap() { return null; } - public void setExtractor(IDataExtractorService extractor) { - this.extractor = extractor; - } - - public void setTransportManager(ITransportManager tm) { - this.transportManager = tm; - } - - public void setNodeService(INodeService nodeService) { - this.nodeService = nodeService; - } - - public void setAckService(IAcknowledgeService ackService) { - this.ackService = ackService; - } - - public void setClusterService(IClusterService clusterService) { - this.clusterService = clusterService; - } - } \ No newline at end of file diff --git a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/impl/RegistrationService.java b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/impl/RegistrationService.java index 52304ae2cb..2d83deaa86 100644 --- a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/impl/RegistrationService.java +++ b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/impl/RegistrationService.java @@ -24,20 +24,19 @@ import java.io.OutputStream; import java.net.ConnectException; import java.net.UnknownHostException; -import java.sql.ResultSet; -import java.sql.SQLException; import java.sql.Types; import java.util.Collection; -import java.util.HashMap; import java.util.Iterator; import java.util.List; -import java.util.Map; import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.time.DateUtils; import org.jumpmind.db.sql.AbstractSqlMap; -import org.jumpmind.symmetric.Version; +import org.jumpmind.db.sql.ISqlRowMapper; +import org.jumpmind.db.sql.Row; +import org.jumpmind.db.sql.mapper.StringMapper; import org.jumpmind.symmetric.common.ParameterConstants; +import org.jumpmind.symmetric.db.ISymmetricDialect; import org.jumpmind.symmetric.model.Node; import org.jumpmind.symmetric.model.NodeSecurity; import org.jumpmind.symmetric.model.RegistrationRequest; @@ -48,16 +47,13 @@ import org.jumpmind.symmetric.service.IDataLoaderService; import org.jumpmind.symmetric.service.IDataService; import org.jumpmind.symmetric.service.INodeService; +import org.jumpmind.symmetric.service.IParameterService; import org.jumpmind.symmetric.service.IRegistrationService; import org.jumpmind.symmetric.service.RegistrationFailedException; import org.jumpmind.symmetric.service.RegistrationRedirectException; import org.jumpmind.symmetric.statistic.IStatisticManager; import org.jumpmind.symmetric.transport.ITransportManager; -import org.jumpmind.symmetric.upgrade.UpgradeConstants; import org.jumpmind.symmetric.util.RandomTimeSlot; -import org.springframework.dao.DataAccessException; -import org.springframework.jdbc.core.ResultSetExtractor; -import org.springframework.jdbc.core.RowMapper; /** * @see IRegistrationService @@ -77,9 +73,23 @@ public class RegistrationService extends AbstractService implements IRegistratio private RandomTimeSlot randomTimeSlot; private INodePasswordFilter nodePasswordFilter; - + private IStatisticManager statisticManager; + public RegistrationService(IParameterService parameterService, + ISymmetricDialect symmetricDialect, INodeService nodeService, + IDataExtractorService dataExtractorService, IDataService dataService, + IDataLoaderService dataLoaderService, ITransportManager transportManager, + IStatisticManager statisticManager) { + super(parameterService, symmetricDialect); + this.nodeService = nodeService; + this.dataExtractorService = dataExtractorService; + this.dataService = dataService; + this.dataLoaderService = dataLoaderService; + this.transportManager = transportManager; + this.statisticManager = statisticManager; + } + public boolean registerNode(Node node, OutputStream out, boolean isRequestedRegistration) throws IOException { return registerNode(node, null, null, out, isRequestedRegistration); @@ -130,18 +140,12 @@ public boolean registerNode(Node node, String remoteHost, String remoteAddress, node.setNodeId(nodeId); - jdbcTemplate.update(getSql("registerNodeSql"), + sqlTemplate.update(getSql("registerNodeSql"), new Object[] { node.getSyncUrl(), node.getSchemaVersion(), node.getDatabaseType(), node.getDatabaseVersion(), node.getSymmetricVersion(), node.getNodeId() }, new int[] { Types.VARCHAR, Types.VARCHAR, Types.VARCHAR, Types.VARCHAR, Types.VARCHAR, Types.VARCHAR }); - if (node.getSymmetricVersion() != null - && Version.isOlderThanVersion(node.getSymmetricVersion(), - UpgradeConstants.VERSION_FOR_NEW_REGISTRATION_PROTOCOL)) { - markNodeAsRegistered(nodeId); - } - if (parameterService.is(ParameterConstants.AUTO_RELOAD_ENABLED)) { // only send automatic initial load once or if the client is really // re-registering @@ -157,13 +161,13 @@ public boolean registerNode(Node node, String remoteHost, String remoteAddress, remoteAddress)); statisticManager.incrementNodesRegistered(1); - + return true; } public List getRegistrationRequests( boolean includeNodesWithOpenRegistrations) { - List requests = jdbcTemplate.query( + List requests = sqlTemplate.query( getSql("selectRegistrationRequestSql"), new RegistrationRequestMapper(), RegistrationStatus.RQ.name()); if (!includeNodesWithOpenRegistrations) { @@ -185,14 +189,14 @@ public List getRegistrationRequests( public void saveRegisgtrationRequest(RegistrationRequest request) { String externalId = request.getExternalId() == null ? "" : request.getExternalId(); String nodeGroupId = request.getNodeGroupId() == null ? "" : request.getNodeGroupId(); - int count = jdbcTemplate.update( + int count = sqlTemplate.update( getSql("updateRegistrationRequestSql"), new Object[] { request.getLastUpdateBy(), request.getLastUpdateTime(), request.getRegisteredNodeId(), request.getStatus().name(), nodeGroupId, externalId, request.getIpAddress(), request.getHostName(), RegistrationStatus.RQ.name() }); if (count == 0) { - jdbcTemplate.update( + sqlTemplate.update( getSql("insertRegistrationRequestSql"), new Object[] { request.getLastUpdateBy(), request.getLastUpdateTime(), request.getRegisteredNodeId(), request.getStatus().name(), nodeGroupId, @@ -202,8 +206,8 @@ public void saveRegisgtrationRequest(RegistrationRequest request) { } public String getRedirectionUrlFor(String externalId) { - List list = jdbcTemplate.queryForList(getSql("getRegistrationRedirectUrlSql"), - new Object[] { externalId }, new int[] { Types.VARCHAR }, String.class); + List list = sqlTemplate.query(getSql("getRegistrationRedirectUrlSql"), + new StringMapper(), new Object[] { externalId }, new int[] { Types.VARCHAR }); if (list.size() > 0) { return transportManager.resolveURL(list.get(0), parameterService.getRegistrationUrl()); } else { @@ -212,11 +216,11 @@ public String getRedirectionUrlFor(String externalId) { } public void saveRegistrationRedirect(String externalIdToRedirect, String nodeIdToRedirectTo) { - int count = jdbcTemplate.update(getSql("updateRegistrationRedirectUrlSql"), new Object[] { + int count = sqlTemplate.update(getSql("updateRegistrationRedirectUrlSql"), new Object[] { nodeIdToRedirectTo, externalIdToRedirect }, new int[] { Types.VARCHAR, Types.VARCHAR }); if (count == 0) { - jdbcTemplate.update(getSql("insertRegistrationRedirectUrlSql"), new Object[] { + sqlTemplate.update(getSql("insertRegistrationRedirectUrlSql"), new Object[] { nodeIdToRedirectTo, externalIdToRedirect }, new int[] { Types.VARCHAR, Types.VARCHAR }); } @@ -226,22 +230,7 @@ public void saveRegistrationRedirect(String externalIdToRedirect, String nodeIdT * @see IRegistrationService#markNodeAsRegistered(Node) */ public void markNodeAsRegistered(String nodeId) { - jdbcTemplate.update(getSql("registerNodeSecuritySql"), new Object[] { nodeId }); - } - - public Map getRegistrationRedirectMap() { - return this.jdbcTemplate.query(getSql("getRegistrationRedirectSql"), new Object[0], - new ResultSetExtractor>() { - public Map extractData(ResultSet rs) throws SQLException, - DataAccessException { - Map results = new HashMap(); - while (rs.next()) { - results.put(rs.getString(1), rs.getString(2)); - } - ; - return results; - } - }); + sqlTemplate.update(getSql("registerNodeSecuritySql"), new Object[] { nodeId }); } private void sleepBeforeRegistrationRetry() { @@ -294,7 +283,7 @@ public void registerWithServer() { registered = false; } } - + if (!registered && maxNumberOfAttempts != 0) { sleepBeforeRegistrationRetry(); } @@ -315,13 +304,13 @@ public synchronized void reOpenRegistration(String nodeId) { String password = nodeService.getNodeIdGenerator().generatePassword(nodeService, node); password = filterPasswordOnSaveIfNeeded(password); if (node != null) { - int updateCount = jdbcTemplate.update(getSql("reopenRegistrationSql"), new Object[] { + int updateCount = sqlTemplate.update(getSql("reopenRegistrationSql"), new Object[] { password, nodeId }); if (updateCount == 0) { // if the update count was 0, then we probably have a row in the // node table, but not in node security. // lets go ahead and try to insert into node security. - jdbcTemplate.update(getSql("openRegistrationNodeSecuritySql"), new Object[] { + sqlTemplate.update(getSql("openRegistrationNodeSecuritySql"), new Object[] { nodeId, password, nodeService.findNode(nodeId).getNodeId() }); } } else { @@ -348,14 +337,15 @@ protected synchronized String openRegistration(Node node) { String nodeId = nodeService.getNodeIdGenerator().generateNodeId(nodeService, node); Node existingNode = nodeService.findNode(nodeId); if (existingNode == null) { - // make sure there isn't a node security row lying around w/out a node row + // make sure there isn't a node security row lying around w/out + // a node row nodeService.deleteNodeSecurity(nodeId); String password = nodeService.getNodeIdGenerator().generatePassword(nodeService, node); password = filterPasswordOnSaveIfNeeded(password); nodeService.insertNode(nodeId, node.getNodeGroupId(), node.getExternalId(), me.getNodeId()); - jdbcTemplate.update(getSql("openRegistrationNodeSecuritySql"), new Object[] { + sqlTemplate.update(getSql("openRegistrationNodeSecuritySql"), new Object[] { nodeId, password, me.getNodeId() }); nodeService.insertNodeGroup(node.getNodeGroupId(), null); log.info("NodeRegistrationOpened", node.getExternalId(), node.getNodeGroupId(), @@ -369,11 +359,11 @@ protected synchronized String openRegistration(Node node) { "This node has not been configured. Could not find a row in the identity table."); } } - + @Override protected AbstractSqlMap createSqlMap() { return new RegistrationServiceSqlMap(symmetricDialect.getPlatform(), - createReplacementTokens()); + createSqlReplacementTokens()); } public void setNodeService(INodeService nodeService) { @@ -407,7 +397,7 @@ public void setRandomTimeSlot(RandomTimeSlot randomTimeSlot) { public void setNodePasswordFilter(INodePasswordFilter nodePasswordFilter) { this.nodePasswordFilter = nodePasswordFilter; } - + public void setStatisticManager(IStatisticManager statisticManager) { this.statisticManager = statisticManager; } @@ -419,7 +409,7 @@ private String filterPasswordOnSaveIfNeeded(String password) { } return s; } - + public boolean isRegistrationOpen(String nodeGroupId, String externalId) { Node node = nodeService.findNodeByExternalId(nodeGroupId, externalId); if (node != null) { @@ -429,19 +419,20 @@ public boolean isRegistrationOpen(String nodeGroupId, String externalId) { return false; } - class RegistrationRequestMapper implements RowMapper { - public RegistrationRequest mapRow(ResultSet rs, int rowNum) throws SQLException { + class RegistrationRequestMapper implements ISqlRowMapper { + public RegistrationRequest mapRow(Row rs) { RegistrationRequest request = new RegistrationRequest(); - request.setNodeGroupId(rs.getString(1)); - request.setExternalId(rs.getString(2)); - request.setStatus(RegistrationStatus.valueOf(RegistrationStatus.class, rs.getString(3))); - request.setHostName(rs.getString(4)); - request.setIpAddress(rs.getString(5)); - request.setAttemptCount(rs.getLong(6)); - request.setRegisteredNodeId(rs.getString(7)); - request.setCreateTime(rs.getTimestamp(8)); - request.setLastUpdateBy(rs.getString(7)); - request.setLastUpdateTime(rs.getTimestamp(8)); + request.setNodeGroupId(rs.getString("node_group_id")); + request.setExternalId(rs.getString("external_id")); + request.setStatus(RegistrationStatus.valueOf(RegistrationStatus.class, + rs.getString("status"))); + request.setHostName(rs.getString("host_name")); + request.setIpAddress(rs.getString("ip_address")); + request.setAttemptCount(rs.getLong("attempt_count")); + request.setRegisteredNodeId(rs.getString("registered_node_id")); + request.setCreateTime(rs.getDateTime("create_time")); + request.setLastUpdateBy(rs.getString("last_update_by")); + request.setLastUpdateTime(rs.getDateTime("last_update_time")); return request; } } diff --git a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/impl/RegistrationServiceSqlMap.java b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/impl/RegistrationServiceSqlMap.java index 6cd44195f4..a7a048f159 100644 --- a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/impl/RegistrationServiceSqlMap.java +++ b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/impl/RegistrationServiceSqlMap.java @@ -38,10 +38,7 @@ public RegistrationServiceSqlMap(IDatabasePlatform platform, Map putSql("updateRegistrationRedirectUrlSql" ,"" + "update $(prefixName)_registration_redirect set registration_node_id=? where registrant_external_id=? " ); - - putSql("getRegistrationRedirectSql" ,"" + -"select registrant_external_id, registration_node_id from $(prefixName)_registration_redirect " ); - + putSql("insertRegistrationRequestSql" ,"" + "insert into $(prefixName)_registration_request " + " (last_update_by, last_update_time, attempt_count, registered_node_id, status, " + diff --git a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/impl/RouterService.java b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/impl/RouterService.java index f67da1732b..14d1c6729f 100644 --- a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/impl/RouterService.java +++ b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/impl/RouterService.java @@ -23,6 +23,7 @@ import java.sql.SQLException; import java.util.ArrayList; import java.util.Collection; +import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; @@ -37,6 +38,7 @@ import org.jumpmind.db.sql.AbstractSqlMap; import org.jumpmind.symmetric.common.Constants; import org.jumpmind.symmetric.common.ParameterConstants; +import org.jumpmind.symmetric.db.ISymmetricDialect; import org.jumpmind.symmetric.model.Data; import org.jumpmind.symmetric.model.DataMetaData; import org.jumpmind.symmetric.model.Node; @@ -47,20 +49,32 @@ import org.jumpmind.symmetric.model.OutgoingBatch.Status; import org.jumpmind.symmetric.model.Router; import org.jumpmind.symmetric.model.TriggerRouter; +import org.jumpmind.symmetric.route.BshDataRouter; import org.jumpmind.symmetric.route.ChannelRouterContext; -import org.jumpmind.symmetric.route.DataToRouteReaderFactory; +import org.jumpmind.symmetric.route.ColumnMatchDataRouter; +import org.jumpmind.symmetric.route.ConfigurationChangedDataRouter; +import org.jumpmind.symmetric.route.DataGapDetector; +import org.jumpmind.symmetric.route.DataGapRouteReader; +import org.jumpmind.symmetric.route.DefaultBatchAlgorithm; +import org.jumpmind.symmetric.route.DefaultDataRouter; import org.jumpmind.symmetric.route.IBatchAlgorithm; import org.jumpmind.symmetric.route.IDataRouter; import org.jumpmind.symmetric.route.IDataToRouteGapDetector; import org.jumpmind.symmetric.route.IDataToRouteReader; +import org.jumpmind.symmetric.route.LookupTableDataRouter; +import org.jumpmind.symmetric.route.NonTransactionalBatchAlgorithm; import org.jumpmind.symmetric.route.SimpleRouterContext; +import org.jumpmind.symmetric.route.SubSelectDataRouter; +import org.jumpmind.symmetric.route.TransactionalBatchAlgorithm; import org.jumpmind.symmetric.service.ClusterConstants; import org.jumpmind.symmetric.service.IClusterService; import org.jumpmind.symmetric.service.IConfigurationService; import org.jumpmind.symmetric.service.IDataService; import org.jumpmind.symmetric.service.INodeService; import org.jumpmind.symmetric.service.IOutgoingBatchService; +import org.jumpmind.symmetric.service.IParameterService; import org.jumpmind.symmetric.service.IRouterService; +import org.jumpmind.symmetric.service.ITransformService; import org.jumpmind.symmetric.service.ITriggerRouterService; import org.jumpmind.symmetric.statistic.IStatisticManager; import org.jumpmind.symmetric.statistic.StatisticConstants; @@ -86,14 +100,38 @@ public class RouterService extends AbstractService implements IRouterService { private Map batchAlgorithms; - private DataToRouteReaderFactory dataToRouteReaderFactory; - private IStatisticManager statisticManager; transient ExecutorService readThread = null; - public Map getRouters() { - return routers; + public RouterService(IParameterService parameterService, ISymmetricDialect symmetricDialect, + IClusterService clusterService, IDataService dataService, + IConfigurationService configurationService, ITriggerRouterService triggerRouterService, + IOutgoingBatchService outgoingBatchService, INodeService nodeService, + IStatisticManager statisticManager, ITransformService transformService) { + super(parameterService, symmetricDialect); + this.clusterService = clusterService; + this.dataService = dataService; + this.configurationService = configurationService; + this.triggerRouterService = triggerRouterService; + this.outgoingBatchService = outgoingBatchService; + this.nodeService = nodeService; + this.statisticManager = statisticManager; + + this.batchAlgorithms = new HashMap(); + this.batchAlgorithms.put("default", new DefaultBatchAlgorithm()); + this.batchAlgorithms.put("nontransactional", new NonTransactionalBatchAlgorithm()); + this.batchAlgorithms.put("transactional", new TransactionalBatchAlgorithm()); + + this.routers = new HashMap(); + this.routers.put("configurationChanged", new ConfigurationChangedDataRouter( + configurationService, nodeService, triggerRouterService, parameterService, + transformService)); + this.routers.put("bsh", new BshDataRouter(symmetricDialect)); + this.routers.put("subselect", new SubSelectDataRouter(symmetricDialect)); + this.routers.put("lookuptable", new LookupTableDataRouter(symmetricDialect)); + this.routers.put("default", new DefaultDataRouter()); + this.routers.put("column", new ColumnMatchDataRouter(configurationService)); } /** @@ -115,8 +153,7 @@ protected synchronized ExecutorService getReadService() { if (readThread == null) { readThread = Executors.newCachedThreadPool(new ThreadFactory() { final AtomicInteger threadNumber = new AtomicInteger(1); - final String namePrefix = parameterService.getString( - ParameterConstants.ENGINE_NAME, "").toLowerCase() + final String namePrefix = parameterService.getEngineName().toLowerCase() + "-router-reader-"; public Thread newThread(Runnable r) { @@ -158,8 +195,8 @@ synchronized public long routeData() { try { insertInitialLoadEvents(); long ts = System.currentTimeMillis(); - IDataToRouteGapDetector gapDetector = dataToRouteReaderFactory - .getDataToRouteGapDetector(); + IDataToRouteGapDetector gapDetector = new DataGapDetector(log, dataService, + parameterService, symmetricDialect, getSqlMap()); gapDetector.beforeRouting(); dataCount = routeDataForEachChannel(); gapDetector.afterRouting(); @@ -230,7 +267,8 @@ protected int routeDataForChannel(final NodeChannel nodeChannel, final Node sour long ts = System.currentTimeMillis(); int dataCount = -1; try { - context = new ChannelRouterContext(sourceNode.getNodeId(), nodeChannel, dataSource); + context = new ChannelRouterContext(sourceNode.getNodeId(), nodeChannel, + symmetricDialect.getPlatform().getSqlTemplate().startSqlTransaction()); dataCount = selectDataAndRoute(context); return dataCount; } catch (Exception ex) { @@ -243,7 +281,7 @@ protected int routeDataForChannel(final NodeChannel nodeChannel, final Node sour try { if (dataCount > 0) { long insertTs = System.currentTimeMillis(); - dataService.insertDataEvents(context.getJdbcTemplate(), + dataService.insertDataEvents(context.getSqlTransaction(), context.getDataEventList()); context.clearDataEventsList(); completeBatchesAndCommit(context); @@ -252,7 +290,7 @@ protected int routeDataForChannel(final NodeChannel nodeChannel, final Node sour if (context.getLastDataIdProcessed() > 0) { String channelId = nodeChannel.getChannelId(); long queryTs = System.currentTimeMillis(); - long dataLeftToRoute = jdbcTemplate.queryForInt( + long dataLeftToRoute = sqlTemplate.queryForInt( getSql("selectUnroutedCountForChannelSql"), channelId, context.getLastDataIdProcessed()); queryTs = System.currentTimeMillis() - queryTs; @@ -333,7 +371,8 @@ protected Set findAvailableNodes(TriggerRouter triggerRouter, ChannelRoute * The current context of the routing process */ protected int selectDataAndRoute(ChannelRouterContext context) throws SQLException { - IDataToRouteReader reader = dataToRouteReaderFactory.getDataToRouteReader(context); + IDataToRouteReader reader = new DataGapRouteReader(log, getSqlMap(), context, dataService, + symmetricDialect, parameterService); getReadService().execute(reader); Data data = null; int totalDataCount = 0; @@ -356,7 +395,7 @@ protected int selectDataAndRoute(ChannelRouterContext context) throws SQLExcepti try { if (maxNumberOfEventsBeforeFlush <= context.getDataEventList().size() || context.isNeedsCommitted()) { - dataService.insertDataEvents(context.getJdbcTemplate(), + dataService.insertDataEvents(context.getSqlTransaction(), context.getDataEventList()); context.clearDataEventsList(); } @@ -406,7 +445,7 @@ protected int routeData(Data data, ChannelRouterContext context) throws SQLExcep context.getChannel()); Collection nodeIds = null; if (!context.getChannel().isIgnoreEnabled() - && triggerRouter.isRouted(data.getEventType())) { + && triggerRouter.isRouted(data.getDataEventType())) { IDataRouter dataRouter = getDataRouter(triggerRouter); context.addUsedDataRouter(dataRouter); long ts = System.currentTimeMillis(); @@ -453,7 +492,7 @@ protected int insertDataEvents(ChannelRouterContext context, DataMetaData dataMe outgoingBatchService.insertOutgoingBatch(batch); context.getBatchesByNodes().put(nodeId, batch); } - batch.incrementEventCount(dataMetaData.getData().getEventType()); + batch.incrementEventCount(dataMetaData.getData().getDataEventType()); batch.incrementDataEventCount(); numberOfDataEventsInserted++; context.addDataEvent(dataMetaData.getData().getDataId(), batch.getBatchId(), @@ -510,71 +549,27 @@ public void addBatchAlgorithm(String name, IBatchAlgorithm algorithm) { } public long getUnroutedDataCount() { - long maxDataIdAlreadyRouted = 0; - if (dataToRouteReaderFactory.isUsingDataRef()) { - maxDataIdAlreadyRouted = jdbcTemplate - .queryForLong(getSql("selectLastDataIdRoutedUsingDataRefSql")); - } else { - maxDataIdAlreadyRouted = jdbcTemplate - .queryForLong(getSql("selectLastDataIdRoutedUsingDataGapSql")); - } - + long maxDataIdAlreadyRouted = sqlTemplate + .queryForLong(getSql("selectLastDataIdRoutedUsingDataGapSql")); long leftToRoute = dataService.findMaxDataId() - maxDataIdAlreadyRouted; if (leftToRoute > 0) { return leftToRoute; } else { return 0; } - } + } public List getAvailableBatchAlgorithms() { return new ArrayList(batchAlgorithms.keySet()); } - - @Override - protected AbstractSqlMap createSqlMap() { - return new RouterServiceSqlMap(symmetricDialect.getPlatform(), - createReplacementTokens()); - } - public void setConfigurationService(IConfigurationService configurationService) { - this.configurationService = configurationService; - } - - public void setOutgoingBatchService(IOutgoingBatchService outgoingBatchService) { - this.outgoingBatchService = outgoingBatchService; - } - - public void setClusterService(IClusterService clusterService) { - this.clusterService = clusterService; - } - - public void setNodeService(INodeService nodeService) { - this.nodeService = nodeService; - } - - public void setDataService(IDataService dataService) { - this.dataService = dataService; - } - - public void setRouters(Map routers) { - this.routers = routers; - } - - public void setBatchAlgorithms(Map batchAlgorithms) { - this.batchAlgorithms = batchAlgorithms; - } - - public void setTriggerRouterService(ITriggerRouterService triggerService) { - this.triggerRouterService = triggerService; - } - - public void setDataToRouteReaderFactory(DataToRouteReaderFactory dataToRouteReaderFactory) { - this.dataToRouteReaderFactory = dataToRouteReaderFactory; + public Map getRouters() { + return routers; } - public void setStatisticManager(IStatisticManager statisticManager) { - this.statisticManager = statisticManager; + @Override + protected AbstractSqlMap createSqlMap() { + return new RouterServiceSqlMap(symmetricDialect.getPlatform(), createSqlReplacementTokens()); } } \ No newline at end of file diff --git a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/impl/SecurityService.java b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/impl/SecurityService.java index 5dbe66d219..2f6ca5ac8b 100644 --- a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/impl/SecurityService.java +++ b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/impl/SecurityService.java @@ -35,13 +35,20 @@ import org.apache.commons.codec.binary.Base64; import org.apache.commons.math.random.RandomDataImpl; -import org.jumpmind.db.sql.AbstractSqlMap; +import org.jumpmind.log.Log; +import org.jumpmind.log.LogFactory; import org.jumpmind.symmetric.common.SecurityConstants; import org.jumpmind.symmetric.service.ISecurityService; -public class SecurityService extends AbstractService implements ISecurityService { - - private SecretKey secretKey; +public class SecurityService implements ISecurityService { + + protected Log log = LogFactory.getLog(getClass()); + + private SecretKey secretKey; + + public SecurityService() { + + } public String encrypt(String plainText) { try { @@ -90,7 +97,7 @@ private SecretKey getSecretKey() throws Exception { KeyStore.SecretKeyEntry entry = (KeyStore.SecretKeyEntry) ks.getEntry(SecurityConstants.ALIAS_SYM_SECRET_KEY, param); if (entry == null) { - log.debug("SecretKeyGenerating"); + log.debug("Generating secret key"); String keyPassword = new RandomDataImpl().nextSecureHexString(16); KeySpec keySpec = new PBEKeySpec(keyPassword.toCharArray(), SecurityConstants.SALT, SecurityConstants.ITERATION_COUNT); @@ -99,7 +106,7 @@ private SecretKey getSecretKey() throws Exception { ks.setEntry(SecurityConstants.ALIAS_SYM_SECRET_KEY, entry, param); saveKeyStore(ks, password); } else { - log.debug("SecretKeyRetrieving"); + log.debug("Retrieving secret key"); } return entry.getSecretKey(); } @@ -116,11 +123,6 @@ protected void saveKeyStore(KeyStore ks, String password) throws Exception { FileOutputStream os = new FileOutputStream(System.getProperty(SecurityConstants.SYSPROP_KEYSTORE)); ks.store(os, password.toCharArray()); os.close(); - } - - @Override - protected AbstractSqlMap createSqlMap() { - return null; } } \ No newline at end of file diff --git a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/impl/StatisticService.java b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/impl/StatisticService.java index e70f8d6931..51e340ffd8 100644 --- a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/impl/StatisticService.java +++ b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/impl/StatisticService.java @@ -20,8 +20,6 @@ */ package org.jumpmind.symmetric.service.impl; -import java.sql.ResultSet; -import java.sql.SQLException; import java.sql.Types; import java.util.Calendar; import java.util.Date; @@ -30,21 +28,28 @@ import java.util.TreeMap; import org.jumpmind.db.sql.AbstractSqlMap; +import org.jumpmind.db.sql.ISqlRowMapper; +import org.jumpmind.db.sql.Row; +import org.jumpmind.symmetric.db.ISymmetricDialect; +import org.jumpmind.symmetric.service.IParameterService; import org.jumpmind.symmetric.service.IStatisticService; import org.jumpmind.symmetric.statistic.ChannelStats; import org.jumpmind.symmetric.statistic.ChannelStatsByPeriodMap; import org.jumpmind.symmetric.statistic.HostStats; import org.jumpmind.symmetric.statistic.HostStatsByPeriodMap; import org.jumpmind.symmetric.statistic.JobStats; -import org.springframework.jdbc.core.RowMapper; /** * @see IStatisticService */ public class StatisticService extends AbstractService implements IStatisticService { + + public StatisticService(IParameterService parameterService, ISymmetricDialect dialect) { + super(parameterService, dialect); + } public void save(ChannelStats stats) { - jdbcTemplate.update( + sqlTemplate.update( getSql("insertChannelStatsSql"), new Object[] { stats.getNodeId(), stats.getHostName(), stats.getChannelId(), stats.getStartTime(), stats.getEndTime(), stats.getDataRouted(), @@ -60,7 +65,7 @@ public void save(ChannelStats stats) { } public void save(JobStats stats) { - jdbcTemplate.update( + sqlTemplate.update( getSql("insertJobStatsSql"), new Object[] { stats.getNodeId(), stats.getHostName(), stats.getJobName(), stats.getStartTime(), stats.getEndTime(), stats.getProcessedCount() }, new int[] { @@ -70,19 +75,19 @@ public void save(JobStats stats) { public List getJobStatsForPeriod(Date start, Date end, String nodeId) { - return jdbcTemplate.query(getSql("selectChannelStatsSql"), + return sqlTemplate.query(getSql("selectChannelStatsSql"), new JobStatsMapper(), start, end, nodeId); } public TreeMap> getChannelStatsForPeriod(Date start, Date end, String nodeId, int periodSizeInMinutes) { - List list = jdbcTemplate.query(getSql("selectChannelStatsSql"), + List list = sqlTemplate.query(getSql("selectChannelStatsSql"), new ChannelStatsMapper(), start, end, nodeId); return new ChannelStatsByPeriodMap(start, end, list, periodSizeInMinutes); } public void save(HostStats stats) { - jdbcTemplate.update( + sqlTemplate.update( getSql("insertHostStatsSql"), new Object[] { stats.getNodeId(), stats.getHostName(), stats.getStartTime(), stats.getEndTime(), stats.getRestarted(), stats.getNodesPulled(), @@ -103,7 +108,7 @@ public void save(HostStats stats) { public TreeMap getHostStatsForPeriod(Date start, Date end, String nodeId, int periodSizeInMinutes) { - List list = jdbcTemplate.query(getSql("selectHostStatsSql"), + List list = sqlTemplate.query(getSql("selectHostStatsSql"), new HostStatsMapper(), start, end, nodeId); return new HostStatsByPeriodMap(start, end, list, periodSizeInMinutes); } @@ -119,69 +124,69 @@ public Date truncateToMinutes(Date date) { @Override protected AbstractSqlMap createSqlMap() { return new StatisticServiceSqlMap(symmetricDialect.getPlatform(), - createReplacementTokens()); + createSqlReplacementTokens()); } - class JobStatsMapper implements RowMapper { - public JobStats mapRow(ResultSet rs, int rowNum) throws SQLException { + class JobStatsMapper implements ISqlRowMapper { + public JobStats mapRow(Row rs) { JobStats stats = new JobStats(); - stats.setNodeId(rs.getString(1)); - stats.setHostName(rs.getString(2)); - stats.setJobName(rs.getString(3)); - stats.setStartTime(truncateToMinutes(rs.getTimestamp(4))); - stats.setEndTime(truncateToMinutes(rs.getTimestamp(5))); - stats.setProcessedCount(rs.getLong(6)); + stats.setNodeId(rs.getString("node_id")); + stats.setHostName(rs.getString("host_name")); + stats.setJobName(rs.getString("job_name")); + stats.setStartTime(truncateToMinutes(rs.getDateTime("start_time"))); + stats.setEndTime(truncateToMinutes(rs.getDateTime("end_time"))); + stats.setProcessedCount(rs.getLong("processed_count")); return stats; } } - class ChannelStatsMapper implements RowMapper { - public ChannelStats mapRow(ResultSet rs, int rowNum) throws SQLException { + class ChannelStatsMapper implements ISqlRowMapper { + public ChannelStats mapRow(Row rs) { ChannelStats stats = new ChannelStats(); - stats.setNodeId(rs.getString(1)); - stats.setHostName(rs.getString(2)); - stats.setChannelId(rs.getString(3)); - stats.setStartTime(truncateToMinutes(rs.getTimestamp(4))); - stats.setEndTime(truncateToMinutes(rs.getTimestamp(5))); - stats.setDataRouted(rs.getLong(6)); - stats.setDataUnRouted(rs.getLong(7)); - stats.setDataEventInserted(rs.getLong(8)); - stats.setDataExtracted(rs.getLong(9)); - stats.setDataBytesExtracted(rs.getLong(10)); - stats.setDataExtractedErrors(rs.getLong(11)); - stats.setDataSent(rs.getLong(12)); - stats.setDataBytesSent(rs.getLong(13)); - stats.setDataSentErrors(rs.getLong(14)); - stats.setDataLoaded(rs.getLong(15)); - stats.setDataBytesLoaded(rs.getLong(16)); - stats.setDataLoadedErrors(rs.getLong(17)); + stats.setNodeId(rs.getString("node_id")); + stats.setHostName(rs.getString("host_name")); + stats.setChannelId(rs.getString("channel_id")); + stats.setStartTime(truncateToMinutes(rs.getDateTime("start_time"))); + stats.setEndTime(truncateToMinutes(rs.getDateTime("end_time"))); + stats.setDataRouted(rs.getLong("data_routed")); + stats.setDataUnRouted(rs.getLong("data_unrouted")); + stats.setDataEventInserted(rs.getLong("data_event_inserted")); + stats.setDataExtracted(rs.getLong("data_extracted")); + stats.setDataBytesExtracted(rs.getLong("data_bytes_extracted")); + stats.setDataExtractedErrors(rs.getLong("data_extracted_errors")); + stats.setDataSent(rs.getLong("data_sent")); + stats.setDataBytesSent(rs.getLong("data_bytes_sent")); + stats.setDataSentErrors(rs.getLong("data_sent_errors")); + stats.setDataLoaded(rs.getLong("data_loaded")); + stats.setDataBytesLoaded(rs.getLong("data_bytes_loaded")); + stats.setDataLoadedErrors(rs.getLong("data_loaded_errors")); return stats; } } - class HostStatsMapper implements RowMapper { - public HostStats mapRow(ResultSet rs, int rowNum) throws SQLException { + class HostStatsMapper implements ISqlRowMapper { + public HostStats mapRow(Row rs) { HostStats stats = new HostStats(); - stats.setNodeId(rs.getString(1)); - stats.setHostName(rs.getString(2)); - stats.setStartTime(truncateToMinutes(rs.getTimestamp(3))); - stats.setEndTime(truncateToMinutes(rs.getTimestamp(4))); - stats.setRestarted(rs.getLong(5)); - stats.setNodesPulled(rs.getLong(6)); - stats.setNodesPushed(rs.getLong(7)); - stats.setNodesRejected(rs.getLong(8)); - stats.setNodesRegistered(rs.getLong(9)); - stats.setNodesLoaded(rs.getLong(10)); - stats.setNodesDisabled(rs.getLong(11)); - stats.setPurgedDataRows(rs.getLong(12)); - stats.setPurgedDataEventRows(rs.getLong(13)); - stats.setPurgedBatchOutgoingRows(rs.getLong(14)); - stats.setPurgedBatchIncomingRows(rs.getLong(15)); - stats.setTriggersCreatedCount(rs.getLong(16)); - stats.setTriggersRebuiltCount(rs.getLong(17)); - stats.setTriggersRemovedCount(rs.getLong(18)); - stats.setTotalNodesPullTime(rs.getLong(19)); - stats.setTotalNodesPushTime(rs.getLong(20)); + stats.setNodeId(rs.getString("node_id")); + stats.setHostName(rs.getString("host_name")); + stats.setStartTime(truncateToMinutes(rs.getDateTime("start_time"))); + stats.setEndTime(truncateToMinutes(rs.getDateTime("end_time"))); + stats.setRestarted(rs.getLong("restarted")); + stats.setNodesPulled(rs.getLong("nodes_pulled")); + stats.setNodesPushed(rs.getLong("nodes_pushed")); + stats.setNodesRejected(rs.getLong("nodes_rejected")); + stats.setNodesRegistered(rs.getLong("nodes_registered")); + stats.setNodesLoaded(rs.getLong("nodes_loaded")); + stats.setNodesDisabled(rs.getLong("nodes_disabled")); + stats.setPurgedDataRows(rs.getLong("purged_data_rows")); + stats.setPurgedDataEventRows(rs.getLong("purged_data_event_rows")); + stats.setPurgedBatchOutgoingRows(rs.getLong("purged_batch_outgoing_rows")); + stats.setPurgedBatchIncomingRows(rs.getLong("purged_batch_incoming_rows")); + stats.setTriggersCreatedCount(rs.getLong("triggers_created_count")); + stats.setTriggersRebuiltCount(rs.getLong("triggers_rebuilt_count")); + stats.setTriggersRemovedCount(rs.getLong("triggers_removed_count")); + stats.setTotalNodesPullTime(rs.getLong("total_nodes_pull_time")); + stats.setTotalNodesPushTime(rs.getLong("total_nodes_push_time")); return stats; } } diff --git a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/impl/TransformService.java b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/impl/TransformService.java index 76d4207cee..c2d201f5fe 100644 --- a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/impl/TransformService.java +++ b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/impl/TransformService.java @@ -1,36 +1,41 @@ package org.jumpmind.symmetric.service.impl; -import java.sql.ResultSet; -import java.sql.SQLException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import org.jumpmind.db.sql.AbstractSqlMap; +import org.jumpmind.db.sql.ISqlRowMapper; +import org.jumpmind.db.sql.ISqlTransaction; +import org.jumpmind.db.sql.Row; import org.jumpmind.symmetric.common.ParameterConstants; +import org.jumpmind.symmetric.db.ISymmetricDialect; import org.jumpmind.symmetric.io.data.transform.DeleteAction; import org.jumpmind.symmetric.io.data.transform.TransformColumn; import org.jumpmind.symmetric.io.data.transform.TransformColumn.IncludeOnType; import org.jumpmind.symmetric.io.data.transform.TransformPoint; import org.jumpmind.symmetric.io.data.transform.TransformTable; import org.jumpmind.symmetric.model.NodeGroupLink; +import org.jumpmind.symmetric.service.IParameterService; import org.jumpmind.symmetric.service.ITransformService; -import org.springframework.jdbc.core.RowMapper; -import org.springframework.transaction.annotation.Transactional; public class TransformService extends AbstractService implements ITransformService { private Map>> transformsCacheByNodeGroupLinkByTransformPoint; private long lastCacheTimeInMs; - + + public TransformService(IParameterService parameterService, ISymmetricDialect symmetricDialect) { + super(parameterService, symmetricDialect); + } + @Override protected AbstractSqlMap createSqlMap() { return new TransformServiceSqlMap(symmetricDialect.getPlatform(), - createReplacementTokens()); + createSqlReplacementTokens()); } - + public List findTransformsFor(NodeGroupLink nodeGroupLink, TransformPoint transformPoint, boolean useCache) { @@ -102,7 +107,7 @@ protected void refreshCache() { } private List getTransformTablesFromDB() { - List transforms = jdbcTemplate.query( + List transforms = sqlTemplate.query( getSql("selectTransformTable"), new TransformTableMapper()); List columns = getTransformColumnsFromDB(); for (TransformTableNodeGroupLink transformTable : transforms) { @@ -117,7 +122,7 @@ private List getTransformTablesFromDB() { } private List getTransformColumnsFromDB() { - List columns = jdbcTemplate.query(getSql("selectTransformColumn"), + List columns = sqlTemplate.query(getSql("selectTransformColumn"), new TransformColumnMapper()); return columns; } @@ -131,57 +136,71 @@ public List getTransformColumns() { } public List getTransformColumnsForTable() { - List columns = jdbcTemplate.query(getSql("selectTransformColumnForTable"), + List columns = sqlTemplate.query(getSql("selectTransformColumnForTable"), new TransformColumnMapper()); return columns; } - @Transactional public void saveTransformTable(TransformTableNodeGroupLink transformTable) { - if (jdbcTemplate.update(getSql("updateTransformTableSql"), transformTable - .getNodeGroupLink().getSourceNodeGroupId(), transformTable.getNodeGroupLink() - .getTargetNodeGroupId(), transformTable.getSourceCatalogName(), transformTable - .getSourceSchemaName(), transformTable.getSourceTableName(), transformTable - .getTargetCatalogName(), transformTable.getTargetSchemaName(), transformTable - .getTargetTableName(), transformTable.getTransformPoint().toString(), - transformTable.isUpdateFirst(), transformTable.getDeleteAction().toString(), - transformTable.getTransformOrder(), transformTable.getTransformId()) == 0) { - jdbcTemplate.update(getSql("insertTransformTableSql"), transformTable + ISqlTransaction transaction = null; + try { + transaction = sqlTemplate.startSqlTransaction(); + if (transaction.execute(getSql("updateTransformTableSql"), transformTable .getNodeGroupLink().getSourceNodeGroupId(), transformTable.getNodeGroupLink() .getTargetNodeGroupId(), transformTable.getSourceCatalogName(), transformTable .getSourceSchemaName(), transformTable.getSourceTableName(), transformTable .getTargetCatalogName(), transformTable.getTargetSchemaName(), transformTable .getTargetTableName(), transformTable.getTransformPoint().toString(), transformTable.isUpdateFirst(), transformTable.getDeleteAction().toString(), - transformTable.getTransformOrder(), transformTable.getTransformId()); - } - deleteTransformColumns(transformTable.getTransformId()); - List columns = transformTable.getTransformColumns(); - if (columns != null) { - for (TransformColumn transformColumn : columns) { - saveTransformColumn(transformColumn); + transformTable.getTransformOrder(), transformTable.getTransformId()) == 0) { + transaction.execute(getSql("insertTransformTableSql"), transformTable + .getNodeGroupLink().getSourceNodeGroupId(), transformTable + .getNodeGroupLink().getTargetNodeGroupId(), transformTable + .getSourceCatalogName(), transformTable.getSourceSchemaName(), + transformTable.getSourceTableName(), transformTable.getTargetCatalogName(), + transformTable.getTargetSchemaName(), transformTable.getTargetTableName(), + transformTable.getTransformPoint().toString(), transformTable + .isUpdateFirst(), transformTable.getDeleteAction().toString(), + transformTable.getTransformOrder(), transformTable.getTransformId()); } + deleteTransformColumns(transaction, transformTable.getTransformId()); + List columns = transformTable.getTransformColumns(); + if (columns != null) { + for (TransformColumn transformColumn : columns) { + saveTransformColumn(transaction, transformColumn); + } + } + transaction.commit(); + } finally { + close(transaction); } refreshCache(); } - public void deleteTransformColumns(String transformTableId) { - jdbcTemplate.update(getSql("deleteTransformColumnsSql"), transformTableId); + protected void deleteTransformColumns(ISqlTransaction transaction, String transformTableId) { + transaction.execute(getSql("deleteTransformColumnsSql"), (Object) transformTableId); } public void deleteTransformTable(String transformTableId) { - deleteTransformColumns(transformTableId); - jdbcTemplate.update(getSql("deleteTransformTableSql"), transformTableId); - refreshCache(); + ISqlTransaction transaction = null; + try { + transaction = sqlTemplate.startSqlTransaction(); + deleteTransformColumns(transaction, transformTableId); + transaction.execute(getSql("deleteTransformTableSql"), (Object) transformTableId); + refreshCache(); + transaction.commit(); + } finally { + close(transaction); + } } - public void saveTransformColumn(TransformColumn transformColumn) { - if (jdbcTemplate.update(getSql("updateTransformColumnSql"), + protected void saveTransformColumn(ISqlTransaction transaction, TransformColumn transformColumn) { + if (transaction.execute(getSql("updateTransformColumnSql"), transformColumn.getSourceColumnName(), transformColumn.isPk(), transformColumn.getTransformType(), transformColumn.getTransformExpression(), transformColumn.getTransformOrder(), transformColumn.getTransformId(), transformColumn.getIncludeOn().toDbValue(), transformColumn.getTargetColumnName()) == 0) { - jdbcTemplate.update(getSql("insertTransformColumnSql"), + transaction.execute(getSql("insertTransformColumnSql"), transformColumn.getTransformId(), transformColumn.getIncludeOn().toDbValue(), transformColumn.getTargetColumnName(), transformColumn.getSourceColumnName(), transformColumn.isPk(), transformColumn.getTransformType(), @@ -193,47 +212,48 @@ public void deleteTransformColumn(String transformTableId, Boolean includeOn, String targetColumnName) { String includeOnAsChar = null; - // TODO: is this a "Y" or "N" or "1" or "0" - if (includeOn) + if (includeOn) { includeOnAsChar = "Y"; - else + } else { includeOnAsChar = "N"; + } - jdbcTemplate.update(getSql("deleteTransformColumnSql"), transformTableId, includeOnAsChar, - targetColumnName); + sqlTemplate.update(getSql("deleteTransformColumnSql"), (Object) transformTableId, + includeOnAsChar, targetColumnName); refreshCache(); } - class TransformTableMapper implements RowMapper { - public TransformTableNodeGroupLink mapRow(ResultSet rs, int rowNum) throws SQLException { + class TransformTableMapper implements ISqlRowMapper { + public TransformTableNodeGroupLink mapRow(Row rs) { TransformTableNodeGroupLink table = new TransformTableNodeGroupLink(); - table.setTransformId(rs.getString(1)); - table.setNodeGroupLink(new NodeGroupLink(rs.getString(2), rs.getString(3))); - table.setSourceCatalogName(rs.getString(4)); - table.setSourceSchemaName(rs.getString(5)); - table.setSourceTableName(rs.getString(6)); - table.setTargetCatalogName(rs.getString(7)); - table.setTargetSchemaName(rs.getString(8)); - table.setTargetTableName(rs.getString(9)); - table.setTransformPoint(TransformPoint.valueOf(rs.getString(10))); - table.setTransformOrder(rs.getInt(11)); - table.setUpdateFirst(rs.getBoolean(12)); - table.setDeleteAction(DeleteAction.valueOf(rs.getString(13))); + table.setTransformId(rs.getString("transform_id")); + table.setNodeGroupLink(new NodeGroupLink(rs.getString("source_node_group_id"), rs + .getString("target_node_group_id"))); + table.setSourceCatalogName(rs.getString("source_catalog_name")); + table.setSourceSchemaName(rs.getString("source_schema_name")); + table.setSourceTableName(rs.getString("source_table_name")); + table.setTargetCatalogName(rs.getString("target_catalog_name")); + table.setTargetSchemaName(rs.getString("target_schema_name")); + table.setTargetTableName(rs.getString("target_table_name")); + table.setTransformPoint(TransformPoint.valueOf(rs.getString("transform_point"))); + table.setTransformOrder(rs.getInt("transform_order")); + table.setUpdateFirst(rs.getBoolean("update_first")); + table.setDeleteAction(DeleteAction.valueOf(rs.getString("delete_action"))); return table; } } - class TransformColumnMapper implements RowMapper { - public TransformColumn mapRow(ResultSet rs, int rowNum) throws SQLException { + class TransformColumnMapper implements ISqlRowMapper { + public TransformColumn mapRow(Row rs) { TransformColumn col = new TransformColumn(); - col.setTransformId(rs.getString(1)); - col.setIncludeOn(IncludeOnType.decode(rs.getString(2))); - col.setTargetColumnName(rs.getString(3)); - col.setSourceColumnName(rs.getString(4)); - col.setPk(rs.getBoolean(5)); - col.setTransformType(rs.getString(6)); - col.setTransformExpression(rs.getString(7)); - col.setTransformOrder(rs.getInt(8)); + col.setTransformId(rs.getString("transform_id")); + col.setIncludeOn(IncludeOnType.decode(rs.getString("include_on"))); + col.setTargetColumnName(rs.getString("target_column_name")); + col.setSourceColumnName(rs.getString("source_column_name")); + col.setPk(rs.getBoolean("pk")); + col.setTransformType(rs.getString("transform_type")); + col.setTransformExpression(rs.getString("transform_expression")); + col.setTransformOrder(rs.getInt("transform_order")); return col; } } diff --git a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/impl/TriggerRouterService.java b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/impl/TriggerRouterService.java index 5dc03644c5..6061b28fcb 100644 --- a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/impl/TriggerRouterService.java +++ b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/impl/TriggerRouterService.java @@ -16,9 +16,10 @@ * "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.jumpmind.symmetric.service.impl; - + * under the License. + */ +package org.jumpmind.symmetric.service.impl; + import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Types; @@ -35,6 +36,8 @@ import org.apache.commons.lang.StringUtils; import org.jumpmind.db.model.Table; import org.jumpmind.db.sql.AbstractSqlMap; +import org.jumpmind.db.sql.ISqlRowMapper; +import org.jumpmind.db.sql.Row; import org.jumpmind.symmetric.Version; import org.jumpmind.symmetric.common.Constants; import org.jumpmind.symmetric.common.Message; @@ -43,6 +46,7 @@ import org.jumpmind.symmetric.config.ITriggerCreationListener; import org.jumpmind.symmetric.config.TriggerFailureListener; import org.jumpmind.symmetric.config.TriggerSelector; +import org.jumpmind.symmetric.db.ISymmetricDialect; import org.jumpmind.symmetric.ext.IExtraConfigTables; import org.jumpmind.symmetric.io.data.DataEventType; import org.jumpmind.symmetric.model.Channel; @@ -56,79 +60,129 @@ import org.jumpmind.symmetric.service.ClusterConstants; import org.jumpmind.symmetric.service.IClusterService; import org.jumpmind.symmetric.service.IConfigurationService; +import org.jumpmind.symmetric.service.IParameterService; import org.jumpmind.symmetric.service.ITriggerRouterService; import org.jumpmind.symmetric.statistic.IStatisticManager; import org.springframework.dao.EmptyResultDataAccessException; import org.springframework.jdbc.core.RowMapper; - + /** * @see ITriggerRouterService */ -public class TriggerRouterService extends AbstractService implements ITriggerRouterService { - - private Map> rootConfigChannelTableNames; - - private IClusterService clusterService; - +public class TriggerRouterService extends AbstractService implements ITriggerRouterService { + + private Map> rootConfigChannelTableNames; + + private IClusterService clusterService; + private IConfigurationService configurationService; - - private Map routersCache; - - private Map triggerRouterCacheByNodeGroupId = new HashMap(); - + + private Map routersCache; + + private Map triggerRouterCacheByNodeGroupId = new HashMap(); + private long triggerRouterCacheTime; - - private long routersCacheTime; - - private List triggerCreationListeners; - + + private long routersCacheTime; + + private List triggerCreationListeners; + private TriggerFailureListener failureListener = new TriggerFailureListener(); - + private IStatisticManager statisticManager; - + private List extraConfigTables = new ArrayList(); - - /** - * Cache the history for performance. History never changes and does not - * grow big so this should be OK. - */ - private HashMap historyMap = new HashMap(); - - public TriggerRouterService() { - this.addTriggerCreationListeners(this.failureListener); - } - + + /** + * Cache the history for performance. History never changes and does not + * grow big so this should be OK. + */ + private HashMap historyMap = new HashMap(); + + public TriggerRouterService(IParameterService parameterService, + ISymmetricDialect symmetricDialect, IClusterService clusterService, + IConfigurationService configurationService, IStatisticManager statisticManager) { + super(parameterService, symmetricDialect); + this.clusterService = clusterService; + this.configurationService = configurationService; + this.statisticManager = statisticManager; + this.addTriggerCreationListeners(this.failureListener); + + String tablePrefix = parameterService.getTablePrefix(); + + rootConfigChannelTableNames = new HashMap>(2); + + List versionOne = new ArrayList(); + versionOne.add(TableConstants.getTableName(tablePrefix, TableConstants.SYM_NODE_GROUP)); + versionOne + .add(TableConstants.getTableName(tablePrefix, TableConstants.SYM_NODE_GROUP_LINK)); + versionOne.add(TableConstants.getTableName(tablePrefix, TableConstants.SYM_NODE)); + versionOne.add(TableConstants.getTableName(tablePrefix, TableConstants.SYM_NODE_SECURITY)); + versionOne.add(TableConstants.getTableName(tablePrefix, TableConstants.SYM_PARAMETER)); + versionOne.add(TableConstants.getTableName(tablePrefix, TableConstants.SYM_CHANNEL)); + versionOne.add(TableConstants + .getTableName(tablePrefix, TableConstants.SYM_NODE_CHANNEL_CTL)); + versionOne.add(TableConstants.getTableName(tablePrefix, TableConstants.SYM_TRIGGER)); + versionOne.add(TableConstants.getTableName(tablePrefix, TableConstants.SYM_NODE_IDENTITY)); + rootConfigChannelTableNames.put("1", versionOne); + + List versionTwo = new ArrayList(); + versionTwo.add(TableConstants.getTableName(tablePrefix, TableConstants.SYM_NODE_GROUP)); + versionTwo + .add(TableConstants.getTableName(tablePrefix, TableConstants.SYM_NODE_GROUP_LINK)); + versionTwo.add(TableConstants.getTableName(tablePrefix, TableConstants.SYM_NODE)); + versionTwo.add(TableConstants.getTableName(tablePrefix, TableConstants.SYM_NODE_SECURITY)); + versionTwo.add(TableConstants.getTableName(tablePrefix, TableConstants.SYM_PARAMETER)); + versionTwo.add(TableConstants.getTableName(tablePrefix, TableConstants.SYM_CHANNEL)); + versionTwo.add(TableConstants + .getTableName(tablePrefix, TableConstants.SYM_NODE_CHANNEL_CTL)); + versionTwo.add(TableConstants.getTableName(tablePrefix, + TableConstants.SYM_NODE_GROUP_CHANNEL_WINDOW)); + versionTwo.add(TableConstants.getTableName(tablePrefix, TableConstants.SYM_TRIGGER)); + versionTwo.add(TableConstants.getTableName(tablePrefix, TableConstants.SYM_ROUTER)); + versionTwo.add(TableConstants.getTableName(tablePrefix, TableConstants.SYM_TRIGGER_ROUTER)); + versionTwo + .add(TableConstants.getTableName(tablePrefix, TableConstants.SYM_TRANSFORM_TABLE)); + versionTwo.add(TableConstants + .getTableName(tablePrefix, TableConstants.SYM_TRANSFORM_COLUMN)); + versionTwo.add(TableConstants.getTableName(tablePrefix, TableConstants.SYM_NODE_IDENTITY)); + rootConfigChannelTableNames.put("2", versionOne); + + } + @Override protected AbstractSqlMap createSqlMap() { return new TriggerRouterServiceSqlMap(symmetricDialect.getPlatform(), - createReplacementTokens()); - } + createSqlReplacementTokens()); + } public List getTriggers() { - return jdbcTemplate.query("select " + getSql("selectTriggersColumnList", "selectTriggersSql"), new TriggerMapper()); + return sqlTemplate.query("select " + + getSql("selectTriggersColumnList", "selectTriggersSql"), new TriggerMapper()); } - + public boolean isTriggerBeingUsed(String triggerId) { - return jdbcTemplate.queryForInt(getSql("countTriggerRoutersByTriggerIdSql"), triggerId) > 0; + return sqlTemplate.queryForInt(getSql("countTriggerRoutersByTriggerIdSql"), triggerId) > 0; } - + public boolean doesTriggerExist(String triggerId) { - return jdbcTemplate.queryForInt(getSql("countTriggerByTriggerIdSql"), triggerId) > 0; + return sqlTemplate.queryForInt(getSql("countTriggerByTriggerIdSql"), triggerId) > 0; } - + public boolean doesTriggerExistForTable(String tableName) { - return jdbcTemplate.queryForInt(getSql("countTriggerByTableNameSql"), tableName) > 0; + return sqlTemplate.queryForInt(getSql("countTriggerByTableNameSql"), tableName) > 0; } - + public void deleteTrigger(Trigger trigger) { - jdbcTemplate.update(getSql("deleteTriggerSql"), trigger.getTriggerId()); + sqlTemplate.update(getSql("deleteTriggerSql"), (Object) trigger.getTriggerId()); } - + protected void deleteTriggerHistory(TriggerHistory history) { - jdbcTemplate.update(getSql("deleteTriggerHistorySql"), history.getTriggerHistoryId()); + sqlTemplate.update(getSql("deleteTriggerHistorySql"), history.getTriggerHistoryId()); } - - public void createTriggersOnChannelForTables(String channelId, String catalogName, String schemaName, List tables, String lastUpdateBy) { + + public void createTriggersOnChannelForTables(String channelId, String catalogName, + String schemaName, List tables, String lastUpdateBy) { for (String table : tables) { Trigger trigger = new Trigger(); trigger.setChannelId(channelId); @@ -142,8 +196,9 @@ public void createTriggersOnChannelForTables(String channelId, String catalogNam saveTrigger(trigger); } } - - public void createTriggersOnChannelForTables(String channelId, Set tables, String lastUpdateBy) { + + public void createTriggersOnChannelForTables(String channelId, Set
tables, + String lastUpdateBy) { for (Table table : tables) { Trigger trigger = new Trigger(); trigger.setChannelId(channelId); @@ -156,91 +211,91 @@ public void createTriggersOnChannelForTables(String channelId, Set
tables } } - - public void inactivateTriggerHistory(TriggerHistory history) { - jdbcTemplate.update(getSql("inactivateTriggerHistorySql"), new Object[] { history.getErrorMessage(), history - .getTriggerHistoryId() }); - } - - public Map getHistoryRecords() { - final Map retMap = new HashMap(); - jdbcTemplate.query(getSql("allTriggerHistSql"), new TriggerHistoryMapper(retMap)); - return retMap; - } - - protected boolean isTriggerNameInUse(String triggerId, String triggerName) { - return jdbcTemplate.queryForInt(getSql("selectTriggerNameInUseSql"), triggerName, - triggerName, triggerName, triggerId) > 0; - } - - public TriggerHistory findTriggerHistory(String sourceTableName) { - final Map retMap = new HashMap(); - jdbcTemplate.query(getSql("allTriggerHistSql","triggerHistBySourceTableWhereSql"), new Object[] { sourceTableName }, - new int[] { Types.VARCHAR }, new TriggerHistoryMapper(retMap)); - if (retMap.size() > 0) { - return retMap.values().iterator().next(); - } else { - return null; - } - } - - public TriggerHistory getTriggerHistory(int histId) { - TriggerHistory history = historyMap.get(histId); - if (history == null && histId >= 0) { - try { - history = (TriggerHistory) jdbcTemplate.queryForObject(getSql("triggerHistSql"), - new Object[] { histId }, new TriggerHistoryMapper()); - historyMap.put(histId, history); - } catch (EmptyResultDataAccessException ex) { - } - } - return history; - } - - public TriggerHistory getNewestTriggerHistoryForTrigger(String triggerId) { - try { - return (TriggerHistory) jdbcTemplate.queryForObject(getSql("latestTriggerHistSql"), - new Object[] { triggerId }, new TriggerHistoryMapper()); - } catch (EmptyResultDataAccessException ex) { - return null; - } - } - - /** - * Get a list of trigger histories that are currently active - */ - public List getActiveTriggerHistories() { - return jdbcTemplate.query(getSql("allTriggerHistSql", - "activeTriggerHistSql"), new TriggerHistoryMapper()); - } - - private String getNewestVersionOfRootConfigChannelTableNames() { - TreeSet ordered = new TreeSet(rootConfigChannelTableNames.keySet()); - return ordered.last(); - } - - private String getMajorVersion(String version) { - String majorVersion = Integer.toString(Version.parseVersion(version)[0]); - List tables = rootConfigChannelTableNames.get(majorVersion); - if (tables == null) { - String newestVersion = getNewestVersionOfRootConfigChannelTableNames(); - log.warn("TriggersDefaultVersionWarning", newestVersion, majorVersion); - majorVersion = newestVersion; - } - return majorVersion; - } - - public List getTriggerRoutersForRegistration(String version, - NodeGroupLink nodeGroupLink, String... tablesToExclude) { - int initialLoadOrder = 1; - String majorVersion = getMajorVersion(version); + public void inactivateTriggerHistory(TriggerHistory history) { + sqlTemplate.update(getSql("inactivateTriggerHistorySql"), + new Object[] { history.getErrorMessage(), history.getTriggerHistoryId() }); + } + + public Map getHistoryRecords() { + final Map retMap = new HashMap(); + sqlTemplate.query(getSql("allTriggerHistSql"), new TriggerHistoryMapper(retMap)); + return retMap; + } + + protected boolean isTriggerNameInUse(String triggerId, String triggerName) { + return sqlTemplate.queryForInt(getSql("selectTriggerNameInUseSql"), triggerName, + triggerName, triggerName, triggerId) > 0; + } + + public TriggerHistory findTriggerHistory(String sourceTableName) { + final Map retMap = new HashMap(); + sqlTemplate.query(getSql("allTriggerHistSql", "triggerHistBySourceTableWhereSql"), + new TriggerHistoryMapper(retMap), new Object[] { sourceTableName }, + new int[] { Types.VARCHAR }); + if (retMap.size() > 0) { + return retMap.values().iterator().next(); + } else { + return null; + } + } + + public TriggerHistory getTriggerHistory(int histId) { + TriggerHistory history = historyMap.get(histId); + if (history == null && histId >= 0) { + try { + history = (TriggerHistory) sqlTemplate.queryForObject(getSql("triggerHistSql"), + new TriggerHistoryMapper(), histId); + historyMap.put(histId, history); + } catch (EmptyResultDataAccessException ex) { + } + } + return history; + } + + public TriggerHistory getNewestTriggerHistoryForTrigger(String triggerId) { + try { + return (TriggerHistory) sqlTemplate.queryForObject(getSql("latestTriggerHistSql"), + new TriggerHistoryMapper(), triggerId); + } catch (EmptyResultDataAccessException ex) { + return null; + } + } + + /** + * Get a list of trigger histories that are currently active + */ + public List getActiveTriggerHistories() { + return sqlTemplate.query(getSql("allTriggerHistSql", "activeTriggerHistSql"), + new TriggerHistoryMapper()); + } + + private String getNewestVersionOfRootConfigChannelTableNames() { + TreeSet ordered = new TreeSet(rootConfigChannelTableNames.keySet()); + return ordered.last(); + } + + private String getMajorVersion(String version) { + String majorVersion = Integer.toString(Version.parseVersion(version)[0]); + List tables = rootConfigChannelTableNames.get(majorVersion); + if (tables == null) { + String newestVersion = getNewestVersionOfRootConfigChannelTableNames(); + log.warn("Defaulting to major version %s because %s version was not valid while retrieving trigger configuration tables", newestVersion, majorVersion); + majorVersion = newestVersion; + } + return majorVersion; + } + + public List getTriggerRoutersForRegistration(String version, + NodeGroupLink nodeGroupLink, String... tablesToExclude) { + int initialLoadOrder = 1; + String majorVersion = getMajorVersion(version); List tables = new ArrayList(rootConfigChannelTableNames.get(majorVersion)); if (extraConfigTables != null) { for (IExtraConfigTables extraTables : extraConfigTables) { tables.addAll(extraTables.provideTableNames()); } } - + if (tablesToExclude != null) { for (String tableToExclude : tablesToExclude) { String tablename = TableConstants.getTableName(tablePrefix, tableToExclude); @@ -251,167 +306,170 @@ public List getTriggerRoutersForRegistration(String version, } } } - - List triggers = new ArrayList(tables.size()); - for (int j = 0; j < tables.size(); j++) { - String tableName = tables.get(j); - boolean syncChanges = !TableConstants.getTablesThatDoNotSync(tablePrefix).contains( - tableName); - TriggerRouter trigger = buildRegistrationTriggerRouter(version, tableName, syncChanges, - nodeGroupLink); - trigger.setInitialLoadOrder(initialLoadOrder++); - if (tableName.equalsIgnoreCase(TableConstants.getTableName(tablePrefix, - TableConstants.SYM_TRIGGER))) { - trigger.getRouter().setRouterType("trigger"); - } - triggers.add(trigger); - } - return triggers; - } - - protected TriggerRouter buildRegistrationTriggerRouter(String version, String tableName, - boolean syncChanges, NodeGroupLink nodeGroupLink) { - boolean autoSyncConfig = parameterService.is(ParameterConstants.AUTO_SYNC_CONFIGURATION); - - TriggerRouter triggerRouter = new TriggerRouter(); - Trigger trigger = triggerRouter.getTrigger(); - trigger.setTriggerId(Integer.toString(Math.abs(tableName.hashCode()))); - trigger.setSyncOnDelete(syncChanges && autoSyncConfig); - trigger.setSyncOnInsert(syncChanges && autoSyncConfig); - trigger.setSyncOnUpdate(syncChanges && autoSyncConfig); - trigger.setSyncOnIncomingBatch(true); - trigger.setSourceTableName(tableName); - trigger.setChannelId(Constants.CHANNEL_CONFIG); - + + List triggers = new ArrayList(tables.size()); + for (int j = 0; j < tables.size(); j++) { + String tableName = tables.get(j); + boolean syncChanges = !TableConstants.getTablesThatDoNotSync(tablePrefix).contains( + tableName); + TriggerRouter trigger = buildRegistrationTriggerRouter(version, tableName, syncChanges, + nodeGroupLink); + trigger.setInitialLoadOrder(initialLoadOrder++); + if (tableName.equalsIgnoreCase(TableConstants.getTableName(tablePrefix, + TableConstants.SYM_TRIGGER))) { + trigger.getRouter().setRouterType("trigger"); + } + triggers.add(trigger); + } + return triggers; + } + + protected TriggerRouter buildRegistrationTriggerRouter(String version, String tableName, + boolean syncChanges, NodeGroupLink nodeGroupLink) { + boolean autoSyncConfig = parameterService.is(ParameterConstants.AUTO_SYNC_CONFIGURATION); + + TriggerRouter triggerRouter = new TriggerRouter(); + Trigger trigger = triggerRouter.getTrigger(); + trigger.setTriggerId(Integer.toString(Math.abs(tableName.hashCode()))); + trigger.setSyncOnDelete(syncChanges && autoSyncConfig); + trigger.setSyncOnInsert(syncChanges && autoSyncConfig); + trigger.setSyncOnUpdate(syncChanges && autoSyncConfig); + trigger.setSyncOnIncomingBatch(true); + trigger.setSourceTableName(tableName); + trigger.setChannelId(Constants.CHANNEL_CONFIG); + Router router = triggerRouter.getRouter(); - router.setRouterType("configurationChanged"); - router.setNodeGroupLink(nodeGroupLink); - - // little trick to force the rebuild of SymmetricDS triggers every time - // there is a new version of SymmetricDS - trigger.setLastUpdateTime(new Date(Version.version().hashCode())); + router.setRouterType("configurationChanged"); + router.setNodeGroupLink(nodeGroupLink); + + // little trick to force the rebuild of SymmetricDS triggers every time + // there is a new version of SymmetricDS + trigger.setLastUpdateTime(new Date(Version.version().hashCode())); router.setLastUpdateTime(trigger.getLastUpdateTime()); - - triggerRouter.setLastUpdateTime(trigger.getLastUpdateTime()); - - return triggerRouter; + + triggerRouter.setLastUpdateTime(trigger.getLastUpdateTime()); + + return triggerRouter; } - + private String getTriggerRouterSql() { return getTriggerRouterSql(null); } - - private String getTriggerRouterSql(String sql) { + + private String getTriggerRouterSql(String sql) { return getSql("select ", "selectTriggersColumnList", ",", "selectRoutersColumnList", ",", - "selectTriggerRoutersColumnList","selectTriggerRoutersSql", sql); + "selectTriggerRoutersColumnList", "selectTriggerRoutersSql", sql); } - + public List getTriggerRouters() { - return jdbcTemplate.query(getTriggerRouterSql(), new TriggerRouterMapper()); - } - - public Set getTriggerRouterForTableForCurrentNode(String catalogName, String schemaName, String tableName, boolean refreshCache) { - return getTriggerRouterForTableForCurrentNode(null, catalogName, schemaName, tableName, refreshCache); - } - - public Set getTriggerRouterForTableForCurrentNode(NodeGroupLink link, String catalogName, String schemaName, String tableName, boolean refreshCache) { - TriggerRoutersCache cache = getTriggerRoutersCacheForCurrentNode(refreshCache); + return sqlTemplate.query(getTriggerRouterSql(), new TriggerRouterMapper()); + } + + public Set getTriggerRouterForTableForCurrentNode(String catalogName, + String schemaName, String tableName, boolean refreshCache) { + return getTriggerRouterForTableForCurrentNode(null, catalogName, schemaName, tableName, + refreshCache); + } + + public Set getTriggerRouterForTableForCurrentNode(NodeGroupLink link, + String catalogName, String schemaName, String tableName, boolean refreshCache) { + TriggerRoutersCache cache = getTriggerRoutersCacheForCurrentNode(refreshCache); Collection> triggerRouters = cache.triggerRoutersByTriggerId.values(); - HashSet returnList = new HashSet(); - for (List list : triggerRouters) { - for (TriggerRouter triggerRouter : list) { - if (isMatch(link, triggerRouter) && - isMatch(catalogName, schemaName, tableName, triggerRouter.getTrigger())) { - returnList.add(triggerRouter); - } - } - } - return returnList; - } - - protected boolean isMatch(NodeGroupLink link, TriggerRouter router) { - if (link != null && router != null && router.getRouter() != null) { - return link.getSourceNodeGroupId().equals(router.getRouter().getNodeGroupLink().getSourceNodeGroupId()) - && link.getTargetNodeGroupId().equals(router.getRouter().getNodeGroupLink().getTargetNodeGroupId()); - } else { - return true; - } - } - - protected boolean isMatch(String catalogName, String schemaName, String tableName, - Trigger trigger) { - if (!StringUtils.isBlank(tableName) && !tableName.equals(trigger.getSourceTableName())) { - return false; - } else if (StringUtils.isBlank(tableName) - && !StringUtils.isBlank(trigger.getSourceTableName())) { - return false; - } else if (!StringUtils.isBlank(catalogName) - && !catalogName.equals(trigger.getSourceCatalogName())) { - return false; - } else if (StringUtils.isBlank(catalogName) - && !StringUtils.isBlank(trigger.getSourceCatalogName())) { - return false; - } else if (!StringUtils.isBlank(schemaName) - && !schemaName.equals(trigger.getSourceSchemaName())) { - return false; - } else if (StringUtils.isBlank(schemaName) - && !StringUtils.isBlank(trigger.getSourceSchemaName())) { - return false; - } else { - return true; - } - } - - - /** - * Create a list of {@link TriggerRouter} for the SymmetricDS tables that - * should have triggers created for them on the current node. - */ - protected List getConfigurationTablesTriggerRoutersForCurrentNode( - String sourceNodeGroupId) { - List triggers = new ArrayList(); - List links = configurationService.getNodeGroupLinksFor(sourceNodeGroupId); + HashSet returnList = new HashSet(); + for (List list : triggerRouters) { + for (TriggerRouter triggerRouter : list) { + if (isMatch(link, triggerRouter) + && isMatch(catalogName, schemaName, tableName, triggerRouter.getTrigger())) { + returnList.add(triggerRouter); + } + } + } + return returnList; + } + + protected boolean isMatch(NodeGroupLink link, TriggerRouter router) { + if (link != null && router != null && router.getRouter() != null) { + return link.getSourceNodeGroupId().equals( + router.getRouter().getNodeGroupLink().getSourceNodeGroupId()) + && link.getTargetNodeGroupId().equals( + router.getRouter().getNodeGroupLink().getTargetNodeGroupId()); + } else { + return true; + } + } + + protected boolean isMatch(String catalogName, String schemaName, String tableName, + Trigger trigger) { + if (!StringUtils.isBlank(tableName) && !tableName.equals(trigger.getSourceTableName())) { + return false; + } else if (StringUtils.isBlank(tableName) + && !StringUtils.isBlank(trigger.getSourceTableName())) { + return false; + } else if (!StringUtils.isBlank(catalogName) + && !catalogName.equals(trigger.getSourceCatalogName())) { + return false; + } else if (StringUtils.isBlank(catalogName) + && !StringUtils.isBlank(trigger.getSourceCatalogName())) { + return false; + } else if (!StringUtils.isBlank(schemaName) + && !schemaName.equals(trigger.getSourceSchemaName())) { + return false; + } else if (StringUtils.isBlank(schemaName) + && !StringUtils.isBlank(trigger.getSourceSchemaName())) { + return false; + } else { + return true; + } + } + + /** + * Create a list of {@link TriggerRouter} for the SymmetricDS tables that + * should have triggers created for them on the current node. + */ + protected List getConfigurationTablesTriggerRoutersForCurrentNode( + String sourceNodeGroupId) { + List triggers = new ArrayList(); + List links = configurationService.getNodeGroupLinksFor(sourceNodeGroupId); for (NodeGroupLink nodeGroupLink : links) { - triggers.addAll(getTriggerRoutersForRegistration(Version.version(), nodeGroupLink)); - if (NodeGroupLinkAction.P == nodeGroupLink.getDataEventAction()) { - triggers - .add(buildRegistrationTriggerRouter(Version.version(), TableConstants - .getTableName(tablePrefix, TableConstants.SYM_NODE_HOST), true, - nodeGroupLink)); - log.debug("TriggerHistCreating", TableConstants.getTableName(tablePrefix, - TableConstants.SYM_NODE_HOST)); - - } - } - return triggers; - } - - protected void mergeInConfigurationTablesTriggerRoutersForCurrentNode(String sourceNodeGroupId, - List configuredInDatabase) { - List virtualConfigTriggers = getConfigurationTablesTriggerRoutersForCurrentNode(sourceNodeGroupId); - for (TriggerRouter trigger : virtualConfigTriggers) { - if (trigger.getRouter().getNodeGroupLink().getSourceNodeGroupId().equalsIgnoreCase(sourceNodeGroupId) - && !doesTriggerRouterExistInList(configuredInDatabase, trigger)) { - configuredInDatabase.add(trigger); - } - } - } - - protected boolean doesTriggerRouterExistInList(List triggerRouters, - TriggerRouter triggerRouter) { - for (TriggerRouter checkMe : triggerRouters) { - if (checkMe.isSame(triggerRouter)) { - return true; - } - } - return false; - } - - public Map> getTriggerRoutersForCurrentNode( - boolean refreshCache) { - return getTriggerRoutersCacheForCurrentNode(refreshCache).triggerRoutersByTriggerId; - } - + triggers.addAll(getTriggerRoutersForRegistration(Version.version(), nodeGroupLink)); + if (NodeGroupLinkAction.P == nodeGroupLink.getDataEventAction()) { + triggers.add(buildRegistrationTriggerRouter(Version.version(), + TableConstants.getTableName(tablePrefix, TableConstants.SYM_NODE_HOST), + true, nodeGroupLink)); + log.debug("Creating trigger hist entry for %s", + TableConstants.getTableName(tablePrefix, TableConstants.SYM_NODE_HOST)); + + } + } + return triggers; + } + + protected void mergeInConfigurationTablesTriggerRoutersForCurrentNode(String sourceNodeGroupId, + List configuredInDatabase) { + List virtualConfigTriggers = getConfigurationTablesTriggerRoutersForCurrentNode(sourceNodeGroupId); + for (TriggerRouter trigger : virtualConfigTriggers) { + if (trigger.getRouter().getNodeGroupLink().getSourceNodeGroupId() + .equalsIgnoreCase(sourceNodeGroupId) + && !doesTriggerRouterExistInList(configuredInDatabase, trigger)) { + configuredInDatabase.add(trigger); + } + } + } + + protected boolean doesTriggerRouterExistInList(List triggerRouters, + TriggerRouter triggerRouter) { + for (TriggerRouter checkMe : triggerRouters) { + if (checkMe.isSame(triggerRouter)) { + return true; + } + } + return false; + } + + public Map> getTriggerRoutersForCurrentNode(boolean refreshCache) { + return getTriggerRoutersCacheForCurrentNode(refreshCache).triggerRoutersByTriggerId; + } + public List getTriggersForCurrentNode(boolean refreshCache) { Map> triggerRouters = getTriggerRoutersForCurrentNode(refreshCache); List triggers = new ArrayList(triggerRouters.size()); @@ -421,63 +479,66 @@ public List getTriggersForCurrentNode(boolean refreshCache) { } } return triggers; - } - - protected TriggerRoutersCache getTriggerRoutersCacheForCurrentNode( - boolean refreshCache) { - String myNodeGroupId = parameterService.getNodeGroupId(); - long triggerRouterCacheTimeoutInMs = parameterService.getLong(ParameterConstants.CACHE_TIMEOUT_TRIGGER_ROUTER_IN_MS); - TriggerRoutersCache cache = triggerRouterCacheByNodeGroupId == null ? null : triggerRouterCacheByNodeGroupId.get(myNodeGroupId); - if (cache == null || - refreshCache || - System.currentTimeMillis()-this.triggerRouterCacheTime > triggerRouterCacheTimeoutInMs) { + } + + protected TriggerRoutersCache getTriggerRoutersCacheForCurrentNode(boolean refreshCache) { + String myNodeGroupId = parameterService.getNodeGroupId(); + long triggerRouterCacheTimeoutInMs = parameterService + .getLong(ParameterConstants.CACHE_TIMEOUT_TRIGGER_ROUTER_IN_MS); + TriggerRoutersCache cache = triggerRouterCacheByNodeGroupId == null ? null + : triggerRouterCacheByNodeGroupId.get(myNodeGroupId); + if (cache == null + || refreshCache + || System.currentTimeMillis() - this.triggerRouterCacheTime > triggerRouterCacheTimeoutInMs) { synchronized (this) { this.triggerRouterCacheTime = System.currentTimeMillis(); - Map newTriggerRouterCacheByNodeGroupId = new HashMap(); - List triggerRouters = getAllTriggerRoutersForCurrentNode(myNodeGroupId); - Map> triggerRoutersByTriggerId = new HashMap>( - triggerRouters.size()); - Map routers = new HashMap(triggerRouters.size()); - for (TriggerRouter triggerRouter : triggerRouters) { - String triggerId = triggerRouter.getTrigger().getTriggerId(); - List list = triggerRoutersByTriggerId.get(triggerId); - if (list == null) { - list = new ArrayList(); - triggerRoutersByTriggerId.put(triggerId, list); - } - list.add(triggerRouter); - routers.put(triggerRouter.getRouter().getRouterId(), triggerRouter.getRouter()); - } - - newTriggerRouterCacheByNodeGroupId.put(myNodeGroupId, new TriggerRoutersCache( + Map newTriggerRouterCacheByNodeGroupId = new HashMap(); + List triggerRouters = getAllTriggerRoutersForCurrentNode(myNodeGroupId); + Map> triggerRoutersByTriggerId = new HashMap>( + triggerRouters.size()); + Map routers = new HashMap(triggerRouters.size()); + for (TriggerRouter triggerRouter : triggerRouters) { + String triggerId = triggerRouter.getTrigger().getTriggerId(); + List list = triggerRoutersByTriggerId.get(triggerId); + if (list == null) { + list = new ArrayList(); + triggerRoutersByTriggerId.put(triggerId, list); + } + list.add(triggerRouter); + routers.put(triggerRouter.getRouter().getRouterId(), triggerRouter.getRouter()); + } + + newTriggerRouterCacheByNodeGroupId.put(myNodeGroupId, new TriggerRoutersCache( triggerRoutersByTriggerId, routers)); this.triggerRouterCacheByNodeGroupId = newTriggerRouterCacheByNodeGroupId; - cache = triggerRouterCacheByNodeGroupId == null ? null : triggerRouterCacheByNodeGroupId.get(myNodeGroupId); - } - } - return cache; - } - - /** - * @see ITriggerRouterService#getActiveRouterByIdForCurrentNode(String, boolean) - */ - public Router getActiveRouterByIdForCurrentNode(String routerId, boolean refreshCache) { - return getTriggerRoutersCacheForCurrentNode(refreshCache).routersByRouterId - .get(routerId); - } - + cache = triggerRouterCacheByNodeGroupId == null ? null + : triggerRouterCacheByNodeGroupId.get(myNodeGroupId); + } + } + return cache; + } + + /** + * @see ITriggerRouterService#getActiveRouterByIdForCurrentNode(String, + * boolean) + */ + public Router getActiveRouterByIdForCurrentNode(String routerId, boolean refreshCache) { + return getTriggerRoutersCacheForCurrentNode(refreshCache).routersByRouterId.get(routerId); + } + /** * @see ITriggerRouterService#getRoutersByGroupLink(NodeGroupLink) */ public List getRoutersByGroupLink(NodeGroupLink link) { - return jdbcTemplate.query(getSql("select","selectRoutersColumnList", - "selectRouterByNodeGroupLinkWhereSql"), new RouterMapper(), link.getSourceNodeGroupId(), link.getTargetNodeGroupId()); + return sqlTemplate.query( + getSql("select", "selectRoutersColumnList", "selectRouterByNodeGroupLinkWhereSql"), + new RouterMapper(), link.getSourceNodeGroupId(), link.getTargetNodeGroupId()); } - + public Router getRouterById(String routerId) { return getRouterById(routerId, true); - } - + } + public Router getRouterById(String routerId, boolean refreshCache) { final long routerCacheTimeoutInMs = parameterService .getLong(ParameterConstants.CACHE_TIMEOUT_TRIGGER_ROUTER_IN_MS); @@ -496,214 +557,228 @@ public Router getRouterById(String routerId, boolean refreshCache) { } return cache.get(routerId); } - + public List getRouters() { - return jdbcTemplate.query(getSql("select ", "selectRoutersColumnList", "selectRoutersSql"), + return sqlTemplate.query(getSql("select ", "selectRoutersColumnList", "selectRoutersSql"), new RouterMapper()); - } - - public List getAllTriggerRoutersForCurrentNode(String sourceNodeGroupId) { - List triggers = (List) jdbcTemplate.query( - getTriggerRouterSql("activeTriggersForSourceNodeGroupSql"), - new Object[] { sourceNodeGroupId }, new TriggerRouterMapper()); - mergeInConfigurationTablesTriggerRoutersForCurrentNode(sourceNodeGroupId, triggers); - return triggers; - } - - public List getAllTriggerRoutersForReloadForCurrentNode( - String sourceNodeGroupId, String targetNodeGroupId) { - return (List) jdbcTemplate.query(getTriggerRouterSql("activeTriggersForReloadSql"), new Object[] { sourceNodeGroupId, - targetNodeGroupId, Constants.CHANNEL_CONFIG }, new TriggerRouterMapper()); - } - - public TriggerRouter findTriggerRouterById(String triggerId, String routerId) { - List configs = (List) jdbcTemplate.query( - getTriggerRouterSql("selectTriggerRouterSql"), new Object[] { - triggerId, routerId }, new TriggerRouterMapper()); - if (configs.size() > 0) { - return configs.get(0); - } else { - return null; - } - } - - public Trigger getTriggerById(String triggerId) { - List triggers = (List) jdbcTemplate.query( - getTriggerRouterSql("selectTriggerByIdSql"), - new Object[] { triggerId }, new TriggerRouterMapper()); - if (triggers.size() > 0) { - return triggers.get(0).getTrigger(); - } else { - return null; - } - } - - public Map> getTriggerRoutersByChannel(String nodeGroupId) { - final Map> retMap = new HashMap>(); - jdbcTemplate.query(getTriggerRouterSql("selectGroupTriggersSql"), - new Object[] { nodeGroupId }, new TriggerRouterMapper() { - public TriggerRouter mapRow(java.sql.ResultSet rs, int arg1) - throws java.sql.SQLException { - TriggerRouter config = (TriggerRouter) super.mapRow(rs, arg1); - List list = retMap.get(config.getTrigger().getChannelId()); - if (list == null) { - list = new ArrayList(); - retMap.put(config.getTrigger().getChannelId(), list); - } - list.add(config); - return config; - }; - }); - return retMap; - } - - public void insert(TriggerHistory newHistRecord) { - jdbcTemplate.update(getSql("insertTriggerHistorySql"), new Object[] { - newHistRecord.getTriggerId(), newHistRecord.getSourceTableName(), - newHistRecord.getTableHash(), newHistRecord.getCreateTime(), - newHistRecord.getColumnNames(), newHistRecord.getPkColumnNames(), - newHistRecord.getLastTriggerBuildReason().getCode(), - newHistRecord.getNameForDeleteTrigger(), newHistRecord.getNameForInsertTrigger(), - newHistRecord.getNameForUpdateTrigger(), newHistRecord.getSourceSchemaName(), - newHistRecord.getSourceCatalogName(), newHistRecord.getTriggerRowHash(), newHistRecord.getErrorMessage() }, - new int[] { Types.VARCHAR, Types.VARCHAR, Types.BIGINT, Types.TIMESTAMP, - Types.VARCHAR, Types.VARCHAR, Types.CHAR, Types.VARCHAR, Types.VARCHAR, - Types.VARCHAR, Types.VARCHAR, Types.VARCHAR, Types.BIGINT, Types.VARCHAR }); - } - + } + + public List getAllTriggerRoutersForCurrentNode(String sourceNodeGroupId) { + List triggers = (List) sqlTemplate.query( + getTriggerRouterSql("activeTriggersForSourceNodeGroupSql"), + new TriggerRouterMapper(), sourceNodeGroupId); + mergeInConfigurationTablesTriggerRoutersForCurrentNode(sourceNodeGroupId, triggers); + return triggers; + } + + public List getAllTriggerRoutersForReloadForCurrentNode( + String sourceNodeGroupId, String targetNodeGroupId) { + return (List) sqlTemplate.query( + getTriggerRouterSql("activeTriggersForReloadSql"), new TriggerRouterMapper(), + sourceNodeGroupId, targetNodeGroupId, Constants.CHANNEL_CONFIG); + } + + public TriggerRouter findTriggerRouterById(String triggerId, String routerId) { + List configs = (List) sqlTemplate.query( + getTriggerRouterSql("selectTriggerRouterSql"), new TriggerRouterMapper(), + triggerId, routerId); + if (configs.size() > 0) { + return configs.get(0); + } else { + return null; + } + } + + public Trigger getTriggerById(String triggerId) { + List triggers = (List) sqlTemplate.query( + getTriggerRouterSql("selectTriggerByIdSql"), new TriggerRouterMapper(), triggerId); + if (triggers.size() > 0) { + return triggers.get(0).getTrigger(); + } else { + return null; + } + } + + public Map> getTriggerRoutersByChannel(String nodeGroupId) { + final Map> retMap = new HashMap>(); + sqlTemplate.query(getTriggerRouterSql("selectGroupTriggersSql"), new TriggerRouterMapper() { + @Override + public TriggerRouter mapRow(Row rs) { + TriggerRouter tr = super.mapRow(rs); + List list = retMap.get(tr.getTrigger().getChannelId()); + if (list == null) { + list = new ArrayList(); + retMap.put(tr.getTrigger().getChannelId(), list); + } + list.add(tr); + return tr; + }; + }, nodeGroupId); + return retMap; + } + + public void insert(TriggerHistory newHistRecord) { + sqlTemplate.update( + getSql("insertTriggerHistorySql"), + new Object[] { newHistRecord.getTriggerId(), newHistRecord.getSourceTableName(), + newHistRecord.getTableHash(), newHistRecord.getCreateTime(), + newHistRecord.getColumnNames(), newHistRecord.getPkColumnNames(), + newHistRecord.getLastTriggerBuildReason().getCode(), + newHistRecord.getNameForDeleteTrigger(), + newHistRecord.getNameForInsertTrigger(), + newHistRecord.getNameForUpdateTrigger(), + newHistRecord.getSourceSchemaName(), newHistRecord.getSourceCatalogName(), + newHistRecord.getTriggerRowHash(), newHistRecord.getErrorMessage() }, + new int[] { Types.VARCHAR, Types.VARCHAR, Types.BIGINT, Types.TIMESTAMP, + Types.VARCHAR, Types.VARCHAR, Types.CHAR, Types.VARCHAR, Types.VARCHAR, + Types.VARCHAR, Types.VARCHAR, Types.VARCHAR, Types.BIGINT, Types.VARCHAR }); + } + public void deleteTriggerRouter(TriggerRouter triggerRouter) { - jdbcTemplate.update(getSql("deleteTriggerRouterSql"), triggerRouter.getTrigger().getTriggerId(), - triggerRouter.getRouter().getRouterId()); - } - + sqlTemplate.update(getSql("deleteTriggerRouterSql"), (Object)triggerRouter.getTrigger() + .getTriggerId(), triggerRouter.getRouter().getRouterId()); + } + public void saveTriggerRouter(TriggerRouter triggerRouter) { saveTriggerRouter(triggerRouter, false); } - + public void saveTriggerRouter(TriggerRouter triggerRouter, boolean updateTriggerRouterTableOnly) { - if (!updateTriggerRouterTableOnly) { - saveTrigger(triggerRouter.getTrigger()); + if (!updateTriggerRouterTableOnly) { + saveTrigger(triggerRouter.getTrigger()); saveRouter(triggerRouter.getRouter()); - } - triggerRouter.setLastUpdateTime(new Date()); - if (0 == jdbcTemplate.update(getSql("updateTriggerRouterSql"), - new Object[] { triggerRouter.getInitialLoadOrder(), - triggerRouter.getInitialLoadSelect(), - triggerRouter.isPingBackEnabled() ? 1 : 0, - triggerRouter.getLastUpdateBy(), - triggerRouter.getLastUpdateTime(), - triggerRouter.getTrigger().getTriggerId(), - triggerRouter.getRouter().getRouterId() }, - new int[] { Types.NUMERIC, Types.VARCHAR, Types.SMALLINT, Types.VARCHAR, Types.TIMESTAMP, - Types.VARCHAR, Types.VARCHAR })) { - triggerRouter.setCreateTime(triggerRouter.getLastUpdateTime()); - jdbcTemplate.update(getSql("insertTriggerRouterSql"), new Object[] { - triggerRouter.getInitialLoadOrder(), triggerRouter.getInitialLoadSelect(), - triggerRouter.isPingBackEnabled() ? 1 : 0, - triggerRouter.getCreateTime(), triggerRouter.getLastUpdateBy(), - triggerRouter.getLastUpdateTime(), triggerRouter.getTrigger().getTriggerId(), - triggerRouter.getRouter().getRouterId() }, new int[] { Types.NUMERIC, - Types.VARCHAR, Types.SMALLINT, Types.TIMESTAMP, Types.VARCHAR, Types.TIMESTAMP, Types.VARCHAR, - Types.VARCHAR }); - } - } - - protected void resetTriggerRouterCacheByNodeGroupId() { - triggerRouterCacheTime = 0; - } - - public void saveRouter(Router router) { + } + triggerRouter.setLastUpdateTime(new Date()); + if (0 == sqlTemplate.update( + getSql("updateTriggerRouterSql"), + new Object[] { triggerRouter.getInitialLoadOrder(), + triggerRouter.getInitialLoadSelect(), + triggerRouter.isPingBackEnabled() ? 1 : 0, triggerRouter.getLastUpdateBy(), + triggerRouter.getLastUpdateTime(), + triggerRouter.getTrigger().getTriggerId(), + triggerRouter.getRouter().getRouterId() }, new int[] { Types.NUMERIC, + Types.VARCHAR, Types.SMALLINT, Types.VARCHAR, Types.TIMESTAMP, + Types.VARCHAR, Types.VARCHAR })) { + triggerRouter.setCreateTime(triggerRouter.getLastUpdateTime()); + sqlTemplate.update( + getSql("insertTriggerRouterSql"), + new Object[] { triggerRouter.getInitialLoadOrder(), + triggerRouter.getInitialLoadSelect(), + triggerRouter.isPingBackEnabled() ? 1 : 0, + triggerRouter.getCreateTime(), triggerRouter.getLastUpdateBy(), + triggerRouter.getLastUpdateTime(), + triggerRouter.getTrigger().getTriggerId(), + triggerRouter.getRouter().getRouterId() }, new int[] { Types.NUMERIC, + Types.VARCHAR, Types.SMALLINT, Types.TIMESTAMP, Types.VARCHAR, + Types.TIMESTAMP, Types.VARCHAR, Types.VARCHAR }); + } + } + + protected void resetTriggerRouterCacheByNodeGroupId() { + triggerRouterCacheTime = 0; + } + + public void saveRouter(Router router) { router.setLastUpdateTime(new Date()); - router.nullOutBlankFields(); - if (0 == jdbcTemplate.update(getSql("updateRouterSql"), new Object[] { - router.getTargetCatalogName(), router.getTargetSchemaName(), - router.getTargetTableName(), router.getNodeGroupLink().getSourceNodeGroupId(), - router.getNodeGroupLink().getTargetNodeGroupId(), router.getRouterType(), - router.getRouterExpression(), router.isSyncOnUpdate() ? 1 : 0, - router.isSyncOnInsert() ? 1 : 0, router.isSyncOnDelete() ? 1 : 0, - router.getLastUpdateBy(), router.getLastUpdateTime(), router.getRouterId() }, - new int[] { Types.VARCHAR, Types.VARCHAR, Types.VARCHAR, Types.VARCHAR, - Types.VARCHAR, Types.VARCHAR, Types.VARCHAR, Types.SMALLINT, - Types.SMALLINT, Types.SMALLINT, Types.VARCHAR, Types.TIMESTAMP, - Types.VARCHAR })) { - router.setCreateTime(router.getLastUpdateTime()); - jdbcTemplate.update(getSql("insertRouterSql"), new Object[] { - router.getTargetCatalogName(), router.getTargetSchemaName(), - router.getTargetTableName(), router.getNodeGroupLink().getSourceNodeGroupId(), - router.getNodeGroupLink().getTargetNodeGroupId(), router.getRouterType(), - router.getRouterExpression(), router.isSyncOnUpdate() ? 1 : 0, - router.isSyncOnInsert() ? 1 : 0, router.isSyncOnDelete() ? 1 : 0, - router.getCreateTime(), router.getLastUpdateBy(), router.getLastUpdateTime(), - router.getRouterId() }, new int[] { Types.VARCHAR, Types.VARCHAR, - Types.VARCHAR, Types.VARCHAR, Types.VARCHAR, Types.VARCHAR, Types.VARCHAR, - Types.SMALLINT, Types.SMALLINT, Types.SMALLINT, Types.TIMESTAMP, Types.VARCHAR, - Types.TIMESTAMP, Types.VARCHAR }); - } - resetTriggerRouterCacheByNodeGroupId(); - } - + router.nullOutBlankFields(); + if (0 == sqlTemplate + .update(getSql("updateRouterSql"), + new Object[] { router.getTargetCatalogName(), router.getTargetSchemaName(), + router.getTargetTableName(), + router.getNodeGroupLink().getSourceNodeGroupId(), + router.getNodeGroupLink().getTargetNodeGroupId(), + router.getRouterType(), router.getRouterExpression(), + router.isSyncOnUpdate() ? 1 : 0, router.isSyncOnInsert() ? 1 : 0, + router.isSyncOnDelete() ? 1 : 0, router.getLastUpdateBy(), + router.getLastUpdateTime(), router.getRouterId() }, new int[] { + Types.VARCHAR, Types.VARCHAR, Types.VARCHAR, Types.VARCHAR, + Types.VARCHAR, Types.VARCHAR, Types.VARCHAR, Types.SMALLINT, + Types.SMALLINT, Types.SMALLINT, Types.VARCHAR, Types.TIMESTAMP, + Types.VARCHAR })) { + router.setCreateTime(router.getLastUpdateTime()); + sqlTemplate.update( + getSql("insertRouterSql"), + new Object[] { router.getTargetCatalogName(), router.getTargetSchemaName(), + router.getTargetTableName(), + router.getNodeGroupLink().getSourceNodeGroupId(), + router.getNodeGroupLink().getTargetNodeGroupId(), + router.getRouterType(), router.getRouterExpression(), + router.isSyncOnUpdate() ? 1 : 0, router.isSyncOnInsert() ? 1 : 0, + router.isSyncOnDelete() ? 1 : 0, router.getCreateTime(), + router.getLastUpdateBy(), router.getLastUpdateTime(), + router.getRouterId() }, new int[] { Types.VARCHAR, Types.VARCHAR, + Types.VARCHAR, Types.VARCHAR, Types.VARCHAR, Types.VARCHAR, + Types.VARCHAR, Types.SMALLINT, Types.SMALLINT, Types.SMALLINT, + Types.TIMESTAMP, Types.VARCHAR, Types.TIMESTAMP, Types.VARCHAR }); + } + resetTriggerRouterCacheByNodeGroupId(); + } public boolean isRouterBeingUsed(String routerId) { - return jdbcTemplate.queryForInt(getSql("countTriggerRoutersByRouterIdSql"), routerId) > 0; + return sqlTemplate.queryForInt(getSql("countTriggerRoutersByRouterIdSql"), routerId) > 0; } - + public void deleteRouter(Router router) { if (router != null) { - jdbcTemplate.update(getSql("deleteRouterSql"), router.getRouterId()); - } - } - - public void saveTrigger(Trigger trigger) { + sqlTemplate.update(getSql("deleteRouterSql"), (Object)router.getRouterId()); + } + } + + public void saveTrigger(Trigger trigger) { trigger.setLastUpdateTime(new Date()); - trigger.nullOutBlankFields(); - if (0 == jdbcTemplate.update(getSql("updateTriggerSql"), new Object[] { - trigger.getSourceCatalogName(), trigger.getSourceSchemaName(), - trigger.getSourceTableName(), trigger.getChannelId(), - trigger.isSyncOnUpdate() ? 1 : 0, trigger.isSyncOnInsert() ? 1 : 0, - trigger.isSyncOnDelete() ? 1 : 0, trigger.isSyncOnIncomingBatch() ? 1 : 0, - trigger.isUseStreamLobs() ? 1 : 0, - trigger.isUseCaptureLobs() ? 1 : 0, - trigger.getNameForUpdateTrigger(), trigger.getNameForInsertTrigger(), - trigger.getNameForDeleteTrigger(), trigger.getSyncOnUpdateCondition(), - trigger.getSyncOnInsertCondition(), trigger.getSyncOnDeleteCondition(), - trigger.getTxIdExpression(), trigger.getExcludedColumnNames(), - trigger.getLastUpdateBy(), trigger.getLastUpdateTime(), - trigger.getExternalSelect(), trigger.getTriggerId() }, new int[] { Types.VARCHAR, - Types.VARCHAR, Types.VARCHAR, Types.VARCHAR, Types.SMALLINT, Types.SMALLINT, - Types.SMALLINT, Types.SMALLINT, Types.SMALLINT, Types.SMALLINT, Types.VARCHAR, Types.VARCHAR, Types.VARCHAR, - Types.VARCHAR, Types.VARCHAR, Types.VARCHAR, Types.VARCHAR, Types.VARCHAR, - Types.VARCHAR, Types.TIMESTAMP, Types.VARCHAR, Types.VARCHAR })) { - trigger.setCreateTime(trigger.getLastUpdateTime()); - jdbcTemplate.update(getSql("insertTriggerSql"), new Object[] { - trigger.getSourceCatalogName(), trigger.getSourceSchemaName(), - trigger.getSourceTableName(), trigger.getChannelId(), - trigger.isSyncOnUpdate() ? 1 : 0, trigger.isSyncOnInsert() ? 1 : 0, - trigger.isSyncOnDelete() ? 1 : 0, trigger.isSyncOnIncomingBatch() ? 1 : 0, - trigger.isUseStreamLobs() ? 1 : 0, - trigger.isUseCaptureLobs() ? 1 : 0, - trigger.getNameForUpdateTrigger(), trigger.getNameForInsertTrigger(), - trigger.getNameForDeleteTrigger(), trigger.getSyncOnUpdateCondition(), - trigger.getSyncOnInsertCondition(), trigger.getSyncOnDeleteCondition(), - trigger.getTxIdExpression(), trigger.getExcludedColumnNames(), - trigger.getCreateTime(), trigger.getLastUpdateBy(), - trigger.getLastUpdateTime(), trigger.getExternalSelect(), - trigger.getTriggerId() }, new int[] { Types.VARCHAR, Types.VARCHAR, - Types.VARCHAR, Types.VARCHAR, Types.SMALLINT, Types.SMALLINT, Types.SMALLINT, - Types.SMALLINT, Types.SMALLINT, Types.SMALLINT, Types.VARCHAR, Types.VARCHAR, Types.VARCHAR, Types.VARCHAR, - Types.VARCHAR, Types.VARCHAR, Types.VARCHAR, Types.VARCHAR, Types.TIMESTAMP, - Types.VARCHAR, Types.TIMESTAMP, Types.VARCHAR, Types.VARCHAR }); - } - } - - public void syncTriggers() { - syncTriggers(null, false); - } - + trigger.nullOutBlankFields(); + if (0 == sqlTemplate.update( + getSql("updateTriggerSql"), + new Object[] { trigger.getSourceCatalogName(), trigger.getSourceSchemaName(), + trigger.getSourceTableName(), trigger.getChannelId(), + trigger.isSyncOnUpdate() ? 1 : 0, trigger.isSyncOnInsert() ? 1 : 0, + trigger.isSyncOnDelete() ? 1 : 0, trigger.isSyncOnIncomingBatch() ? 1 : 0, + trigger.isUseStreamLobs() ? 1 : 0, trigger.isUseCaptureLobs() ? 1 : 0, + trigger.getNameForUpdateTrigger(), trigger.getNameForInsertTrigger(), + trigger.getNameForDeleteTrigger(), trigger.getSyncOnUpdateCondition(), + trigger.getSyncOnInsertCondition(), trigger.getSyncOnDeleteCondition(), + trigger.getTxIdExpression(), trigger.getExcludedColumnNames(), + trigger.getLastUpdateBy(), trigger.getLastUpdateTime(), + trigger.getExternalSelect(), trigger.getTriggerId() }, new int[] { + Types.VARCHAR, Types.VARCHAR, Types.VARCHAR, Types.VARCHAR, Types.SMALLINT, + Types.SMALLINT, Types.SMALLINT, Types.SMALLINT, Types.SMALLINT, + Types.SMALLINT, Types.VARCHAR, Types.VARCHAR, Types.VARCHAR, Types.VARCHAR, + Types.VARCHAR, Types.VARCHAR, Types.VARCHAR, Types.VARCHAR, Types.VARCHAR, + Types.TIMESTAMP, Types.VARCHAR, Types.VARCHAR })) { + trigger.setCreateTime(trigger.getLastUpdateTime()); + sqlTemplate.update( + getSql("insertTriggerSql"), + new Object[] { trigger.getSourceCatalogName(), trigger.getSourceSchemaName(), + trigger.getSourceTableName(), trigger.getChannelId(), + trigger.isSyncOnUpdate() ? 1 : 0, trigger.isSyncOnInsert() ? 1 : 0, + trigger.isSyncOnDelete() ? 1 : 0, + trigger.isSyncOnIncomingBatch() ? 1 : 0, + trigger.isUseStreamLobs() ? 1 : 0, trigger.isUseCaptureLobs() ? 1 : 0, + trigger.getNameForUpdateTrigger(), trigger.getNameForInsertTrigger(), + trigger.getNameForDeleteTrigger(), trigger.getSyncOnUpdateCondition(), + trigger.getSyncOnInsertCondition(), trigger.getSyncOnDeleteCondition(), + trigger.getTxIdExpression(), trigger.getExcludedColumnNames(), + trigger.getCreateTime(), trigger.getLastUpdateBy(), + trigger.getLastUpdateTime(), trigger.getExternalSelect(), + trigger.getTriggerId() }, new int[] { Types.VARCHAR, Types.VARCHAR, + Types.VARCHAR, Types.VARCHAR, Types.SMALLINT, Types.SMALLINT, + Types.SMALLINT, Types.SMALLINT, Types.SMALLINT, Types.SMALLINT, + Types.VARCHAR, Types.VARCHAR, Types.VARCHAR, Types.VARCHAR, + Types.VARCHAR, Types.VARCHAR, Types.VARCHAR, Types.VARCHAR, + Types.TIMESTAMP, Types.VARCHAR, Types.TIMESTAMP, Types.VARCHAR, + Types.VARCHAR }); + } + } + + public void syncTriggers() { + syncTriggers(null, false); + } + public void syncTriggers(StringBuilder sqlBuffer, boolean gen_always) { if (clusterService.lock(ClusterConstants.SYNCTRIGGERS)) { synchronized (this) { try { - log.info("TriggersSynchronizing"); + log.info("Synchronizing triggers"); // make sure channels are read from the database configurationService.reloadChannels(); List triggersForCurrentNode = getTriggersForCurrentNode(); @@ -712,29 +787,29 @@ public void syncTriggers(StringBuilder sqlBuffer, boolean gen_always) { resetTriggerRouterCacheByNodeGroupId(); } finally { clusterService.unlock(ClusterConstants.SYNCTRIGGERS); - log.info("TriggersSynchronized"); + log.info("Done synchronizing triggers"); } } } else { - log.info("TriggersSynchronizingFailedLock"); + log.info("Failed to synchronize trigger for %s"); } } - + protected Set getTriggerIdsFrom(List triggersThatShouldBeActive) { Set triggerIds = new HashSet(triggersThatShouldBeActive.size()); for (Trigger trigger : triggersThatShouldBeActive) { triggerIds.add(trigger.getTriggerId()); } return triggerIds; - } - + } + protected void inactivateTriggers(List triggersThatShouldBeActive, StringBuilder sqlBuffer) { List activeHistories = getActiveTriggerHistories(); Set triggerIdsThatShouldBeActive = getTriggerIdsFrom(triggersThatShouldBeActive); for (TriggerHistory history : activeHistories) { if (!triggerIdsThatShouldBeActive.contains(history.getTriggerId())) { - log.info("TriggersRemoving", history.getSourceTableName()); + log.info("About to remove triggers for inactivated table: %s", history.getSourceTableName()); symmetricDialect.removeTrigger(sqlBuffer, history.getSourceCatalogName(), history.getSourceSchemaName(), history.getNameForInsertTrigger(), history.getSourceTableName(), history); @@ -753,9 +828,9 @@ protected void inactivateTriggers(List triggersThatShouldBeActive, } } - boolean triggerExists = symmetricDialect.doesTriggerExist(history.getSourceCatalogName(), - history.getSourceSchemaName(), history.getSourceTableName(), - history.getNameForInsertTrigger()); + boolean triggerExists = symmetricDialect.doesTriggerExist( + history.getSourceCatalogName(), history.getSourceSchemaName(), + history.getSourceTableName(), history.getNameForInsertTrigger()); triggerExists |= symmetricDialect.doesTriggerExist(history.getSourceCatalogName(), history.getSourceSchemaName(), history.getSourceTableName(), history.getNameForUpdateTrigger()); @@ -763,189 +838,198 @@ protected void inactivateTriggers(List triggersThatShouldBeActive, history.getSourceSchemaName(), history.getSourceTableName(), history.getNameForDeleteTrigger()); if (triggerExists) { - log.warn("TriggersRemovingFailed", history.getTriggerId(), + log.warn("There are triggers that have been marked as inactive. Please remove triggers represented by trigger_id=%s and trigger_hist_id=%s", history.getTriggerId(), history.getTriggerHistoryId()); } else { inactivateTriggerHistory(history); } } } - } - - protected List toList(Collection> source) { - ArrayList list = new ArrayList(); - for (List triggerRouters : source) { - for (TriggerRouter triggerRouter : triggerRouters) { - list.add(triggerRouter); - } - } - return list; - } - + } + + protected List toList(Collection> source) { + ArrayList list = new ArrayList(); + for (List triggerRouters : source) { + for (TriggerRouter triggerRouter : triggerRouters) { + list.add(triggerRouter); + } + } + return list; + } + protected List getTriggersForCurrentNode() { - return new TriggerSelector(toList(getTriggerRoutersForCurrentNode( - true).values())) - .select(); - } - - protected void updateOrCreateDatabaseTriggers(List triggers, StringBuilder sqlBuffer, boolean gen_always) { - + return new TriggerSelector(toList(getTriggerRoutersForCurrentNode(true).values())).select(); + } + + protected void updateOrCreateDatabaseTriggers(List triggers, StringBuilder sqlBuffer, + boolean gen_always) { + for (Trigger trigger : triggers) { - TriggerHistory newestHistory = null; + TriggerHistory newestHistory = null; try { TriggerReBuildReason reason = TriggerReBuildReason.NEW_TRIGGERS; - Table table = symmetricDialect.getPlatform().getTableFromCache(trigger.getSourceCatalogName(), trigger - .getSourceSchemaName(), trigger.getSourceTableName(), true); + Table table = symmetricDialect.getPlatform().getTableFromCache( + trigger.getSourceCatalogName(), trigger.getSourceSchemaName(), + trigger.getSourceTableName(), true); String errorMessage = null; Channel channel = configurationService.getChannel(trigger.getChannelId()); if (channel == null) { - errorMessage = Message.get("TriggerFoundWithInvalidChannelId", trigger.getTriggerId(), trigger.getChannelId(), Constants.CHANNEL_DEFAULT); - log.error("TriggerFoundWithInvalidChannelId", trigger.getTriggerId(), trigger.getChannelId(), Constants.CHANNEL_DEFAULT); + errorMessage = Message.get("Trigger %s had an unrecognized channel_id of '%s'. Please check to make sure the channel exists. Creating trigger on the '%s' channel", + trigger.getTriggerId(), trigger.getChannelId(), + Constants.CHANNEL_DEFAULT); + log.error(errorMessage); trigger.setChannelId(Constants.CHANNEL_DEFAULT); } - - if (table != null) { - TriggerHistory latestHistoryBeforeRebuild = getNewestTriggerHistoryForTrigger(trigger - .getTriggerId()); - - boolean forceRebuildOfTriggers = false; - if (latestHistoryBeforeRebuild == null) { - reason = TriggerReBuildReason.NEW_TRIGGERS; - forceRebuildOfTriggers = true; - - } else if (TriggerHistory.calculateTableHashFor(table) != latestHistoryBeforeRebuild - .getTableHash()) { - reason = TriggerReBuildReason.TABLE_SCHEMA_CHANGED; - forceRebuildOfTriggers = true; - - } else if (trigger.hasChangedSinceLastTriggerBuild(latestHistoryBeforeRebuild - .getCreateTime()) - || trigger.toHashedValue() != latestHistoryBeforeRebuild - .getTriggerRowHash()) { - reason = TriggerReBuildReason.TABLE_SYNC_CONFIGURATION_CHANGED; - forceRebuildOfTriggers = true; - } else if (gen_always) { - reason = TriggerReBuildReason.FORCED; - forceRebuildOfTriggers = true; + + if (table != null) { + TriggerHistory latestHistoryBeforeRebuild = getNewestTriggerHistoryForTrigger(trigger + .getTriggerId()); + + boolean forceRebuildOfTriggers = false; + if (latestHistoryBeforeRebuild == null) { + reason = TriggerReBuildReason.NEW_TRIGGERS; + forceRebuildOfTriggers = true; + + } else if (TriggerHistory.calculateTableHashFor(table) != latestHistoryBeforeRebuild + .getTableHash()) { + reason = TriggerReBuildReason.TABLE_SCHEMA_CHANGED; + forceRebuildOfTriggers = true; + + } else if (trigger.hasChangedSinceLastTriggerBuild(latestHistoryBeforeRebuild + .getCreateTime()) + || trigger.toHashedValue() != latestHistoryBeforeRebuild + .getTriggerRowHash()) { + reason = TriggerReBuildReason.TABLE_SYNC_CONFIGURATION_CHANGED; + forceRebuildOfTriggers = true; + } else if (gen_always) { + reason = TriggerReBuildReason.FORCED; + forceRebuildOfTriggers = true; + } + + boolean supportsTriggers = symmetricDialect.getPlatform().getPlatformInfo() + .isTriggersSupported(); + + newestHistory = rebuildTriggerIfNecessary(sqlBuffer, forceRebuildOfTriggers, + trigger, DataEventType.INSERT, reason, latestHistoryBeforeRebuild, + null, trigger.isSyncOnInsert() && supportsTriggers, table); + + newestHistory = rebuildTriggerIfNecessary(sqlBuffer, forceRebuildOfTriggers, + trigger, DataEventType.UPDATE, reason, latestHistoryBeforeRebuild, + newestHistory, trigger.isSyncOnUpdate() && supportsTriggers, table); + + newestHistory = rebuildTriggerIfNecessary(sqlBuffer, forceRebuildOfTriggers, + trigger, DataEventType.DELETE, reason, latestHistoryBeforeRebuild, + newestHistory, trigger.isSyncOnDelete() && supportsTriggers, table); + + if (latestHistoryBeforeRebuild != null && newestHistory != null) { + inactivateTriggerHistory(latestHistoryBeforeRebuild); } - - boolean supportsTriggers = symmetricDialect.getPlatform().getPlatformInfo().isTriggersSupported(); - - newestHistory = rebuildTriggerIfNecessary(sqlBuffer, - forceRebuildOfTriggers, trigger, DataEventType.INSERT, reason, - latestHistoryBeforeRebuild, null, trigger.isSyncOnInsert() && supportsTriggers, table); - - newestHistory = rebuildTriggerIfNecessary(sqlBuffer, forceRebuildOfTriggers, - trigger, DataEventType.UPDATE, reason, latestHistoryBeforeRebuild, - newestHistory, trigger.isSyncOnUpdate() && supportsTriggers, table); - - newestHistory = rebuildTriggerIfNecessary(sqlBuffer, forceRebuildOfTriggers, - trigger, DataEventType.DELETE, reason, latestHistoryBeforeRebuild, - newestHistory, trigger.isSyncOnDelete() && supportsTriggers, table); - - if (latestHistoryBeforeRebuild != null && newestHistory != null) { - inactivateTriggerHistory(latestHistoryBeforeRebuild); - } - + if (newestHistory != null) { - newestHistory.setErrorMessage(errorMessage); - if (parameterService.is(ParameterConstants.AUTO_SYNC_TRIGGERS)) { - if (this.triggerCreationListeners != null) { - for (ITriggerCreationListener l : this.triggerCreationListeners) { - l.triggerCreated(trigger, newestHistory); - } - } - } - } - - } else { - log.error("TriggerTableMissing", trigger.qualifiedSourceTableName()); - - if (this.triggerCreationListeners != null) { - for (ITriggerCreationListener l : this.triggerCreationListeners) { - l.tableDoesNotExist(trigger); - } - } - } - } catch (Exception ex) { - log.error("TriggerSynchronizingFailed", ex, trigger.qualifiedSourceTableName()); - + newestHistory.setErrorMessage(errorMessage); + if (parameterService.is(ParameterConstants.AUTO_SYNC_TRIGGERS)) { + if (this.triggerCreationListeners != null) { + for (ITriggerCreationListener l : this.triggerCreationListeners) { + l.triggerCreated(trigger, newestHistory); + } + } + } + } + + } else { + log.error("The configured table does not exist in the datasource that is configured: %s", trigger.qualifiedSourceTableName()); + + if (this.triggerCreationListeners != null) { + for (ITriggerCreationListener l : this.triggerCreationListeners) { + l.tableDoesNotExist(trigger); + } + } + } + } catch (Exception ex) { + log.error("Failed to create triggers for %s", ex, trigger.qualifiedSourceTableName()); + if (newestHistory != null) { // Make sure all the triggers are removed from the table - symmetricDialect.removeTrigger(null, trigger.getSourceCatalogName(), trigger.getSourceSchemaName(), newestHistory.getNameForInsertTrigger(), trigger.getSourceTableName(), newestHistory); - symmetricDialect.removeTrigger(null, trigger.getSourceCatalogName(), trigger.getSourceSchemaName(), newestHistory.getNameForUpdateTrigger(), trigger.getSourceTableName(), newestHistory); - symmetricDialect.removeTrigger(null, trigger.getSourceCatalogName(), trigger.getSourceSchemaName(), newestHistory.getNameForDeleteTrigger(), trigger.getSourceTableName(), newestHistory); + symmetricDialect.removeTrigger(null, trigger.getSourceCatalogName(), + trigger.getSourceSchemaName(), newestHistory.getNameForInsertTrigger(), + trigger.getSourceTableName(), newestHistory); + symmetricDialect.removeTrigger(null, trigger.getSourceCatalogName(), + trigger.getSourceSchemaName(), newestHistory.getNameForUpdateTrigger(), + trigger.getSourceTableName(), newestHistory); + symmetricDialect.removeTrigger(null, trigger.getSourceCatalogName(), + trigger.getSourceSchemaName(), newestHistory.getNameForDeleteTrigger(), + trigger.getSourceTableName(), newestHistory); } - - if (this.triggerCreationListeners != null) { - for (ITriggerCreationListener l : this.triggerCreationListeners) { - l.triggerFailed(trigger, ex); - } - } - } - - } - } - - protected TriggerHistory rebuildTriggerIfNecessary(StringBuilder sqlBuffer, - boolean forceRebuild, Trigger trigger, DataEventType dmlType, - TriggerReBuildReason reason, TriggerHistory oldhist, TriggerHistory hist, - boolean triggerIsActive, Table table) { - + + if (this.triggerCreationListeners != null) { + for (ITriggerCreationListener l : this.triggerCreationListeners) { + l.triggerFailed(trigger, ex); + } + } + } + + } + } + + protected TriggerHistory rebuildTriggerIfNecessary(StringBuilder sqlBuffer, + boolean forceRebuild, Trigger trigger, DataEventType dmlType, + TriggerReBuildReason reason, TriggerHistory oldhist, TriggerHistory hist, + boolean triggerIsActive, Table table) { + boolean triggerExists = false; - boolean triggerRemoved = false; - - TriggerHistory newTriggerHist = new TriggerHistory(table, trigger, reason); - int maxTriggerNameLength = symmetricDialect.getMaxTriggerNameLength(); - - newTriggerHist.setNameForInsertTrigger(getTriggerName(DataEventType.INSERT, - maxTriggerNameLength, trigger).toUpperCase()); - newTriggerHist.setNameForUpdateTrigger(getTriggerName(DataEventType.UPDATE, - maxTriggerNameLength, trigger).toUpperCase()); - newTriggerHist.setNameForDeleteTrigger(getTriggerName(DataEventType.DELETE, - maxTriggerNameLength, trigger).toUpperCase()); - - String oldTriggerName = null; - String oldSourceSchema = null; - String oldCatalogName = null; - if (oldhist != null) { - oldTriggerName = oldhist.getTriggerNameForDmlType(dmlType); - oldSourceSchema = oldhist.getSourceSchemaName(); - oldCatalogName = oldhist.getSourceCatalogName(); - triggerExists = symmetricDialect.doesTriggerExist(oldCatalogName, oldSourceSchema, oldhist - .getSourceTableName(), oldTriggerName); - } else { - // We had no trigger_hist row, lets validate that the trigger as - // defined in the trigger row data does not exist as well. - oldTriggerName = newTriggerHist.getTriggerNameForDmlType(dmlType); - oldSourceSchema = trigger.getSourceSchemaName(); - oldCatalogName = trigger.getSourceCatalogName(); - triggerExists = symmetricDialect.doesTriggerExist(oldCatalogName, oldSourceSchema, trigger - .getSourceTableName(), oldTriggerName); - } - - if (!triggerExists && forceRebuild) { - reason = TriggerReBuildReason.TRIGGERS_MISSING; - } - - if ((forceRebuild || !triggerIsActive) && triggerExists) { - symmetricDialect.removeTrigger(sqlBuffer, oldCatalogName, oldSourceSchema, oldTriggerName, - trigger.getSourceTableName(), oldhist); + boolean triggerRemoved = false; + + TriggerHistory newTriggerHist = new TriggerHistory(table, trigger, reason); + int maxTriggerNameLength = symmetricDialect.getMaxTriggerNameLength(); + + newTriggerHist.setNameForInsertTrigger(getTriggerName(DataEventType.INSERT, + maxTriggerNameLength, trigger).toUpperCase()); + newTriggerHist.setNameForUpdateTrigger(getTriggerName(DataEventType.UPDATE, + maxTriggerNameLength, trigger).toUpperCase()); + newTriggerHist.setNameForDeleteTrigger(getTriggerName(DataEventType.DELETE, + maxTriggerNameLength, trigger).toUpperCase()); + + String oldTriggerName = null; + String oldSourceSchema = null; + String oldCatalogName = null; + if (oldhist != null) { + oldTriggerName = oldhist.getTriggerNameForDmlType(dmlType); + oldSourceSchema = oldhist.getSourceSchemaName(); + oldCatalogName = oldhist.getSourceCatalogName(); + triggerExists = symmetricDialect.doesTriggerExist(oldCatalogName, oldSourceSchema, + oldhist.getSourceTableName(), oldTriggerName); + } else { + // We had no trigger_hist row, lets validate that the trigger as + // defined in the trigger row data does not exist as well. + oldTriggerName = newTriggerHist.getTriggerNameForDmlType(dmlType); + oldSourceSchema = trigger.getSourceSchemaName(); + oldCatalogName = trigger.getSourceCatalogName(); + triggerExists = symmetricDialect.doesTriggerExist(oldCatalogName, oldSourceSchema, + trigger.getSourceTableName(), oldTriggerName); + } + + if (!triggerExists && forceRebuild) { + reason = TriggerReBuildReason.TRIGGERS_MISSING; + } + + if ((forceRebuild || !triggerIsActive) && triggerExists) { + symmetricDialect.removeTrigger(sqlBuffer, oldCatalogName, oldSourceSchema, + oldTriggerName, trigger.getSourceTableName(), oldhist); triggerExists = false; - triggerRemoved = true; - } - - boolean isDeadTrigger = !trigger.isSyncOnInsert() && !trigger.isSyncOnUpdate() - && !trigger.isSyncOnDelete(); - - if (hist == null - && (oldhist == null || (!triggerExists && triggerIsActive) || (isDeadTrigger && forceRebuild))) { - insert(newTriggerHist); - hist = getNewestTriggerHistoryForTrigger(trigger.getTriggerId()); + triggerRemoved = true; } - + + boolean isDeadTrigger = !trigger.isSyncOnInsert() && !trigger.isSyncOnUpdate() + && !trigger.isSyncOnDelete(); + + if (hist == null + && (oldhist == null || (!triggerExists && triggerIsActive) || (isDeadTrigger && forceRebuild))) { + insert(newTriggerHist); + hist = getNewestTriggerHistoryForTrigger(trigger.getTriggerId()); + } + try { if (!triggerExists && triggerIsActive) { symmetricDialect @@ -965,63 +1049,65 @@ protected TriggerHistory rebuildTriggerIfNecessary(StringBuilder sqlBuffer, if (!symmetricDialect.doesTriggerExist(hist.getSourceCatalogName(), hist.getSourceSchemaName(), hist.getSourceTableName(), hist.getTriggerNameForDmlType(dmlType))) { - log.warn("TriggerHistCleanup", hist.getTriggerHistoryId()); + log.warn("Cleaning up trigger hist row of %d after failing to create the associated trigger", hist.getTriggerHistoryId()); hist.setErrorMessage(ex.getMessage()); inactivateTriggerHistory(hist); } throw ex; - } - - return hist; - } - - protected String replaceCharsForTriggerName(String triggerName) { - return triggerName.replaceAll( - "[^a-zA-Z0-9_]|[a|e|i|o|u|A|E|I|O|U]", ""); - } - - protected String getTriggerName(DataEventType dml, int maxTriggerNameLength, Trigger trigger) { - - String triggerName = null; - switch (dml) { - case INSERT: - if (!StringUtils.isBlank(trigger.getNameForInsertTrigger())) { - triggerName = trigger.getNameForInsertTrigger(); - } - break; - case UPDATE: - if (!StringUtils.isBlank(trigger.getNameForUpdateTrigger())) { - triggerName = trigger.getNameForUpdateTrigger(); - } - break; - case DELETE: - if (!StringUtils.isBlank(trigger.getNameForDeleteTrigger())) { - triggerName = trigger.getNameForDeleteTrigger(); - } - break; - } - - if (StringUtils.isBlank(triggerName)) { - String triggerPrefix1 = tablePrefix + "_"; - String triggerSuffix1 = "on_" + dml.getCode().toLowerCase() + "_for_"; - String triggerSuffix2 = replaceCharsForTriggerName(trigger.getTriggerId()); - String triggerSuffix3 = replaceCharsForTriggerName("_" + parameterService.getNodeGroupId()); - triggerName = triggerPrefix1 + triggerSuffix1 + triggerSuffix2 + triggerSuffix3; - // use the node group id as part of the trigger if we can because it - // helps uniquely identify the trigger in embedded databases. In hsqldb we choose the - // correct connection based on the presence of a table that is named for the trigger. - // If the trigger isn't unique across all databases, then we can - // choose the wrong connection. - if (triggerName.length() > maxTriggerNameLength && maxTriggerNameLength > 0) { - triggerName = triggerPrefix1 + triggerSuffix1 + triggerSuffix2; - } - } - - triggerName = triggerName.toUpperCase(); + } + + return hist; + } + + protected String replaceCharsForTriggerName(String triggerName) { + return triggerName.replaceAll("[^a-zA-Z0-9_]|[a|e|i|o|u|A|E|I|O|U]", ""); + } + + protected String getTriggerName(DataEventType dml, int maxTriggerNameLength, Trigger trigger) { + + String triggerName = null; + switch (dml) { + case INSERT: + if (!StringUtils.isBlank(trigger.getNameForInsertTrigger())) { + triggerName = trigger.getNameForInsertTrigger(); + } + break; + case UPDATE: + if (!StringUtils.isBlank(trigger.getNameForUpdateTrigger())) { + triggerName = trigger.getNameForUpdateTrigger(); + } + break; + case DELETE: + if (!StringUtils.isBlank(trigger.getNameForDeleteTrigger())) { + triggerName = trigger.getNameForDeleteTrigger(); + } + break; + } + + if (StringUtils.isBlank(triggerName)) { + String triggerPrefix1 = tablePrefix + "_"; + String triggerSuffix1 = "on_" + dml.getCode().toLowerCase() + "_for_"; + String triggerSuffix2 = replaceCharsForTriggerName(trigger.getTriggerId()); + String triggerSuffix3 = replaceCharsForTriggerName("_" + + parameterService.getNodeGroupId()); + triggerName = triggerPrefix1 + triggerSuffix1 + triggerSuffix2 + triggerSuffix3; + // use the node group id as part of the trigger if we can because it + // helps uniquely identify the trigger in embedded databases. In + // hsqldb we choose the + // correct connection based on the presence of a table that is named + // for the trigger. + // If the trigger isn't unique across all databases, then we can + // choose the wrong connection. + if (triggerName.length() > maxTriggerNameLength && maxTriggerNameLength > 0) { + triggerName = triggerPrefix1 + triggerSuffix1 + triggerSuffix2; + } + } + + triggerName = triggerName.toUpperCase(); if (triggerName.length() > maxTriggerNameLength && maxTriggerNameLength > 0) { triggerName = triggerName.substring(0, maxTriggerNameLength - 1); - log.debug("TriggerNameTruncated", dml.name().toLowerCase(), trigger.getTriggerId(), + log.debug("We just truncated the trigger name for the %s trigger id=%s. You might want to consider manually providing a name for the trigger that is less than %d characters long", dml.name().toLowerCase(), trigger.getTriggerId(), maxTriggerNameLength); } @@ -1038,80 +1124,81 @@ protected String getTriggerName(DataEventType dml, int maxTriggerNameLength, Tri } } - return triggerName; - } - - class NodeGroupLinkMapper implements RowMapper { - public NodeGroupLink mapRow(ResultSet rs, int num) throws SQLException { - NodeGroupLink node_groupTarget = new NodeGroupLink(); - node_groupTarget.setSourceNodeGroupId(rs.getString(1)); - node_groupTarget.setTargetNodeGroupId(rs.getString(2)); - node_groupTarget.setDataEventAction(NodeGroupLinkAction.fromCode(rs.getString(3))); - return node_groupTarget; - } - } - - class TriggerHistoryMapper implements RowMapper { - Map retMap = null; - - TriggerHistoryMapper() { - } - - TriggerHistoryMapper(Map map) { - this.retMap = map; - } - - public TriggerHistory mapRow(ResultSet rs, int i) throws SQLException { - TriggerHistory hist = new TriggerHistory(); - hist.setTriggerHistoryId(rs.getInt(1)); - hist.setTriggerId(rs.getString(2)); - hist.setSourceTableName(rs.getString(3)); - hist.setTableHash(rs.getInt(4)); - hist.setCreateTime(rs.getTimestamp(5)); - hist.setPkColumnNames(rs.getString(6)); - hist.setColumnNames(rs.getString(7)); - hist.setLastTriggerBuildReason(TriggerReBuildReason.fromCode(rs.getString(8))); - hist.setNameForDeleteTrigger(rs.getString(9)); - hist.setNameForInsertTrigger(rs.getString(10)); - hist.setNameForUpdateTrigger(rs.getString(11)); - hist.setSourceSchemaName(rs.getString(12)); - hist.setSourceCatalogName(rs.getString(13)); - hist.setTriggerRowHash(rs.getLong(14)); - hist.setErrorMessage(rs.getString(15)); - if (this.retMap != null) { - this.retMap.put((long) hist.getTriggerHistoryId(), hist); - } - return hist; - } - } - - class RouterMapper implements RowMapper { - public Router mapRow(ResultSet rs, int rowNum) throws SQLException { - Router router = new Router(); - router.setSyncOnInsert(rs.getBoolean("r_sync_on_insert")); - router.setSyncOnUpdate(rs.getBoolean("r_sync_on_update")); - router.setSyncOnDelete(rs.getBoolean("r_sync_on_delete")); + return triggerName; + } + + class NodeGroupLinkMapper implements RowMapper { + public NodeGroupLink mapRow(ResultSet rs, int num) throws SQLException { + NodeGroupLink node_groupTarget = new NodeGroupLink(); + node_groupTarget.setSourceNodeGroupId(rs.getString(1)); + node_groupTarget.setTargetNodeGroupId(rs.getString(2)); + node_groupTarget.setDataEventAction(NodeGroupLinkAction.fromCode(rs.getString(3))); + return node_groupTarget; + } + } + + class TriggerHistoryMapper implements ISqlRowMapper { + Map retMap = null; + + TriggerHistoryMapper() { + } + + TriggerHistoryMapper(Map map) { + this.retMap = map; + } + + public TriggerHistory mapRow(Row rs) { + TriggerHistory hist = new TriggerHistory(); + hist.setTriggerHistoryId(rs.getInt("trigger_hist_id")); + hist.setTriggerId(rs.getString("trigger_id")); + hist.setSourceTableName(rs.getString("source_table_name")); + hist.setTableHash(rs.getInt("table_hash")); + hist.setCreateTime(rs.getDateTime("create_time")); + hist.setPkColumnNames(rs.getString("pk_column_names")); + hist.setColumnNames(rs.getString("column_names")); + hist.setLastTriggerBuildReason(TriggerReBuildReason.fromCode(rs + .getString("last_trigger_build_reason"))); + hist.setNameForDeleteTrigger(rs.getString("name_for_delete_trigger")); + hist.setNameForInsertTrigger(rs.getString("name_for_insert_trigger")); + hist.setNameForUpdateTrigger(rs.getString("name_for_update_trigger")); + hist.setSourceSchemaName(rs.getString("source_schema_name")); + hist.setSourceCatalogName(rs.getString("source_catalog_name")); + hist.setTriggerRowHash(rs.getLong("trigger_row_hash")); + hist.setErrorMessage(rs.getString("error_message")); + if (this.retMap != null) { + this.retMap.put((long) hist.getTriggerHistoryId(), hist); + } + return hist; + } + } + + class RouterMapper implements ISqlRowMapper { + public Router mapRow(Row rs) { + Router router = new Router(); + router.setSyncOnInsert(rs.getBoolean("r_sync_on_insert")); + router.setSyncOnUpdate(rs.getBoolean("r_sync_on_update")); + router.setSyncOnDelete(rs.getBoolean("r_sync_on_delete")); router.setTargetCatalogName(rs.getString("target_catalog_name")); - router.setNodeGroupLink( - configurationService.getNodeGroupLinkFor(rs.getString("source_node_group_id"), rs.getString("target_node_group_id"))); - router.setTargetSchemaName(rs.getString("target_schema_name")); - router.setTargetTableName(rs.getString("target_table_name")); - - String condition = rs.getString("router_expression"); - if (!StringUtils.isBlank(condition)) { - router.setRouterExpression(condition); - } - router.setRouterType(rs.getString("router_type")); - router.setRouterId(rs.getString("router_id")); - router.setCreateTime(rs.getTimestamp("r_create_time")); - router.setLastUpdateTime(rs.getTimestamp("r_last_update_time")); - router.setLastUpdateBy(rs.getString("r_last_update_by")); - return router; - } - } - - class TriggerMapper implements RowMapper { - public Trigger mapRow(ResultSet rs, int rowNum) throws SQLException { + router.setNodeGroupLink(configurationService.getNodeGroupLinkFor( + rs.getString("source_node_group_id"), rs.getString("target_node_group_id"))); + router.setTargetSchemaName(rs.getString("target_schema_name")); + router.setTargetTableName(rs.getString("target_table_name")); + + String condition = rs.getString("router_expression"); + if (!StringUtils.isBlank(condition)) { + router.setRouterExpression(condition); + } + router.setRouterType(rs.getString("router_type")); + router.setRouterId(rs.getString("router_id")); + router.setCreateTime(rs.getDateTime("r_create_time")); + router.setLastUpdateTime(rs.getDateTime("r_last_update_time")); + router.setLastUpdateBy(rs.getString("r_last_update_by")); + return router; + } + } + + class TriggerMapper implements ISqlRowMapper { + public Trigger mapRow(Row rs) { Trigger trigger = new Trigger(); trigger.setTriggerId(rs.getString("trigger_id")); trigger.setChannelId(rs.getString("channel_id")); @@ -1149,88 +1236,88 @@ public Trigger mapRow(ResultSet rs, int rowNum) throws SQLException { } trigger.setTxIdExpression(rs.getString("tx_id_expression")); - - trigger.setCreateTime(rs.getTimestamp("t_create_time")); - trigger.setLastUpdateTime(rs.getTimestamp("t_last_update_time")); + + trigger.setCreateTime(rs.getDateTime("t_create_time")); + trigger.setLastUpdateTime(rs.getDateTime("t_last_update_time")); trigger.setLastUpdateBy(rs.getString("t_last_update_by")); trigger.setExcludedColumnNames(rs.getString("excluded_column_names")); return trigger; } - } - - class TriggerRouterMapper implements RowMapper { - + } + + class TriggerRouterMapper implements ISqlRowMapper { + private TriggerMapper triggerMapper = new TriggerMapper(); private RouterMapper routerMapper = new RouterMapper(); - - public TriggerRouter mapRow(java.sql.ResultSet rs, int rowNum) throws java.sql.SQLException { - TriggerRouter triggerRouter = new TriggerRouter(); - - triggerRouter.setTrigger(triggerMapper.mapRow(rs, rowNum)); - triggerRouter.setRouter(routerMapper.mapRow(rs, rowNum)); - - triggerRouter.setCreateTime(rs.getTimestamp("create_time")); - triggerRouter.setLastUpdateTime(rs.getTimestamp("last_update_time")); - triggerRouter.setLastUpdateBy(rs.getString("last_update_by")); - triggerRouter.setInitialLoadOrder(rs.getInt("initial_load_order")); - triggerRouter.setInitialLoadSelect(rs.getString("initial_load_select")); - triggerRouter.setPingBackEnabled(rs.getBoolean("ping_back_enabled")); - - return triggerRouter; - } - } - - public void setRootConfigChannelTableNames(Map> configChannelTableNames) { - this.rootConfigChannelTableNames = configChannelTableNames; - } - - public void setClusterService(IClusterService clusterService) { - this.clusterService = clusterService; - } - - public void setConfigurationService(IConfigurationService configurationService) { - this.configurationService = configurationService; - } - - public void setTriggerCreationListeners( - List autoTriggerCreationListeners) { - if (triggerCreationListeners != null) { - for (ITriggerCreationListener l : triggerCreationListeners) { - addTriggerCreationListeners(l); - } - } - } - - public void addTriggerCreationListeners(ITriggerCreationListener l) { - if (this.triggerCreationListeners == null) { - this.triggerCreationListeners = new ArrayList(); - } - this.triggerCreationListeners.add(l); - } - + + public TriggerRouter mapRow(Row rs) { + TriggerRouter triggerRouter = new TriggerRouter(); + + triggerRouter.setTrigger(triggerMapper.mapRow(rs)); + triggerRouter.setRouter(routerMapper.mapRow(rs)); + + triggerRouter.setCreateTime(rs.getDateTime("create_time")); + triggerRouter.setLastUpdateTime(rs.getDateTime("last_update_time")); + triggerRouter.setLastUpdateBy(rs.getString("last_update_by")); + triggerRouter.setInitialLoadOrder(rs.getInt("initial_load_order")); + triggerRouter.setInitialLoadSelect(rs.getString("initial_load_select")); + triggerRouter.setPingBackEnabled(rs.getBoolean("ping_back_enabled")); + + return triggerRouter; + } + } + + public void setRootConfigChannelTableNames(Map> configChannelTableNames) { + this.rootConfigChannelTableNames = configChannelTableNames; + } + + public void setClusterService(IClusterService clusterService) { + this.clusterService = clusterService; + } + + public void setConfigurationService(IConfigurationService configurationService) { + this.configurationService = configurationService; + } + + public void setTriggerCreationListeners( + List autoTriggerCreationListeners) { + if (triggerCreationListeners != null) { + for (ITriggerCreationListener l : triggerCreationListeners) { + addTriggerCreationListeners(l); + } + } + } + + public void addTriggerCreationListeners(ITriggerCreationListener l) { + if (this.triggerCreationListeners == null) { + this.triggerCreationListeners = new ArrayList(); + } + this.triggerCreationListeners.add(l); + } + public void addExtraConfigTables(IExtraConfigTables extension) { this.extraConfigTables.add(extension); - } - - public Map getFailedTriggers() { - return this.failureListener.getFailures(); } - + + public Map getFailedTriggers() { + return this.failureListener.getFailures(); + } + public void setStatisticManager(IStatisticManager statisticManager) { this.statisticManager = statisticManager; - } - - class TriggerRoutersCache { - - public TriggerRoutersCache(Map> triggerRoutersByTriggerId, - Map routersByRouterId) { - this.triggerRoutersByTriggerId = triggerRoutersByTriggerId; - this.routersByRouterId = routersByRouterId; - } - - Map> triggerRoutersByTriggerId = new HashMap>(); - Map routersByRouterId = new HashMap(); - } - + } + + class TriggerRoutersCache { + + public TriggerRoutersCache(Map> triggerRoutersByTriggerId, + Map routersByRouterId) { + this.triggerRoutersByTriggerId = triggerRoutersByTriggerId; + this.routersByRouterId = routersByRouterId; + } + + Map> triggerRoutersByTriggerId = new HashMap>(); + Map routersByRouterId = new HashMap(); + } + } \ No newline at end of file diff --git a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/impl/UpgradeService.java b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/impl/UpgradeService.java deleted file mode 100644 index e929d53dfc..0000000000 --- a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/impl/UpgradeService.java +++ /dev/null @@ -1,121 +0,0 @@ -/* - * Licensed to JumpMind Inc under one or more contributor - * license agreements. See the NOTICE file distributed - * with this work for additional information regarding - * copyright ownership. JumpMind Inc licenses this file - * to you under the GNU Lesser General Public License (the - * "License"); you may not use this file except in compliance - * with the License. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see - * . - * - * 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.jumpmind.symmetric.service.impl; - -import java.util.List; -import java.util.Map; - -import org.apache.commons.lang.StringUtils; -import org.jumpmind.db.sql.AbstractSqlMap; -import org.jumpmind.symmetric.Version; -import org.jumpmind.symmetric.common.ParameterConstants; -import org.jumpmind.symmetric.model.Node; -import org.jumpmind.symmetric.service.INodeService; -import org.jumpmind.symmetric.service.IUpgradeService; -import org.jumpmind.symmetric.upgrade.IUpgradeTask; - -public class UpgradeService extends AbstractService implements IUpgradeService { - - private INodeService nodeService; - - private Map> upgradeTaskMap; - - @Override - protected AbstractSqlMap createSqlMap() { - return null; - } - - public boolean isUpgradeNecessary() { - boolean isUpgradeNecessary = false; - String symmetricVersion = nodeService.findSymmetricVersion(); - if (!StringUtils.isBlank(symmetricVersion) && !symmetricVersion.equals("development")) { - if (Version.isOlderVersion(symmetricVersion)) { - String nodeId = nodeService.findIdentityNodeId(); - if (nodeId != null) { - int[] fromVersion = Version.parseVersion(symmetricVersion); - isUpgradeNecessary = doUpgradeTasksExist(nodeId, fromVersion); - if (!isUpgradeNecessary && !parameterService.is(ParameterConstants.AUTO_CONFIGURE_DATABASE)) { - log.warn("UpgradeWarning", ParameterConstants.AUTO_CONFIGURE_DATABASE); - } - } - } - } - return isUpgradeNecessary; - } - - public boolean isUpgradePossible() { - String symmetricVersion = nodeService.findSymmetricVersion(); - if (!StringUtils.isBlank(symmetricVersion) && !symmetricVersion.equals("development")) { - return (Version.parseVersion(symmetricVersion)[0] > 1); - } else { - return true; - } - - } - - public void upgrade() { - String symmetricVersion = nodeService.findSymmetricVersion(); - String nodeId = nodeService.findIdentityNodeId(); - if (symmetricVersion != null && nodeId != null) { - int[] fromVersion = Version.parseVersion(symmetricVersion); - if (Version.isOlderVersion(symmetricVersion)) { - runUpgrade(nodeId, fromVersion); - Node node = nodeService.findIdentity(); - node.setSymmetricVersion(Version.version()); - nodeService.updateNode(node); - } - } else { - log.warn("NodeUpgradeFailed"); - } - } - - protected boolean doUpgradeTasksExist(String nodeId, int[] fromVersion) { - String majorMinorVersion = fromVersion[0] + "." + fromVersion[1]; - List upgradeTaskList = upgradeTaskMap.get(majorMinorVersion); - return upgradeTaskList != null && upgradeTaskList.size() > 0; - } - - private void runUpgrade(String nodeId, int[] fromVersion) { - String majorMinorVersion = fromVersion[0] + "." + fromVersion[1]; - List upgradeTaskList = upgradeTaskMap.get(majorMinorVersion); - log.warn("NodeUpgradeStarting", majorMinorVersion, Version.version()); - boolean isRegistrationServer = StringUtils.isEmpty(parameterService.getRegistrationUrl()); - if (upgradeTaskList != null) { - for (IUpgradeTask upgradeTask : upgradeTaskList) { - if ((isRegistrationServer && upgradeTask.isUpgradeRegistrationServer()) - || (!isRegistrationServer && upgradeTask.isUpgradeNonRegistrationServer())) { - upgradeTask.upgrade(nodeId, parameterService, fromVersion); - } - } - } - log.warn("NodeUpgradeCompleted"); - } - - public void setUpgradeTaskMap(Map> upgradeTaskMap) { - this.upgradeTaskMap = upgradeTaskMap; - } - - public void setNodeService(INodeService nodeService) { - this.nodeService = nodeService; - } - -} \ No newline at end of file diff --git a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/jmx/IncomingManagementService.java b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/jmx/IncomingManagementService.java deleted file mode 100644 index c66f7c647a..0000000000 --- a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/jmx/IncomingManagementService.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Licensed to JumpMind Inc under one or more contributor - * license agreements. See the NOTICE file distributed - * with this work for additional information regarding - * copyright ownership. JumpMind Inc licenses this file - * to you under the GNU Lesser General Public License (the - * "License"); you may not use this file except in compliance - * with the License. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see - * . - * - * 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.jumpmind.symmetric.service.jmx; - -import org.jumpmind.symmetric.statistic.IStatisticManager; -import org.springframework.jmx.export.annotation.ManagedResource; - -@ManagedResource(description = "The management interface for incoming synchronization") -/** - * - */ -public class IncomingManagementService { - - protected IStatisticManager statisticManager; - - public void setStatisticManager(IStatisticManager statisticManager) { - this.statisticManager = statisticManager; - } - -} \ No newline at end of file diff --git a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/jmx/NodeManagementService.java b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/jmx/NodeManagementService.java index ae5d4ccbc8..50244d6ca8 100644 --- a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/jmx/NodeManagementService.java +++ b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/jmx/NodeManagementService.java @@ -16,429 +16,339 @@ * "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.jumpmind.symmetric.service.jmx; - -import java.io.FileOutputStream; -import java.text.DateFormat; -import java.text.NumberFormat; -import java.util.Date; -import java.util.Map; - -import javax.sql.DataSource; - -import org.apache.commons.dbcp.BasicDataSource; -import org.apache.commons.lang.NotImplementedException; -import org.apache.commons.lang.StringUtils; -import org.jumpmind.symmetric.AbstractSymmetricEngine; -import org.jumpmind.symmetric.ISymmetricEngine; -import org.jumpmind.symmetric.common.ParameterConstants; -import org.jumpmind.symmetric.common.SecurityConstants; -import org.jumpmind.symmetric.common.logging.ILog; -import org.jumpmind.symmetric.common.logging.LogFactory; -import org.jumpmind.symmetric.model.Node; -import org.jumpmind.symmetric.service.IClusterService; -import org.jumpmind.symmetric.service.IConfigurationService; -import org.jumpmind.symmetric.service.IDataExtractorService; -import org.jumpmind.symmetric.service.IDataService; -import org.jumpmind.symmetric.service.INodeService; -import org.jumpmind.symmetric.service.IOutgoingBatchService; -import org.jumpmind.symmetric.service.IParameterService; -import org.jumpmind.symmetric.service.IPurgeService; -import org.jumpmind.symmetric.service.IRegistrationService; -import org.jumpmind.symmetric.service.ISecurityService; -import org.jumpmind.symmetric.service.ITriggerRouterService; -import org.jumpmind.symmetric.statistic.IStatisticManager; -import org.jumpmind.symmetric.transport.ConcurrentConnectionManager.NodeConnectionStatistics; -import org.jumpmind.symmetric.transport.IConcurrentConnectionManager; -import org.jumpmind.symmetric.transport.IOutgoingTransport; -import org.jumpmind.symmetric.transport.internal.InternalOutgoingTransport; -import org.springframework.jmx.export.annotation.ManagedAttribute; -import org.springframework.jmx.export.annotation.ManagedOperation; -import org.springframework.jmx.export.annotation.ManagedOperationParameter; -import org.springframework.jmx.export.annotation.ManagedOperationParameters; -import org.springframework.jmx.export.annotation.ManagedResource; - -@ManagedResource(description = "The management interface for a node") -/** - * , + * under the License. */ -public class NodeManagementService { - - final ILog log = LogFactory.getLog(getClass()); - - private IPurgeService purgeService; - - private INodeService nodeService; - - private IDataService dataService; - - private IOutgoingBatchService outgoingBatchService; - - private IConfigurationService configurationService; - - private ITriggerRouterService triggerRouterService; - - private IRegistrationService registrationService; - - private IDataExtractorService dataExtractorService; - - private IClusterService clusterService; - - private IParameterService parameterService; - - private IConcurrentConnectionManager concurrentConnectionManager; - - private ISecurityService securityService; - - private DataSource dataSource; - - IStatisticManager statisticManager; - - public void setStatisticManager(IStatisticManager statisticManager) { - this.statisticManager = statisticManager; - } - - @ManagedAttribute(description = "Checks if SymmetricDS has been started.") - public boolean isStarted() { - ISymmetricEngine engine = getEngine(); - if (engine != null) { - return engine.isStarted(); - } else { - return false; - } - } - - @ManagedOperation(description = "Start the SymmetricDS engine") - public boolean start() { - try { - ISymmetricEngine engine = getEngine(); - if (engine != null) { - return engine.start(); - } else { - return false; - } - } catch (Exception ex) { - log.error(ex); - return false; - } - } - - @ManagedOperation(description = "Stop the SymmetricDS engine") - public void stop() { - try { - ISymmetricEngine engine = getEngine(); - if (engine != null) { - engine.stop(); - } - } catch (Exception ex) { - log.error(ex); - } - } - - @ManagedOperation(description = "Run the purge process") - public void purge() { - purgeService.purgeOutgoing(); - } - - @ManagedOperation(description = "Force the channel settings to be read from the database") - public void clearChannelCache() { - configurationService.reloadChannels(); - } - - @ManagedOperation(description = "Synchronize the triggers") - public void syncTriggers() { - triggerRouterService.syncTriggers(); - } - - protected ISymmetricEngine getEngine() { - return AbstractSymmetricEngine.findEngineByName(parameterService.getString(ParameterConstants.ENGINE_NAME)); - } - - @ManagedAttribute(description = "Get the number of current connections allowed to this " - + "instance of the node via HTTP. If this value is 20, then 20 concurrent push" - + " clients and 20 concurrent pull clients will be allowed") - public int getNumfNodeConnectionsPerInstance() { - return parameterService.getInt(ParameterConstants.CONCURRENT_WORKERS); - } - - @ManagedAttribute(description = "Get connection statistics about indivdual nodes") - public String getNodeConcurrencyStatisticsAsText() { - String lineFeed = "\n"; - if (parameterService.getString(ParameterConstants.JMX_LINE_FEED).equals("html")) { - lineFeed = "
"; - } - Map> stats = concurrentConnectionManager - .getNodeConnectionStatisticsByPoolByNodeId(); - StringBuilder out = new StringBuilder(); - for (String pool : stats.keySet()) { - out - .append("-------------------------------------------------------------------------------------------------------------------------------"); out.append(lineFeed); - out.append(" CONNECTION TYPE: "); - out.append(pool); - out.append(lineFeed); - out - .append("-------------------------------------------------------------------------------------------------------------------------------"); - out.append(lineFeed); - out - .append(" NODE ID LAST CONNECT TIME NUMBER OF CONNECTIONS NUMBER OF REJECTIONS AVG CONNECTED TIME"); - out.append(lineFeed); - out - .append("-------------------------------------------------------------------------------------------------------------------------------"); out.append(lineFeed); - Map nodeStats = stats.get(pool); - for (String nodeId : nodeStats.keySet()) { - NodeConnectionStatistics nodeStat = nodeStats.get(nodeId); - out.append(StringUtils.leftPad(nodeId, 20)); - out.append(StringUtils.leftPad(DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.MEDIUM).format( - new Date(nodeStat.getLastConnectionTimeMs())), 30)); - out.append(StringUtils.leftPad(Long.toString(nodeStat.getTotalConnectionCount()), 27)); - out.append(StringUtils.leftPad(Integer.toString(nodeStat.getNumOfRejections()), 25)); - out.append(StringUtils.leftPad(NumberFormat.getIntegerInstance().format( - nodeStat.getTotalConnectionTimeMs() / nodeStat.getTotalConnectionCount()), 25)); - } - out.append(lineFeed); - } - return out.toString(); - } - - public String getCurrentNodeConcurrencyReservationsAsText() { - throw new NotImplementedException(); - } - - @ManagedAttribute(description = "Get a list of nodes that have been added to the white list, a list of node ids that always get through the concurrency manager.") - public String getNodesInWhiteList() { - StringBuilder ret = new StringBuilder(); - String[] list = concurrentConnectionManager.getWhiteList(); - for (String string : list) { - ret.append(string); - ret.append(","); - } - return ret.length() > 0 ? ret.substring(0, ret.length() - 1) : ""; - } - - @ManagedOperation(description = "Add a node id to the list of nodes that will always get through the concurrency manager") - @ManagedOperationParameters( { @ManagedOperationParameter(name = "nodeId", description = "The node id to add to the white list") }) - public void addNodeToWhiteList(String nodeId) { - concurrentConnectionManager.addToWhitelist(nodeId); - } - - @ManagedOperation(description = "Remove a node id to the list of nodes that will always get through the concurrency manager") - @ManagedOperationParameters( { @ManagedOperationParameter(name = "nodeId", description = "The node id to remove from the white list") }) - public void removeNodeFromWhiteList(String nodeId) { - concurrentConnectionManager.removeFromWhiteList(nodeId); - } - - @ManagedAttribute(description = "Configure the number of connections allowed to this node." - + " If the value is set to zero you are effectively disabling your transport" - + " (wihch can be useful for maintainance") - public void setNumOfNodeConnectionsPerInstance(int value) { - parameterService.saveParameter(ParameterConstants.CONCURRENT_WORKERS, value); - } - - @ManagedAttribute(description = "The group this node belongs to") - public String getNodeGroupId() { - return parameterService.getNodeGroupId(); - } - - @ManagedAttribute(description = "An external name given to this SymmetricDS node") - public String getExternalId() { - return parameterService.getExternalId(); - } - - @ManagedAttribute(description = "The node id given to this SymmetricDS node") - public String getNodeId() { - Node node = nodeService.findIdentity(); - if (node != null) { - return node.getNodeId(); - } else { - return "?"; - } - } - - @ManagedAttribute(description = "Whether the basic DataSource is being used as the default datasource.") - public boolean isBasicDataSource() { - return dataSource instanceof BasicDataSource; - } - - @ManagedAttribute(description = "If a BasicDataSource, then show the number of active connections") - public int getNumberOfActiveConnections() { - if (isBasicDataSource()) { - return ((BasicDataSource) dataSource).getNumActive(); - } else { - return -1; - } - } - - @ManagedOperation(description = "Check to see if the external id is registered") - @ManagedOperationParameters( { - @ManagedOperationParameter(name = "nodeGroupId", description = "The node group id for a node"), - @ManagedOperationParameter(name = "externalId", description = "The external id for a node") }) - public boolean isExternalIdRegistered(String nodeGroupdId, String externalId) { - return nodeService.isExternalIdRegistered(nodeGroupdId, externalId); - } - - @ManagedOperation(description = "Emergency remove all locks (if left abandoned on a cluster)") - public void clearAllLocks() { - clusterService.clearAllLocks(); - } - - @ManagedOperation(description = "Check to see if the initial load for a node id is complete. This method will throw an exception if the load error'd out or was never started.") - @ManagedOperationParameters( { @ManagedOperationParameter(name = "nodeId", description = "The node id") }) - public boolean areAllLoadBatchesComplete(String nodeId) { - return outgoingBatchService.areAllLoadBatchesComplete(nodeId); - } - - @ManagedOperation(description = "Enable or disable synchronization completely for a node") - @ManagedOperationParameters( { - @ManagedOperationParameter(name = "nodeId", description = "The node to enable or disable"), - @ManagedOperationParameter(name = "syncEnabled", description = "true is enabled, false is disabled") }) - public boolean setSyncEnabledForNode(String nodeId, boolean syncEnabled) { - Node node = nodeService.findNode(nodeId); - if (node != null) { - node.setSyncEnabled(syncEnabled); - nodeService.updateNode(node); - return true; - } else { - return false; - } - } - - @ManagedOperation(description = "Enable or disable a channel for a specific external id") - @ManagedOperationParameters( { - @ManagedOperationParameter(name = "ignore", description = "Set to true to enable and false to disable"), - @ManagedOperationParameter(name = "channelId", description = "The channel id to enable or disable"), - @ManagedOperationParameter(name = "nodeGroupId", description = "The node group id for a node"), - @ManagedOperationParameter(name = "externalId", description = "The external id for a node") }) - public void ignoreNodeChannelForExternalId(boolean ignore, String channelId, String nodeGroupId, String externalId) { - nodeService.ignoreNodeChannelForExternalId(ignore, channelId, nodeGroupId, externalId); - } - - @ManagedOperation(description = "Open the registration for a node with the specified external id") - @ManagedOperationParameters( { - @ManagedOperationParameter(name = "nodeGroup", description = "The node group id this node will belong to"), - @ManagedOperationParameter(name = "externalId", description = "The external id for the node") }) - public void openRegistration(String nodeGroupId, String externalId) { - Node node = nodeService.findNodeByExternalId(nodeGroupId, externalId); - if (node != null) { - registrationService.reOpenRegistration(node.getExternalId()); - } else { - registrationService.openRegistration(nodeGroupId, externalId); - } - } - - @ManagedOperation(description = "Send an initial load of data to a node.") - @ManagedOperationParameters( { @ManagedOperationParameter(name = "nodeId", description = "The node id to reload.") }) - public String reloadNode(String nodeId) { - return dataService.reloadNode(nodeId); - } - - @ManagedOperation(description = "Send a SQL event to a node.") - @ManagedOperationParameters( { - @ManagedOperationParameter(name = "nodeId", description = "The node id to sent the event to."), - @ManagedOperationParameter(name = "catalogName", description = "The catalog name to reload. Can be null."), - @ManagedOperationParameter(name = "schemaName", description = "The schema name to reload. Can be null."), - @ManagedOperationParameter(name = "tableName", description = "The table name the SQL is for."), - @ManagedOperationParameter(name = "sql", description = "The SQL statement to send.") }) - public String sendSQL(String nodeId, String catalogName, String schemaName, String tableName, String sql) { - return dataService.sendSQL(nodeId, catalogName, schemaName, tableName, sql, false); - } - - @ManagedOperation(description = "Send a delete and reload of a table to a node.") - @ManagedOperationParameters( { @ManagedOperationParameter(name = "nodeId", description = "The node id to reload."), - @ManagedOperationParameter(name = "catalogName", description = "The catalog name to reload. Can be null."), - @ManagedOperationParameter(name = "schemaName", description = "The schema name to reload. Can be null."), - @ManagedOperationParameter(name = "tableName", description = "The table name to reload.") }) - public String reloadTable(String nodeId, String catalogName, String schemaName, String tableName) { - return dataService.reloadTable(nodeId, catalogName, schemaName, tableName); - } - - @ManagedOperation(description = "Send a delete and reload of a table to a node.") - @ManagedOperationParameters( { - @ManagedOperationParameter(name = "nodeId", description = "The node id to reload."), - @ManagedOperationParameter(name = "catalogName", description = "The catalog name to reload. Can be null."), - @ManagedOperationParameter(name = "schemaName", description = "The schema name to reload. Can be null."), - @ManagedOperationParameter(name = "tableName", description = "The table name to reload."), - @ManagedOperationParameter(name = "overrideInitialLoadSelect", description = "Override initial load select where-clause.") }) - public String reloadTable(String nodeId, String catalogName, String schemaName, String tableName, String overrideInitialLoadSelect) { - return dataService.reloadTable(nodeId, catalogName, schemaName, tableName, overrideInitialLoadSelect); - } - - @ManagedOperation(description = "Write a range of batches to a file in SymmetricDS Data Format.") - @ManagedOperationParameters( { - @ManagedOperationParameter(name = "startBatchId", description = "Starting batch ID of range"), - @ManagedOperationParameter(name = "endBatchId", description = "Ending batch ID of range"), - @ManagedOperationParameter(name = "fileName", description = "File name to write batches") }) - public void writeBatchRangeToFile(String startBatchId, String endBatchId, String fileName) throws Exception { - FileOutputStream out = new FileOutputStream(fileName); - IOutgoingTransport transport = new InternalOutgoingTransport(out); - dataExtractorService.extractBatchRange(transport, startBatchId, endBatchId); - transport.close(); - out.close(); - } - - @ManagedOperation(description = "Encrypts plain text for use with db.user and db.password properties") - @ManagedOperationParameters( { - @ManagedOperationParameter(name = "plainText", description = "Plain text to encrypt") }) - public String encryptText(String plainText) throws Exception { - try { - return SecurityConstants.PREFIX_ENC + securityService.encrypt(plainText); - } - catch (Exception e) - { - e.printStackTrace(); - } - return ""; - } - public void setPurgeService(IPurgeService purgeService) { - this.purgeService = purgeService; - } - - public void setDataSource(DataSource dataSource) { - this.dataSource = dataSource; - } - - public void setDataService(IDataService dataService) { - this.dataService = dataService; - } - - public void setNodeService(INodeService nodeService) { - this.nodeService = nodeService; - } - - public void setRegistrationService(IRegistrationService registrationService) { - this.registrationService = registrationService; - } - - public void setOutgoingBatchService(IOutgoingBatchService outgoingBatchService) { - this.outgoingBatchService = outgoingBatchService; - } - - public void setDataExtractorService(IDataExtractorService dataExtractorService) { - this.dataExtractorService = dataExtractorService; - } - - public void setClusterService(IClusterService clusterService) { - this.clusterService = clusterService; - } - - public void setParameterService(IParameterService parameterService) { - this.parameterService = parameterService; - } - - public void setConcurrentConnectionManager(IConcurrentConnectionManager concurrentConnectionManager) { - this.concurrentConnectionManager = concurrentConnectionManager; - } - - public void setSecurityService(ISecurityService securityService) { - this.securityService = securityService; - } - - public void setConfigurationService(IConfigurationService configurationService) { - this.configurationService = configurationService; - } - - public void setTriggerRouterService(ITriggerRouterService triggerService) { - this.triggerRouterService = triggerService; - } + +package org.jumpmind.symmetric.service.jmx; + +import java.io.FileOutputStream; +import java.text.DateFormat; +import java.text.NumberFormat; +import java.util.Date; +import java.util.Map; + +import javax.sql.DataSource; + +import org.apache.commons.dbcp.BasicDataSource; +import org.apache.commons.lang.NotImplementedException; +import org.apache.commons.lang.StringUtils; +import org.jumpmind.symmetric.ClientSymmetricEngine; +import org.jumpmind.symmetric.common.ParameterConstants; +import org.jumpmind.symmetric.common.SecurityConstants; +import org.jumpmind.symmetric.common.logging.ILog; +import org.jumpmind.symmetric.common.logging.LogFactory; +import org.jumpmind.symmetric.model.Node; +import org.jumpmind.symmetric.transport.ConcurrentConnectionManager.NodeConnectionStatistics; +import org.jumpmind.symmetric.transport.IOutgoingTransport; +import org.jumpmind.symmetric.transport.internal.InternalOutgoingTransport; +import org.springframework.jmx.export.annotation.ManagedAttribute; +import org.springframework.jmx.export.annotation.ManagedOperation; +import org.springframework.jmx.export.annotation.ManagedOperationParameter; +import org.springframework.jmx.export.annotation.ManagedOperationParameters; +import org.springframework.jmx.export.annotation.ManagedResource; + +@ManagedResource(description = "The management interface for a node") +public class NodeManagementService { + + final ILog log = LogFactory.getLog(getClass()); + + protected ClientSymmetricEngine engine; + + public NodeManagementService(ClientSymmetricEngine engine) { + this.engine = engine; + } + + @ManagedAttribute(description = "Checks if SymmetricDS has been started.") + public boolean isStarted() { + if (engine != null) { + return engine.isStarted(); + } else { + return false; + } + } + + @ManagedOperation(description = "Start the SymmetricDS engine") + public boolean start() { + try { + if (engine != null) { + return engine.start(); + } else { + return false; + } + } catch (Exception ex) { + log.error(ex); + return false; + } + } + + @ManagedOperation(description = "Stop the SymmetricDS engine") + public void stop() { + try { + if (engine != null) { + engine.stop(); + } + } catch (Exception ex) { + log.error(ex); + } + } + + @ManagedOperation(description = "Run the purge process") + public void purge() { + engine.getPurgeService().purgeOutgoing(); + } + + @ManagedOperation(description = "Force the channel settings to be read from the database") + public void clearChannelCache() { + engine.getConfigurationService().reloadChannels(); + } + + @ManagedOperation(description = "Synchronize the triggers") + public void syncTriggers() { + engine.getTriggerRouterService().syncTriggers(); + } + + @ManagedAttribute(description = "Get the number of current connections allowed to this " + + "instance of the node via HTTP. If this value is 20, then 20 concurrent push" + + " clients and 20 concurrent pull clients will be allowed") + public int getNumfNodeConnectionsPerInstance() { + return engine.getParameterService().getInt(ParameterConstants.CONCURRENT_WORKERS); + } + + @ManagedAttribute(description = "Get connection statistics about indivdual nodes") + public String getNodeConcurrencyStatisticsAsText() { + String lineFeed = "\n"; + if (engine.getParameterService().getString(ParameterConstants.JMX_LINE_FEED).equals("html")) { + lineFeed = "
"; + } + Map> stats = engine + .getConcurrentConnectionManager().getNodeConnectionStatisticsByPoolByNodeId(); + StringBuilder out = new StringBuilder(); + for (String pool : stats.keySet()) { + out.append("-------------------------------------------------------------------------------------------------------------------------------"); + out.append(lineFeed); + out.append(" CONNECTION TYPE: "); + out.append(pool); + out.append(lineFeed); + out.append("-------------------------------------------------------------------------------------------------------------------------------"); + out.append(lineFeed); + out.append(" NODE ID LAST CONNECT TIME NUMBER OF CONNECTIONS NUMBER OF REJECTIONS AVG CONNECTED TIME"); + out.append(lineFeed); + out.append("-------------------------------------------------------------------------------------------------------------------------------"); + out.append(lineFeed); + Map nodeStats = stats.get(pool); + for (String nodeId : nodeStats.keySet()) { + NodeConnectionStatistics nodeStat = nodeStats.get(nodeId); + out.append(StringUtils.leftPad(nodeId, 20)); + out.append(StringUtils.leftPad( + DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.MEDIUM) + .format(new Date(nodeStat.getLastConnectionTimeMs())), 30)); + out.append(StringUtils.leftPad(Long.toString(nodeStat.getTotalConnectionCount()), + 27)); + out.append(StringUtils.leftPad(Integer.toString(nodeStat.getNumOfRejections()), 25)); + out.append(StringUtils.leftPad( + NumberFormat.getIntegerInstance().format( + nodeStat.getTotalConnectionTimeMs() + / nodeStat.getTotalConnectionCount()), 25)); + } + out.append(lineFeed); + } + return out.toString(); + } + + public String getCurrentNodeConcurrencyReservationsAsText() { + throw new NotImplementedException(); + } + + @ManagedAttribute(description = "Get a list of nodes that have been added to the white list, a list of node ids that always get through the concurrency manager.") + public String getNodesInWhiteList() { + StringBuilder ret = new StringBuilder(); + String[] list = engine.getConcurrentConnectionManager().getWhiteList(); + for (String string : list) { + ret.append(string); + ret.append(","); + } + return ret.length() > 0 ? ret.substring(0, ret.length() - 1) : ""; + } + + @ManagedOperation(description = "Add a node id to the list of nodes that will always get through the concurrency manager") + @ManagedOperationParameters({ @ManagedOperationParameter(name = "nodeId", description = "The node id to add to the white list") }) + public void addNodeToWhiteList(String nodeId) { + engine.getConcurrentConnectionManager().addToWhitelist(nodeId); + } + + @ManagedOperation(description = "Remove a node id to the list of nodes that will always get through the concurrency manager") + @ManagedOperationParameters({ @ManagedOperationParameter(name = "nodeId", description = "The node id to remove from the white list") }) + public void removeNodeFromWhiteList(String nodeId) { + engine.getConcurrentConnectionManager().removeFromWhiteList(nodeId); + } + + @ManagedAttribute(description = "Configure the number of connections allowed to this node." + + " If the value is set to zero you are effectively disabling your transport" + + " (wihch can be useful for maintainance") + public void setNumOfNodeConnectionsPerInstance(int value) { + engine.getParameterService().saveParameter(ParameterConstants.CONCURRENT_WORKERS, value); + } + + @ManagedAttribute(description = "The group this node belongs to") + public String getNodeGroupId() { + return engine.getParameterService().getNodeGroupId(); + } + + @ManagedAttribute(description = "An external name given to this SymmetricDS node") + public String getExternalId() { + return engine.getParameterService().getExternalId(); + } + + @ManagedAttribute(description = "The node id given to this SymmetricDS node") + public String getNodeId() { + Node node = engine.getNodeService().findIdentity(); + if (node != null) { + return node.getNodeId(); + } else { + return "?"; + } + } + + @ManagedAttribute(description = "Whether the basic DataSource is being used as the default datasource.") + public boolean isBasicDataSource() { + DataSource dataSource = engine.getDataSource(); + return dataSource instanceof BasicDataSource; + } + + @ManagedAttribute(description = "If a BasicDataSource, then show the number of active connections") + public int getNumberOfActiveConnections() { + if (isBasicDataSource()) { + DataSource dataSource = engine.getDataSource(); + return ((BasicDataSource) dataSource).getNumActive(); + } else { + return -1; + } + } + + @ManagedOperation(description = "Check to see if the external id is registered") + @ManagedOperationParameters({ + @ManagedOperationParameter(name = "nodeGroupId", description = "The node group id for a node"), + @ManagedOperationParameter(name = "externalId", description = "The external id for a node") }) + public boolean isExternalIdRegistered(String nodeGroupdId, String externalId) { + return engine.getNodeService().isExternalIdRegistered(nodeGroupdId, externalId); + } + + @ManagedOperation(description = "Emergency remove all locks (if left abandoned on a cluster)") + public void clearAllLocks() { + engine.getClusterService().clearAllLocks(); + } + + @ManagedOperation(description = "Check to see if the initial load for a node id is complete. This method will throw an exception if the load error'd out or was never started.") + @ManagedOperationParameters({ @ManagedOperationParameter(name = "nodeId", description = "The node id") }) + public boolean areAllLoadBatchesComplete(String nodeId) { + return engine.getOutgoingBatchService().areAllLoadBatchesComplete(nodeId); + } + + @ManagedOperation(description = "Enable or disable synchronization completely for a node") + @ManagedOperationParameters({ + @ManagedOperationParameter(name = "nodeId", description = "The node to enable or disable"), + @ManagedOperationParameter(name = "syncEnabled", description = "true is enabled, false is disabled") }) + public boolean setSyncEnabledForNode(String nodeId, boolean syncEnabled) { + Node node = engine.getNodeService().findNode(nodeId); + if (node != null) { + node.setSyncEnabled(syncEnabled); + engine.getNodeService().updateNode(node); + return true; + } else { + return false; + } + } + + @ManagedOperation(description = "Enable or disable a channel for a specific external id") + @ManagedOperationParameters({ + @ManagedOperationParameter(name = "ignore", description = "Set to true to enable and false to disable"), + @ManagedOperationParameter(name = "channelId", description = "The channel id to enable or disable"), + @ManagedOperationParameter(name = "nodeGroupId", description = "The node group id for a node"), + @ManagedOperationParameter(name = "externalId", description = "The external id for a node") }) + public void ignoreNodeChannelForExternalId(boolean ignore, String channelId, + String nodeGroupId, String externalId) { + engine.getNodeService().ignoreNodeChannelForExternalId(ignore, channelId, nodeGroupId, + externalId); + } + + @ManagedOperation(description = "Open the registration for a node with the specified external id") + @ManagedOperationParameters({ + @ManagedOperationParameter(name = "nodeGroup", description = "The node group id this node will belong to"), + @ManagedOperationParameter(name = "externalId", description = "The external id for the node") }) + public void openRegistration(String nodeGroupId, String externalId) { + Node node = engine.getNodeService().findNodeByExternalId(nodeGroupId, externalId); + if (node != null) { + engine.getRegistrationService().reOpenRegistration(node.getExternalId()); + } else { + engine.getRegistrationService().openRegistration(nodeGroupId, externalId); + } + } + + @ManagedOperation(description = "Send an initial load of data to a node.") + @ManagedOperationParameters({ @ManagedOperationParameter(name = "nodeId", description = "The node id to reload.") }) + public String reloadNode(String nodeId) { + return engine.getDataService().reloadNode(nodeId); + } + + @ManagedOperation(description = "Send a SQL event to a node.") + @ManagedOperationParameters({ + @ManagedOperationParameter(name = "nodeId", description = "The node id to sent the event to."), + @ManagedOperationParameter(name = "catalogName", description = "The catalog name to reload. Can be null."), + @ManagedOperationParameter(name = "schemaName", description = "The schema name to reload. Can be null."), + @ManagedOperationParameter(name = "tableName", description = "The table name the SQL is for."), + @ManagedOperationParameter(name = "sql", description = "The SQL statement to send.") }) + public String sendSQL(String nodeId, String catalogName, String schemaName, String tableName, + String sql) { + return engine.getDataService().sendSQL(nodeId, catalogName, schemaName, tableName, sql, + false); + } + + @ManagedOperation(description = "Send a delete and reload of a table to a node.") + @ManagedOperationParameters({ + @ManagedOperationParameter(name = "nodeId", description = "The node id to reload."), + @ManagedOperationParameter(name = "catalogName", description = "The catalog name to reload. Can be null."), + @ManagedOperationParameter(name = "schemaName", description = "The schema name to reload. Can be null."), + @ManagedOperationParameter(name = "tableName", description = "The table name to reload.") }) + public String reloadTable(String nodeId, String catalogName, String schemaName, String tableName) { + return engine.getDataService().reloadTable(nodeId, catalogName, schemaName, tableName); + } + + @ManagedOperation(description = "Send a delete and reload of a table to a node.") + @ManagedOperationParameters({ + @ManagedOperationParameter(name = "nodeId", description = "The node id to reload."), + @ManagedOperationParameter(name = "catalogName", description = "The catalog name to reload. Can be null."), + @ManagedOperationParameter(name = "schemaName", description = "The schema name to reload. Can be null."), + @ManagedOperationParameter(name = "tableName", description = "The table name to reload."), + @ManagedOperationParameter(name = "overrideInitialLoadSelect", description = "Override initial load select where-clause.") }) + public String reloadTable(String nodeId, String catalogName, String schemaName, + String tableName, String overrideInitialLoadSelect) { + return engine.getDataService().reloadTable(nodeId, catalogName, schemaName, tableName, + overrideInitialLoadSelect); + } + + @ManagedOperation(description = "Write a range of batches to a file in SymmetricDS Data Format.") + @ManagedOperationParameters({ + @ManagedOperationParameter(name = "startBatchId", description = "Starting batch ID of range"), + @ManagedOperationParameter(name = "endBatchId", description = "Ending batch ID of range"), + @ManagedOperationParameter(name = "fileName", description = "File name to write batches") }) + public void writeBatchRangeToFile(String startBatchId, String endBatchId, String fileName) + throws Exception { + FileOutputStream out = new FileOutputStream(fileName); + IOutgoingTransport transport = new InternalOutgoingTransport(out); + engine.getDataExtractorService().extractBatchRange(transport, startBatchId, endBatchId); + transport.close(); + out.close(); + } + + @ManagedOperation(description = "Encrypts plain text for use with db.user and db.password properties") + @ManagedOperationParameters({ @ManagedOperationParameter(name = "plainText", description = "Plain text to encrypt") }) + public String encryptText(String plainText) throws Exception { + try { + return SecurityConstants.PREFIX_ENC + engine.getSecurityService().encrypt(plainText); + } catch (Exception e) { + e.printStackTrace(); + } + return ""; + } + } \ No newline at end of file diff --git a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/jmx/NotificationService.java b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/jmx/NotificationService.java deleted file mode 100644 index be621fd8e1..0000000000 --- a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/jmx/NotificationService.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Licensed to JumpMind Inc under one or more contributor - * license agreements. See the NOTICE file distributed - * with this work for additional information regarding - * copyright ownership. JumpMind Inc licenses this file - * to you under the GNU Lesser General Public License (the - * "License"); you may not use this file except in compliance - * with the License. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see - * . - * - * 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.jumpmind.symmetric.service.jmx; - -import javax.management.Notification; - -import org.jumpmind.symmetric.common.logging.ILog; -import org.jumpmind.symmetric.common.logging.LogFactory; -import org.jumpmind.symmetric.service.INotificationService; -import org.springframework.jmx.export.annotation.ManagedResource; -import org.springframework.jmx.export.notification.NotificationPublisher; -import org.springframework.jmx.export.notification.NotificationPublisherAware; - -@ManagedResource(description = "Provide an implementation of SymmetricDS notifications by JMX") -public class NotificationService implements NotificationPublisherAware, INotificationService { - - static final ILog log = LogFactory.getLog(NotificationService.class); - - NotificationPublisher notificationPublisher; - - public void setNotificationPublisher(NotificationPublisher notificationPublisher) { - this.notificationPublisher = notificationPublisher; - } - - public void sendNotification(Notification event) { - log.warn("JMXNotificationSending", event.getMessage()); - this.notificationPublisher.sendNotification(event); - } - -} \ No newline at end of file diff --git a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/jmx/OutgoingManagementService.java b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/jmx/OutgoingManagementService.java deleted file mode 100644 index a9b93dc5af..0000000000 --- a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/jmx/OutgoingManagementService.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Licensed to JumpMind Inc under one or more contributor - * license agreements. See the NOTICE file distributed - * with this work for additional information regarding - * copyright ownership. JumpMind Inc licenses this file - * to you under the GNU Lesser General Public License (the - * "License"); you may not use this file except in compliance - * with the License. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see - * . - * - * 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.jumpmind.symmetric.service.jmx; - -import java.io.ByteArrayOutputStream; - -import org.jumpmind.symmetric.service.IDataExtractorService; -import org.jumpmind.symmetric.statistic.IStatisticManager; -import org.jumpmind.symmetric.transport.IOutgoingTransport; -import org.jumpmind.symmetric.transport.internal.InternalOutgoingTransport; -import org.springframework.jmx.export.annotation.ManagedOperation; -import org.springframework.jmx.export.annotation.ManagedOperationParameter; -import org.springframework.jmx.export.annotation.ManagedOperationParameters; -import org.springframework.jmx.export.annotation.ManagedResource; - -@ManagedResource(description = "The management interface for outgoing synchronization") -/** - * - */ -public class OutgoingManagementService { - - protected IStatisticManager statisticManager; - - protected IDataExtractorService dataExtractorService; - - public void setStatisticManager(IStatisticManager statisticManager) { - this.statisticManager = statisticManager; - } - - @ManagedOperation(description = "Show a batch in SymmetricDS Data Format.") - @ManagedOperationParameters( { @ManagedOperationParameter(name = "batchId", description = "The batch ID to display") }) - public String showBatch(String batchId) throws Exception { - ByteArrayOutputStream out = new ByteArrayOutputStream(); - IOutgoingTransport transport = new InternalOutgoingTransport(out,null); - dataExtractorService.extractBatchRange(transport, batchId, batchId); - transport.close(); - out.close(); - return out.toString(); - } - - public void setDataExtractorService(IDataExtractorService dataExtractorService) { - this.dataExtractorService = dataExtractorService; - } -} \ No newline at end of file diff --git a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/jmx/ParameterManagementService.java b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/jmx/ParameterManagementService.java index 2198ff7850..4cb424d36d 100644 --- a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/jmx/ParameterManagementService.java +++ b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/service/jmx/ParameterManagementService.java @@ -16,79 +16,79 @@ * "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.jumpmind.symmetric.service.jmx; - -import java.util.Map; - -import org.jumpmind.symmetric.common.ParameterConstants; -import org.jumpmind.symmetric.service.IParameterService; -import org.springframework.jmx.export.annotation.ManagedAttribute; -import org.springframework.jmx.export.annotation.ManagedOperation; -import org.springframework.jmx.export.annotation.ManagedOperationParameter; -import org.springframework.jmx.export.annotation.ManagedOperationParameters; -import org.springframework.jmx.export.annotation.ManagedResource; - -@ManagedResource(description = "The management interface for node parameters") -/** - * + * under the License. */ -public class ParameterManagementService { - - private IParameterService parameterService; - - @ManagedOperation(description = "Reload supported parameters from file or database") - public void rereadParameters() { - this.parameterService.rereadParameters(); - } - - @ManagedOperation(description = "Update a parameter for this node only") - @ManagedOperationParameters( { @ManagedOperationParameter(name = "key", description = "The name of the parameter"), - @ManagedOperationParameter(name = "value", description = "The value for the parameter") }) - public void updateParameter(String key, String value) { - this.parameterService.saveParameter(key, value); - } - - @ManagedOperation(description = "Update a parameter for all nodes") - @ManagedOperationParameters( { @ManagedOperationParameter(name = "key", description = "The name of the parameter"), - @ManagedOperationParameter(name = "value", description = "The value for the parameter") }) - public void updateParameterForAll(String key, String value) { - this.parameterService.saveParameter(ParameterConstants.ALL, ParameterConstants.ALL, key, value); - } - - @ManagedOperation(description = "Update a parameter for all nodes in a group") - @ManagedOperationParameters( { - @ManagedOperationParameter(name = "nodeGroup", description = "The name of the node group"), - @ManagedOperationParameter(name = "key", description = "The name of the parameter"), - @ManagedOperationParameter(name = "value", description = "The value for the parameter") }) - public void updateParameterForNodeGroup(String nodeGroup, String key, String value) { - this.parameterService.saveParameter(ParameterConstants.ALL, nodeGroup, key, value); - } - - @ManagedOperation(description = "Update a parameter for a specific node") - @ManagedOperationParameters( { - @ManagedOperationParameter(name = "externalId", description = "The name of the external id of node"), - @ManagedOperationParameter(name = "nodeGroup", description = "The name of the node group"), - @ManagedOperationParameter(name = "key", description = "The name of the parameter"), - @ManagedOperationParameter(name = "value", description = "The value for the parameter") }) - public void updateParameterForNode(String externalId, String nodeGroup, String key, String value) { - this.parameterService.saveParameter(externalId, nodeGroup, key, value); - } - - @ManagedAttribute(description = "The parameters configured for this SymmetricDS instance") - public String getParametersList() { - StringBuilder buffer = new StringBuilder(); - Map params = parameterService.getAllParameters(); - buffer.append("
");
-        for (String key : params.keySet()) {
-            buffer.append(key).append("=").append(params.get(key)).append("\n");
-        }
-        buffer.append("
"); - return buffer.toString(); - } - - public void setParameterService(IParameterService parameterService) { - this.parameterService = parameterService; - } + +package org.jumpmind.symmetric.service.jmx; + +import org.jumpmind.properties.TypedProperties; +import org.jumpmind.symmetric.common.ParameterConstants; +import org.jumpmind.symmetric.service.IParameterService; +import org.springframework.jmx.export.annotation.ManagedAttribute; +import org.springframework.jmx.export.annotation.ManagedOperation; +import org.springframework.jmx.export.annotation.ManagedOperationParameter; +import org.springframework.jmx.export.annotation.ManagedOperationParameters; +import org.springframework.jmx.export.annotation.ManagedResource; + +@ManagedResource(description = "The management interface for node parameters") +public class ParameterManagementService { + + private IParameterService parameterService; + + public ParameterManagementService(IParameterService parameterService) { + this.parameterService = parameterService; + } + + @ManagedOperation(description = "Reload supported parameters from file or database") + public void rereadParameters() { + this.parameterService.rereadParameters(); + } + + @ManagedOperation(description = "Update a parameter for this node only") + @ManagedOperationParameters({ + @ManagedOperationParameter(name = "key", description = "The name of the parameter"), + @ManagedOperationParameter(name = "value", description = "The value for the parameter") }) + public void updateParameter(String key, String value) { + this.parameterService.saveParameter(key, value); + } + + @ManagedOperation(description = "Update a parameter for all nodes") + @ManagedOperationParameters({ + @ManagedOperationParameter(name = "key", description = "The name of the parameter"), + @ManagedOperationParameter(name = "value", description = "The value for the parameter") }) + public void updateParameterForAll(String key, String value) { + this.parameterService.saveParameter(ParameterConstants.ALL, ParameterConstants.ALL, key, + value); + } + + @ManagedOperation(description = "Update a parameter for all nodes in a group") + @ManagedOperationParameters({ + @ManagedOperationParameter(name = "nodeGroup", description = "The name of the node group"), + @ManagedOperationParameter(name = "key", description = "The name of the parameter"), + @ManagedOperationParameter(name = "value", description = "The value for the parameter") }) + public void updateParameterForNodeGroup(String nodeGroup, String key, String value) { + this.parameterService.saveParameter(ParameterConstants.ALL, nodeGroup, key, value); + } + + @ManagedOperation(description = "Update a parameter for a specific node") + @ManagedOperationParameters({ + @ManagedOperationParameter(name = "externalId", description = "The name of the external id of node"), + @ManagedOperationParameter(name = "nodeGroup", description = "The name of the node group"), + @ManagedOperationParameter(name = "key", description = "The name of the parameter"), + @ManagedOperationParameter(name = "value", description = "The value for the parameter") }) + public void updateParameterForNode(String externalId, String nodeGroup, String key, String value) { + this.parameterService.saveParameter(externalId, nodeGroup, key, value); + } + + @ManagedAttribute(description = "The parameters configured for this SymmetricDS instance") + public String getParametersList() { + StringBuilder buffer = new StringBuilder(); + TypedProperties properties = parameterService.getAllParameters(); + buffer.append("
");
+        for (Object key : properties.keySet()) {
+            buffer.append(key).append("=").append(properties.get(key)).append("\n");
+        }
+        buffer.append("
"); + return buffer.toString(); + } } \ No newline at end of file diff --git a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/statistic/StatisticManager.java b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/statistic/StatisticManager.java index 30aead844b..6d282461d0 100644 --- a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/statistic/StatisticManager.java +++ b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/statistic/StatisticManager.java @@ -28,13 +28,10 @@ import java.util.concurrent.Semaphore; import org.jumpmind.symmetric.common.ParameterConstants; -import org.jumpmind.symmetric.common.logging.ILog; -import org.jumpmind.symmetric.common.logging.LogFactory; import org.jumpmind.symmetric.model.Node; import org.jumpmind.symmetric.model.NodeChannel; import org.jumpmind.symmetric.service.IConfigurationService; import org.jumpmind.symmetric.service.INodeService; -import org.jumpmind.symmetric.service.INotificationService; import org.jumpmind.symmetric.service.IParameterService; import org.jumpmind.symmetric.service.IStatisticService; import org.jumpmind.symmetric.util.AppUtils; @@ -46,8 +43,6 @@ public class StatisticManager implements IStatisticManager { private static final String UNKNOWN = "Unknown"; - static final ILog log = LogFactory.getLog(StatisticManager.class); - private Map channelStats = new HashMap(); private List jobStats = new ArrayList(); @@ -58,8 +53,6 @@ public class StatisticManager implements IStatisticManager { protected IStatisticService statisticService; - protected INotificationService notificationService; - protected IParameterService parameterService; protected IConfigurationService configurationService; @@ -72,7 +65,12 @@ public class StatisticManager implements IStatisticManager { Semaphore jobStatsLock = new Semaphore(NUMBER_OF_PERMITS, true); - public StatisticManager() { + public StatisticManager(IParameterService parameterService, INodeService nodeService, + IConfigurationService configurationService, IStatisticService statisticsService) { + this.parameterService = parameterService; + this.nodeService = nodeService; + this.configurationService = configurationService; + this.statisticService = statisticsService; } protected void init() { @@ -342,7 +340,8 @@ public void incrementTriggersCreatedCount(long count) { } public void flush() { - boolean recordStatistics = parameterService.is(ParameterConstants.STATISTIC_RECORD_ENABLE, false); + boolean recordStatistics = parameterService.is(ParameterConstants.STATISTIC_RECORD_ENABLE, + false); if (channelStats != null) { channelStatsLock.acquireUninterruptibly(NUMBER_OF_PERMITS); try { @@ -471,24 +470,4 @@ protected HostStats getHostStats() { return hostStats; } - public void setNodeService(INodeService nodeService) { - this.nodeService = nodeService; - } - - public void setStatisticService(IStatisticService statisticService) { - this.statisticService = statisticService; - } - - public void setNotificationService(INotificationService notificationService) { - this.notificationService = notificationService; - } - - public void setParameterService(IParameterService parameterService) { - this.parameterService = parameterService; - } - - public void setConfigurationService(IConfigurationService configurationService) { - this.configurationService = configurationService; - } - } \ No newline at end of file diff --git a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/transport/AbstractTransportManager.java b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/transport/AbstractTransportManager.java index df96e59894..35ce9e55fc 100644 --- a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/transport/AbstractTransportManager.java +++ b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/transport/AbstractTransportManager.java @@ -33,9 +33,9 @@ import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.math.NumberUtils; +import org.jumpmind.log.Log; +import org.jumpmind.log.LogFactory; import org.jumpmind.symmetric.common.Constants; -import org.jumpmind.symmetric.common.logging.ILog; -import org.jumpmind.symmetric.common.logging.LogFactory; import org.jumpmind.symmetric.model.BatchInfo; import org.jumpmind.symmetric.model.IncomingBatch; import org.jumpmind.symmetric.model.IncomingBatch.Status; @@ -46,12 +46,17 @@ */ abstract public class AbstractTransportManager { - protected ILog log = LogFactory.getLog(getClass()); + protected Log log = LogFactory.getLog(getClass()); protected Map extensionSyncUrlHandlers = new HashMap(); public AbstractTransportManager() { - } + } + + public AbstractTransportManager(Log log) { + this.log = log; + } + public void addExtensionSyncUrlHandler(String name, ISyncUrlExtension handler) { if (extensionSyncUrlHandlers == null) { diff --git a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/transport/ConcurrentConnectionManager.java b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/transport/ConcurrentConnectionManager.java index f1ca297d06..8584e3599c 100644 --- a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/transport/ConcurrentConnectionManager.java +++ b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/transport/ConcurrentConnectionManager.java @@ -38,8 +38,14 @@ public class ConcurrentConnectionManager implements IConcurrentConnectionManager protected Map> nodeConnectionStatistics = new HashMap>(); - protected Set whiteList = new HashSet(); - + protected Set whiteList = new HashSet(); + + public ConcurrentConnectionManager(IParameterService parameterService, + IStatisticManager statisticManager) { + this.parameterService = parameterService; + this.statisticManager = statisticManager; + } + protected void logTooBusyRejection(String nodeId, String poolId) { getNodeConnectionStatistics(nodeId, poolId).numOfRejections++; } @@ -129,14 +135,6 @@ private Map getReservationMap(String poolId) { return reservations; } - public void setParameterService(IParameterService parameterService) { - this.parameterService = parameterService; - } - - public void setStatisticManager(IStatisticManager statisticManager) { - this.statisticManager = statisticManager; - } - protected static class Reservation { String nodeId; long timeToLiveInMs; diff --git a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/transport/TransportManagerFactory.java b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/transport/TransportManagerFactory.java new file mode 100644 index 0000000000..86dc8223e5 --- /dev/null +++ b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/transport/TransportManagerFactory.java @@ -0,0 +1,124 @@ +/* + * Licensed to JumpMind Inc under one or more contributor + * license agreements. See the NOTICE file distributed + * with this work for additional information regarding + * copyright ownership. JumpMind Inc licenses this file + * to you under the GNU Lesser General Public License (the + * "License"); you may not use this file except in compliance + * with the License. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see + * . + * + * 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.jumpmind.symmetric.transport; + +import java.security.GeneralSecurityException; +import java.security.KeyManagementException; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.security.SecureRandom; + +import javax.net.ssl.HostnameVerifier; +import javax.net.ssl.HttpsURLConnection; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLSession; +import javax.net.ssl.SSLSocketFactory; +import javax.net.ssl.TrustManager; + +import org.apache.commons.lang.StringUtils; +import org.jumpmind.exception.SecurityException; +import org.jumpmind.symmetric.ISymmetricEngine; +import org.jumpmind.symmetric.common.Constants; +import org.jumpmind.symmetric.common.ParameterConstants; +import org.jumpmind.symmetric.transport.http.HttpTransportManager; +import org.jumpmind.symmetric.transport.http.SelfSignedX509TrustManager; +import org.jumpmind.symmetric.transport.internal.InternalTransportManager; + +public class TransportManagerFactory { + + private ISymmetricEngine symmetricEngine; + + public TransportManagerFactory(ISymmetricEngine symmetricEngine) { + this.symmetricEngine = symmetricEngine; + } + + public ITransportManager create() { + try { + String transport = symmetricEngine.getParameterService().getString( + ParameterConstants.TRANSPORT_TYPE); + if (Constants.PROTOCOL_HTTP.equalsIgnoreCase(transport)) { + final String httpSslVerifiedServerNames = symmetricEngine.getParameterService() + .getString(ParameterConstants.TRANSPORT_HTTPS_VERIFIED_SERVERS); + if (!StringUtils.isBlank(httpSslVerifiedServerNames)) { + HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() { + public boolean verify(String s, SSLSession sslsession) { + boolean verified = false; + if (!StringUtils.isBlank(httpSslVerifiedServerNames)) { + if (httpSslVerifiedServerNames + .equalsIgnoreCase(Constants.TRANSPORT_HTTPS_VERIFIED_SERVERS_ALL)) { + verified = true; + } else { + String[] names = httpSslVerifiedServerNames.split(","); + for (String string : names) { + if (s != null && s.equals(string.trim())) { + verified = true; + break; + } + } + } + } + return verified; + } + }); + } + + // Allow self signed certs based on the parameter value. + boolean allowSelfSignedCerts = symmetricEngine.getParameterService().is( + ParameterConstants.TRANSPORT_HTTPS_ALLOW_SELF_SIGNED_CERTS, false); + if (allowSelfSignedCerts) { + HttpsURLConnection.setDefaultSSLSocketFactory(createSelfSignedSocketFactory()); + } + + return new HttpTransportManager(symmetricEngine); + + } else if (Constants.PROTOCOL_INTERNAL.equalsIgnoreCase(transport)) { + return new InternalTransportManager(symmetricEngine); + } else { + throw new IllegalStateException("An invalid transport type of " + transport + + " was specified."); + } + } catch (GeneralSecurityException ex) { + throw new SecurityException(ex); + } + } + + /** + * Create an SSL Socket Factory that accepts self signed certificates. + * + * @return + * @throws NoSuchAlgorithmException + * @throws KeyManagementException + * @throws KeyStoreException + */ + private static SSLSocketFactory createSelfSignedSocketFactory() + throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException { + SSLSocketFactory factory = null; + + SSLContext context = SSLContext.getInstance("TLS"); + context.init(null, new TrustManager[] { new SelfSignedX509TrustManager(null) }, + new SecureRandom()); + factory = context.getSocketFactory(); + + return factory; + } + +} \ No newline at end of file diff --git a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/transport/TransportManagerFactoryBean.java b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/transport/TransportManagerFactoryBean.java deleted file mode 100644 index c49a1a85d0..0000000000 --- a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/transport/TransportManagerFactoryBean.java +++ /dev/null @@ -1,134 +0,0 @@ -/* - * Licensed to JumpMind Inc under one or more contributor - * license agreements. See the NOTICE file distributed - * with this work for additional information regarding - * copyright ownership. JumpMind Inc licenses this file - * to you under the GNU Lesser General Public License (the - * "License"); you may not use this file except in compliance - * with the License. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see - * . - * - * 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.jumpmind.symmetric.transport; - -import java.security.KeyManagementException; -import java.security.KeyStoreException; -import java.security.NoSuchAlgorithmException; -import java.security.SecureRandom; - -import javax.net.ssl.HostnameVerifier; -import javax.net.ssl.HttpsURLConnection; -import javax.net.ssl.SSLContext; -import javax.net.ssl.SSLSession; -import javax.net.ssl.SSLSocketFactory; -import javax.net.ssl.TrustManager; - -import org.apache.commons.lang.StringUtils; -import org.jumpmind.symmetric.common.Constants; -import org.jumpmind.symmetric.common.ParameterConstants; -import org.jumpmind.symmetric.service.IConfigurationService; -import org.jumpmind.symmetric.service.IParameterService; -import org.jumpmind.symmetric.transport.http.HttpTransportManager; -import org.jumpmind.symmetric.transport.http.SelfSignedX509TrustManager; -import org.jumpmind.symmetric.transport.internal.InternalTransportManager; -import org.springframework.beans.factory.FactoryBean; - -public class TransportManagerFactoryBean implements FactoryBean { - - private IParameterService parameterService; - - private IConfigurationService configurationService; - - public ITransportManager getObject() throws Exception { - String transport = parameterService.getString(ParameterConstants.TRANSPORT_TYPE); - if (Constants.PROTOCOL_HTTP.equalsIgnoreCase(transport)) { - final String httpSslVerifiedServerNames = parameterService - .getString(ParameterConstants.TRANSPORT_HTTPS_VERIFIED_SERVERS); - if (!StringUtils.isBlank(httpSslVerifiedServerNames)) { - HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() { - public boolean verify(String s, SSLSession sslsession) { - boolean verified = false; - if (!StringUtils.isBlank(httpSslVerifiedServerNames)) { - if (httpSslVerifiedServerNames.equalsIgnoreCase(Constants.TRANSPORT_HTTPS_VERIFIED_SERVERS_ALL)) { - verified = true; - } else { - String[] names = httpSslVerifiedServerNames.split(","); - for (String string : names) { - if (s != null && s.equals(string.trim())) { - verified = true; - break; - } - } - } - } - return verified; - } - }); - } - - // Allow self signed certs based on the parameter value. - boolean allowSelfSignedCerts = parameterService.is(ParameterConstants.TRANSPORT_HTTPS_ALLOW_SELF_SIGNED_CERTS, false); - if (allowSelfSignedCerts) { - HttpsURLConnection.setDefaultSSLSocketFactory(createSelfSignedSocketFactory()); - } - - return new HttpTransportManager(parameterService); - - } else if (Constants.PROTOCOL_INTERNAL.equalsIgnoreCase(transport)) { - return new InternalTransportManager(configurationService); - } else { - throw new IllegalStateException("An invalid transport type of " + transport + " was specified."); - } - } - - public Class getObjectType() { - return ITransportManager.class; - } - - public boolean isSingleton() { - return true; - } - - public void setParameterService(IParameterService parameterService) { - this.parameterService = parameterService; - } - - public IConfigurationService getConfigurationService() { - return configurationService; - } - - public void setConfigurationService(IConfigurationService configurationService) { - this.configurationService = configurationService; - } - - /** - * Create an SSL Socket Factory that accepts self signed certificates. - * - * @return - * @throws NoSuchAlgorithmException - * @throws KeyManagementException - * @throws KeyStoreException - */ - private static SSLSocketFactory createSelfSignedSocketFactory() throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException { - SSLSocketFactory factory = null; - - SSLContext context = SSLContext.getInstance("TLS"); - context.init(null, - new TrustManager[] {new SelfSignedX509TrustManager(null)}, - new SecureRandom()); - factory = context.getSocketFactory(); - - return factory; - } - -} \ No newline at end of file diff --git a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/transport/file/FileIncomingTransport.java b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/transport/file/FileIncomingTransport.java deleted file mode 100644 index d00e4dd130..0000000000 --- a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/transport/file/FileIncomingTransport.java +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Licensed to JumpMind Inc under one or more contributor - * license agreements. See the NOTICE file distributed - * with this work for additional information regarding - * copyright ownership. JumpMind Inc licenses this file - * to you under the GNU Lesser General Public License (the - * "License"); you may not use this file except in compliance - * with the License. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see - * . - * - * 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.jumpmind.symmetric.transport.file; - -import java.io.BufferedReader; -import java.io.File; -import java.io.IOException; - -import org.apache.commons.io.IOUtils; -import org.jumpmind.symmetric.io.ThresholdFileWriter; -import org.jumpmind.symmetric.transport.IIncomingTransport; - -/** - * Wraps an incoming stream that comes from a file. - */ -public class FileIncomingTransport implements IIncomingTransport { - - ThresholdFileWriter fileWriter; - - BufferedReader reader; - - public FileIncomingTransport(ThresholdFileWriter fileWriter) { - this.fileWriter = fileWriter; - } - - public void close() throws IOException { - IOUtils.closeQuietly(reader); - if (fileWriter != null) { - fileWriter.delete(); - } - } - - public String getUrl() { - File file = getFile(); - if (file != null) { - return file.getAbsolutePath(); - } else { - return null; - } - } - - public boolean isOpen() { - return reader != null; - } - - public BufferedReader open() throws IOException { - reader = fileWriter.getReader(); - return reader; - } - - public String getRedirectionUrl() { - return null; - } - - public File getFile() { - if (fileWriter != null) { - return fileWriter.getFile(); - } else { - return null; - } - } - -} \ No newline at end of file diff --git a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/transport/http/HttpBandwidthUrlSelector.java b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/transport/http/HttpBandwidthUrlSelector.java index 69acabbc46..8c4e1b2a35 100644 --- a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/transport/http/HttpBandwidthUrlSelector.java +++ b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/transport/http/HttpBandwidthUrlSelector.java @@ -29,11 +29,10 @@ import java.util.Map; import org.jumpmind.extension.IBuiltInExtensionPoint; -import org.jumpmind.symmetric.common.logging.ILog; -import org.jumpmind.symmetric.common.logging.LogFactory; +import org.jumpmind.log.Log; +import org.jumpmind.log.LogFactory; import org.jumpmind.symmetric.service.IBandwidthService; import org.jumpmind.symmetric.service.INodeService; -import org.jumpmind.symmetric.service.impl.BandwidthService; import org.jumpmind.symmetric.transport.ISyncUrlExtension; /** @@ -45,12 +44,10 @@ *

* Valid parameters are constants on this class that start with PARAM_. Any * parameter that is a numeral will be designated a possible URL. - * - * */ public class HttpBandwidthUrlSelector implements ISyncUrlExtension, IBuiltInExtensionPoint { - protected ILog log = LogFactory.getLog(getClass()); + protected Log log = LogFactory.getLog(getClass()); public static String PARAM_PRELOAD_ONLY = "initialLoadOnly"; public static String PARAM_SAMPLE_SIZE = "sampleSize"; @@ -65,7 +62,14 @@ public class HttpBandwidthUrlSelector implements ISyncUrlExtension, IBuiltInExte private Map> cachedUrls = new HashMap>(); private INodeService nodeService; - private IBandwidthService bandwidthService = new BandwidthService(); + private IBandwidthService bandwidthService; + + public HttpBandwidthUrlSelector(Log log, INodeService nodeService, + IBandwidthService bandwidthService) { + this.log = log; + this.nodeService = nodeService; + this.bandwidthService = bandwidthService; + } public String resolveUrl(URI uri) { Map params = getParameters(uri); @@ -184,14 +188,6 @@ public void setAutoRegister(boolean autoRegister) { this.autoRegister = autoRegister; } - public void setNodeService(INodeService nodeService) { - this.nodeService = nodeService; - } - - public void setBandwidthService(IBandwidthService bandwidthService) { - this.bandwidthService = bandwidthService; - } - public void setDefaultMaxSampleDuration(long defaultMaxSampleDuration) { this.defaultMaxSampleDuration = defaultMaxSampleDuration; } diff --git a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/transport/http/HttpTransportManager.java b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/transport/http/HttpTransportManager.java index d82d4e9876..383bad8bd0 100644 --- a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/transport/http/HttpTransportManager.java +++ b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/transport/http/HttpTransportManager.java @@ -21,33 +21,32 @@ package org.jumpmind.symmetric.transport.http; -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.io.OutputStreamWriter; -import java.io.PrintWriter; -import java.net.HttpURLConnection; -import java.net.URL; -import java.util.List; -import java.util.Map; -import java.util.zip.GZIPInputStream; - -import org.apache.commons.codec.binary.Base64; -import org.apache.commons.lang.StringUtils; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.jumpmind.symmetric.common.Constants; -import org.jumpmind.symmetric.common.ParameterConstants; -import org.jumpmind.symmetric.model.IncomingBatch; -import org.jumpmind.symmetric.model.Node; -import org.jumpmind.symmetric.service.IParameterService; -import org.jumpmind.symmetric.transport.AbstractTransportManager; -import org.jumpmind.symmetric.transport.IIncomingTransport; -import org.jumpmind.symmetric.transport.IOutgoingWithResponseTransport; -import org.jumpmind.symmetric.transport.ITransportManager; -import org.jumpmind.symmetric.transport.TransportUtils; -import org.jumpmind.symmetric.web.WebConstants; +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.io.PrintWriter; +import java.net.HttpURLConnection; +import java.net.URL; +import java.util.List; +import java.util.Map; +import java.util.zip.GZIPInputStream; + +import org.apache.commons.codec.binary.Base64; +import org.apache.commons.lang.StringUtils; +import org.jumpmind.symmetric.ISymmetricEngine; +import org.jumpmind.symmetric.common.Constants; +import org.jumpmind.symmetric.common.ParameterConstants; +import org.jumpmind.symmetric.model.IncomingBatch; +import org.jumpmind.symmetric.model.Node; +import org.jumpmind.symmetric.service.IParameterService; +import org.jumpmind.symmetric.transport.AbstractTransportManager; +import org.jumpmind.symmetric.transport.IIncomingTransport; +import org.jumpmind.symmetric.transport.IOutgoingWithResponseTransport; +import org.jumpmind.symmetric.transport.ITransportManager; +import org.jumpmind.symmetric.transport.TransportUtils; +import org.jumpmind.symmetric.web.WebConstants; /** * Allow remote communication to nodes, in order to push data, pull data, and @@ -55,15 +54,15 @@ */ public class HttpTransportManager extends AbstractTransportManager implements ITransportManager { - protected static final Log logger = LogFactory.getLog(HttpTransportManager.class); - private IParameterService parameterService; public HttpTransportManager() { } - public HttpTransportManager(IParameterService parameterService) { - this.parameterService = parameterService; + public HttpTransportManager(ISymmetricEngine engine) { + super(engine.getLog()); + this.parameterService = engine.getParameterService(); + this.addExtensionSyncUrlHandler("httpBandwidthUrlSelector", new HttpBandwidthUrlSelector(log, engine.getNodeService(), engine.getBandwidthService())); } public int sendAcknowledgement(Node remote, List list, Node local, String securityToken, String registrationUrl) throws IOException { diff --git a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/transport/internal/InternalTransportManager.java b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/transport/internal/InternalTransportManager.java index 37b12259aa..fce6fb89f2 100644 --- a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/transport/internal/InternalTransportManager.java +++ b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/transport/internal/InternalTransportManager.java @@ -21,52 +21,44 @@ package org.jumpmind.symmetric.transport.internal; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.io.OutputStreamWriter; -import java.io.PipedInputStream; -import java.io.PipedOutputStream; -import java.io.PrintWriter; -import java.net.HttpURLConnection; -import java.util.List; -import java.util.Map; - -import org.apache.commons.io.IOUtils; -import org.jumpmind.symmetric.ISymmetricEngine; -import org.jumpmind.symmetric.StandaloneSymmetricEngine; -import org.jumpmind.symmetric.common.Constants; -import org.jumpmind.symmetric.common.logging.ILog; -import org.jumpmind.symmetric.common.logging.LogFactory; -import org.jumpmind.symmetric.model.BatchInfo; -import org.jumpmind.symmetric.model.ChannelMap; -import org.jumpmind.symmetric.model.IncomingBatch; -import org.jumpmind.symmetric.model.Node; -import org.jumpmind.symmetric.service.IAcknowledgeService; -import org.jumpmind.symmetric.service.IConfigurationService; -import org.jumpmind.symmetric.service.IDataExtractorService; -import org.jumpmind.symmetric.service.IDataLoaderService; -import org.jumpmind.symmetric.service.IRegistrationService; -import org.jumpmind.symmetric.transport.AbstractTransportManager; -import org.jumpmind.symmetric.transport.IIncomingTransport; -import org.jumpmind.symmetric.transport.IOutgoingTransport; -import org.jumpmind.symmetric.transport.IOutgoingWithResponseTransport; -import org.jumpmind.symmetric.transport.ITransportManager; -import org.springframework.beans.factory.BeanFactory; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.io.PipedInputStream; +import java.io.PipedOutputStream; +import java.io.PrintWriter; +import java.net.HttpURLConnection; +import java.util.List; +import java.util.Map; + +import org.apache.commons.io.IOUtils; +import org.jumpmind.symmetric.AbstractSymmetricEngine; +import org.jumpmind.symmetric.ISymmetricEngine; +import org.jumpmind.symmetric.common.Constants; +import org.jumpmind.symmetric.common.logging.ILog; +import org.jumpmind.symmetric.common.logging.LogFactory; +import org.jumpmind.symmetric.model.BatchInfo; +import org.jumpmind.symmetric.model.ChannelMap; +import org.jumpmind.symmetric.model.IncomingBatch; +import org.jumpmind.symmetric.model.Node; +import org.jumpmind.symmetric.transport.AbstractTransportManager; +import org.jumpmind.symmetric.transport.IIncomingTransport; +import org.jumpmind.symmetric.transport.IOutgoingTransport; +import org.jumpmind.symmetric.transport.IOutgoingWithResponseTransport; +import org.jumpmind.symmetric.transport.ITransportManager; /** - * Coordinates interaction between two symmetric engines in the same JVM. - * - * + * Coordinates interaction between two symmetric engines in the same JVM. */ public class InternalTransportManager extends AbstractTransportManager implements ITransportManager { static final ILog log = LogFactory.getLog(InternalTransportManager.class); - IConfigurationService configurationService; - public InternalTransportManager(IConfigurationService configurationService) { - super(); - this.configurationService = configurationService; + protected ISymmetricEngine symmetricEngine; + + public InternalTransportManager(ISymmetricEngine engine) { + this.symmetricEngine = engine; } public IIncomingTransport getPullTransport(Node remote, final Node local, @@ -75,14 +67,12 @@ public IIncomingTransport getPullTransport(Node remote, final Node local, final PipedOutputStream respOs = new PipedOutputStream(); final PipedInputStream respIs = new PipedInputStream(respOs); - final ChannelMap suspendIgnoreChannels = configurationService.getSuspendIgnoreChannelLists(remote.getNodeId()); + final ChannelMap suspendIgnoreChannels = symmetricEngine.getConfigurationService().getSuspendIgnoreChannelLists(remote.getNodeId()); runAtClient(remote.getSyncUrl(), null, respOs, new IClientRunnable() { - public void run(BeanFactory factory, InputStream is, OutputStream os) throws Exception { - IDataExtractorService extractor = (IDataExtractorService) factory - .getBean(Constants.DATAEXTRACTOR_SERVICE); + public void run(ISymmetricEngine engine, InputStream is, OutputStream os) throws Exception { IOutgoingTransport transport = new InternalOutgoingTransport(respOs, suspendIgnoreChannels); - extractor.extract(local, transport); + engine.getDataExtractorService().extract(local, transport); transport.close(); } }); @@ -98,10 +88,9 @@ public IOutgoingWithResponseTransport getPushTransport(final Node remote, final PipedInputStream respIs = new PipedInputStream(respOs); runAtClient(remote.getSyncUrl(), pushIs, respOs, new IClientRunnable() { - public void run(BeanFactory factory, InputStream is, OutputStream os) throws Exception { + public void run(ISymmetricEngine engine, InputStream is, OutputStream os) throws Exception { // This should be basically what the push servlet does ... - IDataLoaderService service = (IDataLoaderService) factory.getBean(Constants.DATALOADER_SERVICE); - service.loadDataFromPush(remote.getNodeId(), pushIs, respOs); + engine.getDataLoaderService().loadDataFromPush(remote.getNodeId(), pushIs, respOs); } }); return new InternalOutgoingWithResponseTransport(pushOs, respIs); @@ -113,11 +102,10 @@ public IIncomingTransport getRegisterTransport(final Node client, String registr final PipedInputStream respIs = new PipedInputStream(respOs); runAtClient(registrationUrl, null, respOs, new IClientRunnable() { - public void run(BeanFactory factory, InputStream is, OutputStream os) throws Exception { + public void run(ISymmetricEngine engine, InputStream is, OutputStream os) throws Exception { // This should be basically what the registration servlet does // ... - IRegistrationService service = (IRegistrationService) factory.getBean(Constants.REGISTRATION_SERVICE); - service.registerNode(client, os, false); + engine.getRegistrationService().registerNode(client, os, false); } }); return new InternalIncomingTransport(respIs); @@ -128,15 +116,11 @@ public int sendAcknowledgement(Node remote, List list, try { if (list != null && list.size() > 0) { ISymmetricEngine remoteEngine = getTargetEngine(remote.getSyncUrl()); - String ackData = getAcknowledgementData(local.getNodeId(), list); - List batches = readAcknowledgement(ackData); - IAcknowledgeService service = (IAcknowledgeService) remoteEngine.getApplicationContext().getBean( - Constants.ACKNOWLEDGE_SERVICE); + List batches = readAcknowledgement(ackData); for (BatchInfo batchInfo : batches) { - service.ack(batchInfo); + remoteEngine.getAcknowledgeService().ack(batchInfo); } - } return HttpURLConnection.HTTP_OK; } catch (Exception ex) { @@ -159,7 +143,7 @@ private void runAtClient(final String url, final InputStream is, final OutputStr public void run() { try { ISymmetricEngine engine = getTargetEngine(url); - runnable.run(engine.getApplicationContext(), is, os); + runnable.run(engine, is, os); } catch (Exception e) { log.error(e); } finally { @@ -171,7 +155,7 @@ public void run() { } private ISymmetricEngine getTargetEngine(String url) { - ISymmetricEngine engine = StandaloneSymmetricEngine.findEngineByUrl(url); + ISymmetricEngine engine = AbstractSymmetricEngine.findEngineByUrl(url); if (engine == null) { throw new NullPointerException("Could not find the engine reference for the following url: " + url); } else { @@ -180,7 +164,7 @@ private ISymmetricEngine getTargetEngine(String url) { } interface IClientRunnable { - public void run(BeanFactory factory, InputStream is, OutputStream os) throws Exception; + public void run(ISymmetricEngine engine, InputStream is, OutputStream os) throws Exception; } } \ No newline at end of file diff --git a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/upgrade/AbstractSqlUpgradeTask.java b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/upgrade/AbstractSqlUpgradeTask.java deleted file mode 100644 index d58756e673..0000000000 --- a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/upgrade/AbstractSqlUpgradeTask.java +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Licensed to JumpMind Inc under one or more contributor - * license agreements. See the NOTICE file distributed - * with this work for additional information regarding - * copyright ownership. JumpMind Inc licenses this file - * to you under the GNU Lesser General Public License (the - * "License"); you may not use this file except in compliance - * with the License. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see - * . - * - * 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.jumpmind.symmetric.upgrade; - -import org.apache.commons.lang.StringUtils; -import org.jumpmind.symmetric.service.IParameterService; -import org.springframework.jdbc.core.JdbcTemplate; - -/** - * - */ -abstract public class AbstractSqlUpgradeTask implements IUpgradeTask { - - protected JdbcTemplate jdbcTemplate; - - protected boolean isUpgradeRegistrationServer = true; - - protected boolean isUpgradeNonRegistrationServer = true; - - protected boolean useReplacement = true; - - public void upgrade(int[] fromVersion) { - } - - protected String prepareSql(String nodeId, IParameterService parameterService, String sql) { - if (useReplacement) { - sql = replace("groupId", parameterService.getNodeGroupId(), sql); - sql = replace("externalId", parameterService.getExternalId(), sql); - sql = replace("nodeId", nodeId, sql); - } - return sql; - } - - protected String replace(String prop, String replaceWith, String sourceString) { - return StringUtils.replace(sourceString, "$(" + prop + ")", replaceWith); - } - - public void setJdbcTemplate(JdbcTemplate jdbc) { - this.jdbcTemplate = jdbc; - } - - public boolean isUpgradeNonRegistrationServer() { - return isUpgradeNonRegistrationServer; - } - - public boolean getUpgradeNonRegistrationServer() { - return isUpgradeNonRegistrationServer; - } - - public void setUpgradeNonRegistrationServer(boolean isUpgradeNonRegistrationServer) { - this.isUpgradeNonRegistrationServer = isUpgradeNonRegistrationServer; - } - - public boolean isUpgradeRegistrationServer() { - return isUpgradeRegistrationServer; - } - - public boolean getUpgradeRegistrationServer() { - return isUpgradeRegistrationServer; - } - - public void setUpgradeRegistrationServer(boolean isUpgradeRegistrationServer) { - this.isUpgradeRegistrationServer = isUpgradeRegistrationServer; - } - - public boolean getUseReplacement() { - return useReplacement; - } - - public void setUseReplacement(boolean useReplacement) { - this.useReplacement = useReplacement; - } - -} \ No newline at end of file diff --git a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/upgrade/IUpgradeTask.java b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/upgrade/IUpgradeTask.java deleted file mode 100644 index 72f4fbe773..0000000000 --- a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/upgrade/IUpgradeTask.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Licensed to JumpMind Inc under one or more contributor - * license agreements. See the NOTICE file distributed - * with this work for additional information regarding - * copyright ownership. JumpMind Inc licenses this file - * to you under the GNU Lesser General Public License (the - * "License"); you may not use this file except in compliance - * with the License. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see - * . - * - * 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.jumpmind.symmetric.upgrade; - -import org.jumpmind.symmetric.service.IParameterService; - -/** - * - */ -public interface IUpgradeTask { - - public void upgrade(String nodeId, IParameterService parameterService, int[] fromVersion); - - public boolean isUpgradeRegistrationServer(); - - public boolean isUpgradeNonRegistrationServer(); -} \ No newline at end of file diff --git a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/upgrade/SqlDrivenUpgradeTask.java b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/upgrade/SqlDrivenUpgradeTask.java deleted file mode 100644 index 7cda936b3f..0000000000 --- a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/upgrade/SqlDrivenUpgradeTask.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Licensed to JumpMind Inc under one or more contributor - * license agreements. See the NOTICE file distributed - * with this work for additional information regarding - * copyright ownership. JumpMind Inc licenses this file - * to you under the GNU Lesser General Public License (the - * "License"); you may not use this file except in compliance - * with the License. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see - * . - * - * 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.jumpmind.symmetric.upgrade; - -import java.sql.ResultSet; -import java.sql.SQLException; - -import org.jumpmind.symmetric.common.logging.ILog; -import org.jumpmind.symmetric.common.logging.LogFactory; -import org.jumpmind.symmetric.service.IParameterService; -import org.springframework.jdbc.core.RowCallbackHandler; - -/** - * - */ -public class SqlDrivenUpgradeTask extends AbstractSqlUpgradeTask { - - private static final ILog log = LogFactory.getLog(SqlDrivenUpgradeTask.class); - - protected String driverSql; - - protected String updateSql; - - public void upgrade(final String nodeId, final IParameterService parameterService, int[] fromVersion) { - String sql = prepareSql(nodeId, parameterService, driverSql); - log.warn("SqlForEachUpgrade", sql); - log.warn("SqlDoUpgrade", updateSql); - jdbcTemplate.query(sql, new RowCallbackHandler() { - public void processRow(ResultSet rs) throws SQLException { - int count = rs.getMetaData().getColumnCount(); - Object[] params = new Object[count]; - for (int i = 0; i < count; i++) { - params[i] = rs.getObject(i + 1); - } - jdbcTemplate.update(prepareSql(nodeId, parameterService, updateSql), params); - } - }); - } - - public void setDriverSql(String driverSql) { - this.driverSql = driverSql; - } - - public void setUpdateSql(String updateSql) { - this.updateSql = updateSql; - } - -} \ No newline at end of file diff --git a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/upgrade/SqlUpgradeTask.java b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/upgrade/SqlUpgradeTask.java deleted file mode 100644 index c2ff8274df..0000000000 --- a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/upgrade/SqlUpgradeTask.java +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Licensed to JumpMind Inc under one or more contributor - * license agreements. See the NOTICE file distributed - * with this work for additional information regarding - * copyright ownership. JumpMind Inc licenses this file - * to you under the GNU Lesser General Public License (the - * "License"); you may not use this file except in compliance - * with the License. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see - * . - * - * 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.jumpmind.symmetric.upgrade; - -import java.util.List; - -import org.jumpmind.symmetric.common.logging.ILog; -import org.jumpmind.symmetric.common.logging.LogFactory; -import org.jumpmind.symmetric.db.ISymmetricDialect; -import org.jumpmind.symmetric.service.IParameterService; - -/** - * - */ -public class SqlUpgradeTask extends AbstractSqlUpgradeTask { - - private static final ILog log = LogFactory.getLog(SqlUpgradeTask.class); - - protected ISymmetricDialect symmetricDialect; - - protected String dialectName; - - protected List sqlList; - - protected boolean ignoreFailure; - - public void upgrade(int[] fromVersion) { - for (String sql : sqlList) { - log.warn("SqlUpgrade", sql); - jdbcTemplate.update(sql); - } - } - - public void upgrade(String nodeId, IParameterService parameterService, int[] fromVersion) { - if (dialectName == null || (symmetricDialect != null && symmetricDialect.getName().equalsIgnoreCase((dialectName)))) { - for (String sql : sqlList) { - sql = prepareSql(nodeId, parameterService, sql); - log.warn("SqlUpgrade", sql); - if (ignoreFailure) { - try { - jdbcTemplate.update(sql); - } catch (Exception e) { - log.warn("SqlUpgradeIgnoring", e.getMessage()); - } - } else { - jdbcTemplate.update(sql); - } - } - } - } - - public void setSqlList(List sqlList) { - this.sqlList = sqlList; - } - - public void setIgnoreFailure(boolean ignoreFailure) { - this.ignoreFailure = ignoreFailure; - } - - public void setSymmetricDialect(ISymmetricDialect symmetricDialect) { - this.symmetricDialect = symmetricDialect; - } - - public void setDialectName(String dialectName) { - this.dialectName = dialectName; - } - -} \ No newline at end of file diff --git a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/upgrade/UpgradeConstants.java b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/upgrade/UpgradeConstants.java deleted file mode 100644 index dd34b2c678..0000000000 --- a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/upgrade/UpgradeConstants.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Licensed to JumpMind Inc under one or more contributor - * license agreements. See the NOTICE file distributed - * with this work for additional information regarding - * copyright ownership. JumpMind Inc licenses this file - * to you under the GNU Lesser General Public License (the - * "License"); you may not use this file except in compliance - * with the License. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see - * . - * - * 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.jumpmind.symmetric.upgrade; - -public class UpgradeConstants { - - public static final String VERSION_FOR_NEW_REGISTRATION_PROTOCOL = "1.6.0"; - -} \ No newline at end of file diff --git a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/util/AppUtils.java b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/util/AppUtils.java index 1155e25d57..1591997c16 100644 --- a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/util/AppUtils.java +++ b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/util/AppUtils.java @@ -36,8 +36,6 @@ import org.apache.commons.io.FileUtils; import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.time.FastDateFormat; -import org.jumpmind.symmetric.ISymmetricEngine; -import org.jumpmind.symmetric.common.Constants; import org.jumpmind.symmetric.common.logging.ILog; import org.jumpmind.symmetric.common.logging.LogFactory; @@ -127,17 +125,6 @@ public static String getTimezoneOffset() { return null; } - /** - * Handy utility method to look up a SymmetricDS component given the bean - * name. - * - * @see Constants - */ - @SuppressWarnings("unchecked") - public static T find(String name, ISymmetricEngine engine) { - return (T) engine.getApplicationContext().getBean(name); - } - /** * Use this method to create any needed temporary files for SymmetricDS. */ diff --git a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/util/MaxRowsStatementCreator.java b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/util/MaxRowsStatementCreator.java deleted file mode 100644 index 3c48c4bfe8..0000000000 --- a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/util/MaxRowsStatementCreator.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Licensed to JumpMind Inc under one or more contributor - * license agreements. See the NOTICE file distributed - * with this work for additional information regarding - * copyright ownership. JumpMind Inc licenses this file - * to you under the GNU Lesser General Public License (the - * "License"); you may not use this file except in compliance - * with the License. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see - * . - * - * 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.jumpmind.symmetric.util; - -import java.sql.Connection; -import java.sql.PreparedStatement; -import java.sql.SQLException; - -import org.springframework.jdbc.core.PreparedStatementCreator; - -/** - * - */ -public class MaxRowsStatementCreator implements PreparedStatementCreator { - - private String sql; - - private int maxRows; - - public MaxRowsStatementCreator(String sql, int maxRows) { - this.sql = sql; - this.maxRows = maxRows; - } - - public PreparedStatement createPreparedStatement(Connection conn) throws SQLException { - PreparedStatement st = conn.prepareStatement(sql); - st.setMaxRows(maxRows); - return st; - } - -} \ No newline at end of file diff --git a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/util/RandomTimeSlot.java b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/util/RandomTimeSlot.java index 1e10c23437..ac210e2b95 100644 --- a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/util/RandomTimeSlot.java +++ b/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/util/RandomTimeSlot.java @@ -16,59 +16,57 @@ * "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.jumpmind.symmetric.util; - -import java.util.Random; - -import org.jumpmind.symmetric.common.ParameterConstants; -import org.jumpmind.symmetric.service.IParameterService; - -/** - * Use runtime configuration specific seeding to get a random number for use in - * time slotting nodes to help stagger load. - * - * - */ -public class RandomTimeSlot { - - int maxValue = -1; - - Random random; - - public RandomTimeSlot() { - random = new Random(); - } - - public RandomTimeSlot(String externalId, int maxValue) { - this.maxValue = maxValue; - random = new Random(fromExternalId(externalId)); - } - - private long fromExternalId(String externalId) { - if (externalId != null) { - return Math.abs(externalId.hashCode()); - } else { - return Integer.MAX_VALUE; - } - } - - public void setParameterService(IParameterService s) { - long seed = fromExternalId(s.getExternalId()); - random = new Random(seed); - if (maxValue < 0) { - maxValue = s.getInt(ParameterConstants.JOB_RANDOM_MAX_START_TIME_MS); - } - } - - public int getRandomValueSeededByExternalId() { - int nextValue = random.nextInt(maxValue); - return nextValue == 0 ? 1 : nextValue; - } - - public void setMaxValue(int maxValue) { - this.maxValue = maxValue; - } + * under the License. + */ + +package org.jumpmind.symmetric.util; + +import java.util.Random; + +import org.jumpmind.symmetric.common.ParameterConstants; +import org.jumpmind.symmetric.service.IParameterService; + +/** + * Use runtime configuration specific seeding to get a random number for use in + * time slotting nodes to help stagger load. + */ +public class RandomTimeSlot { + + int maxValue = -1; + + Random random; + + public RandomTimeSlot() { + random = new Random(); + } + + public RandomTimeSlot(IParameterService parameterService) { + long seed = fromExternalId(parameterService.getExternalId()); + random = new Random(seed); + if (maxValue < 0) { + maxValue = parameterService.getInt(ParameterConstants.JOB_RANDOM_MAX_START_TIME_MS); + } + } + + public RandomTimeSlot(String externalId, int maxValue) { + this.maxValue = maxValue; + random = new Random(fromExternalId(externalId)); + } + + private long fromExternalId(String externalId) { + if (externalId != null) { + return Math.abs(externalId.hashCode()); + } else { + return Integer.MAX_VALUE; + } + } + + public int getRandomValueSeededByExternalId() { + int nextValue = random.nextInt(maxValue); + return nextValue == 0 ? 1 : nextValue; + } + + public void setMaxValue(int maxValue) { + this.maxValue = maxValue; + } } \ No newline at end of file diff --git a/symmetric/symmetric-core/src/main/resources/org/jumpmind/symmetric/db/db2-zseries.xml b/symmetric/symmetric-core/src/main/resources/org/jumpmind/symmetric/db/db2-zseries.xml deleted file mode 100644 index 697c77e423..0000000000 --- a/symmetric/symmetric-core/src/main/resources/org/jumpmind/symmetric/db/db2-zseries.xml +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/symmetric/symmetric-core/src/main/resources/org/jumpmind/symmetric/db/db2.xml b/symmetric/symmetric-core/src/main/resources/org/jumpmind/symmetric/db/db2.xml deleted file mode 100644 index 08dc48fca2..0000000000 --- a/symmetric/symmetric-core/src/main/resources/org/jumpmind/symmetric/db/db2.xml +++ /dev/null @@ -1,24 +0,0 @@ - - - - - - - - - - - - \ No newline at end of file diff --git a/symmetric/symmetric-core/src/main/resources/org/jumpmind/symmetric/db/derby.xml b/symmetric/symmetric-core/src/main/resources/org/jumpmind/symmetric/db/derby.xml deleted file mode 100644 index adc280806b..0000000000 --- a/symmetric/symmetric-core/src/main/resources/org/jumpmind/symmetric/db/derby.xml +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - - - - - \ No newline at end of file diff --git a/symmetric/symmetric-core/src/main/resources/org/jumpmind/symmetric/db/firebird.xml b/symmetric/symmetric-core/src/main/resources/org/jumpmind/symmetric/db/firebird.xml deleted file mode 100644 index 38093ec8f5..0000000000 --- a/symmetric/symmetric-core/src/main/resources/org/jumpmind/symmetric/db/firebird.xml +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - - - - - \ No newline at end of file diff --git a/symmetric/symmetric-core/src/main/resources/org/jumpmind/symmetric/db/greenplum.xml b/symmetric/symmetric-core/src/main/resources/org/jumpmind/symmetric/db/greenplum.xml deleted file mode 100644 index 203190d451..0000000000 --- a/symmetric/symmetric-core/src/main/resources/org/jumpmind/symmetric/db/greenplum.xml +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - - - - - \ No newline at end of file diff --git a/symmetric/symmetric-core/src/main/resources/org/jumpmind/symmetric/db/h2.xml b/symmetric/symmetric-core/src/main/resources/org/jumpmind/symmetric/db/h2.xml deleted file mode 100644 index bdf0102e92..0000000000 --- a/symmetric/symmetric-core/src/main/resources/org/jumpmind/symmetric/db/h2.xml +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - - - - - \ No newline at end of file diff --git a/symmetric/symmetric-core/src/main/resources/org/jumpmind/symmetric/db/hsqldb.xml b/symmetric/symmetric-core/src/main/resources/org/jumpmind/symmetric/db/hsqldb.xml deleted file mode 100644 index 6d1dfba2be..0000000000 --- a/symmetric/symmetric-core/src/main/resources/org/jumpmind/symmetric/db/hsqldb.xml +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - - - - - \ No newline at end of file diff --git a/symmetric/symmetric-core/src/main/resources/org/jumpmind/symmetric/db/hsqldb2.xml b/symmetric/symmetric-core/src/main/resources/org/jumpmind/symmetric/db/hsqldb2.xml deleted file mode 100644 index a81bf07bd6..0000000000 --- a/symmetric/symmetric-core/src/main/resources/org/jumpmind/symmetric/db/hsqldb2.xml +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - - - - - \ No newline at end of file diff --git a/symmetric/symmetric-core/src/main/resources/org/jumpmind/symmetric/db/informix.xml b/symmetric/symmetric-core/src/main/resources/org/jumpmind/symmetric/db/informix.xml deleted file mode 100644 index 56eab1e22f..0000000000 --- a/symmetric/symmetric-core/src/main/resources/org/jumpmind/symmetric/db/informix.xml +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - - - - - \ No newline at end of file diff --git a/symmetric/symmetric-core/src/main/resources/org/jumpmind/symmetric/db/interbase.xml b/symmetric/symmetric-core/src/main/resources/org/jumpmind/symmetric/db/interbase.xml deleted file mode 100644 index 2fc5e10dae..0000000000 --- a/symmetric/symmetric-core/src/main/resources/org/jumpmind/symmetric/db/interbase.xml +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - - - - - \ No newline at end of file diff --git a/symmetric/symmetric-core/src/main/resources/org/jumpmind/symmetric/db/mssql.xml b/symmetric/symmetric-core/src/main/resources/org/jumpmind/symmetric/db/mssql.xml deleted file mode 100644 index b40d3e8ff4..0000000000 --- a/symmetric/symmetric-core/src/main/resources/org/jumpmind/symmetric/db/mssql.xml +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - - - - - \ No newline at end of file diff --git a/symmetric/symmetric-core/src/main/resources/org/jumpmind/symmetric/db/mysql.xml b/symmetric/symmetric-core/src/main/resources/org/jumpmind/symmetric/db/mysql.xml deleted file mode 100644 index ed61ca0e55..0000000000 --- a/symmetric/symmetric-core/src/main/resources/org/jumpmind/symmetric/db/mysql.xml +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - - - - - \ No newline at end of file diff --git a/symmetric/symmetric-core/src/main/resources/org/jumpmind/symmetric/db/oracle.xml b/symmetric/symmetric-core/src/main/resources/org/jumpmind/symmetric/db/oracle.xml deleted file mode 100644 index 87f0a75a3e..0000000000 --- a/symmetric/symmetric-core/src/main/resources/org/jumpmind/symmetric/db/oracle.xml +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - - - - - - - \ No newline at end of file diff --git a/symmetric/symmetric-core/src/main/resources/org/jumpmind/symmetric/db/postgresql.xml b/symmetric/symmetric-core/src/main/resources/org/jumpmind/symmetric/db/postgresql.xml deleted file mode 100644 index 1ac0a18f11..0000000000 --- a/symmetric/symmetric-core/src/main/resources/org/jumpmind/symmetric/db/postgresql.xml +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - - - - - \ No newline at end of file diff --git a/symmetric/symmetric-core/src/main/resources/org/jumpmind/symmetric/db/sqlite.xml b/symmetric/symmetric-core/src/main/resources/org/jumpmind/symmetric/db/sqlite.xml deleted file mode 100644 index 92f5200ad6..0000000000 --- a/symmetric/symmetric-core/src/main/resources/org/jumpmind/symmetric/db/sqlite.xml +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - - - - - \ No newline at end of file diff --git a/symmetric/symmetric-core/src/main/resources/org/jumpmind/symmetric/db/sybase.xml b/symmetric/symmetric-core/src/main/resources/org/jumpmind/symmetric/db/sybase.xml deleted file mode 100644 index def6b9a522..0000000000 --- a/symmetric/symmetric-core/src/main/resources/org/jumpmind/symmetric/db/sybase.xml +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - - - - - \ No newline at end of file diff --git a/symmetric/symmetric-core/src/main/resources/symmetric-client.xml b/symmetric/symmetric-core/src/main/resources/symmetric-client.xml deleted file mode 100644 index 57faf38096..0000000000 --- a/symmetric/symmetric-core/src/main/resources/symmetric-client.xml +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/symmetric/symmetric-core/src/main/resources/symmetric-database.xml b/symmetric/symmetric-core/src/main/resources/symmetric-database.xml deleted file mode 100644 index 545cc64267..0000000000 --- a/symmetric/symmetric-core/src/main/resources/symmetric-database.xml +++ /dev/null @@ -1,84 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/symmetric/symmetric-core/src/main/resources/symmetric-default.properties b/symmetric/symmetric-core/src/main/resources/symmetric-default.properties index cfe11c37a4..a3ab049118 100644 --- a/symmetric/symmetric-core/src/main/resources/symmetric-default.properties +++ b/symmetric/symmetric-core/src/main/resources/symmetric-default.properties @@ -392,15 +392,6 @@ auto.registration=false # Type: boolean auto.reload=false -# Indicate whether the process of inserting data, data_events and outgoing_batches for -# a reload is transactional. The only reason this might be marked as false is to reduce -# possible contention while multiple nodes connect for reloads at the same time. -# -# DatabaseOverridable: true -# Tags: other -# Type: boolean -datareload.batch.insert.transactional=true - # Set this if you want to give your server a unique name to be used to identify which server did what action. Typically useful when running in # a clustered environment. This is currently used by the ClusterService when locking for a node. # @@ -556,6 +547,10 @@ start.watchdog.job=true # Tags: routing routing.peek.ahead.window.after.max.size=2000 +# DatabaseOverridable: true +# Tags: routing +routing.wait.for.data.timeout.seconds=330 + # DatabaseOverridable: true # Tags: routing routing.flush.jdbc.batch.size=50000 @@ -757,7 +752,7 @@ jmx.http.console.localhost.only.enabled=false # to all nodes that this node is configured to push to. # Tags: other # Type: boolean -heartbeat.sync.on.push=true +heartbeat.sync.on.push.enabled=true # This is the number of seconds between when the heartbeat job runs. # Tags: other diff --git a/symmetric/symmetric-core/src/main/resources/symmetric-dialects.xml b/symmetric/symmetric-core/src/main/resources/symmetric-dialects.xml deleted file mode 100644 index 04fadd23cf..0000000000 --- a/symmetric/symmetric-core/src/main/resources/symmetric-dialects.xml +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/symmetric/symmetric-core/src/main/resources/symmetric-empty.xml b/symmetric/symmetric-core/src/main/resources/symmetric-empty.xml deleted file mode 100644 index 3313c8f6b9..0000000000 --- a/symmetric/symmetric-core/src/main/resources/symmetric-empty.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/symmetric/symmetric-core/src/main/resources/symmetric-extensions.xml b/symmetric/symmetric-core/src/main/resources/symmetric-extensions.xml index fdfde0850d..ca2457b5f5 100644 --- a/symmetric/symmetric-core/src/main/resources/symmetric-extensions.xml +++ b/symmetric/symmetric-core/src/main/resources/symmetric-extensions.xml @@ -5,55 +5,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/symmetric/symmetric-core/src/main/resources/symmetric-jmx.xml b/symmetric/symmetric-core/src/main/resources/symmetric-jmx.xml index 1ca42858a1..dc5db822c3 100644 --- a/symmetric/symmetric-core/src/main/resources/symmetric-jmx.xml +++ b/symmetric/symmetric-core/src/main/resources/symmetric-jmx.xml @@ -52,17 +52,6 @@ - - - - - - - - - - - diff --git a/symmetric/symmetric-core/src/main/resources/symmetric-jobs.xml b/symmetric/symmetric-core/src/main/resources/symmetric-jobs.xml deleted file mode 100644 index dfd9996ff0..0000000000 --- a/symmetric/symmetric-core/src/main/resources/symmetric-jobs.xml +++ /dev/null @@ -1,102 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/symmetric/symmetric-core/src/main/resources/symmetric-messages.properties b/symmetric/symmetric-core/src/main/resources/symmetric-messages.properties index 32157e5f77..4f991e9944 100644 --- a/symmetric/symmetric-core/src/main/resources/symmetric-messages.properties +++ b/symmetric/symmetric-core/src/main/resources/symmetric-messages.properties @@ -17,8 +17,7 @@ Arguments=Arguments: %s LongRunningOperation=%s took %d ms AutoConfigRegistrationService=Inserting rows for node, security, identity and group for registration server AutoConfigNodeIdAlreadyExists=Not inserting node row for %s because it already exists -AuthenticationFailed=Could not authenticate with node. -BandwidthCalculated=%s was calculated to have a download bandwidth of %s kbps. +AuthenticationFailed=. BandwidthSampleSizeParsingFailed=Unable to parse sampleSize of %s BandwidthSampleTTLParsingFailed=Unable to parse sampleTTL of %s BatchCompleting=Completing batch %d @@ -33,7 +32,7 @@ BatchStatusLoggingFailed=Could not log the outgoing batch status because the bat BatchStatusRecordFailed=Failed to record status of batch %s BshColumnTransform.exception=Beanshell script error for target column %s on transform %s BufferWriting=%s -ChannelFlushed=Channels flushed because new channels came through the dataloader. + ChannelAutoConfiguring=Auto-configuring %s channel. ChannelExists=No need to create channel %s. It already exists. CleanStrandedTempFiles=Cleaned %d stranded temporary files. @@ -53,7 +52,7 @@ CompressionServletFlushingBuffer=flush buffer @ CompressionServletResponseWrappe CompressionServletStreamSettingOutput=stream is set to %s in getOutputStream CompressionServletStreamSettingWriter=stream is set to %s in getWriter CompressionServletCharacterEncoding=character encoding is %s -ConfigurationChanged=About to syncTriggers because new configuration came through the dataloader. +ConfigurationChanged=. DB2DialectInitializingError=Error while initializing DB2 dialect DB2ResettingAutoIncrementColumns=Resetting auto increment columns for %s DataPullingInReloadMode=Immediate pull requested while in reload mode. @@ -61,29 +60,11 @@ DataPulling=Pull requested for %s DataPulled=Pull data received from %s. %d rows and %d batches were processed. DataPullingFailed=Pull no data received %s DataPullingFailedLock=Did not run the pull process because the cluster service has it locked -DataPurgeIncomingRunning=The incoming purge process is about to run. -DataPurgeIncomingCompleted=The incoming purge process has completed. -DataPurgeIncomingRunningFailed=Could not get a lock to run an incoming purge. -DataPurgeIncomingRange=Getting range for incoming batch -DataPurgeIncomingAllCompleted=Purged all %d incoming batch for node %s DataPurgeSkippingNoInitialLoad=No sense running the purge service because an initial load has not been completed. DataPurgeStatsRunning=The statistic purge process is about to run. DataPurgeStatsRun=Purged %d statistic rows. DataPurgeStatsCompleted=The statistic purge process has completed. DataPurgeStatsRunningFailedLock=Did not run the statistic purge process because the cluster service has it locked. -DataPurgeDataGapsRunning=The data gap purge process is about to run. -DataPurgeDataGapsRun=Purged %d data gap rows. -DataPurgeDataGapsCompleted=The data gap purge process has completed. -DataPurgeDataGapsRunningFailedLock=Did not run the data gap purge process because the cluster service has it locked. -DataPurgeOutgoingRunning=The outgoing purge process is about to run for data older than %s. -DataPurgeOutgoingCompleted=The outgoing purge process has completed. -DataPurgeOutgoingRunningFailedLock=Could not get a lock to run an outgoing purge. -DataPurgeOutgoingRange=Getting range for outgoing batch -DataPurgeRowsRange=Getting range for data -DataPurgeUpdatedStrandedBatches=Set the status to OK for %d batches that no longer are associated with valid nodes. -DataPurgeTableStarting=About to purge %s -DataPurgeTableRunning=Purged %d of %s rows so far using %d statements. -DataPurgeTableCompleted=Done purging %d of %s rows. DataPushed=Pushed data to %s DataPushing=Push requested for %s DataPushingCompleted=Push completed for %s @@ -98,17 +79,14 @@ DataExtractorUsingAlreadyExtractedBatch=We have already extracted batch %d. Usi DataExtractorMissingRowData=The row data was blank for the data row with a data id of %d. DataExtractorMissingPkData=The primary key data was blank for the data row with a data id of %d. DataExtractorReachedMaxNumberOfBytesToSync=Reached byte threshold after %d batches at %d bytes. Data will continue to be synchronized on the next pull. -DataEventInsertFailed=Could not insert a data event: data_id=%d batch_id=%d router_id=%s +DataEventInsertFailed= DataSent=Push data sent to %s DataAckExtendedReading=Reading extend ack: %s DataAckReading=Reading ack: %s DataAckReadingFailed=Did not receive an acknowledgement for the batches sent. DataAckSaving=Saving ack: %s, %s -DatabaseConnectionException=Could not get a connection to the database: %s. Waiting for 10 seconds before trying to connect to the database again. -DatabaseParametersReadingFailed=Could not read database parameters. We will try again later. DatabaseSchemaBuilding=Building database schema from: %s DatabaseStats=There are currently %s active database connections. -DbDialectInUse=The DbDialect being used is %s DeprecatedPropertyMsg=The following property is deprecated: %s. Please use: %s DDLRunning=Running DDL: %s DDLUtilsSkipOracleIndex=Skipping Oracle index %s. Not a normal index. @@ -148,7 +126,6 @@ JobFailedToSchedule=Failed to schedule this job, %s JobFailedToFind=Failed to find the job name %s JobRescheduling=Rescheduling %s with %s ms delay JobStarting=Starting %s -JobNoAutoStart=Job %s not configured for auto start LauncherLogLocation=Log output will be written to %s LauncherMissingArgument=Check the argument you passed in. --%s takes an argument of {groupId},{externalId} LauncherMissingFilenameTriggerSQL=Please provide a file name to write the trigger SQL to @@ -198,9 +175,7 @@ Option=Option: name=%s, value=%s PlatformInUse=The DDLUtils platform being used is %s PlatformTurningOnDelimitedIdentifierMode=Turning on delimited identifier mode for ddlutils PostgreSqlCustomVariableMissing=Please add "custom_variable_classes = 'symmetric'" to your postgresql.conf file -PostTriggerCreateFailed=Failed to create post trigger: %s -RegisteredNodeStarting=Starting registered node [group=%s, id=%s, externalId=%s] -RegistrationEmpty=%s attempted registration, but was sent an empty configuration. +RegisteredNodeStarting= RegistrationFailed=Registration attempt failed. Registration was not open for the node. RegistrationLost=Registration was lost. Attempting to re-register. RegistrationNotAllowed=%s was not allowed to register. @@ -208,7 +183,7 @@ RegistrationNotAllowedNoInitialLoad=Registration is not allowed until this node RegistrationOpened=Opened Registration for %s RegistrationRedirecting=Redirecting %s to %s for registration. RegistrationRedirectsMissing=There are no registration redirect nodes configured. -RegistrationRequired=Registration is required before this operation can complete. +RegistrationRequired=. ReloadedNode=Inserted reload events for node %s in %d ms RouterGeneralError=Error in data router. Routing to nobody. RouterInitialLoadNotRouted=%d data rows were not routed during the initial load of %s because they were filtered out by the data router. @@ -255,9 +230,9 @@ SymmetricDSClosing=Closing SymmetricDS externalId=%s version=%s database=%s SymmetricDSDatabaseNotAutoConfig=SymmetricDS is not configured to auto-create the database. SymmetricDSDatabaseInitializing=Initializing SymmetricDS database. SymmetricDSDatabaseInitialized=Done initializing SymmetricDS database. -SymmetricDSStarted=Started SymmetricDS -SymmetricDSInfo=SymmetricDS: type=%s, name=%s, version=%s, groupId=%s, externalId=%s, databaseName=%s, databaseVersion=%s, driverName=%s, driverVersion=%s -SymmetricDSNotStarted=Did not start SymmetricDS. It has not been configured properly. +SymmetricDSStarted= +SymmetricDSInfo= +SymmetricDSNotStarted=. SymmetricDSUpgradeFailed=The upgrade failed. The system may be unstable. Please resolve the problem manually. SymmetricDSUpgradeNeeded=Upgrade of node is necessary. Please set the auto.upgrade property to true for an automated upgrade. SymmetricDSManualUpgradeNeeded=A manual upgrade of the node is required. Can not automatically upgrade from version %s to version %s. @@ -265,20 +240,16 @@ SymmetricEngineMissing=Could not find a reference to the SymmetricEngine from %s SymmetricEngineDuplicateName=An engine with the name of %s was not started because an engine of the same name has already been started. Please set the engine.name property in the properties file to a unique name. SymmetricEngineNotRegistered=Did not run the %s job because the engine is not registered. SymmetricEngineNotStarted=The engine is not currently started. -SyncDisabled=Synchronization is disabled on the server node. +SyncDisabled=. TableDropped=Just dropped table %s_CONFIG TableDuplicating=Duplicating table %s into %s TableGeneratingEventsFailure=Not generating data/data events for table %s because a trigger or trigger hist is not created yet. TablesMissing=There are SymmetricDS tables missing. They will be auto created. -TablesAutoUpdatingStart=Checking if SymmetricDS tables need created or altered. -TablesAutoUpdatingFoundTablesToAlter = There are SymmetricDS tables that needed altered. -TablesAutoUpdatingAlterSql=Alter SQL Generated: %s -TablesAutoUpdatingDone=Done with auto update of SymmetricDS tables. TextMessagePublishing=Publishing text message %s TextMessagePublished=%s published %d messages in the last %d ms. TransactionIDSupportEnabling=Enabling transaction ID support -TransportFailedConnectionBusy=The server was too busy to accept the connection. -TransportFailedConnectionUnavailable=Could not connect to the transport: %s +TransportFailedConnectionBusy=. +TransportFailedConnectionUnavailable= TransportFailedUnknownHost=Could not connect to the transport because the host was unknown: %s TransportSyncURLOverriding=Overriding an existing '%s' extension sync url handler with a second one. TransportSyncURLBlank=Using the registration URL to contact the remote node because the syncURL for the node is blank. @@ -289,32 +260,30 @@ ThrottleFilterStarting=Before hit servlet ThrottleFilterCompleted=After hit servlet TriggerAlreadyExists=A trigger already exists for that name. Details are as follows: %s TriggerConfigurationCreatingFailed=Unexpected node group link while creating configuration triggers: source_node_group_id=%s, action=%s -TriggerCreateFailed=Failed to create trigger: %s -TriggerHistCleanup=Cleaning up trigger hist row of %d after failing to create the associated trigger -TriggerCreating=Creating %s trigger for %s +TriggerHistCleanup= TriggerDoesNotExist=Trigger does not exist TriggerDropped=Just dropped trigger %s TriggerDropError=Error removing %s: %s -TriggerHistCreating=Creating trigger hist entry for %s +TriggerHistCreating= TriggerHistMissing=Could not find a trigger hist record for recorded data %d. Was the trigger hist record deleted manually? TriggerInitializing=Initializing %s for %s TriggerMayExist=Could not figure out if the trigger exists. Assuming that is does not TriggerMissing=Could not find an %s trigger in the cache for table %s and a hist id of %s -TriggerNameTruncated=We just truncated the trigger name for the %s trigger id=%s. You might want to consider manually providing a name for the trigger that is less than %d characters long. +TriggerNameTruncated=. TriggerProcessingFailedMissing=Could not find trigger for trigger id of %s. Not processing data with the id of %s -TriggerTableMissing=The configured table does not exist in the datasource that is configured: %s +TriggerTableMissing= TriggerUnavailable=The trigger %s is no longer available for an initial load. TriggerRouterUnavailable=The trigger router with a trigger id of %s and router id of %s was not found -TriggersRemoving=About to remove triggers for inactivated table: %s -TriggersRemovingFailed=There are triggers that have been marked as inactive. Please remove triggers represented by trigger_id=%s and trigger_hist_id=%s -TriggerSynchronizingFailed=Failed to synchronize trigger for %s -TriggersSynchronizing=Synchronizing triggers -TriggerFoundWithInvalidChannelId=Trigger %s had an unrecognized channel_id of '%s'. Please check to make sure the channel exists. Creating trigger on the '%s' channel. +TriggersRemoving= +TriggersRemovingFailed= +TriggerSynchronizingFailed= +TriggersSynchronizing= +TriggerFoundWithInvalidChannelId= TriggersSynchronizingFailedLock=Did not run the syncTriggers process because the cluster service has it locked -TriggersSynchronized=Done synchronizing triggers -TriggersDefaultVersionWarning=Defaulting to major version %s because %s version was not valid while retrieving trigger configuration tables. +TriggersSynchronized= +TriggersDefaultVersionWarning= UpgradeWarning=The version of SymmetricDS incremented and %s is set to false. Please check to see if you need to update database schemas. -UnregisteredNodeStarting=Starting unregistered node [group=%s, externalId=%s] +UnregisteredNodeStarting= URLConnectingFailure=Could not connect to the %s node's transport because of a bad URL: %s WebServerInitializeError=Failed to initialize the web server context. WebServerStarting=About to start %s web server on port %d @@ -358,12 +327,12 @@ LookupColumnTransform.multipleRows=Expected a single row, but returned multiple LookupColumnTransform.noRows=Expected a single row, but returned no rows from lookup for target column %s on transform %s LookupColumnTransform.noSql=Expected SQL expression for lookup transform, but no expression was found for target column %s on transform %s XmlPublisherTableNotFound='%s' not in list to publish -ValidationSetRegistrationUrl=Please set the property %s so this node may pull registration or manually insert configuration into the configuration tables. -ValidationComparePropertiesToDatabase=The configured state does not match recorded database state. The recorded external id is %s while the configured external id is %s. The recorded node group id is %s while the configured node group id is %s. -ValidationMakeSureSyncUrlIsSet=The sync.url property must be set for the registration server. Otherwise, registering nodes will not be able to sync with it. -ValidationOfflineSettings=The %s property must be a longer period of time than the %s property. Otherwise, nodes will be taken offline before the heartbeat job has a chance to run. -ValidationPleaseSetMe=Please set the registration.url, node.group.id, and external.id for the node. -ValidationRegServerIsMissingConfiguration=This node is configured as a registration server, but it is missing its node_identity. It probably needs configured. +ValidationSetRegistrationUrl=. +ValidationComparePropertiesToDatabase=. +ValidationMakeSureSyncUrlIsSet=. +ValidationOfflineSettings=. +ValidationPleaseSetMe=. +ValidationRegServerIsMissingConfiguration= RemovedTriggers=Remove %d triggers TransformTypeInvalid=Invalid transform type of %s for transform %s with source column of %s. %s TransformMatchingFallbackNotFound=Could not find a matching transform while falling back to %s diff --git a/symmetric/symmetric-core/src/main/resources/symmetric-properties.xml b/symmetric/symmetric-core/src/main/resources/symmetric-properties.xml deleted file mode 100644 index 143d00678c..0000000000 --- a/symmetric/symmetric-core/src/main/resources/symmetric-properties.xml +++ /dev/null @@ -1,43 +0,0 @@ - - - - - - - - - classpath:/symmetric-default.properties - classpath:/symmetric-console-default.properties - file:../conf/symmetric.properties - classpath:/symmetric.properties - classpath:/symmetric-override.properties - file:${user.home}/.symmetric/symmetric-override.properties - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/symmetric/symmetric-core/src/main/resources/symmetric-routers.xml b/symmetric/symmetric-core/src/main/resources/symmetric-routers.xml deleted file mode 100644 index c716cabc6f..0000000000 --- a/symmetric/symmetric-core/src/main/resources/symmetric-routers.xml +++ /dev/null @@ -1,71 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/symmetric/symmetric-core/src/main/resources/symmetric-services.xml b/symmetric/symmetric-core/src/main/resources/symmetric-services.xml deleted file mode 100644 index b253152d4f..0000000000 --- a/symmetric/symmetric-core/src/main/resources/symmetric-services.xml +++ /dev/null @@ -1,412 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - $[sym.sync.table.prefix]_node_group - $[sym.sync.table.prefix]_node_group_link - $[sym.sync.table.prefix]_node - $[sym.sync.table.prefix]_node_security - $[sym.sync.table.prefix]_parameter - $[sym.sync.table.prefix]_channel - $[sym.sync.table.prefix]_node_channel_ctl - $[sym.sync.table.prefix]_node_group_channel_window - $[sym.sync.table.prefix]_trigger - $[sym.sync.table.prefix]_router - $[sym.sync.table.prefix]_trigger_router - $[sym.sync.table.prefix]_transform_table - $[sym.sync.table.prefix]_transform_column - $[sym.sync.table.prefix]_node_identity - - - - - $[sym.sync.table.prefix]_node_group - $[sym.sync.table.prefix]_node_group_link - $[sym.sync.table.prefix]_node - $[sym.sync.table.prefix]_node_security - $[sym.sync.table.prefix]_parameter - $[sym.sync.table.prefix]_channel - $[sym.sync.table.prefix]_node_channel_ctl - $[sym.sync.table.prefix]_trigger - $[sym.sync.table.prefix]_node_identity - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/symmetric/symmetric-core/src/main/resources/symmetric-upgrade.xml b/symmetric/symmetric-core/src/main/resources/symmetric-upgrade.xml deleted file mode 100644 index 5479285f2d..0000000000 --- a/symmetric/symmetric-core/src/main/resources/symmetric-upgrade.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/symmetric/symmetric-core/src/test/java/org/jumpmind/symmetric/db/GenSqlMap.java b/symmetric/symmetric-core/src/test/java/org/jumpmind/symmetric/db/GenSqlMap.java deleted file mode 100644 index f5419fd10a..0000000000 --- a/symmetric/symmetric-core/src/test/java/org/jumpmind/symmetric/db/GenSqlMap.java +++ /dev/null @@ -1,83 +0,0 @@ -package org.jumpmind.symmetric.db; - -import java.io.File; -import java.util.Map; -import java.util.Set; - -import org.apache.commons.io.FileUtils; -import org.apache.commons.lang.StringUtils; -import org.springframework.context.support.ClassPathXmlApplicationContext; - -public class GenSqlMap { - - @SuppressWarnings({ "rawtypes", "unchecked" }) - public static void main(String[] args) throws Exception { - ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext( - "classpath:/symmetric-client.xml"); - Map beans = ctx.getBeansOfType(Map.class); - Set keys = beans.keySet(); - for (String k : keys) { - if (k.endsWith("Sql")) { - System.out.println(k); - Map sql = beans.get(k); - String className = k.substring(0, 1).toUpperCase() - + k.subSequence(1, k.length() - 3) + "SqlMap"; - String fileName = className + ".java"; - File file = new File("target", fileName); - StringBuilder b = new StringBuilder(); - b.append("package org.jumpmind.symmetric.service.impl;"); - b.append("\n"); - b.append("\n"); - b.append("import org.jumpmind.db.IDatabasePlatform;\n"); - b.append("import org.jumpmind.db.sql.AbstractSqlMap;\n"); - b.append("import java.util.Map;\n"); - b.append("\n"); - b.append("public class " + className + " extends AbstractSqlMap {"); - b.append("\n"); - b.append("\n"); - b.append(" public " + className - + "(IDatabasePlatform platform, Map replacementTokens) { "); - b.append("\n"); - b.append(" super(platform, replacementTokens);\n"); - b.append("\n"); - for (String key : sql.keySet()) { - b.append(" putSql(" + v(key, ",\"\" + \n", 0) + v(sql.get(key), ");\n", 100)); - b.append("\n"); - } - b.append(" }"); - b.append("\n"); - b.append("\n"); - b.append("}"); - FileUtils.write(file, b); - } - } - - } - - protected static String v(String t, String suffix, int rightPad) { - if (t == null) { - return "null;\n"; - } else { - String v = ""; - String[] lines = t.trim().split("\n"); - int longestLine = 0; - for (int i = 0; i < lines.length; i++) { - lines[i] = lines[i].trim(); - lines[i] = lines[i].replace("\\", "\\\\").replace("\"", "\\\"") - .replace("sym_", "$(prefixName)_"); - if (i > 0) { - lines[i] = StringUtils.leftPad(lines[i], lines[i].length() + 2); - } - lines[i] = "\"" + lines[i]; - longestLine = longestLine < lines[i].length() + 3 ? lines[i].length() + 3 : longestLine; - } - - for (String line : lines) { - v = v + StringUtils.rightPad(line, longestLine) + "\" + \n"; - } - v = v.substring(0, v.length() - 3) + suffix; - return v; - } - } - -} diff --git a/symmetric/symmetric-core/src/test/java/org/jumpmind/symmetric/route/ConfigurationChangedDataRouterTest.java b/symmetric/symmetric-core/src/test/java/org/jumpmind/symmetric/route/ConfigurationChangedDataRouterTest.java index 1c1af04faf..c5da7a609c 100644 --- a/symmetric/symmetric-core/src/test/java/org/jumpmind/symmetric/route/ConfigurationChangedDataRouterTest.java +++ b/symmetric/symmetric-core/src/test/java/org/jumpmind/symmetric/route/ConfigurationChangedDataRouterTest.java @@ -162,7 +162,7 @@ public void testRouteS1toRegsvrFromS1() { protected DataMetaData buildDataMetaData(String tableName, String nodeId) { Data data = new Data(); data.setTableName(tableName); - data.setEventType(DataEventType.UPDATE); + data.setDataEventType(DataEventType.UPDATE); data.setTriggerHistory(new TriggerHistory(tableName, "NODE_ID", "NODE_ID")); data.setPkData(nodeId); data.setRowData(nodeId); diff --git a/symmetric/symmetric-server/src/test/java/org/jumpmind/symmetric/service/mock/MockNodeService.java b/symmetric/symmetric-core/src/test/java/org/jumpmind/symmetric/service/impl/MockNodeService.java similarity index 96% rename from symmetric/symmetric-server/src/test/java/org/jumpmind/symmetric/service/mock/MockNodeService.java rename to symmetric/symmetric-core/src/test/java/org/jumpmind/symmetric/service/impl/MockNodeService.java index 55e20c3607..a2900b4db3 100644 --- a/symmetric/symmetric-server/src/test/java/org/jumpmind/symmetric/service/mock/MockNodeService.java +++ b/symmetric/symmetric-core/src/test/java/org/jumpmind/symmetric/service/impl/MockNodeService.java @@ -19,7 +19,7 @@ * under the License. */ -package org.jumpmind.symmetric.service.mock; +package org.jumpmind.symmetric.service.impl; import java.util.Collection; import java.util.List; diff --git a/symmetric/symmetric-server/src/test/java/org/jumpmind/symmetric/transport/http/HttpBandwidthBalancerUnitTest.java b/symmetric/symmetric-core/src/test/java/org/jumpmind/symmetric/transport/http/HttpBandwidthBalancerTest.java similarity index 72% rename from symmetric/symmetric-server/src/test/java/org/jumpmind/symmetric/transport/http/HttpBandwidthBalancerUnitTest.java rename to symmetric/symmetric-core/src/test/java/org/jumpmind/symmetric/transport/http/HttpBandwidthBalancerTest.java index 1fa44a25c2..c03137178f 100644 --- a/symmetric/symmetric-server/src/test/java/org/jumpmind/symmetric/transport/http/HttpBandwidthBalancerUnitTest.java +++ b/symmetric/symmetric-core/src/test/java/org/jumpmind/symmetric/transport/http/HttpBandwidthBalancerTest.java @@ -16,7 +16,8 @@ * "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. */ + * under the License. + */ package org.jumpmind.symmetric.transport.http; @@ -25,20 +26,18 @@ import junit.framework.Assert; +import org.jumpmind.log.LogFactory; import org.jumpmind.symmetric.service.IBandwidthService; -import org.jumpmind.symmetric.service.mock.MockNodeService; +import org.jumpmind.symmetric.service.impl.MockNodeService; import org.junit.Test; -/** - * - */ -public class HttpBandwidthBalancerUnitTest { +public class HttpBandwidthBalancerTest { @Test public void testUriParsing() throws Exception { URI uri = new URI( "ext://plugin/?1=http://rgn.com/sync&2=http://rgn2.com/sync&sampleBytes=1000&sampleTTL=200&initialLoadOnly=true"); - HttpBandwidthUrlSelector ext = new HttpBandwidthUrlSelector(); + HttpBandwidthUrlSelector ext = getMockBandwidthBalancer(true); Map params = ext.getParameters(uri); Assert.assertEquals("http://rgn.com/sync", params.get("1")); Assert.assertEquals("http://rgn2.com/sync", params.get("2")); @@ -50,16 +49,18 @@ public void testUriParsing() throws Exception { @Test public void testResolveUrl() throws Exception { HttpBandwidthUrlSelector ext = getMockBandwidthBalancer(false); - URI uri = new URI("ext://balancer?10=100&100=50&"+HttpBandwidthUrlSelector.PARAM_PRELOAD_ONLY+"=true"); + URI uri = new URI("ext://balancer?10=100&100=50&" + + HttpBandwidthUrlSelector.PARAM_PRELOAD_ONLY + "=true"); Assert.assertEquals("50", ext.resolveUrl(uri)); ext = getMockBandwidthBalancer(true); Assert.assertEquals("100", ext.resolveUrl(uri)); } - + @Test public void testSampleTTL() throws Exception { HttpBandwidthUrlSelector ext = getMockBandwidthBalancer(true); - URI uri = new URI("ext://balancer?1=100&2=1&"+HttpBandwidthUrlSelector.PARAM_SAMPLE_TTL+"=1000"); + URI uri = new URI("ext://balancer?1=100&2=1&" + HttpBandwidthUrlSelector.PARAM_SAMPLE_TTL + + "=1000"); Assert.assertEquals("1", ext.resolveUrl(uri)); long ts = ext.lastSampleTs; Assert.assertEquals("1", ext.resolveUrl(uri)); @@ -68,20 +69,20 @@ public void testSampleTTL() throws Exception { Assert.assertEquals("1", ext.resolveUrl(uri)); Assert.assertNotSame(ts, ext.lastSampleTs); } - + protected HttpBandwidthUrlSelector getMockBandwidthBalancer(final boolean dataLoadCompleted) { - HttpBandwidthUrlSelector ext = new HttpBandwidthUrlSelector(); - ext.setBandwidthService(new IBandwidthService() { - public double getDownloadKbpsFor(String url, long sampleSize, long maxTestDuration) { - return sampleSize / Double.parseDouble(url); - } - }); - ext.setNodeService(new MockNodeService() { - @Override - public boolean isDataLoadCompleted() { - return dataLoadCompleted; - } - }); + HttpBandwidthUrlSelector ext = new HttpBandwidthUrlSelector(LogFactory.getLog(getClass()), + new MockNodeService() { + @Override + public boolean isDataLoadCompleted() { + return dataLoadCompleted; + } + }, new IBandwidthService() { + public double getDownloadKbpsFor(String url, long sampleSize, + long maxTestDuration) { + return sampleSize / Double.parseDouble(url); + } + }); return ext; } diff --git a/symmetric/symmetric-db/src/main/java/org/jumpmind/db/model/Table.java b/symmetric/symmetric-db/src/main/java/org/jumpmind/db/model/Table.java index 02ddc7ddc6..d609db7d30 100644 --- a/symmetric/symmetric-db/src/main/java/org/jumpmind/db/model/Table.java +++ b/symmetric/symmetric-db/src/main/java/org/jumpmind/db/model/Table.java @@ -87,6 +87,18 @@ public Table(String catalog, String schema, String tableName) { this.name = tableName; } + public Table(String catalog, String schema, String tableName, String[] columnNames, + String[] keyNames) { + this(catalog, schema, tableName); + for (String name : columnNames) { + addColumn(new Column(name)); + } + for (String name : keyNames) { + getColumnWithName(name).setPrimaryKey(true); + } + + } + /** * Returns the catalog of this table as read from the database. * @@ -194,7 +206,7 @@ public int getColumnCount() { public int getPrimaryKeyColumnCount() { return getPrimaryKeyColumns().length; } - + /** * Returns the column at the specified position. * @@ -955,6 +967,14 @@ public void reOrderColumns(Column[] targetOrder, boolean copyPrimaryKeys) { columns = orderedColumns; } + public void orderColumns(String[] columnNames) { + Column[] orderedColumns = orderColumns(columnNames, this); + this.columns.clear(); + for (Column column : orderedColumns) { + this.columns.add(column); + } + } + public static Column[] orderColumns(String[] columnNames, Table table) { Column[] unorderedColumns = table.getColumns(); Column[] orderedColumns = new Column[columnNames.length]; @@ -1005,7 +1025,7 @@ public String[] getPrimaryKeyColumnNames() { } return columnNames; } - + public static Table buildTable(String tableName, String[] keyNames, String[] columnNames) { Table table = new Table(); table.setName(tableName); diff --git a/symmetric/symmetric-db/src/main/java/org/jumpmind/db/platform/DatabasePlatformSettings.java b/symmetric/symmetric-db/src/main/java/org/jumpmind/db/platform/DatabasePlatformSettings.java index 4c124133e5..dad468b33a 100644 --- a/symmetric/symmetric-db/src/main/java/org/jumpmind/db/platform/DatabasePlatformSettings.java +++ b/symmetric/symmetric-db/src/main/java/org/jumpmind/db/platform/DatabasePlatformSettings.java @@ -4,13 +4,15 @@ public class DatabasePlatformSettings { protected int fetchSize = 1000; protected int queryTimeout; + protected int batchSize = 100; public DatabasePlatformSettings() { } - public DatabasePlatformSettings(int fetchSize, int queryTimeout) { + public DatabasePlatformSettings(int fetchSize, int queryTimeout, int batchSize) { this.fetchSize = fetchSize; this.queryTimeout = queryTimeout; + this.batchSize = batchSize; } public void setFetchSize(int fetchSize) { @@ -28,5 +30,13 @@ public void setQueryTimeout(int queryTimeout) { public int getQueryTimeout() { return queryTimeout; } + + public void setBatchSize(int batchSize) { + this.batchSize = batchSize; + } + + public int getBatchSize() { + return batchSize; + } } diff --git a/symmetric/symmetric-db/src/main/java/org/jumpmind/db/sql/AbstractSqlMap.java b/symmetric/symmetric-db/src/main/java/org/jumpmind/db/sql/AbstractSqlMap.java index 47f5ce6e67..a4b7ae9133 100644 --- a/symmetric/symmetric-db/src/main/java/org/jumpmind/db/sql/AbstractSqlMap.java +++ b/symmetric/symmetric-db/src/main/java/org/jumpmind/db/sql/AbstractSqlMap.java @@ -10,7 +10,7 @@ * Utility SQL container that should be sub-classed in order to populate with * SQL statements from the subclasses constructor. */ -abstract public class AbstractSqlMap { +abstract public class AbstractSqlMap implements ISqlMap { private IDatabasePlatform platform; diff --git a/symmetric/symmetric-db/src/main/java/org/jumpmind/db/sql/AbstractSqlTemplate.java b/symmetric/symmetric-db/src/main/java/org/jumpmind/db/sql/AbstractSqlTemplate.java index 3fdf80efdf..c10047f799 100644 --- a/symmetric/symmetric-db/src/main/java/org/jumpmind/db/sql/AbstractSqlTemplate.java +++ b/symmetric/symmetric-db/src/main/java/org/jumpmind/db/sql/AbstractSqlTemplate.java @@ -14,12 +14,43 @@ abstract public class AbstractSqlTemplate implements ISqlTemplate { protected String identifierQuoteString; - public int queryForInt(String sql) { - return queryForObject(sql, Number.class, (Object[]) null).intValue(); + public T queryForObject(String sql, ISqlRowMapper mapper, Object... args) { + List list = query(sql, mapper, args); + if (list != null && list.size() > 0) { + return list.get(0); + } else { + return null; + } } - public ISqlReadCursor queryForCursor(Query query, ISqlRowMapper mapper) { - return this.queryForCursor(query.getSql(), mapper, query.getArgs(), query.getArgTypes()); + public int queryForInt(String sql, Object... args) { + Number number = queryForObject(sql, Number.class, args); + if (number != null) { + return number.intValue(); + } else { + return 0; + } + } + + public long queryForLong(String sql, Object... args) { + Number number = queryForObject(sql, Number.class, args); + if (number != null) { + return number.longValue(); + } else { + return 0l; + } + } + + public Map queryForMap(String sql, final String keyColumn, final String valueColumn, + Object... args) { + final Map map = new HashMap(); + query(sql, new ISqlRowMapper() { + public Object mapRow(Row rs) { + map.put(rs.getString(keyColumn), rs.getString(valueColumn)); + return null; + } + }, args); + return map; } public ISqlReadCursor queryForCursor(String sql, ISqlRowMapper mapper) { @@ -48,6 +79,26 @@ public Map query(String sql, String keyCol, String valueCol, Object } return map; } + + public List query(String sql, int maxRowsToFetch, ISqlRowMapper mapper, + Object... params) { + return query(sql, maxRowsToFetch, mapper, params, null); + } + + public List query(String sql, int maxRowsToFetch, ISqlRowMapper mapper, + Map namedParams) { + ParsedSql parsedSql = NamedParameterUtils.parseSqlStatement(sql); + String newSql = NamedParameterUtils.substituteNamedParameters(parsedSql, namedParams); + Object[] params = NamedParameterUtils.buildValueArray(parsedSql, namedParams); + return query(newSql, maxRowsToFetch, mapper, params, null); + } + + public List query(String sql, ISqlRowMapper mapper, Map namedParams) { + ParsedSql parsedSql = NamedParameterUtils.parseSqlStatement(sql); + String newSql = NamedParameterUtils.substituteNamedParameters(parsedSql, namedParams); + Object[] params = NamedParameterUtils.buildValueArray(parsedSql, namedParams); + return query(newSql, mapper, params, null); + } public List query(String sql, Object[] args, int[] types) { return query(sql, new ISqlRowMapper() { @@ -56,20 +107,27 @@ public Row mapRow(Row row) { } }, args, types); } - - public List query(String sql, ISqlRowMapper mapper) { - return query(sql, mapper, null, null); + + public List query(String sql, ISqlRowMapper mapper, Object[] args, int[] types) { + return query(sql, -1, mapper, args, types); } - public List query(String sql, ISqlRowMapper mapper, Object[] args, int[] types) { + public List query(String sql, int maxNumberOfRowsToFetch, ISqlRowMapper mapper, + Object[] args, int[] types) { ISqlReadCursor cursor = queryForCursor(sql, mapper, args, types); try { T next = null; List list = new ArrayList(); + int rowCount = 0; do { next = cursor.next(); if (next != null) { list.add(next); + rowCount++; + } + + if (maxNumberOfRowsToFetch > 0 && rowCount >= maxNumberOfRowsToFetch) { + break; } } while (next != null); return list; @@ -79,17 +137,9 @@ public List query(String sql, ISqlRowMapper mapper, Object[] args, int } } } - - public int update(String sql, Object[] values) { - return update(sql, values, null); - } - public int update(String sql) { - return update(sql, null, null); - } - - public int update(String... sql) { - return update(true, true, -1, sql); + public int update(String sql, Object... values) { + return update(sql, values, null); } public int update(Table table, Map params) { @@ -120,4 +170,67 @@ protected int update(DmlType type, Table table, Map params) { return update(sql, values, types); } + protected String expandSql(String sql, Object[] args) { + if (args != null && args.length > 0) { + for (Object arg : args) { + if (arg instanceof SqlList) { + SqlList list = (SqlList) arg; + StringBuilder sqllist = new StringBuilder(); + for (int i = 0; i < list.size(); i++) { + sqllist.append("?"); + if (i < list.size() - 1) { + sqllist.append(","); + } + } + sql = sql.replaceFirst(list.getReplacementToken(), sqllist.toString()); + } else if (arg instanceof SqlToken) { + SqlToken token = (SqlToken) arg; + sql = sql.replaceFirst(token.getReplacementToken(), "?"); + } + } + } + return sql; + } + + protected Object[] expandArgs(String sql, Object[] args) { + if (args != null && args.length > 0) { + List argsList = null; + for (int i = 0; i < args.length; i++) { + Object arg = args[i]; + if (arg instanceof SqlList) { + if (argsList == null) { + argsList = new ArrayList(); + for (int j = 0; j < i; j++) { + argsList.add(args[j]); + } + } + SqlList list = (SqlList) arg; + if (sql.contains(list.getReplacementToken())) { + for (Object listItem : list) { + argsList.add(listItem); + } + } + } else if (arg instanceof SqlToken) { + if (argsList == null) { + argsList = new ArrayList(); + for (int j = 0; j < i; j++) { + argsList.add(args[j]); + } + } + SqlToken token = (SqlToken) arg; + if (sql.contains(token.getReplacementToken())) { + argsList.add(token.getValue()); + } + } else if (argsList != null) { + argsList.add(arg); + } + } + + if (argsList != null) { + args = argsList.toArray(new Object[argsList.size()]); + } + } + return args; + } + } diff --git a/symmetric/symmetric-db/src/main/java/org/jumpmind/db/sql/ISqlMap.java b/symmetric/symmetric-db/src/main/java/org/jumpmind/db/sql/ISqlMap.java new file mode 100644 index 0000000000..11dcfc110d --- /dev/null +++ b/symmetric/symmetric-db/src/main/java/org/jumpmind/db/sql/ISqlMap.java @@ -0,0 +1,7 @@ +package org.jumpmind.db.sql; + +public interface ISqlMap { + + public String getSql(String... keys); + +} diff --git a/symmetric/symmetric-db/src/main/java/org/jumpmind/db/sql/ISqlRowMapper.java b/symmetric/symmetric-db/src/main/java/org/jumpmind/db/sql/ISqlRowMapper.java index a664267465..b993fbfdbf 100644 --- a/symmetric/symmetric-db/src/main/java/org/jumpmind/db/sql/ISqlRowMapper.java +++ b/symmetric/symmetric-db/src/main/java/org/jumpmind/db/sql/ISqlRowMapper.java @@ -2,5 +2,5 @@ public interface ISqlRowMapper { - public T mapRow(Row row); + public T mapRow(Row rs); } diff --git a/symmetric/symmetric-db/src/main/java/org/jumpmind/db/sql/ISqlTemplate.java b/symmetric/symmetric-db/src/main/java/org/jumpmind/db/sql/ISqlTemplate.java index 27208a19cc..a409e63daa 100644 --- a/symmetric/symmetric-db/src/main/java/org/jumpmind/db/sql/ISqlTemplate.java +++ b/symmetric/symmetric-db/src/main/java/org/jumpmind/db/sql/ISqlTemplate.java @@ -2,6 +2,7 @@ import java.util.List; import java.util.Map; +import java.util.Set; import org.jumpmind.db.model.Table; @@ -15,12 +16,20 @@ public interface ISqlTemplate { public String queryForClob(String sql, Object... args); public T queryForObject(String sql, Class clazz, Object... params); + + public T queryForObject(String sql, ISqlRowMapper mapper, Object... params); + + public int queryForInt(String sql, Object... args); - public Map queryForMap(String sql, Object... params); + public long queryForLong(String sql, Object... args); - public int queryForInt(String sql); + public Map queryForMap(String sql, Object... params); - public ISqlReadCursor queryForCursor(Query query, ISqlRowMapper mapper); + public Map queryForMap(String sql, ISqlRowMapper mapper, String keyColumn, + Object... args); + + public Map queryForMap(String sql, String keyColumn, String valueColumn, + Object... args); public ISqlReadCursor queryForCursor(String sql, ISqlRowMapper mapper, Object[] params, int[] types); @@ -30,27 +39,27 @@ public ISqlReadCursor queryForCursor(String sql, ISqlRowMapper mapper, public List query(String sql); public List query(String sql, Object[] params, int[] types); - - public List query(String sql, ISqlRowMapper mapper); + + public List query(String sql, ISqlRowMapper mapper, Map namedParams); public List query(String sql, ISqlRowMapper mapper, Object... params); public List query(String sql, ISqlRowMapper mapper, Object[] params, int[] types); - - public List query(Query query, ISqlRowMapper mapper); + + public List query(String sql, int maxRowsToFetch, ISqlRowMapper mapper, Object[] params, int[] types); + + public List query(String sql, int maxRowsToFetch, ISqlRowMapper mapper, Object... params); + + public List query(String sql, int maxRowsToFetch, ISqlRowMapper mapper, Map params); public Map query(String sql, String keyCol, String valueCol, Object[] params, int[] types); - public int update(String sql); - - public int update(String... sql); - public int update(boolean autoCommit, boolean failOnError, int commitRate, String... sql); public int update(String sql, Object[] values, int[] types); - public int update(String sql, Object[] values); + public int update(String sql, Object... values); public int update(Table table, Map params); @@ -72,4 +81,17 @@ public Map query(String sql, String keyCol, String valueCol, Object public String getDatabaseProductName(); + public String getDatabaseProductVersion(); + + public String getDriverName(); + + public String getDriverVersion(); + + public Set getSqlKeywords(); + + public boolean supportsGetGeneratedKeys(); + + public long insertWithGeneratedKey(final String sql, String column, final String sequenceName, + final Object[] args, final int[] types); + } diff --git a/symmetric/symmetric-db/src/main/java/org/jumpmind/db/sql/ISqlTransaction.java b/symmetric/symmetric-db/src/main/java/org/jumpmind/db/sql/ISqlTransaction.java index 0f2c69df95..5645cb3b52 100644 --- a/symmetric/symmetric-db/src/main/java/org/jumpmind/db/sql/ISqlTransaction.java +++ b/symmetric/symmetric-db/src/main/java/org/jumpmind/db/sql/ISqlTransaction.java @@ -10,16 +10,12 @@ public interface ISqlTransaction { public void setInBatchMode(boolean batchMode); - public void setNumberOfRowsBeforeBatchFlush(int numberOfRowsBeforeBatchFlush); - - public int getNumberOfRowsBeforeBatchFlush(); - public T queryForObject(final String sql, Class clazz, final Object... args); - + public int queryForInt(final String sql, final Object... args); - public int execute(final String sql, Object... args); - + public int execute(final String sql, Object... args); + public void commit(); public void rollback(); @@ -36,11 +32,14 @@ public interface ISqlTransaction { public int flush(); public List getUnflushedMarkers(boolean clear); - + /** - * Indicate that the current session is to allow updates to columns that have been - * marked as auto increment. This is specific to SQL Server. + * Indicate that the current session is to allow updates to columns that + * have been marked as auto increment. This is specific to SQL Server. */ public void allowInsertIntoAutoIncrementColumns(boolean value, Table table); + public long insertWithGeneratedKey(String sql, String column, String sequenceName, + Object... args); + } diff --git a/symmetric/symmetric-db/src/main/java/org/jumpmind/db/sql/NamedParameterUtils.java b/symmetric/symmetric-db/src/main/java/org/jumpmind/db/sql/NamedParameterUtils.java new file mode 100644 index 0000000000..40e53207b0 --- /dev/null +++ b/symmetric/symmetric-db/src/main/java/org/jumpmind/db/sql/NamedParameterUtils.java @@ -0,0 +1,284 @@ +/* + * Copyright 2002-2011 the original author or authors. + * + * Licensed 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.jumpmind.db.sql; + +import java.util.Collection; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; + +/** + * Helper methods for named parameter parsing. Only intended for internal use + * within Spring's JDBC framework. + * + * @author Thomas Risberg + * @author Juergen Hoeller + * @since 2.0 + */ +public abstract class NamedParameterUtils { + + /** + * Set of characters that qualify as parameter separators, indicating that a + * parameter name in a SQL String has ended. + */ + private static final char[] PARAMETER_SEPARATORS = new char[] { '"', '\'', ':', '&', ',', ';', + '(', ')', '|', '=', '+', '-', '*', '%', '/', '\\', '<', '>', '^' }; + + /** + * Set of characters that qualify as comment or quotes starting characters. + */ + private static final String[] START_SKIP = new String[] { "'", "\"", "--", "/*" }; + + /** + * Set of characters that at are the corresponding comment or quotes ending + * characters. + */ + private static final String[] STOP_SKIP = new String[] { "'", "\"", "\n", "*/" }; + + // ------------------------------------------------------------------------- + // Core methods used by NamedParameterJdbcTemplate and SqlQuery/SqlUpdate + // ------------------------------------------------------------------------- + + /** + * Parse the SQL statement and locate any placeholders or named parameters. + * Named parameters are substituted for a JDBC placeholder. + * + * @param sql + * the SQL statement + * @return the parsed statement, represented as ParsedSql instance + */ + public static ParsedSql parseSqlStatement(String sql) { + Set namedParameters = new HashSet(); + ParsedSql parsedSql = new ParsedSql(sql); + + char[] statement = sql.toCharArray(); + int namedParameterCount = 0; + int unnamedParameterCount = 0; + int totalParameterCount = 0; + + int i = 0; + while (i < statement.length) { + int skipToPosition = skipCommentsAndQuotes(statement, i); + if (i != skipToPosition) { + if (skipToPosition >= statement.length) { + break; + } + i = skipToPosition; + } + char c = statement[i]; + if (c == ':' || c == '&') { + int j = i + 1; + if (j < statement.length && statement[j] == ':' && c == ':') { + // Postgres-style "::" casting operator - to be skipped. + i = i + 2; + continue; + } + while (j < statement.length && !isParameterSeparator(statement[j])) { + j++; + } + if (j - i > 1) { + String parameter = sql.substring(i + 1, j); + if (!namedParameters.contains(parameter)) { + namedParameters.add(parameter); + namedParameterCount++; + } + parsedSql.addNamedParameter(parameter, i, j); + totalParameterCount++; + } + i = j - 1; + } else { + if (c == '?') { + unnamedParameterCount++; + totalParameterCount++; + } + } + i++; + } + parsedSql.setNamedParameterCount(namedParameterCount); + parsedSql.setUnnamedParameterCount(unnamedParameterCount); + parsedSql.setTotalParameterCount(totalParameterCount); + return parsedSql; + } + + /** + * Skip over comments and quoted names present in an SQL statement + * + * @param statement + * character array containing SQL statement + * @param position + * current position of statement + * @return next position to process after any comments or quotes are skipped + */ + private static int skipCommentsAndQuotes(char[] statement, int position) { + for (int i = 0; i < START_SKIP.length; i++) { + if (statement[position] == START_SKIP[i].charAt(0)) { + boolean match = true; + for (int j = 1; j < START_SKIP[i].length(); j++) { + if (!(statement[position + j] == START_SKIP[i].charAt(j))) { + match = false; + break; + } + } + if (match) { + int offset = START_SKIP[i].length(); + for (int m = position + offset; m < statement.length; m++) { + if (statement[m] == STOP_SKIP[i].charAt(0)) { + boolean endMatch = true; + int endPos = m; + for (int n = 1; n < STOP_SKIP[i].length(); n++) { + if (m + n >= statement.length) { + // last comment not closed properly + return statement.length; + } + if (!(statement[m + n] == STOP_SKIP[i].charAt(n))) { + endMatch = false; + break; + } + endPos = m + n; + } + if (endMatch) { + // found character sequence ending comment or + // quote + return endPos + 1; + } + } + } + // character sequence ending comment or quote not found + return statement.length; + } + + } + } + return position; + } + + /** + * Parse the SQL statement and locate any placeholders or named parameters. + * Named parameters are substituted for a JDBC placeholder and any select + * list is expanded to the required number of placeholders. Select lists may + * contain an array of objects and in that case the placeholders will be + * grouped and enclosed with parantheses. This allows for the use of + * "expression lists" in the SQL statement like:
+ * select id, name, state from table where (name, age) in (('John', 35), + * ('Ann', 50)) + *

+ * The parameter values passed in are used to determine the number of + * placeholder to be used for a select list. Select lists should be limited + * to 100 or fewer elements. A larger number of elements is not guaramteed + * to be supported by the database and is strictly vendor-dependent. + * + * @param parsedSql + * the parsed represenation of the SQL statement + * @param paramSource + * the source for named parameters + * @return the SQL statement with substituted parameters + * @see #parseSqlStatement + */ + public static String substituteNamedParameters(ParsedSql parsedSql, + Map paramSource) { + String originalSql = parsedSql.getOriginalSql(); + StringBuilder actualSql = new StringBuilder(); + List paramNames = parsedSql.getParameterNames(); + int lastIndex = 0; + for (int i = 0; i < paramNames.size(); i++) { + String paramName = (String) paramNames.get(i); + int[] indexes = parsedSql.getParameterIndexes(i); + int startIndex = indexes[0]; + int endIndex = indexes[1]; + actualSql.append(originalSql.substring(lastIndex, startIndex)); + if (paramSource != null && paramSource.containsKey(paramName)) { + Object value = paramSource.get(paramName); + if (value instanceof Collection) { + Iterator entryIter = ((Collection) value).iterator(); + int k = 0; + while (entryIter.hasNext()) { + if (k > 0) { + actualSql.append(", "); + } + k++; + Object entryItem = entryIter.next(); + if (entryItem instanceof Object[]) { + Object[] expressionList = (Object[]) entryItem; + actualSql.append("("); + for (int m = 0; m < expressionList.length; m++) { + if (m > 0) { + actualSql.append(", "); + } + actualSql.append("?"); + } + actualSql.append(")"); + } else { + actualSql.append("?"); + } + } + } else { + actualSql.append("?"); + } + } else { + actualSql.append("?"); + } + lastIndex = endIndex; + } + actualSql.append(originalSql.substring(lastIndex, originalSql.length())); + return actualSql.toString(); + } + + /** + * Convert a Map of named parameter values to a corresponding array. + * + * @param parsedSql + * the parsed SQL statement + * @param paramSource + * the source for named parameters + * @return the array of values + */ + public static Object[] buildValueArray(ParsedSql parsedSql, Map paramSource) { + Object[] paramArray = new Object[parsedSql.getTotalParameterCount()]; + if (parsedSql.getNamedParameterCount() > 0 && parsedSql.getUnnamedParameterCount() > 0) { + throw new IllegalStateException( + "You can't mix named and traditional ? placeholders. You have " + + parsedSql.getNamedParameterCount() + " named parameter(s) and " + + parsedSql.getUnnamedParameterCount() + + " traditonal placeholder(s) in [" + parsedSql.getOriginalSql() + "]"); + } + List paramNames = parsedSql.getParameterNames(); + for (int i = 0; i < paramNames.size(); i++) { + String paramName = paramNames.get(i); + paramArray[i] = paramSource.get(paramName); + } + return paramArray; + } + + /** + * Determine whether a parameter name ends at the current position, that is, + * whether the given character qualifies as a separator. + */ + private static boolean isParameterSeparator(char c) { + if (Character.isWhitespace(c)) { + return true; + } + for (char separator : PARAMETER_SEPARATORS) { + if (c == separator) { + return true; + } + } + return false; + } + +} diff --git a/symmetric/symmetric-db/src/main/java/org/jumpmind/db/sql/ParsedSql.java b/symmetric/symmetric-db/src/main/java/org/jumpmind/db/sql/ParsedSql.java new file mode 100644 index 0000000000..1b37fcb6f0 --- /dev/null +++ b/symmetric/symmetric-db/src/main/java/org/jumpmind/db/sql/ParsedSql.java @@ -0,0 +1,145 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed 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.jumpmind.db.sql; + +import java.util.ArrayList; +import java.util.List; + +/** + * Holds information about a parsed SQL statement. + * + * @author Thomas Risberg + * @author Juergen Hoeller + * @since 2.0 + */ +public class ParsedSql { + + private String originalSql; + + private List parameterNames = new ArrayList(); + + private List parameterIndexes = new ArrayList(); + + private int namedParameterCount; + + private int unnamedParameterCount; + + private int totalParameterCount; + + + /** + * Create a new instance of the {@link ParsedSql} class. + * @param originalSql the SQL statement that is being (or is to be) parsed + */ + ParsedSql(String originalSql) { + this.originalSql = originalSql; + } + + /** + * Return the SQL statement that is being parsed. + */ + String getOriginalSql() { + return this.originalSql; + } + + + /** + * Add a named parameter parsed from this SQL statement. + * @param parameterName the name of the parameter + * @param startIndex the start index in the original SQL String + * @param endIndex the end index in the original SQL String + */ + void addNamedParameter(String parameterName, int startIndex, int endIndex) { + this.parameterNames.add(parameterName); + this.parameterIndexes.add(new int[] {startIndex, endIndex}); + } + + /** + * Return all of the parameters (bind variables) in the parsed SQL statement. + * Repeated occurences of the same parameter name are included here. + */ + List getParameterNames() { + return this.parameterNames; + } + + /** + * Return the parameter indexes for the specified parameter. + * @param parameterPosition the position of the parameter + * (as index in the parameter names List) + * @return the start index and end index, combined into + * a int array of length 2 + */ + int[] getParameterIndexes(int parameterPosition) { + return this.parameterIndexes.get(parameterPosition); + } + + /** + * Set the count of named parameters in the SQL statement. + * Each parameter name counts once; repeated occurences do not count here. + */ + void setNamedParameterCount(int namedParameterCount) { + this.namedParameterCount = namedParameterCount; + } + + /** + * Return the count of named parameters in the SQL statement. + * Each parameter name counts once; repeated occurences do not count here. + */ + int getNamedParameterCount() { + return this.namedParameterCount; + } + + /** + * Set the count of all of the unnamed parameters in the SQL statement. + */ + void setUnnamedParameterCount(int unnamedParameterCount) { + this.unnamedParameterCount = unnamedParameterCount; + } + + /** + * Return the count of all of the unnamed parameters in the SQL statement. + */ + int getUnnamedParameterCount() { + return this.unnamedParameterCount; + } + + /** + * Set the total count of all of the parameters in the SQL statement. + * Repeated occurences of the same parameter name do count here. + */ + void setTotalParameterCount(int totalParameterCount) { + this.totalParameterCount = totalParameterCount; + } + + /** + * Return the total count of all of the parameters in the SQL statement. + * Repeated occurences of the same parameter name do count here. + */ + int getTotalParameterCount() { + return this.totalParameterCount; + } + + + /** + * Exposes the original SQL String. + */ + @Override + public String toString() { + return this.originalSql; + } + +} diff --git a/symmetric/symmetric-db/src/main/java/org/jumpmind/db/sql/Row.java b/symmetric/symmetric-db/src/main/java/org/jumpmind/db/sql/Row.java index 678d24c968..094f594d62 100644 --- a/symmetric/symmetric-db/src/main/java/org/jumpmind/db/sql/Row.java +++ b/symmetric/symmetric-db/src/main/java/org/jumpmind/db/sql/Row.java @@ -1,5 +1,8 @@ package org.jumpmind.db.sql; +import java.math.BigDecimal; +import java.sql.Time; +import java.sql.Timestamp; import java.text.ParseException; import java.util.Date; @@ -19,6 +22,32 @@ public Row(String columnName, Object value) { put(columnName, value); } + public Number numberValue() { + Object obj = this.values().iterator().next(); + if (obj != null) { + if (obj instanceof Number) { + return (Number) obj; + } else { + return new BigDecimal(obj.toString()); + } + } else { + return null; + } + } + + public Date dateValue() { + Object obj = this.values().iterator().next(); + if (obj != null) { + if (obj instanceof Date) { + return (Date) obj; + } else { + return Timestamp.valueOf(obj.toString()); + } + } else { + return null; + } + } + public String stringValue() { Object obj = this.values().iterator().next(); if (obj != null) { @@ -77,6 +106,16 @@ public boolean getBoolean(String columnName) { } } + public Time getTime(String columnName) { + Object obj = this.get(columnName); + if (obj instanceof Time) { + return (Time) obj; + } else { + Date date = getDateTime(columnName); + return new Time(date.getTime()); + } + } + public Date getDateTime(String columnName) { Object obj = this.get(columnName); if (obj instanceof Number) { diff --git a/symmetric/symmetric-db/src/main/java/org/jumpmind/db/sql/SqlList.java b/symmetric/symmetric-db/src/main/java/org/jumpmind/db/sql/SqlList.java new file mode 100644 index 0000000000..097cb3d00c --- /dev/null +++ b/symmetric/symmetric-db/src/main/java/org/jumpmind/db/sql/SqlList.java @@ -0,0 +1,26 @@ +package org.jumpmind.db.sql; + +import java.util.ArrayList; +import java.util.Collection; + +public class SqlList extends ArrayList { + + private static final long serialVersionUID = 1L; + + protected String replacementToken; + + public SqlList(String replacementToken, Collection originalList) { + super(originalList); + this.replacementToken = replacementToken; + } + + public SqlList(String replacementToken, int size) { + super(size); + this.replacementToken = replacementToken; + } + + public String getReplacementToken() { + return replacementToken; + } + +} diff --git a/symmetric/symmetric-db/src/main/java/org/jumpmind/db/sql/SqlToken.java b/symmetric/symmetric-db/src/main/java/org/jumpmind/db/sql/SqlToken.java new file mode 100644 index 0000000000..a06ce5f667 --- /dev/null +++ b/symmetric/symmetric-db/src/main/java/org/jumpmind/db/sql/SqlToken.java @@ -0,0 +1,21 @@ +package org.jumpmind.db.sql; + +public class SqlToken { + + String replacementToken; + Object value; + + public SqlToken(String replacementToken, Object value) { + this.replacementToken = replacementToken; + this.value = value; + } + + public String getReplacementToken() { + return replacementToken; + } + + public Object getValue() { + return value; + } + +} diff --git a/symmetric/symmetric-db/src/main/java/org/jumpmind/db/sql/mapper/DateMapper.java b/symmetric/symmetric-db/src/main/java/org/jumpmind/db/sql/mapper/DateMapper.java new file mode 100644 index 0000000000..d0e7a2952b --- /dev/null +++ b/symmetric/symmetric-db/src/main/java/org/jumpmind/db/sql/mapper/DateMapper.java @@ -0,0 +1,14 @@ +package org.jumpmind.db.sql.mapper; + +import java.util.Date; + +import org.jumpmind.db.sql.ISqlRowMapper; +import org.jumpmind.db.sql.Row; + +public class DateMapper implements ISqlRowMapper { + + public Date mapRow(Row rs) { + return rs.dateValue(); + } + +} diff --git a/symmetric/symmetric-db/src/main/java/org/jumpmind/db/sql/mapper/NumberMapper.java b/symmetric/symmetric-db/src/main/java/org/jumpmind/db/sql/mapper/NumberMapper.java new file mode 100644 index 0000000000..ee5d7fea85 --- /dev/null +++ b/symmetric/symmetric-db/src/main/java/org/jumpmind/db/sql/mapper/NumberMapper.java @@ -0,0 +1,10 @@ +package org.jumpmind.db.sql.mapper; + +import org.jumpmind.db.sql.ISqlRowMapper; +import org.jumpmind.db.sql.Row; + +public class NumberMapper implements ISqlRowMapper { + public Number mapRow(Row rs) { + return rs.numberValue(); + } +} diff --git a/symmetric/symmetric-io/src/main/java/org/jumpmind/symmetric/io/FileIoResource.java b/symmetric/symmetric-io/src/main/java/org/jumpmind/symmetric/io/FileIoResource.java index c2bb1a672f..995e50482d 100644 --- a/symmetric/symmetric-io/src/main/java/org/jumpmind/symmetric/io/FileIoResource.java +++ b/symmetric/symmetric-io/src/main/java/org/jumpmind/symmetric/io/FileIoResource.java @@ -22,5 +22,10 @@ public InputStream open() { throw new IoException(e); } } + + public boolean exists() { + return file.exists(); + } + } diff --git a/symmetric/symmetric-io/src/main/java/org/jumpmind/symmetric/io/IoResource.java b/symmetric/symmetric-io/src/main/java/org/jumpmind/symmetric/io/IoResource.java index 1e105a26cd..047f9cfe0f 100644 --- a/symmetric/symmetric-io/src/main/java/org/jumpmind/symmetric/io/IoResource.java +++ b/symmetric/symmetric-io/src/main/java/org/jumpmind/symmetric/io/IoResource.java @@ -5,5 +5,7 @@ public interface IoResource { public InputStream open(); + + public boolean exists(); } diff --git a/symmetric/symmetric-io/src/main/java/org/jumpmind/symmetric/io/MemoryIoResource.java b/symmetric/symmetric-io/src/main/java/org/jumpmind/symmetric/io/MemoryIoResource.java index 1d0ad40229..2841bbf9f7 100644 --- a/symmetric/symmetric-io/src/main/java/org/jumpmind/symmetric/io/MemoryIoResource.java +++ b/symmetric/symmetric-io/src/main/java/org/jumpmind/symmetric/io/MemoryIoResource.java @@ -14,5 +14,9 @@ public MemoryIoResource(byte[] buffer) { public InputStream open() { return new ByteArrayInputStream(buffer); } + + public boolean exists() { + return buffer != null && buffer.length > 0; + } } diff --git a/symmetric/symmetric-io/src/main/java/org/jumpmind/symmetric/io/data/CsvData.java b/symmetric/symmetric-io/src/main/java/org/jumpmind/symmetric/io/data/CsvData.java index 7a7fadaac6..b116ed3ac2 100644 --- a/symmetric/symmetric-io/src/main/java/org/jumpmind/symmetric/io/data/CsvData.java +++ b/symmetric/symmetric-io/src/main/java/org/jumpmind/symmetric/io/data/CsvData.java @@ -38,6 +38,7 @@ public class CsvData { public static final String ROW_DATA = "rowData"; public static final String PK_DATA = "pkData"; + public static final String ATTRIBUTE_TABLE_NAME = "tableName"; public static final String ATTRIBUTE_CHANNEL_ID = "channelId"; public static final String ATTRIBUTE_TABLE_ID = "tableId"; public static final String ATTRIBUTE_TX_ID = "transactionId"; @@ -45,6 +46,7 @@ public class CsvData { public static final String ATTRIBUTE_EXTERNAL_DATA = "externalData"; public static final String ATTRIBUTE_ROUTER_ID = "routerId"; public static final String ATTRIBUTE_DATA_ID = "dataId"; + public static final String ATTRIBUTE_CREATE_TIME = "createTime"; private Map parsedCsvData = null; diff --git a/symmetric/symmetric-io/src/main/java/org/jumpmind/symmetric/io/data/reader/DatabaseCapturedCsvDataReader.java b/symmetric/symmetric-io/src/main/java/org/jumpmind/symmetric/io/data/reader/DatabaseCapturedCsvDataReader.java deleted file mode 100644 index 94493ad22e..0000000000 --- a/symmetric/symmetric-io/src/main/java/org/jumpmind/symmetric/io/data/reader/DatabaseCapturedCsvDataReader.java +++ /dev/null @@ -1,252 +0,0 @@ -package org.jumpmind.symmetric.io.data.reader; - -import java.sql.Types; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import org.apache.commons.codec.binary.Base64; -import org.apache.commons.codec.binary.Hex; -import org.apache.commons.lang.ArrayUtils; -import org.jumpmind.db.model.Column; -import org.jumpmind.db.model.Table; -import org.jumpmind.db.platform.IDatabasePlatform; -import org.jumpmind.db.sql.ISqlReadCursor; -import org.jumpmind.db.sql.ISqlRowMapper; -import org.jumpmind.db.sql.ISqlTemplate; -import org.jumpmind.db.sql.Row; -import org.jumpmind.db.util.BinaryEncoding; -import org.jumpmind.symmetric.io.data.Batch; -import org.jumpmind.symmetric.io.data.CsvData; -import org.jumpmind.symmetric.io.data.DataContext; -import org.jumpmind.symmetric.io.data.DataEventType; -import org.jumpmind.symmetric.io.data.IDataReader; -import org.jumpmind.symmetric.io.data.IDataWriter; -import org.jumpmind.util.CollectionUtils; -import org.jumpmind.util.Statistics; - -public class DatabaseCapturedCsvDataReader implements IDataReader { - - protected String selectSql; - - protected IDatabasePlatform platform; - - protected ISqlReadCursor dataCursor; - - protected Map statistics = new HashMap(); - - protected List batchesToSend; - - protected Map settings; - - protected Batch batch; - - protected DatabaseCaptureSettings setting; - - protected CsvData data; - - protected boolean extractOldData = true; - - public DatabaseCapturedCsvDataReader(IDatabasePlatform platform, String sql, - Map csvDataSettings, boolean extractOldData, - Batch... batches) { - this.selectSql = sql; - this.extractOldData = extractOldData; - this.platform = platform; - this.settings = csvDataSettings; - this.batchesToSend = new ArrayList(batches.length); - for (Batch batch : batches) { - this.batchesToSend.add(batch); - } - } - - public void open(DataContext context) { - } - - public Batch nextBatch() { - closeDataCursor(); - if (this.batchesToSend.size() > 0) { - this.batch = this.batchesToSend.remove(0); - this.statistics.put(batch, new Statistics()); - dataCursor = platform.getSqlTemplate().queryForCursor(selectSql, - new CsvDataRowMapper(), new Object[] { batch.getBatchId() }, - new int[] { Types.NUMERIC }); - return batch; - } else { - this.batch = null; - return null; - } - - } - - protected void closeDataCursor() { - if (this.dataCursor != null) { - this.dataCursor.close(); - this.dataCursor = null; - } - } - - public Table nextTable() { - setting = null; - data = this.dataCursor.next(); - if (data != null) { - setting = settings.get(data.getAttribute(CsvData.ATTRIBUTE_TABLE_ID)); - if (setting == null) { - throw new RuntimeException(String.format( - "Table mapping for id of %d was not found", - data.getAttribute(CsvData.ATTRIBUTE_TABLE_ID))); - } - } - return setting != null ? setting.getTableMetaData() : null; - } - - public CsvData nextData() { - if (data == null) { - data = this.dataCursor.next(); - } - - CsvData returnData = null; - if (data != null) { - DatabaseCaptureSettings newCsvDataSetting = settings.get(data - .getAttribute(CsvData.ATTRIBUTE_TABLE_ID)); - if (newCsvDataSetting != null && setting != null - && newCsvDataSetting.getTableMetaData().equals(setting.getTableMetaData())) { - returnData = data; - data = null; - } - } - return returnData; - } - - public void close() { - closeDataCursor(); - } - - public Map getStatistics() { - return statistics; - } - - protected void enhanceWithLobsFromTargetIfNeeded(CsvData data) { - Table table = setting.getTableMetaData(); - table = platform.getTableFromCache(table.getCatalog(), table.getSchema(), table.getName(), - false); - if (table != null) { - List lobColumns = platform.getLobColumns(table); - if (lobColumns.size() > 0) { - String[] columnNames = table.getColumnNames(); - String[] rowData = data.getParsedData(CsvData.ROW_DATA); - Column[] orderedColumns = table.getColumns(); - Object[] objectValues = platform.getObjectValues(batch.getBinaryEncoding(), - rowData, orderedColumns); - Map columnDataMap = CollectionUtils - .toMap(columnNames, objectValues); - Column[] pkColumns = table.getPrimaryKeyColumns(); - ISqlTemplate sqlTemplate = platform.getSqlTemplate(); - Object[] args = new Object[pkColumns.length]; - for (int i = 0; i < pkColumns.length; i++) { - args[i] = columnDataMap.get(pkColumns[i].getName()); - } - - for (Column lobColumn : lobColumns) { - String sql = buildSelect(table, lobColumn, pkColumns); - String valueForCsv = null; - if (platform.isBlob(lobColumn.getTypeCode())) { - byte[] binaryData = sqlTemplate.queryForBlob(sql, args); - if (batch.getBinaryEncoding() == BinaryEncoding.BASE64) { - valueForCsv = new String(Base64.encodeBase64(binaryData)); - } else if (batch.getBinaryEncoding() == BinaryEncoding.HEX) { - valueForCsv = new String(Hex.encodeHex(binaryData)); - } else { - valueForCsv = new String(binaryData); - } - } else { - valueForCsv = sqlTemplate.queryForClob(sql, args); - } - - int index = ArrayUtils.indexOf(columnNames, lobColumn.getName()); - rowData[index] = valueForCsv; - - } - - data.putParsedData(CsvData.ROW_DATA, rowData); - } - } - } - - protected String buildSelect(Table table, Column lobColumn, Column[] pkColumns) { - StringBuilder sql = new StringBuilder("select "); - String quote = platform.getPlatformInfo().getIdentifierQuoteString(); - sql.append(quote); - sql.append(lobColumn.getName()); - sql.append(quote); - sql.append(","); - sql.delete(sql.length() - 1, sql.length()); - sql.append(" from "); - sql.append(table.getFullyQualifiedTableName()); - sql.append(" where "); - for (Column col : pkColumns) { - sql.append(quote); - sql.append(col.getName()); - sql.append(quote); - sql.append("=? and "); - } - sql.delete(sql.length() - 5, sql.length()); - return sql.toString(); - } - - class CsvDataRowMapper implements ISqlRowMapper { - public CsvData mapRow(Row row) { - CsvData data = new CsvData(); - data.putCsvData(CsvData.ROW_DATA, row.getString("ROW_DATA")); - data.putCsvData(CsvData.PK_DATA, row.getString("PK_DATA")); - if (extractOldData) { - data.putCsvData(CsvData.OLD_DATA, row.getString("OLD_DATA")); - } - - if (setting.isSelectLobsFromTarget()) { - enhanceWithLobsFromTargetIfNeeded(data); - } - - data.putAttribute(CsvData.ATTRIBUTE_CHANNEL_ID, row.getString("CHANNEL_ID")); - data.putAttribute(CsvData.ATTRIBUTE_TX_ID, row.getString("TRANSACTION_ID")); - data.setDataEventType(DataEventType.getEventType(row.getString("EVENT_TYPE"))); - data.putAttribute(CsvData.ATTRIBUTE_TABLE_ID, row.getInt("TRIGGER_HIST_ID")); - data.putAttribute(CsvData.ATTRIBUTE_SOURCE_NODE_ID, row.getString("SOURCE_NODE_ID")); - data.putAttribute(CsvData.ATTRIBUTE_ROUTER_ID, row.getString("ROUTER_ID")); - data.putAttribute(CsvData.ATTRIBUTE_EXTERNAL_DATA, row.getString("EXTERNAL_DATA")); - data.putAttribute(CsvData.ATTRIBUTE_DATA_ID, row.getLong("DATA_ID")); - return data; - } - } - - public static class DatabaseCaptureSettings { - - protected boolean selectLobsFromTarget = false; - - protected Table tableMetaData; - - public DatabaseCaptureSettings(boolean useStreamLobs, Table tableMetaData) { - this.selectLobsFromTarget = useStreamLobs; - this.tableMetaData = tableMetaData; - } - - public boolean isSelectLobsFromTarget() { - return selectLobsFromTarget; - } - - public void setSelectLobsFromTarget(boolean selectLobsFromTarget) { - this.selectLobsFromTarget = selectLobsFromTarget; - } - - public Table getTableMetaData() { - return tableMetaData; - } - - public void setTableMetaData(Table tableMetaData) { - this.tableMetaData = tableMetaData; - } - - } - -} diff --git a/symmetric/symmetric-io/src/main/java/org/jumpmind/symmetric/io/data/reader/DatabaseReader.java b/symmetric/symmetric-io/src/main/java/org/jumpmind/symmetric/io/data/reader/DatabaseReader.java deleted file mode 100644 index d9f8fc4953..0000000000 --- a/symmetric/symmetric-io/src/main/java/org/jumpmind/symmetric/io/data/reader/DatabaseReader.java +++ /dev/null @@ -1,5 +0,0 @@ -package org.jumpmind.symmetric.io.data.reader; - -public class DatabaseReader { - -} diff --git a/symmetric/symmetric-io/src/main/java/org/jumpmind/symmetric/io/data/reader/IBatchCsvDataSource.java b/symmetric/symmetric-io/src/main/java/org/jumpmind/symmetric/io/data/reader/IBatchCsvDataSource.java new file mode 100644 index 0000000000..152ae8ed82 --- /dev/null +++ b/symmetric/symmetric-io/src/main/java/org/jumpmind/symmetric/io/data/reader/IBatchCsvDataSource.java @@ -0,0 +1,22 @@ +package org.jumpmind.symmetric.io.data.reader; + +import org.jumpmind.db.model.Table; +import org.jumpmind.symmetric.io.data.Batch; +import org.jumpmind.symmetric.io.data.CsvData; + +public interface IBatchCsvDataSource { + + public Batch getBatch(); + + /** + * Return the table for the last {@link CsvData} retrieved by {@link #next()} + */ + public Table getTable(); + + public CsvData next(); + + public boolean requiresLobsSelectedFromSource(); + + public void close(); + +} diff --git a/symmetric/symmetric-io/src/main/java/org/jumpmind/symmetric/io/data/reader/SourcedCsvDataReader.java b/symmetric/symmetric-io/src/main/java/org/jumpmind/symmetric/io/data/reader/SourcedCsvDataReader.java new file mode 100644 index 0000000000..c9ecef1183 --- /dev/null +++ b/symmetric/symmetric-io/src/main/java/org/jumpmind/symmetric/io/data/reader/SourcedCsvDataReader.java @@ -0,0 +1,180 @@ +package org.jumpmind.symmetric.io.data.reader; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.apache.commons.codec.binary.Base64; +import org.apache.commons.codec.binary.Hex; +import org.apache.commons.lang.ArrayUtils; +import org.jumpmind.db.model.Column; +import org.jumpmind.db.model.Table; +import org.jumpmind.db.platform.IDatabasePlatform; +import org.jumpmind.db.sql.ISqlTemplate; +import org.jumpmind.db.util.BinaryEncoding; +import org.jumpmind.symmetric.io.data.Batch; +import org.jumpmind.symmetric.io.data.CsvData; +import org.jumpmind.symmetric.io.data.DataContext; +import org.jumpmind.symmetric.io.data.DataEventType; +import org.jumpmind.symmetric.io.data.IDataReader; +import org.jumpmind.symmetric.io.data.IDataWriter; +import org.jumpmind.util.CollectionUtils; +import org.jumpmind.util.Statistics; + +public class SourcedCsvDataReader implements IDataReader { + + protected Map statistics = new HashMap(); + + protected IDatabasePlatform platform; + + protected List sourcesToUse; + + protected IBatchCsvDataSource currentSource; + + protected Batch batch; + + protected Table table; + + protected CsvData data; + + public SourcedCsvDataReader(IDatabasePlatform platform, IBatchCsvDataSource source) { + this.sourcesToUse = new ArrayList(); + this.sourcesToUse.add(source); + this.platform = platform; + } + + public SourcedCsvDataReader(IDatabasePlatform platform, List sources) { + this.sourcesToUse = new ArrayList(sources); + this.platform = platform; + } + + public void open(DataContext context) { + } + + public Batch nextBatch() { + closeCurrentSource(); + if (this.sourcesToUse.size() > 0) { + this.currentSource = this.sourcesToUse.get(0); + this.batch = this.currentSource.getBatch(); + } + + return this.batch; + + } + + public Table nextTable() { + this.table = null; + if (this.data == null) { + this.data = this.currentSource.next(); + } + if (this.data != null) { + this.table = this.currentSource.getTable(); + } + return this.table; + } + + public CsvData nextData() { + if (this.data == null) { + this.data = this.currentSource.next(); + } + + if (data == null) { + closeCurrentSource(); + } else { + Table sourceTable = this.currentSource.getTable(); + if (sourceTable != null && sourceTable.equals(this.table)) { + return enhanceWithLobsFromSourceIfNeeded(table, data); + } + } + + return null; + } + + public void close() { + closeCurrentSource(); + } + + protected void closeCurrentSource() { + if (this.currentSource != null) { + this.currentSource.close(); + this.currentSource = null; + } + + this.batch = null; + this.table = null; + this.data = null; + } + + public Map getStatistics() { + return statistics; + } + + protected CsvData enhanceWithLobsFromSourceIfNeeded(Table table, CsvData data) { + if (this.currentSource.requiresLobsSelectedFromSource() + && (data.getDataEventType() == DataEventType.UPDATE || data.getDataEventType() == DataEventType.INSERT)) { + List lobColumns = platform.getLobColumns(table); + if (lobColumns.size() > 0) { + String[] columnNames = table.getColumnNames(); + String[] rowData = data.getParsedData(CsvData.ROW_DATA); + Column[] orderedColumns = table.getColumns(); + Object[] objectValues = platform.getObjectValues(batch.getBinaryEncoding(), + rowData, orderedColumns); + Map columnDataMap = CollectionUtils + .toMap(columnNames, objectValues); + Column[] pkColumns = table.getPrimaryKeyColumns(); + ISqlTemplate sqlTemplate = platform.getSqlTemplate(); + Object[] args = new Object[pkColumns.length]; + for (int i = 0; i < pkColumns.length; i++) { + args[i] = columnDataMap.get(pkColumns[i].getName()); + } + + for (Column lobColumn : lobColumns) { + String sql = buildSelect(table, lobColumn, pkColumns); + String valueForCsv = null; + if (platform.isBlob(lobColumn.getTypeCode())) { + byte[] binaryData = sqlTemplate.queryForBlob(sql, args); + if (batch.getBinaryEncoding() == BinaryEncoding.BASE64) { + valueForCsv = new String(Base64.encodeBase64(binaryData)); + } else if (batch.getBinaryEncoding() == BinaryEncoding.HEX) { + valueForCsv = new String(Hex.encodeHex(binaryData)); + } else { + valueForCsv = new String(binaryData); + } + } else { + valueForCsv = sqlTemplate.queryForClob(sql, args); + } + + int index = ArrayUtils.indexOf(columnNames, lobColumn.getName()); + rowData[index] = valueForCsv; + + } + + data.putParsedData(CsvData.ROW_DATA, rowData); + } + } + return data; + } + + protected String buildSelect(Table table, Column lobColumn, Column[] pkColumns) { + StringBuilder sql = new StringBuilder("select "); + String quote = platform.getPlatformInfo().getIdentifierQuoteString(); + sql.append(quote); + sql.append(lobColumn.getName()); + sql.append(quote); + sql.append(","); + sql.delete(sql.length() - 1, sql.length()); + sql.append(" from "); + sql.append(table.getFullyQualifiedTableName()); + sql.append(" where "); + for (Column col : pkColumns) { + sql.append(quote); + sql.append(col.getName()); + sql.append(quote); + sql.append("=? and "); + } + sql.delete(sql.length() - 5, sql.length()); + return sql.toString(); + } + +} diff --git a/symmetric/symmetric-io/src/main/java/org/jumpmind/symmetric/io/data/reader/TextualCsvDataReader.java b/symmetric/symmetric-io/src/main/java/org/jumpmind/symmetric/io/data/reader/TextualCsvDataReader.java index 3b35b3b4f4..16a980ec19 100644 --- a/symmetric/symmetric-io/src/main/java/org/jumpmind/symmetric/io/data/reader/TextualCsvDataReader.java +++ b/symmetric/symmetric-io/src/main/java/org/jumpmind/symmetric/io/data/reader/TextualCsvDataReader.java @@ -22,6 +22,7 @@ import org.jumpmind.log.Log; import org.jumpmind.log.LogFactory; import org.jumpmind.symmetric.csv.CsvReader; +import org.jumpmind.symmetric.io.IoResource; import org.jumpmind.symmetric.io.data.Batch; import org.jumpmind.symmetric.io.data.CsvConstants; import org.jumpmind.symmetric.io.data.CsvData; @@ -36,6 +37,7 @@ public class TextualCsvDataReader implements IDataReader { protected Log log = LogFactory.getLog(getClass()); + protected IoResource ioResource; protected Reader reader; protected Map statistics = new HashMap(); protected CsvReader csvReader; @@ -56,6 +58,10 @@ public TextualCsvDataReader(InputStream is) { this(toReader(is)); } + public TextualCsvDataReader(IoResource ioResource) { + this.ioResource = ioResource; + } + protected static Reader toReader(InputStream is) { try { return new BufferedReader(new InputStreamReader(is, "UTF-8")); @@ -83,6 +89,9 @@ public TextualCsvDataReader(File file) { } public void open(DataContext context) { + if (this.ioResource != null && this.reader == null) { + this.reader = toReader(this.ioResource.open()); + } this.context = context; this.csvReader = CsvUtils.getCsvReader(reader); this.next = readNext(); @@ -257,6 +266,7 @@ public void close() { if (csvReader != null) { csvReader.close(); } + } public Map getStatistics() { diff --git a/symmetric/symmetric-io/src/main/java/org/jumpmind/symmetric/io/data/writer/CsvDataWriter.java b/symmetric/symmetric-io/src/main/java/org/jumpmind/symmetric/io/data/writer/CsvDataWriter.java new file mode 100644 index 0000000000..8f9b303b84 --- /dev/null +++ b/symmetric/symmetric-io/src/main/java/org/jumpmind/symmetric/io/data/writer/CsvDataWriter.java @@ -0,0 +1,50 @@ +package org.jumpmind.symmetric.io.data.writer; + +import java.io.BufferedWriter; +import java.io.IOException; +import java.io.Writer; +import java.util.List; + +import org.jumpmind.exception.IoException; +import org.jumpmind.symmetric.io.data.Batch; + +public class CsvDataWriter extends AbstractCsvDataWriter { + + private BufferedWriter writer; + + public CsvDataWriter(Writer writer) { + this(null, writer); + } + + public CsvDataWriter(List listeners, Writer writer) { + super(listeners); + if (writer instanceof BufferedWriter) { + this.writer = (BufferedWriter) writer; + } else { + this.writer = new BufferedWriter(writer); + } + } + + @Override + protected void endBatch(Batch batch) { + try { + writer.flush(); + } catch (IOException e) { + throw new IoException(e); + } + } + + @Override + protected void notifyEndBatch(Batch batch, ICsvDataWriterListener listener) { + } + + @Override + protected void print(Batch batch, String data) { + try { + writer.write(data); + } catch (IOException e) { + throw new IoException(e); + } + } + +} diff --git a/symmetric/symmetric-jdbc/src/main/java/org/jumpmind/db/platform/JdbcDatabasePlatformFactory.java b/symmetric/symmetric-jdbc/src/main/java/org/jumpmind/db/platform/JdbcDatabasePlatformFactory.java index ac23dfe922..560a1b6df6 100644 --- a/symmetric/symmetric-jdbc/src/main/java/org/jumpmind/db/platform/JdbcDatabasePlatformFactory.java +++ b/symmetric/symmetric-jdbc/src/main/java/org/jumpmind/db/platform/JdbcDatabasePlatformFactory.java @@ -31,7 +31,6 @@ import javax.sql.DataSource; import org.apache.commons.lang.StringUtils; -import org.jumpmind.db.platform.DatabasePlatformSettings; import org.jumpmind.db.platform.db2.Db2Platform; import org.jumpmind.db.platform.derby.DerbyPlatform; import org.jumpmind.db.platform.firebird.FirebirdPlatform; @@ -45,7 +44,6 @@ import org.jumpmind.db.platform.mysql.MySqlPlatform; import org.jumpmind.db.platform.oracle.OraclePlatform; import org.jumpmind.db.platform.postgresql.PostgreSqlPlatform; -import org.jumpmind.db.platform.sqlite.SqLitePlatform; import org.jumpmind.db.platform.sybase.SybasePlatform; import org.jumpmind.db.sql.SqlException; import org.jumpmind.log.Log; @@ -72,7 +70,6 @@ public class JdbcDatabasePlatformFactory { for (String name : H2Platform.DATABASENAMES) { addPlatform(platforms, name, H2Platform.class); } - addPlatform(platforms, SqLitePlatform.DATABASENAME, SqLitePlatform.class); addPlatform(platforms, InformixPlatform.DATABASENAME, InformixPlatform.class); addPlatform(platforms, DerbyPlatform.DATABASENAME, DerbyPlatform.class); addPlatform(platforms, FirebirdPlatform.DATABASENAME, FirebirdPlatform.class); diff --git a/symmetric/symmetric-jdbc/src/main/java/org/jumpmind/db/platform/db2/Db2JdbcSqlTemplate.java b/symmetric/symmetric-jdbc/src/main/java/org/jumpmind/db/platform/db2/Db2JdbcSqlTemplate.java new file mode 100644 index 0000000000..c72ea0b09a --- /dev/null +++ b/symmetric/symmetric-jdbc/src/main/java/org/jumpmind/db/platform/db2/Db2JdbcSqlTemplate.java @@ -0,0 +1,32 @@ +package org.jumpmind.db.platform.db2; + +import javax.sql.DataSource; + +import org.jumpmind.db.platform.DatabasePlatformSettings; +import org.jumpmind.db.sql.jdbc.JdbcSqlTemplate; +import org.springframework.jdbc.support.lob.LobHandler; + +public class Db2JdbcSqlTemplate extends JdbcSqlTemplate { + + public Db2JdbcSqlTemplate(DataSource dataSource, DatabasePlatformSettings settings, + LobHandler lobHandler) { + super(dataSource, settings, lobHandler); + } + + + @Override + public String getSelectLastInsertIdSql(String sequenceName) { + return "values IDENTITY_VAL_LOCAL()"; + } + + @Override + public boolean supportsGetGeneratedKeys() { + return false; + } + + @Override + protected boolean allowsNullForIdentityColumn() { + return false; + } + +} diff --git a/symmetric/symmetric-jdbc/src/main/java/org/jumpmind/db/platform/db2/Db2Platform.java b/symmetric/symmetric-jdbc/src/main/java/org/jumpmind/db/platform/db2/Db2Platform.java index d5168c28b2..7b065334a8 100644 --- a/symmetric/symmetric-jdbc/src/main/java/org/jumpmind/db/platform/db2/Db2Platform.java +++ b/symmetric/symmetric-jdbc/src/main/java/org/jumpmind/db/platform/db2/Db2Platform.java @@ -85,6 +85,11 @@ public Db2Platform(DataSource dataSource, DatabasePlatformSettings settings, Log ddlReader = new Db2DdlReader(log, this); ddlBuilder = new Db2Builder(log, this); } + + @Override + protected void createSqlTemplate() { + this.sqlTemplate = new Db2JdbcSqlTemplate(dataSource, settings, null); + } public String getName() { return DATABASENAME; diff --git a/symmetric/symmetric-jdbc/src/main/java/org/jumpmind/db/platform/derby/DerbyJdbcSqlTemplate.java b/symmetric/symmetric-jdbc/src/main/java/org/jumpmind/db/platform/derby/DerbyJdbcSqlTemplate.java new file mode 100644 index 0000000000..88ed6758c3 --- /dev/null +++ b/symmetric/symmetric-jdbc/src/main/java/org/jumpmind/db/platform/derby/DerbyJdbcSqlTemplate.java @@ -0,0 +1,31 @@ +package org.jumpmind.db.platform.derby; + +import javax.sql.DataSource; + +import org.jumpmind.db.platform.DatabasePlatformSettings; +import org.jumpmind.db.sql.jdbc.JdbcSqlTemplate; +import org.springframework.jdbc.support.lob.LobHandler; + +public class DerbyJdbcSqlTemplate extends JdbcSqlTemplate { + + public DerbyJdbcSqlTemplate(DataSource dataSource, DatabasePlatformSettings settings, + LobHandler lobHandler) { + super(dataSource, settings, lobHandler); + } + + @Override + public String getSelectLastInsertIdSql(String sequenceName) { + return "values IDENTITY_VAL_LOCAL()"; + } + + @Override + public boolean supportsGetGeneratedKeys() { + return false; + } + + @Override + protected boolean allowsNullForIdentityColumn() { + return false; + } + +} diff --git a/symmetric/symmetric-jdbc/src/main/java/org/jumpmind/db/platform/derby/DerbyPlatform.java b/symmetric/symmetric-jdbc/src/main/java/org/jumpmind/db/platform/derby/DerbyPlatform.java index bd2cc54eed..f10a4eb601 100644 --- a/symmetric/symmetric-jdbc/src/main/java/org/jumpmind/db/platform/derby/DerbyPlatform.java +++ b/symmetric/symmetric-jdbc/src/main/java/org/jumpmind/db/platform/derby/DerbyPlatform.java @@ -88,6 +88,10 @@ public DerbyPlatform(DataSource dataSource, DatabasePlatformSettings settings, L ddlBuilder = new DerbyBuilder(log, this); } + @Override + protected void createSqlTemplate() { + this.sqlTemplate = new DerbyJdbcSqlTemplate(dataSource, settings, null); + } public String getName() { return DATABASENAME; diff --git a/symmetric/symmetric-jdbc/src/main/java/org/jumpmind/db/platform/firebird/FirebirdJdbcSqlTemplate.java b/symmetric/symmetric-jdbc/src/main/java/org/jumpmind/db/platform/firebird/FirebirdJdbcSqlTemplate.java new file mode 100644 index 0000000000..2e53a40b88 --- /dev/null +++ b/symmetric/symmetric-jdbc/src/main/java/org/jumpmind/db/platform/firebird/FirebirdJdbcSqlTemplate.java @@ -0,0 +1,26 @@ +package org.jumpmind.db.platform.firebird; + +import javax.sql.DataSource; + +import org.jumpmind.db.platform.DatabasePlatformSettings; +import org.jumpmind.db.sql.jdbc.JdbcSqlTemplate; +import org.springframework.jdbc.support.lob.LobHandler; + +public class FirebirdJdbcSqlTemplate extends JdbcSqlTemplate { + + public FirebirdJdbcSqlTemplate(DataSource dataSource, DatabasePlatformSettings settings, + LobHandler lobHandler) { + super(dataSource, settings, lobHandler); + } + + @Override + public boolean supportsReturningKeys() { + return true; + } + + @Override + protected boolean allowsNullForIdentityColumn() { + return true; + } + +} diff --git a/symmetric/symmetric-jdbc/src/main/java/org/jumpmind/db/platform/firebird/FirebirdPlatform.java b/symmetric/symmetric-jdbc/src/main/java/org/jumpmind/db/platform/firebird/FirebirdPlatform.java index b536ec4028..0de748a1fd 100644 --- a/symmetric/symmetric-jdbc/src/main/java/org/jumpmind/db/platform/firebird/FirebirdPlatform.java +++ b/symmetric/symmetric-jdbc/src/main/java/org/jumpmind/db/platform/firebird/FirebirdPlatform.java @@ -92,6 +92,11 @@ public FirebirdPlatform(DataSource dataSource, DatabasePlatformSettings settings ddlReader = new FirebirdDdlReader(log, this); ddlBuilder = new FirebirdBuilder(log, this); } + + @Override + protected void createSqlTemplate() { + this.sqlTemplate = new FirebirdJdbcSqlTemplate(dataSource, settings, null); + } public String getName() { return DATABASENAME; diff --git a/symmetric/symmetric-jdbc/src/main/java/org/jumpmind/db/platform/greenplum/GreenplumJdbcSqlTemplate.java b/symmetric/symmetric-jdbc/src/main/java/org/jumpmind/db/platform/greenplum/GreenplumJdbcSqlTemplate.java new file mode 100644 index 0000000000..2b530d206f --- /dev/null +++ b/symmetric/symmetric-jdbc/src/main/java/org/jumpmind/db/platform/greenplum/GreenplumJdbcSqlTemplate.java @@ -0,0 +1,58 @@ +package org.jumpmind.db.platform.greenplum; + +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; + +import javax.sql.DataSource; + +import org.jumpmind.db.platform.DatabasePlatformSettings; +import org.jumpmind.db.platform.postgresql.PostgreSqlJdbcSqlTemplate; +import org.jumpmind.db.sql.jdbc.JdbcUtils; +import org.springframework.jdbc.support.lob.LobHandler; + +public class GreenplumJdbcSqlTemplate extends PostgreSqlJdbcSqlTemplate { + + public GreenplumJdbcSqlTemplate(DataSource dataSource, DatabasePlatformSettings settings, + LobHandler lobHandler) { + super(dataSource, settings, lobHandler); + } + + @Override + public boolean supportsGetGeneratedKeys() { + return false; + } + + @Override + protected long insertWithGeneratedKey(Connection conn, String sql, String column, + String sequenceName, Object[] args, int[] types) throws SQLException { + long key = 0; + PreparedStatement ps = null; + try { + Statement st = null; + ResultSet rs = null; + try { + st = conn.createStatement(); + rs = st.executeQuery("select nextval('" + sequenceName + "_seq')"); + if (rs.next()) { + key = rs.getLong(1); + } + } finally { + close(rs); + close(st); + } + + String replaceSql = sql.replaceFirst("\\(null,", "(" + key + ","); + ps = conn.prepareStatement(replaceSql); + ps.setQueryTimeout(settings.getQueryTimeout()); + JdbcUtils.setValues(ps, args, types, lobHandler); + ps.executeUpdate(); + } finally { + close(ps); + } + return key; + } + +} diff --git a/symmetric/symmetric-jdbc/src/main/java/org/jumpmind/db/platform/h2/H2JdbcSqlTemplate.java b/symmetric/symmetric-jdbc/src/main/java/org/jumpmind/db/platform/h2/H2JdbcSqlTemplate.java new file mode 100644 index 0000000000..b0f8321193 --- /dev/null +++ b/symmetric/symmetric-jdbc/src/main/java/org/jumpmind/db/platform/h2/H2JdbcSqlTemplate.java @@ -0,0 +1,31 @@ +package org.jumpmind.db.platform.h2; + +import javax.sql.DataSource; + +import org.jumpmind.db.platform.DatabasePlatformSettings; +import org.jumpmind.db.sql.jdbc.JdbcSqlTemplate; +import org.springframework.jdbc.support.lob.LobHandler; + +public class H2JdbcSqlTemplate extends JdbcSqlTemplate { + + public H2JdbcSqlTemplate(DataSource dataSource, DatabasePlatformSettings settings, + LobHandler lobHandler) { + super(dataSource, settings, lobHandler); + } + + @Override + public boolean supportsGetGeneratedKeys() { + return false; + } + + @Override + protected boolean allowsNullForIdentityColumn() { + return false; + } + + @Override + public String getSelectLastInsertIdSql(String sequenceName) { + return "call IDENTITY()"; + } + +} diff --git a/symmetric/symmetric-jdbc/src/main/java/org/jumpmind/db/platform/h2/H2Platform.java b/symmetric/symmetric-jdbc/src/main/java/org/jumpmind/db/platform/h2/H2Platform.java index da81e1f317..f56f15d2d6 100644 --- a/symmetric/symmetric-jdbc/src/main/java/org/jumpmind/db/platform/h2/H2Platform.java +++ b/symmetric/symmetric-jdbc/src/main/java/org/jumpmind/db/platform/h2/H2Platform.java @@ -84,6 +84,11 @@ public H2Platform(DataSource dataSource, DatabasePlatformSettings settings, Log ddlReader = new H2DdlReader(log, this); ddlBuilder = new H2Builder(log, this); } + + @Override + protected void createSqlTemplate() { + this.sqlTemplate = new H2JdbcSqlTemplate(dataSource, settings, null); + } public String getName() { return DATABASENAMES[0]; diff --git a/symmetric/symmetric-jdbc/src/main/java/org/jumpmind/db/platform/hsqldb/HsqlDbJdbcSqlTemplate.java b/symmetric/symmetric-jdbc/src/main/java/org/jumpmind/db/platform/hsqldb/HsqlDbJdbcSqlTemplate.java new file mode 100644 index 0000000000..6d4cf04232 --- /dev/null +++ b/symmetric/symmetric-jdbc/src/main/java/org/jumpmind/db/platform/hsqldb/HsqlDbJdbcSqlTemplate.java @@ -0,0 +1,27 @@ +package org.jumpmind.db.platform.hsqldb; + +import javax.sql.DataSource; + +import org.jumpmind.db.platform.DatabasePlatformSettings; +import org.jumpmind.db.sql.jdbc.JdbcSqlTemplate; +import org.springframework.jdbc.support.lob.LobHandler; + +public class HsqlDbJdbcSqlTemplate extends JdbcSqlTemplate { + + public HsqlDbJdbcSqlTemplate(DataSource dataSource, DatabasePlatformSettings settings, + LobHandler lobHandler) { + super(dataSource, settings, lobHandler); + } + + @Override + public String getSelectLastInsertIdSql(String sequenceName) { + return "call IDENTITY()"; + } + + + @Override + protected boolean allowsNullForIdentityColumn() { + return false; + } + +} diff --git a/symmetric/symmetric-jdbc/src/main/java/org/jumpmind/db/platform/hsqldb/HsqlDbPlatform.java b/symmetric/symmetric-jdbc/src/main/java/org/jumpmind/db/platform/hsqldb/HsqlDbPlatform.java index 581e8dff8f..d567f1d187 100644 --- a/symmetric/symmetric-jdbc/src/main/java/org/jumpmind/db/platform/hsqldb/HsqlDbPlatform.java +++ b/symmetric/symmetric-jdbc/src/main/java/org/jumpmind/db/platform/hsqldb/HsqlDbPlatform.java @@ -83,6 +83,11 @@ public HsqlDbPlatform(DataSource dataSource, DatabasePlatformSettings settings, ddlBuilder = new HsqlDbBuilder(log, this); } + + @Override + protected void createSqlTemplate() { + this.sqlTemplate = new HsqlDbJdbcSqlTemplate(dataSource, settings, null); + } public String getName() { return DATABASENAME; diff --git a/symmetric/symmetric-jdbc/src/main/java/org/jumpmind/db/platform/hsqldb2/HsqlDb2JdbcSqlTemplate.java b/symmetric/symmetric-jdbc/src/main/java/org/jumpmind/db/platform/hsqldb2/HsqlDb2JdbcSqlTemplate.java new file mode 100644 index 0000000000..0bd9bee23d --- /dev/null +++ b/symmetric/symmetric-jdbc/src/main/java/org/jumpmind/db/platform/hsqldb2/HsqlDb2JdbcSqlTemplate.java @@ -0,0 +1,26 @@ +package org.jumpmind.db.platform.hsqldb2; + +import javax.sql.DataSource; + +import org.jumpmind.db.platform.DatabasePlatformSettings; +import org.jumpmind.db.sql.jdbc.JdbcSqlTemplate; +import org.springframework.jdbc.support.lob.LobHandler; + +public class HsqlDb2JdbcSqlTemplate extends JdbcSqlTemplate { + + public HsqlDb2JdbcSqlTemplate(DataSource dataSource, DatabasePlatformSettings settings, + LobHandler lobHandler) { + super(dataSource, settings, lobHandler); + } + + @Override + protected boolean allowsNullForIdentityColumn() { + return false; + } + + @Override + public String getSelectLastInsertIdSql(String sequenceName) { + return "call IDENTITY()"; + } + +} diff --git a/symmetric/symmetric-jdbc/src/main/java/org/jumpmind/db/platform/hsqldb2/HsqlDb2Platform.java b/symmetric/symmetric-jdbc/src/main/java/org/jumpmind/db/platform/hsqldb2/HsqlDb2Platform.java index 09abf9abd7..202aee8857 100644 --- a/symmetric/symmetric-jdbc/src/main/java/org/jumpmind/db/platform/hsqldb2/HsqlDb2Platform.java +++ b/symmetric/symmetric-jdbc/src/main/java/org/jumpmind/db/platform/hsqldb2/HsqlDb2Platform.java @@ -83,6 +83,11 @@ public HsqlDb2Platform(DataSource dataSource, DatabasePlatformSettings settings, ddlReader = new HsqlDb2DdlReader(log, this); ddlBuilder = new HsqlDb2Builder(log, this); } + + @Override + protected void createSqlTemplate() { + this.sqlTemplate = new HsqlDb2JdbcSqlTemplate(dataSource, settings, null); + } public String getName() { return DATABASENAME; diff --git a/symmetric/symmetric-jdbc/src/main/java/org/jumpmind/db/platform/informix/InformixJdbcSqlTemplate.java b/symmetric/symmetric-jdbc/src/main/java/org/jumpmind/db/platform/informix/InformixJdbcSqlTemplate.java new file mode 100644 index 0000000000..e0f13a93ad --- /dev/null +++ b/symmetric/symmetric-jdbc/src/main/java/org/jumpmind/db/platform/informix/InformixJdbcSqlTemplate.java @@ -0,0 +1,21 @@ +package org.jumpmind.db.platform.informix; + +import javax.sql.DataSource; + +import org.jumpmind.db.platform.DatabasePlatformSettings; +import org.jumpmind.db.sql.jdbc.JdbcSqlTemplate; +import org.springframework.jdbc.support.lob.LobHandler; + +public class InformixJdbcSqlTemplate extends JdbcSqlTemplate { + + public InformixJdbcSqlTemplate(DataSource dataSource, DatabasePlatformSettings settings, + LobHandler lobHandler) { + super(dataSource, settings, lobHandler); + } + + @Override + public boolean allowsNullForIdentityColumn() { + return false; + } + +} diff --git a/symmetric/symmetric-jdbc/src/main/java/org/jumpmind/db/platform/informix/InformixPlatform.java b/symmetric/symmetric-jdbc/src/main/java/org/jumpmind/db/platform/informix/InformixPlatform.java index cac55edd4e..cc65cf7fcb 100644 --- a/symmetric/symmetric-jdbc/src/main/java/org/jumpmind/db/platform/informix/InformixPlatform.java +++ b/symmetric/symmetric-jdbc/src/main/java/org/jumpmind/db/platform/informix/InformixPlatform.java @@ -63,6 +63,11 @@ public InformixPlatform(DataSource dataSource, DatabasePlatformSettings settings sqlScriptReplacementTokens = new HashMap(); sqlScriptReplacementTokens.put("current_timestamp", "current"); } + + @Override + protected void createSqlTemplate() { + this.sqlTemplate = new InformixJdbcSqlTemplate(dataSource, settings, null); + } public String getName() { return DATABASENAME; diff --git a/symmetric/symmetric-jdbc/src/main/java/org/jumpmind/db/platform/interbase/InterbaseJdbcSqlTemplate.java b/symmetric/symmetric-jdbc/src/main/java/org/jumpmind/db/platform/interbase/InterbaseJdbcSqlTemplate.java new file mode 100644 index 0000000000..208f77e9a5 --- /dev/null +++ b/symmetric/symmetric-jdbc/src/main/java/org/jumpmind/db/platform/interbase/InterbaseJdbcSqlTemplate.java @@ -0,0 +1,27 @@ +package org.jumpmind.db.platform.interbase; + +import javax.sql.DataSource; + +import org.jumpmind.db.platform.DatabasePlatformSettings; +import org.jumpmind.db.sql.jdbc.JdbcSqlTemplate; +import org.springframework.jdbc.support.lob.LobHandler; + +public class InterbaseJdbcSqlTemplate extends JdbcSqlTemplate { + + public InterbaseJdbcSqlTemplate(DataSource dataSource, DatabasePlatformSettings settings, + LobHandler lobHandler) { + super(dataSource, settings, lobHandler); + } + + @Override + public String getSelectLastInsertIdSql(String sequenceName) { + return "select gen_id(gen_" + sequenceName + ", 0) from rdb$database"; + } + + @Override + protected boolean allowsNullForIdentityColumn() { + return true; + } + + +} diff --git a/symmetric/symmetric-jdbc/src/main/java/org/jumpmind/db/platform/interbase/InterbasePlatform.java b/symmetric/symmetric-jdbc/src/main/java/org/jumpmind/db/platform/interbase/InterbasePlatform.java index b459c30e77..c13f3ae58c 100644 --- a/symmetric/symmetric-jdbc/src/main/java/org/jumpmind/db/platform/interbase/InterbasePlatform.java +++ b/symmetric/symmetric-jdbc/src/main/java/org/jumpmind/db/platform/interbase/InterbasePlatform.java @@ -99,6 +99,11 @@ public InterbasePlatform(DataSource dataSource, DatabasePlatformSettings setting ddlReader = new InterbaseDdlReader(log, this); ddlBuilder = new InterbaseBuilder(log, this); } + + @Override + protected void createSqlTemplate() { + this.sqlTemplate = new InterbaseJdbcSqlTemplate(dataSource, settings, null); + } public String getName() { return DATABASENAME; diff --git a/symmetric/symmetric-jdbc/src/main/java/org/jumpmind/db/platform/mssql/MsSqlJdbcSqlTemplate.java b/symmetric/symmetric-jdbc/src/main/java/org/jumpmind/db/platform/mssql/MsSqlJdbcSqlTemplate.java index a740fe1270..2d81b5398b 100644 --- a/symmetric/symmetric-jdbc/src/main/java/org/jumpmind/db/platform/mssql/MsSqlJdbcSqlTemplate.java +++ b/symmetric/symmetric-jdbc/src/main/java/org/jumpmind/db/platform/mssql/MsSqlJdbcSqlTemplate.java @@ -16,5 +16,10 @@ public MsSqlJdbcSqlTemplate(DataSource dataSource, DatabasePlatformSettings sett public ISqlTransaction startSqlTransaction() { return new MsSqlJdbcSqlTransaction(this); } - + + @Override + protected boolean allowsNullForIdentityColumn() { + return false; + } + } diff --git a/symmetric/symmetric-jdbc/src/main/java/org/jumpmind/db/platform/mysql/MySqlJdbcSqlTemplate.java b/symmetric/symmetric-jdbc/src/main/java/org/jumpmind/db/platform/mysql/MySqlJdbcSqlTemplate.java new file mode 100644 index 0000000000..f43b830164 --- /dev/null +++ b/symmetric/symmetric-jdbc/src/main/java/org/jumpmind/db/platform/mysql/MySqlJdbcSqlTemplate.java @@ -0,0 +1,21 @@ +package org.jumpmind.db.platform.mysql; + +import javax.sql.DataSource; + +import org.jumpmind.db.platform.DatabasePlatformSettings; +import org.jumpmind.db.sql.jdbc.JdbcSqlTemplate; +import org.springframework.jdbc.support.lob.LobHandler; + +public class MySqlJdbcSqlTemplate extends JdbcSqlTemplate { + + public MySqlJdbcSqlTemplate(DataSource dataSource, DatabasePlatformSettings settings, + LobHandler lobHandler) { + super(dataSource, settings, lobHandler); + } + + @Override + public String getSelectLastInsertIdSql(String sequenceName) { + return "select last_insert_id()"; + } + +} diff --git a/symmetric/symmetric-jdbc/src/main/java/org/jumpmind/db/platform/mysql/MySqlPlatform.java b/symmetric/symmetric-jdbc/src/main/java/org/jumpmind/db/platform/mysql/MySqlPlatform.java index 63c85eaa78..d476b4038f 100644 --- a/symmetric/symmetric-jdbc/src/main/java/org/jumpmind/db/platform/mysql/MySqlPlatform.java +++ b/symmetric/symmetric-jdbc/src/main/java/org/jumpmind/db/platform/mysql/MySqlPlatform.java @@ -49,7 +49,7 @@ public class MySqlPlatform extends AbstractJdbcDatabasePlatform { * Creates a new platform instance. */ public MySqlPlatform(DataSource dataSource, DatabasePlatformSettings settings, Log log) { - super(dataSource, settings, log); + super(dataSource, overrideSettings(settings), log); info.setMaxIdentifierLength(64); info.setNullAsDefaultValueRequired(true); @@ -112,6 +112,20 @@ public MySqlPlatform(DataSource dataSource, DatabasePlatformSettings settings, L ddlReader = new MySqlDdlReader(log, this); ddlBuilder = new MySqlBuilder(log, this); } + + @Override + protected void createSqlTemplate() { + this.sqlTemplate = new MySqlJdbcSqlTemplate(dataSource, settings, null); + } + + /* + * According to the documentation (and experience) the jdbc driver for mysql + * requires the fetch size to be as follows. + */ + protected static DatabasePlatformSettings overrideSettings(DatabasePlatformSettings settings) { + settings.setFetchSize(Integer.MIN_VALUE); + return settings; + } public String getName() { return DATABASENAME; diff --git a/symmetric/symmetric-jdbc/src/main/java/org/jumpmind/db/platform/oracle/OracleJdbcSqlTemplate.java b/symmetric/symmetric-jdbc/src/main/java/org/jumpmind/db/platform/oracle/OracleJdbcSqlTemplate.java new file mode 100644 index 0000000000..4020abfc7d --- /dev/null +++ b/symmetric/symmetric-jdbc/src/main/java/org/jumpmind/db/platform/oracle/OracleJdbcSqlTemplate.java @@ -0,0 +1,21 @@ +package org.jumpmind.db.platform.oracle; + +import javax.sql.DataSource; + +import org.jumpmind.db.platform.DatabasePlatformSettings; +import org.jumpmind.db.sql.jdbc.JdbcSqlTemplate; +import org.springframework.jdbc.support.lob.LobHandler; + +public class OracleJdbcSqlTemplate extends JdbcSqlTemplate { + + public OracleJdbcSqlTemplate(DataSource dataSource, DatabasePlatformSettings settings, + LobHandler lobHandler) { + super(dataSource, settings, lobHandler); + } + + @Override + public String getSelectLastInsertIdSql(String sequenceName) { + return "select " + sequenceName + ".currval from dual"; + } + +} diff --git a/symmetric/symmetric-jdbc/src/main/java/org/jumpmind/db/platform/oracle/OraclePlatform.java b/symmetric/symmetric-jdbc/src/main/java/org/jumpmind/db/platform/oracle/OraclePlatform.java index 28ba883bd9..534b87643c 100644 --- a/symmetric/symmetric-jdbc/src/main/java/org/jumpmind/db/platform/oracle/OraclePlatform.java +++ b/symmetric/symmetric-jdbc/src/main/java/org/jumpmind/db/platform/oracle/OraclePlatform.java @@ -26,7 +26,6 @@ import org.apache.commons.lang.StringUtils; import org.jumpmind.db.platform.AbstractJdbcDatabasePlatform; import org.jumpmind.db.platform.DatabasePlatformSettings; -import org.jumpmind.db.sql.jdbc.JdbcSqlTemplate; import org.jumpmind.log.Log; import org.springframework.jdbc.support.lob.OracleLobHandler; @@ -109,10 +108,11 @@ public OraclePlatform(DataSource dataSource, DatabasePlatformSettings settings, ddlReader = new OracleDdlReader(log, this); ddlBuilder = new OracleBuilder(log, this); } + @Override protected void createSqlTemplate() { - this.sqlTemplate = new JdbcSqlTemplate(dataSource, settings, new OracleLobHandler()); + this.sqlTemplate = new OracleJdbcSqlTemplate(dataSource, settings, new OracleLobHandler()); } public String getName() { diff --git a/symmetric/symmetric-jdbc/src/main/java/org/jumpmind/db/platform/postgresql/PostgresDmlStatement.java b/symmetric/symmetric-jdbc/src/main/java/org/jumpmind/db/platform/postgresql/PostgreSqlDmlStatement.java similarity index 95% rename from symmetric/symmetric-jdbc/src/main/java/org/jumpmind/db/platform/postgresql/PostgresDmlStatement.java rename to symmetric/symmetric-jdbc/src/main/java/org/jumpmind/db/platform/postgresql/PostgreSqlDmlStatement.java index 77bf56b0c3..c595586497 100644 --- a/symmetric/symmetric-jdbc/src/main/java/org/jumpmind/db/platform/postgresql/PostgresDmlStatement.java +++ b/symmetric/symmetric-jdbc/src/main/java/org/jumpmind/db/platform/postgresql/PostgreSqlDmlStatement.java @@ -24,9 +24,9 @@ import org.jumpmind.db.model.Column; import org.jumpmind.db.sql.DmlStatement; -public class PostgresDmlStatement extends DmlStatement { +public class PostgreSqlDmlStatement extends DmlStatement { - public PostgresDmlStatement(DmlType type, String catalogName, String schemaName, + public PostgreSqlDmlStatement(DmlType type, String catalogName, String schemaName, String tableName, Column[] keys, Column[] columns, boolean isDateOverrideToTimestamp, String identifierQuoteString) { super(type, catalogName, schemaName, tableName, keys, columns, isDateOverrideToTimestamp, diff --git a/symmetric/symmetric-jdbc/src/main/java/org/jumpmind/db/platform/postgresql/PostgreSqlJdbcSqlTemplate.java b/symmetric/symmetric-jdbc/src/main/java/org/jumpmind/db/platform/postgresql/PostgreSqlJdbcSqlTemplate.java new file mode 100644 index 0000000000..cafeb42dfb --- /dev/null +++ b/symmetric/symmetric-jdbc/src/main/java/org/jumpmind/db/platform/postgresql/PostgreSqlJdbcSqlTemplate.java @@ -0,0 +1,27 @@ +package org.jumpmind.db.platform.postgresql; + +import javax.sql.DataSource; + +import org.jumpmind.db.platform.DatabasePlatformSettings; +import org.jumpmind.db.sql.jdbc.JdbcSqlTemplate; +import org.springframework.jdbc.support.lob.LobHandler; + +public class PostgreSqlJdbcSqlTemplate extends JdbcSqlTemplate { + + public PostgreSqlJdbcSqlTemplate(DataSource dataSource, DatabasePlatformSettings settings, + LobHandler lobHandler) { + super(dataSource, settings, lobHandler); + this.requiresAutoCommitFalseToSetFetchSize = true; + } + + @Override + public String getSelectLastInsertIdSql(String sequenceName) { + return "select currval('" + sequenceName + "_seq')"; + } + + @Override + protected boolean allowsNullForIdentityColumn() { + return false; + } + +} diff --git a/symmetric/symmetric-jdbc/src/main/java/org/jumpmind/db/platform/postgresql/PostgreSqlPlatform.java b/symmetric/symmetric-jdbc/src/main/java/org/jumpmind/db/platform/postgresql/PostgreSqlPlatform.java index 6c8313869e..557d120044 100644 --- a/symmetric/symmetric-jdbc/src/main/java/org/jumpmind/db/platform/postgresql/PostgreSqlPlatform.java +++ b/symmetric/symmetric-jdbc/src/main/java/org/jumpmind/db/platform/postgresql/PostgreSqlPlatform.java @@ -46,17 +46,13 @@ public class PostgreSqlPlatform extends AbstractJdbcDatabasePlatform { /* The standard PostgreSQL jdbc driver. */ public static final String JDBC_DRIVER = "org.postgresql.Driver"; /* The subprotocol used by the standard PostgreSQL driver. */ - public static final String JDBC_SUBPROTOCOL = "postgresql"; + public static final String JDBC_SUBPROTOCOL = "postgresql"; /* * Creates a new platform instance. */ public PostgreSqlPlatform(DataSource dataSource, DatabasePlatformSettings settings, Log log) { - super(dataSource, settings, log); - - // Query timeout needs to be zero for postrgres because the jdbc driver does - // not support a timeout setting of of other than zero. - settings.setQueryTimeout(0); + super(dataSource, overrideSettings(settings), log); // this is the default length though it might be changed when building // PostgreSQL @@ -104,6 +100,18 @@ public PostgreSqlPlatform(DataSource dataSource, DatabasePlatformSettings settin ddlReader = new PostgreSqlDdlReader(log, this); ddlBuilder = new PostgreSqlBuilder(log, this); } + + protected static DatabasePlatformSettings overrideSettings(DatabasePlatformSettings settings) { + // Query timeout needs to be zero for postrgres because the jdbc driver does + // not support a timeout setting of of other than zero. + settings.setQueryTimeout(0); + return settings; + } + + @Override + protected void createSqlTemplate() { + this.sqlTemplate = new PostgreSqlJdbcSqlTemplate(dataSource, settings, null); + } public String getName() { return DATABASENAME; @@ -216,7 +224,7 @@ public Object[] getObjectValues(BinaryEncoding encoding, String[] values, @Override public DmlStatement createDmlStatement(DmlType dmlType, String catalogName, String schemaName, String tableName, Column[] keys, Column[] columns) { - return new PostgresDmlStatement(dmlType, catalogName, schemaName, tableName, keys, columns, + return new PostgreSqlDmlStatement(dmlType, catalogName, schemaName, tableName, keys, columns, getPlatformInfo().isDateOverridesToTimestamp(), getPlatformInfo().getIdentifierQuoteString()); } diff --git a/symmetric/symmetric-jdbc/src/main/java/org/jumpmind/db/platform/sqlite/SqLiteBuilder.java b/symmetric/symmetric-jdbc/src/main/java/org/jumpmind/db/platform/sqlite/SqLiteBuilder.java deleted file mode 100644 index 5ccd73c466..0000000000 --- a/symmetric/symmetric-jdbc/src/main/java/org/jumpmind/db/platform/sqlite/SqLiteBuilder.java +++ /dev/null @@ -1,271 +0,0 @@ -/* - * To change this template, choose Tools | Templates - * and open the template in the editor. - */ - -package org.jumpmind.db.platform.sqlite; - -/* - * 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. - */ - -import java.io.Writer; -import java.sql.Types; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Iterator; -import java.util.ListIterator; - -import org.apache.commons.lang.StringUtils; -import org.jumpmind.db.alter.AddColumnChange; -import org.jumpmind.db.alter.ColumnChange; -import org.jumpmind.db.alter.ColumnDataTypeChange; -import org.jumpmind.db.alter.ColumnRequiredChange; -import org.jumpmind.db.alter.ColumnSizeChange; -import org.jumpmind.db.alter.RemoveColumnChange; -import org.jumpmind.db.alter.TableChange; -import org.jumpmind.db.model.Column; -import org.jumpmind.db.model.Database; -import org.jumpmind.db.model.IIndex; -import org.jumpmind.db.model.ModelException; -import org.jumpmind.db.model.Table; -import org.jumpmind.db.model.TypeMap; -import org.jumpmind.db.platform.AbstractDdlBuilder; -import org.jumpmind.db.platform.IDatabasePlatform; -import org.jumpmind.log.Log; - -/* - * The SQL Builder for the SqlLite database. - */ -public class SqLiteBuilder extends AbstractDdlBuilder { - - public SqLiteBuilder(Log log, IDatabasePlatform platform) { - super(log, platform); - - addEscapedCharSequence("'", "''"); - } - - @Override - public void dropTable(Table table, StringBuilder ddl) { - ddl.append("DROP TABLE IF EXISTS "); - printIdentifier(getTableName(table.getName()), ddl); - printEndOfStatement(ddl); - } - - protected void writeColumnAutoIncrementStmt(Table table, Column column, StringBuilder ddl) { - if (!column.isPrimaryKey()) { - ddl.append("PRIMARY KEY AUTOINCREMENT"); - } - } - - @Override - public String getSelectLastIdentityValues(Table table) { - return "CALL IDENTITY()"; - } - - @Override - public void writeExternalIndexDropStmt(Table table, IIndex index, StringBuilder ddl) { - ddl.append("DROP INDEX IF EXISTS "); - printIdentifier(getIndexName(index), ddl); - printEndOfStatement(ddl); - } - - @Override - @SuppressWarnings("unchecked") - protected void processTableStructureChanges(Database currentModel, Database desiredModel, - Collection changes, StringBuilder ddl) { - // Only drop columns that are not part of a primary key - for (Iterator changeIt = changes.iterator(); changeIt.hasNext();) { - TableChange change = (TableChange) changeIt.next(); - - if ((change instanceof RemoveColumnChange) - && ((RemoveColumnChange) change).getColumn().isPrimaryKey()) { - return; - } - } - - // in order to utilize the ALTER TABLE ADD COLUMN BEFORE statement - // we have to apply the add column changes in the correct order - // thus we first gather all add column changes and then execute them - // Since we get them in target table column order, we can simply - // iterate backwards - ArrayList addColumnChanges = new ArrayList(); - - for (Iterator changeIt = changes.iterator(); changeIt.hasNext();) { - TableChange change = (TableChange) changeIt.next(); - if (change instanceof AddColumnChange) { - addColumnChanges.add(change); - changeIt.remove(); - } - } - - for (ListIterator changeIt = addColumnChanges.listIterator(addColumnChanges.size()); changeIt - .hasPrevious();) { - AddColumnChange addColumnChange = (AddColumnChange) changeIt.previous(); - processChange(currentModel, desiredModel, addColumnChange, ddl); - changeIt.remove(); - } - - for (Iterator changeIt = changes.iterator(); changeIt.hasNext();) { - TableChange change = (TableChange) changeIt.next(); - if (change instanceof RemoveColumnChange) { - RemoveColumnChange removeColumnChange = (RemoveColumnChange) change; - processChange(currentModel, desiredModel, removeColumnChange, ddl); - changeIt.remove(); - } - } - - for (Iterator changeIt = changes.iterator(); changeIt.hasNext();) { - TableChange change = (TableChange) changeIt.next(); - if (change instanceof ColumnChange) { - boolean needsAlter = true; - if (change instanceof ColumnDataTypeChange) { - ColumnDataTypeChange dataTypeChange = (ColumnDataTypeChange) change; - if (dataTypeChange.getChangedColumn().getTypeCode() == Types.DECIMAL - && dataTypeChange.getNewTypeCode() == Types.NUMERIC) { - needsAlter = false; - } - if (dataTypeChange.getChangedColumn().getTypeCode() == Types.SMALLINT - && dataTypeChange.getNewTypeCode() == Types.TINYINT) { - needsAlter = false; - } - if (dataTypeChange.getChangedColumn().getTypeCode() == Types.VARCHAR - && dataTypeChange.getNewTypeCode() == Types.LONGVARCHAR) { - needsAlter = false; - } - } - if (change instanceof ColumnSizeChange) { - ColumnSizeChange sizeChange = (ColumnSizeChange) change; - if (sizeChange.getNewScale() == 0 && sizeChange.getNewSize() == 0) { - needsAlter = false; - } else if (sizeChange.getNewSize() == sizeChange.getChangedColumn() - .getSizeAsInt() - && sizeChange.getNewScale() == sizeChange.getChangedColumn().getScale()) { - needsAlter = false; - } - } - if (needsAlter) { - processAlterColumn(currentModel, (ColumnChange) change, ddl); - } - changeIt.remove(); - } - } - - } - - protected void processAlterColumn(Database currentModel, ColumnChange columnChange, - StringBuilder ddl) { - columnChange.apply(currentModel, platform.isDelimitedIdentifierModeOn()); - ddl.append("ALTER TABLE "); - printlnIdentifier(getTableName(columnChange.getChangedTable().getName()), ddl); - printIndent(ddl); - ddl.append("ALTER COLUMN "); - if (columnChange instanceof ColumnRequiredChange) { - ColumnRequiredChange columnRequiredChange = (ColumnRequiredChange) columnChange; - printlnIdentifier(getColumnName(columnChange.getChangedColumn()), ddl); - printIndent(ddl); - if (columnRequiredChange.getChangedColumn().isRequired()) { - ddl.append(" SET NOT NULL "); - } else { - ddl.append(" SET NULL "); - } - } else { - writeColumn(columnChange.getChangedTable(), columnChange.getChangedColumn(), ddl); - } - printEndOfStatement(ddl); - } - - /* - * Processes the addition of a column to a table. - */ - protected void processChange(Database currentModel, Database desiredModel, - AddColumnChange change, StringBuilder ddl) { - ddl.append("ALTER TABLE "); - printlnIdentifier(getTableName(change.getChangedTable().getName()), ddl); - printIndent(ddl); - ddl.append("ADD COLUMN "); - writeColumn(change.getChangedTable(), change.getNewColumn(), ddl); - if (change.getNextColumn() != null) { - ddl.append(" BEFORE "); - printIdentifier(getColumnName(change.getNextColumn()), ddl); - } - printEndOfStatement(ddl); - change.apply(currentModel, platform.isDelimitedIdentifierModeOn()); - } - - /* - * Processes the removal of a column from a table. - */ - protected void processChange(Database currentModel, Database desiredModel, - RemoveColumnChange change, StringBuilder ddl) { - ddl.append("ALTER TABLE "); - printlnIdentifier(getTableName(change.getChangedTable().getName()), ddl); - printIndent(ddl); - ddl.append("DROP COLUMN "); - printIdentifier(getColumnName(change.getColumn()), ddl); - printEndOfStatement(ddl); - change.apply(currentModel, platform.isDelimitedIdentifierModeOn()); - } - - @Override - protected void writeColumnDefaultValueStmt(Table table, Column column, StringBuilder ddl) { - Object parsedDefault = column.getParsedDefaultValue(); - - if (parsedDefault != null) { - if (!platform.getPlatformInfo().isDefaultValuesForLongTypesSupported() - && ((column.getTypeCode() == Types.LONGVARBINARY) || (column.getTypeCode() == Types.LONGVARCHAR))) { - throw new ModelException( - "The platform does not support default values for LONGVARCHAR or LONGVARBINARY columns"); - } - // we write empty default value strings only if the type is not a - // numeric or date/time type - if (isValidDefaultValue(column.getDefaultValue(), column.getTypeCode())) { - ddl.append(" DEFAULT "); - writeColumnDefaultValue(table, column, ddl); - } - } else if (platform.getPlatformInfo().isDefaultValueUsedForIdentitySpec() - && column.isAutoIncrement()) { - ddl.append(" DEFAULT "); - writeColumnDefaultValue(table, column, ddl); - } else if (!StringUtils.isBlank(column.getDefaultValue())) { - ddl.append(" DEFAULT "); - writeColumnDefaultValue(table, column, ddl); - } - } - - @Override - protected void printDefaultValue(Object defaultValue, int typeCode, StringBuilder ddl) { - if (defaultValue != null) { - String defaultValueStr = defaultValue.toString(); - boolean shouldUseQuotes = !TypeMap.isNumericType(typeCode) - && !defaultValueStr.startsWith("TO_DATE(") - && !defaultValue.equals("CURRENT_TIMESTAMP") - && !defaultValue.equals("CURRENT_TIME") && !defaultValue.equals("CURRENT_DATE"); - ; - - if (shouldUseQuotes) { - // characters are only escaped when within a string literal - ddl.append(platform.getPlatformInfo().getValueQuoteToken()); - ddl.append(escapeStringValue(defaultValueStr)); - ddl.append(platform.getPlatformInfo().getValueQuoteToken()); - } else { - ddl.append(defaultValueStr); - } - } - } -} diff --git a/symmetric/symmetric-jdbc/src/main/java/org/jumpmind/db/platform/sqlite/SqLiteDdlReader.java b/symmetric/symmetric-jdbc/src/main/java/org/jumpmind/db/platform/sqlite/SqLiteDdlReader.java deleted file mode 100644 index 95e3c14789..0000000000 --- a/symmetric/symmetric-jdbc/src/main/java/org/jumpmind/db/platform/sqlite/SqLiteDdlReader.java +++ /dev/null @@ -1,94 +0,0 @@ -package org.jumpmind.db.platform.sqlite; - -import java.sql.Connection; -import java.sql.SQLException; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; -import java.util.Map; - -import org.jumpmind.db.model.Column; -import org.jumpmind.db.model.ForeignKey; -import org.jumpmind.db.model.IIndex; -import org.jumpmind.db.model.Table; -import org.jumpmind.db.model.TypeMap; -import org.jumpmind.db.platform.AbstractJdbcDdlReader; -import org.jumpmind.db.platform.DatabaseMetaDataWrapper; -import org.jumpmind.db.platform.IDatabasePlatform; -import org.jumpmind.db.platform.MetaDataColumnDescriptor; -import org.jumpmind.log.Log; - -/* - * Reads a database model from a SQLite database. - */ -public class SqLiteDdlReader extends AbstractJdbcDdlReader { - - public SqLiteDdlReader(Log log, IDatabasePlatform platform) { - super(log, platform); - setDefaultCatalogPattern(null); - setDefaultSchemaPattern(null); - } - - protected Collection readForeignKeys(DatabaseMetaDataWrapper metaData, String tableName) throws SQLException { - // TODO - return new ArrayList(); - } - - protected Collection readIndices(DatabaseMetaDataWrapper metaData, String tableName) throws SQLException { - // TODO - return new ArrayList(); - } - - /* Below here copied from H2. May still need tweaking */ - - @Override - @SuppressWarnings("unchecked") - protected Column readColumn(DatabaseMetaDataWrapper metaData, Map values) throws SQLException { - Column column = super.readColumn(metaData, values); - if (values.get("CHARACTER_MAXIMUM_LENGTH") != null) { - column.setSize(values.get("CHARACTER_MAXIMUM_LENGTH").toString()); - } - if (values.get("COLUMN_DEFAULT") != null) { - column.setDefaultValue(values.get("COLUMN_DEFAULT").toString()); - } - if (values.get("NUMERIC_SCALE") != null) { - column.setScale((Integer) values.get("NUMERIC_SCALE")); - } - if (TypeMap.isTextType(column.getTypeCode()) && (column.getDefaultValue() != null)) { - column.setDefaultValue(unescape(column.getDefaultValue(), "'", "''")); - } - return column; - } - - @SuppressWarnings("unchecked") - @Override - protected List initColumnsForColumn() { - List result = new ArrayList(); - result.add(new MetaDataColumnDescriptor("COLUMN_DEF", 12)); - result.add(new MetaDataColumnDescriptor("COLUMN_DEFAULT", 12)); - result.add(new MetaDataColumnDescriptor("TABLE_NAME", 12)); - result.add(new MetaDataColumnDescriptor("COLUMN_NAME", 12)); - result.add(new MetaDataColumnDescriptor("DATA_TYPE", 4, new Integer(1111))); - result.add(new MetaDataColumnDescriptor("NUM_PREC_RADIX", 4, new Integer(10))); - result.add(new MetaDataColumnDescriptor("DECIMAL_DIGITS", 4, new Integer(0))); - result.add(new MetaDataColumnDescriptor("NUMERIC_SCALE", 4, new Integer(0))); - result.add(new MetaDataColumnDescriptor("COLUMN_SIZE", 12)); - result.add(new MetaDataColumnDescriptor("CHARACTER_MAXIMUM_LENGTH", 12)); - result.add(new MetaDataColumnDescriptor("IS_NULLABLE", 12, "YES")); - result.add(new MetaDataColumnDescriptor("REMARKS", 12)); - return result; - } - - @Override - protected boolean isInternalForeignKeyIndex(Connection connection, DatabaseMetaDataWrapper metaData, Table table, ForeignKey fk, - IIndex index) { - String name = index.getName(); - return name != null && name.startsWith("CONSTRAINT_INDEX_"); - } - - @Override - protected boolean isInternalPrimaryKeyIndex(Connection connection, DatabaseMetaDataWrapper metaData, Table table, IIndex index) { - String name = index.getName(); - return name != null && name.startsWith("PRIMARY_KEY_"); - } -} diff --git a/symmetric/symmetric-jdbc/src/main/java/org/jumpmind/db/platform/sqlite/SqLitePlatform.java b/symmetric/symmetric-jdbc/src/main/java/org/jumpmind/db/platform/sqlite/SqLitePlatform.java deleted file mode 100644 index e6748685fe..0000000000 --- a/symmetric/symmetric-jdbc/src/main/java/org/jumpmind/db/platform/sqlite/SqLitePlatform.java +++ /dev/null @@ -1,96 +0,0 @@ -package org.jumpmind.db.platform.sqlite; - -/* - * 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. - */ - -import java.sql.Types; - -import javax.sql.DataSource; - -import org.jumpmind.db.platform.AbstractJdbcDatabasePlatform; -import org.jumpmind.db.platform.DatabasePlatformSettings; -import org.jumpmind.db.platform.IDatabasePlatform; -import org.jumpmind.log.Log; - -/* - * The platform implementation for the SQLite database. - */ -public class SqLitePlatform extends AbstractJdbcDatabasePlatform implements IDatabasePlatform { - - /* Database name of this platform. */ - public static final String DATABASENAME = "SQLite3"; - - /* The standard H2 driver. */ - public static final String JDBC_DRIVER = "org.sqlite.JDBC"; - - /* - * Creates a new instance of the H2 platform. - */ - public SqLitePlatform(DataSource dataSource,DatabasePlatformSettings settings, Log log) { - super(dataSource, settings, log); - - info.setNonPKIdentityColumnsSupported(false); - info.setIdentityOverrideAllowed(false); - info.setSystemForeignKeyIndicesAlwaysNonUnique(true); - info.setNullAsDefaultValueRequired(false); - info.addNativeTypeMapping(Types.ARRAY, "BINARY", Types.BINARY); - info.addNativeTypeMapping(Types.DISTINCT, "BINARY", Types.BINARY); - info.addNativeTypeMapping(Types.NULL, "BINARY", Types.BINARY); - info.addNativeTypeMapping(Types.REF, "BINARY", Types.BINARY); - info.addNativeTypeMapping(Types.STRUCT, "BINARY", Types.BINARY); - info.addNativeTypeMapping(Types.DATALINK, "BINARY", Types.BINARY); - - info.addNativeTypeMapping(Types.BIT, "BOOLEAN", Types.BIT); - info.addNativeTypeMapping(Types.TINYINT, "SMALLINT", Types.TINYINT); - info.addNativeTypeMapping(Types.SMALLINT, "SMALLINT", Types.SMALLINT); - info.addNativeTypeMapping(Types.BINARY, "BINARY", Types.BINARY); - info.addNativeTypeMapping(Types.BLOB, "BLOB", Types.BLOB); - info.addNativeTypeMapping(Types.CLOB, "CLOB", Types.CLOB); - info.addNativeTypeMapping(Types.FLOAT, "DOUBLE", Types.DOUBLE); - info.addNativeTypeMapping(Types.JAVA_OBJECT, "OTHER"); - - info.setDefaultSize(Types.CHAR, Integer.MAX_VALUE); - info.setDefaultSize(Types.VARCHAR, Integer.MAX_VALUE); - info.setDefaultSize(Types.BINARY, Integer.MAX_VALUE); - info.setDefaultSize(Types.VARBINARY, Integer.MAX_VALUE); - - info.setNonBlankCharColumnSpacePadded(false); - info.setBlankCharColumnSpacePadded(false); - info.setCharColumnSpaceTrimmed(true); - info.setEmptyStringNulled(false); - - - ddlReader = new SqLiteDdlReader(log, this); - ddlBuilder = new SqLiteBuilder(log, this); - } - - public String getName() { - return DATABASENAME; - } - - - public String getDefaultCatalog() { - return null; - } - - public String getDefaultSchema() { - return null; - } - -} \ No newline at end of file diff --git a/symmetric/symmetric-jdbc/src/main/java/org/jumpmind/db/platform/sybase/SybaseJdbcSqlTemplate.java b/symmetric/symmetric-jdbc/src/main/java/org/jumpmind/db/platform/sybase/SybaseJdbcSqlTemplate.java new file mode 100644 index 0000000000..057c235c35 --- /dev/null +++ b/symmetric/symmetric-jdbc/src/main/java/org/jumpmind/db/platform/sybase/SybaseJdbcSqlTemplate.java @@ -0,0 +1,21 @@ +package org.jumpmind.db.platform.sybase; + +import javax.sql.DataSource; + +import org.jumpmind.db.platform.DatabasePlatformSettings; +import org.jumpmind.db.sql.jdbc.JdbcSqlTemplate; +import org.springframework.jdbc.support.lob.LobHandler; + +public class SybaseJdbcSqlTemplate extends JdbcSqlTemplate { + + public SybaseJdbcSqlTemplate(DataSource dataSource, DatabasePlatformSettings settings, + LobHandler lobHandler) { + super(dataSource, settings, lobHandler); + } + + @Override + protected boolean allowsNullForIdentityColumn() { + return false; + } + +} diff --git a/symmetric/symmetric-jdbc/src/main/java/org/jumpmind/db/platform/sybase/SybasePlatform.java b/symmetric/symmetric-jdbc/src/main/java/org/jumpmind/db/platform/sybase/SybasePlatform.java index 7d0c36d4c1..23fb99e903 100644 --- a/symmetric/symmetric-jdbc/src/main/java/org/jumpmind/db/platform/sybase/SybasePlatform.java +++ b/symmetric/symmetric-jdbc/src/main/java/org/jumpmind/db/platform/sybase/SybasePlatform.java @@ -108,6 +108,11 @@ public SybasePlatform(DataSource dataSource, DatabasePlatformSettings settings, sqlScriptReplacementTokens.put("current_timestamp", "getdate()"); } + @Override + protected void createSqlTemplate() { + this.sqlTemplate = new SybaseJdbcSqlTemplate(dataSource, settings, null); + } + public String getName() { return DATABASENAME; } diff --git a/symmetric/symmetric-jdbc/src/main/java/org/jumpmind/db/sql/jdbc/JdbcSqlTemplate.java b/symmetric/symmetric-jdbc/src/main/java/org/jumpmind/db/sql/jdbc/JdbcSqlTemplate.java index b3a8e48580..92ea2a2e37 100644 --- a/symmetric/symmetric-jdbc/src/main/java/org/jumpmind/db/sql/jdbc/JdbcSqlTemplate.java +++ b/symmetric/symmetric-jdbc/src/main/java/org/jumpmind/db/sql/jdbc/JdbcSqlTemplate.java @@ -3,12 +3,17 @@ import java.sql.Blob; import java.sql.Clob; import java.sql.Connection; +import java.sql.DatabaseMetaData; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.ResultSetMetaData; import java.sql.SQLException; import java.sql.Statement; +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; import java.util.Map; +import java.util.Set; import javax.sql.DataSource; @@ -18,6 +23,7 @@ import org.jumpmind.db.sql.ISqlRowMapper; import org.jumpmind.db.sql.ISqlTemplate; import org.jumpmind.db.sql.ISqlTransaction; +import org.jumpmind.db.sql.Row; import org.jumpmind.db.sql.SqlException; import org.jumpmind.log.Log; import org.jumpmind.log.LogFactory; @@ -35,10 +41,13 @@ public class JdbcSqlTemplate extends AbstractSqlTemplate implements ISqlTemplate protected boolean requiresAutoCommitFalseToSetFetchSize = false; protected DatabasePlatformSettings settings; - + protected LobHandler lobHandler; - public JdbcSqlTemplate(DataSource dataSource, DatabasePlatformSettings settings, LobHandler lobHandler) { + protected Boolean supportsGetGeneratedKeys = null; + + public JdbcSqlTemplate(DataSource dataSource, DatabasePlatformSettings settings, + LobHandler lobHandler) { this.dataSource = dataSource; this.settings = settings; this.lobHandler = lobHandler == null ? new DefaultLobHandler() : lobHandler; @@ -52,15 +61,10 @@ public boolean isRequiresAutoCommitFalseToSetFetchSize() { return requiresAutoCommitFalseToSetFetchSize; } - public void setRequiresAutoCommitFalseToSetFetchSize( - boolean requiresAutoCommitFalseToSetFetchSize) { - this.requiresAutoCommitFalseToSetFetchSize = requiresAutoCommitFalseToSetFetchSize; - } - public void setSettings(DatabasePlatformSettings settings) { this.settings = settings; } - + public DatabasePlatformSettings getSettings() { return settings; } @@ -82,9 +86,9 @@ public T execute(Connection con) throws SQLException { PreparedStatement ps = null; ResultSet rs = null; try { - ps = con.prepareStatement(sql); + ps = con.prepareStatement(expandSql(sql, args)); ps.setQueryTimeout(settings.getQueryTimeout()); - JdbcUtils.setValues(ps, args); + JdbcUtils.setValues(ps, expandArgs(sql, args)); rs = ps.executeQuery(); if (rs.next()) { result = (T) rs.getObject(1); @@ -97,7 +101,7 @@ public T execute(Connection con) throws SQLException { } }); } - + public byte[] queryForBlob(final String sql, final Object... args) { return execute(new IConnectionCallback() { public byte[] execute(Connection con) throws SQLException { @@ -118,9 +122,9 @@ public byte[] execute(Connection con) throws SQLException { } return result; } - }); + }); } - + public String queryForClob(final String sql, final Object... args) { return execute(new IConnectionCallback() { public String execute(Connection con) throws SQLException { @@ -141,8 +145,22 @@ public String execute(Connection con) throws SQLException { } return result; } - }); - } + }); + } + + public Map queryForMap(final String sql, final ISqlRowMapper mapper, + final String keyColumn, Object... args) { + final Map result = new HashMap(); + query(sql, new ISqlRowMapper() { + public T mapRow(Row row) { + String keyName = row.getString(keyColumn); + T object = mapper.mapRow(row); + result.put(keyName, object); + return object; + } + }, args); + return result; + } public Map queryForMap(final String sql, final Object... args) { return execute(new IConnectionCallback>() { @@ -411,10 +429,6 @@ public SqlException translate(Exception ex) { } public SqlException translate(String message, Exception ex) { - // TODO - // if (getDbDialect().isDataIntegrityException(ex)) { - // return new DataIntegrityViolationException(message, ex); - // } else if (ex instanceof SqlException) { return (SqlException) ex; } else { @@ -446,4 +460,136 @@ public String execute(Connection con) throws SQLException { }); } + public String getDatabaseProductVersion() { + return execute(new IConnectionCallback() { + public String execute(Connection con) throws SQLException { + return con.getMetaData().getDatabaseProductVersion(); + } + }); + } + + public String getDriverName() { + return execute(new IConnectionCallback() { + public String execute(Connection con) throws SQLException { + return con.getMetaData().getDriverName(); + } + }); + } + + public String getDriverVersion() { + return execute(new IConnectionCallback() { + public String execute(Connection con) throws SQLException { + return con.getMetaData().getDriverVersion(); + } + }); + } + + public Set getSqlKeywords() { + return execute(new IConnectionCallback>() { + public Set execute(Connection con) throws SQLException { + DatabaseMetaData sqlTemplateData = con.getMetaData(); + return new HashSet(Arrays.asList(sqlTemplateData.getSQLKeywords() + .split(","))); + } + }); + } + + public boolean supportsGetGeneratedKeys() { + if (supportsGetGeneratedKeys == null) { + supportsGetGeneratedKeys = execute(new IConnectionCallback() { + public Boolean execute(Connection con) throws SQLException { + return con.getMetaData().supportsGetGeneratedKeys(); + } + }); + } + return supportsGetGeneratedKeys; + } + + public boolean supportsReturningKeys() { + return false; + } + + protected boolean allowsNullForIdentityColumn() { + return true; + } + + protected String getSelectLastInsertIdSql(String sequenceName) { + throw new UnsupportedOperationException(); + } + + public long insertWithGeneratedKey(final String sql, final String column, + final String sequenceName, final Object[] args, final int[] types) { + return execute(new IConnectionCallback() { + public Long execute(Connection conn) throws SQLException { + return insertWithGeneratedKey(conn, sql, column, sequenceName, args, types); + } + }); + } + + protected long insertWithGeneratedKey(Connection conn, String sql, String column, + String sequenceName, Object[] args, int[] types) throws SQLException { + long key = 0; + PreparedStatement ps = null; + try { + boolean supportsGetGeneratedKeys = supportsGetGeneratedKeys(); + boolean supportsReturningKeys = supportsReturningKeys(); + if (allowsNullForIdentityColumn()) { + if (supportsGetGeneratedKeys) { + ps = conn.prepareStatement(sql, new int[] { 1 }); + } else if (supportsReturningKeys) { + ps = conn.prepareStatement(sql + " returning " + sequenceName); + } else { + ps = conn.prepareStatement(sql); + } + } else { + String replaceSql = sql.replaceFirst("\\(\\w*,", "(").replaceFirst("\\(null,", "("); + if (supportsGetGeneratedKeys) { + ps = conn.prepareStatement(replaceSql, Statement.RETURN_GENERATED_KEYS); + } else { + ps = conn.prepareStatement(replaceSql); + } + } + ps.setQueryTimeout(settings.getQueryTimeout()); + JdbcUtils.setValues(ps, args, types, lobHandler); + + ResultSet rs = null; + if (supportsGetGeneratedKeys) { + ps.executeUpdate(); + try { + rs = ps.getGeneratedKeys(); + if (rs.next()) { + key = rs.getLong(1); + } + } finally { + close(rs); + } + } else if (supportsReturningKeys) { + try { + rs = ps.executeQuery(); + if (rs.next()) { + key = rs.getLong(1); + } + } finally { + close(rs); + } + } else { + Statement st = null; + ps.executeUpdate(); + try { + st = conn.createStatement(); + rs = st.executeQuery(getSelectLastInsertIdSql(sequenceName)); + if (rs.next()) { + key = rs.getLong(1); + } + } finally { + close(rs); + close(st); + } + } + } finally { + close(ps); + } + return key; + } + } diff --git a/symmetric/symmetric-jdbc/src/main/java/org/jumpmind/db/sql/jdbc/JdbcSqlTransaction.java b/symmetric/symmetric-jdbc/src/main/java/org/jumpmind/db/sql/jdbc/JdbcSqlTransaction.java index 216a47f913..384181f5e1 100644 --- a/symmetric/symmetric-jdbc/src/main/java/org/jumpmind/db/sql/jdbc/JdbcSqlTransaction.java +++ b/symmetric/symmetric-jdbc/src/main/java/org/jumpmind/db/sql/jdbc/JdbcSqlTransaction.java @@ -20,7 +20,7 @@ * TODO Support Oracle's non-standard way of batching */ public class JdbcSqlTransaction implements ISqlTransaction { - + protected final static Log log = LogFactory.getLog(JdbcSqlTransaction.class); protected boolean inBatchMode = false; @@ -33,8 +33,6 @@ public class JdbcSqlTransaction implements ISqlTransaction { protected JdbcSqlTemplate jdbcSqlTemplate; - protected int numberOfRowsBeforeBatchFlush = 1000; - protected boolean oldAutoCommitValue; protected List markers = new ArrayList(); @@ -50,14 +48,6 @@ public JdbcSqlTransaction(JdbcSqlTemplate jdbcSqlTemplate) { } } - public void setNumberOfRowsBeforeBatchFlush(int numberOfRowsBeforeBatchFlush) { - this.numberOfRowsBeforeBatchFlush = numberOfRowsBeforeBatchFlush; - } - - public int getNumberOfRowsBeforeBatchFlush() { - return numberOfRowsBeforeBatchFlush; - } - public void setInBatchMode(boolean useBatching) { if (connection != null) { this.inBatchMode = useBatching; @@ -134,7 +124,7 @@ public int flush() { } return rowsUpdated; } - + public int queryForInt(String sql, Object... args) { return queryForObject(sql, Integer.class, args); } @@ -220,7 +210,7 @@ protected void removeMarkersThatWereSuccessful(BatchUpdateException ex) { } public void prepare(String sql) { - try { + try { if (this.markers.size() > 0) { throw new IllegalStateException( "Cannot prepare a new batch before the last batch has been flushed."); @@ -240,11 +230,11 @@ public int addRow(Object marker, Object[] args, int[] argTypes) { int rowsUpdated = 0; try { if (log.isDebugEnabled()) { - log.debug("Adding %s %s", ArrayUtils.toString(args), inBatchMode ? " in batch mode" : ""); + log.debug("Adding %s %s", ArrayUtils.toString(args), inBatchMode ? " in batch mode" + : ""); } if (args != null) { - JdbcUtils.setValues(pstmt, args, argTypes, - jdbcSqlTemplate.getLobHandler()); + JdbcUtils.setValues(pstmt, args, argTypes, jdbcSqlTemplate.getLobHandler()); } if (inBatchMode) { if (marker == null) { @@ -252,7 +242,7 @@ public int addRow(Object marker, Object[] args, int[] argTypes) { } markers.add(marker); pstmt.addBatch(); - if (markers.size() >= numberOfRowsBeforeBatchFlush) { + if (markers.size() >= jdbcSqlTemplate.getSettings().getBatchSize()) { rowsUpdated = flush(); } } else { @@ -279,4 +269,14 @@ public Connection getConnection() { public void allowInsertIntoAutoIncrementColumns(boolean value, Table table) { } + public long insertWithGeneratedKey(String sql, String column, String sequenceName, + Object...args) { + try { + return jdbcSqlTemplate.insertWithGeneratedKey(connection, sql, column, sequenceName, + args, null); + } catch (SQLException ex) { + throw jdbcSqlTemplate.translate(ex); + } + } + } diff --git a/symmetric/symmetric-parent/pom.xml b/symmetric/symmetric-parent/pom.xml index 8a0a7950b1..385027e544 100644 --- a/symmetric/symmetric-parent/pom.xml +++ b/symmetric/symmetric-parent/pom.xml @@ -344,6 +344,17 @@ symmetric-core 3.0.0-SNAPSHOT + + org.jumpmind.symmetric + symmetric-core + test-jar + 3.0.0-SNAPSHOT + + + org.jumpmind.symmetric + symmetric-client + 3.0.0-SNAPSHOT + org.jumpmind.symmetric symmetric-server diff --git a/symmetric/symmetric-server/src/main/java/org/jumpmind/symmetric/SymmetricLauncher.java b/symmetric/symmetric-server/src/main/java/org/jumpmind/symmetric/SymmetricLauncher.java index 525a630d81..765e541681 100644 --- a/symmetric/symmetric-server/src/main/java/org/jumpmind/symmetric/SymmetricLauncher.java +++ b/symmetric/symmetric-server/src/main/java/org/jumpmind/symmetric/SymmetricLauncher.java @@ -32,7 +32,6 @@ import java.net.URL; import java.nio.charset.Charset; import java.sql.Connection; -import java.sql.SQLException; import org.apache.commons.cli.CommandLine; import org.apache.commons.cli.HelpFormatter; @@ -68,10 +67,7 @@ import org.jumpmind.symmetric.service.ITriggerRouterService; import org.jumpmind.symmetric.transport.IOutgoingTransport; import org.jumpmind.symmetric.transport.internal.InternalOutgoingTransport; -import org.jumpmind.symmetric.util.AppUtils; import org.jumpmind.symmetric.util.JarBuilder; -import org.springframework.context.ApplicationContext; -import org.springframework.context.support.ClassPathXmlApplicationContext; /** * Run SymmetricDS utilities and/or launch an embedded version of SymmetricDS. @@ -233,11 +229,10 @@ private void printHelp(Options options) { new HelpFormatter().printHelp("sym", options); } - private void testConnection(CommandLine line) throws Exception { + private void testConnection(CommandLine line, String propertiesFile) throws Exception { if (!line.hasOption(OPTION_SKIP_DB_VALIDATION)) { - ApplicationContext ctx = new ClassPathXmlApplicationContext(new String[] { - "classpath:/symmetric-properties.xml", "classpath:/symmetric-database.xml" }); - BasicDataSource ds = (BasicDataSource) ctx.getBean(Constants.DATA_SOURCE); + BasicDataSource ds = ClientSymmetricEngine + .createBasicDataSource(propertiesFile != null ? new File(propertiesFile) : null); Connection c = ds.getConnection(); c.close(); ds.close(); @@ -405,22 +400,25 @@ protected boolean executeOptions(CommandLine line) throws Exception { } if (line.hasOption(OPTION_DDL_GEN)) { - testConnection(line); + testConnection(line, propertiesFile); generateDDL(createEngine(propertiesFile), line.getOptionValue(OPTION_DDL_GEN)); System.exit(0); return true; } if (line.hasOption(OPTION_PURGE)) { - testConnection(line); - ((IPurgeService) createEngine(propertiesFile).getApplicationContext().getBean( - Constants.PURGE_SERVICE)).purgeOutgoing(); + testConnection(line, propertiesFile); + ISymmetricEngine engine = createEngine(propertiesFile); + IPurgeService purgeService = engine.getPurgeService(); + purgeService.purgeOutgoing(); + purgeService.purgeIncoming(); + purgeService.purgeDataGaps(); System.exit(0); return true; } if (line.hasOption(OPTION_OPEN_REGISTRATION)) { - testConnection(line); + testConnection(line, propertiesFile); String arg = line.getOptionValue(OPTION_OPEN_REGISTRATION); openRegistration(createEngine(propertiesFile), arg); System.out.println(Message.get("RegistrationOpened", arg)); @@ -429,7 +427,7 @@ protected boolean executeOptions(CommandLine line) throws Exception { } if (line.hasOption(OPTION_RELOAD_NODE)) { - testConnection(line); + testConnection(line, propertiesFile); String arg = line.getOptionValue(OPTION_RELOAD_NODE); String message = reloadNode(createEngine(propertiesFile), arg); System.out.println(message); @@ -438,7 +436,7 @@ protected boolean executeOptions(CommandLine line) throws Exception { } if (line.hasOption(OPTION_DUMP_BATCH)) { - testConnection(line); + testConnection(line, propertiesFile); String arg = line.getOptionValue(OPTION_DUMP_BATCH); dumpBatch(createEngine(propertiesFile), arg); System.exit(0); @@ -446,7 +444,7 @@ protected boolean executeOptions(CommandLine line) throws Exception { } if (line.hasOption(OPTION_TRIGGER_GEN)) { - testConnection(line); + testConnection(line, propertiesFile); String arg = line.getOptionValue(OPTION_TRIGGER_GEN); boolean gen_always = line.hasOption(OPTION_TRIGGER_GEN_ALWAYS); syncTrigger(createEngine(propertiesFile), arg, gen_always); @@ -455,42 +453,42 @@ protected boolean executeOptions(CommandLine line) throws Exception { } if (line.hasOption(OPTION_AUTO_CREATE)) { - testConnection(line); + testConnection(line, propertiesFile); autoCreateDatabase(createEngine(propertiesFile)); System.exit(0); return true; } if (line.hasOption(OPTION_EXPORT_SCHEMA)) { - testConnection(line); + testConnection(line, propertiesFile); exportSchema(createEngine(propertiesFile), line.getOptionValue(OPTION_EXPORT_SCHEMA)); System.exit(0); return true; } if (line.hasOption(OPTION_RUN_DDL_XML)) { - testConnection(line); + testConnection(line, propertiesFile); runDdlXml(createEngine(propertiesFile), line.getOptionValue(OPTION_RUN_DDL_XML)); System.exit(0); return true; } if (line.hasOption(OPTION_RUN_SQL)) { - testConnection(line); + testConnection(line, propertiesFile); runSql(createEngine(propertiesFile), line.getOptionValue(OPTION_RUN_SQL)); System.exit(0); return true; } if (line.hasOption(OPTION_LOAD_BATCH)) { - testConnection(line); + testConnection(line, propertiesFile); loadBatch(createEngine(propertiesFile), line.getOptionValue(OPTION_LOAD_BATCH)); System.exit(0); return true; } if (line.hasOption(OPTION_ENCRYPT_TEXT)) { - testConnection(line); + testConnection(line, propertiesFile); encryptText(createEngine(propertiesFile), line.getOptionValue(OPTION_ENCRYPT_TEXT)); return true; } @@ -527,7 +525,12 @@ protected String chooseWebDir(CommandLine line, String webDir) { } protected ISymmetricEngine createEngine(String propertiesFile) { - return new StandaloneSymmetricEngine(propertiesFile); + File propsFile = new File(propertiesFile); + if (propsFile.exists()) { + return new ClientSymmetricEngine(propsFile); + } else { + throw new SymmetricException(""); + } } protected void addOption(Options options, String opt, String longOpt, boolean hasArg) { @@ -535,16 +538,14 @@ protected void addOption(Options options, String opt, String longOpt, boolean ha } private void dumpBatch(ISymmetricEngine engine, String batchId) throws Exception { - IDataExtractorService dataExtractorService = (IDataExtractorService) engine - .getApplicationContext().getBean(Constants.DATAEXTRACTOR_SERVICE); + IDataExtractorService dataExtractorService = engine.getDataExtractorService(); IOutgoingTransport transport = new InternalOutgoingTransport(System.out); dataExtractorService.extractBatchRange(transport, batchId, batchId); transport.close(); } private void loadBatch(ISymmetricEngine engine, String fileName) throws Exception { - IDataLoaderService service = (IDataLoaderService) engine.getApplicationContext().getBean( - Constants.DATALOADER_SERVICE); + IDataLoaderService service = engine.getDataLoaderService(); File file = new File(fileName); if (file.exists() && file.isFile()) { FileInputStream in = new FileInputStream(file); @@ -558,24 +559,15 @@ private void loadBatch(ISymmetricEngine engine, String fileName) throws Exceptio } private void encryptText(ISymmetricEngine engine, String plainText) { - ISecurityService service = (ISecurityService) engine.getApplicationContext().getBean( - Constants.SECURITY_SERVICE); + ISecurityService service = engine.getSecurityService(); System.out.println(SecurityConstants.PREFIX_ENC + service.encrypt(plainText)); } private void exportSchema(ISymmetricEngine engine, String fileName) { - IDatabasePlatform platform = engine.getDbDialect().getPlatform(); - Connection c = null; - try { - c = engine.getDataSource().getConnection(); - Database db = platform.readDatabase(engine.getDbDialect().getPlatform() - .getDefaultCatalog(), engine.getDbDialect().getPlatform().getDefaultSchema(), - null); - c.close(); - new DatabaseIO().write(db, fileName); - } catch (SQLException ex) { - throw new RuntimeException(ex); - } + IDatabasePlatform platform = engine.getSymmetricDialect().getPlatform(); + Database db = platform.readDatabase(platform.getDefaultCatalog(), + platform.getDefaultSchema(), null); + new DatabaseIO().write(db, fileName); } private void openRegistration(ISymmetricEngine engine, String argument) { @@ -587,14 +579,12 @@ private void openRegistration(ISymmetricEngine engine, String argument) { } String nodeGroupId = argument.substring(0, index).trim(); String externalId = argument.substring(index + 1).trim(); - IRegistrationService registrationService = (IRegistrationService) engine - .getApplicationContext().getBean(Constants.REGISTRATION_SERVICE); + IRegistrationService registrationService = engine.getRegistrationService(); registrationService.openRegistration(nodeGroupId, externalId); } private String reloadNode(ISymmetricEngine engine, String argument) { - IDataService dataService = (IDataService) engine.getApplicationContext().getBean( - Constants.DATA_SERVICE); + IDataService dataService = engine.getDataService(); return dataService.reloadNode(argument); } @@ -605,8 +595,7 @@ private void syncTrigger(ISymmetricEngine engine, String fileName, boolean gen_a if (file.getParentFile() != null) { file.getParentFile().mkdirs(); } - ITriggerRouterService triggerService = AppUtils.find(Constants.TRIGGER_ROUTER_SERVICE, - engine); + ITriggerRouterService triggerService = engine.getTriggerRouterService(); StringBuilder sqlBuffer = new StringBuilder(); triggerService.syncTriggers(sqlBuffer, gen_always); FileUtils.writeStringToFile(file, sqlBuffer.toString(), null); @@ -621,8 +610,7 @@ private void generateDDL(ISymmetricEngine engine, String fileName) throws IOExce file.getParentFile().mkdirs(); } FileWriter os = new FileWriter(file, false); - os.write(((ISymmetricDialect) engine.getApplicationContext().getBean(Constants.DB_DIALECT)) - .getCreateSymmetricDDL()); + os.write(engine.getSymmetricDialect().getCreateSymmetricDDL()); os.close(); } @@ -650,8 +638,7 @@ private void autoCreateDatabase(ISymmetricEngine engine) { } private void runDdlXml(ISymmetricEngine engine, String fileName) throws FileNotFoundException { - ISymmetricDialect dialect = (ISymmetricDialect) engine.getApplicationContext().getBean( - Constants.DB_DIALECT); + ISymmetricDialect dialect = engine.getSymmetricDialect(); File file = new File(fileName); if (file.exists() && file.isFile()) { IDatabasePlatform pf = dialect.getPlatform(); @@ -664,13 +651,12 @@ private void runDdlXml(ISymmetricEngine engine, String fileName) throws FileNotF private void runSql(ISymmetricEngine engine, String fileName) throws FileNotFoundException, MalformedURLException { - ISymmetricDialect dialect = (ISymmetricDialect) engine.getApplicationContext().getBean( - Constants.DB_DIALECT); + ISymmetricDialect dialect = engine.getSymmetricDialect(); File file = new File(fileName); if (file.exists() && file.isFile()) { SqlScript script = new SqlScript(file.toURI().toURL(), dialect.getPlatform() - .getSqlTemplate(), true, SqlScript.QUERY_ENDS, - dialect.getPlatform().getSqlScriptReplacementTokens()); + .getSqlTemplate(), true, SqlScript.QUERY_ENDS, dialect.getPlatform() + .getSqlScriptReplacementTokens()); script.execute(); } else { throw new SymmetricException("FileNotFound", fileName); diff --git a/symmetric/symmetric-server/src/main/java/org/jumpmind/symmetric/SymmetricWebServer.java b/symmetric/symmetric-server/src/main/java/org/jumpmind/symmetric/SymmetricWebServer.java index b96343c621..ea7f766a3d 100644 --- a/symmetric/symmetric-server/src/main/java/org/jumpmind/symmetric/SymmetricWebServer.java +++ b/symmetric/symmetric-server/src/main/java/org/jumpmind/symmetric/SymmetricWebServer.java @@ -52,6 +52,7 @@ import org.jumpmind.symmetric.common.logging.LogFactory; import org.jumpmind.symmetric.util.AppUtils; import org.jumpmind.symmetric.web.ServletUtils; +import org.jumpmind.symmetric.web.SymmetricEngineHolder; /** * Start up SymmetricDS through an embedded Jetty instance. diff --git a/symmetric/symmetric-server/src/main/java/org/jumpmind/symmetric/integrate/XmlPublisherDataRouter.java b/symmetric/symmetric-server/src/main/java/org/jumpmind/symmetric/integrate/XmlPublisherDataRouter.java index c37a6bbd6e..36cbbf9959 100644 --- a/symmetric/symmetric-server/src/main/java/org/jumpmind/symmetric/integrate/XmlPublisherDataRouter.java +++ b/symmetric/symmetric-server/src/main/java/org/jumpmind/symmetric/integrate/XmlPublisherDataRouter.java @@ -62,7 +62,7 @@ public Set routeToNodes(SimpleRouterContext context, DataMetaData dataMe .getTriggerHistory().getParsedPkColumnNames(), dataMetaData.getData() .toParsedPkData()); if (xml != null) { - toXmlElement(dataMetaData.getData().getEventType(), xml, dataMetaData.getData() + toXmlElement(dataMetaData.getData().getDataEventType(), xml, dataMetaData.getData() .getTableName(), dataMetaData.getTriggerHistory().getParsedColumnNames(), dataMetaData.getData().toParsedRowData(), dataMetaData.getTriggerHistory() .getParsedPkColumnNames(), dataMetaData.getData().toParsedPkData()); diff --git a/symmetric/symmetric-server/src/main/java/org/jumpmind/symmetric/web/AbstractCompressionUriHandler.java b/symmetric/symmetric-server/src/main/java/org/jumpmind/symmetric/web/AbstractCompressionUriHandler.java index e3bbd42bb9..08b2420010 100644 --- a/symmetric/symmetric-server/src/main/java/org/jumpmind/symmetric/web/AbstractCompressionUriHandler.java +++ b/symmetric/symmetric-server/src/main/java/org/jumpmind/symmetric/web/AbstractCompressionUriHandler.java @@ -7,11 +7,18 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import org.jumpmind.log.Log; import org.jumpmind.symmetric.common.ParameterConstants; +import org.jumpmind.symmetric.service.IParameterService; import org.jumpmind.symmetric.web.compression.CompressionServletResponseWrapper; abstract public class AbstractCompressionUriHandler extends AbstractUriHandler { + public AbstractCompressionUriHandler(Log log, String uriPattern, + IParameterService parameterService, IInterceptor... interceptors) { + super(log, uriPattern, parameterService, interceptors); + } + final public void handle(HttpServletRequest req, HttpServletResponse res) throws IOException, ServletException { boolean compressionEnabled = !parameterService diff --git a/symmetric/symmetric-server/src/main/java/org/jumpmind/symmetric/web/AbstractUriHandler.java b/symmetric/symmetric-server/src/main/java/org/jumpmind/symmetric/web/AbstractUriHandler.java index f3e4f9596d..4460fe7d04 100644 --- a/symmetric/symmetric-server/src/main/java/org/jumpmind/symmetric/web/AbstractUriHandler.java +++ b/symmetric/symmetric-server/src/main/java/org/jumpmind/symmetric/web/AbstractUriHandler.java @@ -22,10 +22,11 @@ import java.io.IOException; import java.io.OutputStream; +import java.util.ArrayList; import java.util.List; -import org.jumpmind.symmetric.common.logging.ILog; -import org.jumpmind.symmetric.common.logging.LogFactory; +import org.jumpmind.log.Log; +import org.jumpmind.log.LogFactory; import org.jumpmind.symmetric.model.ChannelMap; import org.jumpmind.symmetric.service.IParameterService; import org.jumpmind.symmetric.transport.IOutgoingTransport; @@ -33,7 +34,7 @@ abstract public class AbstractUriHandler implements IUriHandler { - protected ILog log = LogFactory.getLog(getClass()); + protected Log log = LogFactory.getLog(getClass()); private String uriPattern; @@ -42,6 +43,17 @@ abstract public class AbstractUriHandler implements IUriHandler { protected IParameterService parameterService; private boolean enabled = true; + + public AbstractUriHandler(Log log, String uriPattern, + IParameterService parameterService, IInterceptor... interceptors) { + this.log = log; + this.uriPattern = uriPattern; + this.interceptors = new ArrayList(interceptors.length); + for (IInterceptor i : interceptors) { + this.interceptors.add(i); + } + this.parameterService = parameterService; + } public void setUriPattern(String uriPattern) { this.uriPattern = uriPattern; @@ -77,6 +89,5 @@ public boolean isEnabled() { public void setParameterService(IParameterService parameterService) { this.parameterService = parameterService; - this.log = LogFactory.getLog(parameterService); } } diff --git a/symmetric/symmetric-server/src/main/java/org/jumpmind/symmetric/web/AckUriHandler.java b/symmetric/symmetric-server/src/main/java/org/jumpmind/symmetric/web/AckUriHandler.java index 9a04294218..f7a10018aa 100644 --- a/symmetric/symmetric-server/src/main/java/org/jumpmind/symmetric/web/AckUriHandler.java +++ b/symmetric/symmetric-server/src/main/java/org/jumpmind/symmetric/web/AckUriHandler.java @@ -29,8 +29,10 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import org.jumpmind.log.Log; import org.jumpmind.symmetric.model.BatchInfo; import org.jumpmind.symmetric.service.IAcknowledgeService; +import org.jumpmind.symmetric.service.IParameterService; import org.jumpmind.symmetric.transport.AbstractTransportManager; public class AckUriHandler extends AbstractUriHandler { @@ -44,6 +46,12 @@ public int compare(BatchInfo batchInfo1, BatchInfo batchInfo2) { }; private IAcknowledgeService acknowledgeService; + + public AckUriHandler(Log log, + IParameterService parameterService, IAcknowledgeService acknowledgeService, IInterceptor...interceptors) { + super(log, "/ack/*", parameterService, interceptors); + this.acknowledgeService = acknowledgeService; + } public void handle(HttpServletRequest req, HttpServletResponse res) throws IOException, ServletException { @@ -63,8 +71,4 @@ protected void ack(List batches) throws IOException { } } - public void setAcknowledgeService(IAcknowledgeService acknowledgeService) { - this.acknowledgeService = acknowledgeService; - } - } diff --git a/symmetric/symmetric-server/src/main/java/org/jumpmind/symmetric/web/AuthenticationInterceptor.java b/symmetric/symmetric-server/src/main/java/org/jumpmind/symmetric/web/AuthenticationInterceptor.java index 29add6ed81..782bdba1ef 100644 --- a/symmetric/symmetric-server/src/main/java/org/jumpmind/symmetric/web/AuthenticationInterceptor.java +++ b/symmetric/symmetric-server/src/main/java/org/jumpmind/symmetric/web/AuthenticationInterceptor.java @@ -41,6 +41,10 @@ public enum AuthenticationStatus { }; private INodeService nodeService; + + public AuthenticationInterceptor(INodeService nodeService) { + this.nodeService = nodeService; + } public boolean before(HttpServletRequest req, HttpServletResponse resp) throws IOException, ServletException { @@ -84,10 +88,6 @@ protected AuthenticationStatus getAuthenticationStatus(String nodeId, String sec return retVal; } - public void setNodeService(INodeService nodeService) { - this.nodeService = nodeService; - } - protected boolean syncEnabled(String nodeId) { boolean syncEnabled = false; Node node = nodeService.findNode(nodeId); diff --git a/symmetric/symmetric-server/src/main/java/org/jumpmind/symmetric/web/BandwidthSamplerUriHandler.java b/symmetric/symmetric-server/src/main/java/org/jumpmind/symmetric/web/BandwidthSamplerUriHandler.java index 5f288b2de5..25dba2174e 100644 --- a/symmetric/symmetric-server/src/main/java/org/jumpmind/symmetric/web/BandwidthSamplerUriHandler.java +++ b/symmetric/symmetric-server/src/main/java/org/jumpmind/symmetric/web/BandwidthSamplerUriHandler.java @@ -27,7 +27,9 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import org.jumpmind.log.Log; import org.jumpmind.symmetric.service.IBandwidthService; +import org.jumpmind.symmetric.service.IParameterService; import org.jumpmind.symmetric.util.AppUtils; /** @@ -42,6 +44,10 @@ public class BandwidthSamplerUriHandler extends AbstractUriHandler { protected long defaultTestSlowBandwidthDelay = 0; + public BandwidthSamplerUriHandler(Log log, IParameterService parameterService) { + super(log, "/bandwidth/*", parameterService); + } + public void handle(HttpServletRequest req, HttpServletResponse res) throws IOException, ServletException { long testSlowBandwidthDelay = parameterService != null ? parameterService diff --git a/symmetric/symmetric-server/src/main/java/org/jumpmind/symmetric/web/BatchUriHandler.java b/symmetric/symmetric-server/src/main/java/org/jumpmind/symmetric/web/BatchUriHandler.java index ac30e26c3e..2dbe222432 100644 --- a/symmetric/symmetric-server/src/main/java/org/jumpmind/symmetric/web/BatchUriHandler.java +++ b/symmetric/symmetric-server/src/main/java/org/jumpmind/symmetric/web/BatchUriHandler.java @@ -27,13 +27,21 @@ import javax.servlet.http.HttpServletResponse; import org.apache.commons.lang.StringUtils; +import org.jumpmind.log.Log; import org.jumpmind.symmetric.service.IDataExtractorService; +import org.jumpmind.symmetric.service.IParameterService; import org.jumpmind.symmetric.transport.IOutgoingTransport; public class BatchUriHandler extends AbstractCompressionUriHandler { private IDataExtractorService dataExtractorService; + public BatchUriHandler(Log log, IParameterService parameterService, + IDataExtractorService dataExtractorService) { + super(log, "/batch/*", parameterService); + this.dataExtractorService = dataExtractorService; + } + public void handleWithCompression(HttpServletRequest req, HttpServletResponse res) throws IOException, ServletException { res.setContentType("text/plain"); diff --git a/symmetric/symmetric-server/src/main/java/org/jumpmind/symmetric/web/InfoUriHandler.java b/symmetric/symmetric-server/src/main/java/org/jumpmind/symmetric/web/InfoUriHandler.java index 21db0677e5..13afa77075 100644 --- a/symmetric/symmetric-server/src/main/java/org/jumpmind/symmetric/web/InfoUriHandler.java +++ b/symmetric/symmetric-server/src/main/java/org/jumpmind/symmetric/web/InfoUriHandler.java @@ -28,12 +28,14 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import org.jumpmind.log.Log; import org.jumpmind.symmetric.common.InfoConstants; import org.jumpmind.symmetric.common.ParameterConstants; import org.jumpmind.symmetric.model.Node; import org.jumpmind.symmetric.model.NodeGroup; import org.jumpmind.symmetric.service.IConfigurationService; import org.jumpmind.symmetric.service.INodeService; +import org.jumpmind.symmetric.service.IParameterService; /** * Responsible for providing high level information about the node in property @@ -46,6 +48,14 @@ public class InfoUriHandler extends AbstractUriHandler { private INodeService nodeService; private IConfigurationService configurationService; + + public InfoUriHandler(Log log, IParameterService parameterService, + INodeService nodeService, + IConfigurationService configurationService) { + super(log, "/info/*", parameterService); + this.nodeService = nodeService; + this.configurationService = configurationService; + } public void handle(HttpServletRequest req, HttpServletResponse res) throws IOException, ServletException { @@ -78,12 +88,4 @@ public void handle(HttpServletRequest req, HttpServletResponse res) throws IOExc res.flushBuffer(); } - public void setNodeService(INodeService nodeService) { - this.nodeService = nodeService; - } - - public void setConfigurationService(IConfigurationService configurationService) { - this.configurationService = configurationService; - } - } \ No newline at end of file diff --git a/symmetric/symmetric-server/src/main/java/org/jumpmind/symmetric/web/NodeConcurrencyInterceptor.java b/symmetric/symmetric-server/src/main/java/org/jumpmind/symmetric/web/NodeConcurrencyInterceptor.java index b264f7c37a..4e5c6635d2 100644 --- a/symmetric/symmetric-server/src/main/java/org/jumpmind/symmetric/web/NodeConcurrencyInterceptor.java +++ b/symmetric/symmetric-server/src/main/java/org/jumpmind/symmetric/web/NodeConcurrencyInterceptor.java @@ -45,6 +45,13 @@ public class NodeConcurrencyInterceptor implements IInterceptor { private IConfigurationService configurationService; private IStatisticManager statisticManager; + + public NodeConcurrencyInterceptor(IConcurrentConnectionManager concurrentConnectionManager, + IConfigurationService configurationService, IStatisticManager statisticManager) { + this.concurrentConnectionManager = concurrentConnectionManager; + this.configurationService = configurationService; + this.statisticManager = statisticManager; + } public boolean before(HttpServletRequest req, HttpServletResponse resp) throws IOException, ServletException { @@ -104,16 +111,4 @@ protected void buildSuspendIgnoreResponseHeaders(final String nodeId, final Serv suspendIgnoreChannels.getIgnoreChannelsAsString()); } - public void setConcurrentConnectionManager( - IConcurrentConnectionManager concurrentConnectionManager) { - this.concurrentConnectionManager = concurrentConnectionManager; - } - - public void setConfigurationService(IConfigurationService configurationService) { - this.configurationService = configurationService; - } - - public void setStatisticManager(IStatisticManager statisticManager) { - this.statisticManager = statisticManager; - } } \ No newline at end of file diff --git a/symmetric/symmetric-server/src/main/java/org/jumpmind/symmetric/web/PingUriHandler.java b/symmetric/symmetric-server/src/main/java/org/jumpmind/symmetric/web/PingUriHandler.java index 7b3d27e81d..f4ccbee528 100644 --- a/symmetric/symmetric-server/src/main/java/org/jumpmind/symmetric/web/PingUriHandler.java +++ b/symmetric/symmetric-server/src/main/java/org/jumpmind/symmetric/web/PingUriHandler.java @@ -26,12 +26,19 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import org.jumpmind.log.Log; +import org.jumpmind.symmetric.service.IParameterService; + /** * Simple handler that returns a 200 to indicate that SymmetricDS is deployed * and running. */ public class PingUriHandler extends AbstractUriHandler { + public PingUriHandler(Log log, IParameterService parameterService) { + super(log, "/ping/*", parameterService); + } + public void handle(HttpServletRequest req, HttpServletResponse res) throws IOException, ServletException { } diff --git a/symmetric/symmetric-server/src/main/java/org/jumpmind/symmetric/web/PullUriHandler.java b/symmetric/symmetric-server/src/main/java/org/jumpmind/symmetric/web/PullUriHandler.java index 71cec2b7d8..47af4871ca 100644 --- a/symmetric/symmetric-server/src/main/java/org/jumpmind/symmetric/web/PullUriHandler.java +++ b/symmetric/symmetric-server/src/main/java/org/jumpmind/symmetric/web/PullUriHandler.java @@ -27,11 +27,13 @@ import javax.servlet.http.HttpServletResponse; import org.apache.commons.lang.StringUtils; +import org.jumpmind.log.Log; import org.jumpmind.symmetric.model.ChannelMap; import org.jumpmind.symmetric.model.NodeSecurity; import org.jumpmind.symmetric.service.IConfigurationService; import org.jumpmind.symmetric.service.IDataExtractorService; import org.jumpmind.symmetric.service.INodeService; +import org.jumpmind.symmetric.service.IParameterService; import org.jumpmind.symmetric.service.IRegistrationService; import org.jumpmind.symmetric.statistic.IStatisticManager; import org.jumpmind.symmetric.transport.IOutgoingTransport; @@ -50,6 +52,19 @@ public class PullUriHandler extends AbstractCompressionUriHandler { private IRegistrationService registrationService; private IStatisticManager statisticManager; + + public PullUriHandler(Log log, IParameterService parameterService, + INodeService nodeService, + IConfigurationService configurationService, IDataExtractorService dataExtractorService, + IRegistrationService registrationService, IStatisticManager statisticManager, IInterceptor... interceptors) { + super(log, "/pull/*", parameterService, interceptors); + this.nodeService = nodeService; + this.configurationService = configurationService; + this.dataExtractorService = dataExtractorService; + this.registrationService = registrationService; + this.statisticManager = statisticManager; + } + public void handleWithCompression(HttpServletRequest req, HttpServletResponse res) throws IOException, ServletException { diff --git a/symmetric/symmetric-server/src/main/java/org/jumpmind/symmetric/web/PushUriHandler.java b/symmetric/symmetric-server/src/main/java/org/jumpmind/symmetric/web/PushUriHandler.java index 14f6a51436..adc851854d 100644 --- a/symmetric/symmetric-server/src/main/java/org/jumpmind/symmetric/web/PushUriHandler.java +++ b/symmetric/symmetric-server/src/main/java/org/jumpmind/symmetric/web/PushUriHandler.java @@ -29,7 +29,9 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import org.jumpmind.log.Log; import org.jumpmind.symmetric.service.IDataLoaderService; +import org.jumpmind.symmetric.service.IParameterService; import org.jumpmind.symmetric.statistic.IStatisticManager; /** @@ -40,6 +42,14 @@ public class PushUriHandler extends AbstractUriHandler { private IDataLoaderService dataLoaderService; private IStatisticManager statisticManager; + + public PushUriHandler(Log log, IParameterService parameterService, IDataLoaderService dataLoaderService, + IStatisticManager statisticManager, + IInterceptor... interceptors) { + super(log, "/push/*", parameterService, interceptors); + this.dataLoaderService = dataLoaderService; + this.statisticManager = statisticManager; + } public void handle(HttpServletRequest req, HttpServletResponse res) throws IOException, ServletException { @@ -61,7 +71,7 @@ public void handle(HttpServletRequest req, HttpServletResponse res) throws IOExc protected void push(String sourceNodeId, InputStream inputStream, OutputStream outputStream) throws IOException { long ts = System.currentTimeMillis(); try { - getDataLoaderService().loadDataFromPush(sourceNodeId, inputStream, outputStream); + dataLoaderService.loadDataFromPush(sourceNodeId, inputStream, outputStream); } finally { statisticManager.incrementNodesPushed(1); statisticManager.incrementTotalNodesPushedTime(System.currentTimeMillis() - ts); @@ -78,17 +88,5 @@ protected InputStream createInputStream(HttpServletRequest req) throws IOExcepti } return is; } - - private IDataLoaderService getDataLoaderService() { - return dataLoaderService; - } - - public void setDataLoaderService(IDataLoaderService dataLoaderService) { - this.dataLoaderService = dataLoaderService; - } - - public void setStatisticManager(IStatisticManager statisticManager) { - this.statisticManager = statisticManager; - } - + } \ No newline at end of file diff --git a/symmetric/symmetric-server/src/main/java/org/jumpmind/symmetric/web/RegistrationUriHandler.java b/symmetric/symmetric-server/src/main/java/org/jumpmind/symmetric/web/RegistrationUriHandler.java index 5d25fbb62c..4cb415854e 100644 --- a/symmetric/symmetric-server/src/main/java/org/jumpmind/symmetric/web/RegistrationUriHandler.java +++ b/symmetric/symmetric-server/src/main/java/org/jumpmind/symmetric/web/RegistrationUriHandler.java @@ -28,7 +28,9 @@ import javax.servlet.http.HttpServletResponse; import org.apache.commons.lang.StringUtils; +import org.jumpmind.log.Log; import org.jumpmind.symmetric.model.Node; +import org.jumpmind.symmetric.service.IParameterService; import org.jumpmind.symmetric.service.IRegistrationService; import org.jumpmind.symmetric.service.RegistrationRedirectException; import org.jumpmind.symmetric.transport.http.HttpTransportManager; @@ -40,6 +42,14 @@ public class RegistrationUriHandler extends AbstractUriHandler { private IRegistrationService registrationService; + + + public RegistrationUriHandler(Log log, IParameterService parameterService, + IRegistrationService registrationService, IInterceptor... interceptors) { + super(log, "/registration/*", parameterService, interceptors); + this.registrationService = registrationService; + } + public void handle(HttpServletRequest req, HttpServletResponse res) throws IOException, ServletException { Node node = transform(req); @@ -71,15 +81,7 @@ private Node transform(HttpServletRequest req) { } protected boolean registerNode(Node node, String remoteHost, String remoteAddress, OutputStream outputStream) throws IOException { - return getRegistrationService().registerNode(node, remoteHost, remoteAddress, outputStream, true); - } - - private IRegistrationService getRegistrationService() { - return registrationService; - } - - public void setRegistrationService(IRegistrationService registrationService) { - this.registrationService = registrationService; + return registrationService.registerNode(node, remoteHost, remoteAddress, outputStream, true); } } \ No newline at end of file diff --git a/symmetric/symmetric-server/src/main/java/org/jumpmind/symmetric/web/ServerSymmetricEngine.java b/symmetric/symmetric-server/src/main/java/org/jumpmind/symmetric/web/ServerSymmetricEngine.java new file mode 100644 index 0000000000..4de72dedbf --- /dev/null +++ b/symmetric/symmetric-server/src/main/java/org/jumpmind/symmetric/web/ServerSymmetricEngine.java @@ -0,0 +1,49 @@ +package org.jumpmind.symmetric.web; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; + +import org.jumpmind.symmetric.ClientSymmetricEngine; +import org.jumpmind.symmetric.common.ParameterConstants; + +public class ServerSymmetricEngine extends ClientSymmetricEngine { + + protected List uriHandlers; + + public ServerSymmetricEngine(File propertiesFile) { + super(propertiesFile); + } + + @Override + protected void init() { + super.init(); + + AuthenticationInterceptor authInterceptor = new AuthenticationInterceptor(nodeService); + NodeConcurrencyInterceptor concurrencyInterceptor = new NodeConcurrencyInterceptor( + concurrentConnectionManager, configurationService, statisticManager); + + this.uriHandlers = new ArrayList(); + this.uriHandlers.add(new AckUriHandler(log, parameterService, acknowledgeService, + authInterceptor)); + this.uriHandlers.add(new PingUriHandler(log, parameterService)); + this.uriHandlers.add(new InfoUriHandler(log, parameterService, nodeService, + configurationService)); + this.uriHandlers.add(new BandwidthSamplerUriHandler(log, parameterService)); + this.uriHandlers.add(new PullUriHandler(log, parameterService, nodeService, + configurationService, dataExtractorService, registrationService, statisticManager, + concurrencyInterceptor, authInterceptor)); + this.uriHandlers.add(new PushUriHandler(log, parameterService, dataLoaderService, + statisticManager, concurrencyInterceptor, authInterceptor)); + this.uriHandlers.add(new RegistrationUriHandler(log, parameterService, registrationService, + concurrencyInterceptor)); + if (parameterService.is(ParameterConstants.WEB_BATCH_URI_HANDLER_ENABLE)) { + this.uriHandlers.add(new BatchUriHandler(log, parameterService, dataExtractorService)); + } + } + + public List getUriHandlers() { + return uriHandlers; + } + +} diff --git a/symmetric/symmetric-server/src/main/java/org/jumpmind/symmetric/web/ServletUtils.java b/symmetric/symmetric-server/src/main/java/org/jumpmind/symmetric/web/ServletUtils.java index 29afdba46f..be2b9289a0 100644 --- a/symmetric/symmetric-server/src/main/java/org/jumpmind/symmetric/web/ServletUtils.java +++ b/symmetric/symmetric-server/src/main/java/org/jumpmind/symmetric/web/ServletUtils.java @@ -29,18 +29,12 @@ import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.math.NumberUtils; -import org.jumpmind.symmetric.ISymmetricEngine; -import org.jumpmind.symmetric.StandaloneSymmetricEngine; -import org.jumpmind.symmetric.SymmetricEngineHolder; -import org.jumpmind.symmetric.common.Constants; -import org.jumpmind.symmetric.service.IParameterService; -import org.springframework.context.ApplicationContext; -import org.springframework.web.context.support.WebApplicationContextUtils; /** * Utility methods for working with {@link Servlet}s */ -public class ServletUtils { +public class ServletUtils { + /** * Because you can't send an error when the response is already committed, * this helps to avoid unnecessary errors in the logs. @@ -106,28 +100,6 @@ public static boolean sendError(final ServletResponse resp, final int statusCode retVal = sendError((HttpServletResponse) resp, statusCode, message); } return retVal; - } - - /** - * Search in several places for an {@link ApplicationContext} that contains - * SymmetricDS services. This method uses existence of - * {@link IParameterService} in the context as a clue as to if the context - * contains SymmetricDS artifacts. - */ - public static ApplicationContext getApplicationContext(ServletContext servletContext) { - ApplicationContext ctx = WebApplicationContextUtils.getWebApplicationContext(servletContext); - if (!(ctx.containsBean(Constants.PARAMETER_SERVICE) && ctx.getBean(Constants.PARAMETER_SERVICE) instanceof IParameterService)) { - ISymmetricEngine engine = null; - if (ctx != null && ctx.containsBean(Constants.SYMMETRIC_ENGINE)) { - engine = (ISymmetricEngine) ctx.getBean(Constants.SYMMETRIC_ENGINE); - } else { - engine = StandaloneSymmetricEngine.getEngine(); - } - if (engine != null) { - ctx = engine.getApplicationContext(); - } - } - return ctx; } /** diff --git a/symmetric/symmetric-server/src/main/java/org/jumpmind/symmetric/web/SymmetricContextListener.java b/symmetric/symmetric-server/src/main/java/org/jumpmind/symmetric/web/SymmetricContextListener.java index 6a07534e91..be0704fec5 100644 --- a/symmetric/symmetric-server/src/main/java/org/jumpmind/symmetric/web/SymmetricContextListener.java +++ b/symmetric/symmetric-server/src/main/java/org/jumpmind/symmetric/web/SymmetricContextListener.java @@ -24,7 +24,6 @@ import javax.servlet.ServletContextEvent; import javax.servlet.ServletContextListener; -import org.jumpmind.symmetric.SymmetricEngineHolder; public class SymmetricContextListener implements ServletContextListener { diff --git a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/SymmetricEngineHolder.java b/symmetric/symmetric-server/src/main/java/org/jumpmind/symmetric/web/SymmetricEngineHolder.java similarity index 93% rename from symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/SymmetricEngineHolder.java rename to symmetric/symmetric-server/src/main/java/org/jumpmind/symmetric/web/SymmetricEngineHolder.java index 8269f74f54..9b1ed9365d 100644 --- a/symmetric/symmetric-core/src/main/java/org/jumpmind/symmetric/SymmetricEngineHolder.java +++ b/symmetric/symmetric-server/src/main/java/org/jumpmind/symmetric/web/SymmetricEngineHolder.java @@ -18,7 +18,7 @@ * specific language governing permissions and limitations * under the License. */ -package org.jumpmind.symmetric; +package org.jumpmind.symmetric.web; import java.io.File; import java.io.FileOutputStream; @@ -32,6 +32,7 @@ import org.apache.commons.io.IOUtils; import org.apache.commons.lang.StringUtils; +import org.jumpmind.symmetric.ISymmetricEngine; import org.jumpmind.symmetric.common.Constants; import org.jumpmind.symmetric.common.ParameterConstants; import org.jumpmind.symmetric.common.logging.ILog; @@ -42,13 +43,13 @@ public class SymmetricEngineHolder { final ILog log = LogFactory.getLog(getClass()); - private Map engines = new HashMap(); + private Map engines = new HashMap(); private Set enginesStarting = new HashSet(); private boolean multiServerMode = false; - public Map getEngines() { + public Map getEngines() { return engines; } @@ -100,13 +101,9 @@ public void start() { } protected ISymmetricEngine create(String propertiesFile) { - ISymmetricEngine engine = null; + ServerSymmetricEngine engine = null; try { - final String filePrefix = "file:///"; - if (StringUtils.isNotBlank(propertiesFile) && !propertiesFile.startsWith(filePrefix)) { - propertiesFile = filePrefix + propertiesFile; - } - engine = new StandaloneSymmetricEngine(null, propertiesFile); + engine = new ServerSymmetricEngine(new File(propertiesFile)); if (engine != null) { if (!engines.containsKey(engine.getEngineName())) { engines.put(engine.getEngineName(), engine); @@ -147,7 +144,7 @@ public ISymmetricEngine install(Properties properties) throws Exception { String registrationUrl = properties.getProperty(ParameterConstants.REGISTRATION_URL); if (StringUtils.isNotBlank(registrationUrl)) { - Collection servers = getEngines().values(); + Collection servers = getEngines().values(); for (ISymmetricEngine symmetricWebServer : servers) { if (symmetricWebServer.getParameterService().getSyncUrl().equals(registrationUrl)) { String nodeGroupId = properties.getProperty(ParameterConstants.NODE_GROUP_ID); diff --git a/symmetric/symmetric-server/src/main/java/org/jumpmind/symmetric/web/SymmetricServlet.java b/symmetric/symmetric-server/src/main/java/org/jumpmind/symmetric/web/SymmetricServlet.java index 00ff031ee7..39340f9e3c 100644 --- a/symmetric/symmetric-server/src/main/java/org/jumpmind/symmetric/web/SymmetricServlet.java +++ b/symmetric/symmetric-server/src/main/java/org/jumpmind/symmetric/web/SymmetricServlet.java @@ -32,7 +32,6 @@ import org.apache.commons.lang.StringUtils; import org.jumpmind.symmetric.ISymmetricEngine; -import org.jumpmind.symmetric.SymmetricEngineHolder; import org.jumpmind.symmetric.common.logging.ILog; import org.jumpmind.symmetric.common.logging.LogFactory; @@ -67,7 +66,7 @@ public class SymmetricServlet extends HttpServlet { protected void service(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException { String method = req.getMethod(); - ISymmetricEngine engine = findEngine(req); + ServerSymmetricEngine engine = findEngine(req); IUriHandler handler = findMatchingHandler(engine, req); if (handler != null) { List interceptors = handler.getInterceptors(); @@ -104,9 +103,9 @@ protected void service(HttpServletRequest req, HttpServletResponse res) } } - protected ISymmetricEngine findEngine(HttpServletRequest req) { + protected ServerSymmetricEngine findEngine(HttpServletRequest req) { String engineName = getEngineNameFromUrl((HttpServletRequest) req); - ISymmetricEngine engine = null; + ServerSymmetricEngine engine = null; SymmetricEngineHolder holder = ServletUtils.getSymmetricEngineHolder(getServletContext()); if (holder != null) { if (engineName != null) { @@ -131,15 +130,15 @@ protected static String getEngineNameFromUrl(HttpServletRequest req) { return engineName; } - protected Collection getUriHandlersFrom(ISymmetricEngine engine) { + protected Collection getUriHandlersFrom(ServerSymmetricEngine engine) { if (engine != null) { - return engine.getApplicationContext().getBeansOfType(IUriHandler.class).values(); + return engine.getUriHandlers(); } else { return null; } } - protected IUriHandler findMatchingHandler(ISymmetricEngine engine, HttpServletRequest req) + protected IUriHandler findMatchingHandler(ServerSymmetricEngine engine, HttpServletRequest req) throws ServletException { Collection handlers = getUriHandlersFrom(engine); if (handlers != null) { diff --git a/symmetric/symmetric-server/src/main/resources/symmetric-server.xml b/symmetric/symmetric-server/src/main/resources/symmetric-server.xml deleted file mode 100644 index 29fe191239..0000000000 --- a/symmetric/symmetric-server/src/main/resources/symmetric-server.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - \ No newline at end of file diff --git a/symmetric/symmetric-server/src/main/resources/symmetric-web.xml b/symmetric/symmetric-server/src/main/resources/symmetric-web.xml deleted file mode 100644 index 80dd6501af..0000000000 --- a/symmetric/symmetric-server/src/main/resources/symmetric-web.xml +++ /dev/null @@ -1,91 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/symmetric/symmetric-server/src/test/java/org/jumpmind/symmetric/io/ThresholdFileWriterUnitTest.java b/symmetric/symmetric-server/src/test/java/org/jumpmind/symmetric/io/ThresholdFileWriterUnitTest.java deleted file mode 100644 index f46214bf55..0000000000 --- a/symmetric/symmetric-server/src/test/java/org/jumpmind/symmetric/io/ThresholdFileWriterUnitTest.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Licensed to JumpMind Inc under one or more contributor - * license agreements. See the NOTICE file distributed - * with this work for additional information regarding - * copyright ownership. JumpMind Inc licenses this file - * to you under the GNU Lesser General Public License (the - * "License"); you may not use this file except in compliance - * with the License. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see - * . - * - * 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.jumpmind.symmetric.io; - -import java.io.File; - -import org.apache.commons.io.IOUtils; -import org.junit.Assert; -import org.junit.Test; - -public class ThresholdFileWriterUnitTest { - - final String TEST_STR = "The quick brown fox jumped over the lazy dog"; - - @Test - public void testNoWriteToFile() throws Exception { - File file = getTestFile(); - ThresholdFileWriter writer = new ThresholdFileWriter(TEST_STR.length() + 1, file); - writer.write(TEST_STR); - Assert.assertFalse(file.exists()); - Assert.assertEquals(TEST_STR, IOUtils.toString(writer.getReader())); - file.delete(); - } - - @Test - public void testWriteToFile() throws Exception { - File file = getTestFile(); - ThresholdFileWriter writer = new ThresholdFileWriter(TEST_STR.length() - 1, file); - writer.write(TEST_STR); - Assert.assertTrue(file.exists()); - Assert.assertEquals(TEST_STR, IOUtils.toString(writer.getReader())); - file.delete(); - } - - private File getTestFile() { - File file = new File("target/test/buffered.file.writer.tst"); - file.getParentFile().mkdirs(); - file.delete(); - return file; - } -} \ No newline at end of file diff --git a/symmetric/symmetric-server/src/test/java/org/jumpmind/symmetric/route/DataRefRouteReaderUnitTest.java b/symmetric/symmetric-server/src/test/java/org/jumpmind/symmetric/route/DataRefRouteReaderUnitTest.java deleted file mode 100644 index e887faf45b..0000000000 --- a/symmetric/symmetric-server/src/test/java/org/jumpmind/symmetric/route/DataRefRouteReaderUnitTest.java +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Licensed to JumpMind Inc under one or more contributor - * license agreements. See the NOTICE file distributed - * with this work for additional information regarding - * copyright ownership. JumpMind Inc licenses this file - * to you under the GNU Lesser General Public License (the - * "License"); you may not use this file except in compliance - * with the License. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see - * . - * - * 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.jumpmind.symmetric.route; - -import org.jumpmind.symmetric.common.logging.ILog; -import org.jumpmind.symmetric.common.logging.LogFactory; -import org.jumpmind.symmetric.model.Channel; -import org.jumpmind.symmetric.service.ISqlProvider; -import org.jumpmind.symmetric.service.impl.RouterServiceSqlMap; -import org.junit.Assert; -import org.junit.Test; - -public class DataRefRouteReaderUnitTest { - - protected ILog log = LogFactory.getLog(getClass()); - - private static final String BLANK = "''"; - - RouterServiceSqlMap sql = new RouterServiceSqlMap(null, null); - - @Test - public void testOldDataReplacement() { - DataRefRouteReader reader = new DataRefRouteReader(log, getSqlProvider(), null, null); - Channel channel = new Channel(); - Assert.assertTrue(reader.getSql(DataRefRouteReader.SELECT_DATA_TO_BATCH_SQL, channel) - .contains("old_data")); - Assert.assertFalse(reader.getSql(DataRefRouteReader.SELECT_DATA_TO_BATCH_SQL, channel) - .contains(BLANK)); - channel.setUseOldDataToRoute(false); - Assert.assertFalse(reader.getSql(DataRefRouteReader.SELECT_DATA_TO_BATCH_SQL, channel) - .contains("old_data")); - Assert.assertTrue(reader.getSql(DataRefRouteReader.SELECT_DATA_TO_BATCH_SQL, channel) - .contains(BLANK)); - } - - @Test - public void testRowDataReplacement() { - DataRefRouteReader reader = new DataRefRouteReader(log, getSqlProvider(), null, null); - Channel channel = new Channel(); - Assert.assertTrue(reader.getSql(DataRefRouteReader.SELECT_DATA_TO_BATCH_SQL, channel) - .contains("row_data")); - Assert.assertFalse(reader.getSql(DataRefRouteReader.SELECT_DATA_TO_BATCH_SQL, channel) - .contains(BLANK)); - channel.setUseRowDataToRoute(false); - Assert.assertFalse(reader.getSql(DataRefRouteReader.SELECT_DATA_TO_BATCH_SQL, channel) - .contains("row_data")); - Assert.assertTrue(reader.getSql(DataRefRouteReader.SELECT_DATA_TO_BATCH_SQL, channel) - .contains(BLANK)); - } - - @Test - public void testOldAndRowDataReplacement() { - DataRefRouteReader reader = new DataRefRouteReader(log, getSqlProvider(), null, null); - Channel channel = new Channel(); - Assert.assertTrue(reader.getSql(DataRefRouteReader.SELECT_DATA_TO_BATCH_SQL, channel) - .contains("row_data")); - Assert.assertTrue(reader.getSql(DataRefRouteReader.SELECT_DATA_TO_BATCH_SQL, channel) - .contains("old_data")); - Assert.assertFalse(reader.getSql(DataRefRouteReader.SELECT_DATA_TO_BATCH_SQL, channel) - .contains(BLANK)); - channel.setUseRowDataToRoute(false); - channel.setUseOldDataToRoute(false); - Assert.assertFalse(reader.getSql(DataRefRouteReader.SELECT_DATA_TO_BATCH_SQL, channel) - .contains("row_data")); - Assert.assertFalse(reader.getSql(DataRefRouteReader.SELECT_DATA_TO_BATCH_SQL, channel) - .contains("old_data")); - Assert.assertTrue(reader.getSql(DataRefRouteReader.SELECT_DATA_TO_BATCH_SQL, channel) - .contains(BLANK)); - } - - private ISqlProvider getSqlProvider() { - return new ISqlProvider() { - public String getSql(String... keys) { - return sql.getSql(keys[0]); - } - }; - } - -} \ No newline at end of file diff --git a/symmetric/symmetric-server/src/test/java/org/jumpmind/symmetric/stress/AbstractMultiTierStressTest.java b/symmetric/symmetric-server/src/test/java/org/jumpmind/symmetric/stress/AbstractMultiTierStressTest.java deleted file mode 100644 index 84d41c1980..0000000000 --- a/symmetric/symmetric-server/src/test/java/org/jumpmind/symmetric/stress/AbstractMultiTierStressTest.java +++ /dev/null @@ -1,227 +0,0 @@ -/* - * Licensed to JumpMind Inc under one or more contributor - * license agreements. See the NOTICE file distributed - * with this work for additional information regarding - * copyright ownership. JumpMind Inc licenses this file - * to you under the GNU Lesser General Public License (the - * "License"); you may not use this file except in compliance - * with the License. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see - * . - * - * 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.jumpmind.symmetric.stress; - -import java.util.Map; - -import javax.annotation.Resource; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.jumpmind.symmetric.SymmetricWebServer; -import org.jumpmind.symmetric.common.Constants; -import org.jumpmind.symmetric.common.ParameterConstants; -import org.jumpmind.symmetric.model.Node; -import org.jumpmind.symmetric.model.NodeSecurity; -import org.jumpmind.symmetric.service.INodeService; -import org.jumpmind.symmetric.service.IOutgoingBatchService; -import org.jumpmind.symmetric.service.IParameterService; -import org.jumpmind.symmetric.test.MultiTierTestConstants; -import org.jumpmind.symmetric.util.AppUtils; -import org.junit.Assert; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.springframework.jdbc.core.JdbcTemplate; -import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; - -@RunWith(SpringJUnit4ClassRunner.class) -abstract public class AbstractMultiTierStressTest { - - final static Log logger = LogFactory - .getLog(AbstractMultiTierStressTest.class); - - @Resource - protected SymmetricWebServer homeServer; - - @Resource - protected SymmetricWebServer regionServer; - - @Resource - protected SymmetricWebServer workstation000101; - - @Resource - protected SymmetricWebServer workstation000102; - - @Resource - protected Map unitTestSql; - - @Test(timeout = 120000) - public void validateHomeServerStartup() { - INodeService nodeService = AppUtils.find(Constants.NODE_SERVICE, - homeServer.getEngine()); - Node node = nodeService.findIdentity(); - Assert.assertNotNull(node); - Assert.assertEquals(node.getNodeId(), - MultiTierTestConstants.NODE_ID_HOME); - } - - @Test(timeout = 120000) - public void registerAndLoadRegion() { - registerAndLoad(homeServer, MultiTierTestConstants.NODE_ID_REGION_1, - regionServer, MultiTierTestConstants.NODE_GROUP_REGION, false, - false, true); - } - - @Test(timeout = 120000) - public void registerAndLoadWorkstations() { - registerAndLoad(regionServer, - MultiTierTestConstants.NODE_ID_STORE_0001_WORKSTATION_001, - workstation000101, - MultiTierTestConstants.NODE_GROUP_WORKSTATION, true, true, true); - registerAndLoad(regionServer, - MultiTierTestConstants.NODE_ID_STORE_0001_WORKSTATION_002, - workstation000102, - MultiTierTestConstants.NODE_GROUP_WORKSTATION, true, true, true); - } - - @Test - public void pushTest() { - getTemplate(workstation000101).update( - "truncate table sync_workstation_to_home"); - getTemplate(workstation000102).update( - "truncate table sync_workstation_to_home"); - getTemplate(regionServer).update( - "truncate table sync_workstation_to_home"); - getTemplate(homeServer).update( - "truncate table sync_workstation_to_home"); - - PushThread w1 = new PushThread(unitTestSql - .get("insertWorkstationToHomeSql"), workstation000101, 250, 500, - 10); - PushThread w2 = new PushThread(unitTestSql - .get("insertWorkstationToHomeSql"), workstation000102, 500, 250, - 12); - w2.start(); - w1.start(); - while (regionServer.getEngine().push().wasDataProcessed() || !w2.done || !w1.done) { - try { - Thread.sleep(5); - } catch (Exception ex) { - } - } - - JdbcTemplate t = getTemplate(homeServer); - int countAtHomeServer = t - .queryForInt("select count(*) from sync_workstation_to_home"); - int countInserted = w1.insertedCount + w2.insertedCount; - Assert.assertTrue(countInserted > 0); - Assert.assertEquals(countInserted, countAtHomeServer); - } - - protected void registerAndLoad(SymmetricWebServer registrationServer, - String externalId, SymmetricWebServer clientNode, - String nodeGroupId, boolean autoRegister, boolean autoReload, - boolean testReload) { - IParameterService parameterService = getParameterService(registrationServer); - if (!autoRegister) { - registrationServer.getEngine().openRegistration(nodeGroupId, - externalId); - parameterService.saveParameter( - ParameterConstants.AUTO_REGISTER_ENABLED, false); - } else { - parameterService.saveParameter( - ParameterConstants.AUTO_REGISTER_ENABLED, true); - } - clientNode.getEngine().pull(); - INodeService nodeService = AppUtils.find(Constants.NODE_SERVICE, - clientNode.getEngine()); - Node node = nodeService.findIdentity(); - Assert.assertNotNull(node); - Assert.assertEquals(node.getNodeId(), externalId); - - if (testReload) { - if (!autoReload) { - registrationServer.getEngine().reloadNode(externalId); - parameterService.saveParameter( - ParameterConstants.AUTO_RELOAD_ENABLED, false); - } else { - parameterService.saveParameter( - ParameterConstants.AUTO_RELOAD_ENABLED, true); - } - - IOutgoingBatchService homeOutgoingBatchService = AppUtils.find( - Constants.OUTGOING_BATCH_SERVICE, registrationServer.getEngine()); - while (!homeOutgoingBatchService.areAllLoadBatchesComplete(externalId)) { - clientNode.getEngine().pull(); - } - - NodeSecurity clientNodeSecurity = nodeService - .findNodeSecurity(externalId); - Assert.assertFalse(clientNodeSecurity.isInitialLoadEnabled()); - Assert.assertNotNull(clientNodeSecurity.getInitialLoadTime()); - } - } - - protected JdbcTemplate getTemplate(SymmetricWebServer server) { - JdbcTemplate t = AppUtils.find(Constants.JDBC_TEMPLATE, server.getEngine()); - return t; - } - - protected IParameterService getParameterService(SymmetricWebServer server) { - IParameterService s = AppUtils - .find(Constants.PARAMETER_SERVICE, server.getEngine()); - return s; - } - - class PushThread extends Thread { - SymmetricWebServer client; - String insertSql; - int insertedCount; - int numberOfIterations; - int numberOfInsertsPerIteration; - boolean done = false; - long sleep; - - public PushThread(String insertSql, SymmetricWebServer client, - int numberOfIterations, int numberOfInsertsPerIteration, - long sleep) { - this.setName("stressthread" - + getParameterService(client).getExternalId()); - this.insertSql = insertSql; - this.numberOfInsertsPerIteration = numberOfInsertsPerIteration; - this.numberOfIterations = numberOfIterations; - this.client = client; - this.sleep = sleep; - } - - @Override - public void run() { - IParameterService ps = getParameterService(client); - for (int i = 0; i < numberOfIterations; i++) { - if (insertSql != null) { - for (int p = 0; p < numberOfInsertsPerIteration; p++) { - JdbcTemplate t = getTemplate(client); - insertedCount += t.update(insertSql, - ps.getExternalId() + "-" + i + "-" + p, - "The hyper blue dog jumped off a cliff" ); - } - } - client.getEngine().push(); - try { - Thread.sleep(sleep); - } catch (Exception ex) { - } - } - done = true; - } - - } - -} \ No newline at end of file diff --git a/symmetric/symmetric-server/src/test/java/org/jumpmind/symmetric/stress/H2MultiTierStressTest.java b/symmetric/symmetric-server/src/test/java/org/jumpmind/symmetric/stress/H2MultiTierStressTest.java deleted file mode 100644 index ff6b19d964..0000000000 --- a/symmetric/symmetric-server/src/test/java/org/jumpmind/symmetric/stress/H2MultiTierStressTest.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Licensed to JumpMind Inc under one or more contributor - * license agreements. See the NOTICE file distributed - * with this work for additional information regarding - * copyright ownership. JumpMind Inc licenses this file - * to you under the GNU Lesser General Public License (the - * "License"); you may not use this file except in compliance - * with the License. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see - * . - * - * 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.jumpmind.symmetric.stress; - -import org.springframework.test.context.ContextConfiguration; - -@ContextConfiguration(locations = { "classpath:/stress/h2-multi-tier-stress-test.xml" }) -public class H2MultiTierStressTest extends AbstractMultiTierStressTest { - -} \ No newline at end of file diff --git a/symmetric/symmetric-server/src/test/java/org/jumpmind/symmetric/stress/MSSQLMultiTierStressTest.java b/symmetric/symmetric-server/src/test/java/org/jumpmind/symmetric/stress/MSSQLMultiTierStressTest.java deleted file mode 100644 index 81defdee85..0000000000 --- a/symmetric/symmetric-server/src/test/java/org/jumpmind/symmetric/stress/MSSQLMultiTierStressTest.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Licensed to JumpMind Inc under one or more contributor - * license agreements. See the NOTICE file distributed - * with this work for additional information regarding - * copyright ownership. JumpMind Inc licenses this file - * to you under the GNU Lesser General Public License (the - * "License"); you may not use this file except in compliance - * with the License. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see - * . - * - * 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.jumpmind.symmetric.stress; - -import org.springframework.test.context.ContextConfiguration; - -@ContextConfiguration(locations = { "classpath:/stress/sql-server-multi-tier-stress-test.xml" }) -public class MSSQLMultiTierStressTest extends AbstractMultiTierStressTest { - -} \ No newline at end of file diff --git a/symmetric/symmetric-server/src/test/java/org/jumpmind/symmetric/test/TestSetupUtil.java b/symmetric/symmetric-server/src/test/java/org/jumpmind/symmetric/test/TestSetupUtil.java index e2399d0e68..84e7faa3ff 100644 --- a/symmetric/symmetric-server/src/test/java/org/jumpmind/symmetric/test/TestSetupUtil.java +++ b/symmetric/symmetric-server/src/test/java/org/jumpmind/symmetric/test/TestSetupUtil.java @@ -52,7 +52,7 @@ import org.jumpmind.db.platform.IDdlBuilder; import org.jumpmind.db.sql.SqlScript; import org.jumpmind.symmetric.ISymmetricEngine; -import org.jumpmind.symmetric.StandaloneSymmetricEngine; +import org.jumpmind.symmetric.OldStandaloneSymmetricEngine; import org.jumpmind.symmetric.SymmetricWebServer; import org.jumpmind.symmetric.common.Constants; import org.jumpmind.symmetric.common.ParameterConstants; @@ -137,7 +137,7 @@ public static void setup(String testPrefix, String sqlScriptSuffix, String clien if (rootDb != null) { // Temporary engine used for test database setup - ISymmetricEngine setupEngine = new StandaloneSymmetricEngine("file:" + ISymmetricEngine setupEngine = new OldStandaloneSymmetricEngine("file:" + writeTempPropertiesFileFor(testPrefix, rootDb, DatabaseRole.ROOT).getAbsolutePath(), null); dropAndCreateDatabaseTables(rootDb, setupEngine); setupEngine.setup(); @@ -159,7 +159,7 @@ public static void setup(String testPrefix, String sqlScriptSuffix, String clien FileReader reader = new FileReader(file); properties.load(reader); IOUtils.closeQuietly(reader); - clientEngine = new StandaloneSymmetricEngine(properties); + clientEngine = new OldStandaloneSymmetricEngine(properties); dropAndCreateDatabaseTables(clientDb, clientEngine); } } diff --git a/symmetric/symmetric-server/src/test/java/org/jumpmind/symmetric/util/DefaultNodeIdGeneratorTest.java b/symmetric/symmetric-server/src/test/java/org/jumpmind/symmetric/util/DefaultNodeIdGeneratorTest.java index 073279714f..d8679361ad 100644 --- a/symmetric/symmetric-server/src/test/java/org/jumpmind/symmetric/util/DefaultNodeIdGeneratorTest.java +++ b/symmetric/symmetric-server/src/test/java/org/jumpmind/symmetric/util/DefaultNodeIdGeneratorTest.java @@ -24,7 +24,7 @@ import org.jumpmind.symmetric.model.Node; import org.jumpmind.symmetric.model.NodeSecurity; -import org.jumpmind.symmetric.service.mock.MockNodeService; +import org.jumpmind.symmetric.service.impl.MockNodeService; import org.junit.Test; /** diff --git a/symmetric/symmetric-server/src/test/java/org/jumpmind/symmetric/web/MockNodeService.java b/symmetric/symmetric-server/src/test/java/org/jumpmind/symmetric/web/MockNodeService.java deleted file mode 100644 index b630d4311c..0000000000 --- a/symmetric/symmetric-server/src/test/java/org/jumpmind/symmetric/web/MockNodeService.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Licensed to JumpMind Inc under one or more contributor - * license agreements. See the NOTICE file distributed - * with this work for additional information regarding - * copyright ownership. JumpMind Inc licenses this file - * to you under the GNU Lesser General Public License (the - * "License"); you may not use this file except in compliance - * with the License. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see - * . - * - * 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.jumpmind.symmetric.web; - -final class MockNodeService extends org.jumpmind.symmetric.service.mock.MockNodeService { - static final String GOOD_SECURITY_TOKEN = "1"; - static final String GOOD_NODE_ID = "1"; - - @Override - public boolean isNodeAuthorized(String nodeId, String password) { - return GOOD_NODE_ID.equals(nodeId) && GOOD_SECURITY_TOKEN.equals(password); - } -} \ No newline at end of file diff --git a/symmetric/symmetric-util/src/main/java/org/jumpmind/exception/SecurityException.java b/symmetric/symmetric-util/src/main/java/org/jumpmind/exception/SecurityException.java new file mode 100644 index 0000000000..f4c9c99354 --- /dev/null +++ b/symmetric/symmetric-util/src/main/java/org/jumpmind/exception/SecurityException.java @@ -0,0 +1,17 @@ +package org.jumpmind.exception; + +import java.security.GeneralSecurityException; + +public class SecurityException extends RuntimeException { + + private static final long serialVersionUID = 1L; + + public SecurityException(java.lang.SecurityException ex) { + super(ex); + } + + public SecurityException(GeneralSecurityException ex) { + super(ex); + } + +} diff --git a/symmetric/symmetric-util/src/main/java/org/jumpmind/log/Log.java b/symmetric/symmetric-util/src/main/java/org/jumpmind/log/Log.java index 39c698a8a0..ef05905430 100644 --- a/symmetric/symmetric-util/src/main/java/org/jumpmind/log/Log.java +++ b/symmetric/symmetric-util/src/main/java/org/jumpmind/log/Log.java @@ -26,6 +26,10 @@ public void warn(String msg, Object... params) { log(LogLevel.WARN, msg, params); } + public void warn(Throwable ex) { + log(LogLevel.WARN, ex); + } + public void warn(Throwable ex, String msg, Object... params) { log(LogLevel.WARN, ex, msg, params); } diff --git a/symmetric/symmetric-util/src/main/java/org/jumpmind/util/FormatUtils.java b/symmetric/symmetric-util/src/main/java/org/jumpmind/util/FormatUtils.java index 21d1374517..762e3ead45 100644 --- a/symmetric/symmetric-util/src/main/java/org/jumpmind/util/FormatUtils.java +++ b/symmetric/symmetric-util/src/main/java/org/jumpmind/util/FormatUtils.java @@ -1,5 +1,6 @@ package org.jumpmind.util; +import java.util.HashMap; import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -16,6 +17,12 @@ private FormatUtils() { public static String replace(String prop, String replaceWith, String sourceString) { return StringUtils.replace(sourceString, "$(" + prop + ")", replaceWith); } + + public static String replaceToken(String text, String tokenToReplace, String replaceWithText, boolean matchUsingPrefixSuffix) { + Map replacements = new HashMap(1); + replacements.put(tokenToReplace,replaceWithText); + return replaceTokens(text, replacements, matchUsingPrefixSuffix); + } /** * Replace the keys found in the target text with the values found in the