/* * 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); } }