package org.jcommons.db.load;
import java.sql.SQLException;
import java.util.List;
import javax.sql.DataSource;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jcommons.db.load.sort.DependencySheetSorter;
import org.jcommons.db.load.sort.SheetSortingStrategy;
import org.jcommons.io.sheet.Book;
import org.jcommons.io.sheet.Sheet;
/**
* Merges a book into the given data source.
*
* Tables and columns must exist and will not be created!
*
* @author Thorsten Goeckeler
*/
public class DatabaseLoader
{
private static final Log LOG = LogFactory.getLog(DatabaseLoader.class);
private DataSource dataSource;
private SheetSortingStrategy sheetSorter;
/** @return the currently used data source */
public DataSource getDataSource() {
return dataSource;
}
/**
* Inject the data source to be used to load the data.
*
* @param dataSource the database connection to use to load the data
* @return this to allow chaining
*/
public DatabaseLoader setDataSource(final DataSource dataSource) {
this.dataSource = dataSource;
return this;
}
/**
* Load the given book into the given database, either insert or update the data.
*
* @param book the data set to load into the database
* @throws SQLException if load cannot be performed
*/
public void load(final Book book)
throws SQLException
{
if (book == null) return;
if (getDataSource() == null) {
StringBuilder log = new StringBuilder("Cannot import book ").append(defaultName(book));
log.append("as no database connection can be established.");
LOG.error(log.toString());
return;
}
if (LOG.isInfoEnabled()) {
StringBuilder log = new StringBuilder("Importing book ").append(defaultName(book));
log.append("with ").append(book.getSheets().size()).append(" sheets into the database.");
LOG.info(log.toString());
}
// simple load strategy, first load every sheet with mandatory fields, then update with the rest
SheetLoader loader = new SheetLoader().setDataSource(getDataSource());
List<Sheet> sheets = getSheets(book);
// load mandatory fields (and primary keys to ensure foreign key relationships)
for (Sheet sheet : sheets) {
loader.load(sheet);
}
// load all other data including foreign keys that can be referenced now
for (Sheet sheet : sheets) {
loader.update(sheet);
}
if (LOG.isInfoEnabled()) {
StringBuilder log = new StringBuilder("Imported book ").append(defaultName(book));
log.append("with ").append(book.getSheets().size()).append(" sheets into the database.");
LOG.info(log.toString());
}
}
/**
* Return the sheets in the order they shall be loaded.
*
* @param book the book containing the sheets, never null
* @return the ordered list of sheets
*/
protected List<Sheet> getSheets(final Book book) {
getSheetSorter().setDataSource(getDataSource());
return getSheetSorter().sort(book.getSheets());
}
/**
* Determine the name of the book for debug messages
*
* @param book the currently inspected book
* @return the quoted name of the book or the empty string if it has no name
*/
private String defaultName(final Book book) {
StringBuilder text = new StringBuilder();
if (book != null && StringUtils.isNotBlank(book.getName())) {
text.append("\"").append(book.getName()).append("\" ");
}
return text.toString();
}
/** @return currently used sorting strategy for the sheets or a default implementation */
public SheetSortingStrategy getSheetSorter() {
if (sheetSorter == null) sheetSorter = new DependencySheetSorter();
return sheetSorter;
}
/**
* Define a sheet sorting strategy other than the default one.
*
* @param sheetSorter the sheet sorting strategy to use, <code>null</code> to reset to default implementation
*/
public void setSheetSorter(final SheetSortingStrategy sheetSorter) {
this.sheetSorter = sheetSorter;
}
}