org.libreplan.web.resources.machine.MachineCRUDController.java Source code

Java tutorial

Introduction

Here is the source code for org.libreplan.web.resources.machine.MachineCRUDController.java

Source

/*
 * This file is part of LibrePlan
 *
 * Copyright (C) 2009-2010 Fundacin para o Fomento da Calidade Industrial e
 *                         Desenvolvemento Tecnolxico de Galicia
 * Copyright (C) 2010-2011 Igalia, S.L.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * 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/>.
 */

package org.libreplan.web.resources.machine;

import static org.libreplan.web.I18nHelper._;

import java.util.ConcurrentModificationException;
import java.util.Date;
import java.util.List;
import java.util.Set;

import org.joda.time.LocalDate;
import org.libreplan.business.calendars.entities.BaseCalendar;
import org.libreplan.business.calendars.entities.ResourceCalendar;
import org.libreplan.business.common.entities.Limits;
import org.libreplan.business.common.exceptions.InstanceNotFoundException;
import org.libreplan.business.common.exceptions.ValidationException;
import org.libreplan.business.resources.daos.IResourceDAO;
import org.libreplan.business.resources.entities.Machine;
import org.libreplan.web.calendars.BaseCalendarEditionController;
import org.libreplan.web.calendars.IBaseCalendarModel;
import org.libreplan.web.common.BaseCRUDController;
import org.libreplan.web.common.ConstraintChecker;
import org.libreplan.web.common.Level;
import org.libreplan.web.common.Util;
import org.libreplan.web.common.ILimitsModel;
import org.libreplan.web.common.components.bandboxsearch.BandboxMultipleSearch;
import org.libreplan.web.costcategories.ResourcesCostCategoryAssignmentController;
import org.libreplan.web.resources.search.ResourcePredicate;
import org.libreplan.web.resources.worker.CriterionsController;
import org.libreplan.web.resources.worker.CriterionsMachineController;
import org.libreplan.web.resources.worker.WorkerCRUDController.LimitingResourceEnum;
import org.zkoss.zk.ui.Component;
import org.zkoss.zk.ui.WrongValueException;
import org.zkoss.zk.ui.event.CheckEvent;
import org.zkoss.zk.ui.event.Event;
import org.zkoss.zk.ui.event.Events;
import org.zkoss.zkplus.spring.SpringUtil;
import org.zkoss.zul.Combobox;
import org.zkoss.zul.Comboitem;
import org.zkoss.zul.ComboitemRenderer;
import org.zkoss.zul.Constraint;
import org.zkoss.zul.Datebox;
import org.zkoss.zul.Grid;
import org.zkoss.zul.Hbox;
import org.zkoss.zul.Label;
import org.zkoss.zul.Listbox;
import org.zkoss.zul.Listcell;
import org.zkoss.zul.Listitem;
import org.zkoss.zul.RowRenderer;
import org.zkoss.zul.SimpleListModel;
import org.zkoss.zul.Tab;
import org.zkoss.zul.Textbox;
import org.zkoss.zul.Window;

/**
 * Controller for {@link Machine} resource.
 * <br />
 * @author Diego Pino Garcia <dpino@igalia.com>
 * @author Lorenzo Tilve ?lvaro <ltilve@igalia.com>
 * @author Vova Perebykivskyi <vova@libreplan-enterprise.com>
 */
public class MachineCRUDController extends BaseCRUDController<Machine> {

    private ILimitsModel limitsModel;

    private IMachineModel machineModel;

    private IBaseCalendarModel resourceCalendarModel;

    private IResourceDAO resourceDAO;

    private Component configurationUnits;

    private CriterionsMachineController criterionsController;

    private MachineConfigurationController configurationController;

    private ResourcesCostCategoryAssignmentController resourcesCostCategoryAssignmentController;

    private Grid listing;

    private Datebox filterStartDate;

    private Datebox filterFinishDate;

    private Listbox filterLimitingResource;

    private Textbox txtfilter;

    private BandboxMultipleSearch bdFilters;

    private BaseCalendarsComboitemRenderer baseCalendarsComboitemRenderer = new BaseCalendarsComboitemRenderer();

    public List<Machine> getMachines() {
        return machineModel.getMachines();
    }

    public Machine getMachine() {
        return machineModel.getMachine();
    }

    @Override
    public void doAfterCompose(Component comp) throws Exception {
        super.doAfterCompose(comp);

        machineModel = (IMachineModel) SpringUtil.getBean("machineModel");
        limitsModel = (ILimitsModel) SpringUtil.getBean("limitsModel");
        resourceDAO = (IResourceDAO) SpringUtil.getBean("resourceDAO");
        resourceCalendarModel = (IBaseCalendarModel) SpringUtil.getBean("resourceCalendarModel");

        setupCriterionsController();
        setupConfigurationController();
        setupResourcesCostCategoryAssignmentController();
        showListWindow();
        initFilterComponent();
        setupFilterLimitingResourceListbox();
    }

    private void initFilterComponent() {
        this.filterFinishDate = (Datebox) listWindow.getFellowIfAny("filterFinishDate");
        this.filterStartDate = (Datebox) listWindow.getFellowIfAny("filterStartDate");
        this.filterLimitingResource = (Listbox) listWindow.getFellowIfAny("filterLimitingResource");
        this.bdFilters = (BandboxMultipleSearch) listWindow.getFellowIfAny("bdFilters");
        this.txtfilter = (Textbox) listWindow.getFellowIfAny("txtfilter");
        this.listing = (Grid) listWindow.getFellowIfAny("listing");
        clearFilterDates();
    }

    private void setupCriterionsController() throws Exception {
        final Component comp = editWindow.getFellowIfAny("criterionsContainer");
        criterionsController = new CriterionsMachineController();
        criterionsController.doAfterCompose(comp);
    }

    private void setupConfigurationController() {
        configurationUnits = editWindow.getFellow("configurationUnits");

        configurationController = (MachineConfigurationController) configurationUnits
                .getAttribute("configurationController", true);
    }

    private void setupResourcesCostCategoryAssignmentController() {
        Component costCategoryAssignmentContainer = editWindow.getFellowIfAny("costCategoryAssignmentContainer");

        resourcesCostCategoryAssignmentController = (ResourcesCostCategoryAssignmentController) costCategoryAssignmentContainer
                .getAttribute("assignmentController", true);
    }

    @Override
    protected void initCreate() {
        machineModel.initCreate();
        criterionsController.prepareForCreate(machineModel.getMachine());
        configurationController.initConfigurationController(machineModel);
        resourcesCostCategoryAssignmentController.setResource(machineModel.getMachine());
        selectMachineDataTab();
        resourceCalendarModel.cancel();
    }

    @Override
    protected void initEdit(Machine machine) {
        machineModel.initEdit(machine);
        prepareCriterionsForEdit();
        prepareCalendarForEdit();
        selectMachineDataTab();
        configurationController.initConfigurationController(machineModel);
        resourcesCostCategoryAssignmentController.setResource(machineModel.getMachine());
    }

    private void selectMachineDataTab() {
        Tab tabMachineData = (Tab) editWindow.getFellow("tbMachineData");
        tabMachineData.setSelected(true);
    }

    private void prepareCriterionsForEdit() {
        criterionsController.prepareForEdit(machineModel.getMachine());
    }

    private void prepareCalendarForEdit() {
        if (isCalendarNull()) {
            return;
        }

        updateCalendarController();
        resourceCalendarModel.initEdit(machineModel.getCalendarOfMachine());
        try {
            baseCalendarEditionController.doAfterCompose(editCalendarWindow);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }

        baseCalendarEditionController.setSelectedDay(new LocalDate());
        Util.reloadBindings(editCalendarWindow);
        Util.reloadBindings(createNewVersionWindow);
    }

    @Override
    protected void beforeSaving() throws ValidationException {
        validateConstraints();
    }

    @Override
    protected void save() throws ValidationException {
        saveCalendar();
        if (!confirmCriterions()) {
            return;
        }
        machineModel.confirmSave();
    }

    private void validateConstraints() {
        Tab tab = (Tab) editWindow.getFellowIfAny("tbMachineData");
        try {
            validateMachineDataTab();
            tab = (Tab) editWindow.getFellowIfAny("assignedCriteriaTab");
            criterionsController.validateConstraints();
            tab = (Tab) editWindow.getFellowIfAny("costCategoryAssignmentTab");
            resourcesCostCategoryAssignmentController.validateConstraints();
            // TODO: check 'calendar' tab
        } catch (WrongValueException e) {
            tab.setSelected(true);
            throw e;
        }
    }

    private void validateMachineDataTab() {
        ConstraintChecker.isValid(editWindow.getFellowIfAny("machineDataTabpanel"));
    }

    private void saveCalendar() throws ValidationException {
        if (baseCalendarEditionController != null) {
            baseCalendarEditionController.save();
        }

        if (machineModel.getCalendar() == null) {
            createCalendar();
        }
    }

    private boolean confirmCriterions() throws ValidationException {
        if (criterionsController != null) {
            if (!criterionsController.validate()) {
                return false;
            }
            criterionsController.save();
        }

        return true;
    }

    public List<BaseCalendar> getBaseCalendars() {
        return machineModel.getBaseCalendars();
    }

    private void createCalendar() {
        Combobox combobox = (Combobox) editWindow.getFellow("createDerivedCalendar");
        Comboitem selectedItem = combobox.getSelectedItem();
        if (selectedItem == null) {
            throw new WrongValueException(combobox, _("Please, select a calendar"));
        }

        BaseCalendar parentCalendar = combobox.getSelectedItem().getValue();
        if (parentCalendar == null) {
            parentCalendar = machineModel.getDefaultCalendar();
        }

        resourceCalendarModel.initCreateDerived(parentCalendar);
        resourceCalendarModel.generateCalendarCodes();
        machineModel.setCalendar((ResourceCalendar) resourceCalendarModel.getBaseCalendar());
    }

    private Window editCalendarWindow;

    private Window createNewVersionWindow;

    private BaseCalendarEditionController baseCalendarEditionController;

    private void updateCalendarController() {
        editCalendarWindow = (Window) editWindow.getFellowIfAny("editCalendarWindow");
        createNewVersionWindow = (Window) editWindow.getFellowIfAny("createNewVersion");

        createNewVersionWindow.setVisible(true);
        createNewVersionWindow.setVisible(false);

        baseCalendarEditionController = new BaseCalendarEditionController(resourceCalendarModel, editCalendarWindow,
                createNewVersionWindow, messagesForUser) {

            @Override
            public void goToList() {
                machineModel.setCalendarOfMachine((ResourceCalendar) resourceCalendarModel.getBaseCalendar());
                reloadWindow();
            }

            @Override
            public void cancel() {
                machineModel.removeCalendar();
                resourceCalendarModel.cancel();
                reloadWindow();
            }

            @Override
            public void save() {
                validateCalendarExceptionCodes();
                ResourceCalendar calendar = (ResourceCalendar) resourceCalendarModel.getBaseCalendar();
                if (calendar != null) {
                    resourceCalendarModel.generateCalendarCodes();
                    machineModel.setCalendarOfMachine(calendar);
                }
                reloadWindow();
            }

            @Override
            public void saveAndContinue() {
                save();
            }

        };

        editCalendarWindow.setAttribute("calendarController", this, true);
        createNewVersionWindow.setAttribute("calendarController", this, true);
    }

    private void reloadWindow() {
        Util.reloadBindings(editWindow);
    }

    public boolean isCalendarNull() {
        return (machineModel.getCalendarOfMachine() == null);
    }

    public boolean isCalendarNotNull() {
        return !isCalendarNull();
    }

    public BaseCalendarEditionController getEditionController() {
        return baseCalendarEditionController;
    }

    @SuppressWarnings("unused")
    private CriterionsController getCriterionsController() {
        return (CriterionsController) editWindow.getFellow("criterionsContainer")
                .getAttribute("assignedCriterionsController");
    }

    public MachineConfigurationController getConfigurationController() {
        return configurationController;
    }

    public BaseCalendarsComboitemRenderer getBaseCalendarsComboitemRenderer() {
        return baseCalendarsComboitemRenderer;
    }

    private class BaseCalendarsComboitemRenderer implements ComboitemRenderer {

        @Override
        public void render(Comboitem comboitem, Object o, int i) throws Exception {
            BaseCalendar calendar = (BaseCalendar) o;
            comboitem.setLabel(calendar.getName());
            comboitem.setValue(calendar);

            if (isDefaultCalendar(calendar)) {
                Combobox combobox = (Combobox) comboitem.getParent();
                combobox.setSelectedItem(comboitem);
            }
        }

        private boolean isDefaultCalendar(BaseCalendar calendar) {
            BaseCalendar defaultCalendar = machineModel.getDefaultCalendar();
            return defaultCalendar.getId().equals(calendar.getId());
        }
    }

    /**
     * Operations to filter the machines by multiple filters.
     */

    public Constraint checkConstraintFinishDate() {
        return new Constraint() {
            @Override
            public void validate(Component comp, Object value) throws WrongValueException {
                Date finishDate = (Date) value;

                if ((finishDate != null) && (filterStartDate.getValue() != null)
                        && (finishDate.compareTo(filterStartDate.getValue()) < 0)) {

                    filterFinishDate.setValue(null);
                    throw new WrongValueException(comp, _("must be after start date"));
                }
            }
        };
    }

    public Constraint checkConstraintStartDate() {
        return new Constraint() {
            @Override
            public void validate(Component comp, Object value) throws WrongValueException {
                Date startDate = (Date) value;

                if ((startDate != null) && (filterFinishDate.getValue() != null)
                        && (startDate.compareTo(filterFinishDate.getValue()) > 0)) {

                    filterStartDate.setValue(null);
                    throw new WrongValueException(comp, _("must be lower than end date"));
                }
            }
        };
    }

    public void onApplyFilter() {
        ResourcePredicate predicate = createPredicate();
        if (predicate != null) {
            filterByPredicate(predicate);
        } else {
            showAllMachines();
        }
    }

    private ResourcePredicate createPredicate() {
        List listFilters = bdFilters.getSelectedElements();

        String personalFilter = txtfilter.getValue();

        // Get the dates filter
        LocalDate startDate = null;
        LocalDate finishDate = null;
        if (filterStartDate.getValue() != null) {
            startDate = LocalDate.fromDateFields(filterStartDate.getValue());
        }
        if (filterFinishDate.getValue() != null) {
            finishDate = LocalDate.fromDateFields(filterFinishDate.getValue());
        }

        final Listitem item = filterLimitingResource.getSelectedItem();

        Boolean isLimitingResource = (item != null)
                ? LimitingResourceEnum.valueOf((LimitingResourceEnum) item.getValue())
                : null;

        if (listFilters.isEmpty() && (personalFilter == null || personalFilter.isEmpty()) && startDate == null
                && finishDate == null && isLimitingResource == null) {

            return null;
        }

        return new ResourcePredicate(listFilters, personalFilter, startDate, finishDate, isLimitingResource);
    }

    private void filterByPredicate(ResourcePredicate predicate) {
        List<Machine> filteredResources = machineModel.getFilteredMachines(predicate);
        listing.setModel(new SimpleListModel<>(filteredResources.toArray()));
        listing.invalidate();
    }

    private void clearFilterDates() {
        filterStartDate.setValue(null);
        filterFinishDate.setValue(null);
    }

    public void showAllMachines() {
        listing.setModel(new SimpleListModel(machineModel.getAllMachines().toArray()));
        listing.invalidate();
    }

    private void setupFilterLimitingResourceListbox() {
        for (LimitingResourceEnum resourceEnum : LimitingResourceEnum.getLimitingResourceFilterOptionList()) {
            Listitem item = new Listitem();
            item.setParent(filterLimitingResource);
            item.setValue(resourceEnum);
            item.appendChild(new Listcell(resourceEnum.toString()));
            filterLimitingResource.appendChild(item);
        }
        filterLimitingResource.setSelectedIndex(0);
    }

    public Set<LimitingResourceEnum> getLimitingResourceOptionList() {
        return LimitingResourceEnum.getLimitingResourceOptionList();
    }

    public Object getLimitingResource() {
        final Machine machine = getMachine();
        return (machine != null) ? LimitingResourceEnum.valueOf(machine.isLimitingResource())
                : LimitingResourceEnum.NON_LIMITING_RESOURCE; // Default option
    }

    public void setLimitingResource(LimitingResourceEnum option) {
        Machine machine = getMachine();
        if (machine != null) {
            machine.setResourceType(LimitingResourceEnum.toResourceType(option));
        }
    }

    public boolean isEditing() {
        return (getMachine() != null && !getMachine().isNewObject());
    }

    public void onCheckGenerateCode(Event e) {
        CheckEvent ce = (CheckEvent) e;
        if (ce.isChecked()) {
            // We have to auto-generate the code if it's unsaved
            try {
                machineModel.setCodeAutogenerated(ce.isChecked());
            } catch (ConcurrentModificationException err) {
                messagesForUser.showMessage(Level.ERROR, err.getMessage());
            }
            Util.reloadBindings(editWindow);
        }
    }

    @Override
    protected boolean beforeDeleting(Machine machine) {
        if (!machineModel.canRemove(machine)) {

            messagesForUser.showMessage(Level.WARNING,
                    _("Machine cannot be deleted. Machine is allocated to a project or contains imputed hours"));

            return false;
        }

        return true;
    }

    @Override
    protected void delete(Machine machine) {
        try {
            machineModel.confirmRemove(machine);
        } catch (InstanceNotFoundException e) {
            messagesForUser.showMessage(Level.INFO, _("Machine was already removed"));
        }
    }

    public RowRenderer getMachinesRenderer() {
        return (row, data, i) -> {
            final Machine machine = (Machine) data;
            row.setValue(machine);

            row.addEventListener(Events.ON_CLICK, event -> goToEditForm(machine));

            row.appendChild(new Label(machine.getName()));
            row.appendChild(new Label(machine.getDescription()));
            row.appendChild(new Label(machine.getCode()));
            row.appendChild(new Label((Boolean.TRUE.equals(machine.isLimitingResource())) ? _("yes") : _("no")));

            Hbox hbox = new Hbox();
            hbox.appendChild(Util.createEditButton(event -> goToEditForm(machine)));
            hbox.appendChild(Util.createRemoveButton(event -> confirmDelete(machine)));
            row.appendChild(hbox);
        };
    }

    @Override
    protected String getEntityType() {
        return _("Machine");
    }

    @Override
    protected String getPluralEntityType() {
        return _("Machines");
    }

    @Override
    protected Machine getEntityBeingEdited() {
        return machineModel.getMachine();
    }

    /**
     * Should be public!
     * Used in _listMachines.zul
     */
    public boolean isCreateButtonDisabled() {
        Limits resourcesTypeLimit = limitsModel.getResourcesType();
        if (isNullOrZeroValue(resourcesTypeLimit)) {
            return false;
        } else {
            Integer resources = resourceDAO.getRowCount().intValue();
            return resources >= resourcesTypeLimit.getValue();
        }
    }

    /**
     * Should be public!
     * Used in _listMachines.zul
     */
    public String getShowCreateFormLabel() {
        Limits resourcesTypeLimit = limitsModel.getResourcesType();

        if (isNullOrZeroValue(resourcesTypeLimit)) {
            return _("Create");
        }

        Integer resources = resourceDAO.getRowCount().intValue();
        int resourcesLeft = resourcesTypeLimit.getValue() - resources;

        return resources >= resourcesTypeLimit.getValue() ? _("Machines limit reached")
                : _("Create") + " ( " + resourcesLeft + " " + _("left") + " )";
    }

    private boolean isNullOrZeroValue(Limits resourcesTypeLimit) {
        return resourcesTypeLimit == null || resourcesTypeLimit.getValue() == null
                || resourcesTypeLimit.getValue().equals(0);
    }

}