package uk.ac.ebi.ep.controller; import java.util.ArrayList; import java.util.LinkedList; import java.util.List; import java.util.stream.Collectors; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import org.apache.log4j.Logger; import org.jsoup.Jsoup; import org.jsoup.safety.Whitelist; import org.springframework.data.domain.Page; import org.springframework.data.domain.PageImpl; import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Pageable; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.validation.BindingResult; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestParam; import uk.ac.ebi.ep.data.search.model.SearchModel; import uk.ac.ebi.ep.ebeye.enzyme.model.Entry; import uk.ac.ebi.ep.ebeye.model.EBISearchResult; import uk.ac.ebi.ep.ebeye.protein.model.Protein; import uk.ac.ebi.ep.web.utils.KeywordType; /** * * @author Joseph <joseph@ebi.ac.uk> */ @Controller public class EnzymeCentricController extends AbstractController { private static final Logger logger = Logger.getLogger(EnzymeCentricController.class); private static final String SEARCH = "/enzymes"; private static final String FILTER = "/search/filter"; private static final String ENZYME_CENTRIC_PAGE = "enzymes"; private static final int DEFAULT_EBI_SEARCH_FACET_COUNT = 1_000; private static final int ASSOCIATED_PROTEIN_LIMIT = 8_00; private static final int PAGE_SIZE = 10; @RequestMapping(value = SEARCH, method = RequestMethod.GET) public String getSearchResults(@RequestParam(required = false, value = "searchKey") String searchKey, @RequestParam(required = false, value = "filterFacet") List<String> filters, @RequestParam(required = false, value = "servicePage") Integer servicePage, @RequestParam(required = false, value = "keywordType") String keywordType, @RequestParam(required = false, value = "searchId") String searchId, SearchModel searchModel, BindingResult result, Model model, HttpSession session, HttpServletRequest request, HttpServletResponse response) { return postSearchResult(searchKey, filters, servicePage, keywordType, searchId, searchModel, model, request); } @RequestMapping(value = SEARCH, method = RequestMethod.POST) public String postSearchResult(@RequestParam(required = false, value = "searchKey") String searchKey, @RequestParam(required = false, value = "filterFacet") List<String> filters, @RequestParam(required = false, value = "servicePage") Integer servicePage, @RequestParam(required = false, value = "keywordType") String keywordType, @RequestParam(required = false, value = "searchId") String searchId, SearchModel searchModel, Model model, HttpServletRequest request) { String view = "error"; int startPage = 0; if (servicePage != null) { if (servicePage < 0) { servicePage = 1; } startPage = servicePage - 1;//EBI search paging index starts at 0 } int pageSize = PAGE_SIZE; int facetCount = DEFAULT_EBI_SEARCH_FACET_COUNT; int associatedProteinLimit = ASSOCIATED_PROTEIN_LIMIT; if (filters == null) { filters = new ArrayList<>(); } if (searchModel.getSearchparams().getText() != null) { searchKey = searchModel.getSearchparams().getText().trim().toLowerCase(); } final String searchTerm = Jsoup.clean(searchKey, Whitelist.basic()); if (filters.contains("")) { filters.remove(""); } KeywordType type = KeywordType.valueOf(keywordType); switch (type) { case KEYWORD: boolean isEc = searchUtil.validateEc(searchTerm); if (isEc) { view = findEnzymesByEC(searchTerm, startPage, pageSize, facetCount, filters, associatedProteinLimit, searchKey, keywordType, model, searchModel, view); } else { view = findEnzymesBySearchTerm(searchTerm, startPage, pageSize, facetCount, filters, associatedProteinLimit, searchKey, keywordType, model, searchModel, view); } break; case DISEASE: view = findEnzymesByOmimId(searchId, startPage, pageSize, facetCount, filters, associatedProteinLimit, searchKey, keywordType, model, searchModel, view); break; case TAXONOMY: view = findEnzymesByTaxId(searchId, startPage, pageSize, facetCount, filters, associatedProteinLimit, searchKey, keywordType, model, searchModel, view); break; case PATHWAYS: view = findEnzymesByPathwayId(searchId, startPage, pageSize, facetCount, filters, associatedProteinLimit, searchKey, keywordType, model, searchModel, view); break; case EC: view = findEnzymesByEC(searchId, startPage, pageSize, facetCount, filters, associatedProteinLimit, searchKey, keywordType, model, searchModel, view); break; default: return view; } return view; } private EBISearchResult getEbiSearchResult(String query, int startPage, int pageSize, int facetCount, List<String> filters) { String facets = filters.stream().collect(Collectors.joining(",")); return enzymeCentricService.getSearchResult(query, startPage, pageSize, facets, facetCount); } private EBISearchResult getEbiSearchResultByOmimId(String omimId, int startPage, int pageSize, int facetCount, List<String> filters) { String facets = filters.stream().collect(Collectors.joining(",")); return enzymeCentricService.findEbiSearchResultsByOmimId(omimId, startPage, pageSize, facets, facetCount); } private EBISearchResult getEbiSearchResultByTaxId(String taxId, int startPage, int pageSize, int facetCount, List<String> filters) { String facets = filters.stream().collect(Collectors.joining(",")); return enzymeCentricService.findEbiSearchResultsByTaxId(taxId, startPage, pageSize, facets, facetCount); } private EBISearchResult getEbiSearchResultByEC(String ec, int startPage, int pageSize, int facetCount, List<String> filters) { String facets = filters.stream().collect(Collectors.joining(",")); return enzymeCentricService.findEbiSearchResultsByEC(ec, startPage, pageSize, facets, facetCount); } private EBISearchResult getEbiSearchResultByPathwayId(String pathwayId, int startPage, int pageSize, int facetCount, List<String> filters) { String facets = filters.stream().collect(Collectors.joining(",")); return enzymeCentricService.findEbiSearchResultsByPathwayId(pathwayId, startPage, pageSize, facets, facetCount); } private String findEnzymesBySearchTerm(String searchTerm, int startPage, int pageSize, int facetCount, List<String> filters, int associatedProteinLimit, String searchKey, String keywordType, Model model, SearchModel searchModel, String view) { EBISearchResult ebiSearchResult = getEbiSearchResult(searchTerm, startPage * pageSize, pageSize, facetCount, filters); int LOWEST_BEST_MATCHED_RESULT_SIZE = 4; if (ebiSearchResult != null) { long hitCount = ebiSearchResult.getHitCount(); Pageable pageable = new PageRequest(startPage, pageSize); Page<Entry> page = new PageImpl<>(ebiSearchResult.getEntries(), pageable, hitCount); List<Entry> entries = page.getContent(); List<Entry> enzymeView = new LinkedList<>(); entries.stream().forEach(entry -> { List<Protein> proteins = ebeyeRestService.queryForUniqueProteins(entry.getEc(), searchTerm, associatedProteinLimit) .stream() .sorted() .collect(Collectors.toList()); if (proteins.isEmpty()) { proteins = ebeyeRestService.queryForUniqueProteins(entry.getEc(), associatedProteinLimit) .stream() .limit(LOWEST_BEST_MATCHED_RESULT_SIZE) .sorted() .collect(Collectors.toList()); } addProteinEntryToEnzymeView(proteins, entry, enzymeView); }); if (enzymeView.isEmpty() && !ebiSearchResult.getEntries().isEmpty()) { logger.info(ebiSearchResult.getEntries().size() + " results are found in Enzyme-centric index for query " + searchTerm + " But none in Protein-centric index"); ebiSearchResult = new EBISearchResult(); ebiSearchResult.setFacets(new ArrayList<>()); ebiSearchResult.setHitCount(0); ebiSearchResult.setEntries(new ArrayList<>()); page = new PageImpl<>(ebiSearchResult.getEntries(), pageable, 0); } return constructModel(ebiSearchResult, enzymeView, page, filters, searchTerm, searchKey, keywordType, model, searchModel); } return view; } private String findEnzymesByOmimId(String omimId, int startPage, int pageSize, int facetCount, List<String> filters, int associatedProteinLimit, String searchKey, String keywordType, Model model, SearchModel searchModel, String view) { EBISearchResult ebiSearchResult = getEbiSearchResultByOmimId(omimId, startPage * pageSize, pageSize, facetCount, filters); if (ebiSearchResult != null) { long hitCount = ebiSearchResult.getHitCount(); Pageable pageable = new PageRequest(startPage, pageSize); Page<Entry> page = new PageImpl<>(ebiSearchResult.getEntries(), pageable, hitCount); List<Entry> entries = page.getContent(); List<Entry> enzymeView = new LinkedList<>(); entries.stream() .forEach(entry -> { List<Protein> proteins = ebeyeRestService.findUniqueProteinsByOmimIdAndEc(omimId, entry.getEc(), associatedProteinLimit) .stream() .sorted() .collect(Collectors.toList()); addProteinEntryToEnzymeView(proteins, entry, enzymeView); }); return constructModel(ebiSearchResult, enzymeView, page, filters, omimId, searchKey, keywordType, model, searchModel); } return view; } private String findEnzymesByTaxId(String taxId, int startPage, int pageSize, int facetCount, List<String> filters, int associatedProteinLimit, String searchKey, String keywordType, Model model, SearchModel searchModel, String view) { EBISearchResult ebiSearchResult = getEbiSearchResultByTaxId(taxId, startPage * pageSize, pageSize, facetCount, filters); if (ebiSearchResult != null) { long hitCount = ebiSearchResult.getHitCount(); Pageable pageable = new PageRequest(startPage, pageSize); Page<Entry> page = new PageImpl<>(ebiSearchResult.getEntries(), pageable, hitCount); List<Entry> entries = page.getContent(); List<Entry> enzymeView = new LinkedList<>(); entries.stream() .forEach(entry -> { List<Protein> proteins = ebeyeRestService.findUniqueProteinsByTaxIdAndEc(taxId, entry.getEc(), associatedProteinLimit) .stream() .sorted() .collect(Collectors.toList()); addProteinEntryToEnzymeView(proteins, entry, enzymeView); }); return constructModel(ebiSearchResult, enzymeView, page, filters, taxId, searchKey, keywordType, model, searchModel); } return view; } private String findEnzymesByEC(String ec, int startPage, int pageSize, int facetCount, List<String> filters, int associatedProteinLimit, String searchKey, String keywordType, Model model, SearchModel searchModel, String view) { EBISearchResult ebiSearchResult = getEbiSearchResultByEC(ec, startPage * pageSize, pageSize, facetCount, filters); if (ebiSearchResult != null) { long hitCount = ebiSearchResult.getHitCount(); Pageable pageable = new PageRequest(startPage, pageSize); Page<Entry> page = new PageImpl<>(ebiSearchResult.getEntries(), pageable, hitCount); List<Entry> entries = page.getContent(); List<Entry> enzymeView = new LinkedList<>(); entries.stream() .forEach(entry -> { List<Protein> proteins = ebeyeRestService.queryForUniqueProteins(entry.getEc(), associatedProteinLimit) .stream() .sorted() .collect(Collectors.toList()); addProteinEntryToEnzymeView(proteins, entry, enzymeView); }); return constructModel(ebiSearchResult, enzymeView, page, filters, ec, searchKey, keywordType, model, searchModel); } return view; } private String findEnzymesByPathwayId(String pathwayId, int startPage, int pageSize, int facetCount, List<String> filters, int associatedProteinLimit, String searchKey, String keywordType, Model model, SearchModel searchModel, String view) { EBISearchResult ebiSearchResult = getEbiSearchResultByPathwayId(pathwayId, startPage * pageSize, pageSize, facetCount, filters); if (ebiSearchResult != null) { long hitCount = ebiSearchResult.getHitCount(); Pageable pageable = new PageRequest(startPage, pageSize); Page<Entry> page = new PageImpl<>(ebiSearchResult.getEntries(), pageable, hitCount); List<Entry> entries = page.getContent(); List<Entry> enzymeView = new LinkedList<>(); entries.stream().forEach(entry -> { List<Protein> proteins = ebeyeRestService.findUniqueProteinsByPathwayIdAndEc(pathwayId, entry.getEc(), associatedProteinLimit) .stream() .sorted() .collect(Collectors.toList()); addProteinEntryToEnzymeView(proteins, entry, enzymeView); }); return constructModel(ebiSearchResult, enzymeView, page, filters, pathwayId, searchKey, keywordType, model, searchModel); } return view; } private String constructModel(EBISearchResult ebiSearchResult, List<Entry> enzymeView, Page page, List<String> filters, String searchId, String searchKey, String keywordType, Model model, SearchModel searchModel) { int current = page.getNumber() + 1; int begin = Math.max(1, current - 5); int end = Math.min(begin + 10, page.getTotalPages()); model.addAttribute("page", page); model.addAttribute("beginIndex", begin); model.addAttribute("endIndex", end); model.addAttribute("currentIndex", current); model.addAttribute("enzymeView", enzymeView); model.addAttribute("filtersApplied", filters); model.addAttribute("searchKey", searchKey); model.addAttribute("keywordType", keywordType); model.addAttribute("searchId", searchId); model.addAttribute("searchModel", searchModel); model.addAttribute(SEARCH_VIDEO, SEARCH_VIDEO); model.addAttribute("ebiResult", ebiSearchResult); model.addAttribute("enzymeFacet", ebiSearchResult.getFacets()); return ENZYME_CENTRIC_PAGE; } private void addProteinEntryToEnzymeView(List<Protein> proteins, Entry entry, List<Entry> enzymeView) { int proteinHits = proteins.size(); if (proteinHits > 0) { entry.setProteins(proteins); entry.setNumProteins(proteinHits); //entry.setNumEnzymeHits(hitCount); entry.setNumEnzymeHits(proteinHits); enzymeView.add(entry); } } }