com.expressui.core.view.menu.MenuBarNode.java Source code

Java tutorial

Introduction

Here is the source code for com.expressui.core.view.menu.MenuBarNode.java

Source

/*
 * Copyright (c) 2012 Brown Bag Consulting.
 * This file is part of the ExpressUI project.
 * Author: Juan Osuna
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License Version 3
 * as published by the Free Software Foundation with the addition of the
 * following permission added to Section 15 as permitted in Section 7(a):
 * FOR ANY PART OF THE COVERED WORK IN WHICH THE COPYRIGHT IS OWNED BY
 * Brown Bag Consulting, Brown Bag Consulting DISCLAIMS THE WARRANTY OF
 * NON INFRINGEMENT OF THIRD PARTY RIGHTS.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 * The interactive user interfaces in modified source and object code versions
 * of this program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU Affero General Public License.
 *
 * You can be released from the requirements of the license by purchasing
 * a commercial license. Buying such a license is mandatory as soon as you
 * develop commercial activities involving the ExpressUI software without
 * disclosing the source code of your own applications. These activities
 * include: offering paid services to customers as an ASP, providing
 * services from a web application, shipping ExpressUI with a closed
 * source product.
 *
 * For more information, please contact Brown Bag Consulting at this
 * address: juan@brownbagconsulting.com.
 */

package com.expressui.core.view.menu;

import com.expressui.core.security.SecurityService;
import com.expressui.core.util.MethodDelegate;
import com.expressui.core.util.ReflectionUtil;
import com.expressui.core.util.SpringApplicationContext;
import com.expressui.core.util.assertion.Assert;
import com.expressui.core.view.field.LabelRegistry;
import com.expressui.core.view.page.Page;
import com.expressui.core.view.util.MessageSource;
import com.vaadin.ui.MenuBar;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;

/**
 * A node in the menu bar tree. Each node has a caption and is linked to a Page or action/listener method.
 * Captions may be set programmatically or looked up in messages file residing in domainMessages/.
 * See for {@link #getKey()} to understand how captions are looked up.
 */
public class MenuBarNode {

    @Resource
    private LabelRegistry labelRegistry;

    @Resource
    private SecurityService securityService;

    @Resource
    private MessageSource domainMessageSource;

    private String key;
    private String caption;
    private MenuBar.Command command;
    private boolean visible = true;
    private LinkedHashMap<String, MenuBarNode> children = new LinkedHashMap<String, MenuBarNode>();

    /**
     * Constructs a root node without a caption or page/action, or a nested node where caption and page/action
     * will be set later.
     */
    public MenuBarNode() {
        SpringApplicationContext.autowire(this);
    }

    /**
     * Constructs nested node with a caption and no page or action.
     *
     * @param caption caption to display to user as menu item
     */
    public MenuBarNode(String key, String caption) {
        this();
        this.key = key;
        setCaption(caption);
        command = new NullCommand();
        labelRegistry.putTypeLabel(this.key, caption);
    }

    /**
     * Constructs nested node with caption and page.
     *
     * @param caption   caption to display to user as menu item
     * @param pageClass page to display when user chooses menu item
     */
    public MenuBarNode(String caption, Class<? extends Page> pageClass) {
        this();
        setCaption(caption);
        command = new PageCommand(pageClass);
        key = pageClass.getName();
        labelRegistry.putTypeLabel(key, caption);
    }

    /**
     * Constructs nested node with caption and action/listener.
     *
     * @param caption    caption to display to user as menu item
     * @param target     target listener object to be invoked when user chooses menu item
     * @param methodName listener method to be invoked when user chooses menu item
     */
    public MenuBarNode(String caption, Object target, String methodName) {
        this();
        setCaption(caption);
        command = new MethodCommand(target, methodName);
        MethodDelegate methodDelegate = ((MethodCommand) command).getMethodDelegate();
        key = methodDelegate.getTarget().getClass().getName() + "." + methodDelegate.getMethod().getName();
        labelRegistry.putTypeLabel(key, caption);
    }

    /**
     * Get the command that is attached to this node.
     *
     * @return command
     */
    public MenuBar.Command getCommand() {
        return command;
    }

    /**
     * Gets the key used to look up captions optionally in domainMessages/ files. This key is generated
     * depending on the type of node:
     * <ul>
     * <li>For pages, the key is the package and class name of the page class</li>
     * <li>For commands, the key is the package and class name of the command target plus the method name
     * of the command listener.</li>
     * <li>For captions, the key must be set programmatically in {@link #addCaption(String)}</li>
     * </ul>
     *
     * @return
     */
    public String getKey() {
        return key;
    }

    /**
     * Gets caption to display to user as menu item.
     *
     * @return caption
     */
    public String getCaption() {
        return caption;
    }

    /**
     * Sets caption to display to user as menu item, thus overwriting any caption obtained from messages file
     * in domainMessages/.
     *
     * @param caption caption to display
     */
    public void setCaption(String caption) {
        Assert.PROGRAMMING.notNull(caption, "caption argument must not be null");
        this.caption = caption;
    }

    /**
     * Asks if this node/menu item is visible.
     *
     * @return true if visible
     */
    public boolean isVisible() {
        return visible;
    }

    /**
     * Sets whether or not this node/menu item is visible.
     *
     * @param visible true if visible
     */
    public void setVisible(boolean visible) {
        this.visible = visible;
    }

    /**
     * Gets child node associated with given key.
     *
     * @param key key to look up child
     * @return child node
     */
    public MenuBarNode getChild(String key) {
        return children.get(key);
    }

    /**
     * Gets all immediate child nodes.
     *
     * @return all child nodes
     */
    public List<MenuBarNode> getChildren() {
        return Collections.unmodifiableList(new ArrayList<MenuBarNode>(children.values()));
    }

    /**
     * Adds a caption to this node without any page or action associated with caption.
     *
     * @param caption caption to display in menu item
     * @return newly created node, to which nested nodes may be added
     */
    public MenuBarNode addCaption(String key, String caption) {
        MenuBarNode menuBarNode = new MenuBarNode(key, caption);
        children.put(key, menuBarNode);

        return menuBarNode;
    }

    /**
     * Adds a caption to this node without any page or action associated with caption.
     * Caption is looked up by the key in messages file in domainMessages/.
     *
     * @return newly created node, to which nested nodes may be added
     */
    public MenuBarNode addCaption(String key) {
        String caption = domainMessageSource.getMessage(key);

        return addCaption(key, caption);
    }

    /**
     * Adds a page to this node.
     *
     * @param caption   caption to display in menu item
     * @param pageClass page to display when menu item is chosen
     * @return newly created node, to which nested nodes may be added
     */
    public MenuBarNode addPage(String caption, Class<? extends Page> pageClass) {
        MenuBarNode menuBarNode = new MenuBarNode(caption, pageClass);
        children.put(menuBarNode.getKey(), menuBarNode);

        return menuBarNode;
    }

    /**
     * Adds a page to this node.
     *
     * @param pageClass page to display when menu item is chosen
     * @return newly created node, to which nested nodes may be added
     */
    public MenuBarNode addPage(Class<? extends Page> pageClass) {
        String caption = domainMessageSource.getMessage(pageClass.getName());
        return addPage(caption, pageClass);
    }

    /**
     * Adds a page to this node.
     *
     * @param caption    caption to display in menu item
     * @param target     target listener object to be invoked when user chooses menu item
     * @param methodName listener method to be invoked when user chooses menu item
     * @return newly created node, to which nested nodes may be added
     */
    public MenuBarNode addCommand(String caption, Object target, String methodName) {
        MenuBarNode menuBarNode = new MenuBarNode(caption, target, methodName);
        children.put(menuBarNode.getKey(), menuBarNode);

        return menuBarNode;
    }

    /**
     * Adds a page to this node.
     *
     * @param target     target listener object to be invoked when user chooses menu item
     * @param methodName listener method to be invoked when user chooses menu item
     * @return newly created node, to which nested nodes may be added
     */
    public MenuBarNode addCommand(Object target, String methodName) {
        String caption = domainMessageSource.getMessage(target.getClass().getName() + "." + methodName);
        return addCommand(caption, target, methodName);
    }

    MenuBar createMenuBar() {
        MenuBar menuBar = new MenuBar();
        menuBar.setSizeUndefined();
        menuBar.setAutoOpen(true);
        menuBar.setHtmlContentAllowed(true);

        for (MenuBarNode child : children.values()) {
            if (child.isViewAllowed() && child.isVisible()) {
                MenuBar.MenuItem childMenuItem = menuBar.addItem(child.caption, child.command);
                child.populate(childMenuItem);
            }
        }

        return menuBar;
    }

    private void populate(MenuBar.MenuItem menuItem) {
        for (MenuBarNode child : children.values()) {
            if (child.isViewAllowed() && child.isVisible()) {
                MenuBar.MenuItem childMenuItem = menuItem.addItem(child.caption, child.command);
                child.populate(childMenuItem);
            }
        }
    }

    private boolean isViewAllowed() {
        if (command instanceof PageCommand) {
            Class pageClass = ((PageCommand) command).getPageClass();
            Class genericType = ReflectionUtil.getGenericArgumentType(pageClass);
            if (genericType == null) {
                return securityService.getCurrentUser().isViewAllowed(pageClass.getName());
            } else {
                return securityService.getCurrentUser().isViewAllowed(pageClass.getName())
                        && securityService.getCurrentUser().isViewAllowed(genericType.getName());
            }
        } else if (command instanceof MethodCommand) {
            MethodDelegate methodDelegate = ((MethodCommand) command).getMethodDelegate();
            String name = methodDelegate.getTarget().getClass().getName() + "."
                    + methodDelegate.getMethod().getName();
            return securityService.getCurrentUser().isViewAllowed(name);
        } else if (command instanceof NullCommand) {
            return securityService.getCurrentUser().isViewAllowed(key);
        } else {
            Assert.PROGRAMMING.fail("Command must be either of type PageCommand,  MethodCommand or NullCommand. "
                    + "Instead it is of type " + command.getClass());
        }

        return false;
    }
}