org.unitime.timetable.action.ClassSearchAction.java Source code

Java tutorial

Introduction

Here is the source code for org.unitime.timetable.action.ClassSearchAction.java

Source

/*
 * 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.io.OutputStream;
import java.util.Collection;
import java.util.Iterator;
import java.util.Set;
import java.util.StringTokenizer;
import java.util.TreeSet;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

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.cpsolver.coursett.model.Placement;
import org.cpsolver.coursett.model.RoomLocation;
import org.cpsolver.coursett.model.TimeLocation;
import org.hibernate.HibernateException;
import org.hibernate.Query;
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.impl.LocalizedLookupDispatchAction;
import org.unitime.localization.messages.CourseMessages;
import org.unitime.localization.messages.Messages;
import org.unitime.timetable.defaults.ApplicationProperty;
import org.unitime.timetable.defaults.SessionAttribute;
import org.unitime.timetable.form.ClassListForm;
import org.unitime.timetable.form.ClassListFormInterface;
import org.unitime.timetable.model.Assignment;
import org.unitime.timetable.model.ClassInstructor;
import org.unitime.timetable.model.Class_;
import org.unitime.timetable.model.Department;
import org.unitime.timetable.model.ItypeDesc;
import org.unitime.timetable.model.StudentClassEnrollment;
import org.unitime.timetable.model.SubjectArea;
import org.unitime.timetable.model.comparators.ClassCourseComparator;
import org.unitime.timetable.model.dao.InstructionalOfferingDAO;
import org.unitime.timetable.model.dao.SubjectAreaDAO;
import org.unitime.timetable.security.SessionContext;
import org.unitime.timetable.security.rights.Right;
import org.unitime.timetable.solver.ClassAssignmentProxy;
import org.unitime.timetable.solver.WebSolver;
import org.unitime.timetable.util.Constants;
import org.unitime.timetable.util.ExportUtils;
import org.unitime.timetable.webutil.BackTracker;
import org.unitime.timetable.webutil.pdf.PdfClassListTableBuilder;

/**
 * @author Stephanie Schluttenhofer, Tomas Muller, Zuzana Mullerova
 */
@Service("/classSearch")
public class ClassSearchAction extends LocalizedLookupDispatchAction {
    protected final static CourseMessages MSG = Localization.create(CourseMessages.class);

    @Autowired
    SessionContext sessionContext;

    /** 
     * Method execute
     * @param mapping
     * @param form
     * @param request
     * @param response
     * @return ActionForward
     * @throws HibernateException
     */

    public ActionForward searchClasses(ActionMapping mapping, ActionForm form, HttpServletRequest request,
            HttpServletResponse response) throws Exception {
        return performAction(mapping, form, request, response, "searchClasses");
    }

    public ActionForward exportPdf(ActionMapping mapping, ActionForm form, HttpServletRequest request,
            HttpServletResponse response) throws Exception {

        return performAction(mapping, form, request, response, "exportPdf");
    }

    public ActionForward performAction(ActionMapping mapping, ActionForm form, HttpServletRequest request,
            HttpServletResponse response, String action) throws Exception {

        sessionContext.checkPermission(Right.Classes);

        ClassListForm classListForm = (ClassListForm) form;

        request.setAttribute(Department.EXTERNAL_DEPT_ATTR_NAME,
                Department.findAllExternal(sessionContext.getUser().getCurrentAcademicSessionId()));

        if ("1".equals(request.getParameter("loadFilter"))) {
            setupGeneralFormFilters(sessionContext, classListForm);
            setupClassListSpecificFormFilters(sessionContext, classListForm);
        } else {
            sessionContext.getUser().setProperty("ClassList.divSec", classListForm.getDivSec() ? "1" : "0");
            sessionContext.getUser().setProperty("ClassList.demand", classListForm.getDemand() ? "1" : "0");
            sessionContext.getUser().setProperty("ClassList.demandIsVisible",
                    classListForm.getDemandIsVisible() ? "1" : "0");
            sessionContext.getUser().setProperty("ClassList.limit", classListForm.getLimit() ? "1" : "0");
            sessionContext.getUser().setProperty("ClassList.roomLimit", classListForm.getRoomLimit() ? "1" : "0");
            sessionContext.getUser().setProperty("ClassList.manager", classListForm.getManager() ? "1" : "0");
            sessionContext.getUser().setProperty("ClassList.datePattern",
                    classListForm.getDatePattern() ? "1" : "0");
            sessionContext.getUser().setProperty("ClassList.timePattern",
                    classListForm.getTimePattern() ? "1" : "0");
            sessionContext.getUser().setProperty("ClassList.instructor", classListForm.getInstructor() ? "1" : "0");
            sessionContext.getUser().setProperty("ClassList.preferences",
                    classListForm.getPreferences() ? "1" : "0");
            if (classListForm.getTimetable() != null)
                sessionContext.getUser().setProperty("ClassList.timetable",
                        classListForm.getTimetable() ? "1" : "0");
            sessionContext.getUser().setProperty("ClassList.schedulePrintNote",
                    classListForm.getSchedulePrintNote() ? "1" : "0");
            sessionContext.getUser().setProperty("ClassList.note", classListForm.getNote() ? "1" : "0");
            if (classListForm.getExams() != null)
                sessionContext.getUser().setProperty("ClassList.exams", classListForm.getExams() ? "1" : "0");
            sessionContext.getUser().setProperty("ClassList.sortBy", classListForm.getSortBy());
            sessionContext.getUser().setProperty("ClassList.filterAssignedRoom",
                    classListForm.getFilterAssignedRoom());
            sessionContext.getUser().setProperty("ClassList.filterInstructor", classListForm.getFilterInstructor());
            sessionContext.getUser().setProperty("ClassList.filterManager", classListForm.getFilterManager());
            sessionContext.getUser().setProperty("ClassList.filterIType", classListForm.getFilterIType());
            sessionContext.getUser().setProperty("ClassList.filterDayCode",
                    String.valueOf(classListForm.getFilterDayCode()));
            sessionContext.getUser().setProperty("ClassList.filterStartSlot",
                    String.valueOf(classListForm.getFilterStartSlot()));
            sessionContext.getUser().setProperty("ClassList.filterLength",
                    String.valueOf(classListForm.getFilterLength()));
            sessionContext.getUser().setProperty("ClassList.sortByKeepSubparts",
                    String.valueOf(classListForm.getSortByKeepSubparts()));
            sessionContext.getUser().setProperty("ClassList.showCrossListedClasses",
                    String.valueOf(classListForm.getShowCrossListedClasses()));
        }

        if (!sessionContext.hasPermission(Right.Examinations))
            classListForm.setExams(null);

        classListForm.setSubjectAreas(SubjectArea.getUserSubjectAreas(sessionContext.getUser()));
        classListForm
                .setClasses(getClasses(classListForm, WebSolver.getClassAssignmentProxy(request.getSession())));

        Collection classes = classListForm.getClasses();
        if (classes.isEmpty()) {
            ActionMessages errors = new ActionMessages();
            errors.add("searchResult", new ActionMessage("errors.generic", MSG.errorNoRecords()));
            saveErrors(request, errors);
            return mapping.findForward("showClassSearch");
        } else {
            StringBuffer ids = new StringBuffer();
            StringBuffer names = new StringBuffer();
            StringBuffer subjIds = new StringBuffer();
            for (int i = 0; i < classListForm.getSubjectAreaIds().length; i++) {
                if (i > 0) {
                    names.append(",");
                    subjIds.append(",");
                }
                ids.append("&subjectAreaIds=" + classListForm.getSubjectAreaIds()[i]);
                subjIds.append(classListForm.getSubjectAreaIds()[i]);
                names.append(((new SubjectAreaDAO()).get(new Long(classListForm.getSubjectAreaIds()[i])))
                        .getSubjectAreaAbbreviation());
            }
            sessionContext.setAttribute(SessionAttribute.ClassesSubjectAreas, subjIds);
            sessionContext.setAttribute(SessionAttribute.ClassesCourseNumber, classListForm.getCourseNbr());

            if ("exportPdf".equals(action)) {
                OutputStream out = ExportUtils.getPdfOutputStream(response, "classes");

                new PdfClassListTableBuilder().pdfTableForClasses(out,
                        WebSolver.getClassAssignmentProxy(request.getSession()),
                        WebSolver.getExamSolver(request.getSession()), classListForm, sessionContext);

                out.flush();
                out.close();

                return null;
            }

            BackTracker.markForBack(request,
                    "classSearch.do?doit=Search&loadFilter=1" + ids + "&courseNbr=" + classListForm.getCourseNbr(),
                    MSG.backClasses(names
                            + (classListForm.getCourseNbr() == null || classListForm.getCourseNbr().length() == 0
                                    ? ""
                                    : " " + classListForm.getCourseNbr())),
                    true, true);

            return mapping.findForward("showClassList");
        }
    }

    public static void setupGeneralFormFilters(SessionContext sessionContext, ClassListFormInterface form) {
        form.setSortBy(sessionContext.getUser().getProperty("ClassList.sortBy",
                ClassCourseComparator.getName(ClassCourseComparator.SortBy.NAME)));
        form.setFilterAssignedRoom(sessionContext.getUser().getProperty("ClassList.filterAssignedRoom", ""));
        form.setFilterManager(sessionContext.getUser().getProperty("ClassList.filterManager", ""));
        form.setFilterIType(sessionContext.getUser().getProperty("ClassList.filterIType", ""));
        form.setFilterDayCode(
                Integer.parseInt(sessionContext.getUser().getProperty("ClassList.filterDayCode", "-1")));
        form.setFilterStartSlot(
                Integer.parseInt(sessionContext.getUser().getProperty("ClassList.filterStartSlot", "-1")));
        form.setFilterLength(
                Integer.parseInt(sessionContext.getUser().getProperty("ClassList.filterLength", "-1")));
        form.setSortByKeepSubparts(
                "1".equals(sessionContext.getUser().getProperty("ClassList.sortByKeepSubparts", "1")));
        form.setShowCrossListedClasses(
                "1".equals(sessionContext.getUser().getProperty("ClassList.showCrossListedClasses", "0")));

    }

    public static void setupClassListSpecificFormFilters(SessionContext sessionContext, ClassListForm form) {
        form.setDivSec("1".equals(sessionContext.getUser().getProperty("ClassList.divSec", "0")));
        form.setLimit("1".equals(sessionContext.getUser().getProperty("ClassList.limit", "1")));
        form.setRoomLimit("1".equals(sessionContext.getUser().getProperty("ClassList.roomLimit", "1")));
        form.setManager("1".equals(sessionContext.getUser().getProperty("ClassList.manager", "1")));
        form.setDatePattern("1".equals(sessionContext.getUser().getProperty("ClassList.datePattern", "1")));
        form.setTimePattern("1".equals(sessionContext.getUser().getProperty("ClassList.timePattern", "1")));
        form.setInstructor("1".equals(sessionContext.getUser().getProperty("ClassList.instructor", "1")));
        form.setPreferences("1".equals(sessionContext.getUser().getProperty("ClassList.preferences", "1")));
        form.setTimetable("1".equals(sessionContext.getUser().getProperty("ClassList.timetable", "1")));
        form.setFilterInstructor(sessionContext.getUser().getProperty("ClassList.filterInstructor", ""));
        form.setSchedulePrintNote(
                "1".equals(sessionContext.getUser().getProperty("ClassList.schedulePrintNote", "1")));
        form.setNote("1".equals(sessionContext.getUser().getProperty("ClassList.note", "0")));
        form.setExams("1".equals(sessionContext.getUser().getProperty("ClassList.exams", "0")));
        if (StudentClassEnrollment.sessionHasEnrollments(sessionContext.getUser().getCurrentAcademicSessionId())) {
            form.setDemandIsVisible(true);
            form.setDemand("1".equals(sessionContext.getUser().getProperty("ClassList.demand", "1")));
        } else {
            form.setDemandIsVisible(false);
            form.setDemand(false);
        }

    }

    public static Set getClasses(ClassListFormInterface form, ClassAssignmentProxy classAssignmentProxy) {
        org.hibernate.Session hibSession = (new InstructionalOfferingDAO()).getSession();

        boolean doFilterManager = form.getFilterManager() != null && form.getFilterManager().length() > 0;
        Long filterManager = (doFilterManager ? Long.valueOf(form.getFilterManager()) : null);

        boolean fetchStructure = true;
        boolean fetchCredits = false;//form.getCredit().booleanValue();
        boolean fetchInstructors = false;//form.getInstructor().booleanValue();
        boolean fetchPreferences = false;//form.getPreferences().booleanValue() || form.getTimePattern().booleanValue();
        boolean fetchAssignments = false;//(form.getTimetable()!=null && form.getTimetable().booleanValue());

        String[] subjectIds = form.getSubjectAreaIds();
        if (subjectIds != null && subjectIds.length > 0) {
            StringBuffer query = new StringBuffer();
            query.append("select c, co from Class_ as c ");

            if (fetchStructure) {
                query.append("left join fetch c.childClasses as cc ");
                query.append("left join fetch c.schedulingSubpart as ss ");
                query.append("left join fetch ss.childSubparts as css ");
                query.append("left join fetch ss.instrOfferingConfig as ioc ");
                query.append("left join fetch ioc.instructionalOffering as io ");
                query.append("left join fetch io.courseOfferings as cox ");
            }

            if (fetchCredits)
                query.append("left join fetch ss.creditConfigs as ssc ");

            if (fetchPreferences || fetchInstructors) {
                query.append("left join fetch c.classInstructors as ci ");
                query.append("left join fetch ci.instructor as di ");
            }

            if (fetchAssignments) {
                query.append("left join fetch c.assignments as ca ");
                query.append("left join fetch ca.rooms as car ");
            }

            if (fetchPreferences) {
                query.append("left join fetch c.preferences as cp ");
                query.append("left join fetch ss.preferences as ssp ");
                query.append("left join fetch di.preferences as dip ");
            }

            query.append(
                    "inner join c.schedulingSubpart.instrOfferingConfig.instructionalOffering.courseOfferings as co ");
            query.append(" where co.subjectArea.uniqueId in ( ");
            boolean first = true;
            for (int i = 0; i < subjectIds.length; i++) {
                if (!first) {
                    query.append(", ");
                } else {
                    first = false;
                }
                query.append(subjectIds[i]);
            }
            query.append(") ");
            if (form.getCourseNbr() != null && form.getCourseNbr().length() > 0) {
                String courseNbr = form.getCourseNbr();
                query.append(" and co.courseNbr ");
                if (courseNbr.indexOf('*') >= 0) {
                    query.append(" like '");
                    courseNbr = courseNbr.replace('*', '%');
                } else {
                    query.append(" = '");
                }
                if (ApplicationProperty.CourseOfferingNumberUpperCase.isTrue())
                    courseNbr = courseNbr.toUpperCase();
                query.append(courseNbr);
                query.append("'  ");
            }

            if (doFilterManager) {
                if (filterManager.longValue() < 0) { //all departmental
                    query.append(" and (c.managingDept is null or c.managingDept in co.subjectArea.department)");
                } else {
                    query.append(" and c.managingDept = " + filterManager);
                }
            }

            if (!form.getShowCrossListedClasses()) {
                query.append(" and co.isControl = true ");
            }
            Query q = hibSession.createQuery(query.toString());
            q.setFetchSize(1000);
            q.setCacheable(true);
            TreeSet ts = new TreeSet(new ClassCourseComparator(form.getSortBy(), classAssignmentProxy,
                    form.getSortByKeepSubparts()));
            long sTime = new java.util.Date().getTime();

            boolean doFilterInstructor = form.getFilterInstructor() != null
                    && form.getFilterInstructor().length() > 0;
            String filterInstructor = (doFilterInstructor ? form.getFilterInstructor().toUpperCase() : null);

            boolean doFilterAssignedRoom = form.getFilterAssignedRoom() != null
                    && form.getFilterAssignedRoom().length() > 0;
            String filterAssignedRoom = (doFilterAssignedRoom ? form.getFilterAssignedRoom().toUpperCase() : null);

            boolean doFilterIType = form.getFilterIType() != null && form.getFilterIType().length() > 0;
            Integer filterIType = (doFilterIType ? Integer.valueOf(form.getFilterIType()) : null);

            boolean doFilterAssignedTime = ((form.getFilterDayCode() >= 0 && form.getFilterStartSlot() >= 0
                    && form.getFilterLength() >= 0)
                    || (form.getFilterDayCode() > 0 && form.getFilterStartSlot() < 0
                            && form.getFilterLength() <= 0));
            TimeLocation filterAssignedTime = (doFilterAssignedTime
                    ? new TimeLocation((form.getFilterDayCode() == 0 ? 255 : form.getFilterDayCode()),
                            (form.getFilterStartSlot() < 0 ? 0 : form.getFilterStartSlot()),
                            (form.getFilterStartSlot() < 0 ? Constants.SLOTS_PER_DAY
                                    : Math.max(5, Constants.SLOT_LENGTH_MIN + form.getFilterLength() - 1)
                                            / Constants.SLOT_LENGTH_MIN),
                            0, 0, null, null, null, 0)
                    : null);
            // days, start time & length selected -> create appropriate time location
            // days, start time selected -> create appropriate time location with 1 slot length
            // start time & length selected -> create time location all days with given start time and length
            // only start time selected -> create time location all days with given start time and 1 slot length
            // only days selected -> create time location of given days all day long (all location assigned in the given days overlap)

            Debug.debug(" --- Filter classes ---");
            for (Iterator i = q.list().iterator(); i.hasNext();) {
                Object[] o = (Object[]) i.next();
                Class_ c = (Class_) o[0];
                if (doFilterInstructor) {
                    boolean filterLine = true;
                    for (Iterator j = c.getClassInstructors().iterator(); j.hasNext();) {
                        ClassInstructor ci = (ClassInstructor) j.next();
                        StringTokenizer stk = new StringTokenizer(filterInstructor, " ,");
                        boolean containsInstructor = true;
                        while (stk.hasMoreTokens()) {
                            String token = stk.nextToken();
                            boolean containsToken = false;
                            if (ci.getInstructor().getFirstName() != null
                                    && ci.getInstructor().getFirstName().toUpperCase().indexOf(token) >= 0)
                                containsToken = true;
                            if (!containsToken && ci.getInstructor().getMiddleName() != null
                                    && ci.getInstructor().getMiddleName().toUpperCase().indexOf(token) >= 0)
                                containsToken = true;
                            if (!containsToken && ci.getInstructor().getLastName() != null
                                    && ci.getInstructor().getLastName().toUpperCase().indexOf(token) >= 0)
                                containsToken = true;
                            if (!containsToken) {
                                containsInstructor = false;
                                break;
                            }
                        }
                        if (containsInstructor) {
                            filterLine = false;
                            break;
                        }
                    }
                    if (filterLine) {
                        continue;
                    }
                }

                if (doFilterIType) {
                    ItypeDesc itype = c.getSchedulingSubpart().getItype();
                    boolean match = false;
                    while (!match && itype != null) {
                        match = itype.getItype().equals(filterIType);
                        itype = itype.getParent();
                    }
                    if (!match) {
                        continue;
                    }
                }

                if (doFilterAssignedTime) {
                    try {
                        Assignment a = classAssignmentProxy.getAssignment(c);
                        if (a == null) {
                            continue;
                        }
                        Placement p = a.getPlacement();
                        if (p == null) {
                            continue;
                        }
                        TimeLocation t = p.getTimeLocation();
                        if (t == null) {
                            continue;
                        }
                        boolean overlap = t.shareDays(filterAssignedTime) && t.shareHours(filterAssignedTime);
                        if (!overlap) {
                            continue;
                        }
                    } catch (Exception e) {
                        continue;
                    }
                }

                if (doFilterAssignedRoom) {
                    try {
                        Assignment a = classAssignmentProxy.getAssignment(c);
                        if (a == null) {
                            continue;
                        }
                        Placement p = a.getPlacement();
                        if (p == null || p.getNrRooms() <= 0) {
                            continue;
                        }
                        boolean filterLine = true;
                        if (p.isMultiRoom()) {
                            for (RoomLocation r : p.getRoomLocations()) {
                                if (r.getName().toUpperCase().indexOf(filterAssignedRoom) >= 0) {
                                    filterLine = false;
                                    break;
                                }
                            }
                        } else {
                            if (p.getRoomLocation().getName().toUpperCase().indexOf(filterAssignedRoom) >= 0) {
                                filterLine = false;
                            }
                        }
                        if (filterLine) {
                            continue;
                        }
                    } catch (Exception e) {
                        continue;
                    }
                }

                ts.add(o);
            }

            long eTime = new java.util.Date().getTime();
            Debug.debug("fetch time = " + (eTime - sTime));
            Debug.debug("rows = " + ts.size());
            return (ts);

        } else {
            return (new TreeSet());
        }

    }

    @Override
    protected Messages getMessages() {
        return MSG;
    }

}