/*
* This file is part of Daxplore Presenter.
*
* Daxplore Presenter is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2.1 of the License, or
* (at your option) any later version.
*
* Daxplore Presenter 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Daxplore Presenter. If not, see <http://www.gnu.org/licenses/>.
*/
package org.daxplore.presenter.server.servlets;
import java.io.IOException;
import java.io.StringReader;
import java.io.Writer;
import java.text.MessageFormat;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Locale;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.jdo.PersistenceManager;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.io.IOUtils;
import org.daxplore.presenter.server.ServerTools;
import org.daxplore.presenter.server.storage.PMF;
import org.daxplore.presenter.server.storage.QuestionMetadataServerImpl;
import org.daxplore.presenter.server.storage.SettingItemStore;
import org.daxplore.presenter.server.storage.StatDataItemStore;
import org.daxplore.presenter.server.storage.StorageTools;
import org.daxplore.presenter.server.storage.TextFileStore;
import org.daxplore.presenter.server.throwable.BadRequestException;
import org.daxplore.presenter.server.throwable.InternalServerException;
import org.daxplore.presenter.shared.EmbedDefinition;
import org.daxplore.presenter.shared.EmbedDefinition.EmbedFlag;
import org.daxplore.presenter.shared.QueryDefinition;
import org.daxplore.presenter.shared.QuestionMetadata;
import org.daxplore.shared.SharedResourceTools;
@SuppressWarnings("serial")
public class PresenterServlet extends HttpServlet {
private static Logger logger = Logger.getLogger(PresenterServlet.class.getName());
private static String presenterHtmlTemplate = null;
private static String browserSuggestionTemplate = null;
private static String printHtmlTemplate = null;
private static String embedHtmlTemplate = null;
private static String googleAnalyticsTrackingTemplate = null;
private HashMap<String, QuestionMetadata> metadataMap = new HashMap<>();
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) {
PersistenceManager pm = null;
try {
// Get input from URL
//TODO use better and more stable parsing
String prefix = request.getPathInfo();
if (prefix!=null && !prefix.isEmpty()) {
if(prefix.charAt(0)=='/') {
prefix = prefix.substring(1);
}
if(!prefix.isEmpty() && prefix.charAt(prefix.length()-1)=='/'){
prefix = prefix.substring(0, prefix.length()-2);
}
}
String useragent = request.getHeader("user-agent");
Cookie[] cookies = request.getCookies();
String feature = request.getParameter("f");
String baseurl = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort();
// Clean user input
if(prefix==null || !SharedResourceTools.isSyntacticallyValidPrefix(prefix)) {
throw new BadRequestException("Someone tried to access a syntactically invalid prefix: '" + prefix + "'");
}
boolean browserSupported = true;
double ieversion = ServerTools.getInternetExplorerVersion(useragent);
if(useragent == null | (ieversion > 0.0 & ieversion < 8.0)) {
browserSupported = false;
}
boolean ignoreBadBrowser = false;
if(cookies != null) {
ignoreBadBrowser = ServerTools.ignoreBadBrowser(cookies);
}
browserSupported |= ignoreBadBrowser;
pm = PMF.get().getPersistenceManager();
String googleAnalyticsID = SettingItemStore.getProperty(pm, prefix, "adminpanel", "gaID");
String gaTemplate = "";
if(googleAnalyticsID!=null && !googleAnalyticsID.equals("")) {
if (googleAnalyticsTrackingTemplate == null) {
try {
googleAnalyticsTrackingTemplate = IOUtils.toString(getServletContext().getResourceAsStream("/js/ga-tracking.js"));
} catch (IOException e) {
throw new InternalServerException("Failed to load the google analytics tracking template", e);
}
}
gaTemplate = MessageFormat.format(googleAnalyticsTrackingTemplate, googleAnalyticsID);
}
String responseHTML = "";
if (!browserSupported) {
responseHTML = getUnsupportedBrowserHTML(baseurl, gaTemplate);
} else {
Locale locale = ServerTools.selectLocale(request, prefix);
if (feature!=null && feature.equalsIgnoreCase("embed")) { // embedded chart
// TODO clean query string
String queryString = request.getParameter("q");
responseHTML = getEmbedHTML(pm, prefix, locale, queryString, baseurl, gaTemplate);
} else if (feature!=null && feature.equalsIgnoreCase("print")) { // printer-friendly chart
String serverPath = request.getRequestURL().toString();
// remove last slash
if (serverPath.charAt(serverPath.length() - 1) == '/') {
serverPath = serverPath.substring(0, serverPath.length() - 1);
}
// remove module name
serverPath = serverPath.substring(0, serverPath.lastIndexOf("/"));
// TODO clean query string
String queryString = request.getParameter("q");
responseHTML = getPrintHTML(pm, prefix, locale, serverPath, queryString, baseurl, gaTemplate);
} else { // standard presenter
responseHTML = getPresenterHTML(pm, prefix, locale, baseurl, gaTemplate);
}
}
response.setContentType("text/html; charset=UTF-8");
try (Writer writer = response.getWriter()){
writer.write(responseHTML);
} catch (IOException e) {
throw new InternalServerException("Failed to display presenter servlet", e);
}
} catch (BadRequestException e) {
logger.log(Level.WARNING, e.getMessage(), e);
response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
} catch (InternalServerException e) {
logger.log(Level.SEVERE, e.getMessage(), e);
response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
} catch (RuntimeException e) {
logger.log(Level.SEVERE, "Unexpected exception: " + e.getMessage(), e);
response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
} finally {
if (pm != null) {
pm.close();
}
}
}
private String getUnsupportedBrowserHTML(String baseurl, String gaTemplate) throws InternalServerException {
if (browserSuggestionTemplate == null) {
try {
browserSuggestionTemplate = IOUtils.toString(getServletContext().getResourceAsStream("/templates/browser-suggestion.html"));
} catch (IOException e) {
throw new InternalServerException("Failed to load the html browser suggestion template", e);
}
}
String[] arguments = {
baseurl, // {0}
gaTemplate // {1}
};
return MessageFormat.format(browserSuggestionTemplate, (Object[])arguments);
}
private String getPresenterHTML(PersistenceManager pm, String prefix, Locale locale, String baseurl, String gaTemplate)
throws InternalServerException, BadRequestException {
String perspectives = "", groups = "", questions = "";
perspectives = TextFileStore.getLocalizedFile(pm, prefix, "perspectives", locale, ".json");
questions = TextFileStore.getLocalizedFile(pm, prefix, "questions", locale, ".json");
groups = TextFileStore.getLocalizedFile(pm, prefix, "groups", locale, ".json");
String pageTitle = SettingItemStore.getLocalizedProperty(pm, prefix, "usertexts", locale, "pageTitle");
String boolsettings = "{}";
String usertexts = TextFileStore.getLocalizedFile(pm, prefix, "usertexts", locale, ".json");
String[] arguments = {
baseurl, // {0}
pageTitle, // {1}
prefix, // {2}
perspectives, // {3}
questions, // {4}
groups, // {5}
boolsettings, // {6}
usertexts, // {7}
gaTemplate // {8}
};
if (presenterHtmlTemplate == null) {
try {
presenterHtmlTemplate = IOUtils.toString(getServletContext().getResourceAsStream("/templates/presentation.html"));
} catch (IOException e) {
throw new InternalServerException("Failed to load the embed html template", e);
}
}
return MessageFormat.format(presenterHtmlTemplate, (Object[])arguments);
}
private String getEmbedHTML(PersistenceManager pm, String prefix, Locale locale,
String queryString, String baseurl, String gaTemplate) throws BadRequestException, InternalServerException {
QuestionMetadata questionMetadata;
String key = prefix + "_" + locale.toLanguageTag();
if(metadataMap.containsKey(key)) {
questionMetadata = metadataMap.get(key);
} else {
String questionText = TextFileStore.getLocalizedFile(pm, prefix, "questions", locale, ".json");
questionMetadata = new QuestionMetadataServerImpl(new StringReader(questionText));
metadataMap.put(key, questionMetadata);
}
QueryDefinition queryDefinition = new QueryDefinition(questionMetadata, queryString);
String statItem = StatDataItemStore.getStats(pm, prefix, queryDefinition);
LinkedList<String> questions = new LinkedList<>();
questions.add(queryDefinition.getQuestionID());
questions.add(queryDefinition.getPerspectiveID());
String pageTitle = SettingItemStore.getLocalizedProperty(pm, prefix, "usertexts", locale, "pageTitle");
String questionString = StorageTools.getQuestionDefinitions(pm, prefix, questions, locale);
String usertexts = TextFileStore.getLocalizedFile(pm, prefix, "usertexts", locale, ".json");
String[] arguments = {
baseurl, // {0}
pageTitle, // {1}
gaTemplate, // {2}
prefix, // {3}
statItem, // {4}
questionString, // {5}
usertexts // {6}
};
if (embedHtmlTemplate == null) {
try {
embedHtmlTemplate = IOUtils.toString(getServletContext().getResourceAsStream("/templates/embed.html"));
} catch (IOException e) {
throw new InternalServerException("Failed to load the embed html template", e);
}
}
return MessageFormat.format(embedHtmlTemplate, (Object[])arguments);
}
private String getPrintHTML(PersistenceManager pm, String prefix, Locale locale,
String serverPath, String queryString, String baseurl, String gaTemplate) throws InternalServerException, BadRequestException {
LinkedList<EmbedFlag> flags = new LinkedList<>();
flags.add(EmbedFlag.LEGEND);
flags.add(EmbedFlag.TRANSPARENT);
flags.add(EmbedFlag.PRINT);
String embedDefinition = new EmbedDefinition(flags).getAsString();
String pageTitle = SettingItemStore.getLocalizedProperty(pm, prefix, "usertexts", locale, "pageTitle");
String[] arguments = {
pageTitle, // {0}
baseurl, // {1}
gaTemplate, // {2}
serverPath, // {3}
queryString, // {4}
locale.toLanguageTag(), // {5}
prefix, // {6}
embedDefinition, // {7}
};
if (printHtmlTemplate == null) {
try {
printHtmlTemplate = IOUtils.toString(getServletContext().getResourceAsStream("/templates/print.html"));
} catch (IOException e) {
throw new InternalServerException("Failed to load print html template", e);
}
}
return MessageFormat.format(printHtmlTemplate, (Object[])arguments);
}
}