/*
* Copyright 2007 T-Rank AS
*
* 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 no.trank.openpipe.jdbc;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.JdbcTemplate;
import static no.trank.openpipe.api.document.DocumentOperation.*;
/**
* A simple document producer for getting documents from a jdbc source.
*
* The producer can trigger add, modify and/or deletes. Each operation has a corresponding pre, post, fail and list
* sqls. Ex: for add you have the setters: setAddPreSql(...), setAddSql(...), setAddPostSql(...) and
* setAddFailSql(List<String> sql).
*
* For each operation type (add, modify, delete):<br/>
* - The preSql is run<br/>
* - Each document is produced by running the producer sql. There is no guarantee that all documents are fetched before
* next step happens. But it is guaranteed that a after a post/failSql a new preSql is run before new documents are
* fetched.<br/>
* - If no errors happened the postSql is run.</br>
* - If an error happened the failSql is run.</br>
*
* To use:
*
* 1. Set the JdbcTemplate (and its dataSource)</br>
* 2. Set the sqls for producing documents.</br>
*
* @version $Revision$
*/
public class SimpleJdbcDocumentProducer extends JdbcDocumentProducer {
private static final Logger log = LoggerFactory.getLogger(SimpleJdbcDocumentProducer.class);
private final Map<String, SqlOperationPart> opPartsMap = new LinkedHashMap<String, SqlOperationPart>();
@Override
public void init() {
super.setOperationParts(new ArrayList<OperationPart>(opPartsMap.values()));
super.init();
}
private static <T> List<T> notNull(List<T> list) {
return list == null ? Collections.<T>emptyList() : list;
}
private static void execute(JdbcTemplate jdbcTemplate, List<String> sqls) throws DataAccessException {
for (String sql : sqls) {
log.debug("Executing sql {}", sql);
jdbcTemplate.execute(sql);
}
}
private SqlOperationPart getPart(String operation) {
SqlOperationPart part = opPartsMap.get(operation);
if (part == null) {
part = new SqlOperationPart(operation);
opPartsMap.put(operation, part);
}
return part;
}
/**
* Set a list of preSqls to run.
*
* @param operation the operation that this preSql is used for.
* @param sql a list of sql to run as preSql
* @see no.trank.openpipe.api.document.DocumentOperation
*/
public void setPreSql(String operation, List<String> sql) {
getPart(operation).setPreSql(sql);
}
/**
* Set a list of sqls to run to get the documents.
*
* @param operation the operation that this preSql is used for.
* @param sql a list of sql to run as preSql
* @see no.trank.openpipe.api.document.DocumentOperation
*/
public void setSql(String operation, List<String> sql) {
getPart(operation).setSqls(sql);
}
/**
* Set a list of sqls to run after documents have been fetched.
*
* @param operation the operation that this preSql is used for.
* @param sql a list of sql to run as preSql
* @see no.trank.openpipe.api.document.DocumentOperation
*/
public void setPostSql(String operation, List<String> sql) {
getPart(operation).setPostSql(sql);
}
/**
* Set a list of sqls to run if there was an error in the pipeline.
*
* @param operation the operation that this preSql is used for.
* @param sql a list of sql to run as preSql
* @see no.trank.openpipe.api.document.DocumentOperation
*/
private void setFailSql(String operation, List<String> sql) {
getPart(operation).setFailSql(sql);
}
/**
* Set a list of preSqls to run before producing add Documents.
*
* @param sql a list of sql to run as preSql
* @see no.trank.openpipe.api.document.DocumentOperation
*/
public void setAddPreSql(List<String> sql) {
setPreSql(ADD_VALUE, sql);
}
/**
* Set a list of sqls to run for producing add Documents.
*
* @param sql a list of sql to run as preSql
* @see no.trank.openpipe.api.document.DocumentOperation
*/
public void setAddSql(List<String> sql) {
setSql(ADD_VALUE, sql);
}
/**
* Set a list of sqls to run after add documents have been produced. (If no error happened)
*
* @param sql a list of sql to run as preSql
* @see no.trank.openpipe.api.document.DocumentOperation
*/
public void setAddPostSql(List<String> sql) {
setPostSql(ADD_VALUE, sql);
}
/**
* Set a list of sqls to run after add documents have been produced and some error happened.
*
* @param sql a list of sql to run as preSql
* @see no.trank.openpipe.api.document.DocumentOperation
*/
public void setAddFailSql(List<String> sql) {
setFailSql(ADD_VALUE, sql);
}
/**
* Set a list of preSqls to run before producing modify Documents.
*
* @param sql a list of sql to run as preSql
* @see no.trank.openpipe.api.document.DocumentOperation
*/
public void setModifyPreSql(List<String> sql) {
setPreSql(MODIFY_VALUE, sql);
}
/**
* Set a list of sqls to run for producing modify Documents.
*
* @param sql a list of sql to run as preSql
* @see no.trank.openpipe.api.document.DocumentOperation
*/
public void setModifySql(List<String> sql) {
setSql(MODIFY_VALUE, sql);
}
/**
* Set a list of sqls to run after modify documents have been produced. (If no error happened)
*
* @param sql a list of sql to run as preSql
* @see no.trank.openpipe.api.document.DocumentOperation
*/
public void setModifyPostSql(List<String> sql) {
setPostSql(MODIFY_VALUE, sql);
}
/**
* Set a list of sqls to run after modify documents have been produced and some error happened.
*
* @param sql a list of sql to run as preSql
* @see no.trank.openpipe.api.document.DocumentOperation
*/
public void setModifyFailSql(List<String> sql) {
setFailSql(MODIFY_VALUE, sql);
}
/**
* Set a list of preSqls to run before producing delete Documents.
*
* @param sql a list of sql to run as preSql
* @see no.trank.openpipe.api.document.DocumentOperation
*/
public void setDeletePreSql(List<String> sql) {
setPreSql(DELETE_VALUE, sql);
}
/**
* Set a list of sqls to run for producing delete Documents.
*
* @param sql a list of sql to run as preSql
* @see no.trank.openpipe.api.document.DocumentOperation
*/
public void setDeleteSql(List<String> sql) {
setSql(DELETE_VALUE, sql);
}
/**
* Set a list of sqls to run after delete documents have been produced. (If no error happened)
*
* @param sql a list of sql to run as preSql
* @see no.trank.openpipe.api.document.DocumentOperation
*/
public void setDeletePostSql(List<String> sql) {
setPostSql(DELETE_VALUE, sql);
}
/**
* Set a list of sqls to run after delete documents have been produced and some error happened.
*
* @param sql a list of sql to run as preSql
* @see no.trank.openpipe.api.document.DocumentOperation
*/
public void setDeleteFailSql(List<String> sql) {
setFailSql(DELETE_VALUE, sql);
}
private static class SqlOperationPart implements OperationPart {
private final String operation;
private List<String> preSql = Collections.emptyList();
private List<String> sqls = Collections.emptyList();
private List<String> postSql = Collections.emptyList();
private List<String> failSql = Collections.emptyList();
public SqlOperationPart(String operation) {
this.operation = operation;
}
@Override
public boolean isEmpty() {
return preSql.isEmpty() && sqls.isEmpty() && postSql.isEmpty();
}
@Override
public String getOperation() {
return operation;
}
@Override
public void doPreSql(JdbcTemplate jdbcTemplate) throws DataAccessException {
execute(jdbcTemplate, preSql);
}
@Override
public void doPostSql(JdbcTemplate jdbcTemplate) throws DataAccessException {
execute(jdbcTemplate, postSql);
}
@Override
public void doFailSql(JdbcTemplate jdbcTemplate) throws DataAccessException {
execute(jdbcTemplate, failSql);
}
@Override
public List<String> getSqls() {
return sqls;
}
public void setSqls(List<String> sqls) {
this.sqls = notNull(sqls);
}
public void setPreSql(List<String> preSql) {
this.preSql = notNull(preSql);
}
public void setPostSql(List<String> postSql) {
this.postSql = notNull(postSql);
}
public void setFailSql(List<String> failSql) {
this.failSql = notNull(failSql);
}
}
}