/**
* Enrichr is a web app that serves the enrichment pages.
*
* @author Edward Y. Chen
* @since 8/2/2012
*/
package edu.mssm.pharm.maayanlab.Enrichr;
import java.io.File;
import java.io.IOException;
import java.text.ParseException;
import java.util.ArrayList;
import javax.servlet.ServletException;
import javax.servlet.annotation.MultipartConfig;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import javax.servlet.http.Part;
import edu.mssm.pharm.maayanlab.common.bio.EnrichedTerm;
import edu.mssm.pharm.maayanlab.common.core.FileUtils;
import edu.mssm.pharm.maayanlab.common.web.JSONify;
import edu.mssm.pharm.maayanlab.common.web.PartReader;
@WebServlet(urlPatterns= {"/enrich", "/share", "/export"})
@MultipartConfig
public class Enrichr extends HttpServlet {
private static final long serialVersionUID = 3310803710142519430L;
protected static final String RESOURCE_PATH = "/datasets/"; // Where to look for stored lists
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/html");
response.setCharacterEncoding("UTF-8");
// Read file
Part fileChunk = request.getPart("file");
if (fileChunk == null || fileChunk.getSize() == 0)
fileChunk = request.getPart("list");
ArrayList<String> inputList = PartReader.readLines(fileChunk);
// Read description
String description = request.getParameter("description");
if (description != null && description.trim().length() != 0)
request.getSession().setAttribute("description", description);
else
request.getSession().removeAttribute("description");
// Increment count
int count = Counters.incrementCounter(Counters.ENRICHMENT);
synchronized (this) {
Integer storedCount = (Integer) getServletContext().getAttribute("enrichment_count");
if (storedCount < count)
getServletContext().setAttribute("enrichment_count", count);
}
postResult(request, response, inputList);
}
// Handle submitting a list either from input or saved list
private void postResult(HttpServletRequest request, HttpServletResponse response, ArrayList<String> inputList) throws ServletException, IOException {
try {
HttpSession session = request.getSession();
// Write gene count
session.setAttribute("length", Integer.toString(inputList.size()));
boolean validate = ("true".equals(request.getParameter("validate"))) ? true : false; // Only submission page validates
Enrichment app = new Enrichment(inputList, validate);
session.setAttribute("process", app); // Save the enrichment object as session variable
request.getRequestDispatcher("results.jsp").forward(request, response); // Maintain /enrich URL instead of showing results.jsp
} catch (ParseException e) { // Send to custom error page if list can't be parsed
response.sendError(HttpServletResponse.SC_BAD_REQUEST, e.getMessage());
}
}
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
HttpSession session = request.getSession();
// Redirect to post if reading from file
String dataset = request.getParameter("dataset");
if (dataset != null) {
String resourceUrl = RESOURCE_PATH + dataset + ".txt";
if ((new File(resourceUrl)).isFile()) {
ArrayList<String> input = FileUtils.readResource(resourceUrl);
if (input.get(0).startsWith("#")) // If input line starts with comment
session.setAttribute("description", input.remove(0).replaceFirst("#", ""));
else
session.removeAttribute("description");
postResult(request, response, input);
}
else { // Send error if list doesn't exist
response.sendError(HttpServletResponse.SC_BAD_REQUEST, "This dataset doesn't exist.");
}
return;
}
Enrichment app = (Enrichment) session.getAttribute("process");
if (app == null) { // If session is expired
getExpired(request, response);
return;
}
// TODO: doesn't share too much code, can probably turn RESTful
if (request.getServletPath().equals("/enrich")) { // Support legacy paths
// TODO: remove legacy
if (request.getParameter("share") == null) { // If not sharing result
if (request.getParameter("filename") == null) // If not exporting file
getJSONResult(request, response, app);
else
getFileResult(request, response, app);
}
else {
getShared(request, response, app);
}
// End of legacy
}
else {
if (request.getServletPath().equals("/share")) {
getShared(request, response, app);
return;
}
if (request.getServletPath().equals("/export")) {
getFileResult(request, response, app);
return;
}
}
}
// Handles expired sessions
private void getExpired(HttpServletRequest request, HttpServletResponse response) throws IOException {
JSONify json = new JSONify();
response.setContentType("application/json");
response.setCharacterEncoding("UTF-8");
json.add("expired", true); // Front-end will deal with this
json.write(response.getWriter());
}
// Handle share requests
private void getShared(HttpServletRequest request, HttpServletResponse response, Enrichment app) throws IOException {
JSONify json = new JSONify();
response.setContentType("application/json");
response.setCharacterEncoding("UTF-8");
HttpSession session = request.getSession();
// Use share counter to generate unique link id
int listNumber = Counters.incrementCounter(Counters.SHARE);
String fileId = Shortener.encode(listNumber);
String description = (String) session.getAttribute("description");
// Write shared file
if (description != null)
FileUtils.writeFile("/datasets/" + fileId + ".txt", "#" + description, app.getInput());
else
FileUtils.writeFile("/datasets/" + fileId + ".txt", app.getInput());
// Add list to the user
User user = (User) session.getAttribute("user");
if (user != null) {
user.getLists().add(new List(listNumber, user, description));
Account.updateUser(user);
}
json.add("link_id", fileId); // Return the link for front-end to display
json.write(response.getWriter());
}
// Handle displaying result in JSON and JavaScript
private void getJSONResult(HttpServletRequest request, HttpServletResponse response, Enrichment app) throws IOException {
String backgroundType = request.getParameter("backgroundType");
ArrayList<EnrichedTerm> results = app.enrich(backgroundType);
JSONify json = new JSONify();
response.setContentType("application/json");
response.setCharacterEncoding("UTF-8");
json.add(backgroundType, flattenResults(results));
json.write(response.getWriter());
}
// Handle displaying result in downloadable file
private void getFileResult(HttpServletRequest request, HttpServletResponse response, Enrichment app) throws IOException {
String filename = request.getParameter("filename");
String backgroundType = request.getParameter("backgroundType");
ArrayList<EnrichedTerm> results = app.enrich(backgroundType);
// Headers needed to trigger a download instead of opening in browser
response.setHeader("Pragma", "public");
response.setHeader("Expires", "0");
response.setHeader("Cache-Control", "must-revalidate, post-check=0, pre-check=0");
response.setContentType("application/octet-stream");
response.setHeader("Content-Disposition", "attachment; filename=\"" + filename + ".txt\"");
response.setHeader("Content-Transfer-Encoding", "binary");
FileUtils.write(response.getWriter(), Enrichment.HEADER, results);
}
// Flatten enrichment results so it can be converted to JSON easily
private Object[][] flattenResults(ArrayList<EnrichedTerm> results) {
Object[][] resultsMatrix = new Object[results.size()][6];
int i = 0;
for (EnrichedTerm enrichedTerm : results) {
resultsMatrix[i][0] = i+1;
resultsMatrix[i][1] = enrichedTerm.getName();
resultsMatrix[i][2] = enrichedTerm.getPValue();
resultsMatrix[i][3] = enrichedTerm.getZScore();
resultsMatrix[i][4] = enrichedTerm.getCombinedScore();
resultsMatrix[i][5] = enrichedTerm.getOverlap();
i++;
}
return resultsMatrix;
}
}