Skip to content

Instantly share code, notes, and snippets.

@daniel-sc
Created November 30, 2015 15:44
Show Gist options
  • Save daniel-sc/bf900ed2964421f63c76 to your computer and use it in GitHub Desktop.
Save daniel-sc/bf900ed2964421f63c76 to your computer and use it in GitHub Desktop.
Analyze MS-Project files - calculate delay from original plan
import net.sf.mpxj.MPXJException;
import net.sf.mpxj.ProjectFile;
import net.sf.mpxj.Task;
import net.sf.mpxj.mpp.MPPReader;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.*;
import java.util.logging.*;
public class Main {
private static final Logger LOG = Logger.getLogger(Main.class.getName());
private static final long MS_TO_DAYS = 1000 * 60 * 60 * 24;
public static void main(String[] args) throws MPXJException, IOException {
Map<String, List<Task>> taskNameToTasks = new HashMap<>();
MPPReader reader = new MPPReader();
Files.find(Paths.get("."), 1, (f, a) -> f.toString().endsWith(".mpp"))
.forEach(f -> {
try {
LOG.info("Reading " + f);
ProjectFile projectFile = reader.read(f.toFile());
projectFile.getAllTasks().stream().forEach(t -> collectTask(t, taskNameToTasks));
} catch (MPXJException e) {
throw new RuntimeException(e);
}
});
Map<String, Long> taskNameToDelay = new HashMap<>();
taskNameToTasks.forEach((name, tasks) -> taskNameToDelay.put(name, computeMaxDistance(tasks)));
LOG.info("Tasks with no matching: " + taskNameToTasks.values().stream().filter(l -> l.size() == 1).count());
LOG.info("Tasks with matching: " + taskNameToTasks.values().stream().filter(l -> l.size() > 1).count());
LOG.info("Moving tasks: " + taskNameToDelay.values().stream().filter(d -> d > 0).count());
Long maxDelayDays = taskNameToDelay.values().stream().sorted().reduce(0L, Math::max);
LOG.info("Maximum delay (days): " + maxDelayDays);
String maxDelayTaskName = taskNameToDelay.keySet().stream().filter(name -> maxDelayDays.equals(taskNameToDelay.get(name))).findAny().get();
LOG.info("Task with maximum delay: " + maxDelayTaskName);
Task maxDelayTask = taskNameToTasks.get(maxDelayTaskName).get(0);
List<Task> parentTasks = getParentTasks(maxDelayTask);
LOG.info("Task in hierarchy:\n" + parentTasks);
LOG.info("Average delay: " + taskNameToDelay.values().stream().reduce(0L, (a, b) -> a + b) / taskNameToDelay.size());
}
/**
* @return list of tasks leading to given task. Top level first.
*/
private static List<Task> getParentTasks(Task task) {
List<Task> result = new ArrayList<>();
while (task != null) {
result.add(0, task);
task = task.getParentTask();
}
return result;
}
private static long computeMaxDistance(List<Task> tasks) {
long max = 0;
for (Task task1 : tasks) {
for (Task task2 : tasks) {
Date finish1 = task1.getFinish();
Date finish2 = task2.getFinish();
max = Math.max(daysDifference(finish1, finish2), max);
}
}
return max;
}
private static long daysDifference(Date finish1, Date finish2) {
return Math.abs((finish1.getTime() - finish2.getTime()) / MS_TO_DAYS);
}
private static void collectTask(Task t, Map<String, List<Task>> taskNameToTasks) {
// use uniqueId, as tasks with the same name might be used in several places
String id = t.getUniqueID() + t.getName().trim();
if (!taskNameToTasks.containsKey(id)) {
taskNameToTasks.put(id, new ArrayList<>());
}
taskNameToTasks.get(id).add(t);
}
}
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.analyse_msproject</groupId>
<artifactId>analyse_msproject</artifactId>
<version>1.0-SNAPSHOT</version>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>net.sf.mpxj</groupId>
<artifactId>mpxj</artifactId>
<version>5.1.13</version>
</dependency>
</dependencies>
</project>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment