Package org.waveprotocol.box.server.frontend

Source Code of org.waveprotocol.box.server.frontend.WaveletInfo

/**
* Copyright 2011 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.box.server.frontend;

import com.google.common.base.Function;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.MapMaker;
import com.google.common.collect.Sets;

import org.waveprotocol.box.common.DeltaSequence;
import org.waveprotocol.box.server.waveserver.WaveServerException;
import org.waveprotocol.box.server.waveserver.WaveletProvider;
import org.waveprotocol.wave.model.id.WaveId;
import org.waveprotocol.wave.model.id.WaveletId;
import org.waveprotocol.wave.model.id.WaveletName;
import org.waveprotocol.wave.model.version.HashedVersion;
import org.waveprotocol.wave.model.version.HashedVersionFactory;
import org.waveprotocol.wave.model.wave.ParticipantId;
import org.waveprotocol.wave.model.wave.data.ReadableWaveletData;

import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

/**
* Provides services to manage and track wavelet participants and wavelet
* subscriptions.
*
* @author yurize@apache.org (Yuri Zelikov)
* @see ClientFrontendImpl
*/
public class WaveletInfo {

  /** Information we hold in memory for each wavelet. */
  private static class PerWavelet {
    private final HashedVersion version0;
    private final Set<ParticipantId> explicitParticipants;
    private final Set<ParticipantId> implicitParticipants;
    private HashedVersion currentVersion;

    PerWavelet(WaveletName waveletName, HashedVersion hashedVersionZero) {
      this.explicitParticipants = Sets.newHashSet();
      this.implicitParticipants = Sets.newHashSet();
      this.version0 = hashedVersionZero;
      this.currentVersion = version0;
    }

    synchronized HashedVersion getCurrentVersion() {
      return currentVersion;
    }

    synchronized void setCurrentVersion(HashedVersion version) {
      this.currentVersion = version;
    }
  }

  private final Map<ParticipantId, UserManager> perUser;
  private final Map<WaveId, Map<WaveletId, PerWavelet>> perWavelet;
  private final WaveletProvider waveletProvider;

  /**
   * Creates new instance of {@link WaveletInfo}.
   *
   * @param hashFactory the factory for hashed versions.
   * @param provider the {@link WaveletProvider}.
   * @return new {@link WaveletInfo} instance.
   */
  public static WaveletInfo create(HashedVersionFactory hashFactory, WaveletProvider provider) {
    return new WaveletInfo(hashFactory, provider);
  }

  WaveletInfo(final HashedVersionFactory hashedVersionFactory, WaveletProvider waveletProvider) {
    this.waveletProvider = waveletProvider;
    perWavelet =
        new MapMaker().makeComputingMap(new Function<WaveId, Map<WaveletId, PerWavelet>>() {
          @Override
          public Map<WaveletId, PerWavelet> apply(final WaveId waveId) {
            return new MapMaker().makeComputingMap(new Function<WaveletId, PerWavelet>() {
              @Override
              public PerWavelet apply(WaveletId waveletId) {
                WaveletName waveletName = WaveletName.of(waveId, waveletId);
                return new PerWavelet(waveletName, hashedVersionFactory
                    .createVersionZero(waveletName));
              }
            });
          }
        });

    perUser = new MapMaker().makeComputingMap(new Function<ParticipantId, UserManager>() {
      @Override
      public UserManager apply(ParticipantId from) {
        return new UserManager();
      }
    });
  }

  /**
   * Returns all visible wavelets in the wave specified by subscription which
   * are also comply with the subscription filter.
   */
  public Set<WaveletId> visibleWaveletsFor(WaveViewSubscription subscription,
      ParticipantId loggedInUser) throws WaveServerException {
    Set<WaveletId> visible = Sets.newHashSet();
    Set<Entry<WaveletId, PerWavelet>> entrySet =
        perWavelet.get(subscription.getWaveId()).entrySet();
    for (Entry<WaveletId, PerWavelet> entry : entrySet) {
      WaveletName waveletName = WaveletName.of(subscription.getWaveId(), entry.getKey());
      if (subscription.includes(entry.getKey())
          && waveletProvider.checkAccessPermission(waveletName, loggedInUser)) {
        visible.add(entry.getKey());
      }
    }
    return visible;
  }

  /**
   * Initializes front-end information from the wave store, if necessary.
   */
  public void initialiseWave(WaveId waveId) throws WaveServerException {
    if (!perWavelet.containsKey(waveId)) {
      Map<WaveletId, PerWavelet> wavelets = perWavelet.get(waveId);
      for (WaveletId waveletId : waveletProvider.getWaveletIds(waveId)) {
        ReadableWaveletData wavelet =
            waveletProvider.getSnapshot(WaveletName.of(waveId, waveletId)).snapshot;
        // Wavelets is a computing map, so get() initializes the entry.
        PerWavelet waveletInfo = wavelets.get(waveletId);
        synchronized (waveletInfo) {
          waveletInfo.currentVersion = wavelet.getHashedVersion();
          waveletInfo.explicitParticipants.addAll(wavelet.getParticipants());
        }
      }
    }
  }

  /**
   * Synchronizes the wavelet version and ensures that the deltas are
   * contiguous.
   *
   * @param waveletName the wavelet name.
   * @param newDeltas the new deltas.
   */
  public void syncWaveletVersion(WaveletName waveletName, DeltaSequence newDeltas) {
    HashedVersion expectedVersion;
    PerWavelet waveletInfo = getWavelet(waveletName);
    synchronized (waveletInfo) {
      expectedVersion = waveletInfo.getCurrentVersion();
      Preconditions.checkState(expectedVersion.getVersion() == newDeltas.getStartVersion(),
          "Expected deltas starting at version %s, got %s", expectedVersion,
          newDeltas.getStartVersion());
      waveletInfo.setCurrentVersion(newDeltas.getEndVersion());
    }
  }

  /**
   * Returns {@link UserManager} for the participant.
   */
  public UserManager getUserManager(ParticipantId participantId) {
    return perUser.get(participantId);
  }

  /**
   * Returns the current wavelet version.
   */
  public HashedVersion getCurrentWaveletVersion(WaveletName waveletName) {
    PerWavelet waveletInfo = getWavelet(waveletName);
    synchronized (waveletInfo) {
      return waveletInfo.getCurrentVersion();
    }
  }

  /**
   * @param waveletName the waveletName.
   * @return the wavelet participants.
   */
  public Set<ParticipantId> getWaveletParticipants(WaveletName waveletName) {
    PerWavelet waveletInfo = getWavelet(waveletName);
    synchronized (waveletInfo) {
      return ImmutableSet.copyOf(waveletInfo.explicitParticipants);
    }
  }

  /**
   * @param waveletName the waveletName.
   * @return the implicit wavelet participants. An implicit participant is not a
   *         "strict" participant on the wavelet, but rather only opened the
   *         wave and listens on updates. For example, anyone can open a shared
   *         wave without becoming explicit participant.
   */
  public Set<ParticipantId> getImplicitWaveletParticipants(WaveletName waveletName) {
    PerWavelet waveletInfo = getWavelet(waveletName);
    synchronized (waveletInfo) {
      return ImmutableSet.copyOf(waveletInfo.explicitParticipants);
    }
  }

  /**
   * Notifies that the participant was added from the wavelet.
   *
   * @param waveletName the wavelet name.
   * @param participant the participant.
   */
  public void notifyAddedExplicitWaveletParticipant(WaveletName waveletName,
      ParticipantId participant) {
    PerWavelet waveletInfo = getWavelet(waveletName);
    synchronized (waveletInfo) {
      waveletInfo.explicitParticipants.add(participant);
    }
  }

  /**
   * Notifies that the participant was removed from the wavelet.
   *
   * @param waveletName the wavelet name.
   * @param participant the participant.
   */
  public void notifyRemovedExplicitWaveletParticipant(WaveletName waveletName,
      ParticipantId participant) {
    PerWavelet waveletInfo = getWavelet(waveletName);
    synchronized (waveletInfo) {
      waveletInfo.explicitParticipants.remove(participant);
    }
  }

  /**
   * Notifies that an implicit participant opened the wave.
   *
   * @param waveletName the wavelet name.
   * @param participant the participant.
   */
  public void notifyAddedImplcitParticipant(WaveletName waveletName, ParticipantId participant) {
    PerWavelet waveletInfo = getWavelet(waveletName);
    synchronized (waveletInfo) {
      if (!waveletInfo.explicitParticipants.contains(participant)) {
        waveletInfo.implicitParticipants.add(participant);
      }
    }
  }

  private PerWavelet getWavelet(WaveletName name) {
    return perWavelet.get(name.waveId).get(name.waveletId);
  }
}
TOP

Related Classes of org.waveprotocol.box.server.frontend.WaveletInfo

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.