Improve ACR
[lgpl/argeo-commons.git] / org.argeo.api.acr / src / org / argeo / api / acr / Content.java
index 3cdf8d7dbec044f6a3a0c7a40fbe092b407a2b86..b605fa1e0062140b18fd5b1784fe8ea0fd6171bc 100644 (file)
@@ -1,14 +1,15 @@
 package org.argeo.api.acr;
 
+import static org.argeo.api.acr.NamespaceUtils.unqualified;
+
 import java.io.Closeable;
 import java.io.IOException;
-import java.util.Collection;
+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;
 
 /**
@@ -28,29 +29,48 @@ public interface Content extends Iterable<Content>, Map<QName, Object> {
 
        <A> Optional<A> get(QName key, Class<A> 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);
+
+       <A> List<A> getMultiple(QName key, Class<A> 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 <A> Optional<A> get(QNamed key, Class<A> 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());
+       }
+
+       // TODO do we really need the helpers below?
 
-       <A> Optional<List<A>> getMultiple(QName key, Class<A> clss);
+       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 <A> List<A> getMultiple(QName key) {
@@ -60,14 +80,15 @@ public interface Content extends Iterable<Content>, Map<QName, Object> {
                } catch (ClassCastException e) {
                        throw new IllegalArgumentException("Requested type is not the default type");
                }
-               Optional<List<A>> 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<A> res = getMultiple(key, type);
+               return res;
+//             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();
+//             }
        }
 
        /*
@@ -83,9 +104,7 @@ public interface Content extends Iterable<Content>, Map<QName, Object> {
        Content add(QName name, QName... classes);
 
        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);
        }
 
        void remove();
@@ -119,6 +138,10 @@ public interface Content extends Iterable<Content>, Map<QName, Object> {
                return false;
        }
 
+       default boolean hasContentClass(QNamed contentClass) {
+               return hasContentClass(contentClass.qName());
+       }
+
        /*
         * SIBLINGS
         */
@@ -154,6 +177,10 @@ public interface Content extends Iterable<Content>, Map<QName, Object> {
                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)
@@ -161,6 +188,10 @@ public interface Content extends Iterable<Content>, Map<QName, Object> {
                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) {
@@ -170,23 +201,49 @@ public interface Content extends Iterable<Content>, Map<QName, Object> {
                return null;
        }
 
-       /*
-        * CONVENIENCE METHODS
-        */
-       default String attr(String key) {
-               Object obj = get(key);
-               if (obj == null)
-                       return null;
-               return obj.toString();
+       default List<Content> children(QName name) {
+               List<Content> res = new ArrayList<>();
+               for (Content child : this) {
+                       if (child.getName().equals(name))
+                               res.add(child);
+               }
+               return res;
+       }
+
+       default Optional<Content> soleChild(QName name) {
+               List<Content> 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
+        */
        default String attr(QName key) {
+               // TODO check String type?
                Object obj = get(key);
                if (obj == null)
                        return null;
                return obj.toString();
+       }
 
+       default String attr(QNamed key) {
+               return attr(key.qName());
+       }
+
+       default String attr(String key) {
+               return attr(unqualified(key));
        }
 //
 //     default String attr(Object key) {