package org.sakaiproject.warehouse.impl;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.sakaiproject.warehouse.util.db.DbLoader;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;
import java.io.InputStream;
import java.util.ArrayList;
import org.quartz.JobExecutionException;
import org.sakaiproject.warehouse.service.ChildWarehouseTask;
import org.sakaiproject.warehouse.service.DataWarehouseManager;
import org.sakaiproject.warehouse.service.WarehouseTask;
/**
* <p>Alternative to the BaseWarehouseTask. For really large datasets
* building up a giant list in memory before writing out to the db results
* in out of memory issues. Extending from this task will help.</p>
*
* <p>The execute() method simply prepares the db (setup up the table, clears it etc).
* In your derived class you want to call execute(Object) with each entity as you go.
* This will batch up a smaller list and then send that to the ChildWarehouseTask
* which will do the real persistence. You need to call flush at the end of your work
* to make sure any remaining objects gets flushed out to the db.</p>
*
*/
public abstract class CallbackWarehouseTask implements WarehouseTask {
protected final Log logger = LogFactory.getLog(getClass());
private DataSource dataSource;
private ChildWarehouseTask task;
private String tableDdlResource;
private DataWarehouseManager dataWarehouseManager;
private ArrayList items = new ArrayList();
private int batchsize = 1000;
public void flush() throws Exception {
execute(true);
items.clear();
}
public void execute() throws JobExecutionException {
Connection connection = null;
try {
connection = getDataSource().getConnection();
connection.setAutoCommit(true);
task.prepare(connection);
}
catch (SQLException e) {
throw new JobExecutionException(e);
}
finally {
if (connection != null) {
try {
connection.close();
}
catch (Exception e) {
// can't do anything with this.
}
}
}
process();
}
public void execute(Object object) throws Exception {
items.add(object);
execute(false);
}
protected void execute(boolean flush) throws Exception {
Connection connection = null;
if (items.size() > getBatchsize() ||
(flush == true && items.size() > 0 )) {
try {
connection = getDataSource().getConnection();
connection.setAutoCommit(true);
task.execute(null, items, connection);
}
catch (SQLException e) {
throw new Exception(e);
}
catch(JobExecutionException e) {
logger.warn("Error executing warehousing tasks", e);
throw new Exception(e);
}
finally {
items.clear();
if (connection != null) {
try {
connection.close();
}
catch (Exception e) {
// can't do anything with this.
}
}
}
}
}
/**
* This method loads the tables and registers the task.
*
* This function is called after the task bean properties have been set.
* Children are singletons where there bean init function is this method.
*/
public void init() {
items.clear();
Connection connection = null;
try {
InputStream tableDdl = getTableDdl();
if (tableDdl != null) {
connection = getDataSource().getConnection();
connection.setAutoCommit(true);
DbLoader loader = new DbLoader(connection);
loader.runLoader(tableDdl);
}
getDataWarehouseManager().registerTask(this);
}
catch (SQLException e) {
throw new RuntimeException(e);
}
finally {
if (connection != null) {
try {
connection.close();
}
catch (Exception e) {
// can't do anything with this.
}
}
}
}
public InputStream getTableDdl() {
if (getTableDdlResource() != null) {
return getClass().getResourceAsStream(getTableDdlResource());
}
return null;
}
protected abstract void process();
public DataSource getDataSource() {
return dataSource;
}
public void setDataSource(DataSource dataSource) {
this.dataSource = dataSource;
}
public ChildWarehouseTask getTask() {
return task;
}
public void setTask(ChildWarehouseTask task) {
this.task = task;
}
public String getTableDdlResource() {
return tableDdlResource;
}
public void setTableDdlResource(String tableDdlResource) {
this.tableDdlResource = tableDdlResource;
}
public DataWarehouseManager getDataWarehouseManager() {
return dataWarehouseManager;
}
public void setDataWarehouseManager(DataWarehouseManager dataWarehouseManager) {
this.dataWarehouseManager = dataWarehouseManager;
}
public int getBatchsize() {
return batchsize;
}
public void setBatchsize(int batchsize) {
this.batchsize = batchsize;
}
}