/** * Creates a document-based basic set. * * @see #DocumentBasedBasicSet(DocumentEventRouter, Object, Serializer, * String, String) */ public static <E, C extends Comparable<C>> DocumentBasedBasicSet<E, C> create( DocumentEventRouter<? super E, E, ?> router, E entryContainer, Serializer<C> serializer, String entryTagName, String valueAttrName) { return new DocumentBasedBasicSet<E, C>( router, entryContainer, serializer, entryTagName, valueAttrName).init(); }
@Override public void remove(T value) { if (valueElements.containsKey(value)) { deleteObsoleteElements(); getDocument().deleteNode(valueElements.get(value)); } }
/** * Handles an element being removed from the container. */ private void handleElementRemoved(E deletedElement) { // To start with though, we do a quick check to see if deletedElement has // the same tag name as value elements. if (!entryTagName.equals(getDocument().getTagName(deletedElement))) { // Exit, because deletedElement definitely isn't part of this container. return; } if (obsoleteElements.remove(deletedElement)) { // Element was obsolete, so ignore the removal event return; } T value = valueOf(deletedElement); E existingElement = valueElements.get(value); if (existingElement != deletedElement) { // deleted element was not part of the backing store for this map, so // ignore it } else { valueElements.remove(value); fireOnValueRemoved(value); } }
/** * Exposes a document as an integer set, suitable for holding folder state. * * @param router router for the folders document * @return folder state. */ private static <E> ObservableBasicSet<Integer> createFolders( DocumentEventRouter<? super E, E, ?> router) { return DocumentBasedBasicSet.create(router, router.getDocument().getDocumentElement(), Serializer.INTEGER, FOLDER_TAG, ID_ATTR); }
/** * Handles a new element being added to the container. If it represents a new * value, that value is recorded. If it represents a value already in this * container, either the old element or the new element is marked obsolete. * The element marked obsolete is the one that appears later in the document. */ private void handleElementAdded(E newElement) { ObservableMutableDocument<? super E, E, ?> document = getDocument(); assert container.equals(document.getParentElement(newElement)); if (!entryTagName.equals(document.getTagName(newElement))) { return; } T value = valueOf(newElement); E oldEntry = valueElements.get(value); if (oldEntry == null) { // Entry is for a new value - add it to the element map and fire an event // to collection listeners valueElements.put(value, newElement); fireOnValueAdded(value); } else if (document.getLocation(oldEntry) < document.getLocation(newElement)) { // newEntry is not needed, so mark it obsolete obsoleteElements.add(newElement); } else { // oldEntry is no needed, so mark it obsoleted and use the new one instead obsoleteElements.add(oldEntry); valueElements.put(value, newElement); } }
/** * Initializes a new object. Call after construction is complete. */ private DocumentBasedBasicSet<E, T> init() { // Plumb events through router.addChildListener(container, new ElementListener<E>() { @Override public void onElementAdded(E element) { handleElementAdded(element); } @Override public void onElementRemoved(E element) { handleElementRemoved(element); } }); // Call handleElementAdded() to notify this class of existing data ObservableMutableDocument<? super E, E, ?> document = getDocument(); E curr = DocHelper.getFirstChildElement(document, container); E next; while (curr != null) { next = DocHelper.getNextSiblingElement(document, curr); handleElementAdded(curr); curr = next; } return this; }
ObservableMutableDocument<? super E, E, ?> document = getDocument(); while (!obsoleteElements.isEmpty()) {
/** * Creates a target map on a substrate. */ private <N, E extends N> void createTargetOn(ValueContext<N, E> context) { DocumentBasedBasicSet<E, Integer> target = DocumentBasedBasicSet.create(DefaultDocumentEventRouter.create(context.doc), context.container, Serializer.INTEGER, ENTRY_TAG, VALUE_ATTR); // Eventually, the target map and the substrate should be sufficient state for all tests. // However, in order to simulate document events, the two need to be wrapped together in a // FungeStack so that Java knows that the element type-parameters match. stack = new FungeStack<N, E, Integer>(context, target, Serializer.INTEGER); }
/** * Gets the value of an entry. * * @param element entry to evaluate * @return the value embedded in the element. */ private T valueOf(E element) { return serializer.fromString(getDocument().getAttribute(element, valueAttrName)); } }
/** * Creates a target map on a substrate. */ private <N, E extends N> void createTargetOn(ValueContext<N, E> context) { DocumentBasedBasicSet<E, Integer> target = DocumentBasedBasicSet.create(DefaultDocumentEventRouter.create(context.doc), context.container, Serializer.INTEGER, ENTRY_TAG, VALUE_ATTR); // Eventually, the target map and the substrate should be sufficient state for all tests. // However, in order to simulate document events, the two need to be wrapped together in a // FungeStack so that Java knows that the element type-parameters match. stack = new FungeStack<N, E, Integer>(context, target, Serializer.INTEGER); }
@Override public void clear() { if (!valueElements.isEmpty()) { deleteObsoleteElements(); // Remove every container element that corresponds to a value ObservableMutableDocument<? super E, E, ?> document = getDocument(); while (!valueElements.isEmpty()) { document.deleteNode(valueElements.values().iterator().next()); } } }
/** Creates an empty ObservableBasicSetImpl to work with. */ @Override protected void createEmptyMap() { ObservablePluggableMutableDocument doc = BasicFactories.observableDocumentProvider().create( "data", Collections.<String, String> emptyMap()); set = DocumentBasedBasicSet.create( DefaultDocumentEventRouter.create(doc), doc.getDocumentElement(), Serializer.STRING, ENTRY_TAG, VALUE_ATTR); } }
@Override public void add(T value) { Preconditions.checkNotNull(value, "value must not be null"); // Add an element to represent the value if (!valueElements.containsKey(value)) { Attributes attrs = new AttributesImpl(valueAttrName, serializer.toString(value)); getDocument().createChildElement(container, entryTagName, attrs); deleteObsoleteElements(); } }
/** Creates an empty ObservableBasicSetImpl to work with. */ @Override protected void createEmptyMap() { ObservablePluggableMutableDocument doc = BasicFactories.observableDocumentProvider().create( "data", Collections.<String, String> emptyMap()); set = DocumentBasedBasicSet.create( DefaultDocumentEventRouter.create(doc), doc.getDocumentElement(), Serializer.STRING, ENTRY_TAG, VALUE_ATTR); } }