/** * Copyright 2009 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.supplement; import org.waveprotocol.wave.model.id.WaveletId; import org.waveprotocol.wave.model.util.ReadableStringMap; import org.waveprotocol.wave.model.version.HashedVersion; import java.util.HashSet; import java.util.Set; /** * Canonical implementation of a {@link Supplement}. * */ public final class SupplementImpl implements Supplement { /** Semantic-free ADT. */ private final PrimitiveSupplement primitive; /** * Creates a supplement. * * @param primitive underlying data-holding primitive */ public SupplementImpl(PrimitiveSupplement primitive) { this.primitive = primitive; } @Override public ThreadState getThreadState(WaveletId waveletId, String threadId) { return primitive.getThreadState(waveletId, threadId); } @Override public void setThreadState(WaveletId waveletId, String threadId, ThreadState newState) { primitive.setThreadState(waveletId, threadId, newState); } /** * Tests if a component is unread, given its last-read and last-modified * versions. * * @param read last-read version * @param modified last-modified version * @return true if the last-read version is the special * {@link PrimitiveSupplement#NO_VERSION} value, or if it is less than * the last-modified value. */ private boolean isUnread(int read, int modified) { return read == PrimitiveSupplement.NO_VERSION || read < modified; } /** * {@inheritDoc} * * A blip is unread if, and only if (a) the read-version for that blip either * does not exist or is less than the last-modified version; and (b) the * wavelet-override version either does not exist or is less than the blip's * last-modified version. */ @Override public boolean isBlipUnread(WaveletId waveletId, String blipId, int version) { return isUnread(primitive.getLastReadBlipVersion(waveletId, blipId), version) && isUnread(primitive.getLastReadWaveletVersion(waveletId), version); } /** * {@inheritDoc} * * The participants collection is unread if, and only if (a) its read-version * either does not exist or is less than its last-modified version; and (b) * the wavelet-override version either does not exist or is less than the * participants' last-modified version. */ @Override public boolean isParticipantsUnread(WaveletId waveletId, int version) { return isUnread(primitive.getLastReadParticipantsVersion(waveletId), version) && isUnread(primitive.getLastReadWaveletVersion(waveletId), version); } @Override public boolean haveParticipantsEverBeenRead(WaveletId waveletId) { return primitive.getLastReadParticipantsVersion(waveletId) != PrimitiveSupplement.NO_VERSION || primitive.getLastReadWaveletVersion(waveletId) != PrimitiveSupplement.NO_VERSION; } @Override public boolean isTagsUnread(WaveletId waveletId, int version) { return isUnread(primitive.getLastReadTagsVersion(waveletId), version) && isUnread(primitive.getLastReadWaveletVersion(waveletId), version); } /** * {@inheritDoc} * * If the blip is already considered as read, this method has no effect. */ @Override public void markBlipAsRead(WaveletId waveletId, String blipId, int version) { if (isBlipUnread(waveletId, blipId, version)) { primitive.setLastReadBlipVersion(waveletId, blipId, version); } } /** * {@inheritDoc} * * If the participants collection is already considered as read, this method * has no effect. */ @Override public void markParticipantsAsRead(WaveletId waveletId, int version) { if (isParticipantsUnread(waveletId, version)) { primitive.setLastReadParticipantsVersion(waveletId, version); } } /** * {@inheritDoc} * * If the tags document is already considered as read, this method * has no effect. */ @Override public void markTagsAsRead(WaveletId waveletId, int version) { if (isTagsUnread(waveletId, version)) { primitive.setLastReadTagsVersion(waveletId, version); } } @Override public void markWaveletAsRead(WaveletId waveletId, int version) { primitive.setLastReadWaveletVersion(waveletId, version); } @Override public void markAsUnread() { primitive.clearReadState(); } @Override public Set<Integer> getFolders() { return toSet(primitive.getFolders()); } @Override public void moveToFolder(int id) { primitive.removeAllFolders(); primitive.addFolder(id); } @Override public void removeAllFolders() { primitive.removeAllFolders(); } @Override public boolean isArchived(WaveletId waveletId, int version) { return (primitive.getArchiveWaveletVersion(waveletId) >= version); } @Override public void follow() { primitive.follow(); } @Override public void unfollow() { primitive.clearArchiveState(); primitive.unfollow(); } @Override public boolean isFollowed(boolean defaultFollowed) { Boolean explicitFollow = primitive.getFollowed(); return explicitFollow != null ? explicitFollow : defaultFollowed; } @Override public void clearArchive() { primitive.clearArchiveState(); } @Override public void archive(WaveletId waveletId, int version) { primitive.archiveAtVersion(waveletId, version); } @Override public void setSeenVersion(WaveletId waveletId, HashedVersion signature) { primitive.setSeenVersion(waveletId, signature); } @Override public HashedVersion getSeenVersion(WaveletId waveletId) { return primitive.getSeenVersion(waveletId); } public int getNotifiedVersion(WaveletId waveletId) { return primitive.getNotifiedVersion(waveletId); } @Override public Set<WaveletId> getSeenWavelets() { return primitive.getSeenWavelets(); } @Override public boolean hasSeenVersion() { return !primitive.getSeenWavelets().isEmpty(); } private static <T> Set<T> toSet(Iterable<T> items) { Set<T> set = new HashSet<T>(); for (T item : items) { set.add(item); } return set; } @Override public WantedEvaluationSet getWantedEvaluationSet(WaveletId waveletId) { Set<WantedEvaluation> relevantEvaluations = new HashSet<WantedEvaluation>(); for (WantedEvaluation evaluation : primitive.getWantedEvaluations()) { // evaluation.getWaveletId() may be null - so must compare in this order if (waveletId.equals(evaluation.getWaveletId())) { relevantEvaluations.add(evaluation); } } return new SimpleWantedEvaluationSet(waveletId, relevantEvaluations); } @Override public void addWantedEvaluation(WantedEvaluation evaluation) { primitive.addWantedEvaluation(evaluation); } @Override public boolean hasPendingNotification() { Boolean pending = primitive.getPendingNotification(); return (pending == null ? false : pending); } @Override public boolean hasPendingNotification(WaveletId waveletId) { if (!hasNotifiedVersion()) { // If we have not used the new approach of notified versions yet, // we need to check if there is a pending notification recorded // using the old pending notification flag. // TODO(user): migrate UDWs to replace the pending notification // flag with notified versions at the current version. return hasPendingNotification(); } return getSeenVersion(waveletId).getVersion() < getNotifiedVersion(waveletId); } @Override public void markWaveletAsNotified(WaveletId waveletId, int version) { primitive.setNotifiedVersion(waveletId, version); } @Override public boolean hasNotifiedVersion() { return !primitive.getNotifiedWavelets().isEmpty(); } @Override public void clearPendingNotification() { primitive.clearPendingNotification(); } @Override public ReadableStringMap<String> getGadgetState(String gadgetId) { return primitive.getGadgetState(gadgetId); } @Override public void setGadgetState(String gadgetId, String key, String value) { primitive.setGadgetState(gadgetId, key, value); } }