X-Git-Url: http://git.argeo.org/?a=blobdiff_plain;ds=sidebyside;f=org.argeo.api.acr%2Fsrc%2Forg%2Fargeo%2Fapi%2Facr%2FContent.java;h=33ddeecedb2d07018cbdbd3d8248193350be3b1b;hb=5d7ebadd9fe583fd9d3b2e4ca6e99079b99aac5a;hp=0fdc14fe30e9f0146afbc8f8dde42187086d0200;hpb=55d1a78150b6be0004f6bcb28703bcdd6daf55a1;p=lgpl%2Fargeo-commons.git diff --git a/org.argeo.api.acr/src/org/argeo/api/acr/Content.java b/org.argeo.api.acr/src/org/argeo/api/acr/Content.java index 0fdc14fe3..33ddeeced 100644 --- a/org.argeo.api.acr/src/org/argeo/api/acr/Content.java +++ b/org.argeo.api.acr/src/org/argeo/api/acr/Content.java @@ -1,19 +1,23 @@ package org.argeo.api.acr; +import static org.argeo.api.acr.NamespaceUtils.unqualified; + import java.io.Closeable; import java.io.IOException; +import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Optional; import java.util.concurrent.CompletableFuture; -import javax.xml.XMLConstants; import javax.xml.namespace.QName; /** * A semi-structured content, with attributes, within a hierarchical structure. */ public interface Content extends Iterable, Map { + /** The base of a repository path. */ + String ROOT_PATH = "/"; QName getName(); @@ -27,29 +31,48 @@ public interface Content extends Iterable, Map { Optional get(QName key, Class clss); - default Object get(String key) { - if (key.indexOf(':') >= 0) - throw new IllegalArgumentException("Name " + key + " has a prefix"); - return get(new QName(XMLConstants.NULL_NS_URI, key, XMLConstants.DEFAULT_NS_PREFIX)); + Class getType(QName key); + + boolean isMultiple(QName key); + + List getMultiple(QName key, Class clss); + + /* + * ATTRIBUTES OPERATION HELPERS + */ + default boolean containsKey(QNamed key) { + return containsKey(key.qName()); } - default Object put(String key, Object value) { - if (key.indexOf(':') >= 0) - throw new IllegalArgumentException("Name " + key + " has a prefix"); - return put(new QName(XMLConstants.NULL_NS_URI, key, XMLConstants.DEFAULT_NS_PREFIX), value); + default Optional get(QNamed key, Class clss) { + return get(key.qName(), clss); } - default Object remove(String key) { - if (key.indexOf(':') >= 0) - throw new IllegalArgumentException("Name " + key + " has a prefix"); - return remove(new QName(XMLConstants.NULL_NS_URI, key, XMLConstants.DEFAULT_NS_PREFIX)); + default Object get(QNamed key) { + return get(key.qName()); } - Class getType(QName key); + default Object put(QNamed key, Object value) { + return put(key.qName(), value); + } - boolean isMultiple(QName key); + default Object remove(QNamed key) { + return remove(key.qName()); + } - Optional> getMultiple(QName key, Class clss); + // TODO do we really need the helpers below? + + default Object get(String key) { + return get(unqualified(key)); + } + + default Object put(String key, Object value) { + return put(unqualified(key), value); + } + + default Object remove(String key) { + return remove(unqualified(key)); + } @SuppressWarnings("unchecked") default List getMultiple(QName key) { @@ -59,32 +82,34 @@ public interface Content extends Iterable, Map { } catch (ClassCastException e) { throw new IllegalArgumentException("Requested type is not the default type"); } - Optional> res = getMultiple(key, type); - if (res == null) - return null; - else { - if (res.isEmpty()) - throw new IllegalStateException("Metadata " + key + " is not availabel as list of type " + type); - return res.get(); - } + List res = getMultiple(key, type); + return res; } /* * CONTENT OPERATIONS */ -// default CompletionStage edit(Consumer work) { -// return CompletableFuture.supplyAsync(() -> { -// work.accept(this); -// return this; -// }).minimalCompletionStage(); -// } - + /** Adds a new empty {@link Content} to this {@link Content}. */ Content add(QName name, QName... classes); + /** + * Adds a new {@link Content} to this {@link Content}, setting the provided + * attributes. The provided attributes can be used as hints by the + * implementation. In particular, setting {@link DName#getcontenttype} will + * imply that this content has a file semantic. + */ + default Content add(QName name, Map attrs, QName... classes) { + Content child = add(name, classes); + putAll(attrs); + return child; + } + default Content add(String name, QName... classes) { - if (name.indexOf(':') >= 0) - throw new IllegalArgumentException("Name " + name + " has a prefix"); - return add(new QName(XMLConstants.NULL_NS_URI, name, XMLConstants.DEFAULT_NS_PREFIX), classes); + return add(unqualified(name), classes); + } + + default Content add(String name, Map attrs, QName... classes) { + return add(unqualified(name), attrs, classes); } void remove(); @@ -94,6 +119,10 @@ public interface Content extends Iterable, Map { */ List getContentClasses(); + default void addContentClasses(QName... contentClass) { + throw new UnsupportedOperationException("Adding content classes to " + getPath() + " is not supported"); + } + /** AND */ default boolean isContentClass(QName... contentClass) { List contentClasses = getContentClasses(); @@ -104,6 +133,14 @@ public interface Content extends Iterable, Map { return true; } + /** AND */ + default boolean isContentClass(QNamed... contentClass) { + List lst = new ArrayList<>(); + for (QNamed qNamed : contentClass) + lst.add(qNamed.qName()); + return isContentClass(lst.toArray(new QName[lst.size()])); + } + /** OR */ default boolean hasContentClass(QName... contentClass) { List contentClasses = getContentClasses(); @@ -114,6 +151,22 @@ public interface Content extends Iterable, Map { return false; } + /** OR */ + default boolean hasContentClass(QNamed... contentClass) { + List lst = new ArrayList<>(); + for (QNamed qNamed : contentClass) + lst.add(qNamed.qName()); + return hasContentClass(lst.toArray(new QName[lst.size()])); + } + + /* + * SIBLINGS + */ + + default int getSiblingIndex() { + return 1; + } + /* * DEFAULT METHODS */ @@ -130,31 +183,123 @@ public interface Content extends Iterable, Map { } /* - * CONVENIENCE METHODS + * CHILDREN */ - default String attr(String key) { - Object obj = get(key); - if (obj == null) - return null; - return obj.toString(); + default boolean hasChild(QName name) { + for (Content child : this) { + if (child.getName().equals(name)) + return true; + } + return false; + } + + default boolean hasChild(QNamed name) { + return hasChild(name.qName()); + } + + default Content anyOrAddChild(QName name, QName... classes) { + Content child = anyChild(name); + if (child != null) + return child; + return this.add(name, classes); + } + + default Content anyOrAddChild(String name, QName... classes) { + return anyOrAddChild(unqualified(name), classes); + } + + /** Any child with this name, or null if there is none */ + default Content anyChild(QName name) { + for (Content child : this) { + if (child.getName().equals(name)) + return child; + } + return null; + } + + default List children(QName name) { + List res = new ArrayList<>(); + for (Content child : this) { + if (child.getName().equals(name)) + res.add(child); + } + return res; + } + + default List children(QNamed name) { + return children(name.qName()); + } + + default Optional soleChild(QNamed name) { + return soleChild(name.qName()); } + default Optional soleChild(QName name) { + List res = children(name); + if (res.isEmpty()) + return Optional.empty(); + if (res.size() > 1) + throw new IllegalStateException(this + " has multiple children with name " + name); + return Optional.of(res.get(0)); + } + + default Content child(QName name) { + return soleChild(name).orElseThrow(); + } + + default Content child(QNamed name) { + return child(name.qName()); + } + + /* + * ATTR AS STRING + */ + /** + * Convenience method returning an attribute as a {@link String}. + * + * @param key the attribute name + * @return the attribute value as a {@link String} or null. + * + * @see Object#toString() + */ default String attr(QName key) { - Object obj = get(key); - if (obj == null) - return null; - return obj.toString(); - - } -// -// default String attr(Object key) { -// return key != null ? attr(key.toString()) : attr(null); -// } -// -// default A get(Object key, Class clss) { -// return key != null ? get(key.toString(), clss) : get(null, clss); -// } + return get(key, String.class).orElse(null); + } + + /** + * Convenience method returning an attribute as a {@link String}. + * + * @param key the attribute name + * @return the attribute value as a {@link String} or null. + * + * @see Object#toString() + */ + default String attr(QNamed key) { + return attr(key.qName()); + } + + /** + * Convenience method returning an attribute as a {@link String}. + * + * @param key the attribute name + * @return the attribute value as a {@link String} or null. + * + * @see Object#toString() + */ + default String attr(String key) { + return attr(unqualified(key)); + } + + /* + * CONTEXT + */ + /** + * A content within this repository + * + * @param path either an absolute path or a path relative to this content + */ + Optional getContent(String path); /* * EXPERIMENTAL UNSUPPORTED