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
This commit is contained in:
Alba Carro 2012-08-24 23:54:29 +02:00 committed by Manuel Rego Casasnovas
parent 59d2a029fc
commit 21a8d1cc68
4 changed files with 430 additions and 0 deletions

View file

@ -120,6 +120,11 @@
<groupId>org.liquibase</groupId>
<artifactId>liquibase-maven-plugin</artifactId>
</dependency>
<!-- MPXJ Library -->
<dependency>
<groupId>net.sourceforge</groupId>
<artifactId>mpxj</artifactId>
</dependency>
</dependencies>
<profiles>

View file

@ -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 <http://www.gnu.org/licenses/>.
*/
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 <alba.carro@gmail.com>
* @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<ImportTask> List of ImportTask with the data that we want to
* import.
*/
private static List<ImportTask> getImportTasks(List<Task> tasks) {
List<ImportTask> importTasks = new ArrayList<ImportTask>();
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;
}
}

View file

@ -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 <http://www.gnu.org/licenses/>.
*/
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 <alba.carro@gmail.com>
*/
@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<OrderElement> children = new ArrayList<OrderElement>();
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<OrderElement> children = new ArrayList<OrderElement>();
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);
}
}

View file

@ -755,6 +755,12 @@
<artifactId>jqplot4java</artifactId>
<version>1.2.3-javascript</version>
</dependency>
<!-- MPXJ Library -->
<dependency>
<groupId>net.sourceforge</groupId>
<artifactId>mpxj</artifactId>
<version>4.3.0</version>
</dependency>
</dependencies>
</dependencyManagement>