Package org.waveprotocol.wave.model.supplement

Source Code of org.waveprotocol.wave.model.supplement.WaveletReadStateCollection

/**
* 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.supplement;

import org.waveprotocol.wave.model.conversation.WaveletBasedConversation;
import org.waveprotocol.wave.model.document.ObservableMutableDocument;
import org.waveprotocol.wave.model.document.operation.impl.AttributesImpl;
import org.waveprotocol.wave.model.document.util.DocHelper;
import org.waveprotocol.wave.model.document.util.DocumentEventRouter;
import org.waveprotocol.wave.model.id.WaveletId;
import org.waveprotocol.wave.model.supplement.ObservablePrimitiveSupplement.Listener;
import org.waveprotocol.wave.model.util.ElementListener;
import org.waveprotocol.wave.model.util.Preconditions;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

/**
* Represents a collection of per-wavelet read-states, implemented by embedding
* them in elements of a document.
*
*/
class WaveletReadStateCollection<E> implements ElementListener<E> {
  private final DocumentEventRouter<? super E, E, ?> router;
  private final E container;

  /** Read state, expressed as a per-wavelet structure. */
  private final Map<WaveletId, WaveletReadState> waveletSupplements =
      new HashMap<WaveletId, WaveletReadState>();

  /** Listener to inject into each read-state. */
  private final Listener listener;

  private WaveletReadStateCollection(DocumentEventRouter<? super E, E, ?> router, E container,
      Listener listener) {
    this.router = router;
    this.container = container;
    this.listener = listener;
  }

  public static <E> WaveletReadStateCollection<E> create(
      DocumentEventRouter<? super E, E, ?> router, E e, Listener listener) {
    WaveletReadStateCollection<E> col = new WaveletReadStateCollection<E>(router, e, listener);
    router.addChildListener(e, col);
    col.load();
    return col;
  }

  private ObservableMutableDocument<? super E, E, ?> getDocument() {
    return router.getDocument();
  }

  private void load() {
    E child = DocHelper.getFirstChildElement(getDocument(), getDocument().getDocumentElement());
    while (child != null) {
      onElementAdded(child);
      child = DocHelper.getNextSiblingElement(getDocument(), child);
    }
  }

  private WaveletId valueOf(E element) {
    String waveletIdStr = getDocument().getAttribute(element, WaveletBasedSupplement.ID_ATTR);
    return WaveletBasedConversation.widFor(waveletIdStr);
  }

  @Override
  public void onElementAdded(E element) {
    assert container == getDocument().getParentElement(element);
    if (!WaveletBasedSupplement.WAVELET_TAG.equals(getDocument().getTagName(element))) {
      return;
    }

    WaveletId waveletId = valueOf(element);
    if (waveletId != null) {
      WaveletReadState existing = waveletSupplements.get(waveletId);
      if (existing == null) {
        WaveletReadState read =
            DocumentBasedWaveletReadState.create(router, element, waveletId, listener);
        waveletSupplements.put(waveletId, read);

        // Fire events reflecting the initial read state.
        //
        // NOTE(user): it is important that these events get fired after the new read-state
        //   object is added to the map above, in order that the interface presented by this
        //   collection object is consistent with the events being broadcast to the listener.
        //
        int waveletVersion = read.getWaveletLastReadVersion();
        if (waveletVersion != WaveletBasedSupplement.NO_VERSION) {
          listener.onLastReadWaveletVersionChanged(waveletId, PrimitiveSupplement.NO_VERSION,
              waveletVersion);
        }
        int participantsVersion = read.getParticipantsLastReadVersion();
        if (participantsVersion != PrimitiveSupplement.NO_VERSION) {
          listener.onLastReadParticipantsVersionChanged(waveletId, PrimitiveSupplement.NO_VERSION,
              participantsVersion);
        }
        int tagsVersion = read.getTagsLastReadVersion();
        if (tagsVersion != PrimitiveSupplement.NO_VERSION) {
          listener.onLastReadTagsVersionChanged(waveletId, PrimitiveSupplement.NO_VERSION,
              tagsVersion);
        }
        for (String blipId : read.getReadBlips()) {
          int blipVersion = read.getBlipLastReadVersion(blipId);
          if (blipVersion != PrimitiveSupplement.NO_VERSION) {
            listener.onLastReadBlipVersionChanged(waveletId, blipId, PrimitiveSupplement.NO_VERSION,
                blipVersion);
          }
        }
      } else {
        //
        // We can't mutate during callbacks yet.
        // Let's just ignore the latter :(. Clean up on timer?
        //
        // Merge the two together, and delete latter.
        //
        // for (String blip : read.getReadBlips()) {
        // existing.setBlipLastReadVersion(blip,
        // read.getBlipLastReadVersion(blip));
        // }
        // int participantsReadVersion =
        // read.getParticipantsLastReadVersion();
        // int waveletReadVersion = read.getWaveletLastReadVersion();
        // if (participantsReadVersion != NO_VERSION) {
        // existing.setParticipantsLastReadVersion(participantsReadVersion);
        // }
        // if (waveletReadVersion != NO_VERSION) {
        // existing.setWaveletLastReadVersion(waveletReadVersion);
        // }
      }
    } else {
      // XML error: someone added a WAVELET element without an id. Ignore.
      // TODO(user): log this at error level, once loggers are injected into
      // these classes.
    }
  }

  public void onElementRemoved(E element) {
    if (WaveletBasedSupplement.WAVELET_TAG.equals(getDocument().getTagName(element))) {
      WaveletId waveletId = valueOf(element);
      if (waveletId != null) {
        WaveletReadState state = waveletSupplements.remove(waveletId);
        if (state == null) {
          // Not good - there was a read-state element and we weren't tracking
          // it...
          // TODO(user): report an error here.
          return;
        }
        // Fire events reflecting everything becoming unread.
        for (String blipId : state.getReadBlips()) {
          int blipVersion = state.getBlipLastReadVersion(blipId);
          if (blipVersion != PrimitiveSupplement.NO_VERSION) {
            listener.onLastReadBlipVersionChanged(waveletId, blipId, blipVersion,
              PrimitiveSupplement.NO_VERSION);
          }
        }
        int tagsVersion = state.getTagsLastReadVersion();
        if (tagsVersion != PrimitiveSupplement.NO_VERSION) {
          listener.onLastReadTagsVersionChanged(waveletId, tagsVersion,
            PrimitiveSupplement.NO_VERSION);
        }
        int participantsVersion = state.getParticipantsLastReadVersion();
        if (participantsVersion != PrimitiveSupplement.NO_VERSION) {
          listener.onLastReadParticipantsVersionChanged(waveletId, participantsVersion,
            PrimitiveSupplement.NO_VERSION);
        }
        int waveletVersion = state.getWaveletLastReadVersion();
        if (waveletVersion != WaveletBasedSupplement.NO_VERSION) {
          listener.onLastReadWaveletVersionChanged(waveletId, PrimitiveSupplement.NO_VERSION,
              waveletVersion);
        }
      }
    }
  }

  private void createEntry(WaveletId waveletId) {
    String waveletIdStr = WaveletBasedConversation.idFor(waveletId);
    E container =
        getDocument().createChildElement(getDocument().getDocumentElement(),
          WaveletBasedSupplement.WAVELET_TAG,
          new AttributesImpl(WaveletBasedSupplement.ID_ATTR, waveletIdStr));
  }

  WaveletReadState getSupplement(WaveletId waveletId) {
    Preconditions.checkNotNull(waveletId, "wavelet id must not be null");
    WaveletReadState wavelet = waveletSupplements.get(waveletId);
    if (wavelet == null) {
      // Create a new container element for tracking state for the wavelet.
      // Callbacks should
      // build it.
      createEntry(waveletId);
      wavelet = waveletSupplements.get(waveletId);
      assert wavelet != null;
    }
    return wavelet;
  }

  void setLastReadBlipVersion(WaveletId waveletId, String blipId, int version) {
    getSupplement(waveletId).setBlipLastReadVersion(blipId, version);
  }

  void setLastReadParticipantsVersion(WaveletId waveletId, int version) {
    getSupplement(waveletId).setParticipantsLastReadVersion(version);
  }

  void setLastReadTagsVersion(WaveletId waveletId, int version) {
    getSupplement(waveletId).setTagsLastReadVersion(version);
  }

  void setLastReadWaveletVersion(WaveletId waveletId, int version) {
    getSupplement(waveletId).setWaveletLastReadVersion(version);
  }

  void clear() {
    Collection<WaveletId> toRemove = new ArrayList<WaveletId>(waveletSupplements.keySet());
    for (WaveletId waveletId : toRemove) {
      waveletSupplements.get(waveletId).remove();
    }
  }

  void clearBlipReadState(WaveletId waveletId, String blipId) {
    waveletSupplements.get(waveletId).clearBlipReadState(blipId);
  }

  int getLastReadParticipantsVersion(WaveletId waveletId) {
    WaveletReadState wavelet = waveletSupplements.get(waveletId);
    return wavelet != null ? wavelet.getParticipantsLastReadVersion()
        : WaveletBasedSupplement.NO_VERSION;
  }

  int getLastReadTagsVersion(WaveletId waveletId) {
    WaveletReadState wavelet = waveletSupplements.get(waveletId);
    return wavelet != null ? wavelet.getTagsLastReadVersion()
        : WaveletBasedSupplement.NO_VERSION;
  }

  int getLastReadBlipVersion(WaveletId waveletId, String blipId) {
    WaveletReadState wavelet = waveletSupplements.get(waveletId);
    return wavelet != null ? wavelet.getBlipLastReadVersion(blipId)
        : WaveletBasedSupplement.NO_VERSION;
  }

  int getLastReadWaveletVersion(WaveletId waveletId) {
    WaveletReadState wavelet = waveletSupplements.get(waveletId);
    return wavelet != null ? wavelet.getWaveletLastReadVersion()
        : WaveletBasedSupplement.NO_VERSION;
  }

  Iterable<WaveletId> getReadWavelets() {
    return waveletSupplements.keySet();
  }

  Iterable<String> getReadBlips(WaveletId waveletId) {
    WaveletReadState wavelet = waveletSupplements.get(waveletId);
    return wavelet != null ? wavelet.getReadBlips() : Collections.<String> emptySet();
  }
}
TOP

Related Classes of org.waveprotocol.wave.model.supplement.WaveletReadStateCollection

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.