Hst Component @Persistable Annotation and Workflow

You can modify repository nodes from the doAction method of an HstComponent. While it is technically possible to perform such modifications in the doBeforeRender method, this approach is discouraged. The doAction method also supports executing workflow actions. Use the org.hippoecm.hst.content.beans.manager.workflow.WorkflowPersistenceManager to perform workflow operations within HST components.

Before using the WorkflowPersistenceManager, note the following: By default, HST rendering uses a JCR session for either liveuser or previewuser. These users typically do not have write access to the repository. If you attempt to perform JCR or workflow operations using a session obtained from:

hstRequest.getRequestContext().getSession()

you generally cannot write to the repository with this session.

To obtain a writable session within a doAction method (or, less commonly, in doBeforeRender), use one of the following approaches:

  1. Call BaseHstComponent#getPersistableSession(HstRequest).
  2. Annotate the doAction method with @Persistable.

Example 1: Using getPersistableSession

@Override public void doAction(HstRequest request, HstResponse response) throws HstComponentException { Session persistableSession = null; try { // Retrieve a writable session. // This session is automatically logged out by the HST request processing thread. // If you obtain a session manually in your own thread, you must log out after use. // If you use multiple persistable sessions in a request, log out sessions as soon as they become idle to return them to the pool. persistableSession = getPersistableSession(request); } catch (Exception e) { } finally { if (persistableSession != null) { persistableSession.logout(); } } }

Example 2: Using the @Persistable Annotation

@Persistable @Override public void doAction(HstRequest request, HstResponse response) throws HstComponentException { try { // This session is automatically logged out by the HST request processing thread. Session persistableSession = request.getRequestContext().getSession(); } catch (Exception e) { } }

Both the @Persistable annotation and the getPersistableSession(HstRequest) method provide access to a JCR session for the user defined by the HST configuration property writable.repository.user.name (typically sitewriter). By default, the sitewriter user has write access only to formdata nodes. To write Hippo Document nodes or perform workflow operations, you must grant additional permissions to the sitewriter user. For details, see Access rights when you want to use workflow from the HST.

Workflow

The WorkflowPersistenceManager allows you to create or modify Hippo Documents by invoking repository workflow actions from HST beans. To use this feature, your HST bean must implement the org.hippoecm.hst.content.beans.ContentNodeBinder interface:

public interface ContentNodeBinder { /** * Performs custom binding from a content POJO to a JCR node. * @param content Content POJO object, which can be retrieved by an OCM solution. * @param node Target JCR node to receive properties or child nodes. * @return true if the binding modifies the node. * @throws ContentNodeBindingException */ boolean bind(Object content, Node node) throws ContentNodeBindingException; }

Example: Implementing a CommentBean

Suppose you want to store a CommentBean as a Comment document in the repository. The following example demonstrates a possible implementation:

@Node(jcrType="demosite:commentdocument") public class CommentBean extends TextBean { private Calendar date; private String commentToUuidOfHandle; @Override public Calendar getDate() { return date == null ? (Calendar)getProperty("demosite:date"): date; } public void setDate(Calendar date) { this.date = date; } public void setCommentTo(String commentToUuidOfHandle) { this.commentToUuidOfHandle = commentToUuidOfHandle; } public BaseBean getCommentTo(){ HippoBean bean = getBean("demosite:commentlink"); if(!(bean instanceof CommentLinkBean)) { return null; } CommentLinkBean commentLinkBean = (CommentLinkBean)bean; if(commentLinkBean == null) { return null; } HippoBean b = commentLinkBean.getReferencedBean(); if(b == null || !(b instanceof BaseBean)) { return null; } return (BaseBean)b; } public boolean bind(Object content, javax.jcr.Node node) throws ContentNodeBindingException { super.bind(content, node); try { BaseBean bean = (BaseBean) content; node.setProperty("demosite:date", bean.getDate()); javax.jcr.Node commentLink = null; if(node.hasNode("demosite:commentlink")) { commentLink = node.getNode("demosite:commentlink"); } else { commentLink = node.addNode("demosite:commentlink", "demosite:commentlink"); } commentLink.setProperty("hippo:docbase", commentToUuidOfHandle); commentLink.setProperty("hippo:values", new String[0]); commentLink.setProperty("hippo:modes", new String[0]); commentLink.setProperty("hippo:facets", new String[0]); } catch (Exception e) { throw new ContentNodeBindingException(e); } return true; } }

In this example, a CommentBean references another document using the demosite:commentlink property, which extends from hippo:facetselect. This allows a comment document to link to the document it comments on.

The bind method is called during WorkflowPersistenceManager operations in HST.

Creating a Comment Document in doAction

The following example shows how to create a new comment document in the repository from a doAction method. The @Persistable annotation ensures that the sitewriter session is used for workflow operations. The wpm.setWorkflowCallbackHandler method registers a callback that executes after wpm.update(commentBean) is called. You can use this callback to perform actions such as delete, publish, requestPublication, or requestDeletion.

@Persistable @Override public void doAction(HstRequest request, HstResponse response) throws HstComponentException { HstRequestContext requestContext = request.getRequestContext(); String type = request.getParameter("type"); if ("add".equals(type)) { String title = request.getParameter("title"); String comment = request.getParameter("comment"); HippoBean commentTo = this.getContentBean(request); if (!(commentTo instanceof HippoDocumentBean)) { log.warn("Cannot comment on non documents"); return; } String commentToUuidOfHandle = ((HippoDocumentBean) commentTo).getCanonicalHandleUUID(); if (title != null && !"".equals(title.trim()) && comment != null) { WorkflowPersistenceManager wpm = null; try { wpm = getWorkflowPersistenceManager(requestContext.getSession()); wpm.setWorkflowCallbackHandler( new BaseWorkflowCallbackHandler<DocumentWorkflow>() { public void processWorkflow( DocumentWorkflow wf) throws Exception { wf.requestPublication(); } }); // Store comments under a timestamped path below the project content String siteCanonicalBasePath = request.getRequestContext().getResolvedMount() .getMount().getCanonicalContentPath(); Calendar currentDate = Calendar.getInstance(); String commentsFolderPath = siteCanonicalBasePath + "/comment/" + currentDate.get(Calendar.YEAR) + "/" + currentDate.get(Calendar.MONTH) + "/" + currentDate.get(Calendar.DAY_OF_MONTH); // Name the comment node with a timestamp for uniqueness String commentNodeName = "comment-for-" + commentTo.getName() + "-" + System.currentTimeMillis(); // Create the comment node wpm.createAndReturn(commentsFolderPath, "demosite:commentdocument", commentNodeName, true); // Retrieve the comment content to update CommentBean commentBean = (CommentBean) wpm.getObject(commentsFolderPath + "/" + commentNodeName); // Update content properties if (commentBean == null) { throw new HstComponentException("Failed to add Comment"); } commentBean.setTitle(SimpleHtmlExtractor.getText(title)); commentBean.setHtml(SimpleHtmlExtractor.getText(comment)); commentBean.setDate(currentDate); commentBean.setCommentTo(commentToUuidOfHandle); // Persist the changes wpm.update(commentBean); } catch (Exception e) { log.warn("Failed to create a comment: ", e); if (wpm != null) { try { wpm.refresh(); } catch (ObjectBeanPersistenceException e1) { log.warn("Failed to refresh: ", e); } } } } } else if ("remove".equals(type)) { } }

For a complete example, refer to the Detail.java doAction method on GitHub.

Share Feedback
Page: /build/component-development/hstcomponent-persistable-annotation-and-workflow
Section: Build
Category *