From 21a8d1cc6898ce50b7e8f7024fecef4a751088ad Mon Sep 17 00:00:00 2001 From: Alba Carro Date: Fri, 24 Aug 2012 23:54:29 +0200 Subject: [PATCH] First step to import orders using MPXJ * Implement the interface OrderImporter using MPXJ * Conversor from MPXJ file types to ImportData * Modify pom.xml to add MPXJ dependency FEA: ItEr77S05BasicProjectImport --- libreplan-business/pom.xml | 5 + .../imports/MPXJProjectFileConversor.java | 176 +++++++++++++ .../orders/imports/OrderImporterMPXJ.java | 243 ++++++++++++++++++ pom.xml | 6 + 4 files changed, 430 insertions(+) create mode 100644 libreplan-business/src/main/java/org/libreplan/business/orders/imports/MPXJProjectFileConversor.java create mode 100644 libreplan-business/src/main/java/org/libreplan/business/orders/imports/OrderImporterMPXJ.java diff --git a/libreplan-business/pom.xml b/libreplan-business/pom.xml index f4cd68969..a53ffc2a6 100644 --- a/libreplan-business/pom.xml +++ b/libreplan-business/pom.xml @@ -120,6 +120,11 @@ org.liquibase liquibase-maven-plugin + + + net.sourceforge + mpxj + diff --git a/libreplan-business/src/main/java/org/libreplan/business/orders/imports/MPXJProjectFileConversor.java b/libreplan-business/src/main/java/org/libreplan/business/orders/imports/MPXJProjectFileConversor.java new file mode 100644 index 000000000..d2601a96c --- /dev/null +++ b/libreplan-business/src/main/java/org/libreplan/business/orders/imports/MPXJProjectFileConversor.java @@ -0,0 +1,176 @@ +/* + * 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 . + */ + +package org.libreplan.business.orders.imports; + +import java.util.ArrayList; +import java.util.List; + +import net.sf.mpxj.ProjectFile; +import net.sf.mpxj.Task; + +/** + * Class that is a conversor from the MPXJ format File to {@link ImportData}. + * + * At these moment it only converts the tasks and its subtasks. + * + * @author Alba Carro Pérez + * @todo It last relationships. resources, calendars, hours, etc. + */ +public class MPXJProjectFileConversor { + + /** + * Converts a ProjectFile into a {@link ImportData}. + * + * This method contains a switch that is going to select the method to call + * for each format. At this time it only differences between planner and + * project. + * + * @param file + * ProjectFile to extract data from. + * @return ImportData with the data that we want to import. + */ + public static ImportData convert(ProjectFile file, String filename) { + + ImportData importData; + + switch (file.getMppFileType()) { + + case 0: + importData = getImportDataFromPlanner(file, filename); + break; + default: + importData = getImportDataFromMPP(file, filename); + break; + + } + + return importData; + } + + /** + * Converts a ProjectFile into a {@link ImportData}. + * + * Assumes that the ProjectFile comes for a .planner file. + * + * @param file + * ProjectFile to extract data from. + * @return ImportData with the data that we want to import. + */ + private static ImportData getImportDataFromPlanner(ProjectFile file, + String filename) { + + ImportData importData = new ImportData(); + + importData.name = filename + .substring(0, filename.length() - 8/* ".planner" */); + + importData.tasks = getImportTasks(file.getChildTasks()); + + return importData; + + } + + /** + * Converts a ProjectFile into a {@link ImportData} + * + * Assumes that the ProjectFile comes for a .mpp file. + * + * @param file + * ProjectFile to extract data from. + * @return ImportData with the data that we want to import. + */ + private static ImportData getImportDataFromMPP(ProjectFile file, + String filename) { + + ImportData importData = new ImportData(); + + for (Task task : file.getChildTasks()) { + // Projects are represented as a level 0 task with all + // real task as its children. Ignore all other top level tasks. + // See + // http://mpxj.sourceforge.net/faq.html#extra-tasks-and-resources + if (task.getChildTasks().size() != 0) { + + String name = task.getName(); + + if (name != null) { + + importData.name = name; + + } else { + // Take the filename if the project name is not set. + importData.name = filename.substring(0, + filename.length() - 4/* ".mpp" */); + + } + + importData.tasks = getImportTasks(task.getChildTasks()); + + break; + } + + } + + return importData; + } + + /** + * Converts a List of MPXJ Tasks into a List of {@link ImportTask}. + * + * @param tasks + * List of MPXJ Tasks to extract data from. + * @return List List of ImportTask with the data that we want to + * import. + */ + private static List getImportTasks(List tasks) { + + List importTasks = new ArrayList(); + + for (Task task : tasks) { + + ImportTask importTask = getTaskData(task); + + importTask.children = getImportTasks(task.getChildTasks()); + + importTasks.add(importTask); + + } + + return importTasks; + + } + + /** + * Converts a MPXJ Task into a {@link ImportTask}. + * + * @param task + * MPXJ Task to extract data from. + * @return ImportTask ImportTask with the data that we want to import. + */ + private static ImportTask getTaskData(Task task) { + + ImportTask importTask = new ImportTask(); + + importTask.name = task.getName(); + + return importTask; + + } +} diff --git a/libreplan-business/src/main/java/org/libreplan/business/orders/imports/OrderImporterMPXJ.java b/libreplan-business/src/main/java/org/libreplan/business/orders/imports/OrderImporterMPXJ.java new file mode 100644 index 000000000..e8ac6df2a --- /dev/null +++ b/libreplan-business/src/main/java/org/libreplan/business/orders/imports/OrderImporterMPXJ.java @@ -0,0 +1,243 @@ +/* + * 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 . + */ + +package org.libreplan.business.orders.imports; + +import java.io.InputStream; +import java.util.ArrayList; +import java.util.ConcurrentModificationException; +import java.util.Date; +import java.util.List; +import java.util.UUID; + +import net.sf.mpxj.reader.ProjectReader; +import net.sf.mpxj.reader.ProjectReaderUtility; + +import org.apache.commons.lang.Validate; +import org.libreplan.business.calendars.entities.BaseCalendar; +import org.libreplan.business.common.IAdHocTransactionService; +import org.libreplan.business.common.daos.IConfigurationDAO; +import org.libreplan.business.common.daos.IEntitySequenceDAO; +import org.libreplan.business.common.entities.EntityNameEnum; +import org.libreplan.business.orders.daos.IOrderDAO; +import org.libreplan.business.orders.entities.Order; +import org.libreplan.business.orders.entities.OrderElement; +import org.libreplan.business.orders.entities.OrderLine; +import org.libreplan.business.orders.entities.OrderLineGroup; +import org.libreplan.business.scenarios.IScenarioManager; +import org.libreplan.business.scenarios.entities.OrderVersion; +import org.libreplan.business.scenarios.entities.Scenario; +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 some external project files + * into Libreplan using MPXJ. + * + * @author Alba Carro Pérez + */ +@Component +@Scope(BeanDefinition.SCOPE_SINGLETON) +public class OrderImporterMPXJ implements OrderImporter { + + @Autowired + private IEntitySequenceDAO entitySequenceDAO; + + @Autowired + protected IAdHocTransactionService transactionService; + + @Autowired + private IConfigurationDAO configurationDAO; + + @Autowired + private IOrderDAO orderDAO; + + @Autowired + private IScenarioManager scenarioManager; + + /** + * Makes a {@link ImportData} from a InputStream. + * + * Uses the filename in order to get the specific ProjectReader for each + * kind of file (.mpp, .planner, etc). + * + * @param file + * InputStream to extract data from. + * @param filename + * String with the name of the original file of the InputStream. + * @return ImportData with the data that we want to import. + */ + @Override + public ImportData getImportData(InputStream file, String filename) { + try { + + ProjectReader reader = ProjectReaderUtility + .getProjectReader(filename); + + return MPXJProjectFileConversor + .convert(reader.read(file), filename); + + } catch (Exception e) { + + throw new RuntimeException(e); + + } + + } + + 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 {@link Order} from a {@link ImportData}. + * + * @param project + * ImportData to extract data from. + * @return Order with all the data that we want. + */ + @Override + @Transactional(readOnly = true) + public Order convertImportDataToOrder(ImportData project) { + + String code = getCode(EntityNameEnum.ORDER); + + Scenario current = scenarioManager.getCurrent(); + + OrderVersion orderVersion = OrderVersion.createInitialVersion(current); + + Validate.notNull(orderVersion); + + OrderElement orderElement; + + orderElement = Order.createUnvalidated(code); + + ((Order) orderElement).setVersionForScenario(current, orderVersion); + + ((Order) orderElement).setDependenciesConstraintsHavePriority(true); + + BaseCalendar calendar = configurationDAO.getConfiguration() + .getDefaultCalendar(); + + ((Order) orderElement).setCalendar(calendar); + + orderElement.useSchedulingDataFor(orderVersion); + + List children = new ArrayList(); + + for (ImportTask task : project.tasks) { + children.add(convertImportTaskToOrderElement(orderVersion, task)); + } + + for (OrderElement child : children) { + ((OrderLineGroup) orderElement).add(child); + } + + orderElement.setName(project.name + ": " + project.hashCode()); + orderElement.setCode(code); + + orderElement.setInitDate(new Date()); + + return (Order) orderElement; + + } + + /** + * Private method. + * + * It makes a {@link OrderElement} from a {@link ImportTask} + * + * @param task + * ImportTask to extract data from. + * @param orderVersion + * Number of version. + * @return OrderElement OrderElement that represent the data. + */ + private OrderElement convertImportTaskToOrderElement( + OrderVersion orderVersion, ImportTask task) { + + Validate.notNull(orderVersion); + OrderElement orderElement; + String code; + + if (task.children.size() == 0) { + code = getCode(EntityNameEnum.ORDER); + + orderElement = OrderLine.createUnvalidatedWithUnfixedPercentage( + code, 0); + + if (!orderElement.getHoursGroups().isEmpty()) { + orderElement.getHoursGroups().get(0) + .setCode(UUID.randomUUID().toString()); + } + + } else { + code = getCode(EntityNameEnum.ORDER); + orderElement = OrderLineGroup.createUnvalidated(code); + orderElement.useSchedulingDataFor(orderVersion); + } + + List children = new ArrayList(); + + for (ImportTask childrenTask : task.children) { + children.add(convertImportTaskToOrderElement(orderVersion, + childrenTask)); + } + + for (OrderElement child : children) { + + ((OrderLineGroup) orderElement).add(child); + } + + orderElement.setName(task.name); + orderElement.setCode(code); + orderElement.setInitDate(new Date()); + + return orderElement; + } + + /** + * Saves an {@link Order} which has all the data that we want to store in + * the database. + * + * @param Order + * Order with the data. + */ + @Override + @Transactional + public void storeOrder(final Order order) { + + orderDAO.save(order); + + } + +} diff --git a/pom.xml b/pom.xml index 7f7508b6d..ea43979b8 100644 --- a/pom.xml +++ b/pom.xml @@ -755,6 +755,12 @@ jqplot4java 1.2.3-javascript + + + net.sourceforge + mpxj + 4.3.0 +