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

Java tutorial

Introduction

Here is the source code for org.opentestsystem.authoring.testauth.service.impl.ReportingMeasureServiceImpl.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 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.BlueprintDenotationType;
import org.opentestsystem.authoring.testauth.domain.BlueprintElement;
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.ReportingMeasureSearchRequest;
import org.opentestsystem.authoring.testauth.persistence.BlueprintElementRepository;
import org.opentestsystem.authoring.testauth.persistence.ReportingMeasureRepository;
import org.opentestsystem.authoring.testauth.service.AffinityGroupService;
import org.opentestsystem.authoring.testauth.service.AssessmentService;
import org.opentestsystem.authoring.testauth.service.ReportingMeasureService;
import org.opentestsystem.authoring.testauth.service.ScoringRuleService;
import org.opentestsystem.authoring.testauth.service.SegmentService;
import org.opentestsystem.authoring.testauth.validation.ValidationHelper;
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 org.springframework.validation.BeanPropertyBindingResult;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;

import com.google.common.collect.Lists;
import com.google.common.collect.Maps;

@Service
public class ReportingMeasureServiceImpl extends AssessmentChildHelper implements ReportingMeasureService {

    private static final Logger LOGGER = LoggerFactory.getLogger(ReportingMeasureServiceImpl.class);
    private static final String BPREF_TYPE_KEY = "blueprintReferenceType";
    private static final String BPREF_ID_NOT_FOUND = "blueprintReferenceId.notfound";
    private static final String BPREF_NOT_ACTIVE = "reportingMeasure.blueprintReferenceId.not.active";
    private static final String BPREF_ASSESSMENTID_MISMATCH = "reportingMeasure.blueprintReferenceId.assessmentId.mismatch";
    private static final String BP_DENOTATION_REQUIRED = "reportingMeasure.blueprintDenotationType.required";

    @Autowired
    private transient ReportingMeasureRepository reportingMeasureRepository;

    @Autowired
    private transient AssessmentService assessmentService;

    @Autowired
    private transient SegmentService segmentService;

    @Autowired
    private transient AffinityGroupService affinityGroupService;

    @Autowired
    private transient BlueprintElementRepository blueprintElementRepository;

    @Autowired
    private transient ScoringRuleService scoringRuleService;

    @Override
    public ReportingMeasure saveReportingMeasure(final String reportingMeasureId,
            final ReportingMeasure reportingMeasure) {
        if (LOGGER.isDebugEnabled()) {
            LOGGER.debug("Saving reportingMeasure");
        }

        if (reportingMeasureId != null && (reportingMeasure == null || StringUtils.isEmpty(reportingMeasure.getId())
                || !reportingMeasureId.equals(reportingMeasure.getId()))) {
            throw new LocalizedException("reportingMeasure.invalid.id");
        }
        checkForLockedAssessment(reportingMeasure.getAssessmentId());
        validateReportingMeasure(reportingMeasure);

        ReportingMeasure savedReportingMeasure = null;
        try {
            savedReportingMeasure = this.reportingMeasureRepository.save(reportingMeasure);
        } catch (final DuplicateKeyException dke) {
            throw new LocalizedException("reportingMeasure.already.exists",
                    paramArray(reportingMeasure.getBlueprintReferenceName(),
                            reportingMeasure.getBlueprintReferenceType().getTitle()),
                    dke);
        }
        return savedReportingMeasure;
    }

    private void validateReportingMeasure(final ReportingMeasure reportingMeasure) {
        final BindingResult bindingResult = new BeanPropertyBindingResult(reportingMeasure, "reportingMeasure");
        if (reportingMeasure.getBlueprintReferenceType() != null
                && reportingMeasure.getBlueprintReferenceId() != null) {
            switch (reportingMeasure.getBlueprintReferenceType()) {
            case TEST:
                if (!reportingMeasure.getBlueprintReferenceId().equals(reportingMeasure.getAssessmentId())) {
                    formatReferenceIdMessage(bindingResult, reportingMeasure, BPREF_ID_NOT_FOUND);
                }
                reportingMeasure.setBlueprintDenotationType(null);
                break;
            case SEGMENT:
                final Segment segment = this.segmentService.getSegment(reportingMeasure.getBlueprintReferenceId());
                if (segment == null) {
                    formatReferenceIdMessage(bindingResult, reportingMeasure, BPREF_ID_NOT_FOUND);
                }
                reportingMeasure.setBlueprintDenotationType(null);
                break;
            case AFFINITY_GROUP:
                final AffinityGroup affinityGroup = this.affinityGroupService
                        .getAffinityGroup(reportingMeasure.getBlueprintReferenceId());
                if (affinityGroup == null) {
                    formatReferenceIdMessage(bindingResult, reportingMeasure, BPREF_ID_NOT_FOUND);
                }
                reportingMeasure.setBlueprintDenotationType(null);
                break;
            case STANDARD:
                if (reportingMeasure.getBlueprintDenotationType() == null) {
                    // missing denotation type message
                    bindingResult.addError(buildFieldError("blueprintDenotationType", BP_DENOTATION_REQUIRED,
                            paramArray(reportingMeasure.getBlueprintReferenceType().name(),
                                    reportingMeasure.getBlueprintReferenceType().getTitle())));
                } else {
                    if (reportingMeasure.getBlueprintDenotationType() == BlueprintDenotationType.STANDARD_KEY) {
                        // ensure ID is actual active BP Element
                        final BlueprintElement blueprintElement = reportingMeasure.getBlueprintReferenceId() == null
                                ? null
                                : this.blueprintElementRepository
                                        .findOne(reportingMeasure.getBlueprintReferenceId());
                        if (blueprintElement == null) {
                            formatReferenceIdMessage(bindingResult, reportingMeasure, BPREF_ID_NOT_FOUND);
                        } else if (!blueprintElement.isActive()) {
                            formatReferenceIdMessage(bindingResult, reportingMeasure, BPREF_NOT_ACTIVE);
                        } else if (!StringUtils.equals(blueprintElement.getAssessmentId(),
                                reportingMeasure.getAssessmentId())) {
                            formatReferenceIdMessage(bindingResult, reportingMeasure, BPREF_ASSESSMENTID_MISMATCH);
                        }
                    } else if (reportingMeasure.getBlueprintDenotationType() == BlueprintDenotationType.LEVEL) {
                        // ensure level choice is valid
                        if (!findDistinctActiveBlueprintLevelsByAssessmentId(reportingMeasure.getAssessmentId())
                                .contains(reportingMeasure.getBlueprintReferenceId())) {
                            formatReferenceIdMessage(bindingResult, reportingMeasure,
                                    "reportingMeasure.blueprintReferenceId.level.invalid");
                        }
                    } else if (reportingMeasure
                            .getBlueprintDenotationType() == BlueprintDenotationType.LEAF_NODES) {
                        // ensure ID field is empty/null
                        if (reportingMeasure.getBlueprintReferenceId() != null) {
                            formatReferenceIdMessage(bindingResult, reportingMeasure,
                                    "reportingMeasure.blueprintReferenceId.notempty");
                        }
                    } else {
                        bindingResult.addError(buildFieldError("blueprintDenotationType", BP_DENOTATION_REQUIRED,
                                paramArray(reportingMeasure.getBlueprintReferenceType().name(),
                                        reportingMeasure.getBlueprintReferenceType().getTitle())));
                    }
                }
                break;
            default:
                // do nothing, cannot enter here if prior validation passed
                break;
            }
            populateScoringRules(reportingMeasure);
            if (CollectionUtils.isEmpty(reportingMeasure.getScoringRuleIdList()) || reportingMeasure
                    .getScoringRuleIdList().size() > reportingMeasure.getScoringRuleList().size()) {
                formatScoringRuleIdMessage(bindingResult, reportingMeasure, null,
                        "reportingMeasure.scoringRuleIdList.invalid");
            }
            for (final ScoringRule scoringRule : reportingMeasure.getScoringRuleList()) {
                if (!scoringRule.getBlueprintReferenceId().equals(reportingMeasure.getBlueprintReferenceId())
                        || !scoringRule.getBlueprintReferenceType()
                                .equals(reportingMeasure.getBlueprintReferenceType())) {
                    formatScoringRuleIdMessage(bindingResult, reportingMeasure, scoringRule,
                            "reportingMeasure.scoringRuleIdList.mismatch");
                }
            }
        }
        if (bindingResult.hasErrors()) {
            throw ValidationHelper.convertErrorsToConstraintException(reportingMeasure, bindingResult);
        }
    }

    private void formatReferenceIdMessage(final BindingResult bindingResult,
            final ReportingMeasure reportingMeasure, final String messageKey) {
        bindingResult.addError(buildFieldError("blueprintReferenceId", messageKey,
                reportingMeasure.getBlueprintReferenceType().getTitle()));
    }

    private FieldError buildFieldError(final String fieldName, final String messageKey,
            final String... messageArgs) {
        return new FieldError("reportingMeasure", fieldName, null, false, paramArray(messageKey), messageArgs,
                messageKey);
    }

    protected List<String> findDistinctActiveBlueprintLevelsByAssessmentId(final String assessmentId) {
        return Lists
                .newArrayList(this.blueprintElementRepository.findDistinctActiveLevelsByAssessmentId(assessmentId));
    }

    private void formatScoringRuleIdMessage(final BindingResult bindingResult,
            final ReportingMeasure reportingMeasure, final ScoringRule scoringRule, final String messageKey) {
        bindingResult.addError(
                new FieldError("reportingMeasure", "scoringRuleIdList", null, false, paramArray(messageKey),
                        paramArray(scoringRule == null ? "" : scoringRule.getLabel(),
                                reportingMeasure.getBlueprintReferenceType().name(),
                                reportingMeasure.getBlueprintReferenceId(), reportingMeasure.getAssessmentId()),
                        messageKey));

    }

    @Override
    public ReportingMeasure getReportingMeasure(final String reportingMeasureId) {
        if (LOGGER.isDebugEnabled()) {
            LOGGER.debug("Finding reportingMeasure for Id: " + reportingMeasureId);
        }
        final ReportingMeasure reportingMeasure = this.reportingMeasureRepository.findOne(reportingMeasureId);
        if (reportingMeasure != null) {
            populateScoringRules(reportingMeasure);
        }
        return reportingMeasure;
    }

    @Override
    public List<ReportingMeasure> getReportingMeasuresByAssessmentId(final String assessmentId) {
        return this.reportingMeasureRepository.findAllByAssessmentId(assessmentId);
    }

    @Override
    public List<ReportingMeasure> getReportingMeasuresByReferenceId(final String blueprintReferenceId) {
        return this.reportingMeasureRepository.findAllByBlueprintReferenceId(blueprintReferenceId);
    }

    @Override
    public List<ReportingMeasure> getReportingMeasuresByScoringRuleId(final String scoringRuleId) {
        return this.reportingMeasureRepository.findAllByScoringRuleIdList(scoringRuleId);
    }

    @Override
    public void removeReportingMeasure(final String reportingMeasureId) {
        if (LOGGER.isDebugEnabled()) {
            LOGGER.debug("Removing reportingMeasure with Id:" + reportingMeasureId);
        }
        final ReportingMeasure reportingMeasureToDelete = this.reportingMeasureRepository
                .findOne(reportingMeasureId);
        if (reportingMeasureToDelete == null) {
            throw new LocalizedException("reportingMeasure.invalid.id", paramArray(reportingMeasureId));
        }
        checkForLockedAssessment(reportingMeasureToDelete.getAssessmentId());

        this.reportingMeasureRepository.delete(reportingMeasureId);
    }

    @Override
    public void removeByAssessmentId(final String assessmentId) {
        checkForLockedAssessment(assessmentId);
        final List<ReportingMeasure> reportingMeasureList = getReportingMeasuresByAssessmentId(assessmentId);
        this.reportingMeasureRepository.delete(reportingMeasureList);
    }

    @Override
    public void removeByReferenceId(final String blueprintReferenceId) {
        final List<ReportingMeasure> reportingMeasureList = getReportingMeasuresByReferenceId(blueprintReferenceId);
        this.reportingMeasureRepository.delete(reportingMeasureList);
    }

    @Override
    public SearchResponse<ReportingMeasure> searchReportingMeasures(final Map<String, String[]> parameterMap) {
        final Map<String, String[]> paramMap = reviseMapParams(parameterMap);
        final ReportingMeasureSearchRequest searchRequest = new ReportingMeasureSearchRequest(paramMap);
        if (searchRequest.isValid()) {
            final SearchResponse<ReportingMeasure> searchResponse = this.reportingMeasureRepository
                    .search(searchRequest);
            for (final ReportingMeasure reportingMeasure : searchResponse.getSearchResults()) {
                populateScoringRules(reportingMeasure); // populate scoring rules first as they are used to build some blueprint reference names
            }
            return searchResponse;
        }
        throw new RestException("reportingMeasure.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(BPREF_TYPE_KEY) && paramMap.get(BPREF_TYPE_KEY)[0] != null) {
            final BlueprintReferenceType blueprintReferenceType = BlueprintReferenceType
                    .fromTitle(paramMap.get(BPREF_TYPE_KEY)[0]);
            if (blueprintReferenceType != null) {
                paramMap.put(BPREF_TYPE_KEY, paramArray(blueprintReferenceType.name()));
            } else {
                paramMap.remove(BPREF_TYPE_KEY);
            }
        }
        return paramMap;
    }

    private void populateScoringRules(final ReportingMeasure reportingMeasure) {
        if (reportingMeasure != null && !CollectionUtils.isEmpty(reportingMeasure.getScoringRuleIdList())) {
            final List<ScoringRule> scoringRuleList = Lists.newArrayList();
            for (final String scoringRuleId : reportingMeasure.getScoringRuleIdList()) {
                final ScoringRule scoringRule = this.scoringRuleService.getScoringRule(scoringRuleId);
                if (scoringRule != null) {
                    scoringRuleList.add(scoringRule);
                }
            }
            reportingMeasure.setScoringRuleList(scoringRuleList);

            if (!CollectionUtils.isEmpty(scoringRuleList)) {
                reportingMeasure.setBlueprintReferenceName(
                        reportingMeasure.getScoringRuleList().get(0).getBlueprintReferenceName());
            }
        }
    }

    @Override
    public List<ReportingMeasure> saveReportingMeasureList(final List<ReportingMeasure> reportingMeasureList) {
        return this.reportingMeasureRepository.save(reportingMeasureList);
    }
}