package com.taobao.yugong.common.db;
import java.lang.reflect.Array;
import java.math.BigDecimal;
import java.text.MessageFormat;
import java.util.Date;
import java.util.List;
import org.apache.commons.lang.ObjectUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.SystemUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.taobao.yugong.common.audit.RecordDumper;
import com.taobao.yugong.common.db.meta.ColumnValue;
import com.taobao.yugong.common.model.record.Record;
import com.taobao.yugong.exception.YuGongException;
/**
* 记录对比
*
* @author agapple 2013-9-29 下午2:56:39
*/
public class RecordDiffer {
private static final String SEP = SystemUtils.LINE_SEPARATOR;
private static String record_format = null;
private static final Logger diffLogger = LoggerFactory.getLogger("check");
static {
record_format = SEP + "-----------------" + SEP;
record_format += "- Schema: {0} , Table: {1}" + SEP;
record_format += "-----------------" + SEP;
record_format += "---Pks" + SEP;
record_format += "{2}" + SEP;
record_format += "---diff" + SEP;
record_format += "\t{3}" + SEP;
}
public static void diff(Record record1, Record record2) {
if (record2 == null) {
diffLogger.info(diffMessage(record1.getSchemaName(),
record1.getTableName(),
record1.getPrimaryKeys(),
"record not found"));
return;
}
if (record1.getColumns().size() > record2.getColumns().size()) {
diffLogger.info(diffMessage(record1.getSchemaName(),
record1.getTableName(),
record1.getPrimaryKeys(),
"column size is great than target column size"));
return;
}
StringBuilder diff = new StringBuilder();
boolean same = true;
int size = record1.getColumns().size();
for (int i = 0; i < size; i++) {
ColumnValue column = record1.getColumns().get(i);
same &= campareOneColumn(column, getColumn(record2, column.getColumn().getName()), diff);
}
if (!same) {
diffLogger.info(diffMessage(record1.getSchemaName(),
record2.getTableName(),
record1.getPrimaryKeys(),
diff.toString()));
}
}
private static boolean campareOneColumn(ColumnValue column1, ColumnValue column2, StringBuilder diff) {
if (!column1.isCheck() || !column2.isCheck()) {
return true;// 可能不需要做对比,忽略
}
Object value1 = column1.getValue();
Object value2 = column2.getValue();
if (value1 == null && value2 == null) {
return true;
}
StringBuilder message = new StringBuilder();
message.append(column1.getColumn())
.append(" , values : [")
.append(ObjectUtils.toString(value1))
.append("] vs [")
.append(ObjectUtils.toString(value2))
.append("]\n\t");
if ((value1 == null && value2 != null) || (value1 != null && value2 == null)) {
diff.append(message);
return false;
}
if (!value1.equals(value2)) {
// custom define
if (value1 instanceof java.util.Date && value2 instanceof java.util.Date) {
boolean result = dateValueEquals((java.util.Date) value1, (java.util.Date) value2);
if (!result) {
String v1 = value1.toString();
String v2 = value2.toString();
// 2012-02-02 02:02:02 与 2012-02-02 肯定是一种包含关系
if (v1.contains(v2) || v2.contains(v1)) {
return true;
}
} else {
return true;
}
} else if (Number.class.isAssignableFrom(value1.getClass())
&& Number.class.isAssignableFrom(value2.getClass())) {
String v1 = null;
String v2 = null;
v1 = getNumberString(value1);
v2 = getNumberString(value2);
boolean result = v1.equals(v2);
if (result) {
return true;
}
} else if (value1.getClass().isArray() && value2.getClass().isArray()) {
boolean result = true;
if (Array.getLength(value1) == Array.getLength(value2)) {
int length = Array.getLength(value1);
for (int i = 0; i < length; i++) {
result &= ObjectUtils.equals(Array.get(value1, i), Array.get(value2, i));
}
if (result) {
return true;
}
}
}
// 其他情况为false
diff.append(message);
return false;
} else {
return true;
}
}
private static String getNumberString(Object value1) {
String v1;
if (value1 instanceof BigDecimal) {
v1 = ((BigDecimal) value1).toPlainString();
if (StringUtils.indexOf(v1, ".") != -1) {
v1 = StringUtils.stripEnd(v1, "0");// 如果0是末尾,则删除之
v1 = StringUtils.stripEnd(v1, ".");// 如果.是末尾,则删除之
}
} else {
v1 = value1.toString();
}
return v1;
}
private static boolean dateValueEquals(Date source, Date target) {
return source.getTime() == target.getTime();
}
private static ColumnValue getColumn(Record record, String columnName) {
for (ColumnValue column : record.getColumns()) {
if (StringUtils.equalsIgnoreCase(columnName, column.getColumn().getName())) {
return column;
}
}
throw new YuGongException("column[" + columnName + "] is not found.");
}
private static String diffMessage(String schemaName, String tableName, List<ColumnValue> primaryKeys, String message) {
return MessageFormat.format(record_format,
schemaName,
tableName,
RecordDumper.dumpRecordColumns(primaryKeys),
message);
}
}