Put Eclipse and JCR components in subdirs in order to clarify indirect
[lgpl/argeo-commons.git] / jcr / org.argeo.cms.jcr / src / org / argeo / cms / jcr / acr / JcrContent.java
diff --git a/jcr/org.argeo.cms.jcr/src/org/argeo/cms/jcr/acr/JcrContent.java b/jcr/org.argeo.cms.jcr/src/org/argeo/cms/jcr/acr/JcrContent.java
new file mode 100644 (file)
index 0000000..04c5d2d
--- /dev/null
@@ -0,0 +1,201 @@
+package org.argeo.cms.jcr.acr;
+
+import java.util.Calendar;
+import java.util.Iterator;
+import java.util.Optional;
+
+import javax.jcr.Node;
+import javax.jcr.NodeIterator;
+import javax.jcr.Property;
+import javax.jcr.PropertyIterator;
+import javax.jcr.PropertyType;
+import javax.jcr.RepositoryException;
+import javax.jcr.Value;
+import javax.jcr.nodetype.NodeType;
+import javax.xml.namespace.QName;
+
+import org.argeo.api.acr.Content;
+import org.argeo.api.acr.spi.AbstractContent;
+import org.argeo.api.acr.spi.ProvidedSession;
+import org.argeo.jcr.Jcr;
+import org.argeo.jcr.JcrException;
+
+public class JcrContent extends AbstractContent {
+       private Node jcrNode;
+
+       private JcrContentProvider provider;
+       private ProvidedSession session;
+
+       protected JcrContent(ProvidedSession session, JcrContentProvider provider, Node node) {
+               this.session = session;
+               this.provider = provider;
+               this.jcrNode = node;
+       }
+
+       @Override
+       public QName getName() {
+               return session.parsePrefixedName(Jcr.getName(jcrNode));
+       }
+
+       @Override
+       public <A> Optional<A> get(QName key, Class<A> clss) {
+               if (isDefaultAttrTypeRequested(clss)) {
+                       return Optional.of((A) get(jcrNode, key.toString()));
+               }
+               return Optional.of((A) Jcr.get(jcrNode, key.toString()));
+       }
+
+       @Override
+       public Iterator<Content> iterator() {
+               try {
+                       return new JcrContentIterator(jcrNode.getNodes());
+               } catch (RepositoryException e) {
+                       throw new JcrException("Cannot list children of " + jcrNode, e);
+               }
+       }
+
+       @Override
+       protected Iterable<QName> keys() {
+               return new Iterable<QName>() {
+
+                       @Override
+                       public Iterator<QName> iterator() {
+                               try {
+                                       PropertyIterator propertyIterator = jcrNode.getProperties();
+                                       return new JcrKeyIterator(provider, propertyIterator);
+                               } catch (RepositoryException e) {
+                                       throw new JcrException("Cannot retrive properties from " + jcrNode, e);
+                               }
+                       }
+               };
+       }
+
+       public Node getJcrNode() {
+               return jcrNode;
+       }
+
+       /** Cast to a standard Java object. */
+       static Object get(Node node, String property) {
+               try {
+                       Value value = node.getProperty(property).getValue();
+                       switch (value.getType()) {
+                       case PropertyType.STRING:
+                               return value.getString();
+                       case PropertyType.DOUBLE:
+                               return (Double) value.getDouble();
+                       case PropertyType.LONG:
+                               return (Long) value.getLong();
+                       case PropertyType.BOOLEAN:
+                               return (Boolean) value.getBoolean();
+                       case PropertyType.DATE:
+                               Calendar calendar = value.getDate();
+                               return calendar.toInstant();
+                       case PropertyType.BINARY:
+                               throw new IllegalArgumentException("Binary is not supported as an attribute");
+                       default:
+                               return value.getString();
+                       }
+               } catch (RepositoryException e) {
+                       throw new JcrException("Cannot cast value from " + property + " of node " + node, e);
+               }
+       }
+
+       class JcrContentIterator implements Iterator<Content> {
+               private final NodeIterator nodeIterator;
+               // we keep track in order to be able to delete it
+               private JcrContent current = null;
+
+               protected JcrContentIterator(NodeIterator nodeIterator) {
+                       this.nodeIterator = nodeIterator;
+               }
+
+               @Override
+               public boolean hasNext() {
+                       return nodeIterator.hasNext();
+               }
+
+               @Override
+               public Content next() {
+                       current = new JcrContent(session, provider, nodeIterator.nextNode());
+                       return current;
+               }
+
+               @Override
+               public void remove() {
+                       if (current != null) {
+                               Jcr.remove(current.getJcrNode());
+                       }
+               }
+
+       }
+
+       @Override
+       public Content getParent() {
+               return new JcrContent(session, provider, Jcr.getParent(getJcrNode()));
+       }
+
+       @Override
+       public Content add(QName name, QName... classes) {
+               if (classes.length > 0) {
+                       QName primaryType = classes[0];
+                       Node child = Jcr.addNode(getJcrNode(), name.toString(), primaryType.toString());
+                       for (int i = 1; i < classes.length; i++) {
+                               try {
+                                       child.addMixin(classes[i].toString());
+                               } catch (RepositoryException e) {
+                                       throw new JcrException("Cannot add child to " + getJcrNode(), e);
+                               }
+                       }
+
+               } else {
+                       Jcr.addNode(getJcrNode(), name.toString(), NodeType.NT_UNSTRUCTURED);
+               }
+               return null;
+       }
+
+       @Override
+       public void remove() {
+               Jcr.remove(getJcrNode());
+       }
+
+       @Override
+       protected void removeAttr(QName key) {
+               Property property = Jcr.getProperty(getJcrNode(), key.toString());
+               if (property != null) {
+                       try {
+                               property.remove();
+                       } catch (RepositoryException e) {
+                               throw new JcrException("Cannot remove property " + key + " from " + getJcrNode(), e);
+                       }
+               }
+
+       }
+
+       class JcrKeyIterator implements Iterator<QName> {
+               private final JcrContentProvider contentSession;
+               private final PropertyIterator propertyIterator;
+
+               protected JcrKeyIterator(JcrContentProvider contentSession, PropertyIterator propertyIterator) {
+                       this.contentSession = contentSession;
+                       this.propertyIterator = propertyIterator;
+               }
+
+               @Override
+               public boolean hasNext() {
+                       return propertyIterator.hasNext();
+               }
+
+               @Override
+               public QName next() {
+                       Property property = null;
+                       try {
+                               property = propertyIterator.nextProperty();
+                               // TODO map standard property names
+                               return session.parsePrefixedName(property.getName());
+                       } catch (RepositoryException e) {
+                               throw new JcrException("Cannot retrieve property " + property, null);
+                       }
+               }
+
+       }
+}