/** {@inheritDoc} */ @Override public boolean replayOperation( Iterator<Modification> modsIterator, CSN csn, Entry modifiedEntry, Modification m) { // We are replaying an operation that was already done // on another master server and this operation has a potential // conflict with some more recent operations on this same entry // we need to take the more complex path to solve them if ((CSN.compare(csn, getLastUpdateTime()) < 0) || (m.getModificationType() != ModificationType.REPLACE)) { // the attribute was modified after this change -> conflict switch (m.getModificationType().asEnum()) { case DELETE: if (csn.isOlderThan(getDeleteTime())) { /* this delete is already obsoleted by a more recent delete * skip this mod */ modsIterator.remove(); break; } if (!conflictDelete(csn, m, modifiedEntry)) { modsIterator.remove(); } break; case ADD: conflictAdd(csn, m, modsIterator); break; case REPLACE: if (csn.isOlderThan(getDeleteTime())) { /* this replace is already obsoleted by a more recent delete * skip this mod */ modsIterator.remove(); break; } /* save the values that are added by the replace operation * into addedValues * first process the replace as a delete operation -> this generate * a list of values that should be kept * then process the addedValues as if they were coming from a add * -> this generate the list of values that needs to be added * concatenate the 2 generated lists into a replace */ Attribute addedValues = m.getAttribute(); m.setAttribute(new AttributeBuilder(addedValues, true).toAttribute()); conflictDelete(csn, m, modifiedEntry); Attribute keptValues = m.getAttribute(); m.setAttribute(addedValues); conflictAdd(csn, m, modsIterator); AttributeBuilder builder = new AttributeBuilder(keptValues); builder.addAll(m.getAttribute()); m.setAttribute(builder.toAttribute()); break; case INCREMENT: // TODO : FILL ME break; } return true; } else { processLocalOrNonConflictModification(csn, m); return false; // the attribute was not modified more recently } }