org.opentestsystem.authoring.testauth.service.impl.ScoringRuleServiceImpl.java Source code

Java tutorial

Introduction

Here is the source code for org.opentestsystem.authoring.testauth.service.impl.ScoringRuleServiceImpl.java

Source

/*******************************************************************************
 * Educational Online Test Delivery System
 * Copyright (c) 2013 American Institutes for Research
 * 
 * Distributed under the AIR Open Source License, Version 1.0
 * See accompanying file AIR-License-1_0.txt or at
 * http://www.smarterapp.org/documents/American_Institutes_for_Research_Open_Source_Software_License.pdf
 ******************************************************************************/
package org.opentestsystem.authoring.testauth.service.impl;

import static org.opentestsystem.authoring.testauth.config.TestAuthUtil.paramArray;
import static org.opentestsystem.authoring.testauth.publish.PublisherUtil.validateConversionListFile;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang.StringUtils;
import org.opentestsystem.authoring.testauth.domain.AffinityGroup;
import org.opentestsystem.authoring.testauth.domain.Assessment;
import org.opentestsystem.authoring.testauth.domain.BlueprintDenotationType;
import org.opentestsystem.authoring.testauth.domain.BlueprintElement;
import org.opentestsystem.authoring.testauth.domain.BlueprintReference;
import org.opentestsystem.authoring.testauth.domain.BlueprintReferenceType;
import org.opentestsystem.authoring.testauth.domain.ReportingMeasure;
import org.opentestsystem.authoring.testauth.domain.ScoringRule;
import org.opentestsystem.authoring.testauth.domain.Segment;
import org.opentestsystem.authoring.testauth.domain.search.ScoringRuleSearchRequest;
import org.opentestsystem.authoring.testauth.persistence.GridFsRepository;
import org.opentestsystem.authoring.testauth.persistence.ScoringRuleRepository;
import org.opentestsystem.authoring.testauth.service.AffinityGroupService;
import org.opentestsystem.authoring.testauth.service.AssessmentService;
import org.opentestsystem.authoring.testauth.service.BlueprintElementService;
import org.opentestsystem.authoring.testauth.service.ReportingMeasureService;
import org.opentestsystem.authoring.testauth.service.ScoringRuleService;
import org.opentestsystem.authoring.testauth.service.SegmentService;
import org.opentestsystem.shared.exception.LocalizedException;
import org.opentestsystem.shared.exception.RestException;
import org.opentestsystem.shared.search.domain.SearchResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.mongodb.DBObject;
import com.mongodb.gridfs.GridFSDBFile;
import com.mongodb.gridfs.GridFSFile;

@Service
public class ScoringRuleServiceImpl extends AssessmentChildHelper implements ScoringRuleService {

    private static final Logger LOGGER = LoggerFactory.getLogger(ScoringRuleServiceImpl.class);
    private static final BlueprintDenotationType[] NON_STANDARD_DENOTATIONS = new BlueprintDenotationType[] {
            BlueprintDenotationType.LEVEL, BlueprintDenotationType.LEAF_NODES };
    private static final String BLUEPRINT_REFERENCE_TYPE_KEY = "blueprintReferenceType";

    @Autowired
    private transient ScoringRuleHelper scoringRuleHelper;

    @Autowired
    private transient ScoringRuleRepository scoringRuleRepository;

    @Autowired
    private transient ReportingMeasureService reportingMeasureService;

    @Autowired
    private transient AssessmentService assessmentService;

    @Autowired
    private transient SegmentService segmentService;

    @Autowired
    private transient AffinityGroupService affinityGroupService;

    @Autowired
    private transient BlueprintElementService blueprintElementService;

    @Autowired
    private transient GridFsRepository gridFsRepository;

    @Override
    public ScoringRule saveScoringRule(final String scoringRuleId, final ScoringRule scoringRule) {
        if (LOGGER.isDebugEnabled()) {
            LOGGER.debug("Saving scoringRule");
        }

        if (scoringRuleId != null && (scoringRule == null || StringUtils.isEmpty(scoringRule.getId())
                || !scoringRuleId.equals(scoringRule.getId()))) {
            throw new LocalizedException("scoringRule.invalid.id");
        }

        checkForLockedAssessment(scoringRule.getAssessmentId());
        this.scoringRuleHelper.validateScoringRule(scoringRule);

        ScoringRule existingScoringRule = null;
        if (StringUtils.isNotBlank(scoringRule.getId())) {
            existingScoringRule = getScoringRule(scoringRule.getId());
        }

        ScoringRule savedScoringRule = null;
        try {
            savedScoringRule = this.scoringRuleRepository.save(scoringRule);
            // check if this scoring rule is associated with reporting measure
            if (existingScoringRule != null) {
                if (existingScoringRule.getBlueprintReferenceType() != scoringRule.getBlueprintReferenceType()
                        || existingScoringRule.getBlueprintDenotationType() != scoringRule
                                .getBlueprintDenotationType()) {
                    removeScoringRulesFromReportingMeasures(scoringRule);
                } else if (!StringUtils.equals(existingScoringRule.getBlueprintReferenceId(),
                        scoringRule.getBlueprintReferenceId())) {
                    updateRelatedReportingMeasures(existingScoringRule.getBlueprintReferenceId(),
                            scoringRule.getBlueprintReferenceId());
                }
            }
        } catch (final DuplicateKeyException dke) {
            if (StringUtils.contains(dke.getMessage(), ScoringRule.ORDER_INDEX_NAME)) {
                throw new LocalizedException("scoringRule.already.exists.order",
                        paramArray(scoringRule.getAssessmentId(), String.valueOf(scoringRule.getOrder())), dke);
            } else {
                throw new LocalizedException("scoringRule.already.exists.label",
                        paramArray(scoringRule.getAssessmentId(), scoringRule.getLabel()), dke);
            }
        }
        return savedScoringRule;
    }

    private void updateRelatedReportingMeasures(final String oldBpReferenceId, final String newBpReferenceId) {
        final List<ReportingMeasure> rmeasures = this.reportingMeasureService
                .getReportingMeasuresByReferenceId(oldBpReferenceId);
        for (final ReportingMeasure rmeasure : rmeasures) {
            rmeasure.setBlueprintReferenceId(newBpReferenceId);
            this.reportingMeasureService.saveReportingMeasure(rmeasure.getId(), rmeasure);
        }
    }

    @Override
    public List<ScoringRule> saveScoringRuleList(final List<ScoringRule> scoringRuleList,
            final boolean clearPrevious) {
        if (clearPrevious) {
            for (final ScoringRule scoringRule : scoringRuleList) {
                checkForLockedAssessment(scoringRule.getAssessmentId());
                this.scoringRuleHelper.validateScoringRule(scoringRule);
            }
            this.scoringRuleRepository.delete(scoringRuleList);
        }
        return this.scoringRuleRepository.save(scoringRuleList);
    }

    @Override
    public ScoringRule getScoringRule(final String scoringRuleId) {
        if (LOGGER.isDebugEnabled()) {
            LOGGER.debug("Finding scoringRule for Id: " + scoringRuleId);
        }
        final ScoringRule scoringRule = this.scoringRuleRepository.findOne(scoringRuleId);
        populateConversionTableFilenames(scoringRule);
        this.scoringRuleHelper.populateComputationRule(scoringRule);
        this.scoringRuleHelper.populateBlueprintReferenceName(scoringRule);
        return scoringRule;
    }

    private void populateConversionTableFilenames(final ScoringRule scoringRule) {
        if (scoringRule != null && scoringRule.getValueConversionTableGridFsId() != null) {
            final GridFSFile gridFsFile = this.gridFsRepository
                    .getById(scoringRule.getValueConversionTableGridFsId());
            if (gridFsFile == null) {
                throw new LocalizedException("scoringRule.valueConversionTableGridFsId.file.not.found");
            }
            scoringRule.setValueConversionTableFilename(gridFsFile.getFilename());
        }
        if (scoringRule != null && scoringRule.getStandardErrorConversionTableGridFsId() != null) {
            final GridFSFile gridFsFile = this.gridFsRepository
                    .getById(scoringRule.getStandardErrorConversionTableGridFsId());
            if (gridFsFile == null) {
                throw new LocalizedException("scoringRule.standardErrorConversionTableGridFsId.file.not.found");
            }
            scoringRule.setStandardErrorConversionTableFilename(gridFsFile.getFilename());
        }
    }

    @Override
    public List<ScoringRule> getScoringRulesByAssessmentId(final String assessmentId) {
        return this.scoringRuleRepository.findAllByAssessmentId(assessmentId);
    }

    @Override
    public List<ScoringRule> getScoringRulesByComputationRuleId(final String computationRuleId) {
        return this.scoringRuleRepository.findAllByComputationRuleId(computationRuleId);
    }

    @Override
    public void removeScoringRule(final String scoringRuleId) {
        if (LOGGER.isDebugEnabled()) {
            LOGGER.debug("Removing scoringRule with Id:" + scoringRuleId);
        }
        final ScoringRule scoringRuleToDelete = this.scoringRuleRepository.findOne(scoringRuleId);
        if (scoringRuleToDelete == null) {
            throw new LocalizedException("scoringRule.invalid.id", paramArray(scoringRuleId));
        }
        removeScoringRules(Lists.newArrayList(scoringRuleToDelete));
    }

    @Override
    public void removeByAssessmentId(final String assessmentId) {
        final List<ScoringRule> scoringRuleList = getScoringRulesByAssessmentId(assessmentId);
        if (!CollectionUtils.isEmpty(scoringRuleList)) {
            removeScoringRules(scoringRuleList);
        }
    }

    @Override
    public void removeByBlueprintReferenceId(final String assessmentId, final String... blueprintReferenceIdList) {
        final List<ScoringRule> scoringRuleList = blueprintReferenceIdList == null
                || CollectionUtils.isEmpty(Arrays.asList(blueprintReferenceIdList))
                        ? this.scoringRuleRepository.findAllByAssessmentIdAndBlueprintDenotationTypeIn(assessmentId,
                                NON_STANDARD_DENOTATIONS)
                        : this.scoringRuleRepository.findAllByAssessmentIdAndBlueprintReferenceIdIn(assessmentId,
                                blueprintReferenceIdList);
        if (!CollectionUtils.isEmpty(scoringRuleList)) {
            removeScoringRules(scoringRuleList);
        }
    }

    private void removeScoringRules(final List<ScoringRule> scoringRuleList) {
        final String assessmentId = scoringRuleList.get(0).getAssessmentId();
        checkForLockedAssessment(assessmentId);
        for (final ScoringRule scoringRule : scoringRuleList) {
            if (scoringRule.getValueConversionTableGridFsId() != null) {
                this.gridFsRepository.delete(scoringRule.getValueConversionTableGridFsId());
            }
            if (scoringRule.getStandardErrorConversionTableGridFsId() != null) {
                this.gridFsRepository.delete(scoringRule.getStandardErrorConversionTableGridFsId());
            }
            removeScoringRulesFromReportingMeasures(scoringRule);
        }

        this.scoringRuleRepository.delete(scoringRuleList);

        final List<ScoringRule> scoringRuleListToUpdate = getScoringRulesByAssessmentId(assessmentId);
        if (!CollectionUtils.isEmpty(scoringRuleListToUpdate)) {
            int i = 1;
            for (final ScoringRule scoringRule : scoringRuleListToUpdate) {
                scoringRule.setOrder(i++);
            }
            saveScoringRuleList(scoringRuleListToUpdate, true);
        }
    }

    @Override
    public SearchResponse<ScoringRule> searchScoringRules(final Map<String, String[]> parameterMap) {
        final Map<String, String[]> paramMap = reviseMapParams(parameterMap);
        final ScoringRuleSearchRequest searchRequest = new ScoringRuleSearchRequest(paramMap);
        if (searchRequest.isValid()) {
            final SearchResponse<ScoringRule> searchResponse = this.scoringRuleRepository.search(searchRequest);
            for (final ScoringRule scoringRule : searchResponse.getSearchResults()) {
                this.scoringRuleHelper.populateComputationRule(scoringRule);
                this.scoringRuleHelper.populateBlueprintReferenceName(scoringRule);
            }
            return searchResponse;
        }
        throw new RestException("scoringRule.search.invalidSearchCriteria");
    }

    // compensate for opting to use @JsonValue in enum for pretty dropdown choices
    private Map<String, String[]> reviseMapParams(final Map<String, String[]> parameterMap) {
        final Map<String, String[]> paramMap = Maps.newHashMap(parameterMap);
        if (paramMap.containsKey(BLUEPRINT_REFERENCE_TYPE_KEY)
                && paramMap.get(BLUEPRINT_REFERENCE_TYPE_KEY)[0] != null) {
            final BlueprintReferenceType blueprintReferenceType = BlueprintReferenceType
                    .fromTitle(paramMap.get(BLUEPRINT_REFERENCE_TYPE_KEY)[0]);
            if (blueprintReferenceType != null) {
                paramMap.put(BLUEPRINT_REFERENCE_TYPE_KEY, paramArray(blueprintReferenceType.name()));
            } else {
                paramMap.remove(BLUEPRINT_REFERENCE_TYPE_KEY);
            }
        }
        return paramMap;
    }

    @Override
    public GridFSDBFile getConversionTableFile(final String inGridFSId) {
        return this.gridFsRepository.getById(inGridFSId);
    }

    @Override
    public GridFSFile saveConversionTableFile(final String type, final String fileName, final byte[] inBytes,
            final String contentType) {
        if (type == null) {
            throw new LocalizedException("scoringRule.conversionTableFile.type.invalid");
        }

        validateConversionListFile(inBytes, fileName, type, false);

        final DBObject metadata = null;
        final GridFSFile gridFsFile = this.gridFsRepository.save(inBytes, fileName, contentType, metadata);
        return gridFsFile;
    }

    @Override
    public void deleteConversionTableFile(final String fileGridId) {
        this.gridFsRepository.delete(fileGridId);
    }

    @Override
    public void removeScoringRulesFromReportingMeasures(final ScoringRule scoringRule) {
        final List<ReportingMeasure> rmeasures = this.reportingMeasureService
                .getReportingMeasuresByScoringRuleId(scoringRule.getId());
        for (final ReportingMeasure rmeasure : rmeasures) {
            if (rmeasure.getScoringRuleIdList().size() == 1) {
                this.reportingMeasureService.removeReportingMeasure(rmeasure.getId());
            } else if (rmeasure.getScoringRuleIdList().size() > 1) {
                rmeasure.getScoringRuleIdList().remove(scoringRule.getId());
                this.reportingMeasureService.saveReportingMeasure(rmeasure.getId(), rmeasure);
            }
        }
    }

    @Override
    public Map<String, String> findDistinctActiveBlueprintLevelsByAssessmentId(final String assessmentId) {
        return this.scoringRuleHelper.findDistinctActiveBlueprintLevelsByAssessmentId(assessmentId);
    }

    @Override
    public List<BlueprintElement> findBlueprintElementsMissingScoringRule(final String assessmentId) {
        return this.scoringRuleHelper.findBlueprintElementsMissingScoringRule(assessmentId);
    }

    @Override
    public List<BlueprintReference> getBlueprintReferences(final Map<String, String[]> parameterMap) {
        final List<BlueprintReference> bpReferenceList = new ArrayList<BlueprintReference>();
        final Map<String, String[]> aMap = new HashMap<String, String[]>();
        aMap.put("pageSize", new String[] { "1000" });
        aMap.put("assessmentId", parameterMap.get("assessmentId"));
        final SearchResponse<ScoringRule> scoringRules = searchScoringRules(aMap);
        for (final ScoringRule scoringRule : scoringRules.getSearchResults()) {
            switch (scoringRule.getBlueprintReferenceType()) {
            case AFFINITY_GROUP:
                final AffinityGroup affinityGroup = this.affinityGroupService
                        .getAffinityGroup(scoringRule.getBlueprintReferenceId());
                bpReferenceList.add(new BlueprintReference(affinityGroup.getId(), affinityGroup.getGroupName(),
                        BlueprintReferenceType.AFFINITY_GROUP));
                break;
            case SEGMENT:
                final Segment segment = this.segmentService.getSegment(scoringRule.getBlueprintReferenceId());
                bpReferenceList.add(new BlueprintReference(segment.getId(),
                        segment.getPosition() + " - " + segment.getLabel(), BlueprintReferenceType.SEGMENT));
                break;
            case STANDARD:
                if (scoringRule.getBlueprintDenotationType().equals(BlueprintDenotationType.STANDARD_KEY)) {
                    final BlueprintElement blueprintElement = this.blueprintElementService
                            .getBlueprintElement(scoringRule.getBlueprintReferenceId());
                    bpReferenceList.add(new BlueprintReference(blueprintElement.getId(),
                            blueprintElement.getStandardKey(), BlueprintReferenceType.STANDARD));
                }
                break;
            case TEST:
                final Assessment assessment = this.assessmentService
                        .getAssessment(scoringRule.getBlueprintReferenceId());
                bpReferenceList.add(new BlueprintReference(assessment.getId(), assessment.getName(),
                        BlueprintReferenceType.TEST));
                break;
            default:
                break;
            }
        }
        Collections.sort(bpReferenceList);
        return bpReferenceList;
    }
}