info.magnolia.module.admininterface.AdminTreeMVCHandler.java Source code

Java tutorial

Introduction

Here is the source code for info.magnolia.module.admininterface.AdminTreeMVCHandler.java

Source

/**
 *
 * Magnolia and its source-code is licensed under the LGPL.
 * You may copy, adapt, and redistribute this file for commercial or non-commercial use.
 * When copying, adapting, or redistributing this document in keeping with the guidelines above,
 * you are required to provide proper attribution to obinary.
 * If you reproduce or distribute the document without making any substantive modifications to its content,
 * please use the following attribution line:
 *
 * Copyright 1993-2006 obinary Ltd. (http://www.obinary.com) All rights reserved.
 *
 */

package info.magnolia.module.admininterface;

import info.magnolia.cms.beans.config.MIMEMapping;
import info.magnolia.cms.beans.config.Subscriber;
import info.magnolia.cms.beans.config.ContentRepository;
import info.magnolia.cms.exchange.ExchangeException;
import info.magnolia.cms.exchange.Syndicator;
import info.magnolia.cms.gui.control.Tree;
import info.magnolia.cms.gui.misc.Sources;
import info.magnolia.cms.i18n.MessagesManager;
import info.magnolia.cms.servlets.CommandBasedMVCServletHandler;
import info.magnolia.cms.util.AlertUtil;
import info.magnolia.cms.util.ExclusiveWrite;
import info.magnolia.cms.util.Rule;
import info.magnolia.cms.util.FactoryUtil;
import info.magnolia.cms.core.*;
import info.magnolia.cms.security.AccessDeniedException;
import info.magnolia.context.Context;
import info.magnolia.context.MgnlContext;

import java.io.IOException;
import java.util.Iterator;

import javax.jcr.RepositoryException;
import javax.jcr.PathNotFoundException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * this class wrapes the tree control. The AdminInterfaceServlet instantiates a subclass. To build your own tree you
 * have to override the prepareTree() method
 * @author philipp
 * @author Fabrizio Giustina
 */

public abstract class AdminTreeMVCHandler extends CommandBasedMVCServletHandler {

    /**
     * this are the used actions
     */
    protected static final String COMMAND_SHOW_TREE = "show"; //$NON-NLS-1$

    protected static final String COMMAND_COPY_NODE = "copy"; //$NON-NLS-1$

    protected static final String COMMAND_MOVE_NODE = "move"; //$NON-NLS-1$

    protected static final String COMMAND_ACTIVATE = "activate"; //$NON-NLS-1$

    protected static final String COMMAND_DEACTIVATE = "deactivate"; //$NON-NLS-1$

    protected static final String COMMAND_CREATE_NODE = "createNode"; //$NON-NLS-1$

    protected static final String COMMAND_DELETE_NODE = "delete"; //$NON-NLS-1$

    protected static final String COMMAND_SAVE_VALUE = "saveValue"; //$NON-NLS-1$

    /**
     * The view names
     */

    protected static final String VIEW_TREE = "tree"; //$NON-NLS-1$

    protected static final String VIEW_CREATE = "create"; //$NON-NLS-1$

    protected static final String VIEW_VALUE = "value"; //$NON-NLS-1$

    protected static final String VIEW_NOTHING = "nothing"; //$NON-NLS-1$

    protected static final String VIEW_COPY_MOVE = "copymove"; //$NON-NLS-1$

    /**
     * Log
     */
    private static Logger log = LoggerFactory.getLogger(AdminTreeMVCHandler.class);

    /**
     * name of the tree (not the repository)
     */
    protected Tree tree;

    /**
     * The configuration used to configure the tree
     */
    protected AdminTreeConfiguration configuration;

    protected String path;

    protected String pathOpen;

    protected String pathSelected;

    /**
     * Used to pass the saved value to the view
     */
    protected String displayValue;

    protected String newPath;

    /**
     * Used to display the same tree in the linkbrowser
     */
    protected boolean browseMode;

    /**
     * Override this method if you are not using the same name for the tree and the repository
     * @return name of the repository
     */
    protected String getRepository() {
        return getName();
    }

    /**
     * @return the current HierarchyManager
     */
    public HierarchyManager getHierarchyManager() {
        return MgnlContext.getHierarchyManager(this.getRepository());
    }

    public AdminTreeMVCHandler(String name, HttpServletRequest request, HttpServletResponse response) {
        super(name, request, response);

        setTree(new Tree(name, getRepository(), request));
        path = this.getRequest().getParameter("path"); //$NON-NLS-1$
        if (StringUtils.isEmpty(path)) {
            path = "/"; //$NON-NLS-1$
        }

        pathOpen = this.getRequest().getParameter("pathOpen"); //$NON-NLS-1$
        pathSelected = this.getRequest().getParameter("pathSelected"); //$NON-NLS-1$

        this.setBrowseMode(StringUtils.equals(this.getRequest().getParameter("browseMode"), "true"));
    }

    /**
     * Depending on the request it is generating a logical command name
     * @return name of the command
     */
    public String getCommand() {
        // if an explicit action was called
        if (StringUtils.isNotEmpty(super.getCommand())) {
            return super.getCommand();
        }

        // actions returned from the tree (pased through treeAction)
        if (StringUtils.isNotEmpty(this.getRequest().getParameter("treeAction"))) { //$NON-NLS-1$
            int treeAction = Integer.parseInt(this.getRequest().getParameter("treeAction")); //$NON-NLS-1$

            if (treeAction == Tree.ACTION_COPY) {
                return COMMAND_COPY_NODE;
            }
            if (treeAction == Tree.ACTION_MOVE) {
                return COMMAND_MOVE_NODE;
            }
            if (treeAction == Tree.ACTION_ACTIVATE) {
                return COMMAND_ACTIVATE;
            }
            if (treeAction == Tree.ACTION_DEACTIVATE) {
                return COMMAND_DEACTIVATE;
            }

            return this.getRequest().getParameter("treeAction"); //$NON-NLS-1$
        }

        // other actions depending other informations
        if (this.getRequest().getParameter("createItemType") != null) { //$NON-NLS-1$
            return COMMAND_CREATE_NODE;
        }

        if (this.getRequest().getParameter("deleteNode") != null) { //$NON-NLS-1$
            return COMMAND_DELETE_NODE;
        }

        // editet any value directly in the columns?
        if (this.getRequest().getParameter("saveName") != null //$NON-NLS-1$
                || this.getRequest().getParameter("saveValue") != null
                // value to save is a node data's value (config admin)
                || "true".equals(this.getRequest().getParameter("isNodeDataValue")) //$NON-NLS-1$ //$NON-NLS-2$
                // value to save is a node data's type (config admin)
                || "true".equals(this.getRequest().getParameter("isNodeDataType"))) { //$NON-NLS-1$ //$NON-NLS-2$
            return COMMAND_SAVE_VALUE;
        }

        return COMMAND_SHOW_TREE;
    }

    /**
     * TODO: this is a temporary solution
     */
    protected Context getCommandContext(String commandName) {
        Context context = MgnlContext.getInstance();

        // set general parameters (repository, path, ..)
        context.put(Context.ATTRIBUTE_REPOSITORY, this.getRepository());
        context.put(Context.ATTRIBUTE_PATH, this.pathSelected);

        return context;
    }

    /**
     * Show the tree after execution of a command
     */
    protected String getViewNameAfterExecution(String commandName, Context ctx) {
        return VIEW_TREE;
    }

    /**
     * Show the tree
     */
    public String show() {
        return VIEW_TREE;
    }

    /**
     * Create a new node and show the tree
     * @return newly created content node
     */
    public String createNode() {
        String createItemType = Tree.ITEM_TYPE_NODEDATA;
        if (this.getRequest().getParameter("createItemType") != null) { //$NON-NLS-1$
            createItemType = this.getRequest().getParameter("createItemType"); //$NON-NLS-1$
        }

        getTree().setPath(path);
        synchronized (ExclusiveWrite.getInstance()) {
            getTree().createNode(createItemType);
        }
        return VIEW_TREE;
    }

    /**
     * Copy a node
     */
    public String copy() {
        try {
            synchronized (ExclusiveWrite.getInstance()) {
                copyOrMove(Tree.ACTION_COPY);
            }
        } catch (Exception e) {
            log.error("can't copy", e);
            AlertUtil.setMessage(MessagesManager.get("tree.error.copy") + " " + AlertUtil.getExceptionMessage(e));
        }
        return VIEW_COPY_MOVE;
    }

    /**
     * Move a node
     */
    public String move() {
        try {
            synchronized (ExclusiveWrite.getInstance()) {
                copyOrMove(Tree.ACTION_MOVE);
            }
        } catch (Exception e) {
            log.error("can't move", e);
            AlertUtil.setMessage(MessagesManager.get("tree.error.move") + " " + AlertUtil.getExceptionMessage(e));
        }
        return VIEW_COPY_MOVE;

    }

    /**
     * @param action
     * @throws RepositoryException
     * @throws ExchangeException
     */
    private void copyOrMove(int action) throws ExchangeException, RepositoryException {
        String pathClipboard = this.getRequest().getParameter("pathClipboard"); //$NON-NLS-1$
        int pasteType = Integer.parseInt(this.getRequest().getParameter("pasteType")); //$NON-NLS-1$
        newPath = pasteNode(pathClipboard, pathSelected, pasteType, action);

        if (pasteType == Tree.PASTETYPE_SUB) {
            pathOpen = pathSelected;
        } else {
            // open parent path of destination path
            pathOpen = pathSelected.substring(0, pathSelected.lastIndexOf("/")); //$NON-NLS-1$
        }

        pathSelected = null;
    }

    public void deleteNode(String parentPath, String label) throws ExchangeException, RepositoryException {
        Content parentNode = getHierarchyManager().getContent(parentPath);
        String path;
        if (!parentPath.equals("/")) { //$NON-NLS-1$
            path = parentPath + "/" + label; //$NON-NLS-1$
        } else {
            path = "/" + label; //$NON-NLS-1$
        }
        this.deActivateNode(path);
        parentNode.delete(label);
        parentNode.save();
    }

    public void deleteNode(String path) throws Exception {
        String parentPath = StringUtils.substringBeforeLast(path, "/"); //$NON-NLS-1$
        String label = StringUtils.substringAfterLast(path, "/"); //$NON-NLS-1$
        deleteNode(parentPath, label);
    }

    public String delete() {
        String deleteNode = this.getRequest().getParameter("deleteNode"); //$NON-NLS-1$
        try {
            synchronized (ExclusiveWrite.getInstance()) {
                deleteNode(path, deleteNode);
            }
        } catch (Exception e) {
            log.error("can't delete", e);
            AlertUtil.setMessage(MessagesManager.get("tree.error.delete") + " " + AlertUtil.getExceptionMessage(e));
        }
        return VIEW_TREE;
    }

    public String activate() {
        boolean recursive = (this.getRequest().getParameter("recursive") != null); //$NON-NLS-1$
        // by default every CONTENTNODE under the specified CONTENT node is activated
        try {
            activateNode(pathSelected, recursive);
        } catch (Exception e) {
            log.error("can't activate", e);
            AlertUtil.setMessage(
                    MessagesManager.get("tree.error.activate") + " " + AlertUtil.getExceptionMessage(e));
        }
        return VIEW_TREE;
    }

    public String deactivate() {
        try {
            deActivateNode(pathSelected);
        } catch (Exception e) {
            log.error("can't deactivate", e);
            AlertUtil.setMessage(
                    MessagesManager.get("tree.error.deactivate") + " " + AlertUtil.getExceptionMessage(e));
        }
        return VIEW_TREE;
    }

    /**
     * @param path
     * @param recursive
     */
    public void activateNode(String path, boolean recursive) throws ExchangeException, RepositoryException {

        String parentPath = StringUtils.substringBeforeLast(path, "/");
        if (StringUtils.isEmpty(parentPath)) {
            parentPath = "/";
        }

        Syndicator syndicator = getActivationSyndicator(path);
        if (recursive) {
            activateNodeRecursive(syndicator, parentPath, path);
        } else {
            syndicator.activate(parentPath, path);
        }
    }

    /**
     * recursive activation
     * Override this method to provide tree specific node recursion
     * @param syndicator
     * @param parentPath
     * @param path
     */
    public void activateNodeRecursive(Syndicator syndicator, String parentPath, String path)
            throws ExchangeException, RepositoryException {
        syndicator.activate(parentPath, path);
        Iterator children = this.getTree().getHierarchyManager().getContent(path).getChildren().iterator();
        while (children.hasNext()) {
            this.activateNodeRecursive(syndicator, path, ((Content) children.next()).getHandle());
        }
    }

    /**
     * Create the <code>Syndicator</code> to activate the specified path.
     * method implementation will make sure that proper node collection Rule and Sysdicator is used
     * @param path node path to be activated
     * @return the <code>Syndicator</code> used to activate
     */
    public abstract Syndicator getActivationSyndicator(String path);

    public void deActivateNode(String path) throws ExchangeException, RepositoryException {
        // do not deactivate node datas
        if (this.getTree().getHierarchyManager().isNodeData(path)) {
            return;
        }

        Syndicator syndicator = getDeactivationSyndicator(path);
        syndicator.deActivate(path);
    }

    /**
     * Create the <code>Syndicator</code> to deactivate the specified path.
     * @param path node path to be deactivated
     * @return the <code>Syndicator</code> used to deactivate
     */
    protected Syndicator getDeactivationSyndicator(String path) {
        Rule rule = new Rule();
        Syndicator syndicator = (Syndicator) FactoryUtil.getInstance(Syndicator.class);
        syndicator.init(MgnlContext.getUser(), this.getRepository(),
                ContentRepository.getDefaultWorkspace(this.getRepository()), rule);
        return syndicator;
    }

    public Content copyMoveNode(String source, String destination, boolean move)
            throws ExchangeException, RepositoryException {
        // todo: ??? generic -> RequestInterceptor.java
        if (getHierarchyManager().isExist(destination)) {
            String parentPath = StringUtils.substringBeforeLast(destination, "/"); //$NON-NLS-1$
            String label = StringUtils.substringAfterLast(destination, "/"); //$NON-NLS-1$
            label = Path.getUniqueLabel(getHierarchyManager(), parentPath, label);
            destination = parentPath + "/" + label; //$NON-NLS-1$
        }
        if (move) {
            if (destination.indexOf(source + "/") == 0) { //$NON-NLS-1$
                // todo: disable this possibility in javascript
                // move source into destinatin not possible
                return null;
            }
            this.deActivateNode(source);
            try {
                getHierarchyManager().moveTo(source, destination);
            } catch (Exception e) {
                // try to move below node data
                return null;
            }
        } else {
            // copy
            getHierarchyManager().copyTo(source, destination);
        }
        // SessionAccessControl.invalidateUser(this.getRequest());
        Content newContent = getHierarchyManager().getContent(destination);
        try {
            newContent.updateMetaData();
            newContent.getMetaData().setUnActivated();
        } catch (Exception e) {
            if (log.isDebugEnabled())
                log.debug("Exception caught: " + e.getMessage(), e); //$NON-NLS-1$
        }
        newContent.save();
        return newContent;
    }

    public void moveNode(String source, String destination) throws ExchangeException, RepositoryException {
        this.copyMoveNode(source, destination, true);
    }

    public void copyNode(String source, String destination) throws ExchangeException, RepositoryException {
        this.copyMoveNode(source, destination, false);
    }

    public String renameNode(String newLabel)
            throws AccessDeniedException, ExchangeException, PathNotFoundException, RepositoryException {
        String returnValue;
        String parentPath = StringUtils.substringBeforeLast(this.getPath(), "/"); //$NON-NLS-1$
        newLabel = Path.getValidatedLabel(newLabel);

        // don't rename if it uses the same name as the current
        if (this.getPath().endsWith("/" + newLabel)) {
            return newLabel;
        }

        String dest = parentPath + "/" + newLabel; //$NON-NLS-1$
        if (getHierarchyManager().isExist(dest)) {
            newLabel = Path.getUniqueLabel(getHierarchyManager(), parentPath, newLabel);
            dest = parentPath + "/" + newLabel; //$NON-NLS-1$
        }
        this.deActivateNode(this.getPath());

        if (log.isInfoEnabled()) {
            log.info("Moving node from " + this.getPath() + " to " + dest); //$NON-NLS-1$ //$NON-NLS-2$
        }
        if (getHierarchyManager().isNodeData(this.getPath())) {
            Content parentPage = getHierarchyManager().getContent(parentPath);
            NodeData newNodeData = parentPage.createNodeData(newLabel);
            NodeData existingNodeData = getHierarchyManager().getNodeData(this.getPath());
            newNodeData.setValue(existingNodeData.getString());
            existingNodeData.delete();
            dest = parentPath;
        } else {
            // we can't rename a node. we must move
            // we must place the node at the same position
            Content current = getHierarchyManager().getContent(this.getPath());
            Content parent = current.getParent();
            String placedBefore = null;
            for (Iterator iter = parent.getChildren(current.getNodeTypeName()).iterator(); iter.hasNext();) {
                Content child = (Content) iter.next();
                if (child.getHandle().equals(this.getPath())) {
                    if (iter.hasNext()) {
                        child = (Content) iter.next();
                        placedBefore = child.getName();
                    }
                }
            }

            getHierarchyManager().moveTo(this.getPath(), dest);

            // now set at the same place as before
            if (placedBefore != null) {
                parent.orderBefore(newLabel, placedBefore);
            }
        }

        Content newPage = getHierarchyManager().getContent(dest);
        returnValue = newLabel;
        newPage.updateMetaData();
        newPage.save();

        return returnValue;
    }

    /**
     * Saves a value edited directly inside the tree. This can also be a lable
     * @return name of the view
     */
    public String saveValue() {
        String saveName = this.getRequest().getParameter("saveName"); //$NON-NLS-1$
        Tree tree = getTree();

        // value to save is a node data's value (config admin)
        boolean isNodeDataValue = "true".equals(this.getRequest().getParameter("isNodeDataValue")); //$NON-NLS-1$ //$NON-NLS-2$

        // value to save is a node data's type (config admin)
        boolean isNodeDataType = "true".equals(this.getRequest().getParameter("isNodeDataType")); //$NON-NLS-1$ //$NON-NLS-2$

        String value = StringUtils.defaultString(this.getRequest().getParameter("saveValue")); //$NON-NLS-1$
        displayValue = StringUtils.EMPTY;
        // value to save is a content's meta information
        boolean isMeta = "true".equals(this.getRequest().getParameter("isMeta")); //$NON-NLS-1$ //$NON-NLS-2$
        // value to save is a label (name of page, content node or node data)
        boolean isLabel = "true".equals(this.getRequest().getParameter("isLabel")); //$NON-NLS-1$ //$NON-NLS-2$

        if (isNodeDataValue || isNodeDataType) {
            tree.setPath(StringUtils.substringBeforeLast(path, "/")); //$NON-NLS-1$
            saveName = StringUtils.substringAfterLast(path, "/"); //$NON-NLS-1$
        } else {
            // "/modules/templating/Templates/x"
            tree.setPath(path);
        }

        if (isLabel) {
            displayValue = rename(value);
        } else if (isNodeDataType) {
            int type = Integer.valueOf(value).intValue();
            synchronized (ExclusiveWrite.getInstance()) {
                displayValue = tree.saveNodeDataType(saveName, type);
            }
        } else {
            synchronized (ExclusiveWrite.getInstance()) {
                displayValue = tree.saveNodeData(saveName, value, isMeta);
            }
        }

        // if there was a displayValue passed show it instead of the written value
        displayValue = StringUtils.defaultString(this.getRequest().getParameter("displayValue"), value); //$NON-NLS-1$

        // @todo should be handled in a better way but, at the moment, this is better than nothing
        if (path.startsWith("/subscribers/")) { //$NON-NLS-1$
            Subscriber.reload();
        } else if (path.startsWith("/server/MIMEMapping")) { //$NON-NLS-1$
            MIMEMapping.reload();
        }

        return VIEW_VALUE;
    }

    /**
     * Called during a renaming of a node. First is the action saveValue called
     * @param value the new name
     * @return return the new name (can change if there were not allowed characters passed)
     */
    protected String rename(String value) {
        try {
            synchronized (ExclusiveWrite.getInstance()) {
                return renameNode(value);
            }
        } catch (Exception e) {
            log.error("can't rename", e);
            AlertUtil.setMessage(MessagesManager.get("tree.error.rename") + " " + AlertUtil.getExceptionMessage(e));
        }
        return StringUtils.EMPTY;
    }

    public String pasteNode(String pathOrigin, String pathSelected, int pasteType, int action)
            throws ExchangeException, RepositoryException {
        boolean move = false;
        if (action == Tree.ACTION_MOVE) {
            move = true;
        }
        String label = StringUtils.substringAfterLast(pathOrigin, "/"); //$NON-NLS-1$
        String slash = "/"; //$NON-NLS-1$
        if (pathSelected.equals("/")) { //$NON-NLS-1$
            slash = StringUtils.EMPTY;
        }
        String destination = pathSelected + slash + label;
        if (pasteType == Tree.PASTETYPE_SUB && action != Tree.ACTION_COPY && destination.equals(pathOrigin)) {
            // drag node to parent node: move to last position
            pasteType = Tree.PASTETYPE_LAST;
        }
        if (pasteType == Tree.PASTETYPE_SUB) {
            destination = pathSelected + slash + label;
            Content touchedContent = this.copyMoveNode(pathOrigin, destination, move);
            if (touchedContent == null) {
                return StringUtils.EMPTY;
            }
            return touchedContent.getHandle();

        } else if (pasteType == Tree.PASTETYPE_LAST) {
            // LAST only available for sorting inside the same directory
            try {
                Content touchedContent = getHierarchyManager().getContent(pathOrigin);
                return touchedContent.getHandle();
            } catch (RepositoryException re) {
                return StringUtils.EMPTY;
            }
        } else {
            try {
                // PASTETYPE_ABOVE | PASTETYPE_BELOW
                String nameSelected = StringUtils.substringAfterLast(pathSelected, "/"); //$NON-NLS-1$
                String nameOrigin = StringUtils.substringAfterLast(pathOrigin, "/"); //$NON-NLS-1$
                Content tomove = getHierarchyManager().getContent(pathOrigin);
                Content selected = getHierarchyManager().getContent(pathSelected);
                if (tomove.getParent().getUUID().equals(selected.getParent().getUUID())) {
                    tomove.getParent().orderBefore(nameOrigin, nameSelected);
                    tomove.getParent().save();
                } else {
                    String newOrigin = selected.getParent().getHandle() + "/" + nameOrigin;
                    getHierarchyManager().moveTo(pathOrigin, newOrigin);
                    Content newNode = getHierarchyManager().getContent(newOrigin);
                    if (pasteType == Tree.PASTETYPE_ABOVE) {
                        newNode.getParent().orderBefore(nameOrigin, nameSelected);
                    }
                }
                return tomove.getHandle();
            } catch (RepositoryException re) {
                re.printStackTrace();
                log.error("Problem when pasting node", re);
                return StringUtils.EMPTY;
            }
        }
    }

    /**
     * Render the tree depending on the view name.
     * @param view
     * @throws IOException
     */
    public void renderHtml(String view) throws IOException {
        StringBuffer html = new StringBuffer(500);

        // an alert can happen if there were deactivation problems during a renaming
        if (AlertUtil.isMessageSet()) {
            html.append("<input type=\"hidden\" id=\"mgnlMessage\" value=\"");
            html.append(AlertUtil.getMessage());
            html.append("\" />");
        }

        if (VIEW_TREE.equals(view) || VIEW_CREATE.equals(view) || VIEW_COPY_MOVE.equals(view)) {
            // if there was a node created we have not to set the pathes
            if (!view.equals(VIEW_CREATE)) {
                getTree().setPathOpen(pathOpen);
                getTree().setPathSelected(pathSelected);
            }

            // after moving or copying
            if (view.equals(VIEW_COPY_MOVE)) {
                // pass new path to tree.js for selecting the newly created node
                // NOTE: tree.js checks for this pattern; adapt it there, if any changes are made here
                html.append("<input type=\"hidden\" id=\"mgnlSelectNode\" value=\"");
                html.append(newPath);
                html.append("\" />");
            }

            renderTree(html);
        }

        // after saving a column value
        else if (view.equals(VIEW_VALUE)) {
            html.append(displayValue);
        }
        this.getResponse().getWriter().print(html);
    }

    /**
     * Create the html for the tree. Calls tree.getHtml after calling prepareTree.
     * @param html
     */
    protected void renderTree(StringBuffer html) {
        String mode = StringUtils.defaultString(this.getRequest().getParameter("treeMode")); //$NON-NLS-1$
        boolean snippetMode = mode.equals("snippet"); //$NON-NLS-1$
        Tree tree = getTree();

        tree.setJavascriptTree("mgnlTreeControl"); //$NON-NLS-1$
        tree.setBrowseMode(this.isBrowseMode());

        if (!snippetMode) {
            html.append("<html><head>"); //$NON-NLS-1$
            html.append("<meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\"/>"); //$NON-NLS-1$
            renderHeaderIncludes(html);
            html.append("<title>Magnolia</title>"); //$NON-NLS-1$
            html.append("<script>window.onresize = mgnlTreeResize;</script>"); //$NON-NLS-1$
            html.append("</head>"); //$NON-NLS-1$
            html.append("<body class=\"mgnlBgDark\" onload=\"");
            html.append(tree.getJavascriptTree());
            html.append(".resizeOnload();\" >");
        }

        tree.setSnippetMode(snippetMode);
        tree.setHeight(50);

        tree.setPath(path);

        this.getConfiguration().prepareTree(tree, this.isBrowseMode(), this.getRequest());
        this.getConfiguration().prepareContextMenu(tree, this.isBrowseMode(), this.getRequest());
        this.getConfiguration().prepareFunctionBar(tree, this.isBrowseMode(), this.getRequest());

        if (!snippetMode) {
            html.append("<div id=\"");
            html.append(tree.getJavascriptTree());
            html.append("_DivSuper\" style=\"display:block;\">");
        }
        html.append(tree.getHtml());
        if (!snippetMode) {
            html.append("</div>"); //$NON-NLS-1$
        }

        if (!snippetMode) {
            html.append("</body></html>"); //$NON-NLS-1$
        }
    }

    /**
     * @param html
     */
    protected void renderHeaderIncludes(StringBuffer html) {
        html.append(new Sources(this.getRequest().getContextPath()).getHtmlJs());
        html.append(new Sources(this.getRequest().getContextPath()).getHtmlCss());
    }

    protected void setTree(Tree tree) {
        this.tree = tree;
    }

    protected Tree getTree() {
        return tree;
    }

    protected String getPath() {
        return path;
    }

    protected String getPathSelected() {
        return pathSelected;
    }

    /**
     * @return Returns the browseMode.
     */
    public boolean isBrowseMode() {
        return browseMode;
    }

    /**
     * @param browseMode The browseMode to set.
     */
    public void setBrowseMode(boolean browseMode) {
        this.browseMode = browseMode;
    }

    /**
     * @return Returns the configuration.
     */
    public AdminTreeConfiguration getConfiguration() {
        return this.configuration;
    }

    /**
     * @param configuration The configuration to set.
     */
    public void setConfiguration(AdminTreeConfiguration configuration) {
        this.configuration = configuration;
    }

}