]> source.dussan.org Git - vaadin-framework.git/commitdiff
Rename AjaxPageHandler -> BootstrapHandler
authorLeif Åstrand <leif@vaadin.com>
Thu, 22 Dec 2011 07:37:43 +0000 (09:37 +0200)
committerLeif Åstrand <leif@vaadin.com>
Thu, 22 Dec 2011 07:37:43 +0000 (09:37 +0200)
src/com/vaadin/terminal/gwt/server/AbstractApplicationServlet.java
src/com/vaadin/terminal/gwt/server/AbstractCommunicationManager.java
src/com/vaadin/terminal/gwt/server/AjaxPageHandler.java [deleted file]
src/com/vaadin/terminal/gwt/server/BootstrapHandler.java [new file with mode: 0644]
src/com/vaadin/terminal/gwt/server/CommunicationManager.java
src/com/vaadin/terminal/gwt/server/PortletCommunicationManager.java

index b2d3a7f89f2ed4c568db9ac9fabe48fa23030b9d..188e35fc2ad218fc40da9fd3c047f1d5c0568b42 100644 (file)
@@ -805,7 +805,7 @@ public abstract class AbstractApplicationServlet extends HttpServlet implements
             /*
              * UIDL request contains valid repaintAll=1 event, the user probably
              * wants to initiate a new application through a custom index.html
-             * without using writeAjaxPage.
+             * without using the bootstrap page.
              */
             return true;
 
index 71a783f1254eef305e86487b9b16bcb2324d060a..021908ab6efe6a6e039452b00878dddb34b8b6a1 100644 (file)
@@ -62,7 +62,7 @@ import com.vaadin.terminal.VariableOwner;
 import com.vaadin.terminal.WrappedRequest;
 import com.vaadin.terminal.WrappedResponse;
 import com.vaadin.terminal.gwt.client.ApplicationConnection;
-import com.vaadin.terminal.gwt.server.AjaxPageHandler.AjaxPageContext;
+import com.vaadin.terminal.gwt.server.BootstrapHandler.BootstrapContext;
 import com.vaadin.terminal.gwt.server.ComponentSizeValidator.InvalidLayout;
 import com.vaadin.ui.AbstractComponent;
 import com.vaadin.ui.AbstractField;
@@ -185,7 +185,7 @@ public abstract class AbstractCommunicationManager implements
      */
     public AbstractCommunicationManager(Application application) {
         this.application = application;
-        application.addRequestHandler(getAjaxPageHandler());
+        application.addRequestHandler(getBootstrapHandler());
         application.addRequestHandler(APP_RESOURCE_HANDLER);
         requireLocale(application.getLocale().toString());
     }
@@ -1907,7 +1907,7 @@ public abstract class AbstractCommunicationManager implements
     private final HashMap<Class<? extends Paintable>, Integer> typeToKey = new HashMap<Class<? extends Paintable>, Integer>();
     private int nextTypeKey = 0;
 
-    private AjaxPageHandler ajaxPageHandler;
+    private BootstrapHandler bootstrapHandler;
 
     String getTagForType(Class<? extends Paintable> class1) {
         Integer object = typeToKey.get(class1);
@@ -1949,20 +1949,20 @@ public abstract class AbstractCommunicationManager implements
     abstract protected void cleanStreamVariable(VariableOwner owner, String name);
 
     /**
-     * Gets the ajax page handler that should be used for generating ajax pages
-     * for this communication manager.
+     * Gets the bootstrap handler that should be used for generating the pages
+     * bootstrapping applications for this communication manager.
      * 
-     * @return the ajax page handler to use
+     * @return the bootstrap handler to use
      */
-    private AjaxPageHandler getAjaxPageHandler() {
-        if (ajaxPageHandler == null) {
-            ajaxPageHandler = createAjaxPageHandler();
+    private BootstrapHandler getBootstrapHandler() {
+        if (bootstrapHandler == null) {
+            bootstrapHandler = createBootstrapHandler();
         }
 
-        return ajaxPageHandler;
+        return bootstrapHandler;
     }
 
-    protected abstract AjaxPageHandler createAjaxPageHandler();
+    protected abstract BootstrapHandler createBootstrapHandler();
 
     protected boolean handleApplicationRequest(WrappedRequest request,
             WrappedResponse response) throws IOException {
@@ -1986,13 +1986,13 @@ public abstract class AbstractCommunicationManager implements
             response.setContentType("application/json; charset=UTF-8");
 
             // Use the same logic as for determined roots
-            AjaxPageHandler ajaxPageHandler = getAjaxPageHandler();
-            AjaxPageContext context = ajaxPageHandler.createContext(
+            BootstrapHandler bootstrapHandler = getBootstrapHandler();
+            BootstrapContext context = bootstrapHandler.createContext(
                     combinedRequest, response, application, root.getRootId());
 
             String widgetset = context.getWidgetsetName();
             String theme = context.getThemeName();
-            String themeUri = ajaxPageHandler.getThemeUri(context, theme);
+            String themeUri = bootstrapHandler.getThemeUri(context, theme);
 
             // TODO These are not required if it was only the init of the root
             // that was delayed
diff --git a/src/com/vaadin/terminal/gwt/server/AjaxPageHandler.java b/src/com/vaadin/terminal/gwt/server/AjaxPageHandler.java
deleted file mode 100644 (file)
index f006708..0000000
+++ /dev/null
@@ -1,645 +0,0 @@
-/*
-@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 javax.servlet.http.HttpServletResponse;
-
-import com.vaadin.Application;
-import com.vaadin.RootRequiresMoreInformation;
-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 AjaxPageHandler implements RequestHandler {
-
-    /** Cookie used to ignore browser checks */
-    private static final String FORCE_LOAD_COOKIE = "vaadinforceload=1";
-
-    protected class AjaxPageContext implements Serializable {
-        private final WrappedResponse response;
-        private final WrappedRequest request;
-        private final Application application;
-        private final int rootId;
-
-        private Writer writer;
-        private Root root;
-        private String widgetsetName;
-        private String themeName;
-        private String appId;
-
-        private boolean rootFetched = false;
-
-        public AjaxPageContext(WrappedResponse response,
-                WrappedRequest request, Application application, int 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 int getRootId() {
-            return rootId;
-        }
-
-        public Root getRoot() {
-            if (!rootFetched) {
-                root = Root.getCurrentRoot();
-                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 {
-
-        if (request.getBrowserDetails() != null) {
-            // Check if the browser is supported; we'll activate Chrome Frame
-            // silently if available.
-            WebBrowser b = request.getBrowserDetails().getWebBrowser();
-            if (b.isTooOldToFunctionProperly() && !b.isChromeFrameCapable()) {
-                // bypass if cookie set
-                String c = request.getHeader("Cookie");
-                if (c == null || !c.contains(FORCE_LOAD_COOKIE)) {
-                    writeBrowserTooOldPage(request, response);
-                    return true;
-                }
-
-            }
-        }
-
-        // TODO Should all urls be handled here?
-        int rootId;
-        try {
-            Root root = application.getRootForRequest(request);
-            if (root == null) {
-                writeError(response, new Throwable("No Root found"));
-                return true;
-            }
-
-            rootId = root.getRootId();
-        } catch (RootRequiresMoreInformation e) {
-            rootId = application.registerPendingRoot(request);
-        }
-
-        try {
-            writeAjaxPage(request, response, application, rootId);
-        } catch (JSONException e) {
-            writeError(response, e);
-        }
-
-        return true;
-    }
-
-    /**
-     * Writes a page encouraging the user to upgrade to a more current browser.
-     * 
-     * @param request
-     * @param response
-     * @throws IOException
-     */
-    protected void writeBrowserTooOldPage(WrappedRequest request,
-            WrappedResponse response) throws IOException {
-        Writer page = response.getWriter();
-        WebBrowser b = request.getBrowserDetails().getWebBrowser();
-
-        page.write("<html><body><h1>I'm sorry, but your browser is not supported</h1>"
-                + "<p>The version ("
-                + b.getBrowserMajorVersion()
-                + "."
-                + b.getBrowserMinorVersion()
-                + ") of the browser you are using "
-                + " is outdated and not supported.</p>"
-                + "<p>You should <b>consider upgrading</b> to a more up-to-date browser.</p> "
-                + "<p>The most popular browsers are <b>"
-                + " <a href=\"https://www.google.com/chrome\">Chrome</a>,"
-                + " <a href=\"http://www.mozilla.com/firefox\">Firefox</a>,"
-                + (b.isWindows() ? " <a href=\"http://windows.microsoft.com/en-US/internet-explorer/downloads/ie\">Internet Explorer</a>,"
-                        : "")
-                + " <a href=\"http://www.opera.com/browser\">Opera</a>"
-                + " and <a href=\"http://www.apple.com/safari\">Safari</a>.</b><br/>"
-                + "Upgrading to the latest version of one of these <b>will make the web safer, faster and better looking.</b></p>"
-                + (b.isIE() ? "<script type=\"text/javascript\" src=\"http://ajax.googleapis.com/ajax/libs/chrome-frame/1/CFInstall.min.js\"></script>"
-                        + "<p>If you can not upgrade your browser, please consider trying <a onclick=\"CFInstall.check({mode:'overlay'});return false;\" href=\"http://www.google.com/chromeframe\">Chrome Frame</a>.</p>"
-                        : "") //
-                + "<p><sub><a onclick=\"document.cookie='"
-                + FORCE_LOAD_COOKIE
-                + "';window.location.reload();return false;\" href=\"#\">Continue without updating</a> (not recommended)</sub></p>"
-                + "</body>\n" + "</html>");
-
-        page.close();
-    }
-
-    protected final void writeAjaxPage(WrappedRequest request,
-            WrappedResponse response, Application application, int rootId)
-            throws IOException, JSONException {
-
-        AjaxPageContext context = createContext(request, response, application,
-                rootId);
-
-        DeploymentConfiguration deploymentConfiguration = request
-                .getDeploymentConfiguration();
-
-        boolean standalone = deploymentConfiguration.isStandalone(request);
-        if (standalone) {
-            setAjaxPageHeaders(context);
-            writeAjaxPageHtmlHeadStart(context);
-            writeAjaxPageHtmlHeader(context);
-            writeAjaxPageHtmlBodyStart(context);
-        }
-
-        // TODO include initial UIDL in the scripts?
-        writeAjaxPageHtmlVaadinScripts(context);
-
-        writeAjaxPageHtmlMainDiv(context);
-
-        Writer page = context.getWriter();
-        if (standalone) {
-            page.write("</body>\n</html>\n");
-        }
-
-        page.close();
-    }
-
-    public AjaxPageContext createContext(WrappedRequest request,
-            WrappedResponse response, Application application, int rootId) {
-        AjaxPageContext context = new AjaxPageContext(response, request,
-                application, rootId);
-        return context;
-    }
-
-    protected String getMainDivStyle(AjaxPageContext 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(AjaxPageContext context);
-
-    public String getWidgetsetForRoot(AjaxPageContext 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 writeAjaxPageHtmlMainDiv(AjaxPageContext 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 writeAjaxPageHtmlBodyStart(AjaxPageContext 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 writeAjaxPageHtmlVaadinScripts(AjaxPageContext 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>");
-
-        page.write("<script type=\"text/javascript\" src=\"");
-        page.write(staticFileLocation);
-        page.write("/VAADIN/vaadinBootstrap.js\"></script>\n");
-
-        page.write("<script type=\"text/javascript\">\n");
-        page.write("//<![CDATA[\n");
-
-        writeMainScriptTagContents(context);
-        page.write("//]]>\n</script>\n");
-    }
-
-    protected void writeMainScriptTagContents(AjaxPageContext 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(AjaxPageContext context)
-            throws JSONException, PaintException {
-        Application application = context.getApplication();
-        int rootId = context.getRootId();
-
-        JSONObject appConfig = new JSONObject();
-
-        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", AbstractApplicationServlet.VERSION);
-        versionInfo.put("applicationVersion", application.getVersion());
-        appConfig.put("versionInfo", versionInfo);
-
-        appConfig.put("widgetset", context.getWidgetsetName());
-
-        if (application.isRootInitPending(rootId)) {
-            appConfig.put("initPending", true);
-        } else {
-            // write the initial UIDL into the config
-            appConfig.put("uidl",
-                    getInitialUIDL(context.getRequest(), context.getRoot()));
-        }
-
-        return appConfig;
-    }
-
-    protected JSONObject getDefaultParameters(AjaxPageContext 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(AjaxPageContext 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 writeAjaxPageHtmlHeader(AjaxPageContext 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>");
-
-        // 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\" />");
-            page.write("<link rel=\"icon\" type=\"image/vnd.microsoft.icon\" href=\""
-                    + themeUri + "/favicon.ico\" />");
-        }
-
-        Root root = context.getRoot();
-        String title = ((root == null || root.getCaption() == null) ? "Vaadin "
-                + AbstractApplicationServlet.VERSION_MAJOR : root.getCaption());
-
-        page.write("<title>"
-                + AbstractApplicationServlet.safeEscapeForHtml(title)
-                + "</title>");
-    }
-
-    /**
-     * 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 setAjaxPageHeaders(AjaxPageContext 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 writeAjaxPageHtmlHeadStart(AjaxPageContext 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(AjaxPageContext 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(AjaxPageContext context) {
-        return context.getApplication().getThemeForRoot(context.getRoot());
-    }
-
-    /**
-     * Don not override.
-     * 
-     * @param context
-     * @return
-     */
-    public String findAndEscapeThemeName(AjaxPageContext 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
-     */
-    protected abstract String getInitialUIDL(WrappedRequest request, Root root)
-            throws PaintException;
-
-}
diff --git a/src/com/vaadin/terminal/gwt/server/BootstrapHandler.java b/src/com/vaadin/terminal/gwt/server/BootstrapHandler.java
new file mode 100644 (file)
index 0000000..cfd65aa
--- /dev/null
@@ -0,0 +1,645 @@
+/*
+@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 javax.servlet.http.HttpServletResponse;
+
+import com.vaadin.Application;
+import com.vaadin.RootRequiresMoreInformation;
+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 {
+
+    /** Cookie used to ignore browser checks */
+    private static final String FORCE_LOAD_COOKIE = "vaadinforceload=1";
+
+    protected class BootstrapContext implements Serializable {
+        private final WrappedResponse response;
+        private final WrappedRequest request;
+        private final Application application;
+        private final int 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, int 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 int getRootId() {
+            return rootId;
+        }
+
+        public Root getRoot() {
+            if (!rootFetched) {
+                root = Root.getCurrentRoot();
+                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 {
+
+        if (request.getBrowserDetails() != null) {
+            // Check if the browser is supported; we'll activate Chrome Frame
+            // silently if available.
+            WebBrowser b = request.getBrowserDetails().getWebBrowser();
+            if (b.isTooOldToFunctionProperly() && !b.isChromeFrameCapable()) {
+                // bypass if cookie set
+                String c = request.getHeader("Cookie");
+                if (c == null || !c.contains(FORCE_LOAD_COOKIE)) {
+                    writeBrowserTooOldPage(request, response);
+                    return true;
+                }
+
+            }
+        }
+
+        // TODO Should all urls be handled here?
+        int rootId;
+        try {
+            Root root = application.getRootForRequest(request);
+            if (root == null) {
+                writeError(response, new Throwable("No Root found"));
+                return true;
+            }
+
+            rootId = root.getRootId();
+        } catch (RootRequiresMoreInformation e) {
+            rootId = application.registerPendingRoot(request);
+        }
+
+        try {
+            writeBootstrapPage(request, response, application, rootId);
+        } catch (JSONException e) {
+            writeError(response, e);
+        }
+
+        return true;
+    }
+
+    /**
+     * Writes a page encouraging the user to upgrade to a more current browser.
+     * 
+     * @param request
+     * @param response
+     * @throws IOException
+     */
+    protected void writeBrowserTooOldPage(WrappedRequest request,
+            WrappedResponse response) throws IOException {
+        Writer page = response.getWriter();
+        WebBrowser b = request.getBrowserDetails().getWebBrowser();
+
+        page.write("<html><body><h1>I'm sorry, but your browser is not supported</h1>"
+                + "<p>The version ("
+                + b.getBrowserMajorVersion()
+                + "."
+                + b.getBrowserMinorVersion()
+                + ") of the browser you are using "
+                + " is outdated and not supported.</p>"
+                + "<p>You should <b>consider upgrading</b> to a more up-to-date browser.</p> "
+                + "<p>The most popular browsers are <b>"
+                + " <a href=\"https://www.google.com/chrome\">Chrome</a>,"
+                + " <a href=\"http://www.mozilla.com/firefox\">Firefox</a>,"
+                + (b.isWindows() ? " <a href=\"http://windows.microsoft.com/en-US/internet-explorer/downloads/ie\">Internet Explorer</a>,"
+                        : "")
+                + " <a href=\"http://www.opera.com/browser\">Opera</a>"
+                + " and <a href=\"http://www.apple.com/safari\">Safari</a>.</b><br/>"
+                + "Upgrading to the latest version of one of these <b>will make the web safer, faster and better looking.</b></p>"
+                + (b.isIE() ? "<script type=\"text/javascript\" src=\"http://ajax.googleapis.com/ajax/libs/chrome-frame/1/CFInstall.min.js\"></script>"
+                        + "<p>If you can not upgrade your browser, please consider trying <a onclick=\"CFInstall.check({mode:'overlay'});return false;\" href=\"http://www.google.com/chromeframe\">Chrome Frame</a>.</p>"
+                        : "") //
+                + "<p><sub><a onclick=\"document.cookie='"
+                + FORCE_LOAD_COOKIE
+                + "';window.location.reload();return false;\" href=\"#\">Continue without updating</a> (not recommended)</sub></p>"
+                + "</body>\n" + "</html>");
+
+        page.close();
+    }
+
+    protected final void writeBootstrapPage(WrappedRequest request,
+            WrappedResponse response, Application application, int 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, int 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>");
+
+        page.write("<script type=\"text/javascript\" src=\"");
+        page.write(staticFileLocation);
+        page.write("/VAADIN/vaadinBootstrap.js\"></script>\n");
+
+        page.write("<script type=\"text/javascript\">\n");
+        page.write("//<![CDATA[\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();
+        int rootId = context.getRootId();
+
+        JSONObject appConfig = new JSONObject();
+
+        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", AbstractApplicationServlet.VERSION);
+        versionInfo.put("applicationVersion", application.getVersion());
+        appConfig.put("versionInfo", versionInfo);
+
+        appConfig.put("widgetset", context.getWidgetsetName());
+
+        if (application.isRootInitPending(rootId)) {
+            appConfig.put("initPending", true);
+        } 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>");
+
+        // 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\" />");
+            page.write("<link rel=\"icon\" type=\"image/vnd.microsoft.icon\" href=\""
+                    + themeUri + "/favicon.ico\" />");
+        }
+
+        Root root = context.getRoot();
+        String title = ((root == null || root.getCaption() == null) ? "Vaadin "
+                + AbstractApplicationServlet.VERSION_MAJOR : root.getCaption());
+
+        page.write("<title>"
+                + AbstractApplicationServlet.safeEscapeForHtml(title)
+                + "</title>");
+    }
+
+    /**
+     * 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
+     */
+    protected abstract String getInitialUIDL(WrappedRequest request, Root root)
+            throws PaintException;
+
+}
index 05b852445c9088b455483d1e1bdae2d9c04a78f1..3a9b8ff2db23411b3ddd7218a13d9bd80e8a7f26 100644 (file)
@@ -186,10 +186,10 @@ public class CommunicationManager extends AbstractCommunicationManager {
     }
 
     @Override
-    protected AjaxPageHandler createAjaxPageHandler() {
-        return new AjaxPageHandler() {
+    protected BootstrapHandler createBootstrapHandler() {
+        return new BootstrapHandler() {
             @Override
-            protected String getApplicationId(AjaxPageContext context) {
+            protected String getApplicationId(BootstrapContext context) {
                 String appUrl = getAppUri(context);
 
                 String appId = appUrl;
@@ -210,7 +210,7 @@ public class CommunicationManager extends AbstractCommunicationManager {
             }
 
             @Override
-            protected String getAppUri(AjaxPageContext context) {
+            protected String getAppUri(BootstrapContext context) {
                 /* Fetch relative url to application */
                 // don't use server and port in uri. It may cause problems with
                 // some
@@ -225,7 +225,7 @@ public class CommunicationManager extends AbstractCommunicationManager {
             }
 
             @Override
-            public String getThemeName(AjaxPageContext context) {
+            public String getThemeName(BootstrapContext context) {
                 String themeName = context.getRequest().getParameter(
                         AbstractApplicationServlet.URL_PARAMETER_THEME);
                 if (themeName == null) {
index 8f999ade5ab749e58af7607f135dc95fac8d0d39..49bcb7a79cf2930ee16180cf9ef702c3fec4f76a 100644 (file)
@@ -118,8 +118,8 @@ public class PortletCommunicationManager extends AbstractCommunicationManager {
     }
 
     @Override
-    protected AjaxPageHandler createAjaxPageHandler() {
-        return new AjaxPageHandler() {
+    protected BootstrapHandler createBootstrapHandler() {
+        return new BootstrapHandler() {
             @Override
             public boolean handleRequest(Application application,
                     WrappedRequest request, WrappedResponse response)
@@ -134,7 +134,7 @@ public class PortletCommunicationManager extends AbstractCommunicationManager {
             }
 
             @Override
-            protected String getApplicationId(AjaxPageContext context) {
+            protected String getApplicationId(BootstrapContext context) {
                 PortletRequest portletRequest = WrappedPortletRequest.cast(
                         context.getRequest()).getPortletRequest();
                 /*
@@ -145,11 +145,11 @@ public class PortletCommunicationManager extends AbstractCommunicationManager {
             }
 
             @Override
-            protected String getAppUri(AjaxPageContext context) {
+            protected String getAppUri(BootstrapContext context) {
                 return getRenderResponse(context).createActionURL().toString();
             }
 
-            private RenderResponse getRenderResponse(AjaxPageContext context) {
+            private RenderResponse getRenderResponse(BootstrapContext context) {
                 PortletResponse response = ((WrappedPortletResponse) context
                         .getResponse()).getPortletResponse();
 
@@ -158,7 +158,7 @@ public class PortletCommunicationManager extends AbstractCommunicationManager {
             }
 
             @Override
-            protected JSONObject getDefaultParameters(AjaxPageContext context)
+            protected JSONObject getDefaultParameters(BootstrapContext context)
                     throws JSONException {
                 /*
                  * We need this in order to get uploads to work. TODO this is
@@ -178,7 +178,7 @@ public class PortletCommunicationManager extends AbstractCommunicationManager {
             }
 
             @Override
-            protected void writeMainScriptTagContents(AjaxPageContext context)
+            protected void writeMainScriptTagContents(BootstrapContext context)
                     throws JSONException, IOException {
                 // fixed base theme to use - all portal pages with Vaadin
                 // applications will load this exactly once
@@ -198,7 +198,7 @@ public class PortletCommunicationManager extends AbstractCommunicationManager {
             }
 
             @Override
-            protected String getMainDivStyle(AjaxPageContext context) {
+            protected String getMainDivStyle(BootstrapContext context) {
                 DeploymentConfiguration deploymentConfiguration = context
                         .getRequest().getDeploymentConfiguration();
                 return deploymentConfiguration.getApplicationOrSystemProperty(
@@ -215,7 +215,7 @@ public class PortletCommunicationManager extends AbstractCommunicationManager {
 
             @Override
             protected JSONObject getApplicationParameters(
-                    AjaxPageContext context) throws JSONException,
+                    BootstrapContext context) throws JSONException,
                     PaintException {
                 JSONObject parameters = super.getApplicationParameters(context);
                 WrappedPortletResponse wrappedPortletResponse = (WrappedPortletResponse) context