/* * To change this template, choose Tools | Templates * and open the template in the editor. */ package uk.ac.ebi.ep.controller; import java.util.Collections; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Optional; import java.util.stream.Collectors; import javax.servlet.ServletContext; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpSession; import org.apache.commons.collections.CollectionUtils; import org.apache.log4j.Logger; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.util.StringUtils; import org.springframework.web.bind.annotation.ModelAttribute; import uk.ac.ebi.ep.base.common.CompoundsPredicate; import uk.ac.ebi.ep.base.common.DiseasesPredicate; import uk.ac.ebi.ep.base.common.EcNumberPredicate; import uk.ac.ebi.ep.base.common.SpeciesPredicate; import uk.ac.ebi.ep.base.search.EnzymeFinder; import uk.ac.ebi.ep.base.search.EnzymeRetriever; import uk.ac.ebi.ep.common.Config; import uk.ac.ebi.ep.common.Pagination; import uk.ac.ebi.ep.data.domain.UniprotEntry; import uk.ac.ebi.ep.data.search.model.Compound; import uk.ac.ebi.ep.data.search.model.Disease; import uk.ac.ebi.ep.data.search.model.EcNumber; import uk.ac.ebi.ep.data.search.model.SearchModel; import uk.ac.ebi.ep.data.search.model.SearchParams; import uk.ac.ebi.ep.data.search.model.SearchParams.SearchType; import uk.ac.ebi.ep.data.search.model.SearchResults; import uk.ac.ebi.ep.data.search.model.Species; import uk.ac.ebi.ep.data.service.EnzymePortalService; import uk.ac.ebi.ep.ebeye.EbeyeRestService; import uk.ac.ebi.ep.ebeye.EbeyeSuggestionService; import uk.ac.ebi.ep.ebeye.EnzymeCentricService; import uk.ac.ebi.ep.enzymeservices.chebi.ChebiAdapter; import uk.ac.ebi.ep.enzymeservices.chebi.ChebiConfig; import uk.ac.ebi.ep.enzymeservices.intenz.IntenzAdapter; import uk.ac.ebi.ep.enzymeservices.intenz.IntenzConfig; import uk.ac.ebi.ep.enzymeservices.reactome.ReactomeConfig; import uk.ac.ebi.ep.enzymeservices.rhea.RheaWsAdapter; import uk.ac.ebi.ep.functions.Functions; import uk.ac.ebi.ep.functions.HtmlUtility; import uk.ac.ebi.ep.literatureservice.service.LiteratureService; import uk.ac.ebi.ep.web.utils.SearchUtil; /** * * @author joseph */ public abstract class AbstractController { private static final Logger logger = Logger.getLogger(AbstractController.class); @Autowired protected Config searchConfig; @Autowired protected EnzymePortalService enzymePortalService; @Autowired protected EbeyeRestService ebeyeRestService; @Autowired protected EbeyeSuggestionService ebeyeSuggestionService; @Autowired protected EnzymeCentricService enzymeCentricService; @Autowired protected LiteratureService literatureService; @Autowired protected RheaWsAdapter rheaAdapter; @Autowired protected ChebiAdapter chebiAdapter; @Autowired protected IntenzAdapter intenzAdapter; // @Autowired protected ReactomeConfig reactomeConfig; @Autowired protected ChebiConfig chebiConfig; @Autowired protected IntenzConfig intenzConfig; @Autowired protected String pdbStructureCompareUrl; @Autowired protected String pdbImgUrl; @Autowired protected String uniprotAlignUrl; @Autowired protected SearchUtil searchUtil; @Autowired protected EnzymeRetriever enzymeRetriever; protected static final String BROWSE_VIDEO = "browseVideo"; protected static final String ENTRY_VIDEO = "entryVideo"; protected static final String HOME_VIDEO = "homeVideo"; protected static final String SEARCH_VIDEO = "searchVideo"; protected static final String SEQUENCE_VIDEO = "sequenceVideo"; @ModelAttribute("searchModel") public SearchModel searchform() { SearchModel searchModelForm = new SearchModel(); SearchParams searchParams = new SearchParams(); searchParams.setStart(0); searchParams.setType(SearchParams.SearchType.KEYWORD); searchParams.setPrevioustext(""); searchModelForm.setSearchparams(searchParams); return searchModelForm; } /** * Stores a search result in the application context. * * @param servletContext the application context. * @param searchKey the key to use for the search results in the table. * @param searchResult the search results. */ protected void cacheSearch(ServletContext servletContext, String searchKey, SearchResults searchResult) { Map<String, SearchResults> prevSearches = getPreviousSearches(servletContext); synchronized (prevSearches) { while (prevSearches.size() >= searchConfig.getSearchCacheSize()) { // remove the eldest: prevSearches.remove(prevSearches.keySet().iterator().next()); } prevSearches.put(searchKey, searchResult); } } /** * Retrieves any previous searches stored in the application context. * * @param servletContext the application context. * @return a map of searches to results. */ @SuppressWarnings("unchecked") protected Map<String, SearchResults> getPreviousSearches( ServletContext servletContext) { Map<String, SearchResults> prevSearches = (Map<String, SearchResults>) servletContext.getAttribute(Attribute.prevSearches.name()); if (prevSearches == null) { // Map implementation which maintains the order of access: prevSearches = Collections.synchronizedMap( new LinkedHashMap<String, SearchResults>( searchConfig.getSearchCacheSize(), 1, true)); servletContext.setAttribute(Attribute.prevSearches.getName(), prevSearches); } return prevSearches; } /** * Updates the {@link lastSummaries Attribute#lastSummaries} attribute in * the user's session. * * @param session * @param summaries */ protected void setLastSummaries(HttpSession session, List<UniprotEntry> summaries) { @SuppressWarnings("unchecked") Map<String, UniprotEntry> lastSummaries = (Map<String, UniprotEntry>) session.getAttribute(Attribute.lastSummaries.getName()); if (lastSummaries == null) { lastSummaries = new HashMap<>(); session.setAttribute(Attribute.lastSummaries.getName(), lastSummaries); } else { lastSummaries.clear(); } for (UniprotEntry summary : summaries) { lastSummaries.put(Functions.getSummaryBasketId(summary), summary); } } protected void clearHistory(HttpSession session) { @SuppressWarnings("unchecked") LinkedList<String> history = (LinkedList<String>) session.getAttribute(Attribute.history.getName()); if (history == null) { history = new LinkedList<>(); session.setAttribute(Attribute.history.getName(), history); } else { history.clear(); } } protected void addToHistory(HttpSession session, String s) { @SuppressWarnings("unchecked") LinkedList<String> history = (LinkedList<String>) session.getAttribute(Attribute.history.getName()); if (history == null) { history = new LinkedList<>(); session.setAttribute(Attribute.history.getName(), history); } if (history.isEmpty() || !history.get(history.size() - 1).equals(s)) { String cleanedText = HtmlUtility.cleanText(s); history.add(cleanedText); } } /** * Adds a search to the user history. The history item (String) actually * stored depends on the type of search, so that the links can be re-created * in the web page properly (see <code>breadcrumbs.jsp</code>). * * @param session the user session. * @param searchType the search type. * @param s the text to be added to history. */ protected void addToHistory(HttpSession session, SearchParams.SearchType searchType, String s) { switch (searchType) { case KEYWORD: addToHistory(session, "searchparams.type=KEYWORD&searchparams.text=" + s); break; case COMPOUND: addToHistory(session, "searchparams.type=COMPOUND&searchparams.text=" + s); break; case SEQUENCE: addToHistory(session, "searchparams.sequence=" + s); break; } } /** * Adds a search to the user history. The history item (String) actually * stored depends on the type of search, so that the links can be re-created * in the web page properly (see <code>breadcrumbs.jsp</code>). * * @param session the user session. * @param searchType the search type. * @param searchKey the text to be added to history. * @param searchId * @param keywordType */ protected void addToHistory(HttpSession session, SearchParams.SearchType searchType, String searchKey, String searchId, String keywordType) { switch (searchType) { case KEYWORD: //addToHistory(session, "searchparams.text=" + searchKey); addToHistory(session, "searchparams.type=KEYWORD&searchparams.text=" + Functions.splitHyphen(searchKey) + "&searchId=" + searchId + "&keywordType=" + keywordType + "&searchKey=" + Functions.splitHyphen(searchKey)); break; case COMPOUND: addToHistory(session, "searchparams.type=COMPOUND&searchparams.text=" + searchKey); break; case SEQUENCE: addToHistory(session, "searchparams.sequence=" + searchKey); break; } } /** * Processes a string to normalise it to use as a key in the application * cache.<br> Note that the key for a ChEBI ID depends on the type of * search: if a keyword search, the prefix will be lowercase ( * <code>chebi:</code>); if a compound structure search, the prefix will be * uppercase ( <code>CHEBI:</code>). * * @param searchParams the search parameters, including the original search * text from the user. * @return A normalised string. */ protected String getSearchKey(SearchParams searchParams) { String key = null; Optional<SearchType> type = Optional.ofNullable(searchParams.getType()); searchParams.setType(type.orElse(SearchType.KEYWORD)); switch (searchParams.getType()) { case KEYWORD: if (!StringUtils.isEmpty(searchParams.getText())) { key = searchParams.getText().trim().toLowerCase(); } break; case SEQUENCE: key = searchParams.getSequence().trim().toUpperCase() .replaceAll("[\n\r]", ""); break; case COMPOUND: key = searchParams.getText().trim().toUpperCase(); break; default: key = searchParams.getText().trim().toLowerCase(); } return key; } /** * Searches by keyword. * * @param searchParameters the search parameters. * @return the search results. */ protected SearchResults searchKeyword(SearchParams searchParameters) { EnzymeFinder finder = new EnzymeFinder(enzymePortalService, ebeyeRestService); SearchResults results = finder.getEnzymes(searchParameters); return results; } /** * Adds a pagination object to the model, suitable to the search results and * search parameters. * * @param searchModel the search model including the search parameters * (including pagination start). * @return a pagination. */ protected Pagination getPagination(SearchModel searchModel) { Pagination pagination = new Pagination( searchModel.getSearchresults().getSummaryentries().size(), searchConfig.getResultsPerPage()); pagination.setFirstResult(searchModel.getSearchparams().getStart()); return pagination; } /** * Applies filters taken from the search parameters to the search results. * * @param searchModel * @param request */ protected void applyFilters(SearchModel searchModel, HttpServletRequest request) { if (searchModel != null) { SearchParams searchParameters = searchModel.getSearchparams(); searchParameters.setSize(searchConfig.getResultsPerPage()); SearchResults resultSet = searchModel.getSearchresults(); final int numOfResults = resultSet.getSummaryentries().size(); Pagination pagination = new Pagination( numOfResults, searchParameters.getSize()); pagination.setFirstResult(searchParameters.getStart()); String compound_autocompleteFilter = request.getParameter("searchparams.compounds"); String specie_autocompleteFilter = request.getParameter("_ctempList_selected"); String diseases_autocompleteFilter = request.getParameter("_DtempList_selected"); // Filter: List<String> speciesFilter = searchParameters.getSpecies(); List<String> compoundsFilter = searchParameters.getCompounds(); List<String> diseasesFilter = searchParameters.getDiseases(); List<Integer> ecNumbersFilter = searchParameters.getEcFamilies(); //remove empty string in the filter to avoid unsual behavior of the filter facets if (speciesFilter.contains("")) { speciesFilter.remove(""); } if (compoundsFilter.contains("")) { compoundsFilter.remove(""); } if (diseasesFilter.contains("")) { diseasesFilter.remove(""); } //to ensure that the seleted item is used in species filter, add the selected to the list. this is a workaround. different JS were used for auto complete and normal filter if ((specie_autocompleteFilter != null && StringUtils.hasLength(specie_autocompleteFilter) == true) && StringUtils.isEmpty(compound_autocompleteFilter) && StringUtils.isEmpty(diseases_autocompleteFilter)) { speciesFilter.add(specie_autocompleteFilter); } if ((diseases_autocompleteFilter != null && StringUtils.hasLength(diseases_autocompleteFilter) == true) && StringUtils.isEmpty(compound_autocompleteFilter) && StringUtils.isEmpty(specie_autocompleteFilter)) { diseasesFilter.add(diseases_autocompleteFilter); } //both from auto complete and normal selection. selected items are displayed on top the list and returns back to the orignial list when not selected. SearchResults searchResults = resultSet; List<Species> defaultSpeciesList = searchResults.getSearchfilters().getSpecies(); resetSelectedSpecies(defaultSpeciesList); for (String selectedItems : searchParameters.getSpecies()) { for (Species theSpecies : defaultSpeciesList) { if (selectedItems.equals(theSpecies.getScientificname())) { theSpecies.setSelected(true); } } } List<Compound> defaultCompoundList = searchResults.getSearchfilters().getCompounds(); resetSelectedCompounds(defaultCompoundList); for (String SelectedCompounds : searchParameters.getCompounds()) { for (Compound theCompound : defaultCompoundList) { if (SelectedCompounds.equals(theCompound.getId())) { theCompound.setSelected(true); } } } List<Disease> defaultDiseaseList = searchResults.getSearchfilters().getDiseases(); resetSelectedDisease(defaultDiseaseList); for (String selectedDisease : searchParameters.getDiseases()) { for (Disease disease : defaultDiseaseList) { if (selectedDisease.equals(disease.getId())) { disease.setSelected(true); } } } List<EcNumber> defaultEcNumberList = searchResults.getSearchfilters().getEcNumbers(); resetSelectedEcNumber(defaultEcNumberList); searchParameters.getEcFamilies() .stream() .forEach(selectedEcFamily -> { defaultEcNumberList .stream() .filter(ec -> selectedEcFamily.equals(ec.getEc())) .forEach(ec -> ec.setSelected(true)); }); //if an item is seleted, then filter the list if (!speciesFilter.isEmpty() || !compoundsFilter.isEmpty() || !diseasesFilter.isEmpty() || !ecNumbersFilter.isEmpty()) { List<UniprotEntry> filteredResults = new LinkedList<>(resultSet.getSummaryentries()); CollectionUtils.filter(filteredResults, new SpeciesPredicate(speciesFilter)); CollectionUtils.filter(filteredResults, new CompoundsPredicate(compoundsFilter)); CollectionUtils.filter(filteredResults, new DiseasesPredicate(diseasesFilter)); CollectionUtils.filter(filteredResults, new EcNumberPredicate(ecNumbersFilter.stream().sorted().collect(Collectors.toList()))); // Create a new SearchResults, don't modify the one in session SearchResults sr = new SearchResults(); // Update the number of results to paginate: pagination.setNumberOfResults(filteredResults.size()); sr.setSearchfilters(resultSet.getSearchfilters()); sr.setSummaryentries(filteredResults); // show the total number of hits (w/o filtering): sr.setTotalfound(resultSet.getTotalfound()); searchModel.setSearchresults(sr); } } } protected void resetSelectedSpecies(List<Species> speciesList) { speciesList.stream().forEach(sp -> sp.setSelected(false)); } protected void resetSelectedCompounds(List<Compound> compounds) { compounds.stream().forEach(compound -> compound.setSelected(false)); } protected void resetSelectedDisease(List<Disease> diseases) { diseases.stream().forEach(disease -> disease.setSelected(false)); } protected void resetSelectedEcNumber(List<EcNumber> ecNumbers) { ecNumbers.stream().forEach(ec -> ec.setSelected(false)); } }