123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605 |
- /*
- @VaadinApache2LicenseForJavaFiles@
- */
-
- package com.vaadin.terminal.gwt.server;
-
- import java.io.BufferedWriter;
- import java.io.IOException;
- import java.io.OutputStreamWriter;
- import java.io.Serializable;
- import java.io.Writer;
- import java.util.Map;
-
- import javax.servlet.http.HttpServletResponse;
-
- import com.vaadin.Application;
- import com.vaadin.RootRequiresMoreInformationException;
- import com.vaadin.Version;
- import com.vaadin.external.json.JSONException;
- import com.vaadin.external.json.JSONObject;
- import com.vaadin.terminal.DeploymentConfiguration;
- import com.vaadin.terminal.PaintException;
- import com.vaadin.terminal.RequestHandler;
- import com.vaadin.terminal.WrappedRequest;
- import com.vaadin.terminal.WrappedResponse;
- import com.vaadin.terminal.gwt.client.ApplicationConnection;
- import com.vaadin.ui.Root;
-
- public abstract class BootstrapHandler implements RequestHandler {
-
- protected class BootstrapContext implements Serializable {
-
- private final WrappedResponse response;
- private final WrappedRequest request;
- private final Application application;
- private final Integer rootId;
-
- private Writer writer;
- private Root root;
- private String widgetsetName;
- private String themeName;
- private String appId;
-
- private boolean rootFetched = false;
-
- public BootstrapContext(WrappedResponse response,
- WrappedRequest request, Application application, Integer rootId) {
- this.response = response;
- this.request = request;
- this.application = application;
- this.rootId = rootId;
- }
-
- public WrappedResponse getResponse() {
- return response;
- }
-
- public WrappedRequest getRequest() {
- return request;
- }
-
- public Application getApplication() {
- return application;
- }
-
- public Writer getWriter() throws IOException {
- if (writer == null) {
- response.setContentType("text/html");
- writer = new BufferedWriter(new OutputStreamWriter(
- response.getOutputStream(), "UTF-8"));
- }
- return writer;
- }
-
- public Integer getRootId() {
- return rootId;
- }
-
- public Root getRoot() {
- if (!rootFetched) {
- root = Root.getCurrent();
- rootFetched = true;
- }
- return root;
- }
-
- public String getWidgetsetName() {
- if (widgetsetName == null) {
- Root root = getRoot();
- if (root != null) {
- widgetsetName = getWidgetsetForRoot(this);
- }
- }
- return widgetsetName;
- }
-
- public String getThemeName() {
- if (themeName == null) {
- Root root = getRoot();
- if (root != null) {
- themeName = findAndEscapeThemeName(this);
- }
- }
- return themeName;
- }
-
- public String getAppId() {
- if (appId == null) {
- appId = getApplicationId(this);
- }
- return appId;
- }
-
- }
-
- public boolean handleRequest(Application application,
- WrappedRequest request, WrappedResponse response)
- throws IOException {
-
- // TODO Should all urls be handled here?
- Integer rootId = null;
- try {
- Root root = application.getRootForRequest(request);
- if (root == null) {
- writeError(response, new Throwable("No Root found"));
- return true;
- }
-
- rootId = Integer.valueOf(root.getRootId());
- } catch (RootRequiresMoreInformationException e) {
- // Just keep going without rootId
- }
-
- try {
- writeBootstrapPage(request, response, application, rootId);
- } catch (JSONException e) {
- writeError(response, e);
- }
-
- return true;
- }
-
- protected final void writeBootstrapPage(WrappedRequest request,
- WrappedResponse response, Application application, Integer rootId)
- throws IOException, JSONException {
-
- BootstrapContext context = createContext(request, response,
- application, rootId);
-
- DeploymentConfiguration deploymentConfiguration = request
- .getDeploymentConfiguration();
-
- boolean standalone = deploymentConfiguration.isStandalone(request);
- if (standalone) {
- setBootstrapPageHeaders(context);
- writeBootstrapPageHtmlHeadStart(context);
- writeBootstrapPageHtmlHeader(context);
- writeBootstrapPageHtmlBodyStart(context);
- }
-
- // TODO include initial UIDL in the scripts?
- writeBootstrapPageHtmlVaadinScripts(context);
-
- writeBootstrapPageHtmlMainDiv(context);
-
- Writer page = context.getWriter();
- if (standalone) {
- page.write("</body>\n</html>\n");
- }
-
- page.close();
- }
-
- public BootstrapContext createContext(WrappedRequest request,
- WrappedResponse response, Application application, Integer rootId) {
- BootstrapContext context = new BootstrapContext(response, request,
- application, rootId);
- return context;
- }
-
- protected String getMainDivStyle(BootstrapContext context) {
- return null;
- }
-
- /**
- * Creates and returns a unique ID for the DIV where the application is to
- * be rendered.
- *
- * @param context
- *
- * @return the id to use in the DOM
- */
- protected abstract String getApplicationId(BootstrapContext context);
-
- public String getWidgetsetForRoot(BootstrapContext context) {
- Root root = context.getRoot();
- WrappedRequest request = context.getRequest();
-
- String widgetset = root.getApplication().getWidgetsetForRoot(root);
- if (widgetset == null) {
- widgetset = request.getDeploymentConfiguration()
- .getConfiguredWidgetset(request);
- }
-
- widgetset = AbstractApplicationServlet.stripSpecialChars(widgetset);
- return widgetset;
- }
-
- /**
- * Method to write the div element into which that actual Vaadin application
- * is rendered.
- * <p>
- * Override this method if you want to add some custom html around around
- * the div element into which the actual Vaadin application will be
- * rendered.
- *
- * @param context
- *
- * @throws IOException
- */
- protected void writeBootstrapPageHtmlMainDiv(BootstrapContext context)
- throws IOException {
- Writer page = context.getWriter();
- String style = getMainDivStyle(context);
-
- /*- Add classnames;
- * .v-app
- * .v-app-loading
- * .v-app-<simpleName for app class>
- *- Additionally added from javascript:
- * .v-theme-<themeName, remove non-alphanum>
- */
-
- String appClass = "v-app-"
- + getApplicationCSSClassName(context.getApplication());
-
- String classNames = "v-app " + appClass;
-
- if (style != null && style.length() != 0) {
- style = " style=\"" + style + "\"";
- }
- page.write("<div id=\"" + context.getAppId() + "\" class=\""
- + classNames + "\"" + style + ">");
- page.write("<div class=\"v-app-loading\"></div>");
- page.write("</div>\n");
- page.write("<noscript>" + getNoScriptMessage() + "</noscript>");
- }
-
- /**
- * Returns a message printed for browsers without scripting support or if
- * browsers scripting support is disabled.
- */
- protected String getNoScriptMessage() {
- return "You have to enable javascript in your browser to use an application built with Vaadin.";
- }
-
- /**
- * Returns the application class identifier for use in the application CSS
- * class name in the root DIV. The application CSS class name is of form
- * "v-app-"+getApplicationCSSClassName().
- *
- * This method should normally not be overridden.
- *
- * @return The CSS class name to use in combination with "v-app-".
- */
- protected String getApplicationCSSClassName(Application application) {
- return application.getClass().getSimpleName();
- }
-
- /**
- *
- * Method to open the body tag of the html kickstart page.
- * <p>
- * This method is responsible for closing the head tag and opening the body
- * tag.
- * <p>
- * Override this method if you want to add some custom html to the page.
- *
- * @throws IOException
- */
- protected void writeBootstrapPageHtmlBodyStart(BootstrapContext context)
- throws IOException {
- Writer page = context.getWriter();
- page.write("\n</head>\n<body scroll=\"auto\" class=\""
- + ApplicationConnection.GENERATED_BODY_CLASSNAME + "\">\n");
- }
-
- /**
- * Method to write the script part of the page which loads needed Vaadin
- * scripts and themes.
- * <p>
- * Override this method if you want to add some custom html around scripts.
- *
- * @param context
- *
- * @throws IOException
- * @throws JSONException
- */
- protected void writeBootstrapPageHtmlVaadinScripts(BootstrapContext context)
- throws IOException, JSONException {
- WrappedRequest request = context.getRequest();
- Writer page = context.getWriter();
-
- DeploymentConfiguration deploymentConfiguration = request
- .getDeploymentConfiguration();
- String staticFileLocation = deploymentConfiguration
- .getStaticFileLocation(request);
-
- page.write("<iframe tabIndex=\"-1\" id=\"__gwt_historyFrame\" "
- + "style=\"position:absolute;width:0;height:0;border:0;overflow:"
- + "hidden;\" src=\"javascript:false\"></iframe>");
-
- String bootstrapLocation = staticFileLocation
- + "/VAADIN/vaadinBootstrap.js";
- page.write("<script type=\"text/javascript\" src=\"");
- page.write(bootstrapLocation);
- page.write("\"></script>\n");
-
- page.write("<script type=\"text/javascript\">\n");
- page.write("//<![CDATA[\n");
- page.write("if (!window.vaadin) alert("
- + JSONObject.quote("Failed to load the bootstrap javascript: "
- + bootstrapLocation) + ");\n");
-
- writeMainScriptTagContents(context);
- page.write("//]]>\n</script>\n");
- }
-
- protected void writeMainScriptTagContents(BootstrapContext context)
- throws JSONException, IOException {
- JSONObject defaults = getDefaultParameters(context);
- JSONObject appConfig = getApplicationParameters(context);
-
- boolean isDebug = !context.getApplication().isProductionMode();
- Writer page = context.getWriter();
-
- page.write("vaadin.setDefaults(");
- printJsonObject(page, defaults, isDebug);
- page.write(");\n");
-
- page.write("vaadin.initApplication(\"");
- page.write(context.getAppId());
- page.write("\",");
- printJsonObject(page, appConfig, isDebug);
- page.write(");\n");
- }
-
- private static void printJsonObject(Writer page, JSONObject jsonObject,
- boolean isDebug) throws IOException, JSONException {
- if (isDebug) {
- page.write(jsonObject.toString(4));
- } else {
- page.write(jsonObject.toString());
- }
- }
-
- protected JSONObject getApplicationParameters(BootstrapContext context)
- throws JSONException, PaintException {
- Application application = context.getApplication();
- Integer rootId = context.getRootId();
-
- JSONObject appConfig = new JSONObject();
-
- if (rootId != null) {
- appConfig.put(ApplicationConnection.ROOT_ID_PARAMETER, rootId);
- }
-
- if (context.getThemeName() != null) {
- appConfig.put("themeUri",
- getThemeUri(context, context.getThemeName()));
- }
-
- JSONObject versionInfo = new JSONObject();
- versionInfo.put("vaadinVersion", Version.getFullVersion());
- versionInfo.put("applicationVersion", application.getVersion());
- appConfig.put("versionInfo", versionInfo);
-
- appConfig.put("widgetset", context.getWidgetsetName());
-
- if (rootId == null || application.isRootInitPending(rootId.intValue())) {
- appConfig.put("initialPath", context.getRequest()
- .getRequestPathInfo());
-
- Map<String, String[]> parameterMap = context.getRequest()
- .getParameterMap();
- appConfig.put("initialParams", parameterMap);
- } else {
- // write the initial UIDL into the config
- appConfig.put("uidl",
- getInitialUIDL(context.getRequest(), context.getRoot()));
- }
-
- return appConfig;
- }
-
- protected JSONObject getDefaultParameters(BootstrapContext context)
- throws JSONException {
- JSONObject defaults = new JSONObject();
-
- WrappedRequest request = context.getRequest();
- Application application = context.getApplication();
-
- // Get system messages
- Application.SystemMessages systemMessages = AbstractApplicationServlet
- .getSystemMessages(application.getClass());
- if (systemMessages != null) {
- // Write the CommunicationError -message to client
- JSONObject comErrMsg = new JSONObject();
- comErrMsg.put("caption",
- systemMessages.getCommunicationErrorCaption());
- comErrMsg.put("message",
- systemMessages.getCommunicationErrorMessage());
- comErrMsg.put("url", systemMessages.getCommunicationErrorURL());
-
- defaults.put("comErrMsg", comErrMsg);
-
- JSONObject authErrMsg = new JSONObject();
- authErrMsg.put("caption",
- systemMessages.getAuthenticationErrorCaption());
- authErrMsg.put("message",
- systemMessages.getAuthenticationErrorMessage());
- authErrMsg.put("url", systemMessages.getAuthenticationErrorURL());
-
- defaults.put("authErrMsg", authErrMsg);
- }
-
- DeploymentConfiguration deploymentConfiguration = request
- .getDeploymentConfiguration();
- String staticFileLocation = deploymentConfiguration
- .getStaticFileLocation(request);
- String widgetsetBase = staticFileLocation + "/"
- + AbstractApplicationServlet.WIDGETSET_DIRECTORY_PATH;
- defaults.put("widgetsetBase", widgetsetBase);
-
- if (!application.isProductionMode()) {
- defaults.put("debug", true);
- }
-
- if (deploymentConfiguration.isStandalone(request)) {
- defaults.put("standalone", true);
- }
-
- defaults.put("appUri", getAppUri(context));
-
- return defaults;
- }
-
- protected abstract String getAppUri(BootstrapContext context);
-
- /**
- * Method to write the contents of head element in html kickstart page.
- * <p>
- * Override this method if you want to add some custom html to the header of
- * the page.
- *
- * @throws IOException
- */
- protected void writeBootstrapPageHtmlHeader(BootstrapContext context)
- throws IOException {
- Writer page = context.getWriter();
- String themeName = context.getThemeName();
-
- page.write("<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\"/>\n");
-
- // Chrome frame in all versions of IE (only if Chrome frame is
- // installed)
- page.write("<meta http-equiv=\"X-UA-Compatible\" content=\"chrome=1\"/>\n");
-
- page.write("<style type=\"text/css\">"
- + "html, body {height:100%;margin:0;}</style>\n");
-
- // Add favicon links
- if (themeName != null) {
- String themeUri = getThemeUri(context, themeName);
- page.write("<link rel=\"shortcut icon\" type=\"image/vnd.microsoft.icon\" href=\""
- + themeUri + "/favicon.ico\" />\n");
- page.write("<link rel=\"icon\" type=\"image/vnd.microsoft.icon\" href=\""
- + themeUri + "/favicon.ico\" />\n");
- }
-
- Root root = context.getRoot();
- String title = ((root == null || root.getCaption() == null) ? "" : root
- .getCaption());
-
- page.write("<title>"
- + AbstractApplicationServlet.safeEscapeForHtml(title)
- + "</title>\n");
- }
-
- /**
- * Method to set http request headers for the Vaadin kickstart page.
- * <p>
- * Override this method if you need to customize http headers of the page.
- *
- * @param context
- */
- protected void setBootstrapPageHeaders(BootstrapContext context) {
- WrappedResponse response = context.getResponse();
-
- // Window renders are not cacheable
- response.setHeader("Cache-Control", "no-cache");
- response.setHeader("Pragma", "no-cache");
- response.setDateHeader("Expires", 0);
- response.setContentType("text/html; charset=UTF-8");
- }
-
- /**
- * Method to write the beginning of the html page.
- * <p>
- * This method is responsible for writing appropriate doc type declarations
- * and to open html and head tags.
- * <p>
- * Override this method if you want to add some custom html to the very
- * beginning of the page.
- *
- * @param context
- * @throws IOException
- */
- protected void writeBootstrapPageHtmlHeadStart(BootstrapContext context)
- throws IOException {
- Writer page = context.getWriter();
-
- // write html header
- page.write("<!DOCTYPE html PUBLIC \"-//W3C//DTD "
- + "XHTML 1.0 Transitional//EN\" "
- + "\"http://www.w3.org/TR/xhtml1/"
- + "DTD/xhtml1-transitional.dtd\">\n");
-
- page.write("<html xmlns=\"http://www.w3.org/1999/xhtml\""
- + ">\n<head>\n");
- }
-
- /**
- * Get the URI for the application theme.
- *
- * A portal-wide default theme is fetched from the portal shared resource
- * directory (if any), other themes from the portlet.
- *
- * @param context
- * @param themeName
- *
- * @return
- */
- public String getThemeUri(BootstrapContext context, String themeName) {
- WrappedRequest request = context.getRequest();
- final String staticFilePath = request.getDeploymentConfiguration()
- .getStaticFileLocation(request);
- return staticFilePath + "/"
- + AbstractApplicationServlet.THEME_DIRECTORY_PATH + themeName;
- }
-
- /**
- * Override if required
- *
- * @param context
- * @return
- */
- public String getThemeName(BootstrapContext context) {
- return context.getApplication().getThemeForRoot(context.getRoot());
- }
-
- /**
- * Don not override.
- *
- * @param context
- * @return
- */
- public String findAndEscapeThemeName(BootstrapContext context) {
- String themeName = getThemeName(context);
- if (themeName == null) {
- WrappedRequest request = context.getRequest();
- themeName = request.getDeploymentConfiguration()
- .getConfiguredTheme(request);
- }
-
- // XSS preventation, theme names shouldn't contain special chars anyway.
- // The servlet denies them via url parameter.
- themeName = AbstractApplicationServlet.stripSpecialChars(themeName);
-
- return themeName;
- }
-
- protected void writeError(WrappedResponse response, Throwable e)
- throws IOException {
- response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
- e.getLocalizedMessage());
- }
-
- /**
- * Gets the initial UIDL message to send to the client.
- *
- * @param request
- * the originating request
- * @param root
- * the root for which the UIDL should be generated
- * @return a string with the initial UIDL message
- * @throws PaintException
- * if an exception occurs while painting the components
- * @throws JSONException
- * if an exception occurs while formatting the output
- */
- protected abstract String getInitialUIDL(WrappedRequest request, Root root)
- throws PaintException, JSONException;
-
- }
|