Working FreeMarker/JCR integration
authorMathieu Baudier <mbaudier@argeo.org>
Wed, 20 Mar 2019 18:22:30 +0000 (19:22 +0100)
committerMathieu Baudier <mbaudier@argeo.org>
Wed, 20 Mar 2019 18:22:30 +0000 (19:22 +0100)
org.argeo.cms/src/org/argeo/cms/internal/http/HtmlServlet.java [new file with mode: 0644]
org.argeo.cms/src/org/argeo/cms/internal/kernel/NodeHttp.java
org.argeo.core/src/org/argeo/fm/jcr/JcrModel.java

diff --git a/org.argeo.cms/src/org/argeo/cms/internal/http/HtmlServlet.java b/org.argeo.cms/src/org/argeo/cms/internal/http/HtmlServlet.java
new file mode 100644 (file)
index 0000000..b4990c3
--- /dev/null
@@ -0,0 +1,124 @@
+package org.argeo.cms.internal.http;
+
+import java.io.File;
+import java.io.IOException;
+import java.security.PrivilegedExceptionAction;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.jcr.Node;
+import javax.jcr.Repository;
+import javax.jcr.Session;
+import javax.security.auth.Subject;
+import javax.security.auth.login.LoginContext;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.argeo.cms.CmsException;
+import org.argeo.cms.auth.HttpRequestCallbackHandler;
+import org.argeo.fm.jcr.JcrModel;
+import org.argeo.jcr.JcrUtils;
+import org.argeo.node.NodeConstants;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.FrameworkUtil;
+import org.osgi.framework.ServiceReference;
+import org.osgi.util.tracker.ServiceTracker;
+
+import freemarker.template.Configuration;
+import freemarker.template.SimpleScalar;
+import freemarker.template.Template;
+import freemarker.template.TemplateExceptionHandler;
+
+public class HtmlServlet extends HttpServlet {
+       private static final long serialVersionUID = 2083925371199357045L;
+       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();
+               }
+       }
+
+       private final BundleContext bc = FrameworkUtil.getBundle(getClass()).getBundleContext();
+       private ServiceTracker<Repository, Repository> repositorySt;
+
+       private Repository repository;
+
+       @Override
+       public void init() throws ServletException {
+               repositorySt = new ServiceTracker<Repository, Repository>(bc, Repository.class, null) {
+
+                       @Override
+                       public Repository addingService(ServiceReference<Repository> reference) {
+                               String cn = reference.getProperty(NodeConstants.CN).toString();
+                               Repository repo = super.addingService(reference);
+                               if (NodeConstants.NODE.equals(cn))
+                                       repository = repo;
+                               return repo;
+                       }
+
+               };
+               repositorySt.open();
+       }
+
+       @Override
+       public void destroy() {
+               if (repositorySt != null)
+                       repositorySt.close();
+       }
+
+       @Override
+       protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
+               String path = req.getPathInfo();
+               String servletPath = req.getServletPath();
+               String[] p = path.split("/");
+
+               String basePath =servletPath+'/'+p[1];
+               String template = p[1] + ".ftl";
+               StringBuilder sb = new StringBuilder();
+               for (int i = 2; i < p.length; i++)
+                       sb.append('/').append(p[i]);
+
+               Session session = null;
+               try {
+                       LoginContext lc = new LoginContext(NodeConstants.LOGIN_CONTEXT_USER,
+                                       new HttpRequestCallbackHandler(req, resp));
+                       lc.login();
+                       session = Subject.doAs(lc.getSubject(), new PrivilegedExceptionAction<Session>() {
+
+                               @Override
+                               public Session run() throws Exception {
+                                       Session session = repository.login();
+                                       return session;
+                               }
+                       });
+
+                       Node node = session.getNode(sb.toString());
+
+                       Template t = cfg.getTemplate(template);
+                       Map<String, Object> root = new HashMap<>();
+                       root.put("node", new JcrModel(node));
+                       root.put("basePath", new SimpleScalar(basePath));
+
+                       t.process(root, resp.getWriter());
+
+                       resp.setContentType("text/html");
+               } catch (Exception e) {
+                       throw new CmsException("Cannot log in", e);
+               } finally {
+                       JcrUtils.logoutQuietly(session);
+               }
+       }
+
+}
index 9a2177df1be0fad1ee14431ea8c59f8d420a1ae4..08d770b8b5ccc7c0b1a46f2968166c8075375fbb 100644 (file)
@@ -18,6 +18,7 @@ import org.apache.jackrabbit.webdav.simple.SimpleWebdavServlet;
 import org.argeo.cms.CmsException;
 import org.argeo.cms.internal.http.CmsSessionProvider;
 import org.argeo.cms.internal.http.DataHttpContext;
+import org.argeo.cms.internal.http.HtmlServlet;
 import org.argeo.cms.internal.http.HttpUtils;
 import org.argeo.cms.internal.http.LinkServlet;
 import org.argeo.cms.internal.http.PrivateHttpContext;
@@ -213,6 +214,7 @@ public class NodeHttp implements KernelConstants {
                        try {
                                httpService.registerServlet("/!", new LinkServlet(), null, null);
                                httpService.registerServlet("/robots.txt", new RobotServlet(), null, null);
+                               httpService.registerServlet("/html", new HtmlServlet(), null, null);
                        } catch (Exception e) {
                                throw new CmsException("Cannot register filters", e);
                        }
index e6e8efad1ed3bb8fe08a4edbbcd748076e5dc080..5cae5c1a86394737dd9bc6bff2128266fed6af91 100644 (file)
@@ -2,12 +2,17 @@ package org.argeo.fm.jcr;
 
 import javax.jcr.Node;
 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,9 +68,20 @@ public class JcrModel implements TemplateNodeModel, TemplateHashModel {
                }
        }
 
+       // HASH
+
        @Override
        public TemplateModel get(String key) throws TemplateModelException {
                try {
+                       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 node.getParent() != null ? new JcrModel(node.getParent()) : null;
+
                        Property property = node.getProperty(key);
                        if (property == null)
                                return null;
@@ -77,10 +93,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);
+                       }
+               }
+
+       }
 }