From: Mathieu Baudier Date: Sat, 11 Dec 2021 18:19:57 +0000 (+0100) Subject: First draft of GCR API X-Git-Tag: argeo-commons-2.3.5~127 X-Git-Url: https://git.argeo.org/?a=commitdiff_plain;h=06af25d84c049b149ee9db2235faeff3170b4f7e;p=lgpl%2Fargeo-commons.git First draft of GCR API --- diff --git a/org.argeo.api/src/org/argeo/api/gcr/AbstractContent.java b/org.argeo.api/src/org/argeo/api/gcr/AbstractContent.java new file mode 100644 index 000000000..a54ff1ee2 --- /dev/null +++ b/org.argeo.api/src/org/argeo/api/gcr/AbstractContent.java @@ -0,0 +1,38 @@ +package org.argeo.api.gcr; + +import java.util.AbstractMap; +import java.util.HashSet; +import java.util.Set; + +public abstract class AbstractContent extends AbstractMap implements Content { + + @Override + public Set> entrySet() { + Set> result = new HashSet<>(); + for (String key : keys()) { + Entry entry = new Entry() { + + @Override + public String getKey() { + return key; + } + + @Override + public Object getValue() { + // TODO check type + return attr(key); + } + + @Override + public Object setValue(Object value) { + throw new UnsupportedOperationException(); + } + + }; + result.add(entry); + } + return result; + } + + protected abstract Iterable keys(); +} diff --git a/org.argeo.api/src/org/argeo/api/gcr/Content.java b/org.argeo.api/src/org/argeo/api/gcr/Content.java new file mode 100644 index 000000000..c5cee9f0e --- /dev/null +++ b/org.argeo.api/src/org/argeo/api/gcr/Content.java @@ -0,0 +1,48 @@ +package org.argeo.api.gcr; + +import java.util.Map; + +public interface Content extends Iterable, Map { + + String getName(); + +// Iterable keys(); + + A get(String key, Class clss); + + ContentSession getSession(); + + /* + * DEFAULT METHODS + */ + default A adapt(Class clss) { + return null; + } + + /* + * CONVENIENCE METHODS + */ + default String attr(String key) { + return get(key, String.class); + } + + default String attr(Enum key) { + return attr(key.name()); + } + + default A get(Enum key, Class clss) { + return get(key.name(), clss); + } + + /* + * EXPERIMENTAL UNSUPPORTED + */ + default boolean hasText() { + return false; + } + + default String getText() { + throw new UnsupportedOperationException(); + } + +} diff --git a/org.argeo.api/src/org/argeo/api/gcr/ContentSession.java b/org.argeo.api/src/org/argeo/api/gcr/ContentSession.java index cd2543f8e..78325b135 100644 --- a/org.argeo.api/src/org/argeo/api/gcr/ContentSession.java +++ b/org.argeo.api/src/org/argeo/api/gcr/ContentSession.java @@ -1,5 +1,7 @@ package org.argeo.api.gcr; -public interface ContentSession { +import java.util.function.Supplier; + +public interface ContentSession extends Supplier { } diff --git a/org.argeo.api/src/org/argeo/api/gcr/Contents.java b/org.argeo.api/src/org/argeo/api/gcr/Contents.java new file mode 100644 index 000000000..62b1e9b45 --- /dev/null +++ b/org.argeo.api/src/org/argeo/api/gcr/Contents.java @@ -0,0 +1,44 @@ +package org.argeo.api.gcr; + +import java.io.PrintStream; +import java.util.function.BiConsumer; + +public class Contents { + public static void traverse(Content content, BiConsumer doIt) { + traverse(content, doIt, 0); + } + + public static void traverse(Content content, BiConsumer doIt, int currentDepth) { + doIt.accept(content, currentDepth); + int nextDepth = currentDepth + 1; + for (Content child : content) { + traverse(child, doIt, nextDepth); + } + } + + public static void print(Content content, PrintStream out, int depth, boolean printText) { + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < depth; i++) { + sb.append(" "); + } + String prefix = sb.toString(); + out.println(prefix + content.getName()); + for (String key : content.keySet()) { + out.println(prefix + " " + key + "=" + content.get(key)); + } + if (printText) { + if (content.hasText()) { + out.println(""); + } + } + } + + public static boolean isString(T t) { + return t instanceof String; + } + + /** Singleton. */ + private Contents() { + + } +} diff --git a/org.argeo.cms/src/org/argeo/cms/gcr/xml/DomContent.java b/org.argeo.cms/src/org/argeo/cms/gcr/xml/DomContent.java new file mode 100644 index 000000000..19bae2d87 --- /dev/null +++ b/org.argeo.cms/src/org/argeo/cms/gcr/xml/DomContent.java @@ -0,0 +1,108 @@ +package org.argeo.cms.gcr.xml; + +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; + +import org.argeo.api.gcr.AbstractContent; +import org.argeo.api.gcr.Content; +import org.argeo.api.gcr.ContentSession; +import org.w3c.dom.Attr; +import org.w3c.dom.Element; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; +import org.w3c.dom.Text; + +public class DomContent extends AbstractContent implements Content { + + private final DomContentSession contentSession; + private final Element element; + +// private String text = null; + private Boolean hasText = null; + + public DomContent(DomContentSession contentSession, Element element) { + this.contentSession = contentSession; + this.element = element; + } + + @Override + public Iterator iterator() { + NodeList nodeList = element.getChildNodes(); + return new ElementIterator(contentSession, nodeList); + } + + @Override + public String getName() { + return element.getNodeName(); + } + + @Override + public Iterable keys() { + // TODO implement an iterator? + Set result = new HashSet<>(); + NamedNodeMap attributes = element.getAttributes(); + for (int i = 0; i < attributes.getLength(); i++) { + Attr attr = (Attr) attributes.item(i); + String attrName = attr.getNodeName(); + result.add(attrName); + } + return result; + } + + @Override + public A get(String key, Class clss) { + if (element.hasAttribute(key)) { + String value = element.getAttribute(key); + if (clss.isAssignableFrom(String.class)) + return (A) value; + else + throw new IllegalArgumentException(); + } else + return null; + } + + @Override + public ContentSession getSession() { + return contentSession; + } + + @Override + public boolean hasText() { +// return element instanceof Text; + if (hasText != null) + return hasText; + NodeList nodeList = element.getChildNodes(); + if (nodeList.getLength() > 1) { + hasText = false; + return hasText; + } + nodes: for (int i = 0; i < nodeList.getLength(); i++) { + Node node = nodeList.item(i); + if (node instanceof Text) { + Text text =(Text) node; + if (!text.isElementContentWhitespace()) { + hasText = true; + break nodes; + } + } + } + if (hasText == null) + hasText = false; + return hasText; +// if (text != null) +// return true; +// text = element.getTextContent(); +// return text != null; + } + + @Override + public String getText() { + if (hasText()) + return element.getTextContent(); + else + return null; + } + +} diff --git a/org.argeo.cms/src/org/argeo/cms/gcr/xml/DomContentSession.java b/org.argeo.cms/src/org/argeo/cms/gcr/xml/DomContentSession.java new file mode 100644 index 000000000..ededa6cca --- /dev/null +++ b/org.argeo.cms/src/org/argeo/cms/gcr/xml/DomContentSession.java @@ -0,0 +1,50 @@ +package org.argeo.cms.gcr.xml; + +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Set; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; + +import org.argeo.api.gcr.Content; +import org.argeo.api.gcr.ContentSession; +import org.argeo.api.gcr.Contents; +import org.w3c.dom.Document; + +public class DomContentSession implements ContentSession { + private Document document; + + public DomContentSession(Document document) { + this.document = document; + this.document.normalizeDocument(); + } + + @Override + public Content get() { + return new DomContent(this, document.getDocumentElement()); + } + + public static void main(String args[]) throws Exception { + HashMap map = new HashMap<>(); + map.put(null, "test"); + System.out.println(map.get(null)); + + Set set = new HashSet<>(); + set.add(null); + + DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); + DocumentBuilder dBuilder = factory.newDocumentBuilder(); + Path testFile; + testFile = Paths.get(System.getProperty("user.home") + "/dev/git/unstable/argeo-commons/pom.xml"); + testFile = Paths.get(System.getProperty("user.home") + "/tmp/test.xml"); + Document doc = dBuilder.parse(Files.newInputStream(testFile)); + + DomContentSession contentSession = new DomContentSession(doc); + Contents.traverse(contentSession.get(), (c, d) -> Contents.print(c, System.out, d, true)); + + } +} diff --git a/org.argeo.cms/src/org/argeo/cms/gcr/xml/ElementIterator.java b/org.argeo.cms/src/org/argeo/cms/gcr/xml/ElementIterator.java new file mode 100644 index 000000000..a5bde1c5d --- /dev/null +++ b/org.argeo.cms/src/org/argeo/cms/gcr/xml/ElementIterator.java @@ -0,0 +1,54 @@ +package org.argeo.cms.gcr.xml; + +import java.util.Iterator; +import java.util.NoSuchElementException; + +import org.argeo.api.gcr.Content; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +public class ElementIterator implements Iterator { + private final DomContentSession contentSession; + private final NodeList nodeList; + + private int currentIndex; + private final int length; + private Element nextElement = null; + + public ElementIterator(DomContentSession contentSession, NodeList nodeList) { + this.contentSession = contentSession; + this.nodeList = nodeList; + + this.length = nodeList.getLength(); + this.currentIndex = 0; + this.nextElement = findNext(); + } + + private Element findNext() { + while (currentIndex < length) { + Node node = nodeList.item(currentIndex); + if (node instanceof Element) { + return (Element) node; + } + currentIndex++; + } + return null; + } + + @Override + public boolean hasNext() { + return nextElement != null; + } + + @Override + public Content next() { + if (nextElement == null) + throw new NoSuchElementException(); + DomContent result = new DomContent(contentSession, nextElement); + currentIndex++; + nextElement = findNext(); + return result; + } + +}