org.unitime.timetable.server.solver.AssignedClassesBackend.java Source code

Java tutorial

Introduction

Here is the source code for org.unitime.timetable.server.solver.AssignedClassesBackend.java

Source

/*
 * Licensed to The Apereo Foundation under one or more contributor license
 * agreements. See the NOTICE file distributed with this work for
 * additional information regarding copyright ownership.
 *
 * The Apereo Foundation licenses this file to you under the Apache License,
 * Version 2.0 (the "License"); you may not use this file except in
 * compliance with the License. You may obtain a copy of the License at:
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * 
*/
package org.unitime.timetable.server.solver;

import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;

import org.hibernate.ObjectNotFoundException;
import org.hibernate.type.LongType;
import org.springframework.beans.factory.annotation.Autowired;
import org.unitime.localization.impl.Localization;
import org.unitime.timetable.defaults.ApplicationProperty;
import org.unitime.timetable.defaults.SessionAttribute;
import org.unitime.timetable.defaults.UserProperty;
import org.unitime.timetable.gwt.command.client.GwtRpcException;
import org.unitime.timetable.gwt.command.server.GwtRpcImplementation;
import org.unitime.timetable.gwt.command.server.GwtRpcImplements;
import org.unitime.timetable.gwt.resources.GwtMessages;
import org.unitime.timetable.gwt.shared.TableInterface;
import org.unitime.timetable.gwt.shared.CourseTimetablingSolverInterface.AssignedClassesRequest;
import org.unitime.timetable.gwt.shared.CourseTimetablingSolverInterface.AssignedClassesResponse;
import org.unitime.timetable.gwt.shared.SolverInterface.SolverType;
import org.unitime.timetable.gwt.shared.TableInterface.TableCellInterface;
import org.unitime.timetable.gwt.shared.TableInterface.TableCellMulti;
import org.unitime.timetable.gwt.shared.TableInterface.TableHeaderIterface;
import org.unitime.timetable.gwt.shared.TableInterface.TableRowInterface;
import org.unitime.timetable.model.Assignment;
import org.unitime.timetable.model.Class_;
import org.unitime.timetable.model.CourseOffering;
import org.unitime.timetable.model.PreferenceLevel;
import org.unitime.timetable.model.Solution;
import org.unitime.timetable.model.SolverGroup;
import org.unitime.timetable.model.dao.Class_DAO;
import org.unitime.timetable.model.dao.SolutionDAO;
import org.unitime.timetable.security.SessionContext;
import org.unitime.timetable.security.rights.Right;
import org.unitime.timetable.solver.SolverProxy;
import org.unitime.timetable.solver.interactive.ClassAssignmentDetails;
import org.unitime.timetable.solver.interactive.SuggestionsModel;
import org.unitime.timetable.solver.interactive.ClassAssignmentDetails.TimeInfo;
import org.unitime.timetable.solver.service.SolverService;
import org.unitime.timetable.solver.ui.AssignmentPreferenceInfo;
import org.unitime.timetable.util.Constants;
import org.unitime.timetable.webutil.BackTracker;

/**
 * @author Tomas Muller
 */
@GwtRpcImplements(AssignedClassesRequest.class)
public class AssignedClassesBackend
        implements GwtRpcImplementation<AssignedClassesRequest, AssignedClassesResponse> {
    protected static GwtMessages MESSAGES = Localization.create(GwtMessages.class);
    protected static DecimalFormat sDF = new DecimalFormat("0.###", new java.text.DecimalFormatSymbols(Locale.US));

    @Autowired
    SolverService<SolverProxy> courseTimetablingSolverService;

    public static boolean isAllSubjects(String subjects) {
        if (subjects == null || subjects.isEmpty() || subjects.equals(Constants.ALL_OPTION_VALUE))
            return true;
        for (String id : subjects.split(","))
            if (Constants.ALL_OPTION_VALUE.equals(id))
                return true;
        return false;
    }

    public static int getOrder(TimeInfo time) {
        int firstWorkDay = ApplicationProperty.TimePatternFirstDayOfWeek.intValue();
        int days = time.getDays();
        if (firstWorkDay != 0) {
            days = time.getDays() << firstWorkDay;
            days = (days & 127) + (days >> 7);
        }
        return (Constants.sDayCode2Order[days] << 18) + (time.getStartSlot() << 11) + time.getMin();
    }

    @Override
    public AssignedClassesResponse execute(AssignedClassesRequest request, SessionContext context) {
        context.checkPermission(Right.AssignedClasses);
        AssignedClassesResponse response = new AssignedClassesResponse();

        context.getUser().setProperty("SuggestionsModel.simpleMode",
                request.getFilter().getParameterValue("simpleMode"));
        boolean simple = "1".equals(request.getFilter().getParameterValue("simpleMode"));
        SuggestionsModel model = (SuggestionsModel) context.getAttribute(SessionAttribute.SuggestionsModel);
        if (model != null)
            model.setSimpleMode(simple);

        SolverProxy solver = courseTimetablingSolverService.getSolver();
        String subjects = request.getFilter().getParameterValue("subjectArea");
        context.setAttribute(SessionAttribute.OfferingsSubjectArea,
                isAllSubjects(subjects) ? Constants.ALL_OPTION_VALUE
                        : request.getFilter().getParameterValue("subjectArea"));
        String instructorNameFormat = UserProperty.NameFormat.get(context.getUser());

        String solutionIdsStr = (String) context.getAttribute(SessionAttribute.SelectedSolution);
        if (solver == null) {
            if (solutionIdsStr == null || solutionIdsStr.isEmpty()) {
                for (SolverGroup g : SolverGroup.getUserSolverGroups(context.getUser())) {
                    for (Long id : (List<Long>) SolutionDAO.getInstance().getSession().createQuery(
                            "select s.uniqueId from Solution s where s.commited = true and s.owner = :groupId")
                            .setLong("groupId", g.getUniqueId()).setCacheable(true).list()) {
                        if (solutionIdsStr == null)
                            solutionIdsStr = id.toString();
                        else
                            solutionIdsStr += (solutionIdsStr.isEmpty() ? "" : ",") + id;
                    }
                }
            }
            if (solutionIdsStr == null || solutionIdsStr.isEmpty())
                throw new GwtRpcException(MESSAGES.errorAssignedClassesNoSolution());
        }

        List<ClassAssignmentDetails> assignedClasses = new ArrayList<ClassAssignmentDetails>();
        if (isAllSubjects(subjects)) {
            if (solver != null) {
                assignedClasses = solver.getAssignedClasses();
            } else {
                org.hibernate.Session hibSession = SolutionDAO.getInstance().getSession();
                for (String solutionId : solutionIdsStr.split(",")) {
                    Solution solution = SolutionDAO.getInstance().get(Long.valueOf(solutionId));
                    try {
                        for (Assignment a : solution.getAssignments()) {
                            assignedClasses.add(new ClassAssignmentDetails(solution, a, false, hibSession,
                                    instructorNameFormat));
                        }
                    } catch (ObjectNotFoundException e) {
                        hibSession.refresh(solution);
                        for (Assignment a : solution.getAssignments()) {
                            assignedClasses.add(new ClassAssignmentDetails(solution, a, false, hibSession,
                                    instructorNameFormat));
                        }
                    }
                }
            }
        } else {
            org.hibernate.Session hibSession = SolutionDAO.getInstance().getSession();
            for (String id : subjects.split(",")) {
                String prefix = request.getFilter().getParameter("subjectArea").getOptionText(id) + " ";
                if (solver != null) {
                    assignedClasses.addAll(solver.getAssignedClasses(prefix));
                } else {
                    for (String solutionId : solutionIdsStr.split(",")) {
                        Solution solution = SolutionDAO.getInstance().get(Long.valueOf(solutionId));
                        try {
                            for (Assignment a : solution.getAssignments()) {
                                if (prefix != null && !a.getClassName().startsWith(prefix))
                                    continue;
                                assignedClasses.add(new ClassAssignmentDetails(solution, a, false, hibSession,
                                        instructorNameFormat));
                            }
                        } catch (ObjectNotFoundException e) {
                            hibSession.refresh(solution);
                            for (Assignment a : solution.getAssignments()) {
                                if (prefix != null && !a.getClassName().startsWith(prefix))
                                    continue;
                                assignedClasses.add(new ClassAssignmentDetails(solution, a, false, hibSession,
                                        instructorNameFormat));
                            }
                        }
                    }
                }
            }
        }

        Collections.sort(assignedClasses);
        for (ClassAssignmentDetails ca : assignedClasses) {
            AssignmentPreferenceInfo ci = ca.getInfo();

            TableCellMulti studentConfs = new TableCellMulti();
            studentConfs.add(dispNumber(ci.getNrStudentConflicts()));

            if (ci.getNrCommitedStudentConflicts() != 0) {
                if (studentConfs.getNrChunks() <= 1)
                    studentConfs.add(" (");
                else
                    studentConfs.add(",");
                studentConfs.add(dispNumber(ci.getNrCommitedStudentConflicts())
                        .setFormattedValue("c" + ci.getNrCommitedStudentConflicts()));
            }
            if (ci.getNrDistanceStudentConflicts() != 0) {
                if (studentConfs.getNrChunks() <= 1)
                    studentConfs.add(" (");
                else
                    studentConfs.add(",");
                studentConfs.add(dispNumber(ci.getNrDistanceStudentConflicts())
                        .setFormattedValue("d" + ci.getNrDistanceStudentConflicts()));
            }
            if (ci.getNrHardStudentConflicts() != 0) {
                if (studentConfs.getNrChunks() <= 1)
                    studentConfs.add(" (");
                else
                    studentConfs.add(",");
                studentConfs.add(dispNumber(ci.getNrHardStudentConflicts())
                        .setFormattedValue("h" + ci.getNrHardStudentConflicts()));
            }
            if (studentConfs.getNrChunks() > 1)
                studentConfs.add(")");

            TableInterface.TableCellRooms rooms = new TableInterface.TableCellRooms();
            if (ca.getAssignedRoom() != null) {
                for (int i = 0; i < ca.getAssignedRoom().length; i++) {
                    rooms.add(ca.getAssignedRoom()[i].getName(), ca.getAssignedRoom()[i].getColor(),
                            ca.getAssignedRoom()[i].getId(),
                            PreferenceLevel.int2string(ca.getAssignedRoom()[i].getPref()));
                }
            } else if (ca.getRoom() != null) {
                for (int i = 0; i < ca.getRoom().length; i++) {
                    rooms.add(ca.getRoom()[i].getName(), ca.getRoom()[i].getColor(), ca.getRoom()[i].getId(),
                            PreferenceLevel.int2string(ca.getRoom()[i].getPref()));
                }
            }
            TableInterface.TableCellItems instructors = new TableInterface.TableCellItems();
            if (ca.getInstructor() != null)
                for (int i = 0; i < ca.getInstructor().length; i++) {
                    instructors.add(ca.getInstructor()[i].getName(), ca.getInstructor()[i].getColor(),
                            ca.getInstructor()[i].getId());
                }
            TimeInfo time = (ca.getAssignedTime() != null ? ca.getAssignedTime() : ca.getTime());

            boolean showClassDetail = (solver == null
                    && context.hasPermission(ca.getClazz().getClassId(), "Class_", Right.ClassDetail));

            if (simple)
                response.addRow(new TableRowInterface(ca.getClazz().getClassId(),
                        (showClassDetail ? "classDetail.do?cid=" + ca.getClazz().getClassId()
                                : "gwt.jsp?page=suggestions&menu=hide&id=" + ca.getClazz().getClassId()),
                        (showClassDetail ? null : MESSAGES.dialogSuggestions()),
                        new TableInterface.TableCellClassName(ca.getClazz().getName())
                                .setColor(PreferenceLevel.prolog2color(ca.getClazz().getPref())),
                        new TableCellInterface(time.getDatePatternName())
                                .setColor(PreferenceLevel.int2color(time.getDatePatternPreference())),
                        new TableInterface.TableCellTime(
                                time.getDaysName() + " " + time.getStartTime() + " - " + time.getEndTime())
                                        .setOrder(getOrder(time))
                                        .setId(ca.getClazz().getClassId() + "," + time.getDays() + ","
                                                + time.getStartSlot())
                                        .setColor(PreferenceLevel.int2color(time.getPref())),
                        rooms, instructors, studentConfs));
            else
                response.addRow(new TableRowInterface(ca.getClazz().getClassId(),
                        (showClassDetail ? "classDetail.do?cid=" + ca.getClazz().getClassId()
                                : "gwt.jsp?page=suggestions&menu=hide&id=" + ca.getClazz().getClassId()),
                        (showClassDetail ? null : MESSAGES.dialogSuggestions()),
                        new TableInterface.TableCellClassName(ca.getClazz().getName())
                                .setColor(PreferenceLevel.prolog2color(ca.getClazz().getPref())),
                        new TableCellInterface(time.getDatePatternName())
                                .setColor(PreferenceLevel.int2color(time.getDatePatternPreference())),
                        new TableInterface.TableCellTime(
                                time.getDaysName() + " " + time.getStartTime() + " - " + time.getEndTime())
                                        .setOrder(getOrder(time))
                                        .setId(ca.getClazz().getClassId() + "," + time.getDays() + ","
                                                + time.getStartSlot())
                                        .setColor(PreferenceLevel.int2color(time.getPref())),
                        rooms, instructors, studentConfs, dispNumber(ci.getTimePreference()),
                        dispNumber(ci.sumRoomPreference()), dispNumber(ci.getGroupConstraintPref()),
                        dispNumber(ci.getBtbInstructorPreference()), dispNumber(ci.getUselessHalfHours()),
                        dispNumber(ci.getTooBigRoomPreference()), dispNumber(ci.getDeptBalancPenalty()),
                        dispNumber(ci.getSpreadPenalty()), dispNumber(ci.getPerturbationPenalty())));
        }

        if (simple)
            response.setHeader(new TableHeaderIterface(MESSAGES.colClass()),
                    new TableHeaderIterface(MESSAGES.colDate()), new TableHeaderIterface(MESSAGES.colTime()),
                    new TableHeaderIterface(MESSAGES.colRoom()), new TableHeaderIterface(MESSAGES.colInstructor()),
                    new TableHeaderIterface(MESSAGES.colNrStudentConflicts()));
        else
            response.setHeader(new TableHeaderIterface(MESSAGES.colClass()),
                    new TableHeaderIterface(MESSAGES.colDate()), new TableHeaderIterface(MESSAGES.colTime()),
                    new TableHeaderIterface(MESSAGES.colRoom()), new TableHeaderIterface(MESSAGES.colInstructor()),
                    new TableHeaderIterface(MESSAGES.colShortStudentConflicts()),
                    new TableHeaderIterface(MESSAGES.colShortTimePref()),
                    new TableHeaderIterface(MESSAGES.colShortRoomPref()),
                    new TableHeaderIterface(MESSAGES.colShortDistPref()),
                    new TableHeaderIterface(MESSAGES.colShortInstructorBtbPref()),
                    new TableHeaderIterface(MESSAGES.colShortUselessHalfHours()),
                    new TableHeaderIterface(MESSAGES.colShortTooBigRooms()),
                    new TableHeaderIterface(MESSAGES.colShortDepartmentBalance()),
                    new TableHeaderIterface(MESSAGES.colShortSameSubpartBalance()),
                    new TableHeaderIterface(MESSAGES.colShortPerturbations()));

        SolverPageBackend.fillSolverWarnings(context, solver, SolverType.COURSE, response);
        BackTracker.markForBack(context, "gwt.jsp?page=assignedClasses", MESSAGES.pageAssignedClasses(), true,
                true);

        if (ApplicationProperty.TimeGridShowCrosslists.isTrue())
            addCrosslistedNames(response, ApplicationProperty.SolverShowClassSufix.isTrue(),
                    ApplicationProperty.SolverShowConfiguratioName.isTrue());

        return response;
    }

    public TableCellInterface dispNumber(int value) {
        return new TableCellInterface<Integer>(value).setColor(value < 0 ? "green" : value > 0 ? "red" : null);
    }

    public TableCellInterface dispNumber(double value) {
        return new TableCellInterface<Double>(value, sDF.format(value))
                .setColor(value < 0 ? "green" : value > 0 ? "red" : null);
    }

    public static void addCrosslistedNames(TableInterface table, boolean showClassSuffix, boolean showConfigNames) {
        Map<Long, TableInterface.TableRowInterface> id2row = new HashMap<Long, TableInterface.TableRowInterface>();
        for (TableInterface.TableRowInterface row : table.getRows()) {
            if (row.hasId())
                id2row.put(row.getId(), row);
        }
        if (id2row.isEmpty())
            return;
        if (id2row.size() <= 1000) {
            for (Object[] o : (List<Object[]>) Class_DAO.getInstance().getSession().createQuery(
                    "select c, co from Class_ c inner join c.schedulingSubpart.instrOfferingConfig.instructionalOffering.courseOfferings co where "
                            + "co.isControl = false and c.uniqueId in :classIds order by co.subjectAreaAbbv, co.courseNbr")
                    .setParameterList("classIds", id2row.keySet(), LongType.INSTANCE).setCacheable(true).list()) {
                Class_ clazz = (Class_) o[0];
                CourseOffering course = (CourseOffering) o[1];
                TableInterface.TableRowInterface row = id2row.get(clazz.getUniqueId());
                if (row != null)
                    ((TableInterface.TableCellClassName) row.getCell(0))
                            .addAlternative(clazz.getClassLabel(course, showClassSuffix, showConfigNames));
            }
        } else {
            List<Long> ids = new ArrayList<Long>(1000);
            for (Long id : id2row.keySet()) {
                ids.add(id);
                if (ids.size() == 1000) {
                    for (Object[] o : (List<Object[]>) Class_DAO.getInstance().getSession().createQuery(
                            "select c, co from Class_ c inner join c.schedulingSubpart.instrOfferingConfig.instructionalOffering.courseOfferings co where "
                                    + "co.isControl = false and c.uniqueId in :classIds order by co.subjectAreaAbbv, co.courseNbr")
                            .setParameterList("classIds", ids, LongType.INSTANCE).setCacheable(true).list()) {
                        Class_ clazz = (Class_) o[0];
                        CourseOffering course = (CourseOffering) o[1];
                        TableInterface.TableRowInterface row = id2row.get(clazz.getUniqueId());
                        if (row != null)
                            ((TableInterface.TableCellClassName) row.getCell(0))
                                    .addAlternative(clazz.getClassLabel(course, showClassSuffix, showConfigNames));
                    }
                    ids.clear();
                }
            }
            if (!ids.isEmpty()) {
                for (Object[] o : (List<Object[]>) Class_DAO.getInstance().getSession().createQuery(
                        "select c, co from Class_ c inner join c.schedulingSubpart.instrOfferingConfig.instructionalOffering.courseOfferings co where "
                                + "co.isControl = false and c.uniqueId in :classIds order by co.subjectAreaAbbv, co.courseNbr")
                        .setParameterList("classIds", ids, LongType.INSTANCE).setCacheable(true).list()) {
                    Class_ clazz = (Class_) o[0];
                    CourseOffering course = (CourseOffering) o[1];
                    TableInterface.TableRowInterface row = id2row.get(clazz.getUniqueId());
                    if (row != null)
                        ((TableInterface.TableCellClassName) row.getCell(0))
                                .addAlternative(clazz.getClassLabel(course, showClassSuffix, showConfigNames));
                }
            }
        }
    }
}