package net.codjo.segmentation.server.plugin;
import net.codjo.expression.ExpressionManager;
import net.codjo.expression.FindUses;
import net.codjo.expression.InvalidExpressionException;
import net.codjo.mad.common.structure.SqlUtil;
import net.codjo.mad.server.handler.HandlerCommand;
import net.codjo.mad.server.handler.HandlerException;
import net.codjo.segmentation.server.participant.context.ContextManager;
import net.codjo.segmentation.server.preference.family.RowFilter;
import net.codjo.segmentation.server.preference.family.TableMetaData;
import net.codjo.segmentation.server.preference.family.VarField;
import net.codjo.segmentation.server.preference.family.XmlFamilyPreference;
import net.codjo.segmentation.server.util.CompilationUtil;
import net.codjo.segmentation.server.util.CompilationUtil.CyclicVariableException;
import net.codjo.segmentation.server.util.SegmentationUtil;
import net.codjo.sql.builder.DefaultFieldInfoList;
import net.codjo.sql.builder.JoinKey;
import net.codjo.sql.builder.JoinKeyExpression;
import net.codjo.sql.builder.OrderByField;
import net.codjo.sql.builder.QueryBuilder;
import net.codjo.sql.builder.QueryBuilderFactory;
import net.codjo.sql.builder.QueryConfig;
import net.codjo.variable.UnknownVariableException;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Statement;
import java.sql.Types;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
*
*/
public class ExpressionCompilerCommand extends HandlerCommand {
private static final String VAR = "VAR_";
private ContextManager contextManager;
public ExpressionCompilerCommand(ContextManager contextManager) {
this.contextManager = contextManager;
}
@Override
public CommandResult executeQuery(CommandQuery query) throws SQLException, HandlerException {
query.checkRequiredArguments("expression", "familyId");
try {
executeImpl(query);
return createEmptyResult();
}
catch (Exception e) {
throw new HandlerException(e);
}
}
private void executeImpl(CommandQuery query)
throws CompilationException, SQLException, CyclicVariableException, UnknownVariableException,
InvalidExpressionException {
String expressionToCompile = query.getArgumentString("expression");
String familyId = query.getArgumentString("familyId");
expressionToCompile = CompilationUtil.replaceVariables(expressionToCompile,
getContext().getConnection());
XmlFamilyPreference familyPreference = contextManager.getFamilyPreference(familyId);
if (familyPreference.getTableMetaData() == null) {
TableMetaData tableMetaData = TableMetaData.create(familyPreference.getDestinationTable(),
getContext().getConnection());
familyPreference.setTableMetaData(tableMetaData);
}
ExpressionManager expressionManager = new ExpressionManager(familyPreference.createFunctionManager());
expressionManager.setExpressionManagerName(expressionToCompile);
Map<String, Integer> varColumn = new HashMap<String, Integer>();
expressionManager.setVarColumn(varColumn);
findVariablesColumnType(expressionToCompile, familyPreference, varColumn);
Map<String, Integer> sourceColumn = new HashMap<String, Integer>();
expressionManager.setSourceColumn(sourceColumn);
Map<String, Integer> destColumn = new HashMap<String, Integer>();
expressionManager.setDestColumn(destColumn);
FindUses findUses = new FindUses();
findUses.add(expressionToCompile);
Collection usedSourceColumns = findUses.buildReport().getUsedSourceColumns();
if (!usedSourceColumns.isEmpty()) {
//noinspection unchecked
findSourceColumnType(familyPreference, sourceColumn, new ArrayList<String>(usedSourceColumns));
}
destColumn.put("DEST_FIELD", Types.BIT);
expressionManager.add("DEST_FIELD", expressionToCompile);
expressionManager.compileExpressions();
}
private void findVariablesColumnType(String expressionToCompile,
XmlFamilyPreference familyPreference,
Map<String, Integer> varColumn) throws InvalidExpressionException {
FindUses findVarUses = new FindUses(VAR);
findVarUses.add(expressionToCompile);
//noinspection unchecked
Collection<String> usedVarColumns = findVarUses.buildReport().getUsedSourceColumns();
for (String usedVarColumn : usedVarColumns) {
for (VarField variable : familyPreference.getVariables()) {
if (variable.getName().equals(VAR + usedVarColumn)) {
int sqlType = new SqlUtil().stringToSqlType(variable.getSqlType());
varColumn.put(VAR + usedVarColumn, sqlType);
}
}
}
}
private void findSourceColumnType(XmlFamilyPreference familyPreference,
Map<String, Integer> sourceColumn,
List<String> usedSourceColumns)
throws UnknownVariableException, SQLException {
QueryBuilder builder = QueryBuilderFactory.newSelectQueryBuilder(
new QueryConfigWithoutWhereClause(familyPreference.getSelectConfig()));
List<String> fields = new ArrayList<String>(usedSourceColumns);
if (familyPreference.hasFilter()) {
RowFilter filter = familyPreference.getFilter();
fields.add(SegmentationUtil.determineFullColumnName(filter.getTableName(),
filter.getColumnName()));
}
String selectQuery = SegmentationUtil.buildSelectQuery(builder,
fields,
Collections.<String, String>emptyMap(),
new DefaultFieldInfoList());
Statement statement = getContext().getConnection().createStatement();
try {
ResultSet resultSet = statement.executeQuery(selectQuery);
ResultSetMetaData metaData = resultSet.getMetaData();
for (int i = 0; i < usedSourceColumns.size(); i++) {
sourceColumn.put(usedSourceColumns.get(i), metaData.getColumnType(i + 1));
}
}
finally {
statement.close();
}
}
private static class QueryConfigWithoutWhereClause implements QueryConfig {
private final QueryConfig selectConfig;
private QueryConfigWithoutWhereClause(QueryConfig selectConfig) {
this.selectConfig = selectConfig;
}
public Map<String, JoinKey> getJoinKeyMap() {
return selectConfig.getJoinKeyMap();
}
public String getRootTableName() {
return selectConfig.getRootTableName();
}
public JoinKeyExpression getRootExpression() {
return new JoinKeyExpression();
}
public OrderByField[] getOrderByFields() {
return new OrderByField[0];
}
}
}