Package org.waveprotocol.wave.model.testing

Source Code of org.waveprotocol.wave.model.testing.OpBasedWaveletFactory$Builder

/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements.  See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership.  The ASF licenses this file
* to you 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.testing;

import org.waveprotocol.wave.model.id.IdGenerator;
import org.waveprotocol.wave.model.id.WaveId;
import org.waveprotocol.wave.model.id.WaveletId;
import org.waveprotocol.wave.model.operation.OperationException;
import org.waveprotocol.wave.model.operation.OperationRuntimeException;
import org.waveprotocol.wave.model.operation.SilentOperationSink;
import org.waveprotocol.wave.model.operation.SilentOperationSink.Executor;
import org.waveprotocol.wave.model.operation.wave.WaveletOperation;
import org.waveprotocol.wave.model.schema.SchemaProvider;
import org.waveprotocol.wave.model.version.HashedVersion;
import org.waveprotocol.wave.model.wave.ParticipantId;
import org.waveprotocol.wave.model.wave.data.DocumentFactory;
import org.waveprotocol.wave.model.wave.data.ObservableWaveletData;
import org.waveprotocol.wave.model.wave.data.WaveletData;
import org.waveprotocol.wave.model.wave.data.impl.EmptyWaveletSnapshot;
import org.waveprotocol.wave.model.wave.data.impl.ObservablePluggableMutableDocument;
import org.waveprotocol.wave.model.wave.data.impl.WaveletDataImpl;
import org.waveprotocol.wave.model.wave.opbased.OpBasedWavelet;
import org.waveprotocol.wave.model.wave.opbased.WaveViewImpl;

/**
* Factory for creating {@link OpBasedWavelet} instances suitable for testing.
*
*/
public final class OpBasedWaveletFactory implements WaveViewImpl.WaveletFactory<OpBasedWavelet>,
    Factory<OpBasedWavelet> {

  /**
   * An operation sink that, on every operation it consumes, fires a version
   * update operation back to the wavelet, then passes the operation along to
   * the next sink. Wavelet versioning is specifically designed to be
   * server-controlled. In a test context, this sink is used to simulate the
   * behaviour of a wavelet server firing back acknowledgements with version
   * updates, in order that tests that mutate wavelets also see version number
   * increase.
   */
  private final static class VersionIncrementingSink implements
      SilentOperationSink<WaveletOperation> {
    private final WaveletData data;
    private final SilentOperationSink<? super WaveletOperation> output;

    public VersionIncrementingSink(WaveletData data,
        SilentOperationSink<? super WaveletOperation> output) {
      this.data = data;
      this.output = output;
    }

    @Override
    public void consume(WaveletOperation op) {
      // Update local version, simulating server response.
      try {
        op.createVersionUpdateOp(1, null).apply(data);
      } catch (OperationException e) {
        throw new OperationRuntimeException("test sink verison update failed", e);
      }

      // Pass to output sink.
      output.consume(op);
    }
  }

  /**
   * Builder, through which a factory can be conveniently configured.
   */
  public final static class Builder {
    private final SchemaProvider schemas;
    private ObservableWaveletData.Factory<?> holderFactory;
    private SilentOperationSink<? super WaveletOperation> sink;
    private ParticipantId author;

    public Builder(SchemaProvider schemas) {
      this.schemas = schemas;
    }

    public Builder with(SilentOperationSink<? super WaveletOperation> sink) {
      this.sink = sink;
      return this;
    }

    public Builder with(ObservableWaveletData.Factory<?> holderFactory) {
      this.holderFactory = holderFactory;
      return this;
    }

    public Builder with(ParticipantId author) {
      this.author = author;
      return this;
    }

    public OpBasedWaveletFactory build() {
      if (holderFactory == null) {
        DocumentFactory<?> docFactory = ObservablePluggableMutableDocument.createFactory(schemas);
        holderFactory = WaveletDataImpl.Factory.create(docFactory);
      }
      if (sink == null) {
        sink = SilentOperationSink.VOID;
      }
      if (author == null) {
        // Old tests expect this.
        author = FAKE_PARTICIPANT;
      }
      return new OpBasedWaveletFactory(holderFactory, sink, author);
    }
  }

  private static final ParticipantId FAKE_PARTICIPANT = new ParticipantId("fake@example.com");

  // Parameters with which to create the OpBasedWavelets.
  private final ObservableWaveletData.Factory<?> holderFactory;
  private final SilentOperationSink<? super WaveletOperation> sink;
  private final ParticipantId author;

  // Testing hacks.
  private MockWaveletOperationContextFactory lastContextFactory;
  private MockParticipationHelper lastAuthoriser;

  /**
   * Creates a factory, which creates op-based waves that adapt wave data
   * holders provided by another factory, sending produced operations to a given
   * sink.
   *
   * @param holderFactory factory for providing wave data holders
   * @param sink sink to which produced operations are sent
   * @param author id to which edits are to be attributed
   */
  private OpBasedWaveletFactory(ObservableWaveletData.Factory<?> holderFactory,
      SilentOperationSink<? super WaveletOperation> sink,
      ParticipantId author) {
    this.holderFactory = holderFactory;
    this.sink = sink;
    this.author = author;
  }

  public static Builder builder(SchemaProvider schemas) {
    return new Builder(schemas);
  }

  @Override
  public OpBasedWavelet create() {
    IdGenerator gen = FakeIdGenerator.create();
    return create(gen.newWaveId(), gen.newConversationWaveletId(), FAKE_PARTICIPANT);
  }

  @Override
  public OpBasedWavelet create(WaveId waveId, WaveletId waveletId, ParticipantId creator) {
    long now = System.currentTimeMillis();
    HashedVersion v0 = HashedVersion.unsigned(0);
    ObservableWaveletData waveData = holderFactory
        .create(new EmptyWaveletSnapshot(waveId, waveletId, creator, v0, now));
    lastContextFactory = new MockWaveletOperationContextFactory().setParticipantId(author);
    lastAuthoriser = new MockParticipationHelper();
    SilentOperationSink<WaveletOperation> executor =
        Executor.<WaveletOperation, WaveletData>build(waveData);
    SilentOperationSink<WaveletOperation> out = new VersionIncrementingSink(waveData, sink);
    return new OpBasedWavelet(waveId, waveData, lastContextFactory, lastAuthoriser, executor, out);
  }

  /**
   * Gets the authoriser provided to help the last {@link OpBasedWavelet} that
   * was created. The result is undefined if no wavelets have been created.
   */
  public MockParticipationHelper getLastAuthoriser() {
    return lastAuthoriser;
  }

  /**
   * Gets the helper provided to the last {@link OpBasedWavelet} that was
   * created. The result is undefined if no wavelets have been created.
   */
  public MockWaveletOperationContextFactory getLastContextFactory() {
    return lastContextFactory;
  }
}
TOP

Related Classes of org.waveprotocol.wave.model.testing.OpBasedWaveletFactory$Builder

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.