/**
   * Deserializes the snapshot contained in the {@link WaveletSnapshot} into an {@link
   * ObservableWaveletData}.
   *
   * @param snapshot the {@link WaveletSnapshot} to deserialize.
   * @throws OperationException if the ops in the snapshot can not be applied.
   * @throws InvalidParticipantAddress
   * @throws InvalidIdException
   */
  public static ObservableWaveletData deserializeWavelet(WaveletSnapshot snapshot, WaveId waveId)
      throws OperationException, InvalidParticipantAddress, InvalidIdException {
    ObservableWaveletData.Factory<? extends ObservableWaveletData> factory =
        WaveletDataImpl.Factory.create(
            ObservablePluggableMutableDocument.createFactory(SchemaCollection.empty()));

    ParticipantId author = ParticipantId.of(snapshot.getCreator());
    WaveletId waveletId = ModernIdSerialiser.INSTANCE.deserialiseWaveletId(snapshot.getWaveletId());
    long creationTime = snapshot.getCreationTime();

    ObservableWaveletData wavelet =
        factory.create(
            new EmptyWaveletSnapshot(
                waveId,
                waveletId,
                author,
                CoreWaveletOperationSerializer.deserialize(snapshot.getVersion()),
                creationTime));

    for (String participant : snapshot.getParticipantIdList()) {
      wavelet.addParticipant(getParticipantId(participant));
    }

    for (DocumentSnapshot document : snapshot.getDocumentList()) {
      addDocumentSnapshotToWavelet(document, wavelet);
    }

    wavelet.setVersion(snapshot.getVersion().getVersion());
    wavelet.setLastModifiedTime(snapshot.getLastModifiedTime());
    // The creator and creation time are set when the empty wavelet template is
    // created above.

    return wavelet;
  }
  /**
   * Reverses the operations detailed in the list of deltas on the given wavelet.
   *
   * @param wavelet {@link ObservableWaveletData} to apply operations to
   * @param deltas the {@link WaveletDelta} containing the operations which we should revert on the
   *     given wavelet.
   * @throws OperationException if the operations can not be rolled back.
   */
  private static void rollback(ObservableWaveletData wavelet, List<TransformedWaveletDelta> deltas)
      throws OperationException {
    List<WaveletOperation> inverseOps = Lists.newArrayList();

    // Go through everything in reverse order
    for (int i = deltas.size() - 1; i >= 0; i--) {
      TransformedWaveletDelta delta = deltas.get(i);
      // Metadata such as the last modified ts will change due to the rollback
      // of operations.
      for (int j = delta.size() - 1; j >= 0; j--) {
        WaveletOperation op = delta.get(j);
        WaveletOperation inverseOp = WaveletOperationInverter.invert(op);
        inverseOps.add(inverseOp);
      }
    }

    long startVersion = wavelet.getVersion();
    int opCount = 0;
    for (WaveletOperation inverseOp : inverseOps) {
      inverseOp.apply(wavelet);
      opCount++;
    }
    if (wavelet.getVersion() != startVersion - opCount) {
      throw new OperationException(
          "Expected end version "
              + (startVersion - opCount)
              + " doesn't match the version of the wavelet "
              + wavelet.getVersion());
    }
  }
 private ParticipantId computeCreator(WaveViewData wave) {
   for (ObservableWaveletData wavelet : wave.getWavelets()) {
     if (IdUtil.isConversationRootWaveletId(wavelet.getWaveletId())) {
       return wavelet.getCreator();
     }
   }
   // If not found creator - compare with UNKNOWN_CREATOR;
   return UNKNOWN_CREATOR;
 }
 private long computeCreatedTime(WaveViewData wave) {
   long creationTime = -1;
   for (ObservableWaveletData wavelet : wave.getWavelets()) {
     creationTime =
         creationTime < wavelet.getCreationTime()
             ? wavelet.getCreationTime()
             : creationTime;
   }
   return creationTime;
 }
 private long computeLmt(WaveViewData wave) {
   long lmt = -1;
   for (ObservableWaveletData wavelet : wave.getWavelets()) {
     // Skip non conversational wavelets.
     if (!IdUtil.isConversationalId(wavelet.getWaveletId())) {
       continue;
     }
     lmt = lmt < wavelet.getLastModifiedTime() ? wavelet.getLastModifiedTime() : lmt;
   }
   return lmt;
 }
  /**
   * Verifies whether the wavelet matches the filter criteria.
   *
   * @param wavelet the wavelet.
   * @param user the logged in user.
   * @param withList the list of participants to be used in 'with' filter.
   * @param creatorList the list of participants to be used in 'creator' filter.
   * @param isAllQuery true if the search results should include shared for this domain waves.
   */
  private boolean matches(
      ObservableWaveletData wavelet,
      ParticipantId user,
      ParticipantId sharedDomainParticipantId,
      List<ParticipantId> withList,
      List<ParticipantId> creatorList,
      boolean isAllQuery)
      throws WaveletStateException {
    // If it is user data wavelet for the user - return true.
    if (IdUtil.isUserDataWavelet(wavelet.getWaveletId()) && wavelet.getCreator().equals(user)) {
      return true;
    }
    // Filter by creator. This is the fastest check so we perform it first.
    for (ParticipantId creator : creatorList) {
      if (!creator.equals(wavelet.getCreator())) {
        // Skip.
        return false;
      }
    }
    // The wavelet should have logged in user as participant for 'in:inbox'
    // query.
    if (!isAllQuery && !wavelet.getParticipants().contains(user)) {
      return false;
    }
    // Or if it is an 'all' query - then either logged in user or shared domain
    // participant should be present in the wave.
    if (isAllQuery
        && !WaveletDataUtil.checkAccessPermission(wavelet, user, sharedDomainParticipantId)) {
      return false;
    }
    // If not returned 'false' above - then logged in user is either
    // explicit or implicit participant and therefore has access permission.

    // Now filter by 'with'.
    for (ParticipantId otherUser : withList) {
      if (!wavelet.getParticipants().contains(otherUser)) {
        // Skip.
        return false;
      }
    }
    return true;
  }
Esempio n. 7
0
  @Override
  public void onOperationChannelCreated(
      OperationChannel channel, ObservableWaveletData snapshot, Accessibility accessibility) {
    WaveletId wid = snapshot.getWaveletId();
    String id = ModernIdSerialiser.INSTANCE.serialiseWaveletId(wid);

    Preconditions.checkState(!channels.containsKey(id));
    channels.put(id, channel);

    if (wave.getWavelet(wid) != null) {
      connect(id);
    } else {
      // This will trigger the onWaveletAdded callback above.
      wave.addWavelet(operationalizer.operationalize(snapshot));
    }
  }
Esempio n. 8
0
  /** Opens a mux, binding its operation channels with operation-supporting wavelets. */
  public static void openAndBind(
      WaveletOperationalizer operationalizer,
      WaveViewImpl<OpBasedWavelet> wave,
      WaveDocuments<? extends CcDocument> docRegistry,
      OperationChannelMultiplexer mux,
      IdFilter filter,
      Command whenOpened) {
    StaticChannelBinder staticBinder = new StaticChannelBinder(operationalizer, docRegistry);
    LiveChannelBinder liveBinder =
        new LiveChannelBinder(staticBinder, operationalizer, wave, mux, whenOpened);

    final Collection<KnownWavelet> remoteWavelets = CollectionUtils.createQueue();
    final Collection<ObservableWaveletData> localWavelets = CollectionUtils.createQueue();
    for (ObservableWaveletData wavelet : operationalizer.getWavelets()) {
      // Version 0 wavelets must be wavelets that the client has created in this
      // session. They are not to be included in the known-wavelet collection,
      // because the server does not know about them.
      if (wavelet.getVersion() > 0) {
        remoteWavelets.add(
            new KnownWavelet(wavelet, wavelet.getHashedVersion(), Accessibility.READ_WRITE));
      } else {
        localWavelets.add(wavelet);
      }
    }

    // Start listening to wave events and channel events.
    wave.addListener(liveBinder);
    // This binder only starts getting events once open() has been called, since
    // that is what sets this binder as a mux listener. Since wavelet-to-channel
    // binding occurs through event callbacks, this listener setting must occur
    // before trying to bind localWavelets.
    mux.open(liveBinder, filter, remoteWavelets);
    for (ObservableWaveletData local : localWavelets) {
      mux.createOperationChannel(local.getWaveletId(), local.getCreator());
    }
  }
 /** Returns the {@link HashedVersion} of the wavelet after all deltas have been applied. */
 public HashedVersion getVersionAfterDeltas() {
   return deltas.isEmpty() ? snapshotAfterDeltas.getHashedVersion() : deltas.getEndVersion();
 }