/** * Copyright 2008 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.util; import org.waveprotocol.wave.model.document.Document; import org.waveprotocol.wave.model.document.MutableDocumentImpl; import org.waveprotocol.wave.model.document.indexed.IndexedDocProvider; import org.waveprotocol.wave.model.document.indexed.IndexedDocument; import org.waveprotocol.wave.model.document.operation.DocOp; import org.waveprotocol.wave.model.document.operation.Nindo; import org.waveprotocol.wave.model.document.operation.automaton.DocumentSchema; import org.waveprotocol.wave.model.document.operation.impl.DocInitializationBuilder; import org.waveprotocol.wave.model.document.raw.RawDocument; import org.waveprotocol.wave.model.document.raw.RawDocumentProviderImpl; import org.waveprotocol.wave.model.document.raw.impl.Element; import org.waveprotocol.wave.model.document.raw.impl.Node; import org.waveprotocol.wave.model.document.raw.impl.RawDocumentImpl; import org.waveprotocol.wave.model.document.raw.impl.Text; import org.waveprotocol.wave.model.operation.OperationException; import org.waveprotocol.wave.model.operation.OperationRuntimeException; import org.waveprotocol.wave.model.operation.OperationSequencer; import org.waveprotocol.wave.model.operation.OperationSink; import java.util.Map; /** * Useful open implementations of {@code DocumentProvider} go here */ public class DocProviders { /** * RawDocument provider based on RawDocumentImpl as the document * implementation. */ public final static RawDocument.Provider<RawDocumentImpl> ROJO = RawDocumentProviderImpl.create(RawDocumentImpl.BUILDER); /** * IndexedDocumentProvider with a substrate based on the "Rojo" dom * implementation */ public final static IndexedDocProvider<Node, Element, Text, RawDocumentImpl> POJO = IndexedDocProvider.create(ROJO); /** * Provider of {@link MutableDocumentImpl}s with substrates based on the * "DocProviders.POJO" dom implementation and a trivial sequencer. */ public final static DocumentProvider<MutableDocumentImpl<Node, Element, Text>> MOJO = new DocumentProvider<MutableDocumentImpl<Node, Element, Text>>() { @Override public MutableDocumentImpl<Node, Element, Text> create(String tagName, Map<String, String> attributes) { IndexedDocument<Node, Element, Text> doc = POJO.create(tagName, attributes); return new MutableDocumentImpl<Node, Element, Text>(createTrivialSequencer(doc), doc); } @Override public MutableDocumentImpl<Node, Element, Text> parse(String text) { IndexedDocument<Node, Element, Text> doc = POJO.parse(text); return new MutableDocumentImpl<Node, Element, Text>(createTrivialSequencer(doc), doc); } }; /** * Creates a document which applies generated operations to a copy of * itself, thus ensuring those ops are valid when received remotely. */ public static Document createValidatingDocument(DocumentSchema schema) { IndexedDocument<Node, Element, Text> indexedDoc = POJO.build(new DocInitializationBuilder().build(), schema); return new DocumentImpl(createCopyingSequencer(indexedDoc), indexedDoc); } /** * A simple sequencer * @param doc the document to apply non-invertible ops to, and get the invertible ones from */ public final static <N, E extends N> OperationSequencer<Nindo> createTrivialSequencer( IndexedDocument<N, E, ? extends N> doc) { return createTrivialSequencer(doc, null); } /** * A simple sequencer * @param doc the document to apply non-invertible ops to, and get the invertible ones from * @param outputSink optional, may be null. */ public final static <N, E extends N> OperationSequencer<Nindo> createTrivialSequencer( final IndexedDocument<N, E, ? extends N> doc, final OperationSink<DocOp> outputSink) { return new OperationSequencer<Nindo>() { @Override public void begin() { } @Override public void end() { } @Override public void consume(Nindo op) { try { DocOp docOp = doc.consumeAndReturnInvertible(op); if (outputSink != null) { outputSink.consume(docOp); } } catch (OperationException oe) { throw new OperationRuntimeException("DocProviders trivial sequencer consume failed.", oe); } } }; } /** * Creates a sequencer that applies outgoing operations to a copy of the given * document, ensuring that both incoming and outgoing ops are valid. * * This is not implemented efficiently, intended for use in unit tests only. * * @param doc document to copy */ public final static <N, E extends N> OperationSequencer<Nindo> createCopyingSequencer( IndexedDocument<N, E, ? extends N> doc) { final IndexedDocument<Node, Element, Text> copy = POJO.build( doc.asOperation(), doc.getSchema()); return createTrivialSequencer(doc, new OperationSink<DocOp>() { @Override public void consume(DocOp op) throws OperationException { // Should throw exceptions if the op is invalid. copy.consume(op); } }); } protected DocProviders() { } }