preparing the first OT implementation for removing leaderboard columns

This commit is contained in:
Axel Uhl
2012-03-28 14:06:39 +02:00
parent 2fc3fc6173
commit b35a479d9d
12 changed files with 259 additions and 52 deletions
@@ -17,4 +17,14 @@ public class ClientServerOperationPair<O extends Operation<?>> {
public O getServerOp() {
return serverOp;
}
@SuppressWarnings("unchecked")
public static <O extends Operation<S>, S> O getNoOp() {
return (O) new Operation<S>() {
@Override
public S applyTo(S toState) {
return toState; // don't change anything, return state unchanged
}
};
}
}
@@ -17,4 +17,5 @@ public interface Operation<S> extends Cloneable {
* @return the state produced by applying this operation to <tt>toState</tt>
*/
S applyTo(S toState);
}
@@ -6,7 +6,11 @@ public interface Transformer<O extends Operation<?>> {
* based on the same state. The complementary pair of operations is computed
* such that if the client applies the server operation returned, and the
* server applies the client operation returned, both end up in equal states
* again.
* again.<p>
*
* If a resulting operation is supposed to not have any effects, return the
* {@link ClientServerOperationPair#getNoOp()} operation, but never <code>null</code>
* as any of the operations in the resulting pair.
*/
ClientServerOperationPair<O> transform(O clientOp, O serverOp);
}
@@ -0,0 +1,25 @@
package com.sap.sailing.server.operationaltransformation;
public abstract class AbstractLeaderboardColumnOperation extends AbstractRacingEventServiceOperation {
private final String leaderboardName;
private final String columnName;
public AbstractLeaderboardColumnOperation(String leaderboardName, String columnName) {
super();
this.leaderboardName = leaderboardName;
this.columnName = columnName;
}
public String getLeaderboardName() {
return leaderboardName;
}
public String getColumnName() {
return columnName;
}
protected boolean affectsSameColumn(AbstractLeaderboardColumnOperation other) {
return getLeaderboardName().equals(other.getLeaderboardName()) && getColumnName().equals(other.getColumnName());
}
}
@@ -0,0 +1,33 @@
package com.sap.sailing.server.operationaltransformation;
/**
* Performs identical transformations for all operation types by simply returning the operation passed. Subclasses need
* to override the transformation methods for those operation types that have an impact for them.
*
* @author Axel Uhl (d043530)
*
*/
public abstract class AbstractRacingEventServiceOperation implements RacingEventServiceOperation {
@Override
public RacingEventServiceOperation transformClientRenameLeaderboardColumnOp(
RenameLeaderboardColumn renameLeaderboardColumnClientOp) {
return renameLeaderboardColumnClientOp;
}
@Override
public RacingEventServiceOperation transformServerRenameLeaderboardColumnOp(
RenameLeaderboardColumn renameLeaderboardColumnServerOp) {
return renameLeaderboardColumnServerOp;
}
@Override
public RacingEventServiceOperation transformServerRemoveColumnFromLeaderboard(RemoveColumnFromLeaderboard removeColumnFromLeaderboardServerOp) {
return removeColumnFromLeaderboardServerOp;
}
@Override
public RacingEventServiceOperation transformClientRemoveColumnFromLeaderboard(RemoveColumnFromLeaderboard removeColumnFromLeaderboardClientOp) {
return removeColumnFromLeaderboardClientOp;
}
}
@@ -2,27 +2,35 @@ package com.sap.sailing.server.operationaltransformation;
import com.sap.sailing.server.RacingEventService;
public class AddColumnToLeaderboard implements RacingEventServiceOperation {
private final String columnName;
private final String leaderboardName;
/**
* Doesn't transform for the {@link RemoveColumnFromLeaderboard} because only existing leaderboards can be removed,
* and adding is only possible for non-existing names.
*
* @author Axel Uhl (d043530)
*
*/
public class AddColumnToLeaderboard extends AbstractLeaderboardColumnOperation {
private final boolean medalRace;
public AddColumnToLeaderboard(String columnName, String leaderboardName, boolean medalRace) {
super();
this.columnName = columnName;
this.leaderboardName = leaderboardName;
super(leaderboardName, columnName);
this.medalRace = medalRace;
}
@Override
public RacingEventService applyTo(RacingEventService toState) {
toState.addColumnToLeaderboard(columnName, leaderboardName, medalRace);
toState.addColumnToLeaderboard(getColumnName(), getLeaderboardName(), medalRace);
return toState;
}
@Override
public RacingEventServiceOperation transformFor(RacingEventServiceOperation peerOp) {
public RacingEventServiceOperation transformClientOp(RacingEventServiceOperation serverOp) {
// TODO Auto-generated method stub
return null;
}
@Override
public RacingEventServiceOperation transformServerOp(RacingEventServiceOperation clientOp) {
// TODO Auto-generated method stub
return null;
}
@@ -1,28 +1,55 @@
package com.sap.sailing.server.operationaltransformation;
import com.sap.sailing.operationaltransformation.ClientServerOperationPair;
import com.sap.sailing.server.RacingEventService;
public class MoveLeaderboardColumnDown implements RacingEventServiceOperation {
private final String leaderboardName;
private final String columnName;
public class MoveLeaderboardColumnDown extends AbstractLeaderboardColumnOperation {
public MoveLeaderboardColumnDown(String leaderboardName, String columnName) {
super();
this.leaderboardName = leaderboardName;
this.columnName = columnName;
super(leaderboardName, columnName);
}
@Override
public RacingEventService applyTo(RacingEventService toState) {
toState.moveLeaderboardColumnDown(leaderboardName, columnName);
toState.moveLeaderboardColumnDown(getLeaderboardName(), getColumnName());
return toState;
}
@Override
public RacingEventServiceOperation transformFor(RacingEventServiceOperation peerOp) {
public RacingEventServiceOperation transformClientOp(RacingEventServiceOperation serverOp) {
// TODO Auto-generated method stub
return null;
}
@Override
public RacingEventServiceOperation transformServerOp(RacingEventServiceOperation clientOp) {
// TODO Auto-generated method stub
return null;
}
@Override
public RacingEventServiceOperation transformServerRemoveColumnFromLeaderboard(
RemoveColumnFromLeaderboard removeColumnFromLeaderboardServerOp) {
if (affectsSameColumn(removeColumnFromLeaderboardServerOp)) {
return ClientServerOperationPair.getNoOp();
} else {
return removeColumnFromLeaderboardServerOp;
}
}
@Override
public RacingEventServiceOperation transformClientRemoveColumnFromLeaderboard(
RemoveColumnFromLeaderboard removeColumnFromLeaderboardClientOp) {
if (affectsSameColumn(removeColumnFromLeaderboardClientOp)) {
return ClientServerOperationPair.getNoOp();
} else {
return removeColumnFromLeaderboardClientOp;
}
}
}
@@ -1,28 +1,55 @@
package com.sap.sailing.server.operationaltransformation;
import com.sap.sailing.operationaltransformation.ClientServerOperationPair;
import com.sap.sailing.server.RacingEventService;
public class MoveLeaderboardColumnUp implements RacingEventServiceOperation {
private final String leaderboardName;
private final String columnName;
public class MoveLeaderboardColumnUp extends AbstractLeaderboardColumnOperation {
public MoveLeaderboardColumnUp(String leaderboardName, String columnName) {
super();
this.leaderboardName = leaderboardName;
this.columnName = columnName;
super(leaderboardName, columnName);
}
@Override
public RacingEventService applyTo(RacingEventService toState) {
toState.moveLeaderboardColumnUp(leaderboardName, columnName);
toState.moveLeaderboardColumnUp(getLeaderboardName(), getColumnName());
return toState;
}
@Override
public RacingEventServiceOperation transformFor(RacingEventServiceOperation peerOp) {
public RacingEventServiceOperation transformClientOp(RacingEventServiceOperation serverOp) {
// TODO Auto-generated method stub
return null;
}
@Override
public RacingEventServiceOperation transformServerOp(RacingEventServiceOperation clientOp) {
// TODO Auto-generated method stub
return null;
}
@Override
public RacingEventServiceOperation transformServerRemoveColumnFromLeaderboard(
RemoveColumnFromLeaderboard removeColumnFromLeaderboardServerOp) {
if (affectsSameColumn(removeColumnFromLeaderboardServerOp)) {
return ClientServerOperationPair.getNoOp();
} else {
return removeColumnFromLeaderboardServerOp;
}
}
@Override
public RacingEventServiceOperation transformClientRemoveColumnFromLeaderboard(
RemoveColumnFromLeaderboard removeColumnFromLeaderboardClientOp) {
if (affectsSameColumn(removeColumnFromLeaderboardClientOp)) {
return ClientServerOperationPair.getNoOp();
} else {
return removeColumnFromLeaderboardClientOp;
}
}
}
@@ -8,8 +8,9 @@ public class OperationalTransformer implements Transformer<RacingEventServiceOpe
@Override
public ClientServerOperationPair<RacingEventServiceOperation> transform(RacingEventServiceOperation clientOp,
RacingEventServiceOperation serverOp) {
// TODO Auto-generated method stub
return null;
ClientServerOperationPair<RacingEventServiceOperation> result = new ClientServerOperationPair<RacingEventServiceOperation>(
clientOp.transformClientOp(serverOp), serverOp.transformServerOp(clientOp));
return result;
}
}
@@ -6,9 +6,34 @@ import com.sap.sailing.server.RacingEventService;
public interface RacingEventServiceOperation extends Operation<RacingEventService> {
/**
* Implements the specific transformation rule for the implementing subclass for the set of possible
* peer operations along which to transform this operation. See {@link Transformer#transform(Operation, Operation)}
* for the specification.
* Implements the specific transformation rule for the implementing subclass for the set of possible peer operations
* along which to transform this operation, assuming this is the client operation. See
* {@link Transformer#transform(Operation, Operation)} for the specification.
*
* @return the result of transforming <code>this</code> operation along <code>serverOp</code>
*/
RacingEventServiceOperation transformFor(RacingEventServiceOperation peerOp);
RacingEventServiceOperation transformClientOp(RacingEventServiceOperation serverOp);
/**
* Implements the specific transformation rule for the implementing subclass for the set of possible peer operations
* along which to transform this operation, assuming this is the server operation. See
* {@link Transformer#transform(Operation, Operation)} for the specification.
*
* @return the result of transforming <code>this</code> operation along <code>clientOp</code>
*/
RacingEventServiceOperation transformServerOp(RacingEventServiceOperation clientOp);
/**
* Assumes this is the "server" operation and transforms the client's <code>removeColumnFromLeaderboardClientOp</code> according to this
* operation. The default implementation will probably pass on the untransformed client operation. However, if this
* operation deals with the leaderboard column being removed by <code>removeColumnFromLeaderboardClientOp</code>,
* the result will be <code>null</code>, meaning that this operation cannot be applied after the column has been removed.
*/
RacingEventServiceOperation transformClientRemoveColumnFromLeaderboard(RemoveColumnFromLeaderboard removeColumnFromLeaderboardClientOp);
RacingEventServiceOperation transformServerRemoveColumnFromLeaderboard(RemoveColumnFromLeaderboard removeColumnFromLeaderboardServerOp);
RacingEventServiceOperation transformClientRenameLeaderboardColumnOp(RenameLeaderboardColumn renameLeaderboardColumnClientOp);
RacingEventServiceOperation transformServerRenameLeaderboardColumnOp(RenameLeaderboardColumn renameLeaderboardColumnServerOp);
}
@@ -1,27 +1,51 @@
package com.sap.sailing.server.operationaltransformation;
import com.sap.sailing.operationaltransformation.ClientServerOperationPair;
import com.sap.sailing.server.RacingEventService;
public class RemoveColumnFromLeaderboard implements RacingEventServiceOperation {
private final String columnName;
private final String leaderboardName;
public class RemoveColumnFromLeaderboard extends AbstractLeaderboardColumnOperation {
public RemoveColumnFromLeaderboard(String columnName, String leaderboardName) {
super();
this.columnName = columnName;
this.leaderboardName = leaderboardName;
super(leaderboardName, columnName);
}
@Override
public RacingEventService applyTo(RacingEventService toState) {
toState.removeLeaderboardColumn(leaderboardName, columnName);
toState.removeLeaderboardColumn(getLeaderboardName(), getColumnName());
return toState;
}
@Override
public RacingEventServiceOperation transformFor(RacingEventServiceOperation peerOp) {
// TODO Auto-generated method stub
return null;
public RacingEventServiceOperation transformClientOp(RacingEventServiceOperation serverOp) {
return serverOp.transformClientRemoveColumnFromLeaderboard(this);
}
@Override
public RacingEventServiceOperation transformServerOp(RacingEventServiceOperation clientOp) {
return clientOp.transformServerRemoveColumnFromLeaderboard(this);
}
@Override
public RacingEventServiceOperation transformServerRemoveColumnFromLeaderboard(
RemoveColumnFromLeaderboard removeColumnFromLeaderboardServerOp) {
if (affectsSameColumn(removeColumnFromLeaderboardServerOp)) {
// skip server's remove and hence only apply the client's remove operation
return ClientServerOperationPair.getNoOp();
} else {
return removeColumnFromLeaderboardServerOp;
}
}
@Override
public RacingEventServiceOperation transformClientRemoveColumnFromLeaderboard(
RemoveColumnFromLeaderboard removeColumnFromLeaderboardClientOp) {
if (affectsSameColumn(removeColumnFromLeaderboardClientOp)) {
// skip client's remove and hence only apply the server's remove operation
return ClientServerOperationPair.getNoOp();
} else {
return removeColumnFromLeaderboardClientOp;
}
}
}
@@ -1,30 +1,52 @@
package com.sap.sailing.server.operationaltransformation;
import com.sap.sailing.operationaltransformation.ClientServerOperationPair;
import com.sap.sailing.server.RacingEventService;
public class RenameLeaderboardColumn implements RacingEventServiceOperation {
private final String leaderboardName;
private final String oldColumnName;
public class RenameLeaderboardColumn extends AbstractLeaderboardColumnOperation {
private final String newColumnName;
public RenameLeaderboardColumn(String leaderboardName, String oldColumnName, String newColumnName) {
super();
this.leaderboardName = leaderboardName;
this.oldColumnName = oldColumnName;
super(leaderboardName, oldColumnName);
this.newColumnName = newColumnName;
}
@Override
public RacingEventService applyTo(RacingEventService toState) {
toState.renameLeaderboardColumn(leaderboardName, oldColumnName, newColumnName);
toState.renameLeaderboardColumn(getLeaderboardName(), getColumnName(), newColumnName);
return toState;
}
@Override
public RacingEventServiceOperation transformClientOp(RacingEventServiceOperation serverOp) {
return serverOp.transformClientRenameLeaderboardColumnOp(this);
}
@Override
public RacingEventServiceOperation transformFor(RacingEventServiceOperation peerOp) {
// TODO Auto-generated method stub
return null;
public RacingEventServiceOperation transformServerOp(RacingEventServiceOperation clientOp) {
return clientOp.transformServerRenameLeaderboardColumnOp(this);
}
@Override
public RacingEventServiceOperation transformServerRemoveColumnFromLeaderboard(
RemoveColumnFromLeaderboard removeColumnFromLeaderboardServerOp) {
if (affectsSameColumn(removeColumnFromLeaderboardServerOp)) {
return ClientServerOperationPair.getNoOp(); // don't need the rename anymore when column is removed
} else {
return removeColumnFromLeaderboardServerOp;
}
}
@Override
public RacingEventServiceOperation transformClientRemoveColumnFromLeaderboard(
RemoveColumnFromLeaderboard removeColumnFromLeaderboardClientOp) {
if (affectsSameColumn(removeColumnFromLeaderboardClientOp)) {
return ClientServerOperationPair.getNoOp(); // don't need the rename anymore when column is removed
} else {
return removeColumnFromLeaderboardClientOp;
}
}
}