package com.sap.runlet.operationaltransformation; import java.util.ArrayList; import java.util.List; public class UnmergedOperationsQueue<O extends Operation<S>, S> { /** * As the {@link #unmergedOperationsForPeer} queues are cleaned up whenever merge * confirmations are received from peers, we need to remember which local operation * number the first element in the queue resulted from. */ private int numberOfFirstInList; private List<O> unmergedOperations; public UnmergedOperationsQueue() { numberOfFirstInList = 0; unmergedOperations = new ArrayList<O>(5); } /** * After an operation has been locally applied and needs to be propagated * to the peer for which this is the queue of unmerged operations, the operation * must be appended to this queue. */ public synchronized void sentOutOperation(O operationSentOut) { unmergedOperations.add(operationSentOut); } /** * Returns a copied list of unmerged and stepwise transformed local * operations starting at the requested local operation number. * * @param numberOfConfirmedLocalOperations * A value of 0 means that the remote peer has not confirmed the * merge of any local operation yet. */ public synchronized List<O> getUnmergedOperations(int numberOfConfirmedLocalOperations) { return new ArrayList<O>(unmergedOperations.subList( numberOfConfirmedLocalOperations-numberOfFirstInList, unmergedOperations.size())); } /** * Replaces the local operation with number <tt>localOperationNumber</tt> in the queue by * <tt>transformedOperation</tt>. * * @param localOperationNumber starts with 0 */ public synchronized void updateWithTransformed(int localOperationNumber, O transformedOperation) { unmergedOperations.set(localOperationNumber-numberOfFirstInList, transformedOperation); } /** * Cleans up the queue so that only unconfirmed / unmerged operations * remain. Afterwards, {@link #getUnmergedOperations(int) asking for an * unmerged operation} with an argument for * <tt>numberOfConfirmedLocalOperations</tt> smaller than * <tt>numberOfMergedOperations</tt> passed to this call will result in an * exception. * * @param numberOfMergedOperations * tells how many operations that emerged from the local peer the * remote peer has confirmed to have merged. */ public synchronized void confirm(int numberOfMergedOperations) { for (int i=numberOfFirstInList; i<numberOfMergedOperations; i++) { unmergedOperations.remove(0); } numberOfFirstInList = numberOfMergedOperations; } public synchronized String toString() { int i=numberOfFirstInList; StringBuilder result = new StringBuilder(); result.append('['); boolean first = true; for (O op : unmergedOperations) { if (!first) { result.append(", "); } else { first = false; } result.append(i); result.append(": "); result.append(op); } result.append(']'); return result.toString(); } }