package net.sourceforge.solexatools.webapp.controller; import java.util.HashMap; import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; import javax.servlet.ServletContext; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import net.sourceforge.seqware.common.business.ExperimentLibraryDesignService; import net.sourceforge.seqware.common.business.ExperimentService; import net.sourceforge.seqware.common.business.ExperimentSpotDesignReadSpecService; import net.sourceforge.seqware.common.business.ExperimentSpotDesignService; import net.sourceforge.seqware.common.business.LibrarySelectionService; import net.sourceforge.seqware.common.business.LibrarySourceService; import net.sourceforge.seqware.common.business.LibraryStrategyService; import net.sourceforge.seqware.common.business.PlatformService; import net.sourceforge.seqware.common.business.StudyService; import net.sourceforge.seqware.common.model.Experiment; import net.sourceforge.seqware.common.model.ExperimentLibraryDesign; import net.sourceforge.seqware.common.model.ExperimentSpotDesign; import net.sourceforge.seqware.common.model.ExperimentSpotDesignReadSpec; import net.sourceforge.seqware.common.model.Registration; import net.sourceforge.seqware.common.model.Study; import net.sourceforge.seqware.common.util.Bool; import net.sourceforge.seqware.common.util.Log; import net.sourceforge.solexatools.Security; import net.sourceforge.solexatools.util.SetNodeIdInSession; import net.sourceforge.solexatools.validation.CustomIntegerEditor; import org.springframework.validation.BindException; import org.springframework.validation.BindingResult; import org.springframework.validation.ValidationUtils; import org.springframework.validation.Validator; import org.springframework.web.bind.ServletRequestDataBinder; import org.springframework.web.servlet.ModelAndView; import org.springframework.web.servlet.mvc.multiaction.MultiActionController; /** * ExperimentController * * @author boconnor * @version $Id: $Id */ public class ExperimentController extends MultiActionController { private StudyService studyService; private ExperimentService experimentService; private Validator validator; private Validator updateValidator; private LibrarySelectionService librarySelectionService; private LibrarySourceService librarySourceService; private LibraryStrategyService libraryStrategyService; private PlatformService platformService; private ExperimentLibraryDesignService experimentLibraryDesignService; private ExperimentSpotDesignService experimentSpotDesignService; private ExperimentSpotDesignReadSpecService experimentSpotDesignReadSpecService; /** * <p> * Constructor for ExperimentController. * </p> */ public ExperimentController() { super(); } /** * <p> * Constructor for ExperimentController. * </p> * * @param delegate * a {@link java.lang.Object} object. */ public ExperimentController(Object delegate) { super(delegate); } /** * <p> * Getter for the field <code>studyService</code>. * </p> * * @return a {@link net.sourceforge.seqware.common.business.StudyService} object. */ public StudyService getStudyService() { return studyService; } /** * <p> * Setter for the field <code>studyService</code>. * </p> * * @param studyService * a {@link net.sourceforge.seqware.common.business.StudyService} object. */ public void setStudyService(StudyService studyService) { this.studyService = studyService; } /** * <p> * Getter for the field <code>validator</code>. * </p> * * @return a {@link org.springframework.validation.Validator} object. */ public Validator getValidator() { return validator; } /** * <p> * Setter for the field <code>validator</code>. * </p> * * @param validator * a {@link org.springframework.validation.Validator} object. */ public void setValidator(Validator validator) { this.validator = validator; } /** * <p> * Getter for the field <code>updateValidator</code>. * </p> * * @return a {@link org.springframework.validation.Validator} object. */ public Validator getUpdateValidator() { return updateValidator; } /** * <p> * Setter for the field <code>updateValidator</code>. * </p> * * @param validator * a {@link org.springframework.validation.Validator} object. */ public void setUpdateValidator(Validator validator) { this.updateValidator = validator; } /** * <p> * Getter for the field <code>experimentService</code>. * </p> * * @return a {@link net.sourceforge.seqware.common.business.ExperimentService} object. */ public ExperimentService getExperimentService() { return experimentService; } /** * <p> * Setter for the field <code>experimentService</code>. * </p> * * @param experimentService * a {@link net.sourceforge.seqware.common.business.ExperimentService} object. */ public void setExperimentService(ExperimentService experimentService) { this.experimentService = experimentService; } /** * <p> * Getter for the field <code>librarySelectionService</code>. * </p> * * @return a {@link net.sourceforge.seqware.common.business.LibrarySelectionService} object. */ public LibrarySelectionService getLibrarySelectionService() { return librarySelectionService; } /** * <p> * Setter for the field <code>librarySelectionService</code>. * </p> * * @param librarySelectionService * a {@link net.sourceforge.seqware.common.business.LibrarySelectionService} object. */ public void setLibrarySelectionService(LibrarySelectionService librarySelectionService) { this.librarySelectionService = librarySelectionService; } /** * <p> * Getter for the field <code>librarySourceService</code>. * </p> * * @return a {@link net.sourceforge.seqware.common.business.LibrarySourceService} object. */ public LibrarySourceService getLibrarySourceService() { return librarySourceService; } /** * <p> * Setter for the field <code>librarySourceService</code>. * </p> * * @param librarySourceService * a {@link net.sourceforge.seqware.common.business.LibrarySourceService} object. */ public void setLibrarySourceService(LibrarySourceService librarySourceService) { this.librarySourceService = librarySourceService; } /** * <p> * Getter for the field <code>libraryStrategyService</code>. * </p> * * @return a {@link net.sourceforge.seqware.common.business.LibraryStrategyService} object. */ public LibraryStrategyService getLibraryStrategyService() { return libraryStrategyService; } /** * <p> * Setter for the field <code>libraryStrategyService</code>. * </p> * * @param libraryStrategyService * a {@link net.sourceforge.seqware.common.business.LibraryStrategyService} object. */ public void setLibraryStrategyService(LibraryStrategyService libraryStrategyService) { this.libraryStrategyService = libraryStrategyService; } /** * <p> * Getter for the field <code>platformService</code>. * </p> * * @return a {@link net.sourceforge.seqware.common.business.PlatformService} object. */ public PlatformService getPlatformService() { return platformService; } /** * <p> * Setter for the field <code>platformService</code>. * </p> * * @param platformService * a {@link net.sourceforge.seqware.common.business.PlatformService} object. */ public void setPlatformService(PlatformService platformService) { this.platformService = platformService; } /** * <p> * Getter for the field <code>experimentLibraryDesignService</code>. * </p> * * @return a {@link net.sourceforge.seqware.common.business.ExperimentLibraryDesignService} object. */ public ExperimentLibraryDesignService getExperimentLibraryDesignService() { return experimentLibraryDesignService; } /** * <p> * Setter for the field <code>experimentLibraryDesignService</code>. * </p> * * @param experimentLibraryDesignService * a {@link net.sourceforge.seqware.common.business.ExperimentLibraryDesignService} object. */ public void setExperimentLibraryDesignService(ExperimentLibraryDesignService experimentLibraryDesignService) { this.experimentLibraryDesignService = experimentLibraryDesignService; } /** * {@inheritDoc} * * @param binder * @throws java.lang.Exception */ @Override protected void initBinder(HttpServletRequest request, ServletRequestDataBinder binder) throws Exception { // Uncomment the following line if you're using a Double object // binder.registerCustomEditor(Integer.class, new CustomIntegerEditor()); binder.registerCustomEditor(Integer.TYPE, new CustomIntegerEditor()); super.initBinder(request, binder); } // @Override /** * {@inheritDoc} * * @param arg1 * @throws java.lang.Exception */ @Override protected void bind(HttpServletRequest arg0, Object arg1) throws Exception { // TODO Auto-generated method stub super.bind(arg0, arg1); } /** * Handles the user's request to submit a new study. * * @param request * HttpServletRequest * @param response * HttpServletResponse * @param command * Study command object * @return ModelAndView * @throws java.lang.Exception * if any. */ public ModelAndView handleSubmit(HttpServletRequest request, HttpServletResponse response, Experiment command) throws Exception { Registration registration = Security.getRegistration(request); if (registration == null) return new ModelAndView("redirect:/login.htm"); ModelAndView modelAndView = null; BindingResult errors = this.validate(request, command); if (errors.hasErrors()) { Map<String, Object> model = errors.getModel(); // Experiment experiment = getCurrentExperiment(request); model.put("platformList", getPlatformService().list(registration)); model.put("expLibDesignSelectionList", getLibrarySelectionService().list(registration)); model.put("expLibDesignSourceList", getLibrarySourceService().list(registration)); model.put("expLibDesignStrategyList", getLibraryStrategyService().list(registration)); // experiment.setOwner(registration); // Integer studyId = Integer.parseInt(request.getParameter("studyId")); // experiment.setStudy(getStudyService().findByID(studyId)); Integer studyId = Integer.parseInt(request.getParameter("studyId")); request.setAttribute("studyId", studyId); model.put("strategy", "submit"); // request.setAttribute(getCommandName(command), experiment); modelAndView = new ModelAndView("Experiment", model); } else { command.setOwner(registration); // fill in experiment and linked tables populateExperiment(command, request); getExperimentService().insert(command); // add study id Integer studyId = command.getStudy().getStudyId(); // request.getSession(false).setAttribute("nodeId", "study_" + studyId); SetNodeIdInSession.setStudy(studyId, request); modelAndView = new ModelAndView("redirect:/myStudyList.htm"); } request.getSession(false).removeAttribute("experiment"); return modelAndView; } /** * Handles the user's request to reset the experiment page during a new or update experiment. * * @param command * Experiment command object * @param request * a {@link javax.servlet.http.HttpServletRequest} object. * @param response * a {@link javax.servlet.http.HttpServletResponse} object. * @return a {@link org.springframework.web.servlet.ModelAndView} object. * @throws java.lang.Exception * if any. */ public ModelAndView handleReset(HttpServletRequest request, HttpServletResponse response, Experiment command) throws Exception { Registration registration = Security.getRegistration(request); if (registration == null) return new ModelAndView("redirect:/login.htm"); ModelAndView modelAndView = null; HashMap<String, Object> model = new HashMap<>(); Experiment experiment = getCurrentExperiment(request); model.put("platformList", getPlatformService().list(registration)); model.put("expLibDesignSelectionList", getLibrarySelectionService().list(registration)); model.put("expLibDesignSourceList", getLibrarySourceService().list(registration)); model.put("expLibDesignStrategyList", getLibraryStrategyService().list(registration)); if (experiment.getUpdateTimestamp() == null) { experiment.setOwner(registration); Integer studyId = Integer.parseInt(request.getParameter("studyId")); experiment.setStudy(getStudyService().findByID(studyId)); request.setAttribute("studyId", studyId); model.put("strategy", "submit"); } else { experiment.setPlatformInt(experiment.getPlatform().getPlatformId()); experiment.setExpLibDesignName(experiment.getExperimentLibraryDesign().getName()); experiment.setExpLibDesignDesc(experiment.getExperimentLibraryDesign().getDescription()); experiment.setExpLibDesignProtocol(experiment.getExperimentLibraryDesign().getConstructionProtocol()); experiment.setExpLibDesignStrategy(experiment.getExperimentLibraryDesign().getStrategy().getLibraryStrategyId()); experiment.setExpLibDesignSource(experiment.getExperimentLibraryDesign().getSource().getLibrarySourceId()); experiment.setExpLibDesignSelection(experiment.getExperimentLibraryDesign().getSelection().getLibrarySelectionId()); experiment.setSpotDesignReadSpec(experiment.getExperimentSpotDesign().getReadSpec()); request.setAttribute("studyId", experiment.getStudy().getStudyId()); model.put("swid", experiment.getSwAccession()); model.put("strategy", "update"); } modelAndView = new ModelAndView("Experiment", model); request.setAttribute(getCommandName(command), experiment); return modelAndView; } /** * Handles the user's request to cancel the study or the study update page. * * @param command * Study command object * @param request * a {@link javax.servlet.http.HttpServletRequest} object. * @param response * a {@link javax.servlet.http.HttpServletResponse} object. * @return a {@link org.springframework.web.servlet.ModelAndView} object. * @throws java.lang.Exception * if any. */ public ModelAndView handleCancel(HttpServletRequest request, HttpServletResponse response, Study command) throws Exception { // add study id Integer studyId = Integer.parseInt(request.getParameter("studyId")); // request.getSession(false).setAttribute("nodeId", "study_" + studyId); // SetNodeIdInSession.setStudy(studyId, request); return new ModelAndView("redirect:/myStudyList.htm"); } /** * Handles the user's request to update their study. * * @param command * Study command object * @param request * a {@link javax.servlet.http.HttpServletRequest} object. * @param response * a {@link javax.servlet.http.HttpServletResponse} object. * @return a {@link org.springframework.web.servlet.ModelAndView} object. * @throws java.lang.Exception * if any. */ public ModelAndView handleUpdate(HttpServletRequest request, HttpServletResponse response, Experiment command) throws Exception { Registration registration = Security.getRegistration(request); if (registration == null) return new ModelAndView("redirect:/login.htm"); ModelAndView modelAndView = null; command.setSwAccession(getCurrentExperiment(request).getSwAccession()); BindingResult errors = this.validateUpdate(request, command); if (errors.hasErrors()) { Map model = errors.getModel(); Integer studyId = Integer.parseInt(request.getParameter("studyId")); request.setAttribute("studyId", studyId); request.setAttribute("swid", getCurrentExperiment(request).getSwAccession()); model.put("platformList", getPlatformService().list(registration)); model.put("expLibDesignSelectionList", getLibrarySelectionService().list(registration)); model.put("expLibDesignSourceList", getLibrarySourceService().list(registration)); model.put("expLibDesignStrategyList", getLibraryStrategyService().list(registration)); model.put("strategy", "update"); modelAndView = new ModelAndView("Experiment", model); } else { Experiment newExperiment = command; Log.info("Print runs in controller. Runs=" + command.getExpectedNumberRuns()); Experiment oldExperiment = getCurrentExperiment(request); if (newExperiment != null && oldExperiment != null) { new ServletRequestDataBinder(oldExperiment).bind(request); // set variable which convert with String to Integer and Long oldExperiment.setExpectedNumberRuns(newExperiment.getExpectedNumberRuns()); oldExperiment.setExpectedNumberReads(newExperiment.getExpectedNumberReads()); // fill in experiment and linked tables populateExperiment(oldExperiment, request); getExperimentService().updateDetached(oldExperiment); // getExperimentService().merge(oldExperiment); // add experiment id // request.getSession(false).setAttribute("nodeId", "exp_" + // oldExperiment.getExperimentId()); // add study id // Integer studyId = FindRootUtil.getStudy(oldExperiment).getStudyId(); // SetNodeIdInSession.setStudy(studyId, request); modelAndView = new ModelAndView("redirect:/myStudyList.htm"); } else { modelAndView = new ModelAndView("redirect:/Error.htm"); } request.getSession(false).removeAttribute("experiment"); } // request.getSession(false).removeAttribute("experiment"); return modelAndView; } /** * Handles the user's request to delete their experiment. * * @param command * Experiment command object * @param request * a {@link javax.servlet.http.HttpServletRequest} object. * @param response * a {@link javax.servlet.http.HttpServletResponse} object. * @return a {@link org.springframework.web.servlet.ModelAndView} object. * @throws java.lang.Exception * if any. */ public ModelAndView handleDelete(HttpServletRequest request, HttpServletResponse response, Study command) throws Exception { Registration registration = Security.getRegistration(request); if (registration == null) return new ModelAndView("redirect:/login.htm"); ModelAndView modelAndView = null; HashMap<String, Object> model = new HashMap<>(); Experiment experiment = getRequestedExperiment(request); ServletContext context = this.getServletContext(); boolean deleteRealFiles = Bool.parse(context.getInitParameter("delete.files.for.node.deletion")); if (experiment != null) { if (registration.equals(experiment.getOwner()) || registration.isLIMSAdmin()) { // Integer studyId = experiment.getStudy().getStudyId(); getExperimentService().delete(experiment, deleteRealFiles); // SetNodeIdInSession.setStudy(studyId, request); } } modelAndView = new ModelAndView("redirect:/myStudyList.htm", model); return modelAndView; } private void populateExperiment(Experiment command, HttpServletRequest request) { // setup parent study command.setStudy(getStudyService().findByID(Integer.parseInt(request.getParameter("studyId")))); // setup platform command.setPlatform(getPlatformService().findByID(command.getPlatformInt())); // setup library design ExperimentLibraryDesign eld = command.getExperimentLibraryDesign(); if (eld == null) { eld = new ExperimentLibraryDesign(); } eld.setDescription(command.getExpLibDesignDesc()); eld.setName(command.getExpLibDesignName()); eld.setConstructionProtocol(command.getExpLibDesignProtocol()); // now setup library selectionlibrarySelectionService eld.setSelection(librarySelectionService.findByID(command.getExpLibDesignSelection())); // now setup library strategy eld.setStrategy(libraryStrategyService.findByID(command.getExpLibDesignStrategy())); // now setup library source eld.setSource(librarySourceService.findByID(command.getExpLibDesignSource())); // save the new object if (command.getExperimentLibraryDesign() == null) { getExperimentLibraryDesignService().insert(eld); } else { getExperimentLibraryDesignService().update(eld); } // now associate with experiment command.setExperimentLibraryDesign(eld); // spot design // the trick to this is parsing the read spec and then correctly populating // the // experiment_spot_design and child experiment_spot_design_read_spec rows String readSpec = command.getSpotDesignReadSpec(); ExperimentSpotDesign esd = command.getExperimentSpotDesign(); if (esd == null) { esd = new ExperimentSpotDesign(); } esd.setReadSpec(readSpec); // save this if (command.getExperimentSpotDesign() == null) { getExperimentSpotDesignService().insert(esd); } else { getExperimentSpotDesignService().update(esd); } // clean out previous read specs if they exist for (ExperimentSpotDesignReadSpec rs : esd.getReadSpecs()) { // esd.getReadSpecs().remove(rs); getExperimentSpotDesignReadSpecService().delete(rs); } // now parse each of the ReadSpecs String[] tokens = readSpec.split("}"); Pattern p = Pattern.compile("\\{([FRAPLBOfraplbo\\.]+)\\**(\\d*)"); int readIndex = 0; int position = 1; for (String token : tokens) { Matcher matcher = p.matcher(token); matcher.find(); if (matcher.matches() && matcher.groupCount() == 2 && token.indexOf("..") == -1) { String type = matcher.group(1); if (!"\\.\\.".equals(type)) { // just skipping '{..}' int count = Integer.parseInt(matcher.group(2)); ExperimentSpotDesignReadSpec esdrs = new ExperimentSpotDesignReadSpec(); esdrs.setExperimentSpotDesign(esd); esdrs.setBaseCoord(position); esdrs.setReadIndex(readIndex); esdrs.setLength(count); // FIXME: hard coded!!! I don't know if I'm populating this // correctly!!! esdrs.setReadClass("Application Read"); if (null != type) switch (type) { case "F": esdrs.setReadType("Forward"); break; case "R": esdrs.setReadType("Reverse"); break; case "A": esdrs.setReadType("Adapter"); esdrs.setReadClass("Technical Read"); break; case "P": esdrs.setReadType("Primer"); esdrs.setReadClass("Technical Read"); break; case "L": esdrs.setReadType("Linker"); esdrs.setReadClass("Technical Read"); break; case "B": esdrs.setReadType("BarCode"); break; default: esdrs.setReadType("Other"); break; } readIndex++; esdrs.setBaseCoord(position); // add this.getExperimentSpotDesignReadSpecService().insert(esdrs); position += count; esd.getReadSpecs().add(esdrs); } } } // specify the correct number of reads esd.setReadsPerSpot(readIndex); // update this.getExperimentSpotDesignService().update(esd); // now add esd to command command.setExperimentSpotDesign(esd); } /** * Validates a study. * * @param command * the Command instance as an Object * * @return BindingResult validation errors */ private BindingResult validate(HttpServletRequest request, Object command) { BindingResult errors = new BindException(command, getCommandName(command)); ValidationUtils.invokeValidator(getValidator(), command, errors); return errors; } private BindingResult validateUpdate(HttpServletRequest request, Object command) { BindingResult errors = new BindException(command, getCommandName(command)); ValidationUtils.invokeValidator(getUpdateValidator(), command, errors); return errors; } /** * Gets the emailAddress from the study in the session. * * @param request * HttpServletRequest * * @return the emailAddress from the study in the session, or null if there is no study in the session */ private String getNameFromSession(HttpServletRequest request) { return getCurrentExperiment(request).getTitle(); } /** * Gets the experiment from the session. * * @param request * HttpServletRequest * * @return instance of Experiment from the session, or a new instance if the experiment is not in the session (e.g. the user is not * logged in) */ private Experiment getCurrentExperiment(HttpServletRequest request) { HttpSession session = request.getSession(false); if (session != null) { Object experiment = session.getAttribute("experiment"); if (experiment != null) { return (Experiment) experiment; } } return new Experiment(); } private Experiment getRequestedExperiment(HttpServletRequest request) { HttpSession session = request.getSession(false); Experiment experiment = null; String id = (String) request.getParameter("objectId"); if (id != null) { Integer experimentID = Integer.parseInt(id); experiment = getExperimentService().findByID(experimentID); } return experiment; } /** * <p> * Getter for the field <code>experimentSpotDesignService</code>. * </p> * * @return a {@link net.sourceforge.seqware.common.business.ExperimentSpotDesignService} object. */ public ExperimentSpotDesignService getExperimentSpotDesignService() { return experimentSpotDesignService; } /** * <p> * Setter for the field <code>experimentSpotDesignService</code>. * </p> * * @param experimentSpotDesignService * a {@link net.sourceforge.seqware.common.business.ExperimentSpotDesignService} object. */ public void setExperimentSpotDesignService(ExperimentSpotDesignService experimentSpotDesignService) { this.experimentSpotDesignService = experimentSpotDesignService; } /** * <p> * Getter for the field <code>experimentSpotDesignReadSpecService</code>. * </p> * * @return a {@link net.sourceforge.seqware.common.business.ExperimentSpotDesignReadSpecService} object. */ public ExperimentSpotDesignReadSpecService getExperimentSpotDesignReadSpecService() { return experimentSpotDesignReadSpecService; } /** * <p> * Setter for the field <code>experimentSpotDesignReadSpecService</code>. * </p> * * @param experimentSpotDesignReadSpecService * a {@link net.sourceforge.seqware.common.business.ExperimentSpotDesignReadSpecService} object. */ public void setExperimentSpotDesignReadSpecService(ExperimentSpotDesignReadSpecService experimentSpotDesignReadSpecService) { this.experimentSpotDesignReadSpecService = experimentSpotDesignReadSpecService; } }