// ============================================================================
//
// Copyright (C) 2006-2016 Talend Inc. - www.talend.com
//
// This source code is available under agreement available at
// %InstallDIR%\features\org.talend.rcp.branding.%PRODUCTNAME%\%PRODUCTNAME%license.txt
//
// You should have received a copy of the agreement
// along with this program; if not, write to Talend SA
// 9 rue Pages 92150 Suresnes, France
//
// ============================================================================
package org.talend.dq.analysis.persistent;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.ArrayList;
import java.util.List;
import org.apache.commons.lang.StringUtils;
import routines.system.IPersistableComparableLookupRow;
import routines.system.IPersistableRow;
/**
* created by zhao on Oct 14, Represent a match row that be able to comparable and being lookup with persistent manager.
*
*/
@SuppressWarnings("rawtypes")
public class MatchRow implements IPersistableComparableLookupRow, IPersistableRow {
private final int DEFAULT_HASHCODE = BlockKey.DEFAULT_HASHCODE;
private final int PRIME = BlockKey.PRIME;
private int hashCode = DEFAULT_HASHCODE;
public boolean hashCodeDirty = true;
private byte[] byteArrays = new byte[0];
private static byte[] byteArraysLock = new byte[0];
private List<String> blockKeyList = new ArrayList<String>();
private List<String> rowList = new ArrayList<String>();
private int fieldCount = 0;
private int blockFieldCount = 0;
/**
*
* Construct a match row instance with the record feild size and block feild size.
*
* @param recordFieldCount
* @param blockFieldCount
*/
public MatchRow(int recordFieldCount, int blockFieldCount) {
this.fieldCount = recordFieldCount;
this.blockFieldCount = blockFieldCount;
}
/**
* Getter for row.
*
* @return the row
*/
public List<String> getRow() {
return new ArrayList<String>(rowList);
}
/**
*
* Get row with blocking key.
*
* @return
*/
public List<String> getRowWithBlockKey() {
List<String> rowWithBlockKeyList = new ArrayList<String>(rowList);
if (blockKeyList.size() != 0) {
String joinedBlockKey = StringUtils.join(blockKeyList.toArray(new String[blockKeyList.size()]));
rowWithBlockKeyList.add(joinedBlockKey);
} else {
rowWithBlockKeyList.add(StringUtils.EMPTY);
}
return rowWithBlockKeyList;
}
/**
* Sets the row.
*
* @param row the row to set
*/
public void setRow(List<String> rowList) {
this.rowList = new ArrayList<String>(rowList);
}
/**
* Sets the key.
*
* @param key the key to set
*/
public void setKey(List<String> key) {
blockKeyList = new ArrayList<String>(key);
}
/**
* Getter for key.
*
* @return the key
*/
public List<String> getKey() {
return new ArrayList<String>(blockKeyList);
}
@Override
public int hashCode() {
if (this.hashCodeDirty) {
final int prime = PRIME;
int result = DEFAULT_HASHCODE;
for (String bk : blockKeyList) {
result = prime * result + (bk == null ? 0 : bk.hashCode());
}
this.hashCode = result;
this.hashCodeDirty = false;
}
return this.hashCode;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final MatchRow other = (MatchRow) obj;
int bkIndex = 0;
List<String> otherBlockKeys = other.getKey();
for (String bk : blockKeyList) {
if (bk == null) {
if (otherBlockKeys.get(bkIndex) != null) {
return false;
}
} else if (!bk.equals(otherBlockKeys.get(bkIndex))) {
return false;
}
bkIndex++;
}
return true;
}
public void writeKeysData(ObjectOutputStream out) {
for (String bk : blockKeyList) {
try {
PersistentRowHelper.writeString(bk, out);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
public void readKeysData(ObjectInputStream in) {
synchronized (byteArraysLock) {
try {
for (int i = 0; i < blockFieldCount; i++) {
if (i == 0) {
blockKeyList.clear();
}
blockKeyList.add(PersistentRowHelper.readString(byteArrays, in));
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
/*
* (non-Javadoc)
*
* @see routines.system.IPersistableLookupRow#writeValuesData(java.io.DataOutputStream, java.io.ObjectOutputStream)
*/
public void writeValuesData(DataOutputStream dataOut, ObjectOutputStream objectOut) {
for (String value : rowList) {
try {
PersistentRowHelper.writeString(value, dataOut);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
/*
* (non-Javadoc)
*
* @see routines.system.IPersistableLookupRow#readValuesData(java.io.DataInputStream, java.io.ObjectInputStream)
*/
public void readValuesData(DataInputStream dataIn, ObjectInputStream objectIn) {
try {
for (int i = 0; i < fieldCount; i++) {
if (i == 0) {
// Here is magic line that resolve a bug from persistent API.
rowList.clear();
}
rowList.add(PersistentRowHelper.readString(dataIn));
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
/*
* (non-Javadoc)
*
* @see routines.system.IPersistableLookupRow#copyKeysDataTo(java.lang.Object)
*/
public void copyKeysDataTo(Object other) {
((MatchRow) other).blockKeyList = new ArrayList<String>(blockKeyList);
}
/*
* (non-Javadoc)
*
* @see java.lang.Comparable#compareTo(java.lang.Object)
*/
public int compareTo(Object other) {
int returnValue = -1;
int idx = 0;
List<String> otherBlockKeys = ((MatchRow) other).getKey();
for (String bk : blockKeyList) {
returnValue = PersistentRowHelper.checkNullsAndCompare(bk, otherBlockKeys.get(idx));
if (returnValue != 0) {
return returnValue;
}
idx++;
}
return returnValue;
}
/*
* (non-Javadoc)
*
* @see routines.system.IPersistableLookupRow#copyDataTo(java.lang.Object)
*/
public void copyDataTo(Object other) {
((MatchRow) other).rowList = new ArrayList<String>(rowList);
}
/*
* (non-Javadoc)
*
* @see java.lang.Object#toString()
*/
@SuppressWarnings("nls")
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("row [");
for (String value : rowList) {
sb.append(";" + value);
}
sb.append("]");
return sb.toString();
}
/*
* (non-Javadoc)
*
* @see routines.system.IPersistableRow#writeData(java.io.ObjectOutputStream)
*/
public void writeData(ObjectOutputStream out) {
writeValuesData(new DataOutputStream(out), out);
}
/*
* (non-Javadoc)
*
* @see routines.system.IPersistableRow#readData(java.io.ObjectInputStream)
*/
public void readData(ObjectInputStream in) {
readValuesData(new DataInputStream(in), in);
}
}