org.opentestsystem.authoring.testitembank.persistence.ItemRepositoryImpl.java Source code

Java tutorial

Introduction

Here is the source code for org.opentestsystem.authoring.testitembank.persistence.ItemRepositoryImpl.java

Source

/*******************************************************************************
 * Educational Online Test Delivery System 
 * Copyright (c) 2014 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.testitembank.persistence;

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

import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.ArrayUtils;
import org.opentestsystem.authoring.testitembank.domain.Item;
import org.opentestsystem.authoring.testitembank.domain.ItemHistory;
import org.opentestsystem.authoring.testitembank.domain.ItemScoreDimension;
import org.opentestsystem.authoring.testitembank.exception.TestItemBankException;
import org.opentestsystem.authoring.testitembank.domain.ItemSearchRequest;
import org.opentestsystem.shared.search.domain.SearchResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;

/**
 * Implementation of the CustomTestItemBankRepositoryExtensions methods. Spring
 * Data MongoDB uses naming convention to recognize that this impl class needs
 * to be weaved together with a generated TestItemBankRepository impl to create
 * a complete impl of the repository interface.
 */
public class ItemRepositoryImpl implements ItemRepositoryCustom {

    @Autowired
    private MongoTemplate mongoTemplate;

    //private static final Logger LOGGER = LoggerFactory.getLogger(ItemRepositoryImpl.class);

    @Override
    public void addItem(final Item item) {
        final Query query = new Query();
        query.addCriteria(Criteria.where("tenantId").is(item.getTenantId()));
        query.addCriteria(Criteria.where("identifier").is(item.getIdentifier()));

        final Item existingItem = mongoTemplate.findOne(query, Item.class);
        if (existingItem != null) {
            item.setId(existingItem.getId());
            if (item.compareByVersion(existingItem) < 0) {
                throw new TestItemBankException("item.version.lessThanExisting",
                        new String[] { item.getIdentifier(), item.getVersion(), existingItem.getVersion() });
            }
            // If item already exists, but it has the same version, delete existing, we will replace it with
            // newer entity. We need it to be able to update ItemScoreDimensions without changing item version
            if (item.getVersion() != null && item.getVersion().equalsIgnoreCase(existingItem.getVersion())) {
                mongoTemplate.remove(existingItem);

                query.addCriteria(Criteria.where("version").is(item.getVersion()));
                mongoTemplate.findAndRemove(query, ItemHistory.class);
                //ItemHistory removedItemHistory = mongoTemplate.findAndRemove(query, ItemHistory.class);
                //if (removedItemHistory  != null)
                //  LOGGER.info ("Removed ItemHistory: " + removedItemHistory.getIdentifier () + " version: " + removedItemHistory.getVersion ());
            }
        }
        mongoTemplate.insert(new ItemHistory(item));
        //LOGGER.info ("Inserted to ItemHistory: " + item.getIdentifier () + " version: " + item.getVersion ());
        mongoTemplate.save(item);
        //LOGGER.info ("Saved to Item: " + item.getIdentifier () + " version: " + item.getVersion ());
    }

    @Override
    public List<Item> findItemsByTenantIdAndIdentifierIn(final String tenantId, final List<String> identifierList) {
        final Query query = new Query();
        query.addCriteria(Criteria.where("tenantId").is(tenantId));
        query.addCriteria(Criteria.where("allIncludedMetatdata.Identifier").in(identifierList));
        return this.mongoTemplate.find(query, Item.class);
    }

    @Override
    public List<Item> findItemsByTenantIdAndItemBankAndIdentifierIn(String tenantId, String itemBank,
            List<String> identifierList) {
        final Query query = new Query();
        query.addCriteria(Criteria.where("tenantId").is(tenantId));
        query.addCriteria(Criteria.where("itemBank").is(itemBank));
        // Note that we expect here identifiers  to be structured as, for example,  item-200-1234 or stim-187-345
        if (identifierList.isEmpty() == false && StringUtils.countMatches(identifierList.get(0), "-") == 2) {
            query.addCriteria(Criteria.where("identifier").in(identifierList));
        } else
            query.addCriteria(Criteria.where("allIncludedMetatdata.Identifier").in(identifierList));
        return this.mongoTemplate.find(query, Item.class);
    }

    @Override
    public SearchResponse<Item> searchWithIrtDimensions(final ItemSearchRequest searchRequest) {
        //LOGGER.info ("Calling searchWithIrtDimensions");

        //Save the original search criteria array, it may contain IrtDimension.IrtStatDomain
        Map<String, String[]> searchCriteria = searchRequest.getSearchCriteria();

        Boolean includeAllIrtDimensions = false;
        if (searchCriteria.containsKey("IrtDimension.IrtStatDomain")) {
            //LOGGER.info ("Found IrtDimension.IrtStatDomain search criteria" );

            if (ArrayUtils.contains(searchCriteria.get("IrtDimension.IrtStatDomain"), "*") == true) {
                //LOGGER.info ("Found IrtDimension criteria with * value");
                includeAllIrtDimensions = true;
                // Note that we remove IrtDimension.IrtStatDomain from the searchRequest, but it was saved
                // for future checks in searchCriteria variable
                searchRequest.getSearchCriteria().remove("IrtDimension.IrtStatDomain");
            }
        }

        Query query = searchRequest.buildQuery();
        // SB-736 For searches that requires a criteria, nothing should be returned
        // if criteria is not present
        if (searchRequest.isSearchCriteriaRequired()) {
            if (query.getQueryObject() == null || query.getQueryObject().keySet().size() == 0) {
                return new SearchResponse<Item>(Collections.<Item>emptyList(), searchRequest, 0);
            }
        }
        long total = this.mongoTemplate.count(query, Item.class);
        List<Item> results = (total == 0) ? Collections.<Item>emptyList()
                : this.mongoTemplate.find(query, Item.class);
        //LOGGER.info ("Found " + total + " items in result set");

        // There are three options of dealing with IrtDimensions.
        // 1. original request contained IrtStatDomain criteria and its value was equal to '*'.
        //    We removed this criteria from search request and and set up 
        //    includeAllIrtDimensions variable to 'true'.
        //    It means: include all IrtDimensions into result.
        // 2. original request contained IrtStatDomain criteria and its value was not equal to '*'.
        //    It means: include only IrtDimensions with IrtStatDomain value present in the search criteria.
        // 3. original request did not contain IrtStatDomain criteria.
        //    It means: do not include IrtDimension elements in the result.

        if (includeAllIrtDimensions == true) {
            //LOGGER.info ("Including all IrtDimensions into result set");
            // Case 1. do nothing to results; they are already perfect
        }

        else if (total != 0 && searchCriteria.containsKey("IrtDimension.IrtStatDomain")) {
            // Case 2.
            String[] irtStatDomainValues = searchCriteria.get("IrtDimension.IrtStatDomain");
            for (Item item : results) {
                List<ItemScoreDimension> dimensionList = item.getItemScoreDimensionList();
                List<ItemScoreDimension> updatedDimensionList = new ArrayList<ItemScoreDimension>();
                for (ItemScoreDimension dim : dimensionList) {
                    if (ArrayUtils.contains(irtStatDomainValues, dim.getIrtStatDomain()) == true) {
                        //LOGGER.info("Keeping IrtDimension for " + dim.getIrtStatDomain ());
                        updatedDimensionList.add(dim);
                    } else {
                        //LOGGER.info("Skipping IrtDimension for " + dim.getIrtStatDomain ());
                    }
                }
                item.setItemScoreDimensionList(updatedDimensionList);
                if (item.getAllIncludedMetatdata().containsKey("IrtDimension")) {
                    //LOGGER.info ("Found IrtDimension in allIncludedMetatdata ");
                    item.getAllIncludedMetatdata().put("IrtDimension", updatedDimensionList);
                    //LOGGER.info("Updated IrtDimension in allIncludedMetatdata");
                }
            }
        } else if (total != 0) {
            // Case 3. Need to strip all ItemScoreDimensions
            //LOGGER.info ("Removing IrtDimension from all items and allIncludedMetatdata");
            for (Item item : results) {
                item.setItemScoreDimensionList(null);
                item.getAllIncludedMetatdata().remove("IrtDimension");
            }
        }
        return new SearchResponse<Item>(results, searchRequest, total);
    }
}