/** * Copyright 2009 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.waveprotocol.wave.model.document.operation.algorithm; import org.waveprotocol.wave.model.document.operation.DocOp; import org.waveprotocol.wave.model.operation.OperationException; import org.waveprotocol.wave.model.operation.OperationPair; import org.waveprotocol.wave.model.operation.TransformException; import org.waveprotocol.wave.model.util.Pair; /** * A utility class for transforming document operations. * * TODO: Tweak the behaviour of this transformer to exactly match the * reference implementation in the tests. Specifically, the optimized * implementation in this class may output extraneous annotations * which have no operational effect. * * @author Alexandre Mah */ public final class Transformer { private Transformer() {} /** * Transforms a pair of operations. * * @param clientOp the operation from the client * @param serverOp the operation from the server * @return the transformed pair of operations * @throws TransformException if a problem was encountered during the * transformation process */ public static OperationPair<DocOp> transform(DocOp clientOp, DocOp serverOp) throws TransformException { try { // The transform process consists of decomposing the client and server // operations into two constituent operations each and performing four // transforms structured as in the following diagram: // ci0 cn0 // si0 si1 si2 // ci1 cn1 // sn0 sn1 sn2 // ci2 cn2 // Pair<DocOp, DocOp> c = Decomposer.decompose(clientOp); Pair<DocOp, DocOp> s = Decomposer.decompose(serverOp); DocOp ci0 = c.first; DocOp cn0 = c.second; DocOp si0 = s.first; DocOp sn0 = s.second; OperationPair<DocOp> r1 = new InsertionTransformer().transformOperations(ci0, si0); DocOp ci1 = r1.clientOp(); DocOp si1 = r1.serverOp(); OperationPair<DocOp> r2 = new InsertionNoninsertionTransformer().transformOperations(ci1, sn0); DocOp ci2 = r2.clientOp(); DocOp sn1 = r2.serverOp(); OperationPair<DocOp> r3 = new InsertionNoninsertionTransformer().transformOperations(si1, cn0); DocOp si2 = r3.clientOp(); DocOp cn1 = r3.serverOp(); OperationPair<DocOp> r4 = new NoninsertionTransformer().transformOperations(cn1, sn1); DocOp cn2 = r4.clientOp(); DocOp sn2 = r4.serverOp(); return new OperationPair<DocOp>( Composer.compose(ci2, cn2), Composer.compose(si2, sn2)); } catch (OperationException e) { throw new TransformException(e); } } }