From 56db62a204d7c371f4e496f9cbe45efe1d9a563a Mon Sep 17 00:00:00 2001 From: Mathieu Baudier Date: Tue, 10 Nov 2015 14:57:38 +0000 Subject: [PATCH] Improve social networking git-svn-id: https://svn.argeo.org/commons/trunk@8565 4cfe0d0a-d680-48aa-b62c-e0a02a3f76cc --- .../org/argeo/cms/AbstractCmsEntryPoint.java | 10 ++ .../argeo/cms/internal/kernel/DataHttp.java | 2 +- .../org/argeo/cms/internal/kernel/Kernel.java | 6 +- .../argeo/cms/internal/kernel/NodeHttp.java | 128 ++++++++++++++++-- 4 files changed, 134 insertions(+), 12 deletions(-) diff --git a/org.argeo.cms/src/org/argeo/cms/AbstractCmsEntryPoint.java b/org.argeo.cms/src/org/argeo/cms/AbstractCmsEntryPoint.java index 2ff9aff58..56e5d6914 100644 --- a/org.argeo.cms/src/org/argeo/cms/AbstractCmsEntryPoint.java +++ b/org.argeo.cms/src/org/argeo/cms/AbstractCmsEntryPoint.java @@ -1,5 +1,7 @@ package org.argeo.cms; +import static javax.jcr.Property.JCR_DESCRIPTION; + import java.security.PrivilegedAction; import java.util.HashMap; import java.util.Map; @@ -297,6 +299,8 @@ public abstract class AbstractCmsEntryPoint extends AbstractEntryPoint if (request == null) return; String url = CmsUtils.getCanonicalUrl(node, request); + String desc = node.hasProperty(JCR_DESCRIPTION) ? node.getProperty( + JCR_DESCRIPTION).getString() : null; String imgUrl = null; for (NodeIterator it = node.getNodes(); it.hasNext();) { Node child = it.nextNode(); @@ -313,6 +317,12 @@ public abstract class AbstractCmsEntryPoint extends AbstractEntryPoint js.append(" metas[i].setAttribute('content','" + title + "');"); js.append(" else if(metas[i].getAttribute('property')=='og:url')"); js.append(" metas[i].setAttribute('content','" + url + "');"); + js.append(" else if(metas[i].getAttribute('property')=='og:type')"); + js.append(" metas[i].setAttribute('content','website');"); + if (desc != null) { + js.append(" else if(metas[i].getAttribute('property')=='og:decription')"); + js.append(" metas[i].setAttribute('content','" + desc + "');"); + } if (imgUrl != null) { js.append(" else if(metas[i].getAttribute('property')=='og:image')"); js.append(" metas[i].setAttribute('content','" + imgUrl + "');"); diff --git a/org.argeo.cms/src/org/argeo/cms/internal/kernel/DataHttp.java b/org.argeo.cms/src/org/argeo/cms/internal/kernel/DataHttp.java index 123455e7d..283818086 100644 --- a/org.argeo.cms/src/org/argeo/cms/internal/kernel/DataHttp.java +++ b/org.argeo.cms/src/org/argeo/cms/internal/kernel/DataHttp.java @@ -62,7 +62,7 @@ class DataHttp implements KernelConstants, ArgeoJcrConstants { // WebDav / JCR remoting private OpenInViewSessionProvider sessionProvider; - DataHttp(HttpService httpService, NodeRepository node) { + DataHttp(HttpService httpService) { this.httpService = httpService; sessionProvider = new OpenInViewSessionProvider(); // registerRepositoryServlets(ALIAS_NODE, node); diff --git a/org.argeo.cms/src/org/argeo/cms/internal/kernel/Kernel.java b/org.argeo.cms/src/org/argeo/cms/internal/kernel/Kernel.java index 71b1a5bdd..3960be687 100644 --- a/org.argeo.cms/src/org/argeo/cms/internal/kernel/Kernel.java +++ b/org.argeo.cms/src/org/argeo/cms/internal/kernel/Kernel.java @@ -477,8 +477,8 @@ final class Kernel implements KernelHeader, KernelConstants, ServiceListener { // TODO find constants Object httpPort = sr.getProperty("http.port"); Object httpsPort = sr.getProperty("https.port"); - dataHttp = new DataHttp(httpService, repository); - nodeHttp = new NodeHttp(httpService); + dataHttp = new DataHttp(httpService); + nodeHttp = new NodeHttp(httpService, repository); if (log.isDebugEnabled()) log.debug(httpPortsMsg(httpPort, httpsPort)); } @@ -562,7 +562,7 @@ final class Kernel implements KernelHeader, KernelConstants, ServiceListener { rootThreadGroup.enumerate(threads); int nonDameonCount = 0; for (Thread t : threads) - if (t!=null && !t.isDaemon()) + if (t != null && !t.isDaemon()) nonDameonCount++; return nonDameonCount; } 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 f88ba6789..6e3ef3246 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 @@ -1,9 +1,21 @@ package org.argeo.cms.internal.kernel; +import static javax.jcr.Property.JCR_DESCRIPTION; +import static javax.jcr.Property.JCR_TITLE; +import static org.argeo.cms.CmsTypes.CMS_IMAGE; + import java.io.IOException; +import java.io.PrintWriter; +import java.security.PrivilegedExceptionAction; import java.security.cert.X509Certificate; import java.util.Enumeration; +import javax.jcr.Node; +import javax.jcr.NodeIterator; +import javax.jcr.Repository; +import javax.jcr.RepositoryException; +import javax.jcr.Session; +import javax.security.auth.Subject; import javax.servlet.FilterChain; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; @@ -14,7 +26,9 @@ import javax.servlet.http.HttpSession; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.argeo.cms.CmsException; +import org.argeo.cms.util.CmsUtils; import org.argeo.jcr.ArgeoJcrConstants; +import org.argeo.jcr.JcrUtils; import org.eclipse.equinox.http.servlet.ExtendedHttpService; /** @@ -30,14 +44,17 @@ class NodeHttp implements KernelConstants, ArgeoJcrConstants { // private final DoSFilter dosFilter; // private final QoSFilter qosFilter; - NodeHttp(ExtendedHttpService httpService) { + private Repository repository; + + NodeHttp(ExtendedHttpService httpService, NodeRepository node) { + this.repository = node; // rootFilter = new RootFilter(); // dosFilter = new CustomDosFilter(); // qosFilter = new QoSFilter(); try { - httpService.registerServlet("/!", new LinkServlet(), null, null); - // httpService.registerFilter("/", rootFilter, null, null); + httpService.registerServlet("/!", new LinkServlet(repository), + null, null); } catch (Exception e) { throw new CmsException("Cannot register filters", e); } @@ -46,8 +63,13 @@ class NodeHttp implements KernelConstants, ArgeoJcrConstants { public void destroy() { } - class LinkServlet extends HttpServlet { + static class LinkServlet extends HttpServlet { private static final long serialVersionUID = 3749990143146845708L; + private final Repository repository; + + public LinkServlet(Repository repository) { + this.repository = repository; + } @Override protected void service(HttpServletRequest request, @@ -71,14 +93,104 @@ class NodeHttp implements KernelConstants, ArgeoJcrConstants { isCompatibleBrowser = true; } - if (isBot) + if (isBot) { log.warn("# BOT " + request.getHeader("User-Agent")); + canonicalAnswer(request, response, path); + return; + } + if (isCompatibleBrowser && log.isTraceEnabled()) log.trace("# BWS " + request.getHeader("User-Agent")); - // if (isCompatibleBrowser) {// redirect - response.setHeader("Location", "/#" + path); + redirectTo(response, "/#" + path); + } + + private void redirectTo(HttpServletResponse response, String location) { + response.setHeader("Location", location); response.setStatus(HttpServletResponse.SC_FOUND); - // } + } + + // private boolean canonicalAnswerNeededBy(HttpServletRequest request) { + // String userAgent = request.getHeader("User-Agent").toLowerCase(); + // return userAgent.startsWith("facebookexternalhit/"); + // } + + /** For bots which don't understand RWT. */ + private void canonicalAnswer(HttpServletRequest request, + HttpServletResponse response, String path) { + Session session = null; + try { + PrintWriter writer = response.getWriter(); + session = Subject.doAs(KernelUtils.anonymousLogin(), + new PrivilegedExceptionAction() { + + @Override + public Session run() throws Exception { + return repository.login(); + } + + }); + Node node = session.getNode(path); + String title = node.hasProperty(JCR_TITLE) ? node.getProperty( + JCR_TITLE).getString() : node.getName(); + String desc = node.hasProperty(JCR_DESCRIPTION) ? node + .getProperty(JCR_DESCRIPTION).getString() : null; + String url = CmsUtils.getCanonicalUrl(node, request); + String imgUrl = null; + for (NodeIterator it = node.getNodes(); it.hasNext();) { + Node child = it.nextNode(); + if (child.isNodeType(CMS_IMAGE)) + imgUrl = CmsUtils.getDataUrl(child, request); + } + StringBuilder buf = new StringBuilder(); + buf.append(""); + buf.append(""); + writeMeta(buf, "og:title", title); + writeMeta(buf, "og:type", "website"); + writeMeta(buf, "og:url", url); + if (desc != null) + writeMeta(buf, "og:description", desc); + if (imgUrl != null) + writeMeta(buf, "og:image", imgUrl); + buf.append(""); + buf.append(""); + buf.append( + "

!! This page is meant for indexing robots, not for real people," + + " visit ").append(title) + .append(" instead.

"); + writeCanonical(buf, node); + buf.append(""); + buf.append(""); + writer.print(buf.toString()); + writer.flush(); + } catch (Exception e) { + throw new CmsException("Cannot write canonical answer", e); + } finally { + JcrUtils.logoutQuietly(session); + } + } + + private void writeMeta(StringBuilder buf, String tag, String value) { + buf.append(""); + } + + private void writeCanonical(StringBuilder buf, Node node) + throws RepositoryException { + buf.append("
"); + if (node.hasProperty(JCR_TITLE)) + buf.append("

") + .append(node.getProperty(JCR_TITLE).getString()) + .append("

"); + if (node.hasProperty(JCR_DESCRIPTION)) + buf.append("

") + .append(node.getProperty(JCR_DESCRIPTION).getString()) + .append("

"); + NodeIterator children = node.getNodes(); + while (children.hasNext()) { + writeCanonical(buf, children.nextNode()); + } + buf.append("
"); } } -- 2.30.2