Java tutorial
/* * UniTime 3.2 - 3.5 (University Timetabling Application) * Copyright (C) 2008 - 2013, UniTime LLC, and individual contributors * as indicated by the @authors tag. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program. If not, see <http://www.gnu.org/licenses/>. * */ package org.unitime.timetable.action; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.Map; import java.util.Set; import java.util.TreeSet; import java.util.Vector; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.struts.action.Action; import org.apache.struts.action.ActionForm; import org.apache.struts.action.ActionForward; import org.apache.struts.action.ActionMapping; import org.apache.struts.action.ActionMessage; import org.apache.struts.action.ActionMessages; import org.apache.struts.action.ActionRedirect; import org.apache.struts.util.MessageResources; import org.hibernate.Transaction; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.unitime.commons.Debug; import org.unitime.localization.impl.Localization; import org.unitime.localization.messages.CourseMessages; import org.unitime.timetable.defaults.ApplicationProperty; import org.unitime.timetable.form.InstructionalOfferingConfigEditForm; import org.unitime.timetable.interfaces.ExternalInstrOffrConfigChangeAction; import org.unitime.timetable.interfaces.ExternalLinkLookup; import org.unitime.timetable.model.BuildingPref; import org.unitime.timetable.model.ChangeLog; import org.unitime.timetable.model.Class_; import org.unitime.timetable.model.CourseOffering; import org.unitime.timetable.model.Department; import org.unitime.timetable.model.Event; import org.unitime.timetable.model.Exam; import org.unitime.timetable.model.InstrOfferingConfig; import org.unitime.timetable.model.InstructionalOffering; import org.unitime.timetable.model.ItypeDesc; import org.unitime.timetable.model.Preference; import org.unitime.timetable.model.PreferenceLevel; import org.unitime.timetable.model.RoomFeaturePref; import org.unitime.timetable.model.RoomGroup; import org.unitime.timetable.model.RoomGroupPref; import org.unitime.timetable.model.RoomPref; import org.unitime.timetable.model.SchedulingSubpart; import org.unitime.timetable.model.SimpleItypeConfig; import org.unitime.timetable.model.TimePattern; import org.unitime.timetable.model.TimePref; import org.unitime.timetable.model.comparators.ClassComparator; import org.unitime.timetable.model.comparators.SicComparator; import org.unitime.timetable.model.dao.CourseOfferingDAO; import org.unitime.timetable.model.dao.DepartmentDAO; import org.unitime.timetable.model.dao.InstrOfferingConfigDAO; import org.unitime.timetable.model.dao.InstructionalOfferingDAO; import org.unitime.timetable.model.dao.ItypeDescDAO; import org.unitime.timetable.security.SessionContext; import org.unitime.timetable.security.rights.Right; import org.unitime.timetable.util.Constants; import org.unitime.timetable.util.LookupTables; import org.unitime.timetable.webutil.SchedulingSubpartTableBuilder; /** * MyEclipse Struts * Creation date: 05-19-2005 * * XDoclet definition: * @struts:action path="/instructionalOfferingConfigEdit" name="InstructionalOfferingConfigEditForm" input="/instructionalOfferingConfigEdit.jsp" scope="request" * * @author Tomas Muller, Stephanie Schluttenhofer, Zuzana Mullerova */ @Service("/instructionalOfferingConfigEdit") public class InstructionalOfferingConfigEditAction extends Action { protected final static CourseMessages MSG = Localization.create(CourseMessages.class); @Autowired SessionContext sessionContext; // --------------------------------------------------------- Instance Variables // --------------------------------------------------------- Methods /** * Method execute * @param mapping * @param form * @param request * @param response * @return ActionForward */ public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { MessageResources rsc = getResources(request); InstructionalOfferingConfigEditForm frm = (InstructionalOfferingConfigEditForm) form; if (frm.getConfigId() == null || frm.getConfigId() == 0) sessionContext.checkPermission(frm.getInstrOfferingId(), "InstructionalOffering", Right.InstrOfferingConfigAdd); if (frm.getConfigId() != null && frm.getConfigId() != 0) sessionContext.checkPermission(frm.getConfigId(), "InstrOfferingConfig", Right.InstrOfferingConfigEdit); String html = ""; String op = (request.getParameter("op") == null) ? (frm.getOp() == null || frm.getOp().length() == 0) ? (request.getAttribute("op") == null) ? null : request.getAttribute("op").toString() : frm.getOp() : request.getParameter("op"); if (op == null) op = request.getParameter("hdnOp"); if (op == null || op.trim().length() == 0) throw new Exception(MSG.errorOperationNotInterpreted() + op); // Set up itypes and subparts frm.setOp(op); LookupTables.setupItypes(request, true); LookupTables.setupExternalDepts(request, sessionContext.getUser().getCurrentAcademicSessionId()); TreeSet ts = new TreeSet(); for (Iterator it = ((TreeSet) request.getAttribute(Department.EXTERNAL_DEPT_ATTR_NAME)).iterator(); it .hasNext();) { Department d = (Department) it.next(); if (sessionContext.hasPermission(d, Right.InstrOfferingConfigEditDepartment)) ts.add(d); } request.setAttribute((Department.EXTERNAL_DEPT_ATTR_NAME), ts); request.setAttribute(SimpleItypeConfig.CONFIGS_ATTR_NAME, html); // Clear previous error markers search("-1111", new Vector(), true); // First access to screen if (op.equalsIgnoreCase(rsc.getMessage("op.edit")) // || op.equalsIgnoreCase(rsc.getMessage("button.duplicateConfig")) --- probably never used || op.equalsIgnoreCase(MSG.actionEditConfiguration())) { Long configId = null; try { configId = new Long(request.getParameter("configId")); } catch (Exception e) { throw new Exception(MSG.errorConfigIDNotValid() + request.getParameter("configId")); } sessionContext.checkPermission(configId, "InstrOfferingConfig", Right.InstrOfferingConfigEdit); loadDetailFromConfig(frm, configId, false); // load existing config from database Vector sp = loadOriginalConfig(frm.getConfigId(), frm); boolean createAsNew = false; // if(op.equalsIgnoreCase(rsc.getMessage("button.duplicateConfig"))) // createAsNew = true; if (sp != null && sp.size() > 0) { sessionContext.setAttribute(SimpleItypeConfig.CONFIGS_ATTR_NAME, sp); html = SchedulingSubpartTableBuilder.buildSubpartsTable(request, sessionContext, frm.getLimit(), configId.toString(), createAsNew, frm.getUnlimited().booleanValue()); request.setAttribute(SimpleItypeConfig.CONFIGS_ATTR_NAME, html); } else { sessionContext.setAttribute(SimpleItypeConfig.CONFIGS_ATTR_NAME, null); request.setAttribute(SimpleItypeConfig.CONFIGS_ATTR_NAME, null); } // For duplication set configID to 0 // if(op.equalsIgnoreCase(rsc.getMessage("button.duplicateConfig"))) { // frm.setConfigId(new Long(0)); // frm.setName(InstrOfferingConfig.getGeneratedName( // ( new InstrOfferingConfigDAO().get(configId)).getInstructionalOffering() )); // } } // Add a new configuration if (op.equals(MSG.actionAddConfiguration())) { String courseOfferingId = (request.getParameter("uid") == null) ? (request.getAttribute("uid") == null) ? null : request.getAttribute("uid").toString() : request.getParameter("uid"); if (courseOfferingId == null || courseOfferingId.trim().length() == 0) throw new Exception(MSG.exceptionCourseOfferingIdNeeded()); sessionContext.checkPermission(frm.getInstrOfferingId(), "InstructionalOffering", Right.InstrOfferingConfigAdd); loadDetailFromCourseOffering(frm, new Long(courseOfferingId), true, false); sessionContext.setAttribute(SimpleItypeConfig.CONFIGS_ATTR_NAME, null); request.setAttribute(SimpleItypeConfig.CONFIGS_ATTR_NAME, ""); } // Redirect after making course offered if (op.equalsIgnoreCase(MSG.actionMakeOffered())) { String courseOfferingId = (request.getParameter("uid") == null) ? (request.getAttribute("uid") == null) ? null : request.getAttribute("uid").toString() : request.getParameter("uid"); if (courseOfferingId == null || courseOfferingId.trim().length() == 0) throw new Exception(MSG.exceptionCourseOfferingIdNeeded()); // Get first available config loadDetailFromCourseOffering(frm, new Long(courseOfferingId), true, true); sessionContext.setAttribute(SimpleItypeConfig.CONFIGS_ATTR_NAME, null); request.setAttribute(SimpleItypeConfig.CONFIGS_ATTR_NAME, ""); // load existing config from database if (frm.getConfigId() != null && frm.getConfigId().intValue() > 0) { Vector sp = loadOriginalConfig(frm.getConfigId(), frm); if (sp != null && sp.size() > 0) { sessionContext.setAttribute(SimpleItypeConfig.CONFIGS_ATTR_NAME, sp); html = SchedulingSubpartTableBuilder.buildSubpartsTable(request, sessionContext, frm.getLimit(), courseOfferingId, false, frm.getUnlimited().booleanValue()); request.setAttribute(SimpleItypeConfig.CONFIGS_ATTR_NAME, html); } else { sessionContext.setAttribute(SimpleItypeConfig.CONFIGS_ATTR_NAME, null); request.setAttribute(SimpleItypeConfig.CONFIGS_ATTR_NAME, null); } } } // Add Instructional Type if (op.equals(MSG.actionAddInstructionalTypeToConfig())) { ActionMessages errors = frm.validate(mapping, request); if (!errors.isEmpty()) { html = SchedulingSubpartTableBuilder.buildSubpartsTable(request, sessionContext, frm.getLimit(), frm.getCourseOfferingId(), false, frm.getUnlimited().booleanValue()); request.setAttribute(SimpleItypeConfig.CONFIGS_ATTR_NAME, html); saveErrors(request, errors); return mapping.findForward("displayForm"); } addInstructionalType(frm); frm.setItype(Constants.BLANK_OPTION_VALUE); html = SchedulingSubpartTableBuilder.buildSubpartsTable(request, sessionContext, frm.getLimit(), frm.getCourseOfferingId(), false, frm.getUnlimited().booleanValue()); request.setAttribute(SimpleItypeConfig.CONFIGS_ATTR_NAME, html); } // Move / Order / Delete Itypes if (op.indexOf(rsc.getMessage("op.shift")) >= 0 || op.equals(rsc.getMessage("op.delete"))) { int limit = 0; try { limit = Integer.parseInt(request.getParameter("limit")); } catch (Exception e) { limit = 0; } frm.setLimit(limit); processShiftOrDelete(request.getParameter("id"), op); html = SchedulingSubpartTableBuilder.buildSubpartsTable(request, sessionContext, frm.getLimit(), frm.getCourseOfferingId(), false, frm.getUnlimited().booleanValue()); request.setAttribute(SimpleItypeConfig.CONFIGS_ATTR_NAME, html); } // Multiple Limits if (op.equalsIgnoreCase("multipleLimits")) { html = SchedulingSubpartTableBuilder.buildSubpartsTable(request, sessionContext, frm.getLimit(), frm.getCourseOfferingId(), false, frm.getUnlimited().booleanValue()); request.setAttribute(SimpleItypeConfig.CONFIGS_ATTR_NAME, html); } // User commits changes if (op.equals(MSG.actionSaveConfiguration()) || op.equals(MSG.actionUpdateConfiguration())) { html = SchedulingSubpartTableBuilder.buildSubpartsTable(request, sessionContext, frm.getLimit(), frm.getCourseOfferingId(), false, frm.getUnlimited().booleanValue()); ActionMessages errors = frm.validate(mapping, request); if (!errors.isEmpty()) { html = SchedulingSubpartTableBuilder.buildSubpartsTable(request, sessionContext, frm.getLimit(), frm.getCourseOfferingId(), false, frm.getUnlimited().booleanValue()); request.setAttribute(SimpleItypeConfig.CONFIGS_ATTR_NAME, html); saveErrors(request, errors); return mapping.findForward("displayForm"); } try { updateConfig(request, frm); html = SchedulingSubpartTableBuilder.buildSubpartsTable(request, sessionContext, frm.getLimit(), frm.getCourseOfferingId(), false, frm.getUnlimited().booleanValue()); request.setAttribute(SimpleItypeConfig.CONFIGS_ATTR_NAME, html); // Redirect to instr offering detail on success ActionRedirect redirect = new ActionRedirect(mapping.findForward("instructionalOfferingDetail")); redirect.addParameter("io", frm.getInstrOfferingId()); redirect.addParameter("op", "view"); return redirect; } catch (Exception e) { html = SchedulingSubpartTableBuilder.buildSubpartsTable(request, sessionContext, frm.getLimit(), frm.getCourseOfferingId(), false, frm.getUnlimited().booleanValue()); request.setAttribute(SimpleItypeConfig.CONFIGS_ATTR_NAME, html); errors.add("subparts", new ActionMessage("errors.generic", "Configuration could not be updated. If possible, split your configuration change into 2 or more separate operations. " + (e.getClass().getName().startsWith("org.hibernate.") ? "" : "Exception: " + e.getMessage()))); saveErrors(request, errors); return mapping.findForward("displayForm"); } } // Delete configuration if (op.equals(MSG.actionDeleteConfiguration())) { sessionContext.checkPermission(frm.getConfigId(), "InstrOfferingConfig", Right.InstrOfferingConfigDelete); deleteConfig(request, frm); // Redirect to instr offering detail on success ActionRedirect redirect = new ActionRedirect(mapping.findForward("instructionalOfferingDetail")); redirect.addParameter("io", frm.getInstrOfferingId()); redirect.addParameter("op", "view"); redirect.addParameter("cfgDelete", "1"); return redirect; } // User clicks Unlimited Enrollment if (op.equalsIgnoreCase("unlimitedEnrollment")) { html = SchedulingSubpartTableBuilder.buildSubpartsTable(request, sessionContext, frm.getLimit(), frm.getCourseOfferingId(), false, frm.getUnlimited().booleanValue()); request.setAttribute(SimpleItypeConfig.CONFIGS_ATTR_NAME, html); return mapping.findForward("displayForm"); } return mapping.findForward("displayForm"); } private void loadDetailFromConfig(InstructionalOfferingConfigEditForm frm, Long configId, boolean init) throws Exception { // Check uniqueid if (configId == null) throw new Exception("Config Id need for operation. "); InstrOfferingConfigDAO iocDao = new InstrOfferingConfigDAO(); InstrOfferingConfig ioc = iocDao.get(configId); if (ioc == null) throw new Exception("Congifuration not found for id: " + configId); frm.setConfigId(configId); frm.setName(ioc.getName()); frm.setUnlimited(ioc.isUnlimitedEnrollment()); Long courseOfferingId = ioc.getControllingCourseOffering().getUniqueId(); loadDetailFromCourseOffering(frm, courseOfferingId, init, false); } /** * Loads course offering details into the form * @param courseOfferingId Course Offering Uid * @param frm Form * @throws Exception */ private void loadDetailFromCourseOffering(InstructionalOfferingConfigEditForm frm, Long courseOfferingId, boolean init, boolean loadDefaultConfig) throws Exception { // Check uniqueid if (courseOfferingId == null) throw new Exception("Course Offering Id need for operation. "); // Load Course Offering CourseOfferingDAO coDao = new CourseOfferingDAO(); CourseOffering co = coDao.get(courseOfferingId); if (co == null) throw new Exception("Course Offering not found for id: " + courseOfferingId); InstructionalOffering io = co.getInstructionalOffering(); // Set values frm.setCourseOfferingId(co.getUniqueId().toString()); frm.setSubjectArea(co.getSubjectAreaAbbv()); frm.setCourseNumber(co.getCourseNbr()); frm.setInstrOfferingName(co.getCourseNameWithTitle()); frm.setInstrOfferingId(io.getUniqueId().toString()); frm.setNotOffered(io.isNotOffered()); Set configs = io.getInstrOfferingConfigs(); frm.setConfigCount(new Integer(configs.size())); // Catalog Link String linkLookupClass = ApplicationProperty.CourseCatalogLinkProvider.value(); if (linkLookupClass != null && linkLookupClass.trim().length() > 0) { ExternalLinkLookup lookup = (ExternalLinkLookup) (Class.forName(linkLookupClass).newInstance()); Map results = lookup.getLink(io); if (results == null) throw new Exception(lookup.getErrorMessage()); frm.setCatalogLinkLabel((String) results.get(ExternalLinkLookup.LINK_LABEL)); frm.setCatalogLinkLocation((String) results.get(ExternalLinkLookup.LINK_LOCATION)); } if (loadDefaultConfig) { if (configs == null || configs.size() == 0) { frm.setConfigId(null); frm.setName("1"); } else { InstrOfferingConfig ioc = (InstrOfferingConfig) configs.iterator().next(); frm.setConfigId(ioc.getUniqueId()); if (init) { frm.setName(ioc.getName()); frm.setUnlimited(ioc.isUnlimitedEnrollment()); } } } else { if (frm.getName() == null || frm.getName().trim().length() == 0) frm.setName(InstrOfferingConfig.getGeneratedName(io)); } } /** * Loads original config from database * @param user User object * @param courseOfferingId Course Offering Uid * @param frm Form */ private Vector loadOriginalConfig(Long configId, InstructionalOfferingConfigEditForm frm) throws Exception { InstrOfferingConfigDAO cfgDao = new InstrOfferingConfigDAO(); InstrOfferingConfig config = cfgDao.get(configId); frm.setLimit(config.getLimit().intValue()); Vector sp = toSimpleItypeConfig(config); if (sp != null && sp.size() > 0) Collections.sort(sp, new SicComparator()); return sp; } /** * Add a new Inst. Type to the user defined config * @param httpSession Http Session object * @param frm Form object * @throws Exception */ private void addInstructionalType(InstructionalOfferingConfigEditForm frm) throws Exception { // Create object ItypeDescDAO itypeDao = new ItypeDescDAO(); ItypeDesc itype = itypeDao.get(new Integer(frm.getItype())); if (itype == null) throw new Exception("Instructional Type not found"); // Retrieve object containing user defined config from session Vector sp = (Vector) sessionContext.getAttribute(SimpleItypeConfig.CONFIGS_ATTR_NAME); if (sp == null) sp = new Vector(); // Create new object SimpleItypeConfig sic = new SimpleItypeConfig(itype); sic.setSubpartId(-1L); //sic.setLimitPerClass(frm.getLimit()); //sic.setRoomCapacity(frm.getLimit()); sp.addElement(sic); //Collections.sort(sp, new SicComparator()); // Store back in session sessionContext.setAttribute(SimpleItypeConfig.CONFIGS_ATTR_NAME, sp); } /** * Processes arrow click and config element delete operations * @param httpSession Http Session object * @param id Id of the config element whose shift / delete arrow was clicked * @param op Operation to be performed * @throws Exception */ private void processShiftOrDelete(String id, String op) throws Exception { // Read user defined config Vector sp = (Vector) sessionContext.getAttribute(SimpleItypeConfig.CONFIGS_ATTR_NAME); // No subparts if (sp == null || sp.size() == 0) throw new Exception("Could not retrieve user defined configs"); // Locate config element Vector indx = new Vector(); SimpleItypeConfig result = search(id, indx, false); if (result == null) throw new Exception("Could not retrieve config element: " + id); int index = Integer.parseInt(indx.elementAt(0).toString()); // Process ops if (op.equalsIgnoreCase("shiftUp")) { // Get parent SimpleItypeConfig parent = result.getParent(); // Element is at the top most level if (parent == null) { // Switch elements with one above int indx1 = index; int indx2 = indx1 - 1; Object tmp = sp.elementAt(indx1); sp.insertElementAt(tmp, indx2); sp.removeElementAt(indx1 + 1); } // Element is a subpart of another element else { // Locate the element index in the subparts Vector v = parent.getSubparts(); for (int i = 0; i < v.size(); i++) { SimpleItypeConfig subp = (SimpleItypeConfig) v.elementAt(i); // Switch elements with one above if (subp.getId() == Long.parseLong(id)) { Object tmp = v.elementAt(i); v.insertElementAt(tmp, i - 1); v.removeElementAt(i + 1); break; } } } } if (op.equalsIgnoreCase("shiftDown")) { // Get parent SimpleItypeConfig parent = result.getParent(); // Element is at the top most level if (parent == null) { // Switch elements with one below int indx1 = index + 1; int indx2 = index; Object tmp = sp.elementAt(indx1); sp.insertElementAt(tmp, indx2); sp.removeElementAt(indx1 + 1); } // Element is a subpart of another element else { // Locate the element index in the subparts Vector v = parent.getSubparts(); for (int i = 0; i < v.size(); i++) { SimpleItypeConfig subp = (SimpleItypeConfig) v.elementAt(i); // Switch elements with one below if (subp.getId() == Long.parseLong(id)) { Object tmp = v.elementAt(i + 1); v.insertElementAt(tmp, i); v.removeElementAt(i + 2); break; } } } } if (op.equalsIgnoreCase("shiftLeft")) { // Get parent SimpleItypeConfig parent = result.getParent(); // Remove element from parent subpart Vector v = parent.getSubparts(); for (int i = 0; i < v.size(); i++) { SimpleItypeConfig subp = (SimpleItypeConfig) v.elementAt(i); if (subp.getId() == Long.parseLong(id)) { v.removeElementAt(i); break; } } // Get grandparent and set it as parent of element SimpleItypeConfig grandParent = parent.getParent(); result.setParent(grandParent); // Parent is at the top most level if (grandParent == null) { sp.insertElementAt(result, index + 1); } // Grandparent exists else { // Locate parent in grandparent subparts Vector v1 = grandParent.getSubparts(); for (int i = 0; i < v1.size(); i++) { SimpleItypeConfig subp = (SimpleItypeConfig) v1.elementAt(i); // Add element just after parent subpart if (subp.getId() == parent.getId()) { v1.insertElementAt(result, i + 1); break; } } } } if (op.equalsIgnoreCase("shiftRight")) { // Get parent SimpleItypeConfig parent = result.getParent(); // Element is at the top most level if (parent == null) { // Switch elements with one below SimpleItypeConfig curr = (SimpleItypeConfig) sp.elementAt(index); SimpleItypeConfig prev = (SimpleItypeConfig) sp.elementAt(index - 1); prev.addSubpart(curr); sp.removeElementAt(index); } // Element is a subpart of another element else { // Locate the element index in the subparts Vector v = parent.getSubparts(); for (int i = 0; i < v.size(); i++) { SimpleItypeConfig subp = (SimpleItypeConfig) v.elementAt(i); // Add the element to the subpart of the element above if (subp.getId() == Long.parseLong(id)) { SimpleItypeConfig curr = (SimpleItypeConfig) v.elementAt(i); SimpleItypeConfig prev = (SimpleItypeConfig) v.elementAt(i - 1); prev.addSubpart(curr); v.removeElementAt(i); break; } } } } if (op.equalsIgnoreCase("delete")) { // Get parent SimpleItypeConfig parent = result.getParent(); // Element is at the top most level if (parent == null) { sp.removeElementAt(index); } // Element is a subpart of another element else { // Locate the element index in the subparts Vector v = parent.getSubparts(); for (int i = 0; i < v.size(); i++) { SimpleItypeConfig subp = (SimpleItypeConfig) v.elementAt(i); if (subp.getId() == Long.parseLong(id)) { v.removeElementAt(i); break; } } } } sessionContext.setAttribute(SimpleItypeConfig.CONFIGS_ATTR_NAME, sp); } /** * Search user-defined configs for SimpleItypeConfig with the given id * @param httpSession Session object containing user-defined configs * @param id Id of the target config * @param indx Stores the row number of the config element that has the match * @return null if not found, SimpleItypeConfig object if found */ private SimpleItypeConfig search(String id, Vector indx, boolean clearErrorFlags) { // Read user defined config Vector sp = (Vector) sessionContext.getAttribute(SimpleItypeConfig.CONFIGS_ATTR_NAME); // No subparts if (sp == null || sp.size() == 0) return null; SimpleItypeConfig result = null; // Loop through itypes for (int i = 0; i < sp.size(); i++) { SimpleItypeConfig sic = (SimpleItypeConfig) sp.elementAt(i); indx.clear(); indx.addElement("" + i); if (clearErrorFlags) sic.setHasError(false); // Recursively process each itype config result = searchR(sic, id, clearErrorFlags); if (result != null) break; } if (clearErrorFlags) sessionContext.setAttribute(SimpleItypeConfig.CONFIGS_ATTR_NAME, sp); return result; } /** * Recursive function to perform search * @param sic Parent Config object * @param id Target Id * @return null if not found, SimpleItypeConfig object if found */ private SimpleItypeConfig searchR(SimpleItypeConfig sic, String id, boolean clearErrorFlags) { if (sic.getId() == Long.parseLong(id)) return sic; Vector v = sic.getSubparts(); SimpleItypeConfig result = null; // Loop through children sub-parts for (int i = 0; i < v.size(); i++) { SimpleItypeConfig sic1 = (SimpleItypeConfig) v.elementAt(i); if (clearErrorFlags) sic1.setHasError(false); result = searchR(sic1, id, clearErrorFlags); if (result != null) break; } return result; } /** * Deletes configuration * and associated prefs * @param request * @param frm * @throws Exception */ private void deleteConfig(HttpServletRequest request, InstructionalOfferingConfigEditForm frm) throws Exception { org.hibernate.Session hibSession = null; Transaction tx = null; try { InstrOfferingConfigDAO iocDao = new InstrOfferingConfigDAO(); hibSession = iocDao.getSession(); tx = hibSession.beginTransaction(); Long configId = frm.getConfigId(); InstrOfferingConfig ioc = iocDao.get(configId); InstructionalOffering io = ioc.getInstructionalOffering(); deleteSubpart(request, hibSession, ioc, new HashMap()); io.removeConfiguration(ioc); io.computeLabels(hibSession); if (!ioc.isUnlimitedEnrollment().booleanValue()) io.setLimit(new Integer(io.getLimit().intValue() - ioc.getLimit().intValue())); ChangeLog.addChange(hibSession, sessionContext, io, io.getCourseName() + " [" + ioc.getName() + "]", ChangeLog.Source.INSTR_CFG_EDIT, ChangeLog.Operation.DELETE, io.getControllingCourseOffering().getSubjectArea(), null); Event.deleteFromEvents(hibSession, ioc); Exam.deleteFromExams(hibSession, ioc); // The following line was calling delete ioc for the second time (which is a problem for MySQL as // it returns zero number of deleted lines even when called in the same transaction). //hibSession.delete(ioc); hibSession.saveOrUpdate(io); hibSession.flush(); tx.commit(); hibSession.refresh(io); String className = ApplicationProperty.ExternalActionInstrOffrConfigChange.value(); if (className != null && className.trim().length() > 0) { ExternalInstrOffrConfigChangeAction configChangeAction = (ExternalInstrOffrConfigChangeAction) (Class .forName(className).newInstance()); configChangeAction.performExternalInstrOffrConfigChangeAction(io, hibSession); } } catch (Exception e) { try { if (tx != null && tx.isActive()) tx.rollback(); } catch (Exception e1) { } Debug.error(e); throw (e); } } /** * Update configuration without destroying existing subparts/classes * and associated prefs * @param request * @param frm * @throws Exception */ private void updateConfig(HttpServletRequest request, InstructionalOfferingConfigEditForm frm) throws Exception { // Read user defined config Vector sp = (Vector) sessionContext.getAttribute(SimpleItypeConfig.CONFIGS_ATTR_NAME); // No subparts if (sp == null || sp.size() == 0) return; RoomGroup rg = RoomGroup.getGlobalDefaultRoomGroup(sessionContext.getUser().getCurrentAcademicSessionId()); InstrOfferingConfig ioc = null; InstructionalOffering io = null; org.hibernate.Session hibSession = null; Transaction tx = null; try { InstructionalOfferingDAO ioDao = new InstructionalOfferingDAO(); InstrOfferingConfigDAO iocDao = new InstrOfferingConfigDAO(); hibSession = iocDao.getSession(); tx = hibSession.beginTransaction(); io = ioDao.get(new Long(frm.getInstrOfferingId())); Long configId = frm.getConfigId(); Boolean unlimitedEnroll = (frm.getUnlimited() == null) ? new Boolean(false) : frm.getUnlimited(); int limit = (unlimitedEnroll.booleanValue()) ? 0 : frm.getLimit(); if (configId == null || configId.intValue() == 0) { ioc = new InstrOfferingConfig(); ioc.setLimit(new Integer(limit)); ioc.setName(frm.getName()); ioc.setUnlimitedEnrollment(unlimitedEnroll); ioc.setInstructionalOffering(io); io.addToinstrOfferingConfigs(ioc); hibSession.saveOrUpdate(ioc); hibSession.saveOrUpdate(io); } else { ioc = iocDao.get(configId); ioc.setLimit(new Integer(limit)); ioc.setName(frm.getName()); ioc.setUnlimitedEnrollment(unlimitedEnroll); } HashMap notDeletedSubparts = new HashMap(); // Update subparts in the modified config for (int i = 0; i < sp.size(); i++) { SimpleItypeConfig sic = (SimpleItypeConfig) sp.elementAt(i); createOrUpdateSubpart(request, hibSession, sic, ioc, null, rg, notDeletedSubparts); createOrUpdateClasses(request, hibSession, sic, ioc, null); } // Update Parents Set s = ioc.getSchedulingSubparts(); for (Iterator i = s.iterator(); i.hasNext();) { SchedulingSubpart subp = (SchedulingSubpart) i.next(); if (subp.getParentSubpart() == null) { Debug.debug("Setting parents for " + subp.getItypeDesc()); updateParentClasses(subp, null, hibSession, notDeletedSubparts); } } // Remove any subparts that do not exist in the modified config deleteSubpart(request, hibSession, ioc, notDeletedSubparts); hibSession.saveOrUpdate(ioc); hibSession.saveOrUpdate(io); io.computeLabels(hibSession); ChangeLog.addChange(hibSession, sessionContext, ioc, ChangeLog.Source.INSTR_CFG_EDIT, (configId == null || configId.intValue() == 0 ? ChangeLog.Operation.CREATE : ChangeLog.Operation.UPDATE), ioc.getInstructionalOffering().getControllingCourseOffering().getSubjectArea(), null); hibSession.flush(); tx.commit(); hibSession.refresh(ioc); hibSession.refresh(io); String className = ApplicationProperty.ExternalActionInstrOffrConfigChange.value(); if (className != null && className.trim().length() > 0) { ExternalInstrOffrConfigChangeAction configChangeAction = (ExternalInstrOffrConfigChangeAction) (Class .forName(className).newInstance()); configChangeAction.performExternalInstrOffrConfigChangeAction(io, hibSession); } } catch (Exception e) { try { if (tx != null && tx.isActive()) tx.rollback(); } catch (Exception e1) { } try { if (ioc != null) hibSession.refresh(ioc); } catch (Exception e2) { } try { if (io != null) hibSession.refresh(io); } catch (Exception e3) { } Debug.error(e); throw (e); } } private void updateParentClasses(SchedulingSubpart subpart, SchedulingSubpart parent, org.hibernate.Session hibSession, HashMap notDeletedSubparts) { if (parent == null) { Debug.debug("Parent is null. Setting all classes to have no parent"); Set classes = subpart.getClasses(); for (Iterator i = classes.iterator(); i.hasNext();) { Class_ c = (Class_) i.next(); c.setParentClass(null); hibSession.saveOrUpdate(c); } } else { Set classes = subpart.getClasses(); ArrayList classesList = new ArrayList(classes); Collections.sort(classesList, new ClassComparator(ClassComparator.COMPARE_BY_ID)); Set parentClasses = parent.getClasses(); int parentNumClasses = parentClasses.size(); if (parentNumClasses > 0) { Iterator cci = classesList.iterator(); int classPerParent = classesList.size() / parentNumClasses; int classPerParentRem = classesList.size() % parentNumClasses; Debug.debug("Setting " + classPerParent + " class(es) per parent"); Debug.debug("Odd number of classes found - " + classPerParentRem + " classes ... "); for (Iterator i = parentClasses.iterator(); (i.hasNext() && classPerParent != 0);) { Class_ parentClass = (Class_) i.next(); for (int j = 0; j < classPerParent; j++) { Class_ childClass = (Class_) cci.next(); if (notDeletedSubparts.get(childClass.getSchedulingSubpart().getUniqueId()) != null) { Debug.debug("Setting class " + childClass.getClassLabel() + " to parent " + parentClass.getClassLabel()); childClass.setParentClass(parentClass); parentClass.addTochildClasses(childClass); hibSession.saveOrUpdate(parentClass); hibSession.saveOrUpdate(childClass); } else { Debug.debug("Deleting class " + childClass.getClassLabel()); if (childClass.getParentClass() != null) { Class_ pc = childClass.getParentClass(); pc.getChildClasses().remove(childClass); hibSession.saveOrUpdate(pc); childClass.setParentClass(null); hibSession.saveOrUpdate(childClass); } classes.remove(childClass); childClass.deleteAllDependentObjects(hibSession, false); hibSession.delete(childClass); hibSession.saveOrUpdate(subpart); } if (classPerParentRem != 0) { if (cci.hasNext()) { childClass = (Class_) cci.next(); if (notDeletedSubparts .get(childClass.getSchedulingSubpart().getUniqueId()) != null) { Debug.debug("Setting ODD class " + childClass.getClassLabel() + " to parent " + parentClass.getClassLabel()); childClass.setParentClass(parentClass); parentClass.addTochildClasses(childClass); hibSession.saveOrUpdate(parentClass); hibSession.saveOrUpdate(childClass); } else { Debug.debug("Deleting ODD class " + childClass.getClassLabel()); if (childClass.getParentClass() != null) { Class_ pc = childClass.getParentClass(); pc.getChildClasses().remove(childClass); hibSession.saveOrUpdate(pc); childClass.setParentClass(null); hibSession.saveOrUpdate(childClass); } classes.remove(childClass); childClass.deleteAllDependentObjects(hibSession, false); hibSession.delete(childClass); hibSession.saveOrUpdate(childClass.getSchedulingSubpart()); } } --classPerParentRem; } } } if (classPerParentRem != 0) { Iterator cci2 = classesList.iterator(); for (Iterator i = parentClasses.iterator(); i.hasNext();) { Class_ parentClass = (Class_) i.next(); if (cci2.hasNext()) { Class_ childClass = (Class_) cci2.next(); Debug.debug("Setting ODD class " + childClass.getClassLabel() + " to parent " + parentClass.getClassLabel()); childClass.setParentClass(parentClass); parentClass.addTochildClasses(childClass); hibSession.saveOrUpdate(parentClass); hibSession.saveOrUpdate(childClass); } --classPerParentRem; if (classPerParentRem == 0) break; } } hibSession.saveOrUpdate(parent); } } // Traverse through children Set childSubparts = subpart.getChildSubparts(); if (childSubparts == null || childSubparts.size() == 0) return; for (Iterator i = childSubparts.iterator(); i.hasNext();) { SchedulingSubpart cs = (SchedulingSubpart) i.next(); updateParentClasses(cs, subpart, hibSession, notDeletedSubparts); } } /** * Deletes all the subparts that do not exist in the modified config * @param request * @param hibSession * @param ioc * @param notDeletedSubparts * @throws Exception */ private void deleteSubpart(HttpServletRequest request, org.hibernate.Session hibSession, InstrOfferingConfig ioc, HashMap notDeletedSubparts) throws Exception { Set s = ioc.getSchedulingSubparts(); HashMap deletedSubparts = new HashMap(); for (Iterator i = s.iterator(); i.hasNext();) { SchedulingSubpart tmpSubpart = (SchedulingSubpart) i.next(); if (notDeletedSubparts.get(tmpSubpart.getUniqueId()) == null) { Debug.debug("Deleting subpart ... " + tmpSubpart.getUniqueId() + ", " + tmpSubpart.getItypeDesc()); // Delete classes Set classes = tmpSubpart.getClasses(); for (Iterator j = classes.iterator(); j.hasNext();) { Class_ c = (Class_) j.next(); deleteChildClasses(c, hibSession, 1); Class_ pc = c.getParentClass(); if (pc != null) { pc.getChildClasses().remove(c); if (notDeletedSubparts.get(pc.getSchedulingSubpart().getUniqueId()) != null) hibSession.saveOrUpdate(pc); } j.remove(); } // Delete from parent SchedulingSubpart parentSubpart = tmpSubpart.getParentSubpart(); if (parentSubpart != null) { if (parentSubpart.getChildSubparts() != null) parentSubpart.getChildSubparts().remove(tmpSubpart); tmpSubpart.setParentSubpart(null); if (deletedSubparts.get(parentSubpart.getUniqueId()) == null) hibSession.saveOrUpdate(parentSubpart); } // Remove references from child subparts Set childSubparts = tmpSubpart.getChildSubparts(); if (childSubparts != null) Debug.debug("Child subparts exist ... " + childSubparts.size()); tmpSubpart.setChildSubparts(null); deletedSubparts.put(tmpSubpart.getUniqueId(), tmpSubpart.getUniqueId()); hibSession.delete(tmpSubpart); i.remove(); } } hibSession.saveOrUpdate(ioc); hibSession.flush(); } /** * Recursively process the updated config subparts * @param request * @param hibSession * @param sic * @param ioc * @param parent * @param mgr * @param notDeletedSubparts Holds all the subpart ids encountered while recursing * @throws Exception */ private void createOrUpdateSubpart(HttpServletRequest request, org.hibernate.Session hibSession, SimpleItypeConfig sic, InstrOfferingConfig ioc, SchedulingSubpart parent, RoomGroup rg, HashMap notDeletedSubparts) throws Exception { // Set attributes String subpartId = request.getParameter("subpartId" + sic.getId()); String minLimitPerClass = request.getParameter("mnlpc" + sic.getId()); String maxLimitPerClass = request.getParameter("mxlpc" + sic.getId()); String minPerWk = request.getParameter("mpw" + sic.getId()); String numClasses = request.getParameter("nc" + sic.getId()); String numRooms = request.getParameter("nr" + sic.getId()); String roomRatio = request.getParameter("rr" + sic.getId()); String managingDept = request.getParameter("md" + sic.getId()); String disabled = request.getParameter("disabled" + sic.getId()); if (subpartId != null) sic.setSubpartId(Long.parseLong(subpartId)); if (minLimitPerClass != null) sic.setMinLimitPerClass(Constants.getPositiveInteger(minLimitPerClass, 0)); if (maxLimitPerClass != null) sic.setMaxLimitPerClass(Constants.getPositiveInteger(maxLimitPerClass, 0)); if (minPerWk != null) sic.setMinPerWeek(Integer.parseInt(minPerWk)); if (numClasses != null) sic.setNumClasses(Integer.parseInt(numClasses)); if (numRooms != null) sic.setNumRooms(Constants.getPositiveInteger(numRooms, 0)); if (roomRatio != null) sic.setRoomRatio(Constants.getPositiveFloat(roomRatio, 0.0f)); if (managingDept != null) sic.setManagingDeptId(Long.parseLong(managingDept)); if (disabled != null) sic.setDisabled(new Boolean(request.getParameter("disabled" + sic.getId())).booleanValue()); // Read attributes long sid = sic.getSubpartId(); int mnlpc = sic.getMinLimitPerClass(); int mxlpc = sic.getMaxLimitPerClass(); int mpw = sic.getMinPerWeek(); int nr = sic.getNumRooms(); float rr = sic.getRoomRatio(); long md = sic.getManagingDeptId(); boolean db = sic.isDisabled(); if (ioc.isUnlimitedEnrollment().booleanValue()) { mnlpc = 0; mxlpc = 0; nr = 0; rr = 0; } if (request.getParameter("varLimits") == null) { mnlpc = mxlpc; } SchedulingSubpart subpart = null; // Subpart does not exist if (sid < 0) { Debug.debug("Subpart does not exist ... Creating subpart - " + sic.getItype().getDesc()); // Create subpart subpart = new SchedulingSubpart(); subpart.setInstrOfferingConfig(ioc); subpart.setItype(sic.getItype()); subpart.setMinutesPerWk(new Integer(mpw)); subpart.setParentSubpart(parent); subpart.setAutoSpreadInTime(ApplicationProperty.SchedulingSubpartAutoSpreadInTimeDefault.isTrue()); subpart.setStudentAllowOverlap(ApplicationProperty.SchedulingSubpartStudentOverlapsDefault.isTrue()); ioc.addToschedulingSubparts(subpart); if (md < 0 && !ioc.isUnlimitedEnrollment().booleanValue() && rg != null) { // Add default room group pref of classroom HashSet prefs = new HashSet(); RoomGroupPref rgp = new RoomGroupPref(); rgp.setPrefLevel( PreferenceLevel.getPreferenceLevel(Integer.parseInt(PreferenceLevel.PREF_LEVEL_REQUIRED))); rgp.setRoomGroup(rg); rgp.setOwner(subpart); prefs.add(rgp); subpart.setPreferences(prefs); } hibSession.saveOrUpdate(subpart); hibSession.flush(); hibSession.refresh(subpart); sid = subpart.getUniqueId().longValue(); Debug.debug("New subpart uniqueid: " + sid); sic.setSubpartId(sid); notDeletedSubparts.put(new Long(sid), ""); } // End If: Subpart does not exist // Subpart exists else { Debug.debug("Subpart exists ... Updating"); notDeletedSubparts.put(new Long(sid), ""); Set s = ioc.getSchedulingSubparts(); for (Iterator i = s.iterator(); i.hasNext();) { SchedulingSubpart tmpSubpart = (SchedulingSubpart) i.next(); if (tmpSubpart.getUniqueId().longValue() == sid) { subpart = tmpSubpart; break; } } if (subpart == null) throw new Exception("Scheduling Subpart " + sid + " was not found."); Debug.debug("Creating / Updating subpart - " + subpart.getItypeDesc()); Set classes = subpart.getClasses(); // Update only if user has permissions and does not have mixed managed classes //if (subpart.isEditableBy(Web.getUser(request.getSession())) && !subpart.hasMixedManagedClasses()) { if (!db) { // If minutes per week has changed then delete time pattern and time prefs if (subpart.getMinutesPerWk().intValue() != mpw) { Debug.debug("Minutes per week changed ... Deleting time prefs on subpart and classes"); subpart.setMinutesPerWk(new Integer(mpw)); Set prefs = subpart.getPreferences(); for (Iterator i = prefs.iterator(); i.hasNext();) { Preference pref = (Preference) i.next(); if (pref instanceof TimePref) { pref.setOwner(null); hibSession.delete(pref); i.remove(); } } for (Iterator i = classes.iterator(); i.hasNext();) { Class_ c = (Class_) i.next(); Set cPrefs = c.getPreferences(); for (Iterator j = cPrefs.iterator(); j.hasNext();) { Preference pref = (Preference) j.next(); if (pref instanceof TimePref) { pref.setOwner(null); hibSession.delete(pref); j.remove(); } } hibSession.saveOrUpdate(c); } } // Manager changed boolean managerChanged = false; long mdId = md; if (md < 0) { mdId = subpart.getInstrOfferingConfig().getControllingCourseOffering().getSubjectArea() .getDepartment().getUniqueId().longValue(); } if (subpart.getManagingDept().getUniqueId().longValue() != mdId) { Debug.debug("Subpart Managing department changed ..."); managerChanged = true; // Remove from distribution prefs subpart.deleteAllDistributionPreferences(hibSession); // Clear all prefs - except time & distribution Set prefs = subpart.getPreferences(); for (Iterator prefI = prefs.iterator(); prefI.hasNext();) { Object a = prefI.next(); if (a instanceof RoomPref || a instanceof BuildingPref || a instanceof RoomGroupPref || a instanceof RoomFeaturePref) { prefI.remove(); } //Weaken time preferences if the new manager is external if (a instanceof TimePref) { Department mgDept = new DepartmentDAO().get(new Long(mdId)); if (mgDept.isExternalManager().booleanValue()) { //weaken only when both controling and managing departments do not allow required time if (subpart.getControllingDept().isAllowReqTime() == null || !subpart.getControllingDept().isAllowReqTime().booleanValue()) { if (mgDept.isAllowReqTime() == null || !mgDept.isAllowReqTime().booleanValue()) { ((TimePref) a).weakenHardPreferences(); } } } /* // Set all time prefs to neutral in order to preserve time pattern TimePref tp = new TimePref(); tp.setTimePattern(((TimePref) a).getTimePattern()); String prefStr = tp.getTimePatternModel().getPreferences(); ((TimePref) a).setPreference(tp.getPreference()); */ } } // Check if changed to Department and is not unlimited enroll if (md < 0 && !ioc.isUnlimitedEnrollment().booleanValue() && rg != null) { // Add default room group pref of classroom RoomGroupPref rgp = new RoomGroupPref(); rgp.setPrefLevel(PreferenceLevel .getPreferenceLevel(Integer.parseInt(PreferenceLevel.PREF_LEVEL_REQUIRED))); rgp.setRoomGroup(rg); rgp.setOwner(subpart); prefs.add(rgp); } } // Update expected capacity and room capacity for (Iterator i = classes.iterator(); i.hasNext();) { Debug.debug("Updating expected capacity and room capacity on class ..."); Class_ c = (Class_) i.next(); c.setExpectedCapacity(new Integer(mnlpc)); c.setMaxExpectedCapacity(new Integer(mxlpc)); c.setRoomRatio(new Float(rr)); c.setNbrRooms(new Integer(nr)); if (c.getDisplayInstructor() == null) { c.setDisplayInstructor(new Boolean(true)); } if (c.getEnabledForStudentScheduling() == null) { c.setEnabledForStudentScheduling(new Boolean(true)); } if (managerChanged) { if (c.getManagingDept().getUniqueId().longValue() != mdId) { Debug.debug("Class Managing department changed ..."); // Update Managing Department c.setManagingDept(new DepartmentDAO().get(new Long(mdId))); // Remove from distribution prefs c.deleteAllDistributionPreferences(hibSession); // Clear all prefs - except time & distribution Set prefs = c.getPreferences(); for (Iterator prefI = prefs.iterator(); prefI.hasNext();) { Object a = prefI.next(); if (a instanceof RoomPref || a instanceof BuildingPref || a instanceof RoomGroupPref || a instanceof RoomFeaturePref) { prefI.remove(); } // Weaken time preferences if the new manager is external, remove exact times if (a instanceof TimePref) { if (((TimePref) a).getTimePattern().getType() .intValue() == TimePattern.sTypeExactTime) { prefI.remove(); } else { if (c.getManagingDept().isExternalManager().booleanValue()) { //weaken only when both controling and managing departments do not allow required time if (c.getControllingDept().isAllowReqTime() == null || !c.getControllingDept().isAllowReqTime().booleanValue()) { if (c.getManagingDept().isAllowReqTime() == null || !c.getManagingDept().isAllowReqTime().booleanValue()) { ((TimePref) a).weakenHardPreferences(); } } } /* // Set all time prefs to neutral in order to preserve time pattern TimePref tp = new TimePref(); tp.setTimePattern(((TimePref) a).getTimePattern()); String prefStr = tp.getTimePatternModel().getPreferences(); ((TimePref) a).setPreference(prefStr); */ } } } } else { Debug.debug("Class Managing department same as subpart ... ignoring"); } } hibSession.saveOrUpdate(c); } } // End: Update only if user has permissions and does not have mixed managed classes // Update Parent if ((parent != null && subpart.getParentSubpart() != null && !subpart.getParentSubpart().equals(parent)) || (parent == null && subpart.getParentSubpart() != null) || (parent != null && subpart.getParentSubpart() == null)) { Debug.debug("Updating parent subparts and classes ..."); subpart.setParentSubpart(parent); // Update parent for classes if (parent == null) { Debug.debug("No parent subparts ... making top level class"); for (Iterator cci = subpart.getClasses().iterator(); cci.hasNext();) { Class_ childClass = (Class_) cci.next(); childClass.setParentClass(null); hibSession.saveOrUpdate(childClass); } } else { Debug.debug("Parent subpart exists ... setting parent class"); ArrayList classesList = new ArrayList(classes); Collections.sort(classesList, new ClassComparator(ClassComparator.COMPARE_BY_ID)); Set parentClasses = parent.getClasses(); int parentNumClasses = parentClasses.size(); if (parentNumClasses > 0) { Iterator cci = classesList.iterator(); int classPerParent = classesList.size() / parentNumClasses; int classPerParentRem = classesList.size() % parentNumClasses; Debug.debug("Setting " + classPerParent + " class(es) per parent"); Debug.debug("Odd number of classes found - " + classPerParentRem + " classes ... "); for (Iterator i = parentClasses.iterator(); (i.hasNext() && classPerParent != 0);) { Class_ parentClass = (Class_) i.next(); for (int j = 0; j < classPerParent; j++) { Class_ childClass = (Class_) cci.next(); Debug.debug("Setting class " + childClass.getClassLabel() + " to parent " + parentClass.getClassLabel()); childClass.setParentClass(parentClass); parentClass.addTochildClasses(childClass); hibSession.saveOrUpdate(parentClass); hibSession.saveOrUpdate(childClass); if (classPerParentRem != 0) { if (cci.hasNext()) { childClass = (Class_) cci.next(); Debug.debug("Setting ODD class " + childClass.getClassLabel() + " to parent " + parentClass.getClassLabel()); childClass.setParentClass(parentClass); parentClass.addTochildClasses(childClass); hibSession.saveOrUpdate(parentClass); hibSession.saveOrUpdate(childClass); } --classPerParentRem; } } } if (classPerParentRem != 0) { Iterator cci2 = classesList.iterator(); for (Iterator i = parentClasses.iterator(); i.hasNext();) { Class_ parentClass = (Class_) i.next(); if (cci2.hasNext()) { Class_ childClass = (Class_) cci2.next(); Debug.debug("Setting ODD class " + childClass.getClassLabel() + " to parent " + parentClass.getClassLabel()); childClass.setParentClass(parentClass); parentClass.addTochildClasses(childClass); hibSession.saveOrUpdate(parentClass); hibSession.saveOrUpdate(childClass); } --classPerParentRem; if (classPerParentRem == 0) break; } } hibSession.saveOrUpdate(parent); } } } // End If: Update Parent hibSession.saveOrUpdate(subpart); hibSession.flush(); hibSession.refresh(subpart); if (parent != null) hibSession.refresh(parent); } // End If: Subpart Exists // Loop through children sub-parts Vector v = sic.getSubparts(); for (int i = 0; i < v.size(); i++) { SimpleItypeConfig sic1 = (SimpleItypeConfig) v.elementAt(i); createOrUpdateSubpart(request, hibSession, sic1, ioc, subpart, rg, notDeletedSubparts); } hibSession.saveOrUpdate(ioc); hibSession.flush(); } /** * Create or Update Classes * @param sic * @param subpart * @param mgr * @param ncfs * @param lfs */ private void createOrUpdateClasses(HttpServletRequest request, org.hibernate.Session hibSession, SimpleItypeConfig sic, InstrOfferingConfig ioc, SchedulingSubpart parent) throws Exception { // Read attributes long sid = sic.getSubpartId(); int mnlpc = sic.getMinLimitPerClass(); int mxlpc = sic.getMaxLimitPerClass(); int nc = sic.getNumClasses(); int nr = sic.getNumRooms(); float rr = sic.getRoomRatio(); long md = sic.getManagingDeptId(); boolean db = sic.isDisabled(); if (ioc.isUnlimitedEnrollment().booleanValue()) { mnlpc = 0; mxlpc = 0; nr = 0; rr = 0; } if (request.getParameter("varLimits") == null) { mnlpc = mxlpc; } SchedulingSubpart subpart = null; // Subpart does not exist if (sid < 0) { throw new Exception("Subpart does not exist ... Cannot create classes "); } Set s = ioc.getSchedulingSubparts(); for (Iterator i = s.iterator(); i.hasNext();) { SchedulingSubpart tmpSubpart = (SchedulingSubpart) i.next(); if (tmpSubpart.getUniqueId().longValue() == sid) { subpart = tmpSubpart; break; } } if (subpart == null) throw new Exception("Scheduling Subpart " + sid + " was not found."); Debug.debug("Creating / Updating classes for subpart - " + subpart.getItypeDesc()); Set classes = subpart.getClasses(); int numCls = classes.size(); boolean readOnly = false; //if (!subpart.isEditableBy(Web.getUser(request.getSession())) || subpart.hasMixedManagedClasses()) { if (db) { Debug.debug("Subpart is readonly ... cannot change classes"); readOnly = true; } // Get Number of Parent Classes HashMap cpClasses = new HashMap(); if (parent != null) { for (Iterator i = classes.iterator(); i.hasNext();) { Class_ c = (Class_) i.next(); if (c.getParentClass() != null) { Integer classCount = (Integer) cpClasses.get(c.getParentClass().getUniqueId()); if (classCount == null) cpClasses.put(c.getParentClass().getUniqueId(), new Integer(1)); else cpClasses.put(c.getParentClass().getUniqueId(), new Integer(classCount.intValue() + 1)); } } int cpNumClasses = cpClasses.size(); int peerNumClasses = parent.getClasses().size(); // Adjust child per parent if (cpNumClasses != peerNumClasses) { if (readOnly) throw new Exception("Subpart " + subpart.toString() + " has read-only permissions - Number of classes cannot be changed. "); Debug.debug("Parents per child ( " + cpNumClasses + " ) do not match up to - " + peerNumClasses); int classesPerParent = numCls / peerNumClasses; if (numCls > classesPerParent && cpClasses.size() > 0) { int diff = (numCls - classesPerParent) / cpClasses.size(); Debug.debug("Deleting " + diff + " classes per current parent"); // Delete extra classes Set parentClassKeys = cpClasses.keySet(); for (Iterator ci = parentClassKeys.iterator(); ci.hasNext();) { Long parentClassId = (Long) ci.next(); int parentClassCount = ((Integer) cpClasses.get(parentClassId)).intValue(); int deleteCount = parentClassCount - classesPerParent; Debug.debug("Deleting " + deleteCount + " classes for parent class: " + parentClassId.toString()); ArrayList uids = new ArrayList(); for (Iterator i = classes.iterator(); i.hasNext();) { Class_ c1 = (Class_) i.next(); if (c1.getParentClass().getUniqueId().equals(parentClassId)) uids.add(c1.getUniqueId()); } Collections.sort(uids); for (int ct = (uids.size() - deleteCount); ct < uids.size(); ct++) { Long uid = (Long) uids.get(ct); for (Iterator i = classes.iterator(); i.hasNext();) { Class_ c = (Class_) i.next(); if (c.getUniqueId().equals(uid)) { deleteChildClasses(c, hibSession, 1); Class_ pc = c.getParentClass(); if (pc != null) { pc.getChildClasses().remove(c); hibSession.saveOrUpdate(pc); } i.remove(); //hibSession.delete(c); //hibSession.flush(); break; } } } hibSession.saveOrUpdate(subpart); hibSession.saveOrUpdate(parent); hibSession.flush(); } } else { int diff = classesPerParent - numCls; Debug.debug("Adding " + diff + " classes"); // Do nothing - Will be taken care of in the code below } } } // No. of classes changed numCls = classes.size(); if (numCls != nc) { if (readOnly) throw new Exception("Subpart " + subpart.toString() + " has read-only permissions - Number of classes cannot be changed. "); // Increased - create new classes if (nc > numCls) { Debug.debug("No. of classes increased ... Adding " + (nc - numCls) + " classes"); for (int ct = 0; ct < (nc - numCls); ct++) { Class_ c = new Class_(); c.setSchedulingSubpart(subpart); c.setExpectedCapacity(new Integer(mnlpc)); c.setMaxExpectedCapacity(new Integer(mxlpc)); c.setRoomRatio(new Float(rr)); c.setNbrRooms(new Integer(nr)); c.setDisplayInstructor(new Boolean(true)); c.setEnabledForStudentScheduling(new Boolean(true)); c.setPreferences(new HashSet()); if (md > 0) c.setManagingDept(new DepartmentDAO().get(new Long(md))); subpart.addToclasses(c); } hibSession.saveOrUpdate(subpart); hibSession.flush(); setParentClass(hibSession, subpart, parent, nc); } // Decreased - delete last class created else { Debug.debug("No. of classes decreased ... Deleting " + (numCls - nc) + " classes"); ArrayList uids = new ArrayList(); for (Iterator i = classes.iterator(); i.hasNext();) { uids.add(((Class_) i.next()).getUniqueId()); } Collections.sort(uids); // Delete last class(es) if no parent or just one class to be deleted if (parent == null || (numCls - nc) == 1) { for (int ct = nc; ct < numCls; ct++) { Long uid = (Long) uids.get(ct); for (Iterator i = classes.iterator(); i.hasNext();) { Class_ c = (Class_) i.next(); if (c.getUniqueId().equals(uid)) { deleteChildClasses(c, hibSession, 1); Class_ pc = c.getParentClass(); if (pc != null) { pc.getChildClasses().remove(c); hibSession.saveOrUpdate(pc); } i.remove(); //hibSession.delete(c); break; } } } } // Delete per parent else { cpClasses.clear(); for (Iterator i = classes.iterator(); i.hasNext();) { Class_ c = (Class_) i.next(); if (c.getParentClass() != null) { Integer classCount = (Integer) cpClasses.get(c.getParentClass().getUniqueId()); if (classCount == null) cpClasses.put(c.getParentClass().getUniqueId(), new Integer(1)); else cpClasses.put(c.getParentClass().getUniqueId(), new Integer(classCount.intValue() + 1)); } } int diff = (numCls - nc) / cpClasses.size(); Debug.debug("Deleting " + diff + " classes per current parent"); // Delete extra classes Set parentClassKeys = cpClasses.keySet(); for (Iterator ci = parentClassKeys.iterator(); ci.hasNext();) { Long parentClassId = (Long) ci.next(); Debug.debug("Deleting " + diff + " classes for parent class: " + parentClassId.toString()); uids.clear(); for (Iterator i = classes.iterator(); i.hasNext();) { Class_ c1 = (Class_) i.next(); if (c1.getParentClass().getUniqueId().equals(parentClassId)) uids.add(c1.getUniqueId()); } Collections.sort(uids); for (int ct = (uids.size() - diff); ct < uids.size(); ct++) { Long uid = (Long) uids.get(ct); for (Iterator i = classes.iterator(); i.hasNext();) { Class_ c = (Class_) i.next(); if (c.getUniqueId().equals(uid)) { deleteChildClasses(c, hibSession, 1); Class_ pc = c.getParentClass(); if (pc != null) { pc.getChildClasses().remove(c); hibSession.saveOrUpdate(pc); } i.remove(); //hibSession.delete(c); break; } } } hibSession.saveOrUpdate(subpart); hibSession.saveOrUpdate(parent); hibSession.flush(); } } hibSession.saveOrUpdate(subpart); } } // Loop through children sub-parts Vector v = sic.getSubparts(); for (int i = 0; i < v.size(); i++) { SimpleItypeConfig sic1 = (SimpleItypeConfig) v.elementAt(i); createOrUpdateClasses(request, hibSession, sic1, ioc, subpart); } } public void deleteChildClasses(Class_ c, org.hibernate.Session hibSession, int recurseLevel) { Set childClasses = c.getChildClasses(); if (childClasses == null || childClasses.size() == 0) { if (recurseLevel == 1) { Debug.debug("Deleting class (1) ... " + c.getClassLabel() + " - " + c.getUniqueId()); c.deleteAllDependentObjects(hibSession, false); hibSession.delete(c); } return; } for (Iterator cci = childClasses.iterator(); cci.hasNext();) { Class_ cc = (Class_) cci.next(); SchedulingSubpart ps = cc.getSchedulingSubpart(); Set psClasses = ps.getClasses(); for (Iterator iPs = psClasses.iterator(); iPs.hasNext();) { Class_ psCls = (Class_) iPs.next(); if (psCls.equals(cc)) { deleteChildClasses(psCls, hibSession, recurseLevel + 1); Debug.debug("Deleting class (2) ... " + cc.getClassLabel() + " - " + cc.getUniqueId()); cc.deleteAllDependentObjects(hibSession, false); hibSession.delete(cc); iPs.remove(); hibSession.saveOrUpdate(ps); hibSession.saveOrUpdate(c); break; } } cci.remove(); } Debug.debug("Deleting class (3) ... " + c.getClassLabel() + " - " + c.getUniqueId()); c.deleteAllDependentObjects(hibSession, false); hibSession.delete(c); //hibSession.flush(); } public void setParentClass(org.hibernate.Session hibSession, SchedulingSubpart subpart, SchedulingSubpart parent, int subpartNumClasses) { // Set Parent Class if (parent != null) { Set parentClasses = parent.getClasses(); int parentNumClasses = parentClasses.size(); int classesPerParent = subpartNumClasses / parentNumClasses; HashMap cpClasses = new HashMap(); for (Iterator i = parent.getClasses().iterator(); i.hasNext();) { Class_ c = (Class_) i.next(); int childClassCount = 0; Set ccl = c.getChildClasses(); if (ccl != null) { for (Iterator ci = ccl.iterator(); ci.hasNext();) { Class_ cc = (Class_) ci.next(); if (cc.getSchedulingSubpart().equals(subpart)) ++childClassCount; } } cpClasses.put(c.getUniqueId(), new Integer(childClassCount)); } ArrayList parentClassKeys = new ArrayList(cpClasses.keySet()); Collections.sort(parentClassKeys); for (Iterator ci = parentClassKeys.iterator(); ci.hasNext();) { Long parentClassId = (Long) ci.next(); int parentClassCount = ((Integer) cpClasses.get(parentClassId)).intValue(); if (classesPerParent > parentClassCount) { int addCount = classesPerParent - parentClassCount; Debug.debug("Adding " + addCount + " classes for parent class: " + parentClassId.toString()); ArrayList ccList = new ArrayList(subpart.getClasses()); Collections.sort(ccList, new ClassComparator(ClassComparator.COMPARE_BY_ID)); Iterator cci = ccList.iterator(); for (Iterator i = parentClasses.iterator(); i.hasNext();) { Class_ parentClass = (Class_) i.next(); if (parentClass.getUniqueId().equals(parentClassId)) { for (int j = 0; j < addCount; j++) { Class_ childClass = null; do { childClass = (Class_) cci.next(); } while (childClass.getParentClass() != null); childClass.setParentClass(parentClass); parentClass.addTochildClasses(childClass); hibSession.saveOrUpdate(parentClass); hibSession.saveOrUpdate(childClass); } } } } } hibSession.saveOrUpdate(parent); } } public Vector toSimpleItypeConfig(InstrOfferingConfig config) throws Exception { Vector sp = new Vector(); Set subparts = config.getSchedulingSubparts(); Iterator iterSp = subparts.iterator(); // Loop through subparts while (iterSp.hasNext()) { SchedulingSubpart subpart = (SchedulingSubpart) iterSp.next(); // Select top most subparts only if (subpart.getParentSubpart() != null) continue; // Process each subpart SimpleItypeConfig sic = toSimpleItypeConfig(config, subpart); sp.addElement(sic); } return sp; } /** * Read persistent class InstrOfferingConfig and convert it to a * representation that can be displayed * @param config InstrOfferingConfig object * @param subpart Scheduling subpart * @return SimpleItypeConfig object representing the subpart * @throws Exception */ private SimpleItypeConfig toSimpleItypeConfig(InstrOfferingConfig config, SchedulingSubpart subpart) throws Exception { ItypeDesc itype = subpart.getItype(); SimpleItypeConfig sic = new SimpleItypeConfig(itype); boolean isDisabled = setSicProps(config, subpart, sic); Set s = subpart.getChildSubparts(); Iterator iter = s.iterator(); while (iter.hasNext()) { SchedulingSubpart child = (SchedulingSubpart) iter.next(); SimpleItypeConfig childSic = toSimpleItypeConfig(config, child); boolean isDisabledChild = setSicProps(config, child, childSic); sic.addSubpart(childSic); if (isDisabledChild) isDisabled = true; } if (isDisabled) sic.setDisabled(true); return sic; } /** * Sets the class limit, min per wk and num classes properties * @param config InstrOfferingConfig object * @param subpart Scheduling subpart * @return SimpleItypeConfig object representing the subpart */ private boolean setSicProps(InstrOfferingConfig config, SchedulingSubpart subpart, SimpleItypeConfig sic) { int mnlpc = subpart.getMinClassLimit(); int mxlpc = subpart.getMaxClassLimit(); int mpw = subpart.getMinutesPerWk().intValue(); int numClasses = subpart.getNumClasses(); int numRooms = subpart.getMaxRooms(); float rc = subpart.getMaxRoomRatio(); long md = subpart.getManagingDept().getUniqueId().longValue(); boolean mixedManaged = subpart.hasMixedManagedClasses(); if (mnlpc < 0) mnlpc = config.getLimit().intValue(); if (mxlpc < 0) mxlpc = mnlpc; if (numClasses < 0) numClasses = 0; if (mixedManaged) md = Constants.MANAGED_BY_MULTIPLE_DEPTS; sic.setMinLimitPerClass(mnlpc); sic.setMaxLimitPerClass(mxlpc); sic.setMinPerWeek(mpw); sic.setNumClasses(numClasses); sic.setNumRooms(numRooms); sic.setRoomRatio(rc); sic.setSubpartId(subpart.getUniqueId().longValue()); sic.setManagingDeptId(md); // Check Permissions on subpart if (!sessionContext.hasPermission(subpart, Right.InstrOfferingConfigEditSubpart) || mixedManaged) { sic.setDisabled(true); sic.setNotOwned(true); return true; } return false; } }