package gov.samhsa.consent2share.service.valueset;
import gov.samhsa.consent2share.domain.valueset.CodeSystem;
import gov.samhsa.consent2share.domain.valueset.CodeSystemRepository;
import gov.samhsa.consent2share.domain.valueset.CodeSystemVersion;
import gov.samhsa.consent2share.domain.valueset.CodeSystemVersionRepository;
import gov.samhsa.consent2share.domain.valueset.ConceptCode;
import gov.samhsa.consent2share.domain.valueset.ConceptCodeRepository;
import gov.samhsa.consent2share.domain.valueset.ConceptCodeValueSet;
import gov.samhsa.consent2share.domain.valueset.ConceptCodeValueSetRepository;
import gov.samhsa.consent2share.domain.valueset.ValueSet;
import gov.samhsa.consent2share.domain.valueset.ValueSetRepository;
import gov.samhsa.consent2share.service.dto.ConceptCodeDto;
import gov.samhsa.consent2share.service.dto.ConceptCodeVSCSDto;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.commons.lang.StringUtils;
import org.apache.poi.POIXMLException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.data.domain.Sort.Direction;
import org.springframework.data.domain.Sort.Order;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;
/**
* The Class ConceptCodeServiceImpl.
*/
public class ConceptCodeServiceImpl implements ConceptCodeService {
/** The logger. */
private final Logger logger = LoggerFactory.getLogger(this.getClass());
/** The concept code page size. */
public final int CONCEPT_CODE_PAGE_SIZE;
/** The concept code repository. */
private ConceptCodeRepository conceptCodeRepository;
/** The value set repository. */
private ValueSetRepository valueSetRepository;
/** The code system repository. */
CodeSystemRepository codeSystemRepository;
/** The code system version repository. */
CodeSystemVersionRepository codeSystemVersionRepository;
/** The concept code value set repository. */
ConceptCodeValueSetRepository conceptCodeValueSetRepository;
/** The value set mgmt helper. */
ValueSetMgmtHelper valueSetMgmtHelper;
/**
* Instantiates a new concept code service impl.
*
* @param conceptCodePageSize
* the concept code page size
* @param conceptCodeRepository
* the concept code repository
* @param valueSetRepository
* the value set repository
* @param codeSystemRepository
* the code system repository
* @param codeSystemVersionRepository
* the code system version repository
* @param conceptCodeValueSetRepository
* the concept code value set repository
* @param valueSetMgmtHelper
* the value set mgmt helper
*/
public ConceptCodeServiceImpl(int conceptCodePageSize,
ConceptCodeRepository conceptCodeRepository,
ValueSetRepository valueSetRepository,
CodeSystemRepository codeSystemRepository,
CodeSystemVersionRepository codeSystemVersionRepository,
ConceptCodeValueSetRepository conceptCodeValueSetRepository,
ValueSetMgmtHelper valueSetMgmtHelper) {
super();
CONCEPT_CODE_PAGE_SIZE = conceptCodePageSize;
this.conceptCodeRepository = conceptCodeRepository;
this.valueSetRepository = valueSetRepository;
this.codeSystemRepository = codeSystemRepository;
this.codeSystemVersionRepository = codeSystemVersionRepository;
this.conceptCodeValueSetRepository = conceptCodeValueSetRepository;
this.valueSetMgmtHelper = valueSetMgmtHelper;
}
/*
* (non-Javadoc)
*
* @see
* gov.samhsa.consent2share.service.valueset.ConceptCodeService#delete(java
* .lang.Long)
*/
@Override
@Transactional(rollbackFor = ConceptCodeNotFoundException.class)
public ConceptCodeDto delete(Long conceptCodeId)
throws ConceptCodeNotFoundException {
logger.debug("Deleting ConceptCode with id: " + conceptCodeId);
ConceptCode deleted = conceptCodeRepository.findOne(conceptCodeId);
if (deleted == null) {
logger.debug("No ConceptCode found with an id: " + conceptCodeId);
throw new ConceptCodeNotFoundException();
}
conceptCodeRepository.delete(deleted);
return valueSetMgmtHelper.createConceptCodeDtoFromEntity(deleted);
}
/*
* (non-Javadoc)
*
* @see
* gov.samhsa.consent2share.service.valueset.ConceptCodeService#findById
* (java.lang.Long)
*/
@Override
public ConceptCodeDto findById(Long id) throws ValueSetNotFoundException,
ConceptCodeNotFoundException {
logger.debug("Finding a ConceptCode with id: " + id);
ConceptCode conceptCode = conceptCodeRepository.findOne(id);
if (null == conceptCode) {
throw new ConceptCodeNotFoundException(
"Selected Code is not Available");
}
// get all value sets in the system
ConceptCodeDto conceptCodeDto = valueSetMgmtHelper
.createConceptCodeDtoFromEntity(conceptCode);
conceptCodeDto.setValueSetMap(getAllValueSetsInMap());
// get all selected value sets that are associated with this concept
// code
conceptCodeDto
.setValueSetIds(getAllValueSetIdsForConceptCode(conceptCode
.getId()));
return conceptCodeDto;
}
/*
* (non-Javadoc)
*
* @see
* gov.samhsa.consent2share.service.valueset.ConceptCodeService#update(gov
* .samhsa.consent2share.service.dto.ConceptCodeDto)
*/
@Override
@Transactional(rollbackFor = ConceptCodeNotFoundException.class)
public ConceptCodeDto update(ConceptCodeDto updated)
throws ConceptCodeNotFoundException, ValueSetNotFoundException {
logger.debug("Updating ConceptCode with information" + updated);
ConceptCode conceptCode = conceptCodeRepository
.findOne(updated.getId());
if (conceptCode == null) {
logger.debug("No ConceptCode found with an id: " + updated.getId());
throw new ConceptCodeNotFoundException();
}
conceptCode.update(updated.getCode(), updated.getName(),
updated.getUserName());
List<Long> selVsIds = updated.getValueSetIds();
// Atleast on valueset need to be associated with a concept code
if (null == selVsIds || selVsIds.size() <= 0) {
throw new ValueSetNotFoundException(
"Need to Associate atleast one valueset to the code: "
+ updated.getCode());
}
// 3.Get the value sets associated to the concept code
List<ConceptCodeValueSet> cValueSets = conceptCodeValueSetRepository
.findAllByPkConceptCodeId(conceptCode.getId());
if (cValueSets == null) {
throw new ValueSetNotFoundException(
"No Valusets associated to the given code" + conceptCode);
}
List<ConceptCodeValueSet> selCodeValueSets = new ArrayList<ConceptCodeValueSet>();
List<Long> selIds = new ArrayList<Long>();
for (ConceptCodeValueSet aCodeValueSet : cValueSets) {
for (Long selId : selVsIds) {
if (aCodeValueSet.getValueSet().getId().equals(selId)) {
selCodeValueSets.add(aCodeValueSet);
selIds.add(selId);
break;
}
}
}
// remove the selected value sets
cValueSets.removeAll(selCodeValueSets);
selVsIds.removeAll(selIds);
// delete the (existing that are not selected )association
if (null != cValueSets && cValueSets.size() > 0)
conceptCodeValueSetRepository.delete(cValueSets);
// add the new associations
List<ConceptCodeValueSet> cVSets = new ArrayList<ConceptCodeValueSet>();
for (Long id : selVsIds) {
ValueSet vSet = valueSetRepository.findOne(id);
if (null == vSet) {
throw new ValueSetNotFoundException(
"No Valueset Found for the Selected Name");
}
ConceptCodeValueSet cValueSet = ConceptCodeValueSet.getBuilder(
conceptCode, vSet).build();
cVSets.add(cValueSet);
}
if (null != cVSets && cVSets.size() > 0)
cVSets = conceptCodeValueSetRepository.save(cVSets);
// set the selected ones back to concept code
conceptCode.setValueSets(selCodeValueSets);
// conceptCodeValueSetRepository.save(selCodeValueSets);
return valueSetMgmtHelper.createConceptCodeDtoFromEntity(conceptCode);
// return null;
}
/*
* (non-Javadoc)
*
* @see
* gov.samhsa.consent2share.service.valueset.ConceptCodeService#findAll()
*/
@Override
public List<ConceptCodeDto> findAll() {
logger.debug("Finding all conceptCodes");
List<ConceptCode> conceptCodes = conceptCodeRepository.findAll();
return valueSetMgmtHelper
.convertConceptCodeEntitiesToDtos(conceptCodes);
}
/*
* (non-Javadoc)
*
* @see
* gov.samhsa.consent2share.service.valueset.ConceptCodeService#findAll()
*/
@Override
public Map<String, Object> findAll(int pageNumber) {
logger.debug("Finding all conceptCodes with paging");
Sort sort = new Sort(new Order(Direction.ASC, "code"));
PageRequest pageRequest = new PageRequest(pageNumber,
CONCEPT_CODE_PAGE_SIZE, sort);
Page<ConceptCode> pagedConceptCodes = conceptCodeRepository
.findAll(pageRequest);
logger.debug("Total Concept Codes: "
+ pagedConceptCodes.getTotalElements());
logger.debug("Total Pages: " + pagedConceptCodes.getTotalPages());
Map<String, Object> pageResultsMap = new HashMap<String, Object>();
pageResultsMap.put("conceptCodes", valueSetMgmtHelper
.convertConceptCodeEntitiesToDtos(pagedConceptCodes
.getContent()));
pageResultsMap.put("totalNumberOfConceptCodes",
pagedConceptCodes.getTotalElements());
pageResultsMap.put("totalPages", pagedConceptCodes.getTotalPages());
pageResultsMap.put("itemsPerPage", pagedConceptCodes.getSize());
pageResultsMap.put("currentPage", pagedConceptCodes.getNumber());
pageResultsMap.put("numberOfElements",
pagedConceptCodes.getNumberOfElements());
return pageResultsMap;
}
/*
* (non-Javadoc)
*
* @see
* gov.samhsa.consent2share.service.valueset.ConceptCodeService#findAllByCode
* (java.lang.String)
*/
@Override
public Map<String, Object> findAllByCode(String searchTerm,
String codeSystem, String codeSystemVersion, String valueSetName,
int pageNumber) {
Sort sort = new Sort(new Order(Direction.ASC, "code"));
PageRequest pageRequest = new PageRequest(pageNumber,
CONCEPT_CODE_PAGE_SIZE, sort);
Page<ConceptCode> pagedConceptCodes = conceptCodeRepository
.findAllByCodeLike("%" + searchTerm + "%", "%" + codeSystem
+ "%", "%" + codeSystemVersion + "%", "%"
+ valueSetName + "%", pageRequest);
logger.debug("Total Concept Codes: "
+ pagedConceptCodes.getTotalElements());
logger.debug("Total Pages: " + pagedConceptCodes.getTotalPages());
Map<String, Object> pageResultsMap = new HashMap<String, Object>();
pageResultsMap.put("conceptCodes", valueSetMgmtHelper
.convertConceptCodeEntitiesToDtos(pagedConceptCodes
.getContent()));
pageResultsMap.put("totalNumberOfConceptCodes",
pagedConceptCodes.getTotalElements());
pageResultsMap.put("totalPages", pagedConceptCodes.getTotalPages());
pageResultsMap.put("itemsPerPage", pagedConceptCodes.getSize());
pageResultsMap.put("currentPage", pagedConceptCodes.getNumber());
pageResultsMap.put("numberOfElements",
pagedConceptCodes.getNumberOfElements());
return pageResultsMap;
}
/*
* (non-Javadoc)
*
* @see
* gov.samhsa.consent2share.service.valueset.ConceptCodeService#findAllByName
* (java.lang.String, java.lang.String, java.lang.String, java.lang.String,
* int)
*/
@Override
public Map<String, Object> findAllByName(String searchTerm,
String codeSystem, String codeSystemVersion, String valueSetName,
int pageNumber) {
Sort sort = new Sort(new Order(Direction.ASC, "name"));
PageRequest pageRequest = new PageRequest(pageNumber,
CONCEPT_CODE_PAGE_SIZE, sort);
if (StringUtils.isEmpty(valueSetName))
valueSetName = "%";
Page<ConceptCode> pagedConceptCodes = conceptCodeRepository
.findAllByName("%" + searchTerm + "%", "%" + codeSystem + "%",
"%" + codeSystemVersion + "%", valueSetName,
pageRequest);
logger.debug("Total Concept Codes: "
+ pagedConceptCodes.getTotalElements());
logger.debug("Total Pages: " + pagedConceptCodes.getTotalPages());
Map<String, Object> pageResultsMap = new HashMap<String, Object>();
pageResultsMap.put("conceptCodes", valueSetMgmtHelper
.convertConceptCodeEntitiesToDtos(pagedConceptCodes
.getContent()));
pageResultsMap.put("totalNumberOfConceptCodes",
pagedConceptCodes.getTotalElements());
pageResultsMap.put("totalPages", pagedConceptCodes.getTotalPages());
pageResultsMap.put("itemsPerPage", pagedConceptCodes.getSize());
pageResultsMap.put("currentPage", pagedConceptCodes.getNumber());
pageResultsMap.put("numberOfElements",
pagedConceptCodes.getNumberOfElements());
return pageResultsMap;
}
/*
* (non-Javadoc)
*
* @see
* gov.samhsa.consent2share.service.valueset.ConceptCodeService#create()
*/
@Override
public ConceptCodeVSCSDto create() throws ValueSetNotFoundException,
CodeSystemVersionNotFoundException, CodeSystemNotFoundException {
ConceptCodeVSCSDto conceptCodeVSCSDto = new ConceptCodeVSCSDto();
conceptCodeVSCSDto.setValueSetsMap(getAllValueSetsInMap());
// Get all code system versions
List<CodeSystem> codeSystems = codeSystemRepository.findAll();
if (codeSystems == null || codeSystems.size() == 0) {
logger.debug("No codeSystems found in the system");
throw new CodeSystemNotFoundException();
}
conceptCodeVSCSDto.setCsVersions(valueSetMgmtHelper
.createCSVersionsDTOFormEntity(codeSystems));
return conceptCodeVSCSDto;
}
/*
* (non-Javadoc)
*
* @see
* gov.samhsa.consent2share.service.valueset.ConceptCodeService#create(gov
* .samhsa.consent2share.service.dto.ConceptCodeDto)
*/
@Override
@Transactional
public ConceptCodeDto create(ConceptCodeDto created)
throws ValueSetNotFoundException, CodeSystemNotFoundException,
DuplicateConceptCodeException {
ConceptCodeDto conceptCodeDto = new ConceptCodeDto();
String description = (created.getDescription() != null) ? created
.getDescription() : "";
// STEP:1 :- Get CodeSystemVersion Object from DB
Long codeSystemVersionId = created.getCodeSystemVersionId();
// find code system version
CodeSystemVersion selectedCsv = codeSystemVersionRepository
.findOne(codeSystemVersionId);
if (selectedCsv == null) {
logger.debug("No Code System version found with an id: "
+ codeSystemVersionId);
throw new CodeSystemNotFoundException();
}
List<Long> selVsIds = created.getValueSetIds();
if (null == selVsIds || selVsIds.size() <= 0) {
throw new ValueSetNotFoundException(
"Need to Associate atleast one valueset to the code: "
+ created.getCode());
}
boolean isNewVS = false;
int conceptCodesInserted = 0;
// Loop through for each selected value set
for (Long valueSetId : selVsIds) {
// STEP:2 :-Get valueset Object from DB
// Long valueSetId = created.getValueSetId();
ValueSet selectedVs = valueSetRepository.findOne(valueSetId);
if (selectedVs == null) {
logger.debug("No valueSet found with an id: " + valueSetId);
throw new ValueSetNotFoundException();
}
// STEP:3 :- Code and its association with value set save
// Check if conceptcode already exists for the code system version
logger.debug("Creating a new ConceptCode with information: "
+ created);
ConceptCode conceptCode = conceptCodeRepository
.findByCodeAndCodeSystemVersionId(created.getCode(),
selectedCsv.getId());
ConceptCodeValueSet conceptCodeValueSet = ConceptCodeValueSet
.getBuilder(conceptCode, selectedVs).build();
if (null != conceptCode) {
// check if association between code and valueset exists
conceptCodeValueSet = conceptCodeValueSetRepository
.findOne(conceptCodeValueSet.getPk());
if (null == conceptCodeValueSet) {
// Scenario-1 : Code Exists and Code with VS association
// does not exists
// build and save association
conceptCodeValueSet = ConceptCodeValueSet.getBuilder(
conceptCode, selectedVs).build();
// save association
conceptCodeValueSet = conceptCodeValueSetRepository
.save(conceptCodeValueSet);
isNewVS = true;
conceptCodesInserted++;
} else {
// Scenario-2 : Code Exists and Code with VS association
// exists
logger.debug("Code and Code with VS association exists: "
+ created);
// isVSPresent = true;
}
} else {
// Scenario-3 : Code and Code with VS association does not
// exists
// build conceptcode
conceptCode = ConceptCode
.getBuilder(created.getCode(), created.getName(),
created.getUserName()).description(description)
.build();
// set code system version
conceptCode.setCodeSystemVersion(selectedCsv);
// Create ConceptCode_Valueset object
conceptCodeValueSet = ConceptCodeValueSet.getBuilder(
conceptCode, selectedVs).build();
List<ConceptCodeValueSet> vs = new ArrayList<ConceptCodeValueSet>();
vs.add(conceptCodeValueSet);
// map association
conceptCode.setValueSets(vs);
isNewVS = true;
// Save conceptcode
conceptCode = conceptCodeRepository.save(conceptCode);
conceptCodesInserted++;
}
conceptCodeDto = valueSetMgmtHelper
.createConceptCodeDtoFromEntity(conceptCode);
}
conceptCodeDto.setConceptCodesInserted(conceptCodesInserted);
if (!isNewVS) {
throw new DuplicateConceptCodeException();
}
return conceptCodeDto;
}
/*
* (non-Javadoc)
*
* @see gov.samhsa.consent2share.service.valueset.ConceptCodeService#
* conceptCodeBatchUpload
* (gov.samhsa.consent2share.service.dto.ConceptCodeDto,
* org.springframework.web.multipart.MultipartFile, java.lang.String,
* java.lang.String, java.lang.Long)
*/
@Override
@Transactional(rollbackFor = DataIntegrityViolationException.class)
public ConceptCodeDto conceptCodeBatchUpload(ConceptCodeDto conceptCodeDto,
MultipartFile file, String codeSystemId, Long codeSystemVersionId,
List<Long> valueSetIds) throws ValueSetNotFoundException,
CodeSystemNotFoundException {
String userName = conceptCodeDto.getUserName();
try {
List<ConceptCodeDto> listOfConceptCodeDtos = valueSetMgmtHelper
.readConceptCodesFromFile(file, codeSystemId,
codeSystemVersionId, valueSetIds, userName);
int rowsUpdated = 0;
// for batch upload
List<Integer> listOfDuplicateCodes = new ArrayList<Integer>();
// iterate rows with value set fields
for (int i = 0; i < listOfConceptCodeDtos.size(); i++) {
try {
conceptCodeDto = create(listOfConceptCodeDtos.get(i));
rowsUpdated = rowsUpdated
+ conceptCodeDto.getConceptCodesInserted();
} catch (DuplicateConceptCodeException e) {
// adjusting for header row
listOfDuplicateCodes.add(i + 2);
}
}
conceptCodeDto.setConceptCodesInserted(rowsUpdated);
conceptCodeDto.setListOfDuplicatesCodes(listOfDuplicateCodes);
} catch (ValueSetNotFoundException ex) {
logger.debug("Missing required field while doing batch upload: "
+ ex.getMessage());
conceptCodeDto.setError(true);
conceptCodeDto.setErrorMessage(ex.getMessage());
throw ex;
} catch (InvalidCSVException ex) {
conceptCodeDto.setError(true);
conceptCodeDto.setErrorMessage(ex.getMessage());
throw ex;
} catch (POIXMLException ex) {
logger.debug("Incorrect file format: " + ex.getMessage());
conceptCodeDto.setError(true);
conceptCodeDto
.setErrorMessage("Incorrect file format. File should be a correct .xslx file");
} catch (IOException ex) {
logger.debug("Unable to open file: " + ex.getMessage());
conceptCodeDto.setError(true);
conceptCodeDto.setErrorMessage("Unable to open file");
} catch (Exception ex) {
logger.debug("Exception thrown: " + ex.getMessage());
conceptCodeDto.setError(true);
conceptCodeDto
.setErrorMessage("An error occurred. Please check with administrator: "
+ ex.getMessage());
}
return conceptCodeDto;
}
/*
* (non-Javadoc)
*
* @see gov.samhsa.consent2share.service.valueset.ConceptCodeService#
* findValueSetsByCodeSystem(java.lang.String, java.lang.String)
*/
@Override
public List<ValueSet> findValueSetsByCodeSystem(String codeSystem,
String codeSystemVersion) {
return conceptCodeRepository.findValueSetNamesFilterByCodeSystem(
codeSystem, codeSystemVersion);
}
/**
* This setter method should be used only by unit tests.
*
* @param conceptCodeRepository
* the new concept code repository
*/
protected void setConceptCodeRepository(
ConceptCodeRepository conceptCodeRepository) {
this.conceptCodeRepository = conceptCodeRepository;
}
/**
* Gets the all value sets in map.
*
* @return the all value sets in map
* @throws ValueSetNotFoundException
* the value set not found exception
*/
private Map<Long, String> getAllValueSetsInMap()
throws ValueSetNotFoundException {
// Get all valuesets
List<ValueSet> valueSets = valueSetRepository.findAll();
if (valueSets == null || valueSets.size() == 0) {
logger.debug("No Valuesets found in the system");
throw new ValueSetNotFoundException(
"No Value Sets Found in the system");
}
return valueSetMgmtHelper.convertValueSetEntitiesToMap(valueSets);
}
/**
* Gets the all value set ids for concept code.
*
* @param conceptCodeId
* the concept code id
* @return the all value set ids for concept code
*/
private List<Long> getAllValueSetIdsForConceptCode(Long conceptCodeId) {
List<ConceptCodeValueSet> cValueSets = conceptCodeValueSetRepository
.findAllByPkConceptCodeId(conceptCodeId);
List<Long> selValueSetIds = new ArrayList<Long>();
for (ConceptCodeValueSet cValueSet : cValueSets) {
selValueSetIds.add(cValueSet.getValueSet().getId());
}
return selValueSetIds;
}
}