Clarify ACR API
[lgpl/argeo-commons.git] / org.argeo.api.acr / src / org / argeo / api / acr / QualifiedData.java
index 89ab665df1de9138c2fccf2ac93788bee3af3bc7..b2c7bbb90073ad8334fc2da29f673c10d9905ee0 100644 (file)
@@ -1,8 +1,187 @@
 package org.argeo.api.acr;
 
+import static org.argeo.api.acr.NamespaceUtils.unqualified;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Optional;
+
 import javax.xml.namespace.QName;
 
 /** A {@link StructuredData} whose attributes have qualified keys. */
 public interface QualifiedData<CHILD extends QualifiedData<CHILD>> extends StructuredData<QName, Object, CHILD> {
+       QName getName();
+
+       CHILD getParent();
+
+       /*
+        * ATTRIBUTES OPERATIONS
+        */
+
+       <A> Optional<A> get(QName key, Class<A> clss);
+
+       Class<?> getType(QName key);
+
+       boolean isMultiple(QName key);
+
+       <A> List<A> getMultiple(QName key, Class<A> clss);
+
+       /*
+        * PATH
+        */
+       char getPathSeparator();
+
+       /*
+        * ATTRIBUTES OPERATION HELPERS
+        */
+       default boolean containsKey(QNamed key) {
+               return containsKey(key.qName());
+       }
+
+       default <A> Optional<A> get(QNamed key, Class<A> clss) {
+               return get(key.qName(), clss);
+       }
+
+       default Object get(QNamed key) {
+               return get(key.qName());
+       }
+
+       default Object put(QNamed key, Object value) {
+               return put(key.qName(), value);
+       }
+
+       default Object remove(QNamed key) {
+               return remove(key.qName());
+       }
+
+       // 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 <A> List<A> getMultiple(QName key) {
+               Class<A> type;
+               try {
+                       type = (Class<A>) getType(key);
+               } catch (ClassCastException e) {
+                       throw new IllegalArgumentException("Requested type is not the default type");
+               }
+               List<A> res = getMultiple(key, type);
+               return res;
+       }
+
+       /*
+        * CHILDREN
+        */
+
+       default boolean hasChild(QName name) {
+               for (CHILD child : this) {
+                       if (child.getName().equals(name))
+                               return true;
+               }
+               return false;
+       }
+
+       default boolean hasChild(QNamed name) {
+               return hasChild(name.qName());
+       }
+
+       /** Any child with this name, or null if there is none */
+       default CHILD anyChild(QName name) {
+               for (CHILD child : this) {
+                       if (child.getName().equals(name))
+                               return child;
+               }
+               return null;
+       }
+
+       default List<CHILD> children(QName name) {
+               List<CHILD> res = new ArrayList<>();
+               for (CHILD child : this) {
+                       if (child.getName().equals(name))
+                               res.add(child);
+               }
+               return res;
+       }
+
+       default List<CHILD> children(QNamed name) {
+               return children(name.qName());
+       }
+
+       default Optional<CHILD> soleChild(QNamed name) {
+               return soleChild(name.qName());
+       }
+
+       default Optional<CHILD> soleChild(QName name) {
+               List<CHILD> 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 CHILD child(QName name) {
+               return soleChild(name).orElseThrow();
+       }
+
+       default CHILD 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 <code>null</code>.
+        * 
+        * @see Object#toString()
+        */
+       default String attr(QName key) {
+               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 <code>null</code>.
+        * 
+        * @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 <code>null</code>.
+        * 
+        * @see Object#toString()
+        */
+       default String attr(String key) {
+               return attr(unqualified(key));
+       }
 
+       /*
+        * SIBLINGS
+        */
+       default int getSiblingIndex() {
+               return 1;
+       }
 }