/*
* ConcourseConnect
* Copyright 2009 Concursive Corporation
* http://www.concursive.com
*
* This file is part of ConcourseConnect, an open source social business
* software and community platform.
*
* Concursive ConcourseConnect 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, version 3 of the License.
*
* Under the terms of the GNU Affero General Public License you must release the
* complete source code for any application that uses any part of ConcourseConnect
* (system header files and libraries used by the operating system are excluded).
* These terms must be included in any work that has ConcourseConnect components.
* If you are developing and distributing open source applications under the
* GNU Affero General Public License, then you are free to use ConcourseConnect
* under the GNU Affero General Public License.
*
* If you are deploying a web site in which users interact with any portion of
* ConcourseConnect over a network, the complete source code changes must be made
* available. For example, include a link to the source archive directly from
* your web site.
*
* For OEMs, ISVs, SIs and VARs who distribute ConcourseConnect with their
* products, and do not license and distribute their source code under the GNU
* Affero General Public License, Concursive provides a flexible commercial
* license.
*
* To anyone in doubt, we recommend the commercial license. Our commercial license
* is competitively priced and will eliminate any confusion about how
* ConcourseConnect can be used and distributed.
*
* ConcourseConnect 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 ConcourseConnect. If not, see <http://www.gnu.org/licenses/>.
*
* Attribution Notice: ConcourseConnect is an Original Work of software created
* by Concursive Corporation
*/
package com.concursive.connect.web.modules.plans.utils;
import com.concursive.connect.web.modules.login.dao.User;
import com.concursive.connect.web.modules.plans.dao.Assignment;
import com.concursive.connect.web.modules.plans.dao.AssignmentFolder;
import com.concursive.connect.web.modules.plans.dao.Requirement;
import net.sf.mpxj.*;
import net.sf.mpxj.mpp.MPPReader;
import net.sf.mpxj.mpx.MPXReader;
import net.sf.mpxj.mspdi.MSPDIReader;
import java.io.ByteArrayInputStream;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
/**
* Imports data from other formats into an outline; adapted from MpxjQuery.java
*
* @author matt rajkowski
* @created September 25, 2007
*/
public class AssignmentMicrosoftProjectImporter {
public static boolean parse(byte[] buffer, Requirement requirement, Connection db) throws SQLException {
if (System.getProperty("DEBUG") != null) {
System.out.println("AssignmentMicrosoftProjectImporter-> parse");
}
try {
db.setAutoCommit(false);
// Determine the correct format
ProjectFile mpx = null;
try {
mpx = new MPXReader().read(new ByteArrayInputStream(buffer));
}
catch (Exception ex) {
mpx = null;
}
if (mpx == null) {
try {
mpx = new MPPReader().read(new ByteArrayInputStream(buffer));
}
catch (Exception ex) {
mpx = null;
}
}
if (mpx == null) {
try {
mpx = new MSPDIReader().read(new ByteArrayInputStream(buffer));
}
catch (Exception ex) {
mpx = null;
}
}
if (mpx == null) {
throw new Exception("Failed to read file");
}
parseProjectHeader(requirement, mpx, db);
parseTasks(requirement, mpx, db);
/*
listResources(mpx);
listTasks(mpx);
listAssignments(mpx);
listAssignmentsByTask(mpx);
listAssignmentsByResource(mpx);
listTaskNotes(mpx);
listResourceNotes(mpx);
listPredecessors(mpx);
listSlack(mpx);
listCalendars(mpx);
*/
db.commit();
} catch (Exception e) {
db.rollback();
e.printStackTrace(System.out);
return false;
} finally {
db.setAutoCommit(true);
}
return true;
}
/**
* Reads basic summary details from the project header.
*
* @param file MPX file
* @param requirement Requirement object
*/
private static void parseProjectHeader(Requirement requirement, ProjectFile file, Connection db) throws SQLException {
ProjectHeader header = file.getProjectHeader();
if (System.getProperty("DEBUG") != null) {
System.out.println("AssignmentMicrosoftProjectImporter-> Project Header: StartDate=" + requirement.getStartDate() + " FinishDate=" + requirement.getDeadline());
}
requirement.setStartDate(new Timestamp(header.getStartDate().getTime()));
requirement.setDeadline(new Timestamp(header.getFinishDate().getTime()));
requirement.update(db);
}
/**
* This method lists all tasks defined in the file in a hierarchical
* format, reflecting the parent-child relationships between them.
*
* @param file MPX file
*/
private static void parseTasks(Requirement requirement, ProjectFile file, Connection db) throws SQLException {
for (Task task : file.getChildTasks()) {
if (!task.getNull()) {
if (System.getProperty("DEBUG") != null) {
System.out.println("0 Task: " + task.getName());
}
// TODO: Some tasks have sub-tasks, so see if this is an assignment
if (task.getChildTasks().size() > 0) {
// This is a folder
AssignmentFolder folder = populateAssignmentFolder(task, requirement, 0, -1);
folder.insert(db);
parseChildTasks(requirement, task, db, 0, folder.getId());
} else {
Assignment assignment = populateAssignment(task, requirement, db, 0, -1);
if (!assignment.hasValidTeam(db)) {
assignment.getAssignedUserList().clear();
}
assignment.insert(db);
}
}
}
}
/**
* Helper method called recursively to list child tasks.
*
* @param parentTask task whose children are to be displayed
* @param indent whitespace used to indent hierarchy levels
*/
private static void parseChildTasks(Requirement requirement, Task parentTask, Connection db, int indent, int folderId) throws SQLException {
++indent;
for (Task task : parentTask.getChildTasks()) {
if (!task.getNull()) {
if (System.getProperty("DEBUG") != null) {
System.out.println(indent + " Task: " + task.getName());
}
if (task.getChildTasks().size() > 0) {
// This is a folder
AssignmentFolder folder = populateAssignmentFolder(task, requirement, indent, folderId);
folder.insert(db);
parseChildTasks(requirement, task, db, indent, folder.getId());
} else {
Assignment assignment = populateAssignment(task, requirement, db, indent, folderId);
if (!assignment.hasValidTeam(db)) {
assignment.getAssignedUserList().clear();
}
assignment.insert(db);
}
}
}
}
private static Assignment populateAssignment(Task task, Requirement requirement, Connection db, int indent, int folderId) throws SQLException {
Assignment assignment = new Assignment();
assignment.setProjectId(requirement.getProjectId());
assignment.setRequirementId(requirement.getId());
assignment.setIndent(indent);
assignment.setEnteredBy(requirement.getModifiedBy());
assignment.setModifiedBy(requirement.getModifiedBy());
assignment.setFolderId(folderId);
// Task description
assignment.setRole(task.getName());
// Status (Not Started -- default)
assignment.setStatusId(1);
Number percentComplete = task.getPercentageComplete();
assignment.setPercentComplete(percentComplete.intValue());
if (percentComplete.intValue() > 0) {
if (System.getProperty("DEBUG") != null) {
System.out.println(" percent: " + percentComplete.toString());
}
// In progress
assignment.setStatusId(2);
if (percentComplete.intValue() == 100) {
// Complete
assignment.setStatusId(5);
}
}
assignment.setPriorityId(2);
Priority priority = task.getPriority();
if (priority != null) {
if (System.getProperty("DEBUG") != null) {
System.out.println(" priority: " + priority.getValue());
}
if (priority.getValue() > 0 && priority.getValue() < 500) {
assignment.setPriorityId(1);
} else if (priority.getValue() > 500) {
assignment.setPriorityId(3);
}
}
Date estStartDate = task.getStart();
if (estStartDate != null) {
assignment.setEstStartDate(new Timestamp(estStartDate.getTime()));
}
Date dueDate = task.getFinish();
if (dueDate != null) {
assignment.setDueDate(new Timestamp(dueDate.getTime()));
}
Duration estimatedDuration = task.getDuration();
if (estimatedDuration != null) {
if (System.getProperty("DEBUG") != null) {
System.out.println(" estimatedLOE: " + estimatedDuration.toString());
}
assignment.setEstimatedLoe(estimatedDuration.toString());
}
Date startDate = task.getActualStart();
if (startDate != null) {
assignment.setStartDate(new Timestamp(startDate.getTime()));
}
Date completeDate = task.getActualFinish();
if (completeDate != null) {
assignment.setCompleteDate(new Timestamp(completeDate.getTime()));
}
Duration actualDuration = task.getActualDuration();
if (actualDuration != null) {
if (System.getProperty("DEBUG") != null) {
System.out.println(" actualLOE: " + actualDuration.toString());
}
assignment.setActualLoe(actualDuration.toString());
}
assignment.setAdditionalNote(task.getNotes());
// Display who is responsible (or add as users)
StringBuffer assigned = new StringBuffer();
for (ResourceAssignment resourceAssigned : task.getResourceAssignments()) {
Resource resource = resourceAssigned.getResource();
if (!resource.getNull()) {
if (System.getProperty("DEBUG") != null) {
System.out.println(" resource");
System.out.println(" id: " + resource.getUniqueID());
System.out.println(" name: " + resource.getName());
System.out.println(" email: " + resource.getEmailAddress());
}
boolean match = false;
// TODO: lookup and associate if a user of the system
String resourceEmail = resource.getEmailAddress();
if (resourceEmail != null) {
int userId = User.getIdByEmailAddress(db, resourceEmail);
if (userId > -1) {
assignment.addUser(userId);
match = true;
}
}
if (!match) {
String resourceName = resource.getName();
if (resourceName != null) {
if (assigned.length() > 0) {
assigned.append(System.getProperty("line.separator"));
}
assigned.append(resourceName);
}
}
}
}
if (assigned.length() > 0) {
assignment.setResponsible(assigned.toString());
}
return assignment;
}
private static AssignmentFolder populateAssignmentFolder(Task task, Requirement requirement, int indent, int folderId) {
AssignmentFolder folder = new AssignmentFolder();
folder.setProjectId(requirement.getProjectId());
folder.setRequirementId(requirement.getId());
folder.setParentId(folderId);
folder.setIndent(indent);
folder.setEnteredBy(requirement.getModifiedBy());
folder.setModifiedBy(requirement.getModifiedBy());
folder.setName(task.getName());
folder.setDescription(task.getNotes());
if (task.getResourceAssignments().size() > 0) {
System.out.println("THIS IS A TASK -- NOT A FOLDER");
}
return folder;
}
/**
* This method lists all resources defined.
*
* @param file MPX file
*/
private static void listResources(ProjectFile file) {
for (Resource resource : file.getAllResources()) {
System.out.println("Resource: " + resource.getName() + " (Unique ID=" + resource.getUniqueID() + ")");
}
System.out.println();
}
/**
* This method lists all resource assignments defined in the file.
*
* @param file MPX file
*/
private static void listAssignments(ProjectFile file) {
List allAssignments = file.getAllResourceAssignments();
Iterator iter = allAssignments.iterator();
ResourceAssignment assignment;
Task task;
Resource resource;
String taskName;
String resourceName;
while (iter.hasNext()) {
assignment = (ResourceAssignment) iter.next();
task = assignment.getTask();
if (task == null) {
taskName = "(null task)";
} else {
taskName = task.getName();
}
resource = assignment.getResource();
if (resource == null) {
resourceName = "(null resource)";
} else {
resourceName = resource.getName();
}
System.out.println("Assignment: Task=" + taskName + " Resource=" + resourceName);
}
System.out.println();
}
/**
* This method displays the resource assignemnts for each task. This time
* rather than just iterating through the list of all assignments in
* the file, we extract the assignemnts on a task-by-task basis.
*
* @param file MPX file
*/
private static void listAssignmentsByTask(ProjectFile file) {
List tasks = file.getAllTasks();
Iterator taskIter = tasks.iterator();
Task task;
List assignments;
Iterator assignmentIter;
ResourceAssignment assignment;
Resource resource;
String resourceName;
while (taskIter.hasNext()) {
task = (Task) taskIter.next();
System.out.println("Assignments for task " + task.getName() + ":");
assignments = task.getResourceAssignments();
assignmentIter = assignments.iterator();
while (assignmentIter.hasNext()) {
assignment = (ResourceAssignment) assignmentIter.next();
resource = assignment.getResource();
if (resource == null) {
resourceName = "(null resource)";
} else {
resourceName = resource.getName();
}
System.out.println(" " + resourceName);
}
}
System.out.println();
}
/**
* This method displays the resource assignemnts for each resource. This time
* rather than just iterating through the list of all assignments in
* the file, we extract the assignemnts on a resource-by-resource basis.
*
* @param file MPX file
*/
private static void listAssignmentsByResource(ProjectFile file) {
List resources = file.getAllResources();
Iterator taskIter = resources.iterator();
Resource resource;
List assignments;
Iterator assignmentIter;
ResourceAssignment assignment;
Task task;
while (taskIter.hasNext()) {
resource = (Resource) taskIter.next();
System.out.println("Assignments for resource " + resource.getName() + ":");
assignments = resource.getTaskAssignments();
assignmentIter = assignments.iterator();
while (assignmentIter.hasNext()) {
assignment = (ResourceAssignment) assignmentIter.next();
task = assignment.getTask();
System.out.println(" " + task.getName());
}
}
System.out.println();
}
/**
* This method lists the predecessors for each task which has
* predecessors.
*
* @param file MPX file
*/
private static void listPredecessors(ProjectFile file) {
List tasks = file.getAllTasks();
Iterator iter = tasks.iterator();
Task task;
List predecessors;
Iterator predecessorIterator;
Relation relation;
while (iter.hasNext()) {
task = (Task) iter.next();
predecessors = task.getPredecessors();
if (predecessors != null && !predecessors.isEmpty()) {
System.out.println(task.getName() + " predecessors:");
predecessorIterator = predecessors.iterator();
while (predecessorIterator.hasNext()) {
relation = (Relation) predecessorIterator.next();
System.out.println(" Task: " + file.getTaskByUniqueID(relation.getTaskUniqueID()).getName());
System.out.println(" Type: " + relation.getType());
System.out.println(" Lag: " + relation.getDuration());
}
}
}
}
/**
* List the slack values for each task.
*
* @param file ProjectFile instance
*/
private static void listSlack(ProjectFile file) {
List tasks = file.getAllTasks();
Iterator iter = tasks.iterator();
Task task;
List predecessors;
Iterator predecessorIterator;
Relation relation;
while (iter.hasNext()) {
task = (Task) iter.next();
System.out.println(task.getName() + " Total Slack=" + task.getTotalSlack() + " Start Slack=" + task.getStartSlack() + " Finish Slack=" + task.getFinishSlack());
}
}
/**
* List details of all calendars in the file.
*
* @param file ProjectFile instance
*/
private static void listCalendars(ProjectFile file) {
Iterator iter = file.getBaseCalendars().iterator();
while (iter.hasNext()) {
System.out.println(iter.next().toString());
}
iter = file.getResourceCalendars().iterator();
while (iter.hasNext()) {
System.out.println(iter.next().toString());
}
}
}