/** * 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 General Public License, version 3.0 (GPLv3) * (the "License"); you may not use this file except in compliance * with the License. * * You should have received a copy of the GNU General Public License, * version 3.0 (GPLv3) along with this library; if not, see * <http://www.gnu.org/licenses/>. * * 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.load; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import org.apache.commons.lang.BooleanUtils; import org.apache.commons.lang.StringUtils; import org.jumpmind.db.model.Table; import org.jumpmind.extension.IBuiltInExtensionPoint; import org.jumpmind.symmetric.ISymmetricEngine; import org.jumpmind.symmetric.common.ParameterConstants; import org.jumpmind.symmetric.io.data.CsvData; import org.jumpmind.symmetric.io.data.DataContext; import org.jumpmind.symmetric.io.data.writer.IDatabaseWriterErrorHandler; import org.jumpmind.symmetric.io.data.writer.IDatabaseWriterFilter; import org.jumpmind.symmetric.model.LoadFilter; import org.jumpmind.symmetric.model.LoadFilter.LoadFilterType; import org.jumpmind.util.FormatUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public abstract class DynamicDatabaseWriterFilter implements IDatabaseWriterFilter, IDatabaseWriterErrorHandler, IBuiltInExtensionPoint { private final String BATCH_COMPLETE_SCRIPTS_KEY = String.format("%d.BatchCompleteScripts", hashCode()); private final String BATCH_COMMIT_SCRIPTS_KEY = String.format("%d.BatchCommitScripts", hashCode()); private final String BATCH_ROLLBACK_SCRIPTS_KEY = String.format("%d.BatchRollbackScripts", hashCode()); private final String FAIL_ON_ERROR_KEY = String.format("%d.FailOnError", hashCode()); protected final Logger log = LoggerFactory.getLogger(getClass()); protected ISymmetricEngine engine = null; protected Map<String, List<LoadFilter>> loadFilters = null; public enum WriteMethod { BEFORE_WRITE, AFTER_WRITE, BATCH_COMPLETE, BATCH_COMMIT, BATCH_ROLLBACK, HANDLE_ERROR }; public DynamicDatabaseWriterFilter(ISymmetricEngine engine, Map<String, List<LoadFilter>> loadFilters) { this.engine = engine; this.loadFilters = loadFilters; } public static List<DynamicDatabaseWriterFilter> getDatabaseWriterFilters(ISymmetricEngine engine, Map<LoadFilterType, Map<String, List<LoadFilter>>> loadFilters) { List<DynamicDatabaseWriterFilter> databaseWriterFilters = new ArrayList<DynamicDatabaseWriterFilter>(); if (loadFilters != null) { for (Map.Entry<LoadFilterType, Map<String, List<LoadFilter>>> entry : loadFilters.entrySet()) { if (entry.getKey().equals(LoadFilterType.BSH)) { databaseWriterFilters.add(new BshDatabaseWriterFilter(engine, entry.getValue())); } else if (entry.getKey().equals(LoadFilterType.JAVA)) { databaseWriterFilters.add(new JavaDatabaseWriterFilter(engine, entry.getValue())); } } } return databaseWriterFilters; } public boolean beforeWrite(DataContext context, Table table, CsvData data) { return processLoadFilters(context, table, data, null, WriteMethod.BEFORE_WRITE); } public void afterWrite(DataContext context, Table table, CsvData data) { processLoadFilters(context, table, data, null, WriteMethod.AFTER_WRITE); } public boolean handleError(DataContext context, Table table, CsvData data, Exception error) { return processLoadFilters(context, table, data, error, WriteMethod.HANDLE_ERROR); } public void earlyCommit(DataContext context) { } public void batchComplete(DataContext context) { executeScripts(context, BATCH_COMPLETE_SCRIPTS_KEY); } public void batchCommitted(DataContext context) { executeScripts(context, BATCH_COMMIT_SCRIPTS_KEY); } public void batchRolledback(DataContext context) { executeScripts(context, BATCH_ROLLBACK_SCRIPTS_KEY); } protected boolean processLoadFilters(DataContext context, Table table, CsvData data, Exception error, WriteMethod writeMethod) { boolean writeRow = true; if (table != null) { List<LoadFilter> foundFilters = null; if (!table.getName().toLowerCase().startsWith(engine.getTablePrefix() + "_")) { foundFilters = lookupFilters(foundFilters, table.getCatalog(), table.getSchema(), FormatUtils.WILDCARD); foundFilters = lookupFilters(foundFilters, table.getCatalog(), FormatUtils.WILDCARD, FormatUtils.WILDCARD); foundFilters = lookupFilters(foundFilters, FormatUtils.WILDCARD, FormatUtils.WILDCARD, FormatUtils.WILDCARD); } String tableName = null; if (isIgnoreCase()) { tableName = table.getName().toUpperCase(); } else { tableName = table.getName(); } foundFilters = lookupFilters(foundFilters, FormatUtils.WILDCARD, FormatUtils.WILDCARD, tableName); foundFilters = lookupFilters(foundFilters, FormatUtils.WILDCARD, table.getSchema(), tableName); foundFilters = lookupFilters(foundFilters, table.getCatalog(), FormatUtils.WILDCARD, tableName); foundFilters = lookupFilters(foundFilters, table.getCatalog(), table.getSchema(), tableName); if (foundFilters != null) { for (LoadFilter filter : foundFilters) { addBatchScriptsToContext(context, filter); } writeRow = processLoadFilters(context, table, data, error, writeMethod, foundFilters); } } return writeRow; } private List<LoadFilter> lookupFilters(List<LoadFilter> foundFilters, String catalogName, String schemaName, String tableName) { List<LoadFilter> filters = loadFilters.get(Table.getFullyQualifiedTableName(catalogName, schemaName, tableName)); if (filters != null) { if (foundFilters == null) { foundFilters = new ArrayList<LoadFilter>(); } foundFilters.addAll(filters); } return foundFilters; } protected abstract boolean processLoadFilters(DataContext context, Table table, CsvData data, Exception error, WriteMethod writeMethod, List<LoadFilter> loadFiltersForTable); protected void addBatchScriptsToContext(DataContext context, LoadFilter filter) { addBatchScriptToContext(context, BATCH_COMPLETE_SCRIPTS_KEY, filter.getBatchCompleteScript()); addBatchScriptToContext(context, BATCH_COMMIT_SCRIPTS_KEY, filter.getBatchCommitScript()); addBatchScriptToContext(context, BATCH_ROLLBACK_SCRIPTS_KEY, filter.getBatchRollbackScript()); if (filter.isFailOnError()) { context.put(FAIL_ON_ERROR_KEY, Boolean.TRUE); } } protected void addBatchScriptToContext(DataContext context, String key, String script) { if (StringUtils.isNotBlank(script)) { @SuppressWarnings("unchecked") Set<String> scripts = (Set<String>) context.get(key); if (scripts == null) { scripts = new HashSet<String>(); context.put(key, scripts); } scripts.add(script); } } protected void executeScripts(DataContext context, String key) { @SuppressWarnings("unchecked") Set<String> scripts = (Set<String>) context.get(key); executeScripts(context, key, scripts, BooleanUtils.isTrue((Boolean) context.get(FAIL_ON_ERROR_KEY))); } protected abstract void executeScripts(DataContext context, String key, Set<String> scripts, boolean isFailOnError); protected boolean isIgnoreCase() { return engine.getParameterService().is(ParameterConstants.DB_METADATA_IGNORE_CASE); } public boolean handlesMissingTable(DataContext context, Table table) { if (engine != null && engine.getParameterService() != null && engine.getParameterService().is(ParameterConstants.BSH_LOAD_FILTER_HANDLES_MISSING_TABLES)) { return true; } else { String tableName = table.getFullyQualifiedTableName(); if (isIgnoreCase()) { tableName = tableName.toUpperCase(); } return loadFilters.containsKey(tableName); } } }