* {@inheritDoc}
*/
public void run() {
try {
EntityContainerComparator comparator;
EntityContainer entityContainer0 = null;
EntityContainer entityContainer1 = null;
// Create a comparator for comparing two entities by type and identifier.
comparator = new EntityContainerComparator(new EntityByTypeThenIdComparator());
// We can't get meaningful data from the initialize data on the
// input streams, so pass empty meta data to the sink and discard
// the input meta data.
postbox0.outputInitialize();
postbox1.outputInitialize();
sink.initialize(Collections.<String, Object>emptyMap());
// BEGIN bound special handling
// If there is a bound, it's going to be the first object
// in a properly sorted stream
entityContainer0 = nextOrNull(postbox0);
entityContainer1 = nextOrNull(postbox1);
// There's only need for special processing if there actually is some data
// on both streams - no data implies no bound
if (entityContainer0 != null && entityContainer1 != null) {
Bound bound0 = null;
Bound bound1 = null;
// If there are any bounds upstream, eat them up
if (entityContainer0.getEntity().getType() == EntityType.Bound) {
bound0 = (Bound) entityContainer0.getEntity();
entityContainer0 = nextOrNull(postbox0);
}
if (entityContainer1.getEntity().getType() == EntityType.Bound) {
bound1 = (Bound) entityContainer1.getEntity();
entityContainer1 = nextOrNull(postbox1);
}
// Only post a bound downstream if both upstream sources had a bound.
// (Otherwise there's either nothing to post or the posted bound is going
// to be smaller than the actual data, which is bad)
if (bound0 != null && bound1 != null) {
sink.process(new BoundContainer(bound0.union(bound1)));
} else if ((bound0 != null && bound1 == null)
|| (bound0 == null && bound1 != null)) {
handleBoundRemoved(bound0 == null);
}
}
// END bound special handling
// We continue in the comparison loop while both sources still have data.
while (
(entityContainer0 != null || postbox0.hasNext())
&& (entityContainer1 != null || postbox1.hasNext())) {
long comparisonResult;
// Get the next input data where required.
if (entityContainer0 == null) {
entityContainer0 = postbox0.getNext();
}
if (entityContainer1 == null) {
entityContainer1 = postbox1.getNext();
}
// Compare the two entities.
comparisonResult = comparator.compare(entityContainer0, entityContainer1);
if (comparisonResult < 0) {
// Entity 0 doesn't exist on the other source and can be
// sent straight through.
sink.process(entityContainer0);
entityContainer0 = null;
} else if (comparisonResult > 0) {
// Entity 1 doesn't exist on the other source and can be
// sent straight through.
sink.process(entityContainer1);
entityContainer1 = null;
} else {
// The entity exists on both sources so we must resolve the conflict.
if (conflictResolutionMethod.equals(ConflictResolutionMethod.Timestamp)) {
int timestampComparisonResult;
timestampComparisonResult =
entityContainer0.getEntity().getTimestamp()
.compareTo(entityContainer1.getEntity().getTimestamp());
if (timestampComparisonResult < 0) {
sink.process(entityContainer1);
} else if (timestampComparisonResult > 0) {
sink.process(entityContainer0);
} else {
// If both have identical timestamps, use the second source.
sink.process(entityContainer1);
}
} else if (conflictResolutionMethod.equals(ConflictResolutionMethod.LatestSource)) {
sink.process(entityContainer1);
} else if (conflictResolutionMethod.equals(ConflictResolutionMethod.Version)) {
int version0 = entityContainer0.getEntity().getVersion();
int version1 = entityContainer1.getEntity().getVersion();
if (version0 < version1) {
sink.process(entityContainer1);
} else if (version0 > version1) {
sink.process(entityContainer0);
} else {