/**
* Alipay.com Inc.
* Copyright (c) 2004-2012 All Rights Reserved.
*/
package com.alipay.zdal.rule.ruleengine.rule;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Map.Entry;
import org.apache.log4j.Logger;
import com.alipay.zdal.common.lang.StringUtil;
import com.alipay.zdal.common.sqljep.function.Comparative;
import com.alipay.zdal.rule.ruleengine.cartesianproductcalculator.CartesianProductCalculator;
import com.alipay.zdal.rule.ruleengine.cartesianproductcalculator.SamplingField;
import com.alipay.zdal.rule.ruleengine.enumerator.Enumerator;
import com.alipay.zdal.rule.ruleengine.enumerator.EnumeratorImp;
import com.alipay.zdal.rule.ruleengine.util.RuleUtils;
/**
* �������һ�����Ĺ���
*
*
*/
public abstract class CartesianProductBasedListResultRule extends ListAbstractResultRule {
private static final Logger log = Logger
.getLogger(CartesianProductBasedListResultRule.class);
Enumerator enumerator = new EnumeratorImp();
/**
* �Ƿ���Ҫ�Խ����ڵ�����ȡ������
*
* @see com.alipay.zdal.rule.ruleengine.rule.ListAbstractResultRule#eval(java.util.Map)
*/
public Map<String/*�����ֵ����db��index��table��index */, Field> eval(
Map<String, Comparative> argumentsMap) {
Map<String, Set<Object>> enumeratedMap = prepareEnumeratedMap(argumentsMap);//������㼯��
if (log.isDebugEnabled()) {
log.debug("Sampling filed message : " + enumeratedMap);
}
Map<String, Field> map = evalElement(enumeratedMap);
decideWhetherOrNotToThrowSpecEmptySetRuntimeException(map);//�����Ƿ��׳�runtimeException
return map;
}
/**
* �����Ƿ��׳�runtimeException
*
* @param map
*/
private void decideWhetherOrNotToThrowSpecEmptySetRuntimeException(Map<String, Field> map) {
if ((map == null || map.isEmpty()) && ruleRequireThrowRuntimeExceptionWhenSetIsEmpty()) {
throw new EmptySetRuntimeException();
}
}
/**
* TODO:���Ҫ�ᵽ�������
* @param argumentsMap
* @return
*/
public Map<String, Set<Object>> prepareEnumeratedMap(Map<String, Comparative> argumentsMap) {
if (log.isDebugEnabled()) {
log.debug("eval at CartesianProductRule ,param is " + argumentsMap);
}
Map<String/* column */, Set<Object>/* ��� */> enumeratedMap = RuleUtils.getSamplingField(
argumentsMap, parameters);
return enumeratedMap;
}
/**
* @see com.alipay.zdal.rule.ruleengine.rule.ListAbstractResultRule#evalWithoutSourceTrace(java.util.Map, java.lang.String, java.util.Set)
*/
public Set<String> evalWithoutSourceTrace(Map<String, Set<Object>> enumeratedMap,
String mappingTargetColumn, Set<Object> mappingKeys) {
// Set<String> set = null;
if (enumeratedMap.size() == 0) {
return evalZeroArgumentExpression();
} else if (enumeratedMap.size() == 1) {
return evalOneArgumentExpression(enumeratedMap, mappingTargetColumn, mappingKeys);
} else {
return evalMutiargumentsExpression(enumeratedMap, mappingTargetColumn, mappingKeys);
}
}
private Set<String> evalMutiargumentsExpression(Map<String, Set<Object>> enumeratedMap,
String mappingTargetColumn,
Set<Object> mappingKeys) {
Set<String> set;
if (mappingTargetColumn != null || mappingKeys != null) {
throw new IllegalArgumentException("����ö�ٲ�֧��ʹ��ӳ�����");
}
// TODO:�õ����ֵ��ͬ�����ֿ��ֱ��ʱ����Ҫreview
// ����һ��ֵ����Ҫ���еѿ�����
CartesianProductCalculator cartiesianProductCalculator = new CartesianProductCalculator(
enumeratedMap);
/*
* ȷʵ����ȷ��set�Ĵ�С����һ����˵�ֿ���16������������Ͷ�16����ʱ������һ�ֿ��ܵĿ����ǽ�
* capacity����Ϊ�����ܳ��ֵĽ����
*/
set = new HashSet<String>(16);
for (SamplingField samplingField : cartiesianProductCalculator) {
evalOnceAndAddToReturnSet(set, samplingField, 16);
}
return set;
}
/**
* û�в����������������contextӦ����д��
* @param enumeratedMap
* @param mappingTargetColumn
* @param mappingKeys
* @return
*/
private Set<String> evalZeroArgumentExpression() {
Set<String> set;
// ����һ��ֵ����Ҫ���еѿ�����
List<String> columns = new ArrayList<String>(1);
SamplingField samplingField = new SamplingField(columns, 1);
// ����ֵ���Ҳ�����뺯����x�ĸ������Ӧ
set = new HashSet<String>();
/*
* ���û��ǰ�˴������Ѿ�ӳ��Ľ������ôʹ��sql�л�õĽ������������
*/
evalOnceAndAddToReturnSet(set, samplingField, 0);
if ((set == null || set.isEmpty()) && ruleRequireThrowRuntimeExceptionWhenSetIsEmpty()) {
throw new EmptySetRuntimeException();
}
return set;
}
private Set<String> evalOneArgumentExpression(Map<String, Set<Object>> enumeratedMap,
String mappingTargetColumn,
Set<Object> mappingKeys) {
Set<String> set;
// ����һ��ֵ����Ҫ���еѿ�����
List<String> columns = new ArrayList<String>(1);
Set<Object> enumeratedValues = null;
for (Entry<String, Set<Object>> entry : enumeratedMap.entrySet()) {
columns.add(entry.getKey());
enumeratedValues = entry.getValue();
}
SamplingField samplingField = new SamplingField(columns, 1);
// ����ֵ���Ҳ�����뺯����x�ĸ������Ӧ
set = new HashSet<String>(enumeratedValues.size());
if (mappingKeys == null) {
/*
* ���û��ǰ�˴������Ѿ�ӳ��Ľ������ôʹ��sql�л�õĽ������������
*/
evalNormal(set, enumeratedValues, samplingField);
} else {
//mappingKeys ��Ϊ�գ���ô֤���ֿ�ʱ�Ѿ�������ӳ�������ô���ж�ӳ����ֵ�Ƿ���ȷ��
//Ȼ��Ҫ����������ʹ��ӳ�������ʹ��sql��������ݣ����������������ȥ��
evalWithMappingKey(mappingTargetColumn, mappingKeys, set, enumeratedValues,
samplingField);
}
if ((set == null || set.isEmpty()) && ruleRequireThrowRuntimeExceptionWhenSetIsEmpty()) {
throw new EmptySetRuntimeException();
}
return set;
}
/**
* ��������Ҫ����������ֿ�ʱ�Ѿ��鵽ӳ������ݣ�
* ��ʹ��ӳ������ݡ�
*
* �б�ı�־��mappingKeys��Ϊ�ա�
*
* @param mappingTargetColumn
* @param mappingKeys
* @param set
* @param enumeratedValues
* @param samplingField
*
*
*/
private void evalWithMappingKey(String mappingTargetColumn, Set<Object> mappingKeys,
Set<String> set, Set<Object> enumeratedValues,
SamplingField samplingField) {
//����targetKey,������������targetKey���Լ���targetKey�ȶԣ���֪�Ƿ�ͷֿ�ʹ����ͬ����targetKey
samplingField.setMappingTargetKey(mappingTargetColumn);
if (mappingKeys.size() == enumeratedValues.size()) {
Iterator<Object> itr = mappingKeys.iterator();
for (Object value : enumeratedValues) {
Object oneTargetKey = itr.next();
samplingField.clear();
samplingField.setMappingValue(oneTargetKey);
samplingField.add(0, value);
evalOnceAndAddToReturnSet(set, samplingField, enumeratedValues.size());
}
} else {
throw new IllegalArgumentException("mappingӳ����targetKeys������IJ�����������,mapping :"
+ mappingKeys + " " + "enumeratedValues is :"
+ enumeratedValues);
}
}
private void evalNormal(Set<String> set, Set<Object> enumeratedValues,
SamplingField samplingField) {
for (Object value : enumeratedValues) {
samplingField.clear();
samplingField.add(0, value);
evalOnceAndAddToReturnSet(set, samplingField, enumeratedValues.size());
}
}
/**
* �����ļ�����̣�����->���������������м��㣬��ȡ���ս����
*
* @param enumeratedMap
* @return ���ص�map����Ϊnull,���п���Ϊ�յ�map�����map��Ϊ�գ����ڲ�����map�ض���Ϊ�ա����ٻ���һ��ֵ
*/
public Map<String/* �����ֵ */, Field> evalElement(Map<String, Set<Object>> enumeratedMap) {
Map<String/* �����ֵ */, Field> map;
if (enumeratedMap.size() == 1) {
// �и�������һ��ֵ����Ҫ���еѿ�����
List<String> columns = new ArrayList<String>(1);
Set<Object> enumeratedValues = null;
for (Entry<String, Set<Object>> entry : enumeratedMap.entrySet()) {
columns.add(entry.getKey());
enumeratedValues = entry.getValue();
}
SamplingField samplingField = new SamplingField(columns, 1);
// ����ֵ���Ҳ�����뺯����x�ĸ������Ӧ
map = new HashMap<String, Field>(enumeratedValues.size());
// Ϊ�����и��������ֶ�
for (Object value : enumeratedValues) {
samplingField.clear();
samplingField.add(0, value);
evalOnceAndAddToReturnMap(map, samplingField, enumeratedValues.size());
}
return map;
}
/**
* ��ʹ��GroovyThreadLocal ��ʽע�����ʱ����Ϊsql��û�ж�Ӧ�����������ߵ����
* �����棬ֱ�Ӹ����û���GroovyThreadLocal��IJ���������õĹ�����м�������طֱ��ֿ�Y��
*/
else if (enumeratedMap.size() == 0) {
List<String> columns = new ArrayList<String>(1);
SamplingField samplingField = new SamplingField(columns, 1);
map = new HashMap<String, Field>(1);
evalOnceAndAddToReturnMap(map, samplingField, 1);
return map;
} else {
//TODO:Ĭ�Ϲرյ�
// TODO:�õ����ֵ��ͬ�����ֿ��ֱ��ʱ����Ҫreview
// ����һ��ֵ����Ҫ���еѿ�����
CartesianProductCalculator cartiesianProductCalculator = new CartesianProductCalculator(
enumeratedMap);
/*
* ȷʵ����ȷ��set�Ĵ�С����һ����˵�ֿ���16������������Ͷ�16����ʱ������һ�ֿ��ܵĿ����ǽ�
* capacity����Ϊ�����ܳ��ֵĽ����
*/
map = new HashMap<String, Field>(16);
for (SamplingField samplingField : cartiesianProductCalculator) {
evalOnceAndAddToReturnMap(map, samplingField, 16);
}
return map;
}
}
/**
* ����ӹ�����Ҫ�ڷ���ֵΪnull��Ϊ��collectionsʱ�׳��쳣����̳д����false��Ϊtrue����
*
* @return
*/
protected boolean ruleRequireThrowRuntimeExceptionWhenSetIsEmpty() {
return false;
}
void evalOnceAndAddToReturnSet(Set<String> set, SamplingField samplingField, int valueSetSize) {
ResultAndMappingKey resultAndMappingKey = evalueateSamplingField(samplingField);
String targetIndex = resultAndMappingKey.result;
//ODOT:�ظ��ж�
if (targetIndex != null) {
set.add(targetIndex);
} else {
throw new IllegalArgumentException("��������Ľ������Ϊnull");
}
}
/**
* ��һ�����ݽ��м���
* ��һ�ι����п��ܷ��ض���⣬����forѭ������
* ֻ�������ݼ����ȡ��ֵ��ʱ��ŻὫ��Ӧ��ֵ��ȡ���кͶ������ڵ�ֵ����map�С�
* @param map
* @param samplingField
* @param valueSetSize
* @Test ���������TairBasedMappingRule�ļ��ɲ��Ժ͵�Ԫ�����ﶼ��
*/
void evalOnceAndAddToReturnMap(Map<String/* �����ֵ */, Field> map, SamplingField samplingField,
int valueSetSize) {
ResultAndMappingKey returnAndMappingKey = evalueateSamplingField(samplingField);
if (returnAndMappingKey != null) {
String dbIndexStr = returnAndMappingKey.result;
if (StringUtil.isBlank(dbIndexStr)) {
throw new IllegalArgumentException("����dbRule������Ľ������Ϊnull");
}
String[] dbIndexes = dbIndexStr.split(",");
for (String dbIndex : dbIndexes) {
List<String> lists = samplingField.getColumns();
List<Object> values = samplingField.getEnumFields();
Field colMap = prepareColumnMap(map, samplingField, dbIndex,
returnAndMappingKey.mappingTargetColumn, returnAndMappingKey.mappingKey);
int index = 0;
for (String column : lists) {
Object value = values.get(index);
Set<Object> set = prepareEnumeratedSet(valueSetSize, colMap, column);
set.add(value);
index++;
}
}
}
}
private Set<Object> prepareEnumeratedSet(int valueSetSize, Field colMap, String column) {
//sourcekey ��ʼ���Ժ���ڲ���set��һֱ����
Set<Object> set = colMap.sourceKeys.get(column);
if (set == null) {
set = new HashSet<Object>(valueSetSize);
colMap.sourceKeys.put(column, set);
}
return set;
}
private Field prepareColumnMap(Map<String, Field> map, SamplingField samplingField,
String targetIndex, String mappngTargetColumn,
Object mappingValue) {
Field colMap = map.get(targetIndex);
if (colMap == null) {
int size = samplingField.getColumns().size();
colMap = new Field(size);
map.put(targetIndex, colMap);
}
if (mappngTargetColumn != null && colMap.mappingTargetColumn == null) {
colMap.mappingTargetColumn = mappngTargetColumn;
}
if (mappingValue != null) {
if (colMap.mappingKeys == null) {
colMap.mappingKeys = new HashSet<Object>();
}
colMap.mappingKeys.add(mappingValue);
}
return colMap;
}
// public Map<String, Set<Object>/* ����������key��ֵ��pair */> getSamplingField(
// Map<String, SharedValueElement> sharedValueElementMap) {
// // TODO:��ϸע��,����ѿ�����
// // ö���Ժ��columns�����ǵ����֮��Ķ�Ӧ��ϵ
// Map<String, Set<Object>> enumeratedMap = new HashMap<String, Set<Object>>(
// sharedValueElementMap.size());
// for (Entry<String, SharedValueElement> entry : sharedValueElementMap
// .entrySet()) {
// SharedValueElement sharedValueElement = entry.getValue();
// String key = entry.getKey();
// // ��ǰenumerator��ָ����ǰ�����Ƿ���Ҫ���������⡣
// // enumerator.setNeedMergeValueInCloseInterval();
//
// try {
// Set<Object> samplingField = enumerator.getEnumeratedValue(
// sharedValueElement.comp,
// sharedValueElement.cumulativeTimes,
// sharedValueElement.atomicIncreaseValue,
// sharedValueElement.needMergeValueInCloseInterval);
// enumeratedMap.put(key, samplingField);
// } catch (UnsupportedOperationException e) {
// throw new UnsupportedOperationException("��ǰ�зֿ�ֱ���ִ����ִ����������:"
// + entry.getKey(), e);
// }
//
// }
// return enumeratedMap;
// }
/**
* ����һ������������һ�����
*
* @return ͨ������Ľ�����������������Ϊnull:
* ӳ�����ԭ������ڣ���ӳ����Ŀ�겻���ڣ��᷵��null��
* ����ʱ�̣������쳣
*
*/
public abstract ResultAndMappingKey evalueateSamplingField(SamplingField samplingField);
}