/* * file: AstaReader.java * author: Jon Iles * copyright: (c) Packwood Software 2011 * date: 07/04/2011 */ /* * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by the * Free Software Foundation; either version 2.1 of the License, or (at your * option) any later version. * * This library 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 Lesser General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this library; if not, write to the Free Software Foundation, Inc., * 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. */ package net.sf.mpxj.asta; import java.util.Arrays; import java.util.Calendar; import java.util.Date; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Map.Entry; import net.sf.mpxj.ConstraintType; import net.sf.mpxj.DateRange; import net.sf.mpxj.Day; import net.sf.mpxj.DayType; import net.sf.mpxj.Duration; import net.sf.mpxj.EventManager; import net.sf.mpxj.ProjectCalendar; import net.sf.mpxj.ProjectCalendarHours; import net.sf.mpxj.ProjectCalendarWeek; import net.sf.mpxj.ProjectConfig; import net.sf.mpxj.ProjectFile; import net.sf.mpxj.ProjectProperties; import net.sf.mpxj.RelationType; import net.sf.mpxj.Resource; import net.sf.mpxj.ResourceAssignment; import net.sf.mpxj.ResourceType; import net.sf.mpxj.Task; import net.sf.mpxj.TimeUnit; /** * This class provides a generic front end to read project data from * a database. */ final class AstaReader { /** * Constructor. */ public AstaReader() { m_project = new ProjectFile(); m_eventManager = m_project.getEventManager(); ProjectConfig config = m_project.getProjectConfig(); config.setAutoTaskUniqueID(false); config.setAutoResourceUniqueID(false); config.setAutoCalendarUniqueID(false); config.setAutoWBS(false); } /** * Retrieves the project data read from this file. * * @return project data */ public ProjectFile getProject() { return m_project; } /** * Process project properties. * * @param row project properties data. */ public void processProjectProperties(Row row) { ProjectProperties ph = m_project.getProjectProperties(); ph.setDuration(row.getDuration("DURATIONHOURS")); ph.setStartDate(row.getDate("STARU")); ph.setFinishDate(row.getDate("ENE")); ph.setName(row.getString("SHORT_NAME")); ph.setAuthor(row.getString("PROJECT_BY")); //DURATION_TIME_UNIT ph.setLastSaved(row.getDate("LAST_EDITED_DATE")); } /** * Process resources. * * @param permanentRows permanent resource data * @param consumableRows consumable resource data */ public void processResources(List<Row> permanentRows, List<Row> consumableRows) { // // Process permanent resources // for (Row row : permanentRows) { Resource resource = m_project.addResource(); resource.setType(ResourceType.WORK); resource.setUniqueID(row.getInteger("PERMANENT_RESOURCEID")); resource.setEmailAddress(row.getString("EMAIL_ADDRESS")); // EFFORT_TIME_UNIT resource.setName(row.getString("NASE")); resource.setResourceCalendar(deriveResourceCalendar(row.getInteger("CALENDAV"))); resource.setMaxUnits(Double.valueOf(row.getDouble("AVAILABILITY").doubleValue() * 100)); resource.setIsGeneric(row.getBoolean("CREATED_AS_FOLDER")); resource.setInitials(getInitials(resource.getName())); } // // Process groups // /* for (Row row : permanentRows) { Resource resource = m_project.getResourceByUniqueID(row.getInteger("PERMANENT_RESOURCEID")); Resource group = m_project.getResourceByUniqueID(row.getInteger("ROLE")); if (resource != null && group != null) { resource.setGroup(group.getName()); } } */ // // Process consumable resources // for (Row row : consumableRows) { Resource resource = m_project.addResource(); resource.setType(ResourceType.MATERIAL); resource.setUniqueID(row.getInteger("CONSUMABLE_RESOURCEID")); resource.setCostPerUse(row.getDouble("COST_PER_USEDEFAULTSAMOUNT")); resource.setPeakUnits(Double.valueOf(row.getDouble("AVAILABILITY").doubleValue() * 100)); resource.setName(row.getString("NASE")); resource.setResourceCalendar(deriveResourceCalendar(row.getInteger("CALENDAV"))); resource.setAvailableFrom(row.getDate("AVAILABLE_FROM")); resource.setAvailableTo(row.getDate("AVAILABLE_TO")); resource.setIsGeneric(row.getBoolean("CREATED_AS_FOLDER")); resource.setMaterialLabel(row.getString("MEASUREMENT")); resource.setInitials(getInitials(resource.getName())); } } /** * Derive a calendar for a resource. * * @param parentCalendarID calendar from which resource calendar is derived * @return new calendar for a resource */ private ProjectCalendar deriveResourceCalendar(Integer parentCalendarID) { ProjectCalendar calendar = m_project.addDefaultDerivedCalendar(); calendar.setUniqueID(Integer.valueOf(m_project.getProjectConfig().getNextCalendarUniqueID())); calendar.setParent(m_project.getCalendarByUniqueID(parentCalendarID)); return calendar; } /** * Process tasks. * * @param bars bar data * @param tasks task data * @param milestones milestone data */ public void processTasks(List<Row> bars, List<Row> tasks, List<Row> milestones) { // // Process bars // for (Row row : bars) { Task task = m_project.addTask(); Integer calendarID = row.getInteger("CALENDAU"); ProjectCalendar calendar = m_project.getCalendarByUniqueID(calendarID); //PROJID task.setUniqueID(row.getInteger("BARID")); task.setStart(row.getDate("STARV")); task.setFinish(row.getDate("ENF")); //NATURAL_ORDER //SPARI_INTEGER task.setName(row.getString("NAMH")); //EXPANDED_TASK //PRIORITY //UNSCHEDULABLE //MARK_FOR_HIDING //TASKS_MAY_OVERLAP //SUBPROJECT_ID //ALT_ID //LAST_EDITED_DATE //LAST_EDITED_BY //Proc_Approve //Proc_Design_info //Proc_Proc_Dur //Proc_Procurement //Proc_SC_design //Proc_Select_SC //Proc_Tender //QA Checked //Related_Documents task.setWBS("-"); task.setCalendar(calendar); m_eventManager.fireTaskReadEvent(task); } // // Create hierarchical bar structure // m_project.getChildTasks().clear(); for (Row row : bars) { Task task = m_project.getTaskByUniqueID(row.getInteger("BARID")); //Task parentTask = m_project.getTaskByUniqueID(row.getInteger("SUBPROJECT_ID")); Task parentTask = m_project.getTaskByUniqueID(row.getInteger("BAR")); if (parentTask == null) { m_project.getChildTasks().add(task); } else { m_project.getChildTasks().remove(task); parentTask.getChildTasks().add(task); if (parentTask.getWBS().equals("-")) { String wbs = row.getString("WBN_CODE"); parentTask.setWBS(wbs == null || wbs.length() == 0 ? "-" : wbs); } } } // // Process Tasks // for (Row row : tasks) { Task parentTask = m_project.getTaskByUniqueID(row.getInteger("BAR")); Task task = parentTask == null ? m_project.addTask() : parentTask.addTask(); //"PROJID" task.setUniqueID(row.getInteger("TASKID")); //GIVEN_DURATIONTYPF //GIVEN_DURATIONELA_MONTHS task.setDuration(row.getDuration("GIVEN_DURATIONHOURS")); task.setResume(row.getDate("RESUME")); //task.setStart(row.getDate("GIVEN_START")); //LATEST_PROGRESS_PERIOD //TASK_WORK_RATE_TIME_UNIT //TASK_WORK_RATE //PLACEMENT //BEEN_SPLIT //INTERRUPTIBLE //HOLDING_PIN ///ACTUAL_DURATIONTYPF //ACTUAL_DURATIONELA_MONTHS task.setActualDuration(row.getDuration("ACTUAL_DURATIONHOURS")); task.setEarlyStart(row.getDate("EARLY_START_DATE")); task.setLateStart(row.getDate("LATE_START_DATE")); //FREE_START_DATE //START_CONSTRAINT_DATE //END_CONSTRAINT_DATE task.setBaselineWork(row.getDuration("EFFORT_BUDGET")); //NATURAO_ORDER //LOGICAL_PRECEDENCE //SPAVE_INTEGER //SWIM_LANE //USER_PERCENT_COMPLETE task.setPercentageComplete(row.getDouble("OVERALL_PERCENV_COMPLETE")); //OVERALL_PERCENT_COMPL_WEIGHT task.setName(row.getString("NARE")); task.setWBS(row.getString("WBN_CODE")); //NOTET //UNIQUE_TASK_ID task.setCalendar(m_project.getCalendarByUniqueID(row.getInteger("CALENDAU"))); //EFFORT_TIMI_UNIT //WORL_UNIT //LATEST_ALLOC_PROGRESS_PERIOD //WORN //BAR //CONSTRAINU //PRIORITB //CRITICAM //USE_PARENU_CALENDAR //BUFFER_TASK //MARK_FOS_HIDING //OWNED_BY_TIMESHEEV_X //START_ON_NEX_DAY //LONGEST_PATH //DURATIOTTYPF //DURATIOTELA_MONTHS //DURATIOTHOURS task.setStart(row.getDate("STARZ")); task.setFinish(row.getDate("ENJ")); //DURATION_TIMJ_UNIT //UNSCHEDULABLG //SUBPROJECT_ID //ALT_ID //LAST_EDITED_DATE //LAST_EDITED_BY processConstraints(row, task); if (task.getPercentageComplete().intValue() != 0) { task.setActualStart(task.getStart()); if (task.getPercentageComplete().intValue() == 100) { task.setActualFinish(task.getFinish()); task.setDuration(task.getActualDuration()); } } m_eventManager.fireTaskReadEvent(task); } for (Row row : milestones) { Task parentTask = m_project.getTaskByUniqueID(row.getInteger("BAR")); Task task = parentTask == null ? m_project.addTask() : parentTask.addTask(); task.setMilestone(true); //PROJID task.setUniqueID(row.getInteger("MILESTONEID")); task.setStart(row.getDate("GIVEN_DATE_TIME")); task.setFinish(row.getDate("GIVEN_DATE_TIME")); //PROGREST_PERIOD //SYMBOL_APPEARANCE //MILESTONE_TYPE //PLACEMENU task.setPercentageComplete(row.getBoolean("COMPLETED") ? COMPLETE : INCOMPLETE); //INTERRUPTIBLE_X //ACTUAL_DURATIONTYPF //ACTUAL_DURATIONELA_MONTHS //ACTUAL_DURATIONHOURS task.setEarlyStart(row.getDate("EARLY_START_DATE")); task.setLateStart(row.getDate("LATE_START_DATE")); //FREE_START_DATE //START_CONSTRAINT_DATE //END_CONSTRAINT_DATE //EFFORT_BUDGET //NATURAO_ORDER //LOGICAL_PRECEDENCE //SPAVE_INTEGER //SWIM_LANE //USER_PERCENT_COMPLETE //OVERALL_PERCENV_COMPLETE //OVERALL_PERCENT_COMPL_WEIGHT task.setName(row.getString("NARE")); task.setWBS(row.getString("WBN_CODE")); //NOTET //UNIQUE_TASK_ID task.setCalendar(m_project.getCalendarByUniqueID(row.getInteger("CALENDAU"))); //WBT //EFFORT_TIMI_UNIT //WORL_UNIT //LATEST_ALLOC_PROGRESS_PERIOD //WORN //CONSTRAINU //PRIORITB //CRITICAM //USE_PARENU_CALENDAR //BUFFER_TASK //MARK_FOS_HIDING //OWNED_BY_TIMESHEEV_X //START_ON_NEX_DAY //LONGEST_PATH //DURATIOTTYPF //DURATIOTELA_MONTHS //DURATIOTHOURS //STARZ //ENJ //DURATION_TIMJ_UNIT //UNSCHEDULABLG //SUBPROJECT_ID //ALT_ID //LAST_EDITED_DATE //LAST_EDITED_BY task.setDuration(ZERO_HOURS); } deriveProjectCalendar(); updateStructure(); } /** * Iterates through the tasks setting the correct * outline level and ID values. */ private void updateStructure() { int id = 1; Integer outlineLevel = Integer.valueOf(1); for (Task task : m_project.getChildTasks()) { id = updateStructure(id, task, outlineLevel); } } /** * Iterates through the tasks setting the correct * outline level and ID values. * * @param id current ID value * @param task current task * @param outlineLevel current outline level * @return next ID value */ private int updateStructure(int id, Task task, Integer outlineLevel) { task.setID(Integer.valueOf(id++)); task.setOutlineLevel(outlineLevel); outlineLevel = Integer.valueOf(outlineLevel.intValue() + 1); for (Task childTask : task.getChildTasks()) { id = updateStructure(id, childTask, outlineLevel); } return id; } /** * Processes predecessor data. * * @param rows predecessor data */ public void processPredecessors(List<Row> rows) { for (Row row : rows) { Task startTask = m_project.getTaskByUniqueID(row.getInteger("START_TASK")); Task endTask = m_project.getTaskByUniqueID(row.getInteger("END_TASK")); if (startTask != null && endTask != null) { RelationType type = getRelationType(row.getInt("TYPI")); Duration startLag = row.getDuration("START_LAG_TIMEHOURS"); Duration endLag = row.getDuration("END_LAG_TIMEHOURS"); Duration lag = null; if (startLag.getDuration() != 0) { lag = startLag; } else { if (endLag.getDuration() != 0) { lag = endLag; } } endTask.addPredecessor(startTask, type, lag); } //PROJID //LINKID //START_LAG_TIMETYPF //START_LAG_TIMEELA_MONTHS //START_LAG_TIMEHOURS //END_LAG_TIMETYPF //END_LAG_TIMEELA_MONTHS //END_LAG_TIMEHOURS //MAXIMUM_LAGTYPF //MAXIMUM_LAGELA_MONTHS //MAXIMUM_LAGHOURS //STARV_DATE //ENF_DATE //CURVATURE_PERCENTAGE //START_LAG_PERCENT_FLOAT //END_LAG_PERCENT_FLOAT //COMMENTS //LINK_CATEGORY //START_LAG_TIME_UNIT //END_LAG_TIME_UNIT //MAXIMUM_LAG_TIME_UNIT //START_TASK //END_TASK //TYPI //START_LAG_TYPE //END_LAG_TYPE //MAINTAIN_TASK_OFFSETS //UNSCHEDULABLF //CRITICAL //ON_LOOP //MAXIMUM_LAG_MODE //ANNOTATE_LEAD_LAG //START_REPOSITION_ON_TAS_MOVE //END_REPOSITION_ON_TASK_MOVE //DRAW_CURVED_IF_VERTICAL //AUTOMATIC_CURVED_LI_SETTINGS //DRAW_CURVED_LINK_TO_LEFT //LOCAL_LINK //DRIVING //ALT_ID //LAST_EDITED_DATE //LAST_EDITED_BY } } /** * Process assignment data. * * @param permanentAssignments assignment data */ public void processAssignments(List<Row> permanentAssignments) { for (Row row : permanentAssignments) { Task task = m_project.getTaskByUniqueID(row.getInteger("ALLOCATEE_TO")); Resource resource = m_project.getResourceByUniqueID(row.getInteger("PLAYER")); if (task != null && resource != null) { double percentComplete = row.getDouble("PERCENT_COMPLETE").doubleValue(); Duration work = row.getWork("EFFORW"); double actualWork = work.getDuration() * percentComplete; double remainingWork = work.getDuration() - actualWork; ResourceAssignment assignment = task.addResourceAssignment(resource); assignment.setUniqueID(row.getInteger("PERMANENT_SCHEDUL_ALLOCATIONID")); assignment.setStart(row.getDate("STARZ")); assignment.setFinish(row.getDate("ENJ")); assignment.setUnits(Double.valueOf(row.getDouble("GIVEN_ALLOCATION").doubleValue() * 100)); assignment.setDelay(row.getDuration("DELAAHOURS")); assignment.setPercentageWorkComplete(Double.valueOf(percentComplete * 100)); assignment.setWork(work); assignment.setActualWork(Duration.getInstance(actualWork, work.getUnits())); assignment.setRemainingWork(Duration.getInstance(remainingWork, work.getUnits())); } //PROJID //REQUIREE_BY //OWNED_BY_TIMESHEET_X //EFFORW //GIVEN_EFFORT //WORK_FROM_TASK_FACTOR //ALLOCATIOO //GIVEN_ALLOCATION //ALLOCATIOP_OF //WORM_UNIT //WORK_RATE_TIMF_UNIT //EFFORT_TIMJ_UNIT //WORO //GIVEN_WORK //WORL_RATE //GIVEN_WORK_RATE //TYPV //CALCULATEG_PARAMETER //BALANCINJ_PARAMETER //SHAREE_EFFORT //CONTRIBUTES_TO_ACTIVI_EFFORT //DELAATYPF //DELAAELA_MONTHS //DELAAHOURS //GIVEO_DURATIONTYPF //GIVEO_DURATIONELA_MONTHS //GIVEO_DURATIONHOURS //DELAY_TIMI_UNIT //RATE_TYPE //USE_TASM_CALENDAR //IGNORF //ELAPSEE //MAY_BE_SHORTER_THAN_TASK //RESUMF //SPAXE_INTEGER //USER_PERCENU_COMPLETE //ALLOCATIOR_GROUP //PRIORITC //ACCOUNTED_FOR_ELSEWHERE //DURATIOTTYPF //DURATIOTELA_MONTHS //DURATIOTHOURS //DURATION_TIMJ_UNIT //UNSCHEDULABLG //SUBPROJECT_ID //permanent_schedul_allocation_ALT_ID //permanent_schedul_allocation_LAST_EDITED_DATE //permanent_schedul_allocation_LAST_EDITED_BY //perm_resource_skill_PROJID //PERM_RESOURCE_SKILLID //ARR_STOUT_STSKI_APARROW_TYPE //ARR_STOUT_STSKI_APLENGTH //ARR_STOUT_STSKI_APEDGE //ARR_STOUT_STSKI_APBORDET_COL //ARR_STOUT_STSKI_APINSIDG_COL //ARR_STOUT_STSKI_APPLACEMENW //BLI_STOUT_STSKI_APBLIP_TYPE //BLI_STOUT_STSKI_APSCALEY //BLI_STOUT_STSKI_APSCALEZ //BLI_STOUT_STSKI_APGAP //BLI_STOUT_STSKI_APBORDES_COL //BLI_STOUT_STSKI_APINSIDF_COL //BLI_STOUT_STSKI_APPLACEMENV //LIN_STOUT_STSKI_APSCALEX //LIN_STOUT_STSKI_APWIDTH //LIN_STOUT_STSKI_APBORDER_COL //LIN_STOUT_STSKI_APINSIDE_COL //LIN_STOUT_STSKI_APLINE_TYPE //SKI_APFOREGROUND_FILL_COLOUR //SKI_APBACKGROUND_FILL_COLOUR //SKI_APPATTERN //DURATIOODEFAULTTTYPF //DURATIOODEFAULTTELA_MONTHS //DURATIOODEFAULTTHOURS //DELAYDEFAULTTTYPF //DELAYDEFAULTTELA_MONTHS //DELAYDEFAULTTHOURS //DEFAULTTALLOCATION //DEFAULTTWORK_FROM_ACT_FACTOR //DEFAULTTEFFORT //DEFAULTTWORL //DEFAULTTWORK_RATE //DEFAULTTWORK_UNIT //DEFAULTTWORK_RATE_TIME_UNIT //DEFAULTTEFFORT_TIMG_UNIT //DEFAULTTDURATION_TIMF_UNIT //DEFAULTTDELAY_TIME_UNIT //DEFAULTTTYPL //DEFAULTTCALCULATED_PARAMETER //DEFAULTTBALANCING_PARAMETER //DEFAULTTWORK_RATE_TYPE //DEFAULTTUSE_TASK_CALENDAR //DEFAULTTALLOC_PROPORTIONALLY //DEFAULTTCAN_BE_SPLIT //DEFAULTTCAN_BE_DELAYED //DEFAULTTCAN_BE_STRETCHED //DEFAULTTACCOUNTED__ELSEWHERE //DEFAULTTCONTRIBUTES_T_EFFORT //DEFAULTTMAY_BE_SHORTER__TASK //DEFAULTTSHARED_EFFORT //ABILITY //EFFECTIVENESS //AVAILABLF_FROM //AVAILABLF_TO //SPARO_INTEGER //EFFORT_TIMF_UNIT //ROLE //CREATED_AS_FOLDER //perm_resource_skill_ALT_ID //perm_resource_skill_LAST_EDITED_DATE //perm_resource_skill_LAST_EDITED_BY } } /** * Convert an integer into a RelationType instance. * * @param index integer value * @return RelationType instance */ private RelationType getRelationType(int index) { if (index < 0 || index > RELATION_TYPES.length) { index = 0; } return RELATION_TYPES[index]; } /** * Convert a name into initials. * * @param name source name * @return initials */ private String getInitials(String name) { String result = null; if (name != null && name.length() != 0) { StringBuilder sb = new StringBuilder(); sb.append(name.charAt(0)); int index = 1; while (true) { index = name.indexOf(' ', index); if (index == -1) { break; } ++index; if (index < name.length() && name.charAt(index) != ' ') { sb.append(name.charAt(index)); } ++index; } result = sb.toString(); } return result; } /** * Asta Powerproject assigns an explicit calendar for each task. This method * is used to find the most common calendar and use this as the default project * calendar. This allows the explicitly assigned task calendars to be removed. */ private void deriveProjectCalendar() { // // Count the number of times each calendar is used // Map<ProjectCalendar, Integer> map = new HashMap<ProjectCalendar, Integer>(); for (Task task : m_project.getAllTasks()) { ProjectCalendar calendar = task.getCalendar(); Integer count = map.get(calendar); if (count == null) { count = Integer.valueOf(1); } else { count = Integer.valueOf(count.intValue() + 1); } map.put(calendar, count); } // // Find the most frequently used calendar // int maxCount = 0; ProjectCalendar defaultCalendar = null; for (Entry<ProjectCalendar, Integer> entry : map.entrySet()) { if (entry.getValue().intValue() > maxCount) { maxCount = entry.getValue().intValue(); defaultCalendar = entry.getKey(); } } // // Set the default calendar for the project // and remove it's use as a task-specific calendar. // if (defaultCalendar != null) { m_project.setDefaultCalendar(defaultCalendar); for (Task task : m_project.getAllTasks()) { if (task.getCalendar() == defaultCalendar) { task.setCalendar(null); } } } } /** * Determines the constraints relating to a task. * * @param row row data * @param task Task instance */ private void processConstraints(Row row, Task task) { ConstraintType constraintType = ConstraintType.AS_SOON_AS_POSSIBLE; Date constraintDate = null; switch (row.getInt("CONSTRAINU")) { case 0: { if (row.getInt("PLACEMENT") == 0) { constraintType = ConstraintType.AS_SOON_AS_POSSIBLE; } else { constraintType = ConstraintType.AS_LATE_AS_POSSIBLE; } break; } case 1: { constraintType = ConstraintType.MUST_START_ON; constraintDate = row.getDate("START_CONSTRAINT_DATE"); break; } case 2: { constraintType = ConstraintType.START_NO_LATER_THAN; constraintDate = row.getDate("START_CONSTRAINT_DATE"); break; } case 3: { constraintType = ConstraintType.START_NO_EARLIER_THAN; constraintDate = row.getDate("START_CONSTRAINT_DATE"); break; } case 4: { constraintType = ConstraintType.MUST_FINISH_ON; constraintDate = row.getDate("END_CONSTRAINT_DATE"); break; } case 5: { constraintType = ConstraintType.FINISH_NO_LATER_THAN; constraintDate = row.getDate("END_CONSTRAINT_DATE"); break; } case 6: { constraintType = ConstraintType.FINISH_NO_EARLIER_THAN; constraintDate = row.getDate("END_CONSTRAINT_DATE"); break; } case 8: { task.setDeadline(row.getDate("END_CONSTRAINT_DATE")); break; } } task.setConstraintType(constraintType); task.setConstraintDate(constraintDate); } /** * Creates a mapping between exception ID values and working/non-working days. * * @param rows rows from the exceptions table * @return exception map */ public Map<Integer, DayType> createExceptionTypeMap(List<Row> rows) { Map<Integer, DayType> map = new HashMap<Integer, DayType>(); for (Row row : rows) { Integer id = row.getInteger("EXCEPTIONNID"); DayType result; switch (row.getInt("UNIQUE_BIT_FIELD")) { case 8: // Working case 32: // Overtime case 128: //Weekend Working { result = DayType.WORKING; break; } case 4: // Non Working case 16: // Holiday case 64: // Weather case -2147483648: // Weekend default: { result = DayType.NON_WORKING; break; } } map.put(id, result); } return map; } /** * Creates a map of work pattern rows indexed by the primary key. * * @param rows work pattern rows * @return work pattern map */ public Map<Integer, Row> createWorkPatternMap(List<Row> rows) { Map<Integer, Row> map = new HashMap<Integer, Row>(); for (Row row : rows) { map.put(row.getInteger("WORK_PATTERNID"), row); } return map; } /** * Creates a map between a calendar ID and a list of * work pattern assignment rows. * * @param rows work pattern assignment rows * @return work pattern assignment map */ public Map<Integer, List<Row>> createWorkPatternAssignmentMap(List<Row> rows) { Map<Integer, List<Row>> map = new HashMap<Integer, List<Row>>(); for (Row row : rows) { Integer calendarID = row.getInteger("WORK_PATTERN_ASSIGNMENTID"); List<Row> list = map.get(calendarID); if (list == null) { list = new LinkedList<Row>(); map.put(calendarID, list); } list.add(row); } return map; } /** * Creates a map between a calendar ID and a list of exception assignment rows. * * @param rows exception assignment rows * @return exception assignment map */ public Map<Integer, List<Row>> createExceptionAssignmentMap(List<Row> rows) { Map<Integer, List<Row>> map = new HashMap<Integer, List<Row>>(); for (Row row : rows) { Integer calendarID = row.getInteger("EXCEPTION_ASSIGNMENTID"); List<Row> list = map.get(calendarID); if (list == null) { list = new LinkedList<Row>(); map.put(calendarID, list); } list.add(row); } return map; } /** * Creates a map between a calendar ID and a list of time entry rows. * * @param rows time entry rows * @return time entry map */ public Map<Integer, List<Row>> createTimeEntryMap(List<Row> rows) { Map<Integer, List<Row>> map = new HashMap<Integer, List<Row>>(); for (Row row : rows) { Integer calendarID = row.getInteger("TIME_ENTRYID"); List<Row> list = map.get(calendarID); if (list == null) { list = new LinkedList<Row>(); map.put(calendarID, list); } list.add(row); } return map; } /** * Creates a ProjectCalendar instance from the Asta data. * * @param calendarRow basic calendar data * @param workPatternMap work pattern map * @param workPatternAssignmentMap work pattern assignment map * @param exceptionAssignmentMap exception assignment map * @param timeEntryMap time entry map * @param exceptionTypeMap exception type map */ public void processCalendar(Row calendarRow, Map<Integer, Row> workPatternMap, Map<Integer, List<Row>> workPatternAssignmentMap, Map<Integer, List<Row>> exceptionAssignmentMap, Map<Integer, List<Row>> timeEntryMap, Map<Integer, DayType> exceptionTypeMap) { // // Create the calendar and add the default working hours // ProjectCalendar calendar = m_project.addCalendar(); Integer dominantWorkPatternID = calendarRow.getInteger("DOMINANT_WORK_PATTERN"); calendar.setUniqueID(calendarRow.getInteger("CALENDARID")); processWorkPattern(calendar, dominantWorkPatternID, workPatternMap, timeEntryMap, exceptionTypeMap); calendar.setName(calendarRow.getString("NAMK")); // // Add any additional working weeks // List<Row> rows = workPatternAssignmentMap.get(calendar.getUniqueID()); if (rows != null) { for (Row row : rows) { Integer workPatternID = row.getInteger("WORK_PATTERN"); if (!workPatternID.equals(dominantWorkPatternID)) { ProjectCalendarWeek week = calendar.addWorkWeek(); week.setDateRange(new DateRange(row.getDate("START_DATE"), row.getDate("END_DATE"))); processWorkPattern(week, row.getInteger("WORK_PATTERN"), workPatternMap, timeEntryMap, exceptionTypeMap); } } } // // Add exceptions - not sure how exceptions which turn non-working days into working days are handled by Asta - if at all? // rows = exceptionAssignmentMap.get(calendar.getUniqueID()); if (rows != null) { for (Row row : rows) { Date startDate = row.getDate("STARU_DATE"); Date endDate = row.getDate("ENE_DATE"); calendar.addCalendarException(startDate, endDate); } } m_eventManager.fireCalendarReadEvent(calendar); } /** * Populates a ProjectCalendarWeek instance from Asta work pattern data. * * @param week target ProjectCalendarWeek instance * @param workPatternID target work pattern ID * @param workPatternMap work pattern data * @param timeEntryMap time entry map * @param exceptionTypeMap exception type map */ private void processWorkPattern(ProjectCalendarWeek week, Integer workPatternID, Map<Integer, Row> workPatternMap, Map<Integer, List<Row>> timeEntryMap, Map<Integer, DayType> exceptionTypeMap) { week.setName(workPatternMap.get(workPatternID).getString("NAMN")); List<Row> timeEntryRows = timeEntryMap.get(workPatternID); long lastEndTime = Long.MIN_VALUE; Day currentDay = Day.SUNDAY; ProjectCalendarHours hours = week.addCalendarHours(currentDay); Arrays.fill(week.getDays(), DayType.NON_WORKING); for (Row row : timeEntryRows) { Date startTime = row.getDate("START_TIME"); Date endTime = row.getDate("END_TIME"); if (startTime.getTime() > endTime.getTime()) { Calendar cal = Calendar.getInstance(); cal.setTime(endTime); cal.add(Calendar.DAY_OF_YEAR, 1); endTime = cal.getTime(); } if (startTime.getTime() < lastEndTime) { currentDay = currentDay.getNextDay(); hours = week.addCalendarHours(currentDay); } DayType type = exceptionTypeMap.get(row.getInteger("EXCEPTIOP")); if (type == DayType.WORKING) { hours.addRange(new DateRange(startTime, endTime)); week.setWorkingDay(currentDay, DayType.WORKING); } lastEndTime = endTime.getTime(); } } private ProjectFile m_project; private EventManager m_eventManager; private static final Double COMPLETE = Double.valueOf(100); private static final Double INCOMPLETE = Double.valueOf(0); private static final Duration ZERO_HOURS = Duration.getInstance(0, TimeUnit.HOURS); private static final RelationType[] RELATION_TYPES = { RelationType.FINISH_START, RelationType.START_START, RelationType.FINISH_FINISH, RelationType.START_FINISH }; }