Move RCP support to Argeo SLC
[lgpl/argeo-commons.git] / org.argeo.core / src / org / argeo / fm / jcr / JcrModel.java
index e6e8efad1ed3bb8fe08a4edbbcd748076e5dc080..e41dfdae7245973167fd9093baf0581716200168 100644 (file)
@@ -1,13 +1,22 @@
 package org.argeo.fm.jcr;
 
+import java.util.ArrayList;
+import java.util.List;
+
 import javax.jcr.Node;
+import javax.jcr.NodeIterator;
 import javax.jcr.Property;
+import javax.jcr.PropertyIterator;
 import javax.jcr.RepositoryException;
+import javax.jcr.Value;
 
 import freemarker.template.SimpleScalar;
+import freemarker.template.TemplateCollectionModel;
 import freemarker.template.TemplateHashModel;
+import freemarker.template.TemplateHashModelEx2;
 import freemarker.template.TemplateModel;
 import freemarker.template.TemplateModelException;
+import freemarker.template.TemplateModelIterator;
 import freemarker.template.TemplateNodeModel;
 import freemarker.template.TemplateSequenceModel;
 
@@ -63,13 +72,53 @@ public class JcrModel implements TemplateNodeModel, TemplateHashModel {
                }
        }
 
+       // HASH
+
        @Override
        public TemplateModel get(String key) throws TemplateModelException {
                try {
-                       Property property = node.getProperty(key);
-                       if (property == null)
-                               return null;
-                       return new SimpleScalar(property.getString());
+                       if ("jcr:path".equals(key))
+                               return new SimpleScalar(node.getPath());
+                       if ("jcr:name".equals(key))
+                               return new SimpleScalar(node.getName());
+                       if ("jcr:properties".equals(key))
+                               return new PropertiesModel();
+                       if ("jcr:parent".equals(key))
+                               return !"/".equals(node.getPath()) ? new JcrModel(node.getParent()) : null;
+
+                       Property property = null;
+                       if (!node.hasProperty(key)) {
+                               List<Property> props = new ArrayList<>();
+                               PropertyIterator pit = node.getProperties("*:" + key);
+                               while (pit.hasNext())
+                                       props.add(pit.nextProperty());
+                               if (props.size() > 1)
+                                       throw new TemplateModelException(
+                                                       "Too many properties match " + key + " (" + props + "), use prefix with \\: escape");
+                               if (!props.isEmpty())
+                                       property = props.get(0);
+                       } else
+                               property = node.getProperty(key);
+                       if (property != null)
+                               return propertyValues(property);
+
+                       Node child = null;
+                       if (!node.hasNode(key)) {
+                               List<Node> children = new ArrayList<>();
+                               NodeIterator nit = node.getNodes("*:" + key);
+                               while (nit.hasNext())
+                                       children.add(nit.nextNode());
+                               if (children.size() > 1)
+                                       throw new TemplateModelException(
+                                                       "Too many properties match " + key + " (" + children + "), use prefix with \\: escape");
+                               if (!children.isEmpty())
+                                       child = children.get(0);
+                       } else
+                               child = node.getNode(key);
+                       if (child != null)
+                               return new JcrModel(child);
+                       return null;
+
                } catch (RepositoryException e) {
                        throw new TemplateModelException("Cannot get property " + key + " of " + node, e);
                }
@@ -77,10 +126,147 @@ public class JcrModel implements TemplateNodeModel, TemplateHashModel {
 
        @Override
        public boolean isEmpty() throws TemplateModelException {
-               // JCR default properties always accessible
                return false;
        }
 
-       // HASH
+       public Node getNode() {
+               return node;
+       }
+
+       protected TemplateModel propertyValues(Property property) throws RepositoryException {
+               if (!property.isMultiple())
+                       return new SimpleScalar(property.getString());
+               Value[] values = property.getValues();
+               StringBuilder sb = new StringBuilder();
+               for (Value value : values) {
+                       sb.append(value.getString()).append('\n');
+               }
+               return new SimpleScalar(sb.toString());
+       }
+
+       class PropertiesModel implements TemplateHashModelEx2 {
+               @Override
+               public TemplateModel get(String key) throws TemplateModelException {
+                       return JcrModel.this.get(key);
+               }
+
+               @Override
+               public boolean isEmpty() throws TemplateModelException {
+                       return false;
+               }
+
+               @Override
+               public TemplateCollectionModel keys() throws TemplateModelException {
+                       try {
+                               PropertyIterator pit = node.getProperties();
+                               return new TemplateCollectionModel() {
 
+                                       @Override
+                                       public TemplateModelIterator iterator() throws TemplateModelException {
+                                               return new TemplateModelIterator() {
+
+                                                       @Override
+                                                       public TemplateModel next() throws TemplateModelException {
+                                                               try {
+                                                                       return new SimpleScalar(pit.nextProperty().getName());
+                                                               } catch (RepositoryException e) {
+                                                                       throw new TemplateModelException("Cannot list properties of " + node, e);
+                                                               }
+                                                       }
+
+                                                       @Override
+                                                       public boolean hasNext() throws TemplateModelException {
+                                                               return pit.hasNext();
+                                                       }
+                                               };
+                                       }
+                               };
+                       } catch (RepositoryException e) {
+                               throw new TemplateModelException("Cannot list properties of " + node, e);
+                       }
+               }
+
+               @Override
+               public int size() throws TemplateModelException {
+                       try {
+                               PropertyIterator pit = node.getProperties();
+                               return (int) pit.getSize();
+                       } catch (RepositoryException e) {
+                               throw new TemplateModelException("Cannot list properties of " + node, e);
+                       }
+               }
+
+               @Override
+               public TemplateCollectionModel values() throws TemplateModelException {
+                       try {
+                               PropertyIterator pit = node.getProperties();
+                               return new TemplateCollectionModel() {
+
+                                       @Override
+                                       public TemplateModelIterator iterator() throws TemplateModelException {
+                                               return new TemplateModelIterator() {
+
+                                                       @Override
+                                                       public TemplateModel next() throws TemplateModelException {
+                                                               try {
+                                                                       return propertyValues(pit.nextProperty());
+                                                               } catch (RepositoryException e) {
+                                                                       throw new TemplateModelException("Cannot list properties of " + node, e);
+                                                               }
+                                                       }
+
+                                                       @Override
+                                                       public boolean hasNext() throws TemplateModelException {
+                                                               return pit.hasNext();
+                                                       }
+                                               };
+                                       }
+                               };
+                       } catch (RepositoryException e) {
+                               throw new TemplateModelException("Cannot list properties of " + node, e);
+                       }
+               }
+
+               @Override
+               public KeyValuePairIterator keyValuePairIterator() throws TemplateModelException {
+                       try {
+                               PropertyIterator pit = node.getProperties();
+                               return new KeyValuePairIterator() {
+
+                                       @Override
+                                       public boolean hasNext() throws TemplateModelException {
+                                               return pit.hasNext();
+                                       }
+
+                                       @Override
+                                       public KeyValuePair next() throws TemplateModelException {
+                                               Property property = pit.nextProperty();
+                                               return new KeyValuePair() {
+
+                                                       @Override
+                                                       public TemplateModel getValue() throws TemplateModelException {
+                                                               try {
+                                                                       return propertyValues(property);
+                                                               } catch (RepositoryException e) {
+                                                                       throw new TemplateModelException("Cannot list properties of " + node, e);
+                                                               }
+                                                       }
+
+                                                       @Override
+                                                       public TemplateModel getKey() throws TemplateModelException {
+                                                               try {
+                                                                       return new SimpleScalar(property.getName());
+                                                               } catch (RepositoryException e) {
+                                                                       throw new TemplateModelException("Cannot list properties of " + node, e);
+                                                               }
+                                                       }
+                                               };
+                                       }
+                               };
+                       } catch (RepositoryException e) {
+                               throw new TemplateModelException("Cannot list properties of " + node, e);
+                       }
+               }
+
+       }
 }