Start using FreeMarker
authorMathieu Baudier <mbaudier@argeo.org>
Wed, 20 Mar 2019 11:21:20 +0000 (12:21 +0100)
committerMathieu Baudier <mbaudier@argeo.org>
Wed, 20 Mar 2019 11:21:20 +0000 (12:21 +0100)
org.argeo.cms.ui/src/org/argeo/cms/script/Html.java [new file with mode: 0644]
org.argeo.cms.ui/src/org/argeo/cms/ui/fm/FmUiProvider.java [new file with mode: 0644]
org.argeo.core/bnd.bnd
org.argeo.core/src/org/argeo/fm/Product.java [new file with mode: 0644]
org.argeo.core/src/org/argeo/fm/TestFreeMarker.java [new file with mode: 0644]
org.argeo.core/src/org/argeo/fm/jcr/JcrModel.java [new file with mode: 0644]
org.argeo.core/src/org/argeo/fm/jcr/NodeIteratorModel.java [new file with mode: 0644]

diff --git a/org.argeo.cms.ui/src/org/argeo/cms/script/Html.java b/org.argeo.cms.ui/src/org/argeo/cms/script/Html.java
new file mode 100644 (file)
index 0000000..e9f4f69
--- /dev/null
@@ -0,0 +1,38 @@
+package org.argeo.cms.script;
+
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+
+import org.argeo.cms.ui.fm.FmUiProvider;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+
+public class Html {
+       private String template;
+       private Node context;
+
+       private Control control;
+
+       public Html(Composite parent, String template, Node context) throws RepositoryException {
+               this.template = template;
+               this.context = context;
+               this.control = new FmUiProvider(this.template).createUi(parent, context);
+       }
+
+       public Html(Composite parent, String template) throws RepositoryException {
+               this(parent, template, null);
+       }
+
+       public String getTemplate() {
+               return template;
+       }
+
+       public Node getContext() {
+               return context;
+       }
+
+       public Control getControl() {
+               return control;
+       }
+
+}
diff --git a/org.argeo.cms.ui/src/org/argeo/cms/ui/fm/FmUiProvider.java b/org.argeo.cms.ui/src/org/argeo/cms/ui/fm/FmUiProvider.java
new file mode 100644 (file)
index 0000000..a5fc903
--- /dev/null
@@ -0,0 +1,66 @@
+package org.argeo.cms.ui.fm;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.StringWriter;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+
+import org.argeo.cms.ui.CmsUiProvider;
+import org.argeo.fm.jcr.JcrModel;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.browser.Browser;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+
+import freemarker.template.Configuration;
+import freemarker.template.Template;
+import freemarker.template.TemplateExceptionHandler;
+
+public class FmUiProvider implements CmsUiProvider {
+       static Configuration cfg;
+       static {
+               try {
+                       cfg = new Configuration(Configuration.VERSION_2_3_28);
+                       cfg.setDirectoryForTemplateLoading(new File(System.getProperty("user.home") + File.separator + "dev"
+                                       + File.separator + "work" + File.separator + "ftl"));
+                       cfg.setDefaultEncoding("UTF-8");
+                       cfg.setTemplateExceptionHandler(TemplateExceptionHandler.HTML_DEBUG_HANDLER);
+                       cfg.setLogTemplateExceptions(false);
+                       cfg.setWrapUncheckedExceptions(true);
+               } catch (IOException e) {
+                       // TODO Auto-generated catch block
+                       e.printStackTrace();
+               }
+       }
+
+       private String template;
+
+       public FmUiProvider(String template) {
+               this.template = template;
+       }
+
+       @Override
+       public Control createUi(Composite parent, Node context) throws RepositoryException {
+               Browser browser = new Browser(parent, SWT.NONE);
+               try {
+                       Map<String, Object> root = new HashMap<>();
+                       if (context != null)
+                               root.put("node", new JcrModel(context));
+
+                       Template temp = cfg.getTemplate(template);
+                       StringWriter out = new StringWriter();
+                       temp.process(root, out);
+                       browser.setText(out.toString());
+               } catch (Exception e) {
+                       // TODO Auto-generated catch block
+                       e.printStackTrace();
+               }
+
+               return browser;
+       }
+
+}
index 8f0929c34088fb077b3b72398e3c093c7b5c31e7..2df657c824ba1d3d3876ab77628c2b64b527ad23 100644 (file)
@@ -1 +1,3 @@
 #Main-Class: org.argeo.sync.cli.Sync
+
+Import-Package: *;resolution:=optional
\ No newline at end of file
diff --git a/org.argeo.core/src/org/argeo/fm/Product.java b/org.argeo.core/src/org/argeo/fm/Product.java
new file mode 100644 (file)
index 0000000..a57ae0d
--- /dev/null
@@ -0,0 +1,31 @@
+package org.argeo.fm;
+
+/**
+ * Product bean; note that it must be a public class!
+ */
+public class Product {
+
+       private String url;
+       private String name;
+
+       // As per the JavaBeans spec., this defines the "url" bean property
+       // It must be public!
+       public String getUrl() {
+               return url;
+       }
+
+       public void setUrl(String url) {
+               this.url = url;
+       }
+
+       // As per the JavaBean spec., this defines the "name" bean property
+       // It must be public!
+       public String getName() {
+               return name;
+       }
+
+       public void setName(String name) {
+               this.name = name;
+       }
+
+}
\ No newline at end of file
diff --git a/org.argeo.core/src/org/argeo/fm/TestFreeMarker.java b/org.argeo.core/src/org/argeo/fm/TestFreeMarker.java
new file mode 100644 (file)
index 0000000..a0c1c48
--- /dev/null
@@ -0,0 +1,60 @@
+package org.argeo.fm;
+
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.Writer;
+import java.util.HashMap;
+import java.util.Map;
+
+import freemarker.template.Configuration;
+import freemarker.template.Template;
+import freemarker.template.TemplateExceptionHandler;
+
+public class TestFreeMarker {
+       static String base = System.getProperty("user.home") + File.separator + "dev" + File.separator + "work"
+                       + File.separator + "ftl";
+       static Configuration cfg;
+       static {
+               try {
+                       cfg = new Configuration(Configuration.VERSION_2_3_28);
+                       cfg.setDirectoryForTemplateLoading(new File(base));
+                       cfg.setDefaultEncoding("UTF-8");
+                       cfg.setTemplateExceptionHandler(TemplateExceptionHandler.HTML_DEBUG_HANDLER);
+                       cfg.setLogTemplateExceptions(false);
+                       cfg.setWrapUncheckedExceptions(true);
+               } catch (IOException e) {
+                       // TODO Auto-generated catch block
+                       e.printStackTrace();
+               }
+       }
+
+       public static void main(String[] args) {
+               if (args.length == 0) {
+                       System.err.println("Usage: <template name> (in " + base + ")");
+               }
+               String template = args[0];
+               try {
+                       /* Create a data-model */
+                       Map<String, Object> root = new HashMap<>();
+                       root.put("user", "Big Joe");
+                       Product latest = new Product();
+                       latest.setUrl("products/greenmouse.html");
+                       latest.setName("green mouse");
+                       root.put("latestProduct", latest);
+
+                       /* Get the template (uses cache internally) */
+                       Template temp = cfg.getTemplate(template);
+
+                       /* Merge data-model with template */
+                       String target = base + File.separator + template + ".html";
+                       Writer out = new FileWriter(target);
+                       temp.process(root, out);
+                       out.flush();
+                       System.out.println("Wrote " + target);
+               } catch (Exception e) {
+                       e.printStackTrace();
+               }
+       }
+
+}
diff --git a/org.argeo.core/src/org/argeo/fm/jcr/JcrModel.java b/org.argeo.core/src/org/argeo/fm/jcr/JcrModel.java
new file mode 100644 (file)
index 0000000..e6e8efa
--- /dev/null
@@ -0,0 +1,86 @@
+package org.argeo.fm.jcr;
+
+import javax.jcr.Node;
+import javax.jcr.Property;
+import javax.jcr.RepositoryException;
+
+import freemarker.template.SimpleScalar;
+import freemarker.template.TemplateHashModel;
+import freemarker.template.TemplateModel;
+import freemarker.template.TemplateModelException;
+import freemarker.template.TemplateNodeModel;
+import freemarker.template.TemplateSequenceModel;
+
+public class JcrModel implements TemplateNodeModel, TemplateHashModel {
+       private final Node node;
+
+       public JcrModel(Node node) {
+               this.node = node;
+       }
+
+       @Override
+       public TemplateSequenceModel getChildNodes() throws TemplateModelException {
+               try {
+                       return new NodeIteratorModel(node.getNodes());
+               } catch (RepositoryException e) {
+                       throw new TemplateModelException("Cannot list children of " + node, e);
+               }
+       }
+
+       @Override
+       public String getNodeName() throws TemplateModelException {
+               try {
+                       return node.getName();
+               } catch (RepositoryException e) {
+                       throw new TemplateModelException("Cannot get name of " + node, e);
+               }
+       }
+
+       @Override
+       public String getNodeNamespace() throws TemplateModelException {
+               // TODO find out namespace
+               return null;
+       }
+
+       @Override
+       public String getNodeType() throws TemplateModelException {
+               try {
+                       return node.getPrimaryNodeType().getName();
+               } catch (RepositoryException e) {
+                       throw new TemplateModelException("Cannot get node type of " + node, e);
+               }
+       }
+
+       @Override
+       public TemplateNodeModel getParentNode() throws TemplateModelException {
+               try {
+                       Node parent = node.getParent();
+                       if (parent == null)
+                               return null;
+                       return new JcrModel(parent);
+               } catch (RepositoryException e) {
+                       throw new TemplateModelException("Cannot get parent of " + node, e);
+               }
+       }
+
+       @Override
+       public TemplateModel get(String key) throws TemplateModelException {
+               try {
+                       Property property = node.getProperty(key);
+                       if (property == null)
+                               return null;
+                       return new SimpleScalar(property.getString());
+               } catch (RepositoryException e) {
+                       throw new TemplateModelException("Cannot get property " + key + " of " + node, e);
+               }
+       }
+
+       @Override
+       public boolean isEmpty() throws TemplateModelException {
+               // JCR default properties always accessible
+               return false;
+       }
+
+       // HASH
+
+}
diff --git a/org.argeo.core/src/org/argeo/fm/jcr/NodeIteratorModel.java b/org.argeo.core/src/org/argeo/fm/jcr/NodeIteratorModel.java
new file mode 100644 (file)
index 0000000..61bcb36
--- /dev/null
@@ -0,0 +1,42 @@
+package org.argeo.fm.jcr;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.jcr.Node;
+import javax.jcr.NodeIterator;
+
+import freemarker.template.TemplateModel;
+import freemarker.template.TemplateModelException;
+import freemarker.template.TemplateSequenceModel;
+
+public class NodeIteratorModel implements TemplateSequenceModel {
+       private final NodeIterator nodeIterator;
+
+       private final List<Node> nodes;
+       private int size;
+
+       public NodeIteratorModel(NodeIterator nodeIterator) {
+               super();
+               this.nodeIterator = nodeIterator;
+               this.size = (int) nodeIterator.getSize();
+               this.nodes = new ArrayList<>(this.size);
+               // TODO optimize with lazy loading
+               while (this.nodeIterator.hasNext()) {
+                       Node node = this.nodeIterator.nextNode();
+                       nodes.add(node);
+               }
+               this.size = nodes.size();
+       }
+
+       @Override
+       public TemplateModel get(int index) throws TemplateModelException {
+               return new JcrModel(nodes.get(index));
+       }
+
+       @Override
+       public int size() throws TemplateModelException {
+               return size;
+       }
+
+}