@Override public void clear() { // Delete non-canonical elements first so no events are generated. cleanup(); // Then delete the canonical, which will remove currentValue. Doc.E element = findCanonicalElement(); if (element != null) { getDocument().deleteNode(element); } assert currentElement == null; assert currentValue == null; }
/** * Initializes the current value without firing events. */ private void maybeInitCurrentValue() { if (currentValue == null) { currentValue = (currentElement != null) ? valueFactory.adapt(getEventRouter(), currentElement) : null; } }
/** * Creates a singleton. * * @param router event router for the document holding the object * @param container container in which the singleton is stored * @param valueTagName tag name of a value instance */ public static <V, I> DocumentBasedSingleton<V, I> create(DocEventRouter router, Doc.E container, String valueTagName, Factory<Doc.E, V, I> valueFactory) { DocumentBasedSingleton<V, I> singleton = new DocumentBasedSingleton<V, I>(router, container, valueTagName, valueFactory); router.addChildListener(container, singleton); return singleton; }
@Override public void onElementRemoved(Doc.E removedElement) { if (removedElement == currentElement) { changeCurrentValue(findCanonicalElement()); } }
/** * Deletes all non-canonical elements from the document. */ private void cleanup() { Doc.E canonical = findCanonicalElement(); Doc.E toDelete = DocHelper.getLastElementWithTagName(getDocument(), valueTagName, container); while (toDelete != canonical) { getDocument().deleteNode(toDelete); toDelete = DocHelper.getLastElementWithTagName(getDocument(), valueTagName, container); } }
public void testAdditionOfNonCanonicalValueChangesNothing() { target.set("42"); target.addListener(listener); remoteInsertRedundantValue("43"); assertValue(target, 42); listener.verifyNoEvent(); }
public void testClearRemovesRedundantValues() { target.set("42"); remoteInsertRedundantValue("43"); target.addListener(listener); target.clear(); assertNoValue(target); listener.verifyValueChanged(42, null); }
@Override public void setUp() { super.setUp(); target = createSingleton(); doc = target.getDocument(); router = target.getEventRouter(); listener = new Listener(); }
/** * Creates a singleton backed by a document root. */ private static DocumentBasedSingleton<Integer, String> createSingleton(DocEventRouter router) { return DocumentBasedSingleton.create(router, router.getDocument().getDocumentElement(), TAG, FACTORY); }
@Override public V set(I initialState) { final Map<String, String> attributes = Initializer.Helper.buildAttributes(initialState, valueFactory); // Insert a new first-child element of the container. Point<Doc.N> insertionPoint = Point.inElement(container, getDocument().getFirstChild(container)); Doc.E element = getDocument().createElement(insertionPoint, valueTagName, attributes); // onElementAdded will create the value object. assert currentElement != null; assert currentValue != null; cleanup(); return currentValue; }
public void testRemoteChangeAfterInitializationGeneratesEvent() { remoteInsertCanonicalValue("42"); DocumentBasedSingleton<Integer, String> other = createSingleton(router); other.addListener(listener); remoteInsertCanonicalValue("43"); listener.verifyValueChanged(42, 43); }
/** * Finds the canonical value-providing document element, which is the first * element with the expected tag name. * * @return the canonical element, or null */ private Doc.E findCanonicalElement() { // NOTE(anorth): this is correct for planned transform semantics where // colliding insertions result in document order matching temporal order. // Current (June 2010) transformation results in the opposite ordering. return DocHelper.getElementWithTagName(getDocument(), valueTagName, container); }
public void testSetClearsRedundantValues() { target.set("42"); remoteInsertRedundantValue("43"); target.addListener(listener); target.set("44"); listener.verifyValueChanged(42, 44); assertSame(DocHelper.getElementWithTagName(doc, TAG), DocHelper.getLastElementWithTagName(doc, TAG)); }
public void testClearRemovesRedundantValues() { target.set("42"); remoteInsertRedundantValue("43"); target.addListener(listener); target.clear(); assertNoValue(target); listener.verifyValueChanged(42, null); }
@Override public void setUp() { super.setUp(); target = createSingleton(); doc = target.getDocument(); router = target.getEventRouter(); listener = new Listener(); }
/** * Creates a singleton backed by a document root. */ private static DocumentBasedSingleton<Integer, String> createSingleton(DocEventRouter router) { return DocumentBasedSingleton.create(router, router.getDocument().getDocumentElement(), TAG, FACTORY); }
public void testRemoteChangeAfterInitializationGeneratesEvent() { remoteInsertCanonicalValue("42"); DocumentBasedSingleton<Integer, String> other = createSingleton(router); other.addListener(listener); remoteInsertCanonicalValue("43"); listener.verifyValueChanged(42, 43); }
@Override public void onElementAdded(Doc.E newElement) { // When a deletion and insertion are composed it's possible that // recalculation from the deletion event changes the current element // to the newly inserted canonical element before this event // is fired. Thus the check that the new element is not already // the current element. // Yet another failure of the ElementListener interface. if (newElement == findCanonicalElement() && newElement != currentElement) { changeCurrentValue(newElement); } }
public void testSetClearsRedundantValues() { target.set("42"); remoteInsertRedundantValue("43"); target.addListener(listener); target.set("44"); listener.verifyValueChanged(42, 44); assertSame(DocHelper.getElementWithTagName(doc, TAG), DocHelper.getLastElementWithTagName(doc, TAG)); }
/** * Creates and stores a conversation container. If the container has a * conversation then initializes that too. */ private ConversationContainer createContainer(ObservableWavelet wavelet) { ObservableDocument manifestDoc = wavelet.getDocument(IdConstants.MANIFEST_DOCUMENT_ID); DocEventRouter router = DefaultDocEventRouter.create(manifestDoc); ObservableSingleton<DocumentBasedManifest, Void> manifestContainer = DocumentBasedSingleton.create(router, manifestDoc.getDocumentElement(), DocumentBasedManifest.MANIFEST_TOP_TAG, DocumentBasedManifest.FACTORY); ConversationContainer container = new ConversationContainer(wavelet, manifestContainer); manifestContainer.addListener(container); containers.put(wavelet, container); WaveletBasedConversation conversation = container.getConversation(); if (conversation != null) { conversations.put(wavelet, conversation); triggerOnConversationAdded(conversation); } return container; }