From: Leif Åstrand Date: Thu, 22 Dec 2011 07:37:43 +0000 (+0200) Subject: Rename AjaxPageHandler -> BootstrapHandler X-Git-Tag: 7.0.0.alpha1~40 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=0be23936ef259c5b44ec51645879cd0830a8d711;p=vaadin-framework.git Rename AjaxPageHandler -> BootstrapHandler --- diff --git a/src/com/vaadin/terminal/gwt/server/AbstractApplicationServlet.java b/src/com/vaadin/terminal/gwt/server/AbstractApplicationServlet.java index b2d3a7f89f..188e35fc2a 100644 --- a/src/com/vaadin/terminal/gwt/server/AbstractApplicationServlet.java +++ b/src/com/vaadin/terminal/gwt/server/AbstractApplicationServlet.java @@ -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; diff --git a/src/com/vaadin/terminal/gwt/server/AbstractCommunicationManager.java b/src/com/vaadin/terminal/gwt/server/AbstractCommunicationManager.java index 71a783f125..021908ab6e 100644 --- a/src/com/vaadin/terminal/gwt/server/AbstractCommunicationManager.java +++ b/src/com/vaadin/terminal/gwt/server/AbstractCommunicationManager.java @@ -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, Integer> typeToKey = new HashMap, Integer>(); private int nextTypeKey = 0; - private AjaxPageHandler ajaxPageHandler; + private BootstrapHandler bootstrapHandler; String getTagForType(Class 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 index f006708d0c..0000000000 --- a/src/com/vaadin/terminal/gwt/server/AjaxPageHandler.java +++ /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("

I'm sorry, but your browser is not supported

" - + "

The version (" - + b.getBrowserMajorVersion() - + "." - + b.getBrowserMinorVersion() - + ") of the browser you are using " - + " is outdated and not supported.

" - + "

You should consider upgrading to a more up-to-date browser.

" - + "

The most popular browsers are " - + " Chrome," - + " Firefox," - + (b.isWindows() ? " Internet Explorer," - : "") - + " Opera" - + " and Safari.
" - + "Upgrading to the latest version of one of these will make the web safer, faster and better looking.

" - + (b.isIE() ? "" - + "

If you can not upgrade your browser, please consider trying Chrome Frame.

" - : "") // - + "

Continue without updating (not recommended)

" - + "\n" + ""); - - 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("\n\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. - *

- * 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- - *- Additionally added from javascript: - * .v-theme- - */ - - String appClass = "v-app-" - + getApplicationCSSClassName(context.getApplication()); - - String classNames = "v-app " + appClass; - - if (style != null && style.length() != 0) { - style = " style=\"" + style + "\""; - } - page.write("

"); - page.write("
"); - page.write("
\n"); - page.write(""); - } - - /** - * 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. - *

- * This method is responsible for closing the head tag and opening the body - * tag. - *

- * 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\n\n"); - } - - /** - * Method to write the script part of the page which loads needed Vaadin - * scripts and themes. - *

- * 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(""); - - page.write("\n"); - - page.write("\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. - *

- * 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("\n"); - - // Chrome frame in all versions of IE (only if Chrome frame is - // installed) - page.write("\n"); - - page.write(""); - - // Add favicon links - if (themeName != null) { - String themeUri = getThemeUri(context, themeName); - page.write(""); - page.write(""); - } - - Root root = context.getRoot(); - String title = ((root == null || root.getCaption() == null) ? "Vaadin " - + AbstractApplicationServlet.VERSION_MAJOR : root.getCaption()); - - page.write("" - + AbstractApplicationServlet.safeEscapeForHtml(title) - + ""); - } - - /** - * Method to set http request headers for the Vaadin kickstart page. - *

- * 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. - *

- * This method is responsible for writing appropriate doc type declarations - * and to open html and head tags. - *

- * 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("\n"); - - page.write("\n\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 index 0000000000..cfd65aa6f7 --- /dev/null +++ b/src/com/vaadin/terminal/gwt/server/BootstrapHandler.java @@ -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("

I'm sorry, but your browser is not supported

" + + "

The version (" + + b.getBrowserMajorVersion() + + "." + + b.getBrowserMinorVersion() + + ") of the browser you are using " + + " is outdated and not supported.

" + + "

You should consider upgrading to a more up-to-date browser.

" + + "

The most popular browsers are " + + " Chrome," + + " Firefox," + + (b.isWindows() ? " Internet Explorer," + : "") + + " Opera" + + " and Safari.
" + + "Upgrading to the latest version of one of these will make the web safer, faster and better looking.

" + + (b.isIE() ? "" + + "

If you can not upgrade your browser, please consider trying Chrome Frame.

" + : "") // + + "

Continue without updating (not recommended)

" + + "\n" + ""); + + 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("\n\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. + *

+ * 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- + *- Additionally added from javascript: + * .v-theme- + */ + + String appClass = "v-app-" + + getApplicationCSSClassName(context.getApplication()); + + String classNames = "v-app " + appClass; + + if (style != null && style.length() != 0) { + style = " style=\"" + style + "\""; + } + page.write("

"); + page.write("
"); + page.write("
\n"); + page.write(""); + } + + /** + * 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. + *

+ * This method is responsible for closing the head tag and opening the body + * tag. + *

+ * 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\n\n"); + } + + /** + * Method to write the script part of the page which loads needed Vaadin + * scripts and themes. + *

+ * 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(""); + + page.write("\n"); + + page.write("\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. + *

+ * 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("\n"); + + // Chrome frame in all versions of IE (only if Chrome frame is + // installed) + page.write("\n"); + + page.write(""); + + // Add favicon links + if (themeName != null) { + String themeUri = getThemeUri(context, themeName); + page.write(""); + page.write(""); + } + + Root root = context.getRoot(); + String title = ((root == null || root.getCaption() == null) ? "Vaadin " + + AbstractApplicationServlet.VERSION_MAJOR : root.getCaption()); + + page.write("" + + AbstractApplicationServlet.safeEscapeForHtml(title) + + ""); + } + + /** + * Method to set http request headers for the Vaadin kickstart page. + *

+ * 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. + *

+ * This method is responsible for writing appropriate doc type declarations + * and to open html and head tags. + *

+ * 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("\n"); + + page.write("\n\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; + +} diff --git a/src/com/vaadin/terminal/gwt/server/CommunicationManager.java b/src/com/vaadin/terminal/gwt/server/CommunicationManager.java index 05b852445c..3a9b8ff2db 100644 --- a/src/com/vaadin/terminal/gwt/server/CommunicationManager.java +++ b/src/com/vaadin/terminal/gwt/server/CommunicationManager.java @@ -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) { diff --git a/src/com/vaadin/terminal/gwt/server/PortletCommunicationManager.java b/src/com/vaadin/terminal/gwt/server/PortletCommunicationManager.java index 8f999ade5a..49bcb7a79c 100644 --- a/src/com/vaadin/terminal/gwt/server/PortletCommunicationManager.java +++ b/src/com/vaadin/terminal/gwt/server/PortletCommunicationManager.java @@ -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