package com.metservice.kanban.model; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; import com.metservice.kanban.KanbanPropertiesFile; //TODO This class needs unit tests. //TODO perhaps rename to factory and replace build methods with create methods /** * * WIP Limit by Nicholas Malcolm and Chris Cooper */ public class KanbanProjectConfigurationBuilder { private final File projectHome; private final KanbanPropertiesFile properties; public KanbanProjectConfigurationBuilder(File kanbanHome, String projectName) throws IOException { projectHome = new File(kanbanHome, projectName); properties = new KanbanPropertiesFile(new File(projectHome, "kanban.properties")); } public KanbanProjectConfiguration buildConfiguration() throws IOException { TreeNode<WorkItemType> rootWorkItemType = getRootWorkItemType(); WorkItemTypeCollection workItemTypes = new WorkItemTypeCollection(rootWorkItemType); KanbanBoardConfiguration boardDefinitions = getBoardDefinitions(workItemTypes); return new KanbanProjectConfiguration(projectHome, boardDefinitions, rootWorkItemType, workItemTypes); } private KanbanBoardConfiguration getBoardDefinitions(WorkItemTypeCollection workItemTypes) throws IOException { Map<String, WorkItemType> workItemTypesByPhase = new HashMap<String, WorkItemType>(); Map<String, Integer> wipLimitsByPhase = new HashMap<String, Integer>(); for (WorkItemType type : workItemTypes) { String[] phases = properties.getPhases(type.getName()); String[] columnLimits = properties.getPhaseWIPLimit(type.getName()); int wipLimit; for (int i = 0; i < phases.length; i++) { try { if (columnLimits != null) { wipLimit = Integer.parseInt(columnLimits[i]); } else { wipLimit = -1; } } catch (Exception e) { // No limit was specified, or it was "" wipLimit = -1; } wipLimitsByPhase.put(phases[i], wipLimit); workItemTypesByPhase.put(phases[i], type); } } KanbanBoardConfiguration phaseSequences = new KanbanBoardConfiguration(); for (BoardIdentifier board : BoardIdentifier.values()) { List<KanbanBoardColumn> columns = new ArrayList<KanbanBoardColumn>(); String[] boardPhases = properties.getPhaseSequence(board); String phase = ""; for (int i = 0; i < boardPhases.length; i++) { phase = boardPhases[i]; columns.add(new KanbanBoardColumn(workItemTypesByPhase.get(phase), phase, wipLimitsByPhase.get(phase))); } phaseSequences.add(board, new KanbanBoardColumnList(columns)); } return phaseSequences; } public TreeNode<WorkItemType> getRootWorkItemType() throws IOException { // There should only be one root work item type (something like product, epic, MMF, etc.) The configuration // file format does not enforce this so we initially assume there are multiple roots and throw exceptions if // we find none or more than one. List<TreeNode<WorkItemType>> roots = getChildWorkItemTypeTreeNodes("root"); if (roots.isEmpty()) { throw new IOException("no root work item type"); } else if (roots.size() > 1) { throw new IOException("multiple root work item types: " + roots); } return roots.get(0); } private List<TreeNode<WorkItemType>> getChildWorkItemTypeTreeNodes(String name) throws IOException { List<TreeNode<WorkItemType>> children = new ArrayList<TreeNode<WorkItemType>>(); //get all the work item types i.e feature,story for (String possibleChildName : properties.getWorkItemTypes()) { if (properties.isChildWorkItemType(name, possibleChildName)) { children.add(createWorkItemTypeTreeNode(possibleChildName)); } } return children; } private TreeNode<WorkItemType> createWorkItemTypeTreeNode(String name) throws IOException { WorkItemType workItemType = new WorkItemType(properties.getPhases(name)); workItemType.setName(name); workItemType.setCardColour(properties.getWorkItemTypeCardColour(name)); workItemType.setBackgroundColour(properties.getWorkItemTypeBackgroundColour(name)); List<TreeNode<WorkItemType>> children = getChildWorkItemTypeTreeNodes(name); return TreeNode.create(WorkItemType.class, workItemType, children); } public Iterable<String> getPhases(Iterable<WorkItemType> workItemTypes) throws IOException { Collection<String> phases = new ArrayList<String>(); for (WorkItemType workItemType : workItemTypes) { for (String phase : properties.getPhases(workItemType.getName())) { phases.add(phase); } } return phases; } }