Java tutorial
/******************************************************************************* * 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); } }