org.squashtest.tm.web.internal.controller.generic.WorkspaceController.java Source code

Java tutorial

Introduction

Here is the source code for org.squashtest.tm.web.internal.controller.generic.WorkspaceController.java

Source

/**
 *     This file is part of the Squashtest platform.
 *     Copyright (C) 2010 - 2016 Henix, henix.fr
 *
 *     See the NOTICE file distributed with this work for additional
 *     information regarding copyright ownership.
 *
 *     This is free software: you can redistribute it and/or modify
 *     it under the terms of the GNU Lesser General Public License as published by
 *     the Free Software Foundation, either version 3 of the License, or
 *     (at your option) any later version.
 *
 *     this software 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 Lesser General Public License for more details.
 *
 *     You should have received a copy of the GNU Lesser General Public License
 *     along with this software.  If not, see <http://www.gnu.org/licenses/>.
 */
package org.squashtest.tm.web.internal.controller.generic;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Locale;

import javax.inject.Inject;
import javax.inject.Provider;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.MultiMap;
import org.apache.commons.collections.Predicate;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.CookieValue;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.squashtest.tm.api.wizard.WorkspaceWizard;
import org.squashtest.tm.api.workspace.WorkspaceType;
import org.squashtest.tm.domain.library.Library;
import org.squashtest.tm.domain.library.LibraryNode;
import org.squashtest.tm.domain.milestone.Milestone;
import org.squashtest.tm.domain.project.Project;
import org.squashtest.tm.service.library.WorkspaceService;
import org.squashtest.tm.service.milestone.ActiveMilestoneHolder;
import org.squashtest.tm.service.milestone.MilestoneFinderService;
import org.squashtest.tm.service.project.ProjectFinder;
import org.squashtest.tm.web.internal.controller.campaign.MenuItem;
import org.squashtest.tm.web.internal.helper.JsTreeHelper;
import org.squashtest.tm.web.internal.i18n.InternationalizationHelper;
import org.squashtest.tm.web.internal.model.builder.DriveNodeBuilder;
import org.squashtest.tm.web.internal.model.builder.JsTreeNodeListBuilder;
import org.squashtest.tm.web.internal.model.builder.JsonProjectBuilder;
import org.squashtest.tm.web.internal.model.json.JsonMilestone;
import org.squashtest.tm.web.internal.model.json.JsonProject;
import org.squashtest.tm.web.internal.model.jstree.JsTreeNode;
import org.squashtest.tm.web.internal.wizard.WorkspaceWizardManager;

import com.google.common.base.Optional;

public abstract class WorkspaceController<LN extends LibraryNode> {
    private static final Logger LOGGER = LoggerFactory.getLogger(WorkspaceController.class);

    @Inject
    private WorkspaceWizardManager workspaceWizardManager;

    @Inject
    protected InternationalizationHelper i18nHelper;

    @Inject
    protected ProjectFinder projectFinder;

    @Inject
    protected JsonProjectBuilder jsonProjectBuilder;

    @Inject
    protected MilestoneFinderService milestoneFinder;

    @Inject
    protected ActiveMilestoneHolder activeMilestoneHolder;

    /**
     * Shows a workspace.
     *
     * @param model
     * @param locale
     * @return
     */
    @RequestMapping(method = RequestMethod.GET)
    public String showWorkspace(Model model, Locale locale,
            @CookieValue(value = "jstree_open", required = false, defaultValue = "") String[] openedNodes,
            @CookieValue(value = "workspace-prefs", required = false, defaultValue = "") String elementId) {

        List<Library<LN>> libraries = getWorkspaceService().findAllLibraries();
        String[] nodesToOpen;

        // #5585 : the case where elementId explicitly equals string litteral "null" can and will happen
        // thus the test here
        if (StringUtils.isBlank(elementId) || "null".equals(elementId)) {
            nodesToOpen = openedNodes;
            model.addAttribute("selectedNode", "");
        } else {
            Long id = Long.valueOf(elementId);
            nodesToOpen = getNodeParentsInWorkspace(id);
            model.addAttribute("selectedNode", getTreeElementIdInWorkspace(id));
        }

        MultiMap expansionCandidates = mapIdsByType(nodesToOpen);

        DriveNodeBuilder<LN> nodeBuilder = driveNodeBuilderProvider().get();

        Optional<Milestone> activeMilestone = activeMilestoneHolder.getActiveMilestone();
        if (activeMilestone.isPresent()) {
            nodeBuilder.filterByMilestone(activeMilestone.get());
        }

        List<JsTreeNode> rootNodes = new JsTreeNodeListBuilder<>(nodeBuilder).expand(expansionCandidates)
                .setModel(libraries).build();

        model.addAttribute("rootModel", rootNodes);

        populateModel(model, locale);

        // also add meta data about projects
        Collection<JsonProject> jsProjects = jsonProjectBuilder.getExtendedReadableProjects();

        model.addAttribute("projects", jsProjects);

        // also, milestones
        if (activeMilestone.isPresent()) {
            JsonMilestone jsMilestone = new JsonMilestone(activeMilestone.get().getId(),
                    activeMilestone.get().getLabel(), activeMilestone.get().getStatus(),
                    activeMilestone.get().getRange(), activeMilestone.get().getEndDate(),
                    activeMilestone.get().getOwner().getLogin());
            model.addAttribute("activeMilestone", jsMilestone);
        }

        return getWorkspaceViewName();
    }

    @ResponseBody
    @RequestMapping(method = RequestMethod.GET, value = "/tree/{openedNodes}")
    public List<JsTreeNode> getRootModel(@PathVariable String[] openedNodes) {
        List<Library<LN>> libraries = getWorkspaceService().findAllLibraries();

        MultiMap expansionCandidates = mapIdsByType(openedNodes);

        DriveNodeBuilder<LN> nodeBuilder = driveNodeBuilderProvider().get();
        List<JsTreeNode> rootNodes = new JsTreeNodeListBuilder<>(nodeBuilder).expand(expansionCandidates)
                .setModel(libraries).build();

        return rootNodes;
    }

    /**
     * @param openedNodes
     * @return
     */
    protected MultiMap mapIdsByType(String[] openedNodes) {
        return JsTreeHelper.mapIdsByType(openedNodes);
    }

    /**
     * Should return a workspace service.
     *
     * @return
     */
    protected abstract <T extends Library<LN>> WorkspaceService<T> getWorkspaceService();

    /**
     * Returns the logical name of the page which shows the workspace.
     *
     * @return
     */
    protected abstract String getWorkspaceViewName();

    /**
     * Returns the list of parents of a node given the id of an element
     *
     * @param elementId
     * @return
     */
    protected abstract String[] getNodeParentsInWorkspace(Long elementId);

    /**
     * Returns the id of a node in the tree given the id of an element
     *
     * @param elementId
     * @return
     */
    protected abstract String getTreeElementIdInWorkspace(Long elementId);

    /**
     * Called when {@link #getWorkspaceViewName()} is invoked. This allows you to add anything you need to
     * thisworkspace's model. No need to supply the treenodes : they will be provided.
     */
    protected abstract void populateModel(Model model, Locale locale);

    /**
     * Returns the workspace type managed by the concrete controller.
     *
     * @return
     */
    protected abstract WorkspaceType getWorkspaceType();

    @ModelAttribute("wizards")
    public MenuItem[] getWorkspaceWizards() {
        Collection<WorkspaceWizard> wizards = workspaceWizardManager.findAllByWorkspace(getWorkspaceType());

        return menuItems(wizards);
    }

    /**
     * @param wizards
     * @return
     */
    @SuppressWarnings("all")
    private MenuItem[] menuItems(Collection<WorkspaceWizard> wizards) {
        Collection<WorkspaceWizard> effective = CollectionUtils.select(wizards, new Predicate() {
            @Override
            public boolean evaluate(Object object) {
                return (((WorkspaceWizard) object).getWizardMenu() != null);
            }
        });

        MenuItem[] res = new MenuItem[effective.size()];
        int i = 0;

        for (WorkspaceWizard wizard : wizards) {
            if (wizard.getWizardMenu() != null) {
                res[i] = createMenuItem(wizard);
                i++;
            }
        }

        return res;
    }

    /**
     * @param wizard
     * @return
     */
    private MenuItem createMenuItem(WorkspaceWizard wizard) {
        MenuItem item = new MenuItem();
        item.setId(wizard.getId());
        item.setLabel(wizard.getWizardMenu().getLabel());
        item.setTooltip(wizard.getWizardMenu().getTooltip());
        item.setUrl(wizard.getWizardMenu().getUrl());
        item.setAccessRule(wizard.getWizardMenu().getAccessRule());

        return item;
    }

    protected InternationalizationHelper getI18nHelper() {
        return i18nHelper;
    }

    /**
     * Returns the appropriate drive node builder. Should never return null.
     *
     * @return
     */
    protected abstract Provider<DriveNodeBuilder<LN>> driveNodeBuilderProvider();

}