/*
* This software is distributed under the terms of the FSF
* Gnu Lesser General Public License (see lgpl.txt).
*
* This program is distributed WITHOUT ANY WARRANTY. See the
* GNU General Public License for more details.
*/
package com.scooterframework.orm.sqldataexpress.service;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.sql.DataSource;
import com.mchange.v2.c3p0.PooledDataSource;
import com.scooterframework.common.logging.LogUtil;
import com.scooterframework.common.util.StringUtil;
import com.scooterframework.common.util.Util;
import com.scooterframework.orm.activerecord.ActiveRecordConstants;
import com.scooterframework.orm.sqldataexpress.config.DatabaseConfig;
import com.scooterframework.orm.sqldataexpress.config.SqlConfig;
import com.scooterframework.orm.sqldataexpress.connection.DatabaseConnectionContext;
import com.scooterframework.orm.sqldataexpress.connection.UserDatabaseConnection;
import com.scooterframework.orm.sqldataexpress.exception.BaseSQLException;
import com.scooterframework.orm.sqldataexpress.exception.CreateConnectionFailureException;
import com.scooterframework.orm.sqldataexpress.exception.TransactionException;
import com.scooterframework.orm.sqldataexpress.exception.UnexpectedDataException;
import com.scooterframework.orm.sqldataexpress.exception.UnsupportedDataProcessorNameException;
import com.scooterframework.orm.sqldataexpress.exception.UnsupportedDataProcessorTypeException;
import com.scooterframework.orm.sqldataexpress.exception.UnsupportedStoredProcedureAPINameException;
import com.scooterframework.orm.sqldataexpress.object.OmniDTO;
import com.scooterframework.orm.sqldataexpress.object.RowData;
import com.scooterframework.orm.sqldataexpress.object.RowInfo;
import com.scooterframework.orm.sqldataexpress.object.TableData;
import com.scooterframework.orm.sqldataexpress.processor.DataProcessor;
import com.scooterframework.orm.sqldataexpress.processor.DataProcessorFactory;
import com.scooterframework.orm.sqldataexpress.processor.DataProcessorTypes;
import com.scooterframework.transaction.ImplicitTransactionManager;
import com.scooterframework.transaction.Transaction;
import com.scooterframework.transaction.TransactionManager;
import com.scooterframework.transaction.TransactionManagerUtil;
/**
* SqlServiceImpl class implements SqlService interface.
*
* @author (Fei) John Chen
*/
public class SqlServiceImpl implements SqlService {
public SqlServiceImpl() {}
/**
* Begin a transaction of default transaction type.
*
* The default transaction type is JDBC if it is not defined in property file.
*/
public void beginTransaction()
throws TransactionException {
getTransactionManager().beginTransaction();
}
/**
* Begin a transaction of a specific type.
*/
public void beginTransaction(String type)
throws TransactionException {
getTransactionManager().beginTransaction(type);
}
/**
* Commit a transaction.
*/
public void commitTransaction()
throws TransactionException {
getTransactionManager().commitTransaction();
}
/**
* Rollback a transaction.
*/
public void rollbackTransaction()
throws TransactionException {
getTransactionManager().rollbackTransaction();
}
/**
* Release all resources hold by this transaction.
*/
public void releaseResources()
throws TransactionException {
getTransactionManager().releaseResources();
}
/**
* execute without output filter
*/
public OmniDTO execute(Map<String, Object> inputs, String processorType, String processorName)
throws BaseSQLException {
return execute(inputs, processorType, processorName, new HashMap<String, String>());
}
/**
* execute with output filter
*/
public OmniDTO execute(Map<String, Object> inputs, String processorType, String processorName, Map<String, String> outputFilters)
throws BaseSQLException {
if (processorType == null || processorName == null)
throw new IllegalArgumentException("processorType or processorName is null.");
if (inputs == null) inputs = new HashMap<String, Object>();
ImplicitTransactionManager tm = TransactionManagerUtil.getImplicitTransactionManager();
OmniDTO returnTO = null;
try {
tm.beginTransactionImplicit();
//if (log.isDebugEnabled()) displayDS((String)inputs.get(DataProcessor.input_key_database_connection_name), "beforeConnection");
UserDatabaseConnection connection = findOrCreateConnection(inputs);
//if (log.isDebugEnabled()) displayDS((String)inputs.get(DataProcessor.input_key_database_connection_name), "beforeExecute");
returnTO = executeKeepConnection(connection, inputs, processorType, processorName, outputFilters);
//if (log.isDebugEnabled()) displayDS((String)inputs.get(DataProcessor.input_key_database_connection_name), "afterExecute");
tm.commitTransactionImplicit();
//if (log.isDebugEnabled()) displayDS((String)inputs.get(DataProcessor.input_key_database_connection_name), "afterCommit");
}
catch(BaseSQLException bdex) {
tm.rollbackTransactionImplicit();
throw bdex;
}
finally {
tm.releaseResourcesImplicit();
displayDS((String)inputs.get(DataProcessor.input_key_database_connection_name), "afterRelease");
}
return returnTO;
}
private void displayDS(String connectionName, String where) {
try {
DataSource ds = null;
if (connectionName == null) {
ds = (DataSource) DatabaseConfig.getInstance().getPooledDataSource();
}
else {
ds = (DataSource) DatabaseConfig.getInstance().getPooledDataSource(connectionName);
}
// make sure it's a c3p0 PooledDataSource
if (ds != null && (ds instanceof PooledDataSource)) {
PooledDataSource pds = (PooledDataSource) ds;
log.debug("displayDS for " + where + " - num_connections: " + pds.getNumConnectionsDefaultUser());
log.debug("displayDS for " + where + " - num_busy_connections: " + pds.getNumBusyConnectionsDefaultUser());
log.debug("displayDS for " + where + " - num_idle_connections: " + pds.getNumIdleConnectionsDefaultUser());
}
} catch(Exception ex) {
log.debug("displayDS for " + where + " - ERROR: " + ex.getMessage());
}
}
/**
* execute a collection of InputInfo objects in one transaction
*/
public Collection<OmniDTO> execute(Collection<InputInfo> inputInfoList)
throws BaseSQLException {
if (inputInfoList == null)
throw new IllegalArgumentException("inputs list is null.");
ImplicitTransactionManager tm = TransactionManagerUtil.getImplicitTransactionManager();
Collection<OmniDTO> returnTOList = new ArrayList<OmniDTO>();
try {
tm.beginTransactionImplicit();
for (InputInfo ip : inputInfoList) {
UserDatabaseConnection connection = findOrCreateConnection(ip);
OmniDTO returnTO = executeKeepConnection(connection, ip.getInputs(), ip.getProcessorType(), ip.getProcessorName(), ip.getOutputFilters());
returnTOList.add(returnTO);
//now execute child InputInfo
Collection<InputInfo> childList = ip.getChildInputInfoObjects();
for (InputInfo childIp : childList) {
OmniDTO returnTO2 = executeKeepConnection(connection, childIp.getInputs(), childIp.getProcessorType(), childIp.getProcessorName(), childIp.getOutputFilters());
returnTO.addChildrenOmniDTOToList(returnTO2);
}
}
tm.commitTransactionImplicit();
}
catch(BaseSQLException bdex) {
tm.rollbackTransactionImplicit();
throw bdex;
}
finally {
tm.releaseResourcesImplicit();
}
return returnTOList;
}
/**
* execute a collection of InputInfo objects in one transaction
*/
public OmniDTO retrieveMasterDetails(InputInfo inputInfo)
throws BaseSQLException {
if (inputInfo == null)
throw new IllegalArgumentException("inputInfo is null.");
ImplicitTransactionManager tm = TransactionManagerUtil.getImplicitTransactionManager();
OmniDTO returnTO = null;
try {
tm.beginTransactionImplicit();
InputInfo ip = inputInfo;
UserDatabaseConnection udc = findOrCreateConnection(ip);
udc.getConnection().setReadOnly(true);
returnTO = executeKeepConnection(udc, ip.getInputs(), ip.getProcessorType(), ip.getProcessorName(), ip.getOutputFilters());
log.debug("parent: " + returnTO);
//now execute child InputInfo
Collection<InputInfo> childList = ip.getChildInputInfoObjects();
for (InputInfo childIp : childList) {
// find all input parameters in childIp that need data from parent
List<String> connectorList = new ArrayList<String>();
Map<String, Object> childInputs = childIp.getInputs();
childInputs = convertKeyCase(childInputs);
for (Map.Entry<String, Object> entry : childInputs.entrySet()) {
String key = entry.getKey();
String value = (String)childInputs.get(key);
if (key != null && key.startsWith("&")) connectorList.add(value);
}
// create a select union query
String query = null;
if (DataProcessorTypes.NAMED_SQL_STATEMENT_PROCESSOR.equals(childIp.getProcessorType())) {
query = SqlConfig.getInstance().getSql(childIp.getProcessorName());
}
else
if (DataProcessorTypes.DIRECT_SQL_STATEMENT_PROCESSOR.equals(childIp.getProcessorType())) {
query = childIp.getProcessorName();
}
log.debug("child query1: " + query);
// check if parent has data
boolean parentHasData = false;
TableData parentRt = null;
if (returnTO != null) {
parentRt = returnTO.getTableData(ip.getProcessorName());
if (parentRt != null) {
int size = parentRt.getAllRows().size();
if (size > 0) parentHasData = true;
}
}
// construct child query
String childQuery = "";
if (query != null && connectorList.size() > 0 && parentHasData) {
childQuery = getNewChildQuery(query, childIp, parentRt.getAllRows());
}
else {
childQuery = query;
}
log.debug("child query2: " + childQuery);
if (parentHasData) {
udc = findOrCreateConnection(childIp);
OmniDTO returnTO2 =
executeKeepConnection(udc,
childIp.getInputs(),
DataProcessorTypes.DIRECT_SQL_STATEMENT_PROCESSOR,
childQuery,
childIp.getOutputFilters());
// merge child records with corresponding parent record
if (returnTO2 != null) {
linkParentWithChild(parentRt,
returnTO2.getTableData(childQuery),
childIp.getProcessorName(),
connectorList);
}
log.debug("returnTO2: " + returnTO2);
}
}
}
catch(SQLException ex) {
throw new BaseSQLException(ex);
}
catch(BaseSQLException bdex) {
throw bdex;
}
finally {
tm.releaseResourcesImplicit();
}
return returnTO;
}
/**
* execute
*/
public OmniDTO execute(Collection<InputParameter> inputParameters, String processorType, String processorName)
throws BaseSQLException {
return execute(inputParameters, processorType, processorName, null);
}
/**
* execute of InputInfo with output filter
*/
public OmniDTO execute(Collection<InputParameter> inputParameters, String processorType, String processorName, Map<String, String> outputFilters)
throws BaseSQLException {
if (inputParameters == null) throw new IllegalArgumentException("inputs is null.");
Map<String, Object> inputsMap = new HashMap<String, Object>();
for (InputParameter ip : inputParameters) {
inputsMap.put(ip.getName(), ip.getValue());
}
return execute(inputsMap, processorType, processorName, outputFilters);
}
/**
* Retrieve a single row data from database. If more than one records is
* returned, an UnexpectedDataException will be thrown.
*
* @param inputs Map of input data
* @param processorType A named SQL or direct SQL or stored procedure
* @param processorName SQL name or SQL itself or stored procedure name
* @return TableData The row data
* @throws com.scooterframework.orm.sqldataexpress.exception.BaseSQLException
*/
public TableData retrieveRow(Map<String, Object> inputs, String processorType, String processorName)
throws BaseSQLException {
inputs.put(DataProcessor.input_key_records_fixed, true);
return retrieveRows(inputs, processorType, processorName, 1);
}
/**
* Retrieve a list of rows from database.
*
* @param inputs Map of input data
* @param processorType A named SQL or direct SQL or stored procedure
* @param processorName SQL name or SQL itself or stored procedure name
* @return TableData The list of row data
* @throws com.scooterframework.orm.sqldataexpress.exception.BaseSQLException
*/
public TableData retrieveRows(Map<String, Object> inputs, String processorType, String processorName)
throws BaseSQLException {
return retrieveRows(inputs, processorType, processorName, DataProcessor.NO_ROW_LIMIT);
}
/**
* <p>
* Retrieve a list of rows from database with a certain limit range. If the
* number of returned records is more than the preset limit range, an
* UnexpectedDataException will be thrown.
*
* <p>
* If DataProcessor.input_key_records_fixed key has value "true" in inputs,
* absolute fixed number of records is required. An UnexpectedDataException
* will be thrown if the number of retrieved records is not equal to
* limitOrFixed.
*
* <p>
* If the limitOrFixed = -1, all records are retrieved.
*
* @param inputs Map of input data
* @param processorType A named SQL or direct SQL or stored procedure
* @param processorName SQL name or SQL itself or stored procedure name
* @param limitOrFixed Number of desired (limit) or fixed records to retrieve
* @return TableData The row data
* @throws com.scooterframework.orm.sqldataexpress.exception.BaseSQLException
*/
public TableData retrieveRows(Map<String, Object> inputs, String processorType, String processorName, int limitOrFixed)
throws BaseSQLException {
return retrieveRows(inputs, processorType, processorName, limitOrFixed, 0);
}
/**
* <p>
* Retrieve a list of rows from database with a certain limit range. If the
* number of returned records is more than the preset limit range, an
* UnexpectedDataException will be thrown.
*
* <p>
* If DataProcessor.input_key_records_fixed key has value "true" in inputs,
* absolute fixed number of records is required. An UnexpectedDataException
* will be thrown if the number of retrieved records is not equal to
* limitOrFixed.
*
* <p>
* If the limitOrFixed = -1, all records are retrieved.
*
* offset defaults to 0.
*
* @param inputs Map of input data
* @param processorType A named SQL or direct SQL or stored procedure
* @param processorName SQL name or SQL itself or stored procedure name
* @param limitOrFixed Number of desired (limit) or fixed records to retrieve
* @param offset int for offset
* @return TableData The row data
* @throws com.scooterframework.orm.sqldataexpress.exception.BaseSQLException
*/
public TableData retrieveRows(Map<String, Object> inputs,
String processorType,
String processorName,
int limitOrFixed,
int offset)
throws BaseSQLException {
if (processorType == null || processorName == null)
throw new IllegalArgumentException("processorType or processorName is null.");
if (inputs == null) inputs = new HashMap<String, Object>();
inputs.put(DataProcessor.input_key_records_offset, Integer.valueOf(offset));
inputs.put(DataProcessor.input_key_records_limit, Integer.valueOf(limitOrFixed));
OmniDTO dto = execute(inputs, processorType, processorName);
TableData td = dto.getTableData(processorName);
if (limitOrFixed != DataProcessor.NO_ROW_LIMIT) {
boolean requireFixed = Util.getBooleanValue(inputs, DataProcessor.input_key_records_fixed, false);
if (requireFixed) {
if (td.getTableSize() != 0 && td.getTableSize() != limitOrFixed) {
throw new UnexpectedDataException("Failed to retrieveRows for '" +
processorName + "': required only " +
limitOrFixed + " but retrieved " + td.getTableSize() + ".");
}
}
else {
if (td.getTableSize() > limitOrFixed) {
throw new UnexpectedDataException("Failed to retrieveRows for '" +
processorName + "': required limit at most " +
limitOrFixed + " but retrieved " + td.getTableSize() + ".");
}
}
}
return td;
}
/**
* Insert data to database.
*
* @param inputs Map of input data
* @param processorType A named SQL or direct SQL or stored procedure
* @param processorName SQL name or SQL itself or stored procedure name
* @throws com.scooterframework.orm.sqldataexpress.exception.BaseSQLException
*/
public void insert(Map<String, Object> inputs, String processorType, String processorName)
throws BaseSQLException {
execute(inputs, processorType, processorName);
}
/**
* Delete data from database.
*
* @param inputs Map of input data
* @param processorType A named SQL or direct SQL or stored procedure
* @param processorName SQL name or SQL itself or stored procedure name
* @return int number of rows deleted
* @throws com.scooterframework.orm.sqldataexpress.exception.BaseSQLException
*/
public int delete(Map<String, Object> inputs, String processorType, String processorName)
throws BaseSQLException {
OmniDTO dto = execute(inputs, processorType, processorName);
return dto.getUpdatedRowCount();
}
/**
* Update data in database.
*
* @param inputs Map of input data
* @param processorType A named SQL or direct SQL or stored procedure
* @param processorName SQL name or SQL itself or stored procedure name
* @return int number of rows updated
* @throws com.scooterframework.orm.sqldataexpress.exception.BaseSQLException
*/
public int update(Map<String, Object> inputs, String processorType, String processorName)
throws BaseSQLException {
OmniDTO dto = execute(inputs, processorType, processorName);
return dto.getUpdatedRowCount();
}
private TransactionManager getTransactionManager() {
return TransactionManagerUtil.getTransactionManager();
}
/**
* Find or create a new connection
*
* @param inputs Map of inputs
* @return UserDatabaseConnection object
*/
private UserDatabaseConnection findOrCreateConnection(Map<String, Object> inputs) {
UserDatabaseConnection udc = null;
DatabaseConnectionContext dcc =
(DatabaseConnectionContext)inputs.get(DataProcessor.input_key_database_connection_context);
String connectionName = (String)inputs.get(DataProcessor.input_key_database_connection_name);
if (dcc != null && connectionName != null) {
throw new IllegalArgumentException("You cannot have both connection name and dcc in the same inputs map.");
}
else {
if (dcc != null) {
udc = getConnection(dcc);
}
else if (connectionName != null) {
udc = getConnection(connectionName);
}
else {
udc = getConnection();
}
}
return udc;
}
/**
* Find or create a new connection
*
* @param ip InputInfo object
* @return UserDatabaseConnection object
*/
private UserDatabaseConnection findOrCreateConnection(InputInfo ip) {
UserDatabaseConnection udc = null;
DatabaseConnectionContext dcc = ip.getDatabaseConnectionContext();
String connectionName = ip.getConnectionName();
if (dcc != null && connectionName != null) {
throw new IllegalArgumentException("You cannot have both connection name and dcc in the same InputInfo object.");
}
else {
if (dcc != null) {
udc = getConnection(dcc);
}
else if (connectionName != null) {
udc = getConnection(connectionName);
}
else {
udc = getConnection();
}
}
return udc;
}
/**
* Get a database connection.
*
* A transaction must have been started before this method is called.
*
* @return UserDatabaseConnection represents the DB connection.
* @exception BaseSQLException
*/
private UserDatabaseConnection getConnection()
throws BaseSQLException {
UserDatabaseConnection conn = null;
try {
Transaction ts = getTransactionManager().getTransaction();
if (ts == null || !ts.isTransactionStarted()) {
throw new TransactionException("getConnection() failed: no started transaction.");
}
conn = ts.getConnection();
if (conn == null) throw new CreateConnectionFailureException("getConnection() failed to create a connection.");
}
catch(CreateConnectionFailureException ccfex) {
throw new BaseSQLException(ccfex);
}
catch(Exception ex) {
throw new BaseSQLException(ex);
}
return conn;
}
/**
* Get a database connection based on connection name.
*
* A transaction must have been started before this method is called.
*
* @return UserDatabaseConnection represents the DB connection.
* @exception BaseSQLException
*/
private UserDatabaseConnection getConnection(String connectionName)
throws BaseSQLException {
UserDatabaseConnection conn = null;
try {
Transaction ts = getTransactionManager().getTransaction();
if (ts == null || !ts.isTransactionStarted()) {
throw new TransactionException("getConnection() failed: no started transaction.");
}
conn = ts.getConnection(connectionName);
if (conn == null) throw new CreateConnectionFailureException("getConnection() failed to create a connection.");
}
catch(CreateConnectionFailureException ccfex) {
throw new BaseSQLException(ccfex);
}
catch(Exception ex) {
throw new BaseSQLException(ex);
}
return conn;
}
/**
* Get a database connection based on connection context.
*
* A transaction must have been started before this method is called.
*
* @return UserDatabaseConnection represents the DB connection.
* @exception BaseSQLException
*/
private UserDatabaseConnection getConnection(DatabaseConnectionContext dcc)
throws BaseSQLException {
UserDatabaseConnection conn = null;
try {
Transaction ts = getTransactionManager().getTransaction();
if (ts == null || !ts.isTransactionStarted()) {
throw new TransactionException("getConnection() failed: no started transaction.");
}
conn = ts.getConnection(dcc);
if (conn == null) throw new CreateConnectionFailureException("getConnection() failed to create a connection.");
}
catch(CreateConnectionFailureException ccfex) {
throw new BaseSQLException(ccfex);
}
catch(Exception ex) {
throw new BaseSQLException(ex);
}
return conn;
}
/**
* execute with output filter
*/
private OmniDTO executeKeepConnection(UserDatabaseConnection udc,
Map<String, Object> inputs, String processorType, String processorName, Map<String, String> outputFilters)
throws BaseSQLException {
if (udc == null)
throw new IllegalArgumentException("UserDatabaseConnection object is null.");
if (processorType == null || processorName == null)
throw new IllegalArgumentException("processorType or processorName is null.");
cleanUpInputs(inputs);
if (inputs == null) inputs = new HashMap<String, Object>();
OmniDTO returnTO = null;
try {
DataProcessor dp = DataProcessorFactory.getInstance().getDataProcessor(udc, processorType, processorName);
returnTO = dp.execute(udc, convertKeyCase(inputs), outputFilters);
if (returnTO != null) {
returnTO.setProcessorType(processorType);
returnTO.setProcessorName(processorName);
}
}
catch(UnsupportedDataProcessorTypeException udptEx) {
throw new BaseSQLException("Unsupported DataProcessor Type: " + processorType);
}
catch(UnsupportedDataProcessorNameException udpnEx) {
throw new BaseSQLException("Unsupported DataProcessor Name: " + processorName);
}
catch(UnsupportedStoredProcedureAPINameException udpnEx) {
throw new BaseSQLException("Unsupported DataProcessor Name: " + processorName);
}
return returnTO;
}
private void cleanUpInputs(Map<String, Object> inputs) {
if (inputs == null) return;
//inputs.remove("__sitemesh__filterapplied");
}
private Map<String, Object> convertKeyCase(Map<String, Object> map) {
Map<String, Object> newMap = new HashMap<String, Object>();
newMap.putAll(map);
for (Map.Entry<String, Object> entry : map.entrySet()) {
String key = entry.getKey();
if (key.equals(ActiveRecordConstants.key_finder_sql)) continue;
newMap.put(key.toUpperCase(), entry.getValue());
}
return newMap;
}
private String populateChildInputs(int rowIndex, Map<String, Object> childInputs, RowData parent, String childQuery) {
String newQuery = childQuery;
Map<String, Object> newInputs = new HashMap<String, Object>();
for (Map.Entry<String, Object> entry :childInputs.entrySet()) {
String key = entry.getKey();
if (key.startsWith("&")) {
String fkName = key.substring(1);
String parentKeyName = (String)entry.getValue();
if (parentKeyName != null) {
parentKeyName = parentKeyName.toUpperCase();
String keyInQuery = "?" + fkName;
if (childQuery.indexOf(keyInQuery) != -1) {
Object parentData = parent.getField(parentKeyName);
String newKeyName = fkName + "_" + rowIndex;
newInputs.put(newKeyName, parentData);
newQuery = StringUtil.replace(newQuery, keyInQuery, "?" + newKeyName);
}
}
}
}
childInputs.putAll(newInputs);
return newQuery;
}
//return a string like this: (?fkName1_rowIndex1, ?fkName2_rowIndex2, ...)
private String populateConditionPart2(int rowIndex, InputInfo childIp, RowData parent) {
String part = "(";
List<String> fkNames = childIp.getFKs();
if (fkNames != null && fkNames.size() > 0) {
Map<String, Object> newInputs = new HashMap<String, Object>();
Map<String, Object> childInputs = childIp.getInputs();
for (String fkName : fkNames) {
String parentKeyName = (String)childInputs.get("&"+fkName);
Object parentData = parent.getField(parentKeyName);
String newKeyName = fkName + "_" + rowIndex;
newInputs.put(newKeyName, parentData);
part = part + "?" + newKeyName + getColumnSqlDataTypeName(parentKeyName, parent) + ",";
}
childInputs.putAll(newInputs);
//remove the last comma
if (part.endsWith(",")) part = part.substring(0, part.lastIndexOf(','));
part = part + ")";
}
return part;
}
private String getColumnSqlDataTypeName(String parentKeyName, RowData parent) {
String sqlDataTypeName = "";
RowInfo ri = parent.getRowInfo();
if (ri != null) {
sqlDataTypeName = ri.getColmnDataTypeName(ri.getColumnPositionIndex(parentKeyName));
}
if (sqlDataTypeName != null && !sqlDataTypeName.equals(""))
sqlDataTypeName = ":" + sqlDataTypeName;
return sqlDataTypeName;
}
private void linkParentWithChild(TableData parentRt, TableData childRt, String processorName, List<String> connectorList) {
if(parentRt == null || childRt == null || childRt.getTableSize() == 0) return;
int size = parentRt.getAllRows().size();
Map<String, Object> connectorMap = new HashMap<String, Object>();
for (int i = 0; i < size; i++) {
RowData parentRow = parentRt.getRow(i);
populateConnectorMap(connectorMap, parentRow, connectorList);
parentRow.addChildRowToMap(processorName, getMatchingRowDataList(connectorMap, childRt));
//clear the map for next row
connectorMap.clear();
}
}
private void populateConnectorMap(Map<String, Object> connectorMap, RowData parentRow, List<String> connectorList) {
for (String key : connectorList) {
connectorMap.put(key, parentRow.getField(key));
}
}
private List<RowData> getMatchingRowDataList(Map<String, Object> connectorMap, TableData childRt) {
List<RowData> filteredList = new ArrayList<RowData>();
boolean allPassed = true;
int size = childRt.getTableSize();
for (int i=0; i<size; i++) {
RowData child = childRt.getRow(i);
for (Map.Entry<String, Object> entry :connectorMap.entrySet()) {
String key = entry.getKey();
Object keyData = entry.getValue();
Object rowData = child.getField(key);
if (rowData == null || !rowData.toString().equalsIgnoreCase(keyData.toString())) {
allPassed = false;
break;
}
}
if (allPassed) {
filteredList.add(child);
}
allPassed = true;
}
return filteredList;
}
private String getNewChildQuery(String query, InputInfo childIp, List<RowData> parentRows) {
if (query == null || childIp == null ||
parentRows == null || parentRows.size() == 0)
return query;//nothing need to be changed.
//query = SqlUtil.convertToUpperCase(query);
String childQuery = query;
//generate a child query as union
if (InputInfo.CONSTRUCT_CHILD_QUERY_THRU_UNION.equals(childIp.getChildQueryType())) {
int size = parentRows.size();
if (size > 0) {
int rowIndex = 0;
for (int i = 0; i < size -1; i++) {
rowIndex = i;
RowData parentRow = parentRows.get(i);
childQuery += populateChildInputs(rowIndex, childIp.getInputs(), parentRow, query) + " UNION ";
}
//last row
rowIndex = size -1;
RowData parentRow = (RowData)parentRows.get(rowIndex);
childQuery += populateChildInputs(rowIndex, childIp.getInputs(), parentRow, query);
}
}
else
if (InputInfo.CONSTRUCT_CHILD_QUERY_MAKE_NEW_WHERE_CLAUSE.equals(childIp.getChildQueryType())) {
int size = parentRows.size();
if (size > 0) {
String conditionPart1 = "(" + childIp.getFKString() + ") in ";
String conditionPart2 = "";
int rowIndex = 0;
for (int i = 0; i < size -1; i++) {
rowIndex = i;
RowData parentRow = parentRows.get(i);
conditionPart2 += populateConditionPart2(rowIndex, childIp, parentRow) + ", ";
}
//last row
rowIndex = size -1;
RowData parentRow = parentRows.get(rowIndex);
conditionPart2 += populateConditionPart2(rowIndex, childIp, parentRow);
childQuery += " WHERE " + conditionPart1 + "(" + conditionPart2 + ")";
}
}
else
if (InputInfo.CONSTRUCT_CHILD_QUERY_ADD_TO_WHERE_CLAUSE.equals(childIp.getChildQueryType())) {
int size = parentRows.size();
if (size > 0) {
String conditionPart1 = "(" + childIp.getFKString() + ") in ";
String conditionPart2 = "";
int rowIndex = 0;
for (int i = 0; i < size -1; i++) {
rowIndex = i;
RowData parentRow = (RowData)parentRows.get(i);
conditionPart2 += populateConditionPart2(rowIndex, childIp, parentRow) + ", ";
}
//last row
rowIndex = size -1;
RowData parentRow = (RowData)parentRows.get(rowIndex);
conditionPart2 += populateConditionPart2(rowIndex, childIp, parentRow);
childQuery += " AND " + conditionPart1 + "(" + conditionPart2 + ")";
}
}
return childQuery;
}
private LogUtil log = LogUtil.getLogger(this.getClass().getName());
}