Created
January 31, 2026 14:04
-
-
Save CodingBash/8217c2019f917f630fd8de51d6ee5f22 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| package edu.columbia.biology.controller; | |
| import java.io.IOException; | |
| import java.net.URLDecoder; | |
| import java.security.Principal; | |
| import java.util.ArrayList; | |
| import java.util.Collection; | |
| import java.util.List; | |
| import java.util.stream.Collectors; | |
| import com.fasterxml.jackson.core.JsonParseException; | |
| import com.fasterxml.jackson.databind.JsonMappingException; | |
| import com.fasterxml.jackson.databind.ObjectMapper; | |
| import org.apache.commons.lang3.NotImplementedException; | |
| import org.apache.commons.lang3.StringUtils; | |
| import org.slf4j.Logger; | |
| import org.slf4j.LoggerFactory; | |
| import org.springframework.beans.factory.annotation.Autowired; | |
| import org.springframework.security.access.AccessDeniedException; | |
| import org.springframework.security.access.annotation.Secured; | |
| import org.springframework.security.core.Authentication; | |
| import org.springframework.web.bind.annotation.PathVariable; | |
| import org.springframework.web.bind.annotation.RequestMapping; | |
| import org.springframework.web.bind.annotation.RequestMethod; | |
| import org.springframework.web.bind.annotation.RequestParam; | |
| import org.springframework.web.bind.annotation.RestController; | |
| import edu.columbia.biology.constants.AuthoritiesSiteRoleConstants; | |
| import edu.columbia.biology.exceptions.InvalidAdvancedSearchQueryStringException; | |
| import edu.columbia.biology.json_model.AdvancedSearchQueryJsonModel; | |
| import edu.columbia.biology.mapper.FitsRepositoryMapper; | |
| import edu.columbia.biology.model.ComplexesSpeciesTree; | |
| import edu.columbia.biology.model.FitTableInformation; | |
| import edu.columbia.biology.processor.AdvancedSearchProcessor; | |
| import edu.columbia.biology.processor.CellxPrincipalProcessor; | |
| import edu.columbia.biology.processor.ComplexesSpeciesTreeProcessor; | |
| import edu.columbia.biology.repository.FitsRepository; | |
| /* | |
| * TODO: [DESIGN] Support pagination | |
| * - It may be hard to support pagination, searching, sorting, etc. from a derived datasource. Consider in the future. Look more into documentation | |
| * - Pagination can be implemented when there is a need for optimization. No need for premature optimization as of now. Perhaps we can paginate a cache! | |
| */ | |
| /** | |
| * {@link RestController} for retrieving factor-related entities | |
| * | |
| * @author bbece | |
| * @see {@link RestController} | |
| */ | |
| @RestController | |
| public class ComplexSpeciesTreeController { | |
| private static final Logger LOGGER = LoggerFactory.getLogger(ComplexSpeciesTreeController.class); | |
| @Autowired | |
| private CellxPrincipalProcessor cellxPrincipalProcessor; | |
| @Autowired | |
| private ComplexesSpeciesTreeProcessor complexSpeciesTreeProcessor; | |
| @Autowired | |
| private FitsRepository fitsRepository; | |
| @Autowired | |
| private FitsRepositoryMapper fitsRepositoryMapper; | |
| @Autowired | |
| private AdvancedSearchProcessor advancedSearchProcessor; | |
| @Autowired | |
| private ObjectMapper objectMapper; | |
| @Secured({ AuthoritiesSiteRoleConstants.ROLE_SITE_DEV }) | |
| @RequestMapping(value = "/taxcomplexes/search", method = RequestMethod.GET) | |
| public ComplexesSpeciesTree retrieveAdvancedSearchComplexesTreeList(Authentication authentication, | |
| @RequestParam(required = false) String queries) | |
| throws InvalidAdvancedSearchQueryStringException, IOException { | |
| if (authentication != null) { | |
| LOGGER.info("Retrieving public species complexes tree for user {}", | |
| cellxPrincipalProcessor.retrieveUserIdFromPrincipal(authentication)); | |
| } else { | |
| LOGGER.info("Retrieving public species complexes tree for guest user"); | |
| } | |
| /* | |
| * Process query JSON | |
| */ | |
| AdvancedSearchQueryJsonModel advancedSearchQueryJsonModel = null; | |
| if (StringUtils.isNotBlank(queries)) { | |
| queries = URLDecoder.decode(queries, "UTF-8"); | |
| try { | |
| advancedSearchQueryJsonModel = objectMapper.readValue(queries, AdvancedSearchQueryJsonModel.class); | |
| } catch (JsonParseException | JsonMappingException ex) { | |
| throw new InvalidAdvancedSearchQueryStringException(ex.getMessage()); | |
| } | |
| } | |
| /* | |
| * Retrieve universe of fits into a ComplexesSpeciesTree datatype | |
| * | |
| * TODO: This should be changed to accessible fits! | |
| */ | |
| Collection<Object[]> fitResultSet = null; | |
| if (cellxPrincipalProcessor.isSiteAdmin(authentication)) { | |
| fitResultSet = fitsRepository.retrievePublicFits(); | |
| } else { | |
| fitResultSet = fitsRepository.retrievePublicCuratedFits(); | |
| } | |
| List<FitTableInformation> fitInformationList = null; | |
| if (fitResultSet.isEmpty()) { | |
| fitInformationList = new ArrayList<FitTableInformation>(); | |
| } else { | |
| fitInformationList = fitsRepositoryMapper.retrieveAllFitsMapper(fitResultSet); | |
| } | |
| ComplexesSpeciesTree complexSpeciesTree = complexSpeciesTreeProcessor | |
| .constructSpeciesComplexesTreeList(fitInformationList); | |
| /* | |
| * Perform filtering on universe of fits if requested | |
| */ | |
| if (advancedSearchQueryJsonModel != null) { | |
| complexSpeciesTree = advancedSearchProcessor.advancedSearchFiltering(complexSpeciesTree, | |
| advancedSearchQueryJsonModel); | |
| } | |
| return complexSpeciesTree; | |
| } | |
| /** | |
| * Returns entire list of public factor-species combinations. | |
| * TODO: 3/12/21: Deprecated? | |
| * @return {@link ComplexSpeciesTree} | |
| * @throws InvalidAdvancedSearchQueryStringException | |
| * @throws IOException | |
| */ | |
| @Secured(AuthoritiesSiteRoleConstants.ROLE_SITE_ADMIN) | |
| @RequestMapping(value = "/taxcomplexes/all", method = RequestMethod.GET) | |
| public ComplexesSpeciesTree retrieveAdminSpeciesComplexesTreeList(Authentication authentication, | |
| @RequestParam(required = false) String queries) | |
| throws InvalidAdvancedSearchQueryStringException, IOException { | |
| if (authentication != null) { | |
| LOGGER.info("Retrieving admin species complexes tree for user {}", | |
| cellxPrincipalProcessor.retrieveUserIdFromPrincipal(authentication)); | |
| } | |
| /* | |
| * Process query JSON | |
| */ | |
| AdvancedSearchQueryJsonModel advancedSearchQueryJsonModel = null; | |
| if (StringUtils.isNotBlank(queries)) { | |
| try { | |
| advancedSearchQueryJsonModel = objectMapper.readValue(queries, AdvancedSearchQueryJsonModel.class); | |
| } catch (JsonParseException | JsonMappingException ex) { | |
| throw new InvalidAdvancedSearchQueryStringException(ex.getMessage()); | |
| } | |
| } | |
| /* | |
| * Retrieve universe of fits into a ComplexesSpeciesTree datatype | |
| */ | |
| List<FitTableInformation> fitInformationList = fitsRepositoryMapper | |
| .retrieveAllFitsMapper(fitsRepository.retrieveAllFits()); | |
| ComplexesSpeciesTree complexSpeciesTree = complexSpeciesTreeProcessor | |
| .constructSpeciesComplexesTreeList(fitInformationList); | |
| /* | |
| * Perform filtering on universe of fits if requested | |
| */ | |
| if (advancedSearchQueryJsonModel != null) { | |
| complexSpeciesTree = advancedSearchProcessor.advancedSearchFiltering(complexSpeciesTree, | |
| advancedSearchQueryJsonModel); | |
| } | |
| return complexSpeciesTree; | |
| } | |
| /** | |
| * Returns public list of public factor-species combinations. | |
| * | |
| * TODO: Temporary admin secured until public launch | |
| * | |
| * @return {@link ComplexSpeciesTree} | |
| * @throws InvalidAdvancedSearchQueryStringException | |
| * @throws IOException | |
| */ | |
| @RequestMapping(value = "/taxcomplexes/public", method = RequestMethod.GET) | |
| public ComplexesSpeciesTree retrievePublicSpeciesComplexesTreeList(Authentication authentication, | |
| @RequestParam(required = false) String queries) | |
| throws InvalidAdvancedSearchQueryStringException, IOException { | |
| if (authentication != null) { | |
| LOGGER.info("Retrieving public species complexes tree for user {}", | |
| cellxPrincipalProcessor.retrieveUserIdFromPrincipal(authentication)); | |
| } else { | |
| LOGGER.info("Retrieving public species complexes tree for guest user"); | |
| } | |
| /* | |
| * Process query JSON | |
| */ | |
| AdvancedSearchQueryJsonModel advancedSearchQueryJsonModel = null; | |
| if (StringUtils.isNotBlank(queries)) { | |
| try { | |
| advancedSearchQueryJsonModel = objectMapper.readValue(queries, AdvancedSearchQueryJsonModel.class); | |
| } catch (JsonParseException | JsonMappingException ex) { | |
| throw new InvalidAdvancedSearchQueryStringException(ex.getMessage()); | |
| } | |
| } | |
| /* | |
| * Retrieve universe of fits into a ComplexesSpeciesTree datatype | |
| */ | |
| Collection<Object[]> fitResultSet = null; | |
| List<FitTableInformation> fitInformationList = null; | |
| if (cellxPrincipalProcessor.isSiteAdmin(authentication)) { | |
| fitResultSet = fitsRepository.retrievePublicFits(); | |
| fitInformationList = fitsRepositoryMapper.retrieveAllFitsMapper(fitResultSet); | |
| } else { | |
| fitResultSet = fitsRepository.retrievePublicCuratedFits(); | |
| fitInformationList = fitsRepositoryMapper.retrieveAllFitsMapper(fitResultSet); | |
| fitInformationList = selectCuratedFits(fitInformationList); | |
| } | |
| ComplexesSpeciesTree complexSpeciesTree = complexSpeciesTreeProcessor | |
| .constructSpeciesComplexesTreeList(fitInformationList); | |
| /* | |
| * Perform filtering on universe of fits if requested | |
| */ | |
| if (advancedSearchQueryJsonModel != null) { | |
| complexSpeciesTree = advancedSearchProcessor.advancedSearchFiltering(complexSpeciesTree, | |
| advancedSearchQueryJsonModel); | |
| } | |
| return complexSpeciesTree; | |
| } | |
| /** | |
| * Returns public list of public factor-species combinations. | |
| * | |
| * @return {@link ComplexSpeciesTree} | |
| * @throws Exception | |
| */ | |
| @Secured({ AuthoritiesSiteRoleConstants.ROLE_SITE_DEV }) | |
| @RequestMapping(value = "/taxcomplexes/accessible", method = RequestMethod.GET) | |
| public ComplexesSpeciesTree retrieveAccessibleSpeciesComplexesTreeList(Authentication authentication, | |
| @RequestParam(required = false) String queries) throws Exception { | |
| if (authentication != null) { | |
| LOGGER.info("Retrieving accessible species complexes tree for user {}", | |
| cellxPrincipalProcessor.retrieveUserIdFromPrincipal(authentication)); | |
| /* | |
| * Process query JSON | |
| */ | |
| AdvancedSearchQueryJsonModel advancedSearchQueryJsonModel = null; | |
| if (StringUtils.isNotBlank(queries)) { | |
| try { | |
| advancedSearchQueryJsonModel = objectMapper.readValue(queries, AdvancedSearchQueryJsonModel.class); | |
| } catch (JsonParseException | JsonMappingException ex) { | |
| throw new InvalidAdvancedSearchQueryStringException(ex.getMessage()); | |
| } | |
| } | |
| /* | |
| * Retrieve universe of fits into a ComplexesSpeciesTree datatype | |
| */ | |
| List<FitTableInformation> fitInformationList = fitsRepositoryMapper.retrieveAllFitsMapper(fitsRepository | |
| .retrieveUserAccessibleFits(cellxPrincipalProcessor.retrieveUserIdFromPrincipal(authentication))); | |
| ComplexesSpeciesTree complexSpeciesTree = complexSpeciesTreeProcessor | |
| .constructSpeciesComplexesTreeList(fitInformationList); | |
| /* | |
| * Perform filtering on universe of fits if requested | |
| */ | |
| if (advancedSearchQueryJsonModel != null) { | |
| complexSpeciesTree = advancedSearchProcessor.advancedSearchFiltering(complexSpeciesTree, | |
| advancedSearchQueryJsonModel); | |
| } | |
| return complexSpeciesTree; | |
| } else { | |
| LOGGER.info( | |
| "No principal/user found for the client, therefore, unable to retrieve user accessible resources"); | |
| throw new AccessDeniedException( | |
| "No principal/user found for the client, therefore, unable to retrieve user accessible resources"); | |
| } | |
| } | |
| /** | |
| * Returns public list of public factor-species combinations. | |
| * | |
| * @return {@link ComplexSpeciesTree} | |
| */ | |
| @Secured(AuthoritiesSiteRoleConstants.ROLE_SITE_PRIVATE) | |
| @RequestMapping(value = "/taxcomplexes/group/{labId}", method = RequestMethod.GET) | |
| public ComplexesSpeciesTree retrieveGroupSpeciesComplexesTreeList(Principal principal, | |
| @PathVariable("labId") int labId) { | |
| throw new NotImplementedException("endpoint: /taxcomplexes/group/{labId}"); | |
| } | |
| /** | |
| * Returns public list of public factor-species combinations. | |
| * | |
| * @return {@link ComplexSpeciesTree} | |
| */ | |
| @Secured(AuthoritiesSiteRoleConstants.ROLE_SITE_PRIVATE) | |
| @RequestMapping(value = "/taxcomplexes/study/{studyName}", method = RequestMethod.GET) | |
| public ComplexesSpeciesTree retrieveGroupSpeciesComplexesTreeList(Principal principal, | |
| @PathVariable("studyName") String studyName) { | |
| throw new NotImplementedException("endpoint: /taxcomplexes/study/{studyName}"); | |
| } | |
| /** | |
| * If web curation is available (not null), return that result (as override), if | |
| * it is null, then return the default pipeline curation. | |
| * | |
| * TODO: Need an option on front-end to remove web curation status of fit to | |
| * default to the pipeline curation -> can cause potential curation bug. | |
| * | |
| * @param fitInformationList | |
| * @return | |
| */ | |
| private List<FitTableInformation> selectCuratedFits(List<FitTableInformation> fitInformationList) { | |
| return fitInformationList.stream().filter(fit -> { | |
| return fit.getCurated() != null ? fit.getCurated() : fit.getPipelineCurated(); | |
| }).collect(Collectors.toList()); | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment