package org.nextprot.api.core.service.impl; import com.google.common.collect.ImmutableList; import org.nextprot.api.commons.constants.AnnotationCategory; import org.nextprot.api.commons.constants.PropertyApiModel; import org.nextprot.api.commons.exception.NextProtException; import org.nextprot.api.commons.service.MasterIdentifierService; import org.nextprot.api.core.dao.PeptideMappingDao; import org.nextprot.api.core.domain.PeptideMapping; import org.nextprot.api.core.domain.PeptideMapping.PeptideEvidence; import org.nextprot.api.core.domain.PeptideMapping.PeptideProperty; import org.nextprot.api.core.domain.annotation.*; import org.nextprot.api.core.service.PeptideMappingService; import org.nextprot.api.core.service.PeptideNamesService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.cache.annotation.Cacheable; import org.springframework.stereotype.Service; import java.util.*; @Service public class PeptideMappingServiceImpl implements PeptideMappingService { @Autowired private MasterIdentifierService masterIdentifierService; @Autowired private PeptideMappingDao peptideMappingDao; @Autowired private PeptideNamesService peptideNamesService; @Override @Cacheable("natural-peptides") public List<PeptideMapping> findNaturalPeptideMappingByMasterUniqueName(String uniqueName) { Long masterId = this.masterIdentifierService.findIdByUniqueName(uniqueName); List<PeptideMapping> peps = findPeptideMappingByMasterId(masterId, true); //returns a immutable list when the result is cacheable (this prevents modifying the cache, since the cache returns a reference) copy on read and copy on write is too much time consuming return new ImmutableList.Builder<PeptideMapping>().addAll(peps).build(); } @Override @Cacheable("srm-peptides") public List<PeptideMapping> findSyntheticPeptideMappingByMasterUniqueName(String uniqueName) { Long masterId = this.masterIdentifierService.findIdByUniqueName(uniqueName); List<PeptideMapping> peps = findPeptideMappingByMasterId(masterId, false); //returns a immutable list when the result is cacheable (this prevents modifying the cache, since the cache returns a reference) copy on read and copy on write is too much time consuming return new ImmutableList.Builder<PeptideMapping>().addAll(peps).build(); } private List<PeptideMapping> findPeptideMappingByMasterId(Long id, boolean isNatural) { List<PeptideMapping> allMapping = isNatural ? this.peptideMappingDao.findNaturalPeptidesByMasterId(id) : this.peptideMappingDao.findSyntheticPeptidesByMasterId(id) ; // key=peptide,value=mapping with 1-n isospecs, 1-n evidences, 1-n properties Map<String, PeptideMapping> mergeMap = new HashMap<>(); if (!allMapping.isEmpty()) { List<String> peptideNames = new ArrayList<>(); Iterator<AnnotationIsoformSpecificity> it; for (PeptideMapping mapping : allMapping) { String key = mapping.getPeptideUniqueName(); if (!mergeMap.containsKey(key)) { // not in the map peptideNames.add(mapping.getPeptideUniqueName()); mergeMap.put(key, mapping); } else { // already in the map it = mapping.getIsoformSpecificity().values().iterator(); if (it.hasNext()) mergeMap.get(key).addIsoformSpecificity(it.next()); } } // attach evidences to peptide mappings List<PeptideEvidence> evidences = isNatural ? this.peptideMappingDao.findNaturalPeptideEvidences(peptideNames) : this.peptideMappingDao.findSyntheticPeptideEvidences(peptideNames); for (PeptideEvidence evidence : evidences) mergeMap.get(evidence.getPeptideName()).addEvidence(evidence); // attach properties to peptide mappings List<PeptideProperty> props = this.peptideMappingDao.findPeptideProperties(peptideNames); for (PeptideProperty prop: props) mergeMap.get(prop.getPeptideName()).addProperty(prop); } return new ArrayList<>(mergeMap.values()); } /* * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - * new interface * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ @Override @Cacheable("natural-peptide-mapping-annotations") public List<Annotation> findNaturalPeptideMappingAnnotationsByMasterUniqueName(String uniqueName) { return findPeptideMappingAnnotationsByMasterUniqueName(uniqueName,true); } @Override @Cacheable("srm-peptide-mapping-annotations") public List<Annotation> findSyntheticPeptideMappingAnnotationsByMasterUniqueName(String uniqueName) { return findPeptideMappingAnnotationsByMasterUniqueName(uniqueName,false); } private List<Annotation> findPeptideMappingAnnotationsByMasterUniqueName(String uniqueName, boolean withNatural) { Long masterId = this.masterIdentifierService.findIdByUniqueName(uniqueName); boolean withSynthetic = ! withNatural; List<Map<String, Object>> records = this.peptideMappingDao.findPeptideMappingAnnotationsByMasterId(masterId, withNatural, withSynthetic); Map<Long,Annotation> annotationMap = buildAnnotationMapFromRecords(records, withNatural); List<Annotation> annotations = new ArrayList<>(annotationMap.values()); if (annotations.isEmpty()) return annotations; List<String> pepNames = this.peptideNamesService.findAllPeptideNamesByMasterId(uniqueName); Map<String,List<AnnotationProperty>> props = this.peptideMappingDao.findPeptideAnnotationPropertiesMap(pepNames); attachPeptidePropertiesToAnnotations(annotations, props); Map<String,List<AnnotationEvidence>> evidences = this.peptideMappingDao.findPeptideAnnotationEvidencesMap(pepNames, withNatural); // nat=true,synth=false attachPeptideEvidencesToAnnotations(annotations, evidences); //returns a immutable list when the result is cacheable (this prevents modifying the cache, //since the cache returns a reference) copy on read and copy on write is too much time consuming return new ImmutableList.Builder<Annotation>().addAll(annotations).build(); } // TODO: REFACTOR ME, I'M NOT DRY! (COPY/PASTED FROM METHOD BELOW) static void attachPeptidePropertiesToAnnotations(List<Annotation> annotations, Map<String, List<AnnotationProperty>> propMap) { for (Annotation annot: annotations) { if (!annot.getPropertiesMap().containsKey(PropertyApiModel.NAME_PEPTIDE_NAME)) { throw new NextProtException("Cannot found property name " + PropertyApiModel.NAME_PEPTIDE_NAME); } Collection<AnnotationProperty> properties = annot.getPropertiesByKey(PropertyApiModel.NAME_PEPTIDE_NAME); AnnotationProperty pepNameProperty = properties.iterator().next(); // WARNING: we expect first property in list be the "peptide name" property ! String pepName = pepNameProperty.getValue(); if (!propMap.containsKey(pepName)) { throw new NextProtException("Found no props for peptide with name:" + pepName); } List<AnnotationProperty> props = cloneUsefulPropertiesForAnnotation(propMap.get(pepName), annot.getAnnotationId()); annot.addProperties(props); } } // TODO: REFACTOR ME, I'M NOT DRY! (COPY/PASTED FROM METHOD ABOVE) static void attachPeptideEvidencesToAnnotations(List<Annotation> annotations, Map<String, List<AnnotationEvidence>> evidences) { for (Annotation annot: annotations) { if (!annot.getPropertiesMap().containsKey(PropertyApiModel.NAME_PEPTIDE_NAME)) { throw new NextProtException("Cannot found property name " + PropertyApiModel.NAME_PEPTIDE_NAME); } Collection<AnnotationProperty> properties = annot.getPropertiesByKey(PropertyApiModel.NAME_PEPTIDE_NAME); AnnotationProperty pepNameProperty = properties.iterator().next(); // WARNING: we expect first property in list be the "peptide name" property ! String pepName = pepNameProperty.getValue(); if (!evidences.containsKey(pepName)) { throw new NextProtException("Found no evidence for peptide with name:" + pepName); } List<AnnotationEvidence> clonedList = cloneEvidencesForAnnotation(evidences.get(pepName), annot.getAnnotationId()); annot.setEvidences(clonedList); } } /* * clone the property 'is proteotypic' and sets its annotation id * and return a list containing this "cloned" property */ static List<AnnotationProperty> cloneUsefulPropertiesForAnnotation(List<AnnotationProperty> peptideProperties, Long annotationId) { List<AnnotationProperty> result = new ArrayList<>(); for (AnnotationProperty pp: peptideProperties) { if (pp.getName().equals(PropertyApiModel.NAME_PEPTIDE_PROTEOTYPICITY)) { AnnotationProperty ap = new AnnotationProperty(); ap.setAnnotationId(annotationId); ap.setAccession(pp.getAccession()); ap.setName(pp.getName()); ap.setValue(pp.getValue()); ap.setValueType(pp.getValueType()); result.add(ap); } } return result; } static List<AnnotationEvidence> cloneEvidencesForAnnotation(List<AnnotationEvidence> peptideEvidences, Long annotationId) { List<AnnotationEvidence> result = new ArrayList<>(); for (AnnotationEvidence pepEvi: peptideEvidences) { AnnotationEvidence annEvi = new AnnotationEvidence(); annEvi.setAnnotationId(annotationId); annEvi.setAssignedBy(pepEvi.getAssignedBy()); annEvi.setAssignmentMethod(pepEvi.getAssignmentMethod()); annEvi.setEvidenceCodeAC(pepEvi.getEvidenceCodeAC()); annEvi.setEvidenceCodeName(pepEvi.getEvidenceCodeName()); annEvi.setEvidenceId(pepEvi.getEvidenceId()); annEvi.setExperimentalContextId(pepEvi.getExperimentalContextId()); annEvi.setNegativeEvidence(pepEvi.isNegativeEvidence()); annEvi.setQualifierType(pepEvi.getQualifierType()); annEvi.setQualityQualifier(pepEvi.getQualityQualifier()); annEvi.setResourceAccession(pepEvi.getResourceAccession()); annEvi.setResourceAssociationType(pepEvi.getResourceAssociationType()); annEvi.setResourceDb(pepEvi.getResourceDb()); annEvi.setResourceDescription(pepEvi.getResourceDescription()); annEvi.setResourceId(pepEvi.getResourceId()); annEvi.setResourceType(pepEvi.getResourceType()); annEvi.setEvidenceCodeOntology(pepEvi.getEvidenceCodeOntology()); if (pepEvi.getPropertiesNames()!=null) { List<AnnotationEvidenceProperty> props = new ArrayList<>(); for (String n: pepEvi.getPropertiesNames()) { String v = pepEvi.getPropertyValue(n); AnnotationEvidenceProperty prop = new AnnotationEvidenceProperty(); prop.setEvidenceId(pepEvi.getEvidenceId()); prop.setPropertyName(n); prop.setPropertyValue(v); props.add(prop); } annEvi.setProperties(props); } result.add(annEvi); } return result; } static Map<Long,Annotation> buildAnnotationMapFromRecords(List<Map<String,Object>> records, boolean isNatural) { Map<Long,Annotation> annotationMap = new HashMap<>(); for (Map<String,Object> record: records) { // retrieve record field values Long annotationId = (Long)record.get(PeptideMappingDao.KEY_ANNOTATION_ID); String iso = (String)record.get(PeptideMappingDao.KEY_ISO_UNIQUE_NAME); String pep = (String)record.get(PeptideMappingDao.KEY_PEP_UNIQUE_NAME); Integer firstPos = (Integer)record.get(PeptideMappingDao.KEY_FIRST_POS); Integer lastPos = (Integer)record.get(PeptideMappingDao.KEY_LAST_POS); String quality = (String)record.get(PeptideMappingDao.KEY_QUALITY_QUALIFIER); String category = isNatural ? AnnotationCategory.PEPTIDE_MAPPING.getDbAnnotationTypeName() : AnnotationCategory.SRM_PEPTIDE_MAPPING.getDbAnnotationTypeName(); // if annot never seen before, put it into the map and initialize it if (!annotationMap.containsKey(annotationId)) { Annotation annot = new Annotation(); annotationMap.put(annotationId, annot); annot.setAnnotationId(annotationId); annot.setCategory(category); annot.setQualityQualifier(quality); annot.addTargetingIsoforms(new ArrayList<AnnotationIsoformSpecificity>()); String entry = iso.substring(0, iso.indexOf('-')); String nature = isNatural ? "_NATUR": "_SYNTH"; annot.setUniqueName("AN_" + entry + "_" + annot.getAnnotationId() + nature); // add peptide name property List<AnnotationProperty> props = new ArrayList<>(); AnnotationProperty prop = new AnnotationProperty(); prop.setAnnotationId(annotationId); prop.setName(PropertyApiModel.NAME_PEPTIDE_NAME); prop.setValue(pep); props.add(prop); annot.addProperties(props); } // add isoform specificity Annotation annot = annotationMap.get(annotationId); AnnotationIsoformSpecificity spec = new AnnotationIsoformSpecificity(); spec.setAnnotationId(annotationId); spec.setFirstPosition(firstPos); spec.setLastPosition(lastPos); spec.setIsoformAccession(iso); spec.setSpecificity("SPECIFIC"); annot.getTargetingIsoformsMap().put(iso, spec); } return annotationMap; } }