}
@SuppressWarnings("unchecked")
private OTOperation transform(final OTOperation remoteOp, final OTOperation localOp, final boolean invertWinRule) {
final boolean remoteWins = invertWinRule ? !this.remoteWins : this.remoteWins;
final OTOperation transformedOp;
final List<Mutation> remoteMutations = remoteOp.getMutations();
final List<Mutation> localMutations = localOp.getMutations();
final List<Mutation> transformedMutations = new ArrayList<Mutation>(remoteMutations.size());
final Iterator<Mutation> remoteOpMutations;
final Iterator<Mutation> localOpMutations;
if (remoteMutations.size() > localMutations.size()) {
remoteOpMutations = noopPaddedIterator(remoteMutations, remoteMutations.size());
localOpMutations = noopPaddedIterator(localMutations, remoteMutations.size());
}
else if (remoteMutations.size() < localMutations.size()) {
remoteOpMutations = noopPaddedIterator(remoteMutations, localMutations.size());
localOpMutations = noopPaddedIterator(localMutations, localMutations.size());
}
else {
remoteOpMutations = remoteMutations.iterator();
localOpMutations = localMutations.iterator();
}
int offset = 0;
boolean resolvesConflict = false;
while (remoteOpMutations.hasNext()) {
final Mutation rm = remoteOpMutations.next();
final Mutation lm = localOpMutations.next();
final int rmIdx = rm.getPosition();
final int diff = rmIdx - lm.getPosition();
final TransactionLog transactionLog = entity.getTransactionLog();
if (diff < 0) {
if (rm.getType() == MutationType.Delete) {
if (rm.getPosition() + rm.length() > lm.getPosition()) {
if (lm.getType() == MutationType.Insert) {
// uh-oh.. our local insert is inside the range of this remote delete ... move the insert
// to the beginning of the delete range to resolve this.
final LogQuery effectiveStateForRevision = transactionLog.getEffectiveStateForRevision(localOp.getRevision());
final State rewind = effectiveStateForRevision.getEffectiveState();
localOp.removeFromCanonHistory();
transactionLog.markDirty();
final Mutation mutation = lm.newBasedOn(rm.getPosition());
mutation.apply(rewind);
final OTOperation localOnlyOperation
= createLocalOnlyOperation(engine, remoteOp.getAgentId(), singletonList(mutation), entity, localOp.getRevision(), OpPair.of(remoteOp, localOp));
transactionLog.insertLog(localOp.getRevision(), localOnlyOperation);
entity.getState().syncStateFrom(rewind);