org.libreplan.importers.CalendarImporterMPXJ.java Source code

Java tutorial

Introduction

Here is the source code for org.libreplan.importers.CalendarImporterMPXJ.java

Source

/*
 * This file is part of LibrePlan
 *
 * Copyright (C) 2012 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.importers;

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

import java.io.InputStream;
import java.util.ArrayList;
import java.util.ConcurrentModificationException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Objects;

import net.sf.mpxj.ProjectFile;
import net.sf.mpxj.reader.ProjectReader;
import net.sf.mpxj.reader.ProjectReaderUtility;

import org.joda.time.LocalDate;
import org.libreplan.business.calendars.daos.IBaseCalendarDAO;
import org.libreplan.business.calendars.daos.ICalendarExceptionTypeDAO;
import org.libreplan.business.calendars.entities.BaseCalendar;
import org.libreplan.business.calendars.entities.CalendarData;
import org.libreplan.business.calendars.entities.CalendarException;
import org.libreplan.business.calendars.entities.CalendarExceptionType;
import org.libreplan.business.calendars.entities.Capacity;
import org.libreplan.business.common.daos.IEntitySequenceDAO;
import org.libreplan.business.common.entities.EntityNameEnum;
import org.libreplan.business.common.exceptions.InstanceNotFoundException;
import org.libreplan.business.common.exceptions.ValidationException;
import org.libreplan.business.workingday.EffortDuration;
import org.libreplan.importers.CalendarDayHoursDTO.CalendarTypeDayDTO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

/**
 * Has all the methods needed to successfully import calendar data of external project files into Libreplan using MPXJ.
 *
 * @author Alba Carro Prez <alba.carro@gmail.com>
 */
@Component
@Scope(BeanDefinition.SCOPE_SINGLETON)
@Transactional
public class CalendarImporterMPXJ implements ICalendarImporter {

    private static ProjectFile projectFile = null;

    @Autowired
    private IBaseCalendarDAO baseCalendarDAO;

    @Autowired
    private IEntitySequenceDAO entitySequenceDAO;

    @Autowired
    private ICalendarExceptionTypeDAO calendarExceptionTypeDAO;

    /**
     * Makes a list of {@link CalendarDTO} from a InputStream.
     *
     * @param file
     *            InputStream to extract data from.
     * @return List<CalendarDTO> with the calendar data that we want to import.
     */
    @Override
    public List<CalendarDTO> getCalendarDTOs(InputStream file, String filename) {

        try {

            ProjectReader reader = ProjectReaderUtility.getProjectReader(filename);

            // In case that orders are imported too
            projectFile = reader.read(file);

            return MPXJProjectFileConverter.convertCalendars(projectFile);

        } catch (Exception e) {

            throw new RuntimeException(e);

        }

    }

    /**
     * Makes a {@link OrderDTO} from a InputStream.
     *
     * Uses the ProjectReader of the class. It must be created before.
     *
     * @param filename
     *            String with the name of the original file of the InputStream.
     * @return OrderDTO with the data that we want to import.
     */
    @Override
    public OrderDTO getOrderDTO(String filename) {
        try {

            return MPXJProjectFileConverter.convert(projectFile, filename);

        } catch (Exception e) {

            throw new RuntimeException(e);

        }

    }

    /**
     * Makes a list of {@link BaseCalendar} from a list of {@link CalendarDTO}.
     *
     * @param calendarDTOs
     *            List of CalendarDTO to extract data from.
     * @return List<BaseCalendar> with all the calendars that we want.
     * @throws InstanceNotFoundException, ValidationException
     */
    @Override
    public List<BaseCalendar> getBaseCalendars(List<CalendarDTO> calendarDTOs) throws InstanceNotFoundException {
        List<BaseCalendar> baseCalendars = new ArrayList<>();

        for (CalendarDTO calendarDTO : calendarDTOs) {

            if (calendarDTO.parent == null) {

                baseCalendars.add(toBaseCalendar(calendarDTO, null));

            } else {

                BaseCalendar parent = findBaseCalendarParent(baseCalendars, calendarDTO.parent);

                if (parent != null) {

                    baseCalendars.add(toBaseCalendar(calendarDTO, parent));

                } else {

                    throw new ValidationException("Parent calendar not found");

                }

            }
        }

        return baseCalendars;
    }

    /**
     * Search for a {@link BaseCalendar} that has this name.
     *
     * @param baseCalendars
     *            List<BaseCalendar> to search into.
     * @param name
     *            Search condition
     * @return BaseCalendar with the name equal to the search condition.
     */
    private BaseCalendar findBaseCalendarParent(List<BaseCalendar> baseCalendars, String name) {

        for (BaseCalendar baseCalendar : baseCalendars) {

            if (Objects.equals(baseCalendar.getName(), name)) {

                return baseCalendar;

            }
        }

        return null;
    }

    /**
     * Makes a {@link BaseCalendar} from a {@link CalendarDTO}.
     *
     * @param calendarDTO
     *            CalendarDTO to extract data from.
     * @return BaseCalendar with the calendar that we want.
     * @throws InstanceNotFoundException, ValidationException
     */
    private BaseCalendar toBaseCalendar(CalendarDTO calendarDTO, BaseCalendar parent)
            throws InstanceNotFoundException {

        String code = getCode(EntityNameEnum.CALENDAR);

        String name = validateName(calendarDTO.name);

        Set<CalendarException> calendarExceptions = getCalendarExceptions(calendarDTO.calendarExceptions);

        List<CalendarData> calendarData = getCalendarData(calendarDTO.calendarWeeks, parent);

        BaseCalendar baseCalendar = BaseCalendar.createUnvalidated(code, name, parent, calendarExceptions,
                calendarData);

        baseCalendar.setCodeAutogenerated(true);

        baseCalendar.setName(name);

        if (parent != null) {
            baseCalendar.setParent(parent);
        }

        baseCalendar
                .generateCalendarExceptionCodes(entitySequenceDAO.getNumberOfDigitsCode(EntityNameEnum.CALENDAR));

        return baseCalendar;
    }

    /**
     * Calculate the next code for the entity.
     *
     * @param entity
     *         EntityNameEnum Entity
     * @return String new code.
     */
    private String getCode(EntityNameEnum entity) {

        String code = entitySequenceDAO.getNextEntityCode(entity);

        if (code == null) {
            throw new ConcurrentModificationException("Could not retrieve Code. Please, try again later");
        }

        return code;
    }

    /**
     * Makes a list of {@link CalendarData} from a list of {@link CalendarWeekDTO}.
     *
     * @param calendarWeeks
     *            List of CalendarWeekDTO to extract data from.
     * @param parent
     *            BaseCalendar parent of all the calendarWeeks.
     * @return List<CalendarData> with all the CalendarData that we want.
     */
    private List<CalendarData> getCalendarData(List<CalendarWeekDTO> calendarWeeks, BaseCalendar parent) {

        List<CalendarData> calendarData = new ArrayList<>();

        for (CalendarWeekDTO calendarWeekDTO : calendarWeeks) {

            calendarData.add(toCalendarData(calendarWeekDTO, parent));
        }

        return calendarData;
    }

    /**
     * Makes a list of {@link CalendarException} from a list of {@link CalendarExceptionDTO}.
     *
     * @param calendarExceptionDTOs
     *            List of CalendarExceptionDTO to extract data from.
     * @return List<CalendarException> with all the CalendarException that we want.
     * @throws InstanceNotFoundException
     */
    private Set<CalendarException> getCalendarExceptions(List<CalendarExceptionDTO> calendarExceptionDTOs)
            throws InstanceNotFoundException {

        Set<CalendarException> calendarExceptions = new HashSet<>();

        for (CalendarExceptionDTO calendarExceptionDTO : calendarExceptionDTOs) {

            calendarExceptions.add(toCalendarException(calendarExceptionDTO));
        }

        return calendarExceptions;
    }

    /**
     * Makes a {@link CalendarException} from a {@link CalendarExceptionDTO}.
     *
     * @param calendarExceptionDTO
     *            CalendarExceptionDTO to extract data from.
     * @return CalendarException with the CalendarException that we want.
     * @throws InstanceNotFoundException
     */
    private CalendarException toCalendarException(CalendarExceptionDTO calendarExceptionDTO)
            throws InstanceNotFoundException {

        LocalDate date = null;

        if (calendarExceptionDTO.date != null) {
            date = LocalDate.fromDateFields(calendarExceptionDTO.date);
        }

        CalendarExceptionType calendarExceptionType;

        if (calendarExceptionDTO.working) {

            calendarExceptionType = calendarExceptionTypeDAO.findUniqueByName("WORKING_DAY");

        } else {

            calendarExceptionType = calendarExceptionTypeDAO.findUniqueByName("NOT_WORKING_DAY");

        }

        return CalendarException.create(date, EffortDuration.hours(calendarExceptionDTO.hours)
                .plus(EffortDuration.minutes(calendarExceptionDTO.minutes)), calendarExceptionType);
    }

    /**
     * Validate if a calendar name is not in use.
     * If it is throws an exception.
     * It not return the same name.
     *
     * @param name
     *            String with the name to validate.
     * @return String with the valid name.
     * @throws ValidationException
     */
    @Transactional
    private String validateName(String name) {

        List<BaseCalendar> calendars = baseCalendarDAO.findByName(name);

        if (calendars.isEmpty()) {
            return name;
        } else {
            throw new ValidationException(_("Calendar name already in use"));
        }

    }

    /**
     * Makes a {@link CalendarData} from a {@link CalendarWeekDTO}.
     *
     * @param workingWeek
     *            CalendarWeekDTO to extract data from.
     * @param parent
     *            BaseCalendar parent of this workingWeek
     * @return CalendarData with the CalendarData that we want.
     */
    private CalendarData toCalendarData(CalendarWeekDTO workingWeek, BaseCalendar parent) {

        LocalDate expiringDate = null;

        if (workingWeek.endDate != null) {
            expiringDate = LocalDate.fromDateFields(workingWeek.endDate);
        }

        if (workingWeek.startDate != null) {
            expiringDate = LocalDate.fromDateFields(workingWeek.startDate);
        }

        CalendarData calendarData = CalendarData.create();

        calendarData.setExpiringDate(expiringDate);

        if (parent != null) {

            calendarData.setParent(parent);

        }

        calendarData.setCodeAutogenerated(true);

        Map<Integer, Capacity> capacitiesPerDays = getCapacitiesPerDays(workingWeek.hoursPerDays);
        try {
            calendarData.updateCapacitiesPerDay(capacitiesPerDays);
        } catch (IllegalArgumentException e) {
            throw new ValidationException(e.getMessage());
        }

        return calendarData;
    }

    /**
     * Makes a map of capacities with a list of {@link CalendarDayHoursDTO}.
     *
     * @param hoursPerDays
     *            List<CalendarDayHoursDTO> to extract data from.
     * @return Map<Integer, Capacity>  with the data that we want.
     * @throws ValidationException
     */
    private Map<Integer, Capacity> getCapacitiesPerDays(List<CalendarDayHoursDTO> hoursPerDays) {

        Map<Integer, Capacity> result = new HashMap<>();

        if (hoursPerDays != null) {
            for (CalendarDayHoursDTO hoursPerDayDTO : hoursPerDays) {
                try {

                    if (hoursPerDayDTO.type == CalendarTypeDayDTO.DEFAULT) {
                        continue;
                    }

                    Integer day = CalendarData.Days.valueOf(hoursPerDayDTO.day.toString()).ordinal();

                    Capacity capacity = Capacity.zero();

                    if (hoursPerDayDTO.type == CalendarTypeDayDTO.WORKING) {

                        capacity = Capacity.create(EffortDuration.hours(hoursPerDayDTO.hours))
                                .overAssignableWithoutLimit();

                    } else if (hoursPerDayDTO.type == CalendarTypeDayDTO.NOT_WORKING) {
                        capacity = Capacity.create(EffortDuration.hours(hoursPerDayDTO.hours));
                    }

                    result.put(day, capacity);

                } catch (IllegalArgumentException e) {

                    throw new ValidationException("a day is not valid");

                } catch (NullPointerException e) {

                    throw new ValidationException("a day is null");
                }
            }
        }

        return result;
    }

    /**
     * Saves a list of {@link BaseCalendar} that has all the calendar data that we want to store in the database.
     *
     * @param baseCalendars
     */
    @Override
    @Transactional
    public void storeBaseCalendars(List<BaseCalendar> baseCalendars) {
        for (BaseCalendar baseCalendar : baseCalendars) {
            baseCalendarDAO.save(baseCalendar);
        }

    }
}