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

Java tutorial

Introduction

Here is the source code for org.opentestsystem.authoring.testauth.service.impl.SegmentServiceImpl.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.buildValidationFieldError;
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.FormPartition;
import org.opentestsystem.authoring.testauth.domain.ItemGroup;
import org.opentestsystem.authoring.testauth.domain.ItemSelectionAlgorithm;
import org.opentestsystem.authoring.testauth.domain.Segment;
import org.opentestsystem.authoring.testauth.domain.search.SegmentSearchRequest;
import org.opentestsystem.authoring.testauth.persistence.SegmentRepository;
import org.opentestsystem.authoring.testauth.service.AffinityGroupService;
import org.opentestsystem.authoring.testauth.service.BlueprintElementService;
import org.opentestsystem.authoring.testauth.service.FormPartitionService;
import org.opentestsystem.authoring.testauth.service.ItemGroupService;
import org.opentestsystem.authoring.testauth.service.ItemSelectionAlgorithmService;
import org.opentestsystem.authoring.testauth.service.ItemService;
import org.opentestsystem.authoring.testauth.service.PerformanceLevelService;
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.service.impl.SegmentHelper.SEGMENT_POSITION_TRANSFORMER;
import org.opentestsystem.authoring.testauth.validation.SegmentValidator;
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.validation.BeanPropertyBindingResult;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;

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

@Service
public class SegmentServiceImpl extends AssessmentChildHelper implements SegmentService {
    private static final Logger LOGGER = LoggerFactory.getLogger(SegmentServiceImpl.class);
    private static final int SEGMENT_MAX_POSITION = 1000;
    private static final int SEGMENT_MIN_POSITION = 1;

    @Autowired
    private transient SegmentRepository segmentRepository;

    @Autowired
    private transient BlueprintElementService blueprintElementService;

    @Autowired
    private transient AffinityGroupService affinityGroupService;

    @Autowired
    private transient ItemGroupService itemGroupService;

    @Autowired
    private transient ItemService itemService;

    @Autowired
    private transient ScoringRuleService scoringRuleService;

    @Autowired
    private transient FormPartitionService formPartitionService;

    @Autowired
    private transient PerformanceLevelService performanceLevelService;

    @Autowired
    private transient ReportingMeasureService reportingMeasureService;

    @Autowired
    private transient ItemSelectionAlgorithmService itemSelectionAlgorithmService;

    @Autowired
    private transient SegmentValidator segmentValidator;

    @Override
    public Segment createSegment(final Segment segment) {
        if (LOGGER.isDebugEnabled()) {
            LOGGER.debug("Saving segment");
        }
        checkForLockedAssessment(segment.getAssessmentId());
        if (segment == null || StringUtils.isNotBlank(segment.getId())) {
            throw new LocalizedException("segment.invalid.id");
        }

        final BindingResult bindingResult = new BeanPropertyBindingResult(segment, "segment");
        if (findSegmentListByAssessmentId(segment.getAssessmentId()).size() + 1 != segment.getPosition()
                || segment.getPosition() > SEGMENT_MAX_POSITION || segment.getPosition() < SEGMENT_MIN_POSITION) {
            bindingResult.addError(
                    new FieldError("segment", "position", null, false, paramArray("segment.invalid.position"),
                            paramArray(String.valueOf(segment.getPosition())), "segment.invalid.position"));
        }
        Segment savedSegment = null;

        validateSegment(bindingResult, segment);

        try {
            savedSegment = this.segmentRepository.save(segment);

            loadReferenceData(savedSegment);
        } catch (final DuplicateKeyException dke) {
            throw new LocalizedException("segment.already.exists", paramArray(segment.getLabel()), dke);
        }
        this.blueprintElementService.addBlueprintElementValueGroup(savedSegment.getAssessmentId(),
                savedSegment.getId(), null);
        this.affinityGroupService.addAffinityGroupValueGroup(savedSegment.getAssessmentId(), savedSegment.getId());
        return savedSegment;
    }

    @Override
    public Segment updateSegment(final Segment segment) {
        if (LOGGER.isDebugEnabled()) {
            LOGGER.debug("Updating segment");
        }
        checkForLockedAssessment(segment.getAssessmentId());

        if (segment == null || StringUtils.isBlank(segment.getId())) {
            throw new LocalizedException("segment.invalid.id");
        }
        final BindingResult bindingResult = new BeanPropertyBindingResult(segment, "segment");
        if (findSegmentListByAssessmentId(segment.getAssessmentId()).size() < segment.getPosition()
                || segment.getPosition() > SEGMENT_MAX_POSITION || segment.getPosition() < SEGMENT_MIN_POSITION) {
            bindingResult.addError(
                    new FieldError("segment", "position", null, false, paramArray("segment.invalid.position"),
                            paramArray(String.valueOf(segment.getPosition())), "segment.invalid.position"));
        }

        final String existingSegmentItemSelectionAlgorithmId = this.segmentRepository.findOne(segment.getId())
                .getItemSelectionAlgorithmId();
        final boolean isNewItemSelectionAlgorithm = !StringUtils.equals(existingSegmentItemSelectionAlgorithmId,
                segment.getItemSelectionAlgorithmId());
        if (isNewItemSelectionAlgorithm) {
            final ItemSelectionAlgorithm existingItemSelectionAlgorithm = this.itemSelectionAlgorithmService
                    .getItemSelectionAlgorithm(existingSegmentItemSelectionAlgorithmId);
            final ItemSelectionAlgorithm newItemSelectionAlgorithm = this.itemSelectionAlgorithmService
                    .getItemSelectionAlgorithm(segment.getItemSelectionAlgorithmId());
            if (existingItemSelectionAlgorithm.getItemSelectionAlgorithmType() != newItemSelectionAlgorithm
                    .getItemSelectionAlgorithmType()) {
                bindingResult.addError(buildValidationFieldError("segment", "itemSelectionAlgorithmId",
                        "segment.cannot.alter.itemSelectionAlgorithm.type",
                        paramArray(existingItemSelectionAlgorithm.getItemSelectionAlgorithmType().name())));
            }
        }

        validateSegment(bindingResult, segment);

        segmentPositionResequencing(segment, true);

        Segment savedSegment = null;

        try {
            savedSegment = this.segmentRepository.save(segment);

            // if ISA has changed, update blueprint values
            if (isNewItemSelectionAlgorithm) {
                this.blueprintElementService.updateBlueprintElementItemSelectionParameters(
                        savedSegment.getAssessmentId(), savedSegment.getId());
                this.affinityGroupService.updateAffinityGroupItemSelectionParameters(savedSegment.getAssessmentId(),
                        savedSegment.getId());
            }

            loadReferenceData(savedSegment);
        } catch (final DuplicateKeyException dke) {
            throw new LocalizedException("segment.already.exists", paramArray(segment.getLabel()), dke);
        }
        return savedSegment;
    }

    private void segmentPositionResequencing(final Segment modifiedSegment,
            final boolean updateIsTrueDeleteIsFalse) {
        final List<Segment> segmentList = findSegmentListByAssessmentId(modifiedSegment.getAssessmentId());
        if (segmentList.size() > 1) {
            final Map<String, Segment> segmentMap = Maps
                    .newHashMap(SegmentHelper.createSegmentIdKeyMap(segmentList));
            // only re-sequence if deleting or if the position value has changed for the segment being updated
            if (segmentMap.containsKey(modifiedSegment.getId()) && (!updateIsTrueDeleteIsFalse
                    || segmentMap.get(modifiedSegment.getId()).getPosition() != modifiedSegment.getPosition())) {
                final int previousPosition = segmentMap.get(modifiedSegment.getId()).getPosition();
                final int newPosition = updateIsTrueDeleteIsFalse ? modifiedSegment.getPosition()
                        : segmentList.size(); // if deleting...move to end of list

                final List<Segment> updatedSegmentList = Lists
                        .newArrayList(Iterables.filter(
                                Iterables.transform(segmentMap.values(),
                                        SEGMENT_POSITION_TRANSFORMER.getInstance(modifiedSegment.getId(),
                                                newPosition, previousPosition)),
                                SegmentHelper.SEGMENT_NOTNULL_FILTER));

                this.segmentRepository.delete(updatedSegmentList);
                this.segmentRepository.save(updatedSegmentList);
            }
        }
    }

    @Override
    public Segment getSegment(final String segmentId) {
        if (LOGGER.isDebugEnabled()) {
            LOGGER.debug("Finding segment for Id: " + segmentId);
        }
        final Segment segment = this.segmentRepository.findOne(segmentId);
        loadReferenceData(segment);
        return segment;
    }

    @Override
    public void removeSegment(final String segmentId) {
        if (LOGGER.isDebugEnabled()) {
            LOGGER.debug("Removing segment with Id:" + segmentId);
        }
        final Segment segment = this.segmentRepository.findOne(segmentId);

        checkForLockedAssessment(segment.getAssessmentId());

        segmentPositionResequencing(segment, false);
        this.itemService.removeBySegmentId(segmentId);
        removeItemGroupsBySegment(segmentId);
        removeFormPartitionsBySegment(segmentId);
        this.scoringRuleService.removeByBlueprintReferenceId(segment.getAssessmentId(), segmentId);
        this.performanceLevelService.removeByReferenceId(segmentId);
        this.reportingMeasureService.removeByReferenceId(segmentId);
        this.blueprintElementService.removeBlueprintElementValueGroup(segment.getAssessmentId(), segmentId);
        this.affinityGroupService.removeAffinityGroupValueGroup(segment.getAssessmentId(), segmentId);
        this.segmentRepository.delete(segmentId);
    }

    @Override
    public void removeByAssessmentId(final String parentId) {
        this.segmentRepository.delete(this.segmentRepository.findAllByAssessmentId(parentId));
    }

    @Override
    public SearchResponse<Segment> searchSegments(final Map<String, String[]> requestMap) {
        final SegmentSearchRequest searchRequest = new SegmentSearchRequest(requestMap);
        if (searchRequest.isValid()) {
            return this.segmentRepository.search(searchRequest);
        } else {
            throw new RestException("segment.search.invalidSearchCriteria");
        }
    }

    @Override
    public void loadReferenceData(final List<Segment> segmentList) {
        for (final Segment segment : segmentList) {
            loadReferenceData(segment);
        }
    }

    private void loadReferenceData(final Segment segment) {
        if (segment != null && StringUtils.isNotEmpty(segment.getItemSelectionAlgorithmId())) {
            segment.setItemSelectionAlgorithm(this.itemSelectionAlgorithmService
                    .getItemSelectionAlgorithm(segment.getItemSelectionAlgorithmId()));
        }
    }

    private void validateSegment(final BindingResult bindingResult, final Segment segment) {
        this.segmentValidator.validate(segment, bindingResult);
        if (bindingResult.hasErrors()) {
            throw ValidationHelper.convertErrorsToConstraintException(segment, bindingResult);
        }
    }

    private void removeItemGroupsBySegment(final String segmentId) {
        final List<ItemGroup> itemGroups = this.itemGroupService.getItemGroupsBySegment(segmentId);
        for (final ItemGroup itemGroup : itemGroups) {
            this.itemGroupService.removeItemGroup(itemGroup.getId());
        }
    }

    private void removeFormPartitionsBySegment(final String segmentId) {
        final List<FormPartition> partitions = this.formPartitionService.getFormPartitionsBySegmentId(segmentId);
        for (final FormPartition partition : partitions) {
            this.formPartitionService.removeFormPartition(partition.getId());
        }
    }

    @Override
    public List<Segment> findSegmentListByAssessmentId(final String assessmentId) {
        return this.segmentRepository.findAllByAssessmentId(assessmentId);
    }

    @Override
    public List<Segment> saveSegmentList(final List<Segment> segmentList, final boolean clearPrevious) {
        if (clearPrevious) {
            for (final Segment segment : segmentList) {
                checkForLockedAssessment(segment.getAssessmentId());
            }
            this.segmentRepository.delete(segmentList);
        }
        return this.segmentRepository.save(segmentList);
    }
}