quickfix.Message.toXML()
反復ロジックに基づく実装。比較の結果は、複合キー(フィールドがグループの一部である場合)と「前」と「後」の状態のペアのソートされたマップです。
import static java.lang.Math.min;
import static java.util.Collections.emptySet;
import static java.util.stream.Collectors.toList;
import static org.apache.commons.collections4.CollectionUtils.subtract;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.TreeMap;
import org.apache.commons.lang3.tuple.ImmutablePair;
import org.apache.commons.lang3.tuple.Pair;
import quickfix.Field;
import quickfix.FieldMap;
import quickfix.Group;
import quickfix.Message;
public class FixDiff {
private static final CompositeKeyComparator COMPARATOR = new CompositeKeyComparator();
private Set<Integer> ignored;
public FixDiff() {
this(emptySet());
}
public FixDiff(Set<Integer> ignored) {
this.ignored = ignored;
}
public Map<List<Integer>, Pair<String, String>> compare(Message expected, Message actual) {
Map<List<Integer>, String> expectedMap = toHierarchialMap(expected);
Map<List<Integer>, String> actualMap = toHierarchialMap(actual);
Collection<List<Integer>> missing = subtract(expectedMap.keySet(), actualMap.keySet());
Collection<List<Integer>> extra = subtract(actualMap.keySet(), expectedMap.keySet());
Collection<List<Integer>> diff = expectedMap.entrySet().stream()
.filter(e -> !missing.contains(e.getKey()) && !extra.contains(e.getKey()))
.filter(e -> !e.getValue().equals(actualMap.get(e.getKey())))
.map(Entry::getKey)
.collect(toList());
TreeMap<List<Integer>, Pair<String, String>> discrepancies = new TreeMap<List<Integer>, Pair<String, String>>(COMPARATOR);
missing.forEach(key -> discrepancies.put(key, new ImmutablePair<String, String>(expectedMap.get(key), null)));
extra.forEach(key -> discrepancies.put(key, new ImmutablePair<String, String>(null, actualMap.get(key))));
diff.forEach(key -> discrepancies.put(key, new ImmutablePair<String, String>(expectedMap.get(key), actualMap.get(key))));
return discrepancies;
}
private Map<List<Integer>, String> toHierarchialMap(Message message) {
Map<List<Integer>, String> result = new HashMap<List<Integer>, String>();
toHierarchialMap(result, new ArrayList<Integer>(), message.getHeader());
toHierarchialMap(result, new ArrayList<Integer>(), message);
toHierarchialMap(result, new ArrayList<Integer>(), message.getTrailer());
return result;
}
private void toHierarchialMap(Map<List<Integer>, String> map, ArrayList<Integer> segmentKey, FieldMap segment) {
Iterator<Field<?>> iterator = segment.iterator();
while (iterator.hasNext()) {
Field<?> field = iterator.next();
if (!ignored.contains(field.getTag()) && field.getObject() != null)
map.put(compositeKey(segmentKey, field.getTag()), field.getObject().toString());
}
Iterator<Integer> groupKeyIterator = segment.groupKeyIterator();
while (iterator.hasNext()) {
Integer groupKey = groupKeyIterator.next();
if (ignored.contains(groupKey))
continue;
for (Group group : segment.getGroups(groupKey))
toHierarchialMap(map, compositeKey(segmentKey, groupKey), group);
}
}
private ArrayList<Integer> compositeKey(ArrayList<Integer> parent, Integer tag) {
ArrayList<Integer> copy = new ArrayList<>(parent);
copy.add(tag);
return copy;
}
private static class CompositeKeyComparator implements Comparator<List<Integer>> {
@Override
public int compare(List<Integer> o1, List<Integer> o2) {
for (int i = 0; i < min(o1.size(), o2.size()); i++) {
if (o1.get(i) != o2.get(i))
return o1.get(i) - o2.get(i);
}
return o1.size() - o2.size();
}
}
}