/** * 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.adt.ObservableMonotonicMap; import org.waveprotocol.wave.model.adt.ObservableMonotonicValue; import org.waveprotocol.wave.model.adt.docbased.DocumentBasedMonotonicMap; import org.waveprotocol.wave.model.adt.docbased.DocumentBasedMonotonicValue; 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.Serializer; /** * Implements the per-wavelet read state, using the * {@link DocumentBasedMonotonicValue} embedding for the participants and * wavelet-override last-read versions, and the * {@link DocumentBasedMonotonicMap} embedding for per-blip last-read versions. * * @param <E> element type of the document implementation */ class DocumentBasedWaveletReadState<E> implements WaveletReadState { private final ObservableMonotonicMap<String, Integer> blips; private final ObservableMonotonicValue<Integer> participants; private final ObservableMonotonicValue<Integer> tags; private final ObservableMonotonicValue<Integer> wavelet; private final DocumentEventRouter<? super E, E, ?> router; private final E container; DocumentBasedWaveletReadState(DocumentEventRouter<? super E, E, ?> router, E container) { this.router = router; this.container = container; blips = DocumentBasedMonotonicMap.create(router, container, Serializer.STRING, Serializer.INTEGER, WaveletBasedSupplement.BLIP_READ_TAG, WaveletBasedSupplement.ID_ATTR, WaveletBasedSupplement.VERSION_ATTR); participants = DocumentBasedMonotonicValue.create(router, container, Serializer.INTEGER, WaveletBasedSupplement.PARTICIPANTS_READ_TAG, WaveletBasedSupplement.VERSION_ATTR); tags = DocumentBasedMonotonicValue.create(router, container, Serializer.INTEGER, WaveletBasedSupplement.TAGS_READ_TAG, WaveletBasedSupplement.VERSION_ATTR); wavelet = DocumentBasedMonotonicValue.create(router, container, Serializer.INTEGER, WaveletBasedSupplement.WAVELET_READ_TAG, WaveletBasedSupplement.VERSION_ATTR); } /** * Creates * * @param router router * @param container element in which the read state is contained * @param id wavelet id being tracked * @param listener listener for read-state changes * @return a new read-state tracker. */ public static <E> DocumentBasedWaveletReadState<E> create( DocumentEventRouter<? super E, E, ?> router, E container, WaveletId id, Listener listener) { DocumentBasedWaveletReadState<E> x = new DocumentBasedWaveletReadState<E>(router, container); x.installListeners(id, listener); return x; } /** * Injects listeners into the underlying ADTs that translate their events * into primitive-supplement events. * * @param wid * @param listener */ private void installListeners(final WaveletId wid, final Listener listener) { blips.addListener(new ObservableMonotonicMap.Listener<String, Integer>() { @Override public void onEntrySet(String key, Integer oldValue, Integer newValue) { listener.onLastReadBlipVersionChanged(wid, key, valueOf(oldValue), valueOf(newValue)); } }); participants.addListener(new ObservableMonotonicValue.Listener<Integer>() { @Override public void onSet(Integer oldValue, Integer newValue) { listener.onLastReadParticipantsVersionChanged(wid, valueOf(oldValue), valueOf(newValue)); } }); tags.addListener(new ObservableMonotonicValue.Listener<Integer>() { @Override public void onSet(Integer oldValue, Integer newValue) { listener.onLastReadTagsVersionChanged(wid, valueOf(oldValue), valueOf(newValue)); } }); wavelet.addListener(new ObservableMonotonicValue.Listener<Integer>() { @Override public void onSet(Integer oldValue, Integer newValue) { listener.onLastReadWaveletVersionChanged(wid, valueOf(oldValue), valueOf(newValue)); } }); } private static int valueOf(Integer version) { return version != null ? version : PrimitiveSupplement.NO_VERSION; } @Override public void setBlipLastReadVersion(String blipId, int version) { blips.put(blipId, version); } @Override public int getBlipLastReadVersion(String id) { return valueOf(blips.get(id)); } @Override public void setParticipantsLastReadVersion(int version) { participants.set(version); } @Override public int getParticipantsLastReadVersion() { return valueOf(participants.get()); } @Override public int getTagsLastReadVersion() { return valueOf(tags.get()); } @Override public void setTagsLastReadVersion(int version) { tags.set(version); } @Override public void setWaveletLastReadVersion(int version) { wavelet.set(version); } @Override public int getWaveletLastReadVersion() { return valueOf(wavelet.get()); } @Override public Iterable<String> getReadBlips() { return blips.keySet(); } @Override public void remove() { router.getDocument().deleteNode(container); } @Override public void clearBlipReadState(String blipId) { blips.remove(blipId); } }