/**
  * Set authorizable id.
  *
  * @param request The sling request.
  * @param node The node where the authorizableId property is set
  * @throws RepositoryException if there is an error when saving to repository
  */
 private void setAuthorizableId(final SlingHttpServletRequest request, final Node node)
     throws RepositoryException {
   final String userIdentifier = request.getParameter(CollabUser.PROP_NAME);
   final Profile sessionProfile = getSessionProfile(request);
   String sessionUserId = null;
   if (sessionProfile != null) {
     sessionUserId = sessionProfile.getAuthorizable().getID();
   }
   if (StringUtils.isNotBlank(sessionUserId)) {
     final boolean anonymous = "anonymous".equals(sessionUserId);
     final boolean authorMode = isAuthorMode();
     if (!anonymous && authorMode) {
       final boolean userExists = userExists(userIdentifier, node.getSession());
       final boolean hasPermissions =
           hasPermissions(userIdentifier, getRequestSession(request), node.getSession());
       // use node.getSession() because that's an admin session
       if (userExists && hasPermissions) {
         JcrUtil.setProperty(node, "authorizableId", userIdentifier);
         if (!userIdentifier.equals(sessionUserId)) {
           log.warn(
               "host {} posted a comment with different userIdentifier ({}) than sessionUserId ({})",
               new String[] {request.getRemoteAddr(), userIdentifier, sessionUserId});
         }
       } else {
         log.warn(
             "host {} posted a comment with an unknown userIdentifier ({})",
             request.getRemoteAddr(),
             userIdentifier);
       }
     } else if (!anonymous && !authorMode) {
       final String userId = sessionUserId;
       if (userIdentifier != null && !sessionUserId.equals(userIdentifier)) {
         final StringBuilder exception = new StringBuilder("host ");
         exception.append(request.getRemoteAddr());
         exception.append("posted a comment with suspect userIdentifier (");
         exception.append(userIdentifier);
         exception.append("), sessionUserId (");
         exception.append(sessionUserId);
         exception.append(")");
         final String exceptionMessage = exception.toString();
         if (log.isWarnEnabled()) {
           log.warn(exceptionMessage);
         }
         throw new CommentException(exceptionMessage);
       }
       JcrUtil.setProperty(node, "authorizableId", userId);
     }
   }
 }
  /** Rewrites the matched subtree. */
  public Node applyTo(Node root, Set<Node> finalNodes)
      throws DialogRewriteException, RepositoryException {
    // save reference to parent node and node name
    Node parent = root.getParent();
    String name = root.getName();

    // rename the root of the tree to rewrite
    rename(root);

    // add a new root with the same name as the original tree
    Node newRoot = parent.addNode(name, "nt:unstructured");

    // add new nodes / properties etc.
    newRoot.setProperty("sling:resourceType", "granite/ui/components/custom");
    Node foo = newRoot.addNode("foo", "nt:unstructured");
    foo.setProperty("bar", 10);

    // copy / convert properties from the original tree
    copyProperty(root, "someName", newRoot, "someNewName");

    // copy nodes from the original tree
    if (root.hasNode("items")) {
      NodeIterator iterator = root.getNode("items").getNodes();
      while (iterator.hasNext()) {
        Node child = iterator.nextNode();
        JcrUtil.copy(child, foo, child.getName());
      }
    }

    // etc...

    // as an optimization, optionally report which of the nodes of the resulting tree are final
    // and don't need to be reconsidered again
    finalNodes.add(newRoot);
    finalNodes.add(foo);

    // remove old root and return new one
    root.remove();
    return newRoot;
  }
  /**
   * This method renders the given request URI using the Sling request processing and stores the
   * result at the request's location relative to the cache root folder. The request is processed in
   * the context of the given user's session.
   *
   * @param uri The request URI including selectors and extensions
   * @param configCacheRoot The cache root folder
   * @param admin The admin session used to store the result in the cache
   * @param session The user's session
   * @return <code>true</code> if the cache was updated
   */
  protected boolean renderResource(
      String uri, String configCacheRoot, Session admin, Session session)
      throws RepositoryException, ServletException, IOException {
    String cachePath = configCacheRoot + getTargetPath(uri);

    ResourceResolver resolver = null;
    try {
      resolver = createResolver(session.getUserID());

      // render resource
      ByteArrayOutputStream out = new ByteArrayOutputStream();
      HttpServletRequest request = createRequest(uri);
      HttpServletResponse response = requestResponseFactory.createResponse(out);

      slingServlet.processRequest(request, response, resolver);
      response.getWriter().flush();

      // compare md5 checksum with cache
      String md5 = requestResponseFactory.getMD5(response);
      String md5Path = cachePath + "/" + JcrConstants.JCR_CONTENT + "/" + MD5_HASH_PROPERTY;

      if (!admin.propertyExists(md5Path) || !admin.getProperty(md5Path).getString().equals(md5)) {
        log.info("MD5 hash missing or not equal, updating content sync cache: {}", cachePath);

        JcrUtil.createPath(cachePath, "sling:Folder", "nt:file", admin, false);

        Node cacheContentNode =
            JcrUtil.createPath(cachePath + "/jcr:content", "nt:resource", admin);
        if (needsUtf8Encoding(response)) {
          cacheContentNode.setProperty(
              JcrConstants.JCR_DATA,
              admin
                  .getValueFactory()
                  .createBinary(
                      IOUtils.toInputStream(out.toString(response.getCharacterEncoding()))));
        } else {
          cacheContentNode.setProperty(
              JcrConstants.JCR_DATA,
              admin.getValueFactory().createBinary(new ByteArrayInputStream(out.toByteArray())));
        }
        cacheContentNode.setProperty(JcrConstants.JCR_LASTMODIFIED, Calendar.getInstance());
        if (response.getContentType() != null) {
          cacheContentNode.setProperty(JcrConstants.JCR_MIMETYPE, response.getContentType());
        }
        if (response.getCharacterEncoding() != null) {
          cacheContentNode.setProperty(JcrConstants.JCR_ENCODING, response.getCharacterEncoding());
        }

        cacheContentNode.addMixin(NT_MD5_HASH);
        cacheContentNode.setProperty(MD5_HASH_PROPERTY, md5);

        admin.save();

        return true;
      } else {
        log.info("Skipping update of content sync cache: {}", uri);

        return false;
      }
    } catch (LoginException e) {
      log.error("Creating resource resolver for resource rendering failed: ", e);
      return false;
    } finally {
      if (resolver != null) {
        resolver.close();
      }

      if (admin.hasPendingChanges()) {
        admin.refresh(false);
      }
    }
  }