/*
* Copyright (c) 2006 Genome Research Limited.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Library General Public License as published
* by the Free Software Foundation; either version 2 of the License or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this program; see the file COPYING.LIB. If not, write to
* the Free Software Foundation Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307 USA
*/
package org.genedb.web.mvc.controller;
import org.genedb.db.dao.SequenceDao;
import org.genedb.querying.history.HistoryItem;
import org.genedb.querying.history.HistoryManager;
import org.genedb.querying.history.HistoryType;
import org.genedb.web.mvc.model.DTOFactory;
import org.genedb.web.mvc.model.FeatureDTO;
import org.genedb.web.mvc.model.GeneDTO;
import org.genedb.web.mvc.model.TranscriptDTO;
import org.gmod.schema.feature.AbstractGene;
import org.gmod.schema.mapped.Feature;
import org.apache.log4j.Logger;
import org.springframework.jmx.export.annotation.ManagedAttribute;
import org.springframework.stereotype.Controller;
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.servlet.ModelAndView;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import javax.servlet.http.HttpSession;
import com.google.common.collect.Maps;
/**
* Looks up a feature by unique name
*
* @author Chinmay Patel (cp2)
* @author Adrian Tivey (art)
* @author gv1
*/
@Controller
@RequestMapping("/gene")
//@ManagedResource(objectName="bean:name=namedFeatureController", description="NamedFeature Controller")
public class TranscriptFeatureController {
private static final Logger logger = Logger.getLogger(TranscriptFeatureController.class);
private SequenceDao sequenceDao;
private String formView;
private String geneView;
private String geneDetailsView;
//private Set<String> validExtensions = Sets.newHashSet();
private int cacheHit = 0;
private int cacheMiss = 0;
private HistoryManagerFactory hmFactory;
private DTOFactory dtoFactory;
public void setDtoFactory(DTOFactory dtoFactory) {
this.dtoFactory = dtoFactory;
}
public void setHistoryManagerFactory(HistoryManagerFactory hmFactory) {
this.hmFactory = hmFactory;
}
// public FeatureDTO getDtoByName(Feature feature) {
//
// logger.info("Getting dto " + feature.getUniqueName());
// logger.info("Feature type = " + feature.getClass());
//
// if (feature instanceof AbstractGene) {
// return factory.make((AbstractGene) feature);
// }
//
// return factory.make(feature);
//
//
// }
//
// public FeatureDTO saveDto(FeatureDTO dto) {
// logger.info("Saving dto " + dto.getUniqueName());
// return dto;
// }
// make this false for debugging...
private static final boolean saveToCache = true;
@RequestMapping(method=RequestMethod.GET, value="/{name}")
public ModelAndView getByName(NameLookupBean nlb, HttpSession session, @PathVariable("name") String name) throws Exception {
logger.info("uniqueName : " + name);
HashMap<String, Object> model = Maps.newHashMap();
model.put("uniqueName", name);
/*
Feature feature = sequenceDao.getFeatureByUniqueName(name, Feature.class);
AbstractGene gene = sequenceDao.getGene(feature);
if (feature == null) {
logger.warn(String.format("Failed to find feature '%s'", name));
//return new ModelAndView("redirect:/feature/notFound.jsp");
return new ModelAndView("redirect:/QueryList");
}
FeatureDTO dto = null;
if (gene != null) {
GeneDTO gdto = (GeneDTO) dtoFactory.getDtoByName(gene);
for (TranscriptDTO tdto : gdto.getTranscripts()) {
logger.info(tdto.getUniqueName() + " == " + name);
if (tdto.getUniqueName().equals(name)) {
logger.info("Found transcript dto matching the user request, using this transcript.");
dto = tdto;
break;
}
if (tdto.getPolypeptide() != null) {
logger.info(tdto.getPolypeptide().getUniqueName() + " == " + name);
if (tdto.getPolypeptide().getUniqueName().equals(name)) {
logger.info("Found polypeptide dto matching the user request, using its transcript.");
dto = tdto;
break;
}
}
}
if (dto == null) {
if (gdto.getTranscripts().size() > 0) {
logger.info("Did not find a transcript matching the user request, but transcripts exist, using the first one.");
dto = gdto.getTranscripts().get(0);
} else {
logger.info("This gene appears not to have any transcripts, using the gene dto.");
dto = gdto;
}
}
// it's the GeneDTO that we want to cache if possible (contains everything else)
if (saveToCache)
dtoFactory.saveDto(gdto);
} else {
logger.info("No gene, using a dto of the feature.");
dto = dtoFactory.getDtoByName(feature);
if (saveToCache)
dtoFactory.saveDto(dto);
}
HistoryManager hm = hmFactory.getHistoryManager(session);
HistoryItem autoBasket = hm.getHistoryItemByType(HistoryType.AUTO_BASKET);
logger.debug(String.format("Basket is '%s'", autoBasket));
hm.addHistoryItem(HistoryType.AUTO_BASKET, feature.getUniqueName());
if (nlb.isAddToBasket()) {
hm.addHistoryItem(HistoryType.BASKET, feature.getUniqueName());
// Add message here
}
HashMap<String, Object> model = Maps.newHashMap();
model.put("taxonNodeName", feature.getOrganism().getCommonName());
model.put("dto", dto);
model.put("organismContext", dto.getOrganismCommonName());
model.put("inBasket", Boolean.FALSE);
//AbstractGene gene = sequenceDao.getGene(feature);
if (gene != null) {
model.put("geneUniaueName", gene.getUniqueName());
model.put("gene", gene);
}
int stepNumber = 10;
int diff = (dto.getMax() - dto.getMin()) / 3; // divide by 3 for amino acids
int stepsUncorrected = diff / stepNumber;
double log = Math.log10(stepsUncorrected);
double round = Math.ceil(log);
double step = Math.pow(10, round);
logger.info(String.format("%s ... %s ... %s ... %s ... %s", diff, stepsUncorrected, log, round, step));
model.put("proteinMapStep", step);
List<String> publicOrthologues = new ArrayList<String>();
for (String ortho : dto.getOrthologueNames()) {
Feature ortho_f = sequenceDao.getFeatureByUniqueName(ortho, Feature.class);
if (ortho_f != null) {
publicOrthologues.add(ortho);
}
}
model.put("orthologues", publicOrthologues);
*/
// logger.info("isDetailsOnly? " + nlb.isDetailsOnly());
//
// String viewName = nlb.isDetailsOnly() ? geneDetailsView : geneView;
// logger.info("viewName? " + viewName);
//ModelAndView mav = new ModelAndView(viewName, model);
ModelAndView mav = new ModelAndView(geneView, model);
return mav;
}
/*
@RequestMapping(method=RequestMethod.GET, value="/transcript/{name}")
public ModelAndView lookUpFeature(HttpServletRequest request,
HttpServletResponse response,
HttpSession session,
NameLookupBean nlb,
BindingResult be,
@PathVariable("name") String nameAndExtension
) throws Exception {
Pair<String, String> pair = GeneDBWebUtils.parseExtension(nameAndExtension, validExtensions);
String name = pair.getFirst();
String extension = pair.getSecond();
logger.warn("Trying to find NamedFeature of '"+name+"'");
//If a new session, redirect to same page (like a POSTBACK), dropping invalidated params
if (session == null) {
logger.warn("There is no session - redirecting to force one.");
return new ModelAndView("redirect:/gene/"+name);
}
// if (!isCurrentCacheValid(nlb.getKey(), session)){
// logger.warn("It appears as though the current session has expired, hence some URL parameters are no longer valid");
// return new ModelAndView("redirect:/gene/"+name);
// }
Feature feature = sequenceDao.getFeatureByUniqueName(name, Feature.class);
if (feature == null) {
logger.warn(String.format("Failed to find feature '%s'", name));
be.reject("no.results");
//return new ModelAndView("redirect:/feature/notFound.jsp");
return new ModelAndView("redirect:/QueryList");
}
Transcript transcript = modelBuilder.findTranscriptForFeature(feature);
if (transcript == null) {
// If feature isn't transcript redirect - include model
// is it part of a gene
logger.warn(String.format("Failed to find transcript for an id of '%s'", name));
be.reject("no.results");
//return new ModelAndView("redirect:/feature/notFound.jsp");
return new ModelAndView("redirect:/QueryList");
}
String viewName = nlb.isDetailsOnly() ? geneDetailsView : geneView;
FeatureDTO dto = bmf.getDtoMap().get(transcript.getFeatureId());
if (dto == null) {
cacheMiss++;
logger.error(String.format("dto cache miss for '%s'. Looked for featureId of '%d'", feature.getUniqueName(), feature.getFeatureId()));
Iterator<Entry<Integer, TranscriptDTO>> it = bmf.getDtoMap().entrySet().iterator();
logger.error(it.getClass().getName());
throw new RuntimeException(String.format("Unable to find '%s' in cache", feature.getUniqueName()));
}
cacheHit++;
logger.trace("dto cache hit for '"+feature.getUniqueName());
HistoryManager hm = hmFactory.getHistoryManager(session);
HistoryItem autoBasket = hm.getHistoryItemByType(HistoryType.AUTO_BASKET);
logger.debug(String.format("Basket is '%s'", autoBasket));
hm.addHistoryItem(HistoryType.AUTO_BASKET, feature.getUniqueName());
// if (nlb.isAddToBasket()) {
// hm.addHistoryItem(HistoryType.BASKET, feature.getUniqueName());
// // Add message here
// }
HashMap<String, Object> model = Maps.newHashMap();
model.put("taxonNodeName", dto.getOrganismCommonName());
model.put("dto", dto);
model.put("organismContext", dto.getOrganismCommonName());
if (StringUtils.hasText(nlb.getKey()) &&
(nlb.getResultsLength() > 0) &&
(nlb.getIndex() > 0) &&
nlb.getIndex() <= nlb.getResultsLength()) {
model.put("key", nlb.getKey());
model.put("index", nlb.getIndex());
model.put("resultsLength", nlb.getResultsLength());
}
HistoryItem basket = hm.getHistoryItemByType(HistoryType.BASKET);
logger.debug(String.format("Basket is '%s'", basket));
if (basket != null && basket.containsEntry(feature.getUniqueName())) {
logger.trace(String.format("Setting inBasket to true for '%s'", feature.getUniqueName()));
model.put("inBasket", Boolean.TRUE);
} else {
logger.trace(String.format("Setting inBasket to false for '%s'", feature.getUniqueName()));
model.put("inBasket", Boolean.FALSE);
}
String geneUniqueName = transcript.getGene().getUniqueName();
model.put("geneUniaueName", geneUniqueName);
List<String> publicOrthologues = new ArrayList<String>();
for (String ortho : dto.getOrthologueNames()) {
Feature ortho_f = sequenceDao.getFeatureByUniqueName(ortho, Feature.class);
if (ortho_f != null) {
publicOrthologues.add(ortho);
}
}
model.put("orthologues", publicOrthologues);
ModelAndView mav;
if (StringUtils.hasLength(extension)) {
mav = new ModelAndView(extension + ":", "dto", dto);
} else {
mav = new ModelAndView(viewName, model);
}
// FIXME Shouldn't be injecting db access code into view
mav.addObject("sequenceDao", sequenceDao);
return mav;
}
*/
/**
* This is to help verify if the current session key used to access the GeneSummary search results is still alive
* @param session the current session ,possibly null
* @param key
* @return true, if there is no key, or if the key exists and is from the
* correct session and is in the results cache
*/
// private boolean isCurrentCacheValid(String key, HttpSession session){
// if (!StringUtils.hasLength(key)) {
// return true;
// }
// if (session == null) {
// return false;
// }
// if (!key.startsWith(session.getId())) {
// return false;
// }
// StoredMap<String, ResultEntry> storedMap = resultsCacheFactory.getResultsCacheMap();
// return storedMap.containsKey(key);
// }
public void setSequenceDao(SequenceDao sequenceDao) {
this.sequenceDao = sequenceDao;
}
public void setGeneView(String geneView) {
this.geneView = geneView;
}
public void setGeneDetailsView(String geneDetailsView) {
this.geneDetailsView = geneDetailsView;
}
@ManagedAttribute(description="The no. of times the controller found the entry in the cache")
public int getCacheHit() {
return cacheHit;
}
@ManagedAttribute(description="The no. of times the controller didn't find the entry in the cache")
public int getCacheMiss() {
return cacheMiss;
}
public static class NameLookupBean {
private boolean detailsOnly = false;
private boolean addToBasket = false;
private String key;
private int index;
private int resultsLength;
public String getKey() {
return key;
}
public void setKey(String key) {
this.key = key;
}
public int getIndex() {
return index;
}
public void setIndex(int index) {
this.index = index;
}
public int getResultsLength() {
return resultsLength;
}
public void setResultsLength(int resultsLength) {
this.resultsLength = resultsLength;
}
public boolean isAddToBasket() {
return addToBasket;
}
public void setAddToBasket(boolean addToBasket) {
this.addToBasket = addToBasket;
}
public boolean isDetailsOnly() {
return detailsOnly;
}
public void setDetailsOnly(boolean detailsOnly) {
this.detailsOnly = detailsOnly;
}
/*
* We need this because the form that is shown when the feature
* can't be found (search/nameLookup.jsp) expects an 'organism'
* property.
*/
public String getOrganism() {
return null;
}
}
public String getFormView() {
return formView;
}
public void setFormView(String formView) {
this.formView = formView;
}
// public ResultsCacheFactory getResultsCacheFactory() {
// return resultsCacheFactory;
// }
//
// public void setResultsCacheFactory(ResultsCacheFactory resultsCacheFactory) {
// this.resultsCacheFactory = resultsCacheFactory;
// }
// public void setValidExtensions(Set<String> validExtensions) {
// this.validExtensions = validExtensions;
// }
}