From 8679f49c5e036d39d34a9fca8a907c4d19df21c9 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Leif=20=C3=85strand?= Date: Fri, 31 Aug 2012 12:02:51 +0300 Subject: [PATCH] Refactor UI bootstrap (#9443) --- WebContent/VAADIN/vaadinBootstrap.js | 8 +- server/src/com/vaadin/Application.java | 341 ++++++++++-------- .../UIRequiresMoreInformationException.java | 37 -- .../vaadin/annotations/PreserveOnRefresh.java | 28 ++ server/src/com/vaadin/annotations/Title.java | 38 ++ .../server/AbstractApplicationPortlet.java | 9 +- .../server/AbstractCommunicationManager.java | 36 +- .../server/BootstrapFragmentResponse.java | 13 +- .../com/vaadin/server/BootstrapHandler.java | 107 ++---- .../vaadin/server/BootstrapPageResponse.java | 14 +- .../com/vaadin/server/BootstrapResponse.java | 40 +- .../vaadin/server/CommunicationManager.java | 7 - .../com/vaadin/server/DefaultUIProvider.java | 3 +- .../server/PortletCommunicationManager.java | 7 - server/src/com/vaadin/server/UIProvider.java | 3 +- .../src/com/vaadin/server/WrappedRequest.java | 9 +- server/src/com/vaadin/ui/UI.java | 50 ++- .../component/root/CustomUIClassLoader.java | 28 +- .../launcher/ApplicationRunnerServlet.java | 4 +- .../application/RefreshStatePreserve.java | 7 +- .../application/ThreadLocalInstances.java | 19 +- .../LoginFormWithMultipleWindows.java | 13 +- .../tests/components/ui/LazyInitUIs.java | 44 ++- .../components/ui/UIsInMultipleTabs.java | 4 +- .../v7a1/CreatingPreserveState.java | 5 +- .../DifferentFeaturesForDifferentClients.java | 42 ++- .../TestAddonContextListener.java | 5 +- 27 files changed, 440 insertions(+), 481 deletions(-) delete mode 100644 server/src/com/vaadin/UIRequiresMoreInformationException.java create mode 100644 server/src/com/vaadin/annotations/PreserveOnRefresh.java create mode 100644 server/src/com/vaadin/annotations/Title.java diff --git a/WebContent/VAADIN/vaadinBootstrap.js b/WebContent/VAADIN/vaadinBootstrap.js index 1f5f3fa973..36cf2ec8eb 100644 --- a/WebContent/VAADIN/vaadinBootstrap.js +++ b/WebContent/VAADIN/vaadinBootstrap.js @@ -153,15 +153,11 @@ var bootstrapApp = function(mayDefer) { var themeUri = getConfig('themeUri'); - if (themeUri) { - loadTheme(themeUri); - } + loadTheme(themeUri); var widgetsetBase = getConfig('widgetsetBase'); var widgetset = getConfig('widgetset'); - if (widgetset && widgetsetBase) { - loadWidgetset(widgetsetBase, widgetset); - } + loadWidgetset(widgetsetBase, widgetset); if (getConfig('uidl') === undefined) { if (mayDefer) { diff --git a/server/src/com/vaadin/Application.java b/server/src/com/vaadin/Application.java index fb2691c6d3..b1a9ae1d26 100644 --- a/server/src/com/vaadin/Application.java +++ b/server/src/com/vaadin/Application.java @@ -28,7 +28,6 @@ import java.util.Collections; import java.util.Enumeration; import java.util.EventObject; import java.util.HashMap; -import java.util.HashSet; import java.util.Iterator; import java.util.LinkedList; import java.util.List; @@ -36,14 +35,15 @@ import java.util.Locale; import java.util.Map; import java.util.Map.Entry; import java.util.Properties; -import java.util.Set; import java.util.logging.Level; import java.util.logging.Logger; import java.util.regex.Matcher; import java.util.regex.Pattern; import com.vaadin.annotations.EagerInit; +import com.vaadin.annotations.PreserveOnRefresh; import com.vaadin.annotations.Theme; +import com.vaadin.annotations.Title; import com.vaadin.annotations.Widgetset; import com.vaadin.data.util.converter.Converter; import com.vaadin.data.util.converter.ConverterFactory; @@ -210,15 +210,16 @@ public class Application implements Terminal.ErrorListener, Serializable { * This implementation simulates the way of finding a window for a * request by extracting a window name from the requested path and * passes that name to {@link #getWindow(String)}. - * + *

* {@inheritDoc} - * - * @see #getWindow(String) - * @see Application#getUI(WrappedRequest) */ - @Override - public UI.LegacyWindow getUI(WrappedRequest request) { + protected T createUIInstance(WrappedRequest request, + Class uiClass) { + return uiClass.cast(getUIInstance(request)); + } + + private UI getUIInstance(WrappedRequest request) { String pathInfo = request.getRequestPathInfo(); String name = null; if (pathInfo != null && pathInfo.length() > 0) { @@ -235,6 +236,19 @@ public class Application implements Terminal.ErrorListener, Serializable { return mainWindow; } + /** + * This implementation simulates the way of finding a window for a + * request by extracting a window name from the requested path and + * passes that name to {@link #getWindow(String)}. + * + *

+ * {@inheritDoc} + */ + @Override + public Class getUIClass(WrappedRequest request) { + return getUIInstance(request).getClass(); + } + /** * Sets the application's theme. *

@@ -269,9 +283,9 @@ public class Application implements Terminal.ErrorListener, Serializable { *

* {@inheritDoc} */ - @Override - public String getThemeForUI(UI uI) { + public String getThemeForUI(WrappedRequest request, + Class uiClass) { return theme; } @@ -476,15 +490,6 @@ public class Application implements Terminal.ErrorListener, Serializable { private final EventRouter eventRouter = new EventRouter(); - /** - * Keeps track of which uIs have been inited. - *

- * TODO Investigate whether this might be derived from the different states - * in getUIForRrequest. - *

- */ - private Set initedUIs = new HashSet(); - private List uiProviders = new LinkedList(); private GlobalResourceHandler globalResourceHandler; @@ -1577,67 +1582,98 @@ public class Application implements Terminal.ErrorListener, Serializable { } /** - * Gets a UI for a request for which no UI is already known. This method is - * called when the framework processes a request that does not originate - * from an existing UI instance. This typically happens when a host page is - * requested. - * + * Gets the UI class for a request for which no UI is already known. This + * method is called when the framework processes a request that does not + * originate from an existing UI instance. This typically happens when a + * host page is requested. *

* Subclasses of Application may override this method to provide custom - * logic for choosing how to create a suitable UI or for picking an already - * created UI. If an existing UI is picked, care should be taken to avoid - * keeping the same UI open in multiple browser windows, as that will cause - * the states to go out of sync. - *

- * + * logic for choosing what kind of UI to use. *

- * If {@link BrowserDetails} are required to create a UI, the implementation - * can throw a {@link UIRequiresMoreInformationException} exception. In this - * case, the framework will instruct the browser to send the additional - * details, whereupon this method is invoked again with the browser details - * present in the wrapped request. Throwing the exception if the browser - * details are already available is not supported. - *

+ * The default implementation in {@link Application} uses the + * {@value #UI_PARAMETER} parameter from web.xml for finding the name of the + * UI class. If {@link DeploymentConfiguration#getClassLoader()} does not + * return null, the returned {@link ClassLoader} is used for + * loading the UI class. Otherwise the {@link ClassLoader} used to load this + * class is used. * - *

- * The default implementation in {@link Application} creates a new instance - * of the UI class returned by {@link #getUIClassName(WrappedRequest)}, - * which in turn uses the {@value #UI_PARAMETER} parameter from web.xml. If - * {@link DeploymentConfiguration#getClassLoader()} for the request returns - * a {@link ClassLoader}, it is used for loading the UI class. Otherwise the - * {@link ClassLoader} used to load this class is used. *

* * @param request * the wrapped request for which a UI is needed * @return a UI instance to use for the request - * @throws UIRequiresMoreInformationException - * may be thrown by an implementation to indicate that - * {@link BrowserDetails} are required to create a UI * - * @see #getUIClassName(WrappedRequest) * @see UI - * @see UIRequiresMoreInformationException * @see WrappedRequest#getBrowserDetails() * * @since 7.0 */ - protected UI getUI(WrappedRequest request) - throws UIRequiresMoreInformationException { - - // Iterate in reverse order - test check newest provider first - for (int i = uiProviders.size() - 1; i >= 0; i--) { + public Class getUIClass(WrappedRequest request) { + // Iterate in reverse order - check newest provider first + int providersSize = uiProviders.size(); + if (providersSize == 0) { + throw new IllegalStateException("There are no UI providers"); + } + for (int i = providersSize - 1; i >= 0; i--) { UIProvider provider = uiProviders.get(i); Class uiClass = provider.getUIClass(this, request); if (uiClass != null) { - return provider.instantiateUI(this, uiClass, request); + return uiClass; + } + } + + throw new RuntimeException( + "No UI provider returned an UI class for request"); + } + + /** + * Creates an UI instance for a request for which no UI is already known. + * This method is called when the framework processes a request that does + * not originate from an existing UI instance. This typically happens when a + * host page is requested. + *

+ * Subclasses of Application may override this method to provide custom + * logic for choosing how to create a suitable UI or for picking an already + * created UI. If an existing UI is picked, care should be taken to avoid + * keeping the same UI open in multiple browser windows, as that will cause + * the states to go out of sync. + *

+ * + * @param request + * @param uiClass + * @return + */ + protected T createUIInstance(WrappedRequest request, + Class uiClass) { + int providersSize = uiProviders.size(); + if (providersSize == 0) { + throw new IllegalStateException("There are no UI providers"); + } + + for (int i = providersSize - 1; i >= 0; i--) { + UIProvider provider = uiProviders.get(i); + + Class providerClass = provider.getUIClass(this, + request); + if (providerClass != null) { + if (providerClass != uiClass) { + getLogger().warning( + "Mismatching UI classes. Expected " + uiClass + + " but got " + providerClass + " from " + + provider); + // Try with next provider if we didn't get the expected + // class + continue; + } + return uiClass.cast(provider.instantiateUI(this, uiClass, + request)); } } throw new RuntimeException( - "No UI providers available or providers are not able to find UI instance"); + "No UI provider created an UI instance for request"); } /** @@ -1653,8 +1689,9 @@ public class Application implements Terminal.ErrorListener, Serializable { * * @since 7.0 */ - public String getThemeForUI(UI uI) { - Theme uiTheme = getAnnotationFor(uI.getClass(), Theme.class); + public String getThemeForUI(WrappedRequest request, + Class uiClass) { + Theme uiTheme = getAnnotationFor(uiClass, Theme.class); if (uiTheme != null) { return uiTheme.value(); } else { @@ -1665,18 +1702,22 @@ public class Application implements Terminal.ErrorListener, Serializable { /** * Finds the widgetset to use for a specific UI. If no specific widgetset is * required, null is returned. + *

+ * The default implementation uses the @{@link Widgetset} annotation if it's + * defined for the UI class. * - * TODO Tell what the default implementation does once it does something. - * - * @param uI - * the UI to get a widgetset for + * @param request + * the wrapped request for which to get a widgetset + * @param uiClass + * the UI class to get a widgetset for * @return the name of the widgetset, or null if the default * widgetset should be used * * @since 7.0 */ - public String getWidgetsetForUI(UI uI) { - Widgetset uiWidgetset = getAnnotationFor(uI.getClass(), Widgetset.class); + public String getWidgetsetForUI(WrappedRequest request, + Class uiClass) { + Widgetset uiWidgetset = getAnnotationFor(uiClass, Widgetset.class); if (uiWidgetset != null) { return uiWidgetset.value(); } else { @@ -1818,8 +1859,6 @@ public class Application implements Terminal.ErrorListener, Serializable { */ private static final ThreadLocal currentApplication = new ThreadLocal(); - private boolean uiPreserved = false; - /** * Gets the currently used application. The current application is * automatically defined when processing requests to the server. In other @@ -1894,17 +1933,12 @@ public class Application implements Terminal.ErrorListener, Serializable { * @param request * the request for which a UI is desired * @return a UI belonging to the request - * @throws UIRequiresMoreInformationException - * if no existing UI could be found and creating a new UI - * requires additional information from the browser * - * @see #getUI(WrappedRequest) - * @see UIRequiresMoreInformationException + * @see #createUI(WrappedRequest) * * @since 7.0 */ - public UI getUIForRequest(WrappedRequest request) - throws UIRequiresMoreInformationException { + public UI getUIForRequest(WrappedRequest request) { UI uI = UI.getCurrent(); if (uI != null) { return uI; @@ -1917,69 +1951,75 @@ public class Application implements Terminal.ErrorListener, Serializable { && browserDetails.getUriFragment() != null; uI = uIs.get(uiId); + Class uiClass = null; + + if (uI == null && hasBrowserDetails + && !retainOnRefreshUIs.isEmpty()) { + uiClass = getUIClass(request); - if (uI == null && isUiPreserved()) { // Check for a known UI - if (!retainOnRefreshUIs.isEmpty()) { - Integer retainedUIId; - if (!hasBrowserDetails) { - throw new UIRequiresMoreInformationException(); - } else { - String windowName = browserDetails.getWindowName(); - retainedUIId = retainOnRefreshUIs.get(windowName); - } + @SuppressWarnings("null") + String windowName = browserDetails.getWindowName(); + Integer retainedUIId = retainOnRefreshUIs.get(windowName); - if (retainedUIId != null) { + if (retainedUIId != null) { + UI retainedUI = uIs.get(retainedUIId); + // We've had the same UI instance in a window with this + // name, but should we still use it? + if (retainedUI.getClass() == uiClass) { uiId = retainedUIId; - uI = uIs.get(uiId); + uI = retainedUI; + } else { + getLogger().info( + "Not using retained UI in " + windowName + + " because retained UI was of type " + + retainedUIId.getClass() + " but " + + uiClass + + " is expected for the request."); } } } - if (uI == null) { - // Throws exception if UI can not yet be created - uI = getUI(request); + } // end synchronized block - // Initialize some fields for a newly created UI - if (uI.getApplication() == null) { - uI.setApplication(this); - } - if (uI.getUIId() < 0) { + UI.setCurrent(uI); - if (uiId == null) { - // Get the next id if none defined - uiId = Integer.valueOf(nextUIId++); - } - uI.setUIId(uiId.intValue()); - uIs.put(uiId, uI); - } - } + return uI; + } - // Set thread local here so it is available in init - UI.setCurrent(uI); + public UI createUI(WrappedRequest request) { + Class uiClass = getUIClass(request); - if (!initedUIs.contains(uiId)) { - boolean initRequiresBrowserDetails = isUiPreserved() - || !uI.getClass().isAnnotationPresent(EagerInit.class); - if (!initRequiresBrowserDetails || hasBrowserDetails) { - uI.doInit(request); + UI ui = createUIInstance(request, uiClass); - // Remember that this UI has been initialized - initedUIs.add(uiId); + // Initialize some fields for a newly created UI + if (ui.getApplication() == null) { + ui.setApplication(this); + } + // Get the next id + Integer uiId = Integer.valueOf(nextUIId++); - // init() might turn on preserve so do this afterwards - if (isUiPreserved()) { - // Remember this UI - String windowName = request.getBrowserDetails() - .getWindowName(); - retainOnRefreshUIs.put(windowName, uiId); - } - } + uIs.put(uiId, ui); + + // Set thread local here so it is available in init + UI.setCurrent(ui); + + ui.doInit(request, uiId.intValue()); + + if (isUiPreserved(request, uiClass)) { + // Remember this UI + String windowName = request.getBrowserDetails().getWindowName(); + if (windowName == null) { + getLogger().warning( + "There is no window.name available for UI " + uiClass + + " that should be preserved."); + } else { + retainOnRefreshUIs.put(windowName, uiId); } - } // end synchronized block + } - return uI; + return ui; } /** @@ -2002,54 +2042,23 @@ public class Application implements Terminal.ErrorListener, Serializable { return uiId; } - /** - * Sets whether the same UI state should be reused if the framework can - * detect that the application is opened in a browser window where it has - * previously been open. The framework attempts to discover this by checking - * the value of window.name in the browser. - *

- * NOTE that you should avoid turning this feature on/off on-the-fly when - * the UI is already shown, as it might not be retained as intended. - *

- * - * @param uiPreserved - * trueif the same UI instance should be reused e.g. - * when the browser window is refreshed. - */ - public void setUiPreserved(boolean uiPreserved) { - this.uiPreserved = uiPreserved; - if (!uiPreserved) { - retainOnRefreshUIs.clear(); - } - } - /** * Checks whether the same UI state should be reused if the framework can * detect that the application is opened in a browser window where it has * previously been open. The framework attempts to discover this by checking * the value of window.name in the browser. * + * @param request + * @param uiClass + * * @return trueif the same UI instance should be reused e.g. * when the browser window is refreshed. */ - public boolean isUiPreserved() { - return uiPreserved; - } - - /** - * Checks whether there's a pending initialization for the UI with the given - * id. - * - * @param uiId - * UI id to check for - * @return true of the initialization is pending, - * false if the UI id is not registered or if the UI - * has already been initialized - * - * @see #getUIForRequest(WrappedRequest) - */ - public boolean isUIInitPending(int uiId) { - return !initedUIs.contains(Integer.valueOf(uiId)); + public boolean isUiPreserved(WrappedRequest request, + Class uiClass) { + PreserveOnRefresh preserveOnRefresh = getAnnotationFor(uiClass, + PreserveOnRefresh.class); + return preserveOnRefresh != null; } /** @@ -2268,4 +2277,20 @@ public class Application implements Terminal.ErrorListener, Serializable { return globalResourceHandler; } + + public String getPageTitleForUI(WrappedRequest request, + Class uiClass) { + Title titleAnnotation = getAnnotationFor(uiClass, Title.class); + if (titleAnnotation == null) { + return null; + } else { + return titleAnnotation.value(); + } + } + + public boolean isEagerInit(WrappedRequest request, + Class uiClass) { + EagerInit eagerInit = getAnnotationFor(uiClass, EagerInit.class); + return eagerInit != null; + } } diff --git a/server/src/com/vaadin/UIRequiresMoreInformationException.java b/server/src/com/vaadin/UIRequiresMoreInformationException.java deleted file mode 100644 index 76a31d88ef..0000000000 --- a/server/src/com/vaadin/UIRequiresMoreInformationException.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright 2011 Vaadin Ltd. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy of - * the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations under - * the License. - */ - -package com.vaadin; - -import com.vaadin.server.WrappedRequest; -import com.vaadin.server.WrappedRequest.BrowserDetails; - -/** - * Exception that is thrown to indicate that creating or initializing the UI - * requires information detailed from the web browser ({@link BrowserDetails}) - * to be present. - * - * This exception may not be thrown if that information is already present in - * the current WrappedRequest. - * - * @see Application#getUI(WrappedRequest) - * @see WrappedRequest#getBrowserDetails() - * - * @since 7.0 - */ -public class UIRequiresMoreInformationException extends Exception { - // Nothing of interest here -} diff --git a/server/src/com/vaadin/annotations/PreserveOnRefresh.java b/server/src/com/vaadin/annotations/PreserveOnRefresh.java new file mode 100644 index 0000000000..59c4abb723 --- /dev/null +++ b/server/src/com/vaadin/annotations/PreserveOnRefresh.java @@ -0,0 +1,28 @@ +/* + * Copyright 2011 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ + +package com.vaadin.annotations; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target(ElementType.TYPE) +@Retention(RetentionPolicy.RUNTIME) +public @interface PreserveOnRefresh { + +} diff --git a/server/src/com/vaadin/annotations/Title.java b/server/src/com/vaadin/annotations/Title.java new file mode 100644 index 0000000000..fcd5d986a8 --- /dev/null +++ b/server/src/com/vaadin/annotations/Title.java @@ -0,0 +1,38 @@ +/* + * Copyright 2011 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ + +package com.vaadin.annotations; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import com.vaadin.ui.UI; + +/** + * Defines the HTML page title for a {@link UI}. + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.TYPE) +public @interface Title { + /** + * Gets the HTML title that should be used if the UI is used on it's own. + * + * @return a page title string + */ + public String value(); +} diff --git a/server/src/com/vaadin/server/AbstractApplicationPortlet.java b/server/src/com/vaadin/server/AbstractApplicationPortlet.java index e47e00577b..e8151462aa 100644 --- a/server/src/com/vaadin/server/AbstractApplicationPortlet.java +++ b/server/src/com/vaadin/server/AbstractApplicationPortlet.java @@ -56,7 +56,6 @@ import com.liferay.portal.kernel.util.PropsUtil; import com.vaadin.Application; import com.vaadin.Application.ApplicationStartEvent; import com.vaadin.Application.SystemMessages; -import com.vaadin.UIRequiresMoreInformationException; import com.vaadin.server.AbstractCommunicationManager.Callback; import com.vaadin.ui.UI; @@ -501,12 +500,7 @@ public abstract class AbstractApplicationPortlet extends GenericPortlet // Both action requests and render requests are ok // without a UI as they render the initial HTML // and then do a second request - try { - uI = application - .getUIForRequest(wrappedRequest); - } catch (UIRequiresMoreInformationException e) { - // Ignore problem and continue without UI - } + uI = application.getUIForRequest(wrappedRequest); break; case BROWSER_DETAILS: // Should not try to find a UI here as the @@ -902,7 +896,6 @@ public abstract class AbstractApplicationPortlet extends GenericPortlet throws PortletException { try { final Application application = getApplicationClass().newInstance(); - application.setUiPreserved(true); return application; } catch (final IllegalAccessException e) { throw new PortletException("getNewApplication failed", e); diff --git a/server/src/com/vaadin/server/AbstractCommunicationManager.java b/server/src/com/vaadin/server/AbstractCommunicationManager.java index 08ad48ff3d..72406e629d 100644 --- a/server/src/com/vaadin/server/AbstractCommunicationManager.java +++ b/server/src/com/vaadin/server/AbstractCommunicationManager.java @@ -60,13 +60,11 @@ import javax.servlet.http.HttpServletResponse; import com.vaadin.Application; import com.vaadin.Application.SystemMessages; -import com.vaadin.UIRequiresMoreInformationException; import com.vaadin.annotations.JavaScript; import com.vaadin.annotations.StyleSheet; import com.vaadin.external.json.JSONArray; import com.vaadin.external.json.JSONException; import com.vaadin.external.json.JSONObject; -import com.vaadin.server.BootstrapHandler.BootstrapContext; import com.vaadin.server.ComponentSizeValidator.InvalidLayout; import com.vaadin.server.RpcManager.RpcInvocationException; import com.vaadin.server.StreamVariable.StreamingEndEvent; @@ -1512,7 +1510,7 @@ public abstract class AbstractCommunicationManager implements Serializable { } private String getTheme(UI uI) { - String themeName = uI.getApplication().getThemeForUI(uI); + String themeName = uI.getTheme(); String requestThemeName = getRequestTheme(); if (requestThemeName != null) { @@ -2410,36 +2408,22 @@ public abstract class AbstractCommunicationManager implements Serializable { WrappedResponse response, Application application) throws IOException { - // if we do not yet have a currentUI, it should be initialized - // shortly, and we should send the initial UIDL - boolean sendUIDL = UI.getCurrent() == null; + assert UI.getCurrent() == null; try { CombinedRequest combinedRequest = new CombinedRequest(request); - UI uI = application.getUIForRequest(combinedRequest); response.setContentType("application/json; charset=UTF-8"); - // Use the same logic as for determined UIs - BootstrapHandler bootstrapHandler = getBootstrapHandler(); - BootstrapContext context = bootstrapHandler.createContext( - combinedRequest, response, application, uI.getUIId()); - - String widgetset = context.getWidgetsetName(); - String theme = context.getThemeName(); - String themeUri = bootstrapHandler.getThemeUri(context, theme); + UI uI = application.getUIForRequest(combinedRequest); + if (uI == null) { + uI = application.createUI(combinedRequest); + } - // TODO These are not required if it was only the init of the UI - // that was delayed JSONObject params = new JSONObject(); - params.put("widgetset", widgetset); - params.put("themeUri", themeUri); - // UI id might have changed based on e.g. window.name params.put(UIConstants.UI_ID_PARAMETER, uI.getUIId()); - if (sendUIDL) { - String initialUIDL = getInitialUIDL(combinedRequest, uI); - params.put("uidl", initialUIDL); - } + String initialUIDL = getInitialUIDL(combinedRequest, uI); + params.put("uidl", initialUIDL); // NOTE! GateIn requires, for some weird reason, getOutputStream // to be used instead of getWriter() (it seems to interpret @@ -2452,10 +2436,6 @@ public abstract class AbstractCommunicationManager implements Serializable { // NOTE GateIn requires the buffers to be flushed to work outWriter.flush(); out.flush(); - } catch (UIRequiresMoreInformationException e) { - // Requiring more information at this point is not allowed - // TODO handle in a better way - throw new RuntimeException(e); } catch (JSONException e) { // TODO Auto-generated catch block e.printStackTrace(); diff --git a/server/src/com/vaadin/server/BootstrapFragmentResponse.java b/server/src/com/vaadin/server/BootstrapFragmentResponse.java index 16f7bc653b..149f59e7a5 100644 --- a/server/src/com/vaadin/server/BootstrapFragmentResponse.java +++ b/server/src/com/vaadin/server/BootstrapFragmentResponse.java @@ -21,6 +21,7 @@ import java.util.List; import org.jsoup.nodes.Node; import com.vaadin.Application; +import com.vaadin.ui.UI; /** * A representation of a bootstrap fragment being generated. The bootstrap @@ -37,7 +38,7 @@ public class BootstrapFragmentResponse extends BootstrapResponse { * Crate a new bootstrap fragment response. * * @see BootstrapResponse#BootstrapResponse(BootstrapHandler, - * WrappedRequest, Application, Integer) + * WrappedRequest, Application, Class) * * @param handler * the bootstrap handler that is firing the event @@ -47,16 +48,16 @@ public class BootstrapFragmentResponse extends BootstrapResponse { * @param application * the application for which the bootstrap page should be * generated - * @param uiId - * the generated id of the UI that will be displayed on the page + * @param uiClass + * the class of the UI that will be displayed on the page * @param fragmentNodes * a mutable list containing the DOM nodes that will make up the * application HTML */ public BootstrapFragmentResponse(BootstrapHandler handler, - WrappedRequest request, Application application, Integer uiId, - List fragmentNodes) { - super(handler, request, application, uiId); + WrappedRequest request, Application application, + Class uiClass, List fragmentNodes) { + super(handler, request, application, uiClass); this.fragmentNodes = fragmentNodes; } diff --git a/server/src/com/vaadin/server/BootstrapHandler.java b/server/src/com/vaadin/server/BootstrapHandler.java index 280372a5e5..2b31d5d3bc 100644 --- a/server/src/com/vaadin/server/BootstrapHandler.java +++ b/server/src/com/vaadin/server/BootstrapHandler.java @@ -37,12 +37,10 @@ import org.jsoup.nodes.Node; import org.jsoup.parser.Tag; import com.vaadin.Application; -import com.vaadin.UIRequiresMoreInformationException; import com.vaadin.external.json.JSONException; import com.vaadin.external.json.JSONObject; import com.vaadin.shared.ApplicationConstants; import com.vaadin.shared.Version; -import com.vaadin.shared.ui.ui.UIConstants; import com.vaadin.ui.UI; public abstract class BootstrapHandler implements RequestHandler { @@ -74,30 +72,20 @@ public abstract class BootstrapHandler implements RequestHandler { return bootstrapResponse.getApplication(); } - public Integer getUIId() { - return bootstrapResponse.getUIId(); - } - - public UI getUI() { - return bootstrapResponse.getUI(); + public Class getUIClass() { + return bootstrapResponse.getUiClass(); } public String getWidgetsetName() { if (widgetsetName == null) { - UI uI = getUI(); - if (uI != null) { - widgetsetName = getWidgetsetForUI(this); - } + widgetsetName = getWidgetsetForUI(this); } return widgetsetName; } public String getThemeName() { if (themeName == null) { - UI uI = getUI(); - if (uI != null) { - themeName = findAndEscapeThemeName(this); - } + themeName = findAndEscapeThemeName(this); } return themeName; } @@ -120,23 +108,11 @@ public abstract class BootstrapHandler implements RequestHandler { WrappedRequest request, WrappedResponse response) throws IOException { - // TODO Should all urls be handled here? - Integer uiId = null; try { - UI uI = application.getUIForRequest(request); - if (uI == null) { - writeError(response, new Throwable("No UI found")); - return true; - } + Class uiClass = application.getUIClass(request); - uiId = Integer.valueOf(uI.getUIId()); - } catch (UIRequiresMoreInformationException e) { - // Just keep going without uiId - } - - try { BootstrapContext context = createContext(request, response, - application, uiId); + application, uiClass); setupMainDiv(context); BootstrapFragmentResponse fragmentResponse = context @@ -166,8 +142,8 @@ public abstract class BootstrapHandler implements RequestHandler { Map headers = new LinkedHashMap(); Document document = Document.createShell(""); BootstrapPageResponse pageResponse = new BootstrapPageResponse( - this, request, context.getApplication(), context.getUIId(), - document, headers); + this, request, context.getApplication(), + context.getUIClass(), document, headers); List fragmentNodes = fragmentResponse.getFragmentNodes(); Element body = document.body(); for (Node node : fragmentNodes) { @@ -242,10 +218,11 @@ public abstract class BootstrapHandler implements RequestHandler { head.appendElement("meta").attr("http-equiv", "X-UA-Compatible") .attr("content", "chrome=1"); - UI uI = context.getUI(); - String title = ((uI == null || uI.getCaption() == null) ? "" : uI - .getCaption()); - head.appendElement("title").appendText(title); + String title = context.getApplication().getPageTitleForUI( + context.getRequest(), context.getUIClass()); + if (title != null) { + head.appendElement("title").appendText(title); + } head.appendElement("style").attr("type", "text/css") .appendText("html, body {height:100%;margin:0;}"); @@ -267,11 +244,12 @@ public abstract class BootstrapHandler implements RequestHandler { body.addClass(ApplicationConstants.GENERATED_BODY_CLASSNAME); } - public BootstrapContext createContext(WrappedRequest request, - WrappedResponse response, Application application, Integer uiId) { + private BootstrapContext createContext(WrappedRequest request, + WrappedResponse response, Application application, + Class uiClass) { BootstrapContext context = new BootstrapContext(response, - new BootstrapFragmentResponse(this, request, application, uiId, - new ArrayList())); + new BootstrapFragmentResponse(this, request, application, + uiClass, new ArrayList())); return context; } @@ -290,10 +268,10 @@ public abstract class BootstrapHandler implements RequestHandler { protected abstract String getApplicationId(BootstrapContext context); public String getWidgetsetForUI(BootstrapContext context) { - UI uI = context.getUI(); WrappedRequest request = context.getRequest(); - String widgetset = uI.getApplication().getWidgetsetForUI(uI); + String widgetset = context.getApplication().getWidgetsetForUI( + context.getRequest(), context.getUIClass()); if (widgetset == null) { widgetset = request.getDeploymentConfiguration() .getConfiguredWidgetset(request); @@ -413,14 +391,9 @@ public abstract class BootstrapHandler implements RequestHandler { protected JSONObject getApplicationParameters(BootstrapContext context) throws JSONException, PaintException { Application application = context.getApplication(); - Integer uiId = context.getUIId(); JSONObject appConfig = new JSONObject(); - if (uiId != null) { - appConfig.put(UIConstants.UI_ID_PARAMETER, uiId); - } - if (context.getThemeName() != null) { appConfig.put("themeUri", getThemeUri(context, context.getThemeName())); @@ -433,18 +406,18 @@ public abstract class BootstrapHandler implements RequestHandler { appConfig.put("widgetset", context.getWidgetsetName()); - if (uiId == null || application.isUIInitPending(uiId.intValue())) { - appConfig.put("initialPath", context.getRequest() - .getRequestPathInfo()); - - Map parameterMap = context.getRequest() - .getParameterMap(); - appConfig.put("initialParams", parameterMap); - } else { + if (application.isEagerInit(context.getRequest(), context.getUIClass())) { + throw new RuntimeException( + "Eager UI init is currently not supported"); // write the initial UIDL into the config - appConfig.put("uidl", - getInitialUIDL(context.getRequest(), context.getUI())); + // appConfig.put("uidl", + // getInitialUIDL(context.getRequest(), context.getUI())); } + appConfig.put("initialPath", context.getRequest().getRequestPathInfo()); + + Map parameterMap = context.getRequest() + .getParameterMap(); + appConfig.put("initialParams", parameterMap); return appConfig; } @@ -532,7 +505,8 @@ public abstract class BootstrapHandler implements RequestHandler { * @return */ public String getThemeName(BootstrapContext context) { - return context.getApplication().getThemeForUI(context.getUI()); + return context.getApplication().getThemeForUI(context.getRequest(), + context.getUIClass()); } /** @@ -561,21 +535,4 @@ public abstract class BootstrapHandler implements RequestHandler { 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 ui - * the UI for which the UIDL should be generated - * @return a string with the initial UIDL message - * @throws PaintException - * if an exception occurs while painting the components - * @throws JSONException - * if an exception occurs while formatting the output - */ - protected abstract String getInitialUIDL(WrappedRequest request, UI ui) - throws PaintException, JSONException; - } diff --git a/server/src/com/vaadin/server/BootstrapPageResponse.java b/server/src/com/vaadin/server/BootstrapPageResponse.java index d6df145728..a5fdfe4707 100644 --- a/server/src/com/vaadin/server/BootstrapPageResponse.java +++ b/server/src/com/vaadin/server/BootstrapPageResponse.java @@ -21,6 +21,7 @@ import java.util.Map; import org.jsoup.nodes.Document; import com.vaadin.Application; +import com.vaadin.ui.UI; /** * A representation of a bootstrap page being generated. The bootstrap page @@ -39,7 +40,7 @@ public class BootstrapPageResponse extends BootstrapResponse { * Crate a new bootstrap page response. * * @see BootstrapResponse#BootstrapResponse(BootstrapHandler, - * WrappedRequest, Application, Integer) + * WrappedRequest, Application, Class) * * @param handler * the bootstrap handler that is firing the event @@ -49,17 +50,18 @@ public class BootstrapPageResponse extends BootstrapResponse { * @param application * the application for which the bootstrap page should be * generated - * @param uiId - * the generated id of the UI that will be displayed on the page + * @param uiClass + * the class of the UI that will be displayed on the page * @param document * the DOM document making up the HTML page * @param headers * a map into which header data can be added */ public BootstrapPageResponse(BootstrapHandler handler, - WrappedRequest request, Application application, Integer uiId, - Document document, Map headers) { - super(handler, request, application, uiId); + WrappedRequest request, Application application, + Class uiClass, Document document, + Map headers) { + super(handler, request, application, uiClass); this.headers = headers; this.document = document; } diff --git a/server/src/com/vaadin/server/BootstrapResponse.java b/server/src/com/vaadin/server/BootstrapResponse.java index 962b48dc31..3173569059 100644 --- a/server/src/com/vaadin/server/BootstrapResponse.java +++ b/server/src/com/vaadin/server/BootstrapResponse.java @@ -19,7 +19,6 @@ package com.vaadin.server; import java.util.EventObject; import com.vaadin.Application; -import com.vaadin.UIRequiresMoreInformationException; import com.vaadin.ui.UI; /** @@ -32,7 +31,7 @@ import com.vaadin.ui.UI; public abstract class BootstrapResponse extends EventObject { private final WrappedRequest request; private final Application application; - private final Integer uiId; + private final Class uiClass; /** * Creates a new bootstrap event. @@ -45,15 +44,15 @@ public abstract class BootstrapResponse extends EventObject { * @param application * the application for which the bootstrap page should be * generated - * @param uiId - * the generated id of the UI that will be displayed on the page + * @param uiClass + * the class of the UI that will be displayed on the page */ public BootstrapResponse(BootstrapHandler handler, WrappedRequest request, - Application application, Integer uiId) { + Application application, Class uiClass) { super(handler); this.request = request; this.application = application; - this.uiId = uiId; + this.uiClass = uiClass; } /** @@ -89,32 +88,13 @@ public abstract class BootstrapResponse extends EventObject { } /** - * Gets the UI id that has been generated for this response. Please note - * that if {@link Application#isUiPreserved()} is enabled, a previously - * created UI with a different id might eventually end up being used. + * Gets the class of the UI that will be displayed on the generated + * bootstrap page. * - * @return the UI id + * @return the class of the UI */ - public Integer getUIId() { - return uiId; + public Class getUiClass() { + return uiClass; } - /** - * Gets the UI for which this page is being rendered, if available. Some - * features of the framework will postpone the UI selection until after the - * bootstrap page has been rendered and required information from the - * browser has been sent back. This method will return null if - * no UI instance is yet available. - * - * @see Application#isUiPreserved() - * @see Application#getUI(WrappedRequest) - * @see UIRequiresMoreInformationException - * - * @return The UI that will be displayed in the page being generated, or - * null if all required information is not yet - * available. - */ - public UI getUI() { - return UI.getCurrent(); - } } diff --git a/server/src/com/vaadin/server/CommunicationManager.java b/server/src/com/vaadin/server/CommunicationManager.java index 9b56e20fd4..3c594eaf02 100644 --- a/server/src/com/vaadin/server/CommunicationManager.java +++ b/server/src/com/vaadin/server/CommunicationManager.java @@ -22,7 +22,6 @@ import java.net.URL; import javax.servlet.ServletContext; import com.vaadin.Application; -import com.vaadin.external.json.JSONException; import com.vaadin.ui.UI; /** @@ -107,12 +106,6 @@ public class CommunicationManager extends AbstractCommunicationManager { } return themeName; } - - @Override - protected String getInitialUIDL(WrappedRequest request, UI uI) - throws PaintException, JSONException { - return CommunicationManager.this.getInitialUIDL(request, uI); - } }; } diff --git a/server/src/com/vaadin/server/DefaultUIProvider.java b/server/src/com/vaadin/server/DefaultUIProvider.java index d4490b1642..93128aad28 100644 --- a/server/src/com/vaadin/server/DefaultUIProvider.java +++ b/server/src/com/vaadin/server/DefaultUIProvider.java @@ -17,14 +17,13 @@ package com.vaadin.server; import com.vaadin.Application; -import com.vaadin.UIRequiresMoreInformationException; import com.vaadin.ui.UI; public class DefaultUIProvider extends AbstractUIProvider { @Override public Class getUIClass(Application application, - WrappedRequest request) throws UIRequiresMoreInformationException { + WrappedRequest request) { Object uiClassNameObj = application .getProperty(Application.UI_PARAMETER); diff --git a/server/src/com/vaadin/server/PortletCommunicationManager.java b/server/src/com/vaadin/server/PortletCommunicationManager.java index f7d9371022..697095d691 100644 --- a/server/src/com/vaadin/server/PortletCommunicationManager.java +++ b/server/src/com/vaadin/server/PortletCommunicationManager.java @@ -137,13 +137,6 @@ public class PortletCommunicationManager extends AbstractCommunicationManager { null); } - @Override - protected String getInitialUIDL(WrappedRequest request, UI uI) - throws PaintException, JSONException { - return PortletCommunicationManager.this.getInitialUIDL(request, - uI); - } - @Override protected JSONObject getApplicationParameters( BootstrapContext context) throws JSONException, diff --git a/server/src/com/vaadin/server/UIProvider.java b/server/src/com/vaadin/server/UIProvider.java index 890809fdd5..36bb164845 100644 --- a/server/src/com/vaadin/server/UIProvider.java +++ b/server/src/com/vaadin/server/UIProvider.java @@ -17,12 +17,11 @@ package com.vaadin.server; import com.vaadin.Application; -import com.vaadin.UIRequiresMoreInformationException; import com.vaadin.ui.UI; public interface UIProvider { public Class getUIClass(Application application, - WrappedRequest request) throws UIRequiresMoreInformationException; + WrappedRequest request); public UI instantiateUI(Application application, Class type, WrappedRequest request); diff --git a/server/src/com/vaadin/server/WrappedRequest.java b/server/src/com/vaadin/server/WrappedRequest.java index 8ae5335763..e95b2d599b 100644 --- a/server/src/com/vaadin/server/WrappedRequest.java +++ b/server/src/com/vaadin/server/WrappedRequest.java @@ -26,8 +26,6 @@ import javax.portlet.PortletRequest; import javax.servlet.ServletRequest; import javax.servlet.http.HttpServletRequest; -import com.vaadin.Application; -import com.vaadin.UIRequiresMoreInformationException; import com.vaadin.annotations.EagerInit; import com.vaadin.ui.UI; @@ -218,11 +216,8 @@ public interface WrappedRequest extends Serializable { * for instance using javascript in the browser. * * This information is only guaranteed to be available in some special - * cases, for instance when - * {@link Application#getUIForRequest(WrappedRequest)} is called again after - * throwing {@link UIRequiresMoreInformationException} or in - * {@link UI#init(WrappedRequest)} for a UI class not annotated with - * {@link EagerInit} + * cases, for instance in {@link UI#init(WrappedRequest)} for a UI class not + * annotated with {@link EagerInit} * * @return the browser details, or null if details are not * available diff --git a/server/src/com/vaadin/ui/UI.java b/server/src/com/vaadin/ui/UI.java index d86d46c155..b6ac271942 100644 --- a/server/src/com/vaadin/ui/UI.java +++ b/server/src/com/vaadin/ui/UI.java @@ -85,7 +85,7 @@ import com.vaadin.tools.ReflectTools; *

* * @see #init(WrappedRequest) - * @see Application#getUI(WrappedRequest) + * @see Application#createUI(WrappedRequest) * * @since 7.0 */ @@ -98,7 +98,6 @@ public abstract class UI extends AbstractComponentContainer implements * window in Vaadin 6 with {@link com.vaadin.Application.LegacyApplication} */ @Deprecated - @EagerInit public static class LegacyWindow extends UI { private String name; @@ -709,28 +708,6 @@ public abstract class UI extends AbstractComponentContainer implements } } - /** - * Sets the id of this UI within its application. The UI id is used to route - * requests to the right UI. - *

- * This method is mainly intended for internal use by the framework. - *

- * - * @param uiId - * the id of this UI - * - * @throws IllegalStateException - * if the UI id has already been set - * - * @see #getUIId() - */ - public void setUIId(int uiId) { - if (this.uiId != -1) { - throw new IllegalStateException("UI id has already been defined"); - } - this.uiId = uiId; - } - /** * Gets the id of the UI, used to identify this UI within its application * when processing requests. The UI id should be present in every request to @@ -748,8 +725,8 @@ public abstract class UI extends AbstractComponentContainer implements * Adds a window as a subwindow inside this UI. To open a new browser window * or tab, you should instead use {@link open(Resource)} with an url * pointing to this application and ensure - * {@link Application#getUI(WrappedRequest)} returns an appropriate UI for - * the request. + * {@link Application#createUI(WrappedRequest)} returns an appropriate UI + * for the request. * * @param window * @throws IllegalArgumentException @@ -831,6 +808,8 @@ public abstract class UI extends AbstractComponentContainer implements private boolean resizeLazy = false; + private String theme; + /** * This method is used by Component.Focusable objects to request focus to * themselves. Focus renders must be handled at window level (instead of @@ -959,8 +938,16 @@ public abstract class UI extends AbstractComponentContainer implements * * @param request * the initialization request + * @param uiId + * the id of the new ui */ - public void doInit(WrappedRequest request) { + public void doInit(WrappedRequest request, int uiId) { + if (this.uiId != -1) { + throw new IllegalStateException("UI id has already been defined"); + } + this.uiId = uiId; + theme = getApplication().getThemeForUI(request, getClass()); + getPage().init(request); // Call the init overridden by the application developer @@ -1352,4 +1339,13 @@ public abstract class UI extends AbstractComponentContainer implements public void setLastUidlRequestTime(long lastUidlRequest) { this.lastUidlRequest = lastUidlRequest; } + + /** + * Gets the theme that was used when the UI was initialized. + * + * @return the theme name + */ + public String getTheme() { + return theme; + } } diff --git a/server/tests/src/com/vaadin/tests/server/component/root/CustomUIClassLoader.java b/server/tests/src/com/vaadin/tests/server/component/root/CustomUIClassLoader.java index 906d6ccebd..89da55a31f 100644 --- a/server/tests/src/com/vaadin/tests/server/component/root/CustomUIClassLoader.java +++ b/server/tests/src/com/vaadin/tests/server/component/root/CustomUIClassLoader.java @@ -10,7 +10,6 @@ import org.easymock.EasyMock; import com.vaadin.Application; import com.vaadin.Application.ApplicationStartEvent; -import com.vaadin.UIRequiresMoreInformationException; import com.vaadin.server.DefaultUIProvider; import com.vaadin.server.DeploymentConfiguration; import com.vaadin.server.WrappedRequest; @@ -56,8 +55,11 @@ public class CustomUIClassLoader extends TestCase { application.start(new ApplicationStartEvent(null, createConfigurationMock(), null)); - UI uI = application.getUIForRequest(createRequestMock(null)); - assertTrue(uI instanceof MyUI); + DefaultUIProvider uiProvider = new DefaultUIProvider(); + Class uiClass = uiProvider.getUIClass(application, + createRequestMock(null)); + + assertEquals(MyUI.class, uiClass); } private static DeploymentConfiguration createConfigurationMock() { @@ -101,9 +103,11 @@ public class CustomUIClassLoader extends TestCase { application.start(new ApplicationStartEvent(null, createConfigurationMock(), null)); - UI uI = application - .getUIForRequest(createRequestMock(loggingClassLoader)); - assertTrue(uI instanceof MyUI); + DefaultUIProvider uiProvider = new DefaultUIProvider(); + Class uiClass = uiProvider.getUIClass(application, + createRequestMock(loggingClassLoader)); + + assertEquals(MyUI.class, uiClass); assertEquals(1, loggingClassLoader.requestedClasses.size()); assertEquals(MyUI.class.getName(), loggingClassLoader.requestedClasses.get(0)); @@ -112,10 +116,6 @@ public class CustomUIClassLoader extends TestCase { private Application createStubApplication() { return new Application() { - { - addUIProvider(new DefaultUIProvider()); - } - @Override public String getProperty(String name) { if (name.equals(UI_PARAMETER)) { @@ -124,14 +124,6 @@ public class CustomUIClassLoader extends TestCase { return super.getProperty(name); } } - - @Override - public UI getUIForRequest(WrappedRequest request) - throws UIRequiresMoreInformationException { - // Always create a new root for testing (can't directly use - // getRoot as it's protected) - return getUI(request); - } }; } } diff --git a/uitest/src/com/vaadin/launcher/ApplicationRunnerServlet.java b/uitest/src/com/vaadin/launcher/ApplicationRunnerServlet.java index e05979ede0..bceecaf35a 100644 --- a/uitest/src/com/vaadin/launcher/ApplicationRunnerServlet.java +++ b/uitest/src/com/vaadin/launcher/ApplicationRunnerServlet.java @@ -30,7 +30,6 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import com.vaadin.Application; -import com.vaadin.UIRequiresMoreInformationException; import com.vaadin.server.AbstractApplicationServlet; import com.vaadin.server.AbstractUIProvider; import com.vaadin.server.WrappedHttpServletRequest; @@ -116,8 +115,7 @@ public class ApplicationRunnerServlet extends AbstractApplicationServlet { @Override public Class getUIClass( - Application application, WrappedRequest request) - throws UIRequiresMoreInformationException { + Application application, WrappedRequest request) { return (Class) classToRun; } }); diff --git a/uitest/src/com/vaadin/tests/application/RefreshStatePreserve.java b/uitest/src/com/vaadin/tests/application/RefreshStatePreserve.java index 3013659ed7..8962f5de9a 100644 --- a/uitest/src/com/vaadin/tests/application/RefreshStatePreserve.java +++ b/uitest/src/com/vaadin/tests/application/RefreshStatePreserve.java @@ -1,7 +1,7 @@ package com.vaadin.tests.application; import com.vaadin.Application; -import com.vaadin.UIRequiresMoreInformationException; +import com.vaadin.annotations.PreserveOnRefresh; import com.vaadin.server.AbstractUIProvider; import com.vaadin.server.WrappedRequest; import com.vaadin.tests.components.AbstractTestApplication; @@ -9,6 +9,7 @@ import com.vaadin.ui.Label; import com.vaadin.ui.UI; public class RefreshStatePreserve extends AbstractTestApplication { + @PreserveOnRefresh public static class RefreshStateUI extends UI { @Override public void init(WrappedRequest request) { @@ -22,12 +23,10 @@ public class RefreshStatePreserve extends AbstractTestApplication { @Override public void init() { super.init(); - setUiPreserved(true); addUIProvider(new AbstractUIProvider() { @Override public Class getUIClass(Application application, - WrappedRequest request) - throws UIRequiresMoreInformationException { + WrappedRequest request) { return RefreshStateUI.class; } }); diff --git a/uitest/src/com/vaadin/tests/application/ThreadLocalInstances.java b/uitest/src/com/vaadin/tests/application/ThreadLocalInstances.java index 0e7dd1b242..89cbf5d3ff 100644 --- a/uitest/src/com/vaadin/tests/application/ThreadLocalInstances.java +++ b/uitest/src/com/vaadin/tests/application/ThreadLocalInstances.java @@ -1,9 +1,9 @@ package com.vaadin.tests.application; import com.vaadin.Application; -import com.vaadin.UIRequiresMoreInformationException; import com.vaadin.server.DownloadStream; import com.vaadin.server.PaintException; +import com.vaadin.server.UIProvider; import com.vaadin.server.WrappedRequest; import com.vaadin.tests.components.AbstractTestApplication; import com.vaadin.tests.integration.FlagSeResource; @@ -73,12 +73,19 @@ public class ThreadLocalInstances extends AbstractTestApplication { @Override public void init() { reportCurrentStatus("app init"); - } + addUIProvider(new UIProvider() { + @Override + public UI instantiateUI(Application application, + Class type, WrappedRequest request) { + return mainWindow; + } - @Override - protected UI getUI(WrappedRequest request) - throws UIRequiresMoreInformationException { - return mainWindow; + @Override + public Class getUIClass(Application application, + WrappedRequest request) { + return mainWindow.getClass(); + } + }); } @Override diff --git a/uitest/src/com/vaadin/tests/components/loginform/LoginFormWithMultipleWindows.java b/uitest/src/com/vaadin/tests/components/loginform/LoginFormWithMultipleWindows.java index ac4c3c8ea3..84c14763ab 100644 --- a/uitest/src/com/vaadin/tests/components/loginform/LoginFormWithMultipleWindows.java +++ b/uitest/src/com/vaadin/tests/components/loginform/LoginFormWithMultipleWindows.java @@ -1,6 +1,7 @@ package com.vaadin.tests.components.loginform; import com.vaadin.Application; +import com.vaadin.server.AbstractUIProvider; import com.vaadin.server.WrappedRequest; import com.vaadin.ui.LoginForm; import com.vaadin.ui.LoginForm.LoginEvent; @@ -12,11 +13,17 @@ import com.vaadin.ui.UI.LegacyWindow; public class LoginFormWithMultipleWindows extends Application { @Override - protected UI getUI(WrappedRequest request) { - return new LoginFormWindow(); + public void init() { + addUIProvider(new AbstractUIProvider() { + @Override + public Class getUIClass(Application application, + WrappedRequest request) { + return LoginFormWindow.class; + } + }); } - public class LoginFormWindow extends LegacyWindow { + public static class LoginFormWindow extends LegacyWindow { public LoginFormWindow() { super(); diff --git a/uitest/src/com/vaadin/tests/components/ui/LazyInitUIs.java b/uitest/src/com/vaadin/tests/components/ui/LazyInitUIs.java index 34bf8f6715..4cd786593a 100644 --- a/uitest/src/com/vaadin/tests/components/ui/LazyInitUIs.java +++ b/uitest/src/com/vaadin/tests/components/ui/LazyInitUIs.java @@ -1,10 +1,10 @@ package com.vaadin.tests.components.ui; -import com.vaadin.UIRequiresMoreInformationException; +import com.vaadin.Application; import com.vaadin.annotations.EagerInit; import com.vaadin.server.ExternalResource; +import com.vaadin.server.UIProvider; import com.vaadin.server.WrappedRequest; -import com.vaadin.server.WrappedRequest.BrowserDetails; import com.vaadin.shared.ui.label.ContentMode; import com.vaadin.tests.components.AbstractTestApplication; import com.vaadin.ui.Label; @@ -22,23 +22,33 @@ public class LazyInitUIs extends AbstractTestApplication { } @Override - public UI getUI(WrappedRequest request) - throws UIRequiresMoreInformationException { + public void init() { + addUIProvider(new UIProvider() { + + @Override + public UI instantiateUI(Application application, + Class type, WrappedRequest request) { + return getUI(request); + } + + @Override + public Class getUIClass(Application application, + WrappedRequest request) { + return getUI(request).getClass(); + } + }); + } + + private UI getUI(WrappedRequest request) { if (request.getParameter("lazyCreate") != null) { // UI created on second request - BrowserDetails browserDetails = request.getBrowserDetails(); - if (browserDetails == null - || browserDetails.getUriFragment() == null) { - throw new UIRequiresMoreInformationException(); - } else { - UI uI = new UI() { - @Override - protected void init(WrappedRequest request) { - addComponent(getRequestInfo("LazyCreateUI", request)); - } - }; - return uI; - } + UI uI = new UI() { + @Override + protected void init(WrappedRequest request) { + addComponent(getRequestInfo("LazyCreateUI", request)); + } + }; + return uI; } else if (request.getParameter("eagerInit") != null) { // UI inited on first request return new EagerInitUI(); diff --git a/uitest/src/com/vaadin/tests/components/ui/UIsInMultipleTabs.java b/uitest/src/com/vaadin/tests/components/ui/UIsInMultipleTabs.java index 022db1bf3e..fe2fe16d93 100644 --- a/uitest/src/com/vaadin/tests/components/ui/UIsInMultipleTabs.java +++ b/uitest/src/com/vaadin/tests/components/ui/UIsInMultipleTabs.java @@ -1,7 +1,6 @@ package com.vaadin.tests.components.ui; import com.vaadin.Application; -import com.vaadin.UIRequiresMoreInformationException; import com.vaadin.server.AbstractUIProvider; import com.vaadin.server.WrappedRequest; import com.vaadin.tests.components.AbstractTestApplication; @@ -26,8 +25,7 @@ public class UIsInMultipleTabs extends AbstractTestApplication { addUIProvider(new AbstractUIProvider() { @Override public Class getUIClass(Application application, - WrappedRequest request) - throws UIRequiresMoreInformationException { + WrappedRequest request) { return TabUI.class; } }); diff --git a/uitest/src/com/vaadin/tests/minitutorials/v7a1/CreatingPreserveState.java b/uitest/src/com/vaadin/tests/minitutorials/v7a1/CreatingPreserveState.java index a96b8957c6..cfb24c732f 100644 --- a/uitest/src/com/vaadin/tests/minitutorials/v7a1/CreatingPreserveState.java +++ b/uitest/src/com/vaadin/tests/minitutorials/v7a1/CreatingPreserveState.java @@ -16,9 +16,10 @@ package com.vaadin.tests.minitutorials.v7a1; +import com.vaadin.annotations.PreserveOnRefresh; import com.vaadin.server.WrappedRequest; -import com.vaadin.ui.UI; import com.vaadin.ui.TextField; +import com.vaadin.ui.UI; /** * Mini tutorial code for @@ -28,6 +29,7 @@ import com.vaadin.ui.TextField; * @author Vaadin Ltd * @since 7.0.0 */ +@PreserveOnRefresh public class CreatingPreserveState extends UI { private static int windowCounter = 0; @@ -36,7 +38,6 @@ public class CreatingPreserveState extends UI { TextField tf = new TextField("Window #" + (++windowCounter)); tf.setImmediate(true); getContent().addComponent(tf); - getApplication().setUiPreserved(true); } } diff --git a/uitest/src/com/vaadin/tests/minitutorials/v7a1/DifferentFeaturesForDifferentClients.java b/uitest/src/com/vaadin/tests/minitutorials/v7a1/DifferentFeaturesForDifferentClients.java index ba3042c48e..54cf8a94e0 100644 --- a/uitest/src/com/vaadin/tests/minitutorials/v7a1/DifferentFeaturesForDifferentClients.java +++ b/uitest/src/com/vaadin/tests/minitutorials/v7a1/DifferentFeaturesForDifferentClients.java @@ -17,10 +17,9 @@ package com.vaadin.tests.minitutorials.v7a1; import com.vaadin.Application; -import com.vaadin.UIRequiresMoreInformationException; +import com.vaadin.server.UIProvider; import com.vaadin.server.WebBrowser; import com.vaadin.server.WrappedRequest; -import com.vaadin.server.WrappedRequest.BrowserDetails; import com.vaadin.ui.Label; import com.vaadin.ui.UI; @@ -35,21 +34,32 @@ import com.vaadin.ui.UI; public class DifferentFeaturesForDifferentClients extends Application { @Override - protected UI getUI(WrappedRequest request) - throws UIRequiresMoreInformationException { - BrowserDetails browserDetails = request.getBrowserDetails(); - // This is a limitation of 7.0.0.alpha1 that there is no better way to - // check if WebBrowser has been fully initialized - if (browserDetails.getUriFragment() == null) { - throw new UIRequiresMoreInformationException(); - } + public void init() { + super.init(); + addUIProvider(new UIProvider() { + @Override + public Class getUIClass(Application application, + WrappedRequest request) { + // could also use browser version etc. + if (request.getHeader("user-agent").contains("mobile")) { + return TouchRoot.class; + } else { + return DefaultRoot.class; + } + } - // could also use screen size, browser version etc. - if (browserDetails.getWebBrowser().isTouchDevice()) { - return new TouchRoot(); - } else { - return new DefaultRoot(); - } + // Must override as default implementation isn't allowed to + // instantiate our non-public classes + @Override + public UI instantiateUI(Application application, + Class type, WrappedRequest request) { + try { + return type.newInstance(); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + }); } } diff --git a/uitest/src/com/vaadin/tests/vaadincontext/TestAddonContextListener.java b/uitest/src/com/vaadin/tests/vaadincontext/TestAddonContextListener.java index 9f3019b21c..1f50110330 100644 --- a/uitest/src/com/vaadin/tests/vaadincontext/TestAddonContextListener.java +++ b/uitest/src/com/vaadin/tests/vaadincontext/TestAddonContextListener.java @@ -42,9 +42,8 @@ public class TestAddonContextListener implements AddonContextListener { } private boolean shouldModify(BootstrapResponse response) { - UI uI = response.getUI(); - boolean shouldModify = uI != null - && uI.getClass() == BootstrapModifyUI.class; + Class uiClass = response.getUiClass(); + boolean shouldModify = uiClass == BootstrapModifyUI.class; return shouldModify; } -- 2.39.5