Created
November 30, 2015 15:44
-
-
Save daniel-sc/bf900ed2964421f63c76 to your computer and use it in GitHub Desktop.
Analyze MS-Project files - calculate delay from original plan
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?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