From: Mathieu Baudier Date: Wed, 20 Mar 2019 18:22:30 +0000 (+0100) Subject: Working FreeMarker/JCR integration X-Git-Tag: argeo-commons-2.1.77~21 X-Git-Url: https://git.argeo.org/?p=lgpl%2Fargeo-commons.git;a=commitdiff_plain;h=00baefdde06ccc6acd6493f5752b98f008419feb Working FreeMarker/JCR integration --- 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 index 000000000..b4990c3f4 --- /dev/null +++ b/org.argeo.cms/src/org/argeo/cms/internal/http/HtmlServlet.java @@ -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 repositorySt; + + private Repository repository; + + @Override + public void init() throws ServletException { + repositorySt = new ServiceTracker(bc, Repository.class, null) { + + @Override + public Repository addingService(ServiceReference 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() { + + @Override + public Session run() throws Exception { + Session session = repository.login(); + return session; + } + }); + + Node node = session.getNode(sb.toString()); + + Template t = cfg.getTemplate(template); + Map 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); + } + } + +} diff --git a/org.argeo.cms/src/org/argeo/cms/internal/kernel/NodeHttp.java b/org.argeo.cms/src/org/argeo/cms/internal/kernel/NodeHttp.java index 9a2177df1..08d770b8b 100644 --- a/org.argeo.cms/src/org/argeo/cms/internal/kernel/NodeHttp.java +++ b/org.argeo.cms/src/org/argeo/cms/internal/kernel/NodeHttp.java @@ -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); } diff --git a/org.argeo.core/src/org/argeo/fm/jcr/JcrModel.java b/org.argeo.core/src/org/argeo/fm/jcr/JcrModel.java index e6e8efad1..5cae5c1a8 100644 --- a/org.argeo.core/src/org/argeo/fm/jcr/JcrModel.java +++ b/org.argeo.core/src/org/argeo/fm/jcr/JcrModel.java @@ -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); + } + } + + } }