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