edu.umd.ks.cm.util.spring.CmToSisExportAdvice.java Source code

Java tutorial

Introduction

Here is the source code for edu.umd.ks.cm.util.spring.CmToSisExportAdvice.java

Source

/**
 * Copyright 2010 The Kuali Foundation Licensed under the
 * Educational Community 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.osedu.org/licenses/ECL-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 edu.umd.ks.cm.util.spring;

import java.io.StringWriter;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;

import org.aopalliance.aop.Advice;
import org.apache.log4j.Logger;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.kuali.rice.kew.api.WorkflowDocument;
import org.kuali.rice.kew.api.WorkflowDocumentFactory;
import org.kuali.student.common.util.security.SecurityUtils;
import org.kuali.student.r1.lum.course.service.CourseServiceConstants;
import org.kuali.student.r2.common.dto.ContextInfo;
import org.kuali.student.r2.common.exceptions.DoesNotExistException;
import org.kuali.student.r1.core.statement.dto.StatementTreeViewInfo;
import org.kuali.student.r1.core.statement.service.StatementService;
import org.kuali.student.r2.core.versionmanagement.dto.VersionDisplayInfo;
import org.kuali.student.r2.lum.clu.dto.CluSetInfo;
import org.kuali.student.r2.lum.clu.service.CluService;
import org.kuali.student.r2.lum.course.dto.CourseInfo;
import org.kuali.student.r2.lum.course.service.CourseService;
import org.springframework.transaction.annotation.Transactional;

import edu.umd.ks.cm.course.service.utils.CM20;
import edu.umd.ks.cm.util.audit.CourseModifyAuditInfo;
import edu.umd.ks.cm.util.siscm.dao.SisCmDao;
import edu.umd.ks.cm.util.siscm.entity.CmToSisExportCourse;
import edu.umd.ks.cm.util.siscm.service.impl.CoreGenEdClusetMapper;

/**
 * @Author VG 10/20/11
 * @See https://issues.umd.edu/browse/KSCM-616
 * Runs after CourseService.updateCourse/createCourse/updateCourseStatement/createCourseStatement is called 
 * configured in ks-embedded-admin-context.xml 
 */

public class CmToSisExportAdvice implements Advice {
    public static final String DO_NOT_OUTPUT_TO_SIS = "_DO_NOT_OUTPUT_TO_SIS_";

    final Logger LOG = Logger.getLogger(getClass());

    private SisCmDao sisCmDao;
    private CluService luService;
    private CourseService courseService;
    private StatementService statementService;

    /**
     * Inject by Spring
     * true if we should push data data to SIS. We need this so
     * we can turn off the data push for the public instance, since
     * it will not have UMD course data in it.
     */
    private boolean enablePushToSis;
    private boolean enableWFDoc;

    private CoreGenEdClusetMapper coreGenedClusetMapper;

    public CmToSisExportAdvice() {
        super();
    }

    //  after CourseService.updateCourse/createCourse
    @Transactional(readOnly = false, noRollbackFor = { DoesNotExistException.class }, rollbackFor = {
            Throwable.class })
    public CourseInfo updateSisCourseInfo(ProceedingJoinPoint pjp, ContextInfo contextInfo) throws Throwable {

        //Check the inbound course for a special attribute flag
        //which says not to use this advice
        CourseInfo inboundCourse = (CourseInfo) pjp.getArgs()[0];

        //Remove the flag if it's there and save state
        boolean outputToSis = true;
        if (CM20.attributeInfoToMap(inboundCourse.getAttributes()).containsKey(DO_NOT_OUTPUT_TO_SIS)) {
            inboundCourse.getAttributes().remove(DO_NOT_OUTPUT_TO_SIS);
            outputToSis = false;
        }

        //Proceed with the call
        CourseInfo courseInfo = (CourseInfo) pjp.proceed();

        // If the enablePushToSis environment variable is false, do not write course to SIS
        // (allows us to turn off push for public environment)
        if (!enablePushToSis)
            outputToSis = false;

        //Only output if the course did not have that attribute
        if (outputToSis)
            doUpdateSisCourseInfo(courseInfo, contextInfo);

        // Only do the Audit if parameter passed is true KSCM-1016
        //      boolean outputToWF = true;
        //        if (!enableWFDoc)
        //           outputToWF = false;
        //      
        //      if(outputToWF)
        //         doWorkflowDocument(courseInfo); 
        // End KSCM-1016

        return courseInfo;
    }

    @Transactional(readOnly = false, noRollbackFor = { DoesNotExistException.class }, rollbackFor = {
            Throwable.class })
    public void doUpdateSisCourseInfo(CourseInfo courseInfo, ContextInfo contextInfo) {
        String state = courseInfo.getState();
        // Write courses with these states to SIS export table
        // Superseded courses must be written to ensure end term is updated in SIS
        if ("Active".equals(state) || "Retired".equals(state) || "Suspended".equals(state)
                || "Superseded".equals(state)) {
            String statusInd = "P"; // Used to be P for pending pending for sis retrival
            List<CmToSisExportCourse> coursePending = sisCmDao.getSisCourseByCrsTrmStat(courseInfo, null);
            if (coursePending.size() > 0)
                sisCmDao.updateSisCourseInfo(courseInfo, coursePending.get(0), statusInd, contextInfo);
            else
                sisCmDao.updateSisCourseInfo(courseInfo, null, statusInd, contextInfo);
        }
    }

    // after CourseService.updateCourseStatement/createCourseStatement
    @Transactional(readOnly = false, noRollbackFor = { DoesNotExistException.class }, rollbackFor = {
            Throwable.class })
    public void updateSisCourseInfoStatement(JoinPoint jp, Object retVal, ContextInfo contextInfo)
            throws Throwable {
        // If the enablePushToSis environment variable is false, do not write course to SIS
        // (allows us to turn off push for public environment)
        if (!enablePushToSis) {
            return;
        }

        StatementTreeViewInfo statement = (StatementTreeViewInfo) retVal;
        String courseId = (String) jp.getArgs()[0];
        CourseInfo courseInfo = courseService.getCourse(courseId, contextInfo);

        //Only update approved courses
        if (courseInfo != null && ("Active".equals(courseInfo.getState()) || "Retired".equals(courseInfo.getState())
                || "Suspended".equals(courseInfo.getState()) || "Superseded".equals(courseInfo.getState()))) {
            String statusInd = "P"; // pending for sis retrival
            List<CmToSisExportCourse> coursePending = sisCmDao.getSisCourseByCrsTrmStat(courseInfo, null);
            if (coursePending.size() > 0)
                sisCmDao.updateSisCourseInfo(courseInfo, coursePending.get(0), statusInd, contextInfo);
            else
                sisCmDao.updateSisCourseInfo(courseInfo, null, statusInd, contextInfo);
        }

        // Only do the Audit if parameter passed is true KSCM-1016
        boolean outputToWF = true;
        if (!enableWFDoc)
            outputToWF = false;

        //      if(outputToWF)
        //         doWorkflowDocument(courseInfo); 
        // End KSCM-1016
    }

    // before LuService.updateCluSet - what UMDCM uses on manual changes
    @Transactional(readOnly = false, noRollbackFor = { DoesNotExistException.class }, rollbackFor = {
            Throwable.class })
    public void updateSisCourseInfoCluSetUpdate(ProceedingJoinPoint pjp, ContextInfo contextInfo) throws Throwable {
        if (true) {
            return;
        }
        // If the enablePushToSis environment variable is false, do not write course to SIS
        // (allows us to turn off push for public environment)
        if (!enablePushToSis) {
            return;
        }

        Object[] args = pjp.getArgs();
        String newCluSetId = (String) args[0]; // Modified cluSetId
        CluSetInfo newCluSetInfo = (CluSetInfo) args[1]; // Modified cluSetInfo

        // Make sure it's a CluSet we care about (Hardcoded)
        String cluSetName = newCluSetInfo.getName();

        // "cluSetName" will now be a long description name (was just the code before)
        // So, get and check the new map which contains hardcoded set description names.

        Map<String, String> CoreGenCluSetCodeToDescriptionMap = coreGenedClusetMapper
                .getCodeToDescriptionMap(contextInfo);

        Boolean weCare = CoreGenCluSetCodeToDescriptionMap.containsValue(cluSetName);
        if (weCare) {

            // Obtain new Ids
            Set<String> newCluIds = new HashSet<String>(newCluSetInfo.getCluIds());
            List<String> listNewCluIds = newCluSetInfo.getCluIds();

            // Obtain old ("current") Ids via luService call         
            List<String> listOldCluIds = luService.getAllCluIdsInCluSet(newCluSetId, contextInfo);
            Set<String> oldCluIds = new HashSet<String>(listOldCluIds);

            // Removed Courses (old - new)
            Set<String> removedCluIds = new HashSet<String>(oldCluIds);
            removedCluIds.removeAll(newCluIds);
            System.out.println("Removed these clu IDs: " + removedCluIds);
            for (String cluId : removedCluIds) {
                // Translate from VerIndId to current Ver Id to get current courseInfo obj
                VersionDisplayInfo vdi = courseService
                        .getCurrentVersion(CourseServiceConstants.COURSE_NAMESPACE_URI, cluId, contextInfo);
                CourseInfo courseInfo = courseService.getCourse(vdi.getId(), contextInfo);
                //sisCmDao.updateSisCourseInfo(courseInfo, "P");//FIXME we should test to see if there is a pushed record before we update vs create
            }

            // Added Courses (new - old)
            Set<String> addedCluIds = new HashSet<String>(newCluIds);
            addedCluIds.removeAll(oldCluIds);
            System.out.println("Added these clu IDs: " + addedCluIds);
            for (String cluId : addedCluIds) {
                // Translate from VerIndId to current Ver Id to get current courseInfo obj
                VersionDisplayInfo vdi = courseService
                        .getCurrentVersion(CourseServiceConstants.COURSE_NAMESPACE_URI, cluId, contextInfo);
                CourseInfo courseInfo = courseService.getCourse(vdi.getId(), contextInfo);
                //sisCmDao.updateSisCourseInfo(courseInfo, "P");//FIXME we should test to see if there is a pushed record before we update vs create                        
            }
        } // end if weCare
    }

    // KSCM-1016
    @Transactional(readOnly = false, noRollbackFor = { DoesNotExistException.class }, rollbackFor = {
            Throwable.class })
    private void doWorkflowDocument(CourseInfo courseInfo, ContextInfo contextInfo) {
        try {
            String principalId = SecurityUtils.getCurrentPrincipalId();

            // Creating xml element with all info
            CourseModifyAuditInfo course = getCourseModifyAuditInfo(courseInfo, principalId, contextInfo);
            JAXBContext context = JAXBContext.newInstance(CourseModifyAuditInfo.class);
            Marshaller marshaller = context.createMarshaller();
            StringWriter writer = new StringWriter();
            marshaller.marshal(course, writer);
            String appContent = writer.toString();

            // Creating a document and sending to Workflow to "Final" state
            // 2.0 upgrade - based on code in KualiStudentPostProcessorBase line 119
            WorkflowDocument document = WorkflowDocumentFactory.createDocument(principalId,
                    "kuali.admin.type.course.modify");
            document.setApplicationContent(appContent);
            document.saveDocument("");
            document.approve("Audit course change to approve");
        } catch (Exception e) {
            LOG.error("Error doWorkflowDocument with courseId: " + courseInfo.getId(), e);
        }
    }

    // KSCM-1016
    private CourseModifyAuditInfo getCourseModifyAuditInfo(CourseInfo courseInfo, String principalId,
            ContextInfo contextInfo) {
        CourseModifyAuditInfo course = new CourseModifyAuditInfo();
        try {
            course.setUserId(principalId);
            course.setCluId(courseInfo.getId());
            course.setCourseInfo(courseInfo);

            String repeatable = getRepeatableCredits(CM20.attributeInfoToMap(courseInfo.getAttributes()));
            course.setRepeatableNL(repeatable);

            List<StatementTreeViewInfo> statements;
            statements = courseService.getCourseStatements(courseInfo.getId(), null, null, contextInfo);

            for (StatementTreeViewInfo statement : statements) {
                String nl = statementService.getNaturalLanguageForStatement(statement.getId(), "KUALI.RULE", "en");

                if (statement.getType().equals("kuali.statement.type.course.academicReadiness.studentEligibility"))
                    course.setStudentEligibilityNL(nl);
                else if (statement.getType().equals("kuali.statement.type.course.academicReadiness.prereq"))
                    course.setPrereqNL(nl);
                else if (statement.getType().equals("kuali.statement.type.course.academicReadiness.coreq"))
                    course.setCoreqNL(nl);
                else if (statement.getType().equals("kuali.statement.type.course.recommendedPreparation"))
                    course.setRecommendedPreparationNL(nl);
            }
            //         course.setStatementsList(statements);

        } catch (Exception e) {
            LOG.error("Error doWorkflowDocument with courseId: " + courseInfo.getId(), e);
        }

        return course;
    }

    private String getRepeatableCredits(Map<String, String> attributes) {
        String attributeNL = "";

        if (attributes.containsKey("repeatableNumCredits") && attributes.get("repeatableNumCredits").length() > 0) {
            attributeNL = "Up to " + attributes.get("repeatableNumCredits") + " credits";

            if (attributes.containsKey("repeatableIfContentDiffers")
                    && attributes.get("repeatableIfContentDiffers").equals("true"))
                attributeNL = attributeNL + " if content differs";
        }

        return attributeNL;
    }

    public SisCmDao getSisCmDao() {
        return sisCmDao;
    }

    public void setSisCmDao(SisCmDao sisCmDao) {
        this.sisCmDao = sisCmDao;
    }

    public CluService getLuService() {
        return luService;
    }

    public void setLuService(CluService luService) {
        this.luService = luService;
    }

    public CourseService getCourseService() {
        return courseService;
    }

    public void setCourseService(CourseService courseService) {
        this.courseService = courseService;
    }

    public void setStatementService(StatementService statementService) {
        this.statementService = statementService;
    }

    public boolean isEnablePushToSis() {
        return enablePushToSis;
    }

    public void setEnablePushToSis(boolean enablePushToSis) {
        this.enablePushToSis = enablePushToSis;
    }

    public boolean isEnableWFDoc() {
        return enableWFDoc;
    }

    public void setEnableWFDoc(boolean enableWFDoc) {
        this.enableWFDoc = enableWFDoc;
    }

    public void setCoreGenedClusetMapper(CoreGenEdClusetMapper coreGenedClusetMapper) {
        this.coreGenedClusetMapper = coreGenedClusetMapper;
    }
}