Skip to content

Instantly share code, notes, and snippets.

@CodingBash
Created January 31, 2026 14:04
Show Gist options
  • Select an option

  • Save CodingBash/8217c2019f917f630fd8de51d6ee5f22 to your computer and use it in GitHub Desktop.

Select an option

Save CodingBash/8217c2019f917f630fd8de51d6ee5f22 to your computer and use it in GitHub Desktop.
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