diff options
author | Leif Åstrand <leif@vaadin.com> | 2012-09-04 11:15:53 +0300 |
---|---|---|
committer | Leif Åstrand <leif@vaadin.com> | 2012-09-05 11:39:31 +0300 |
commit | aa913676e513170244169352dd97d6b583b50065 (patch) | |
tree | f1c0f70d0ca822261af860c285630e2401f0a4b8 /server | |
parent | 65240f403416efc82fb5ff9efce682291d426e89 (diff) | |
download | vaadin-framework-aa913676e513170244169352dd97d6b583b50065.tar.gz vaadin-framework-aa913676e513170244169352dd97d6b583b50065.zip |
Move UI class info querying to UIProvider (#9402)
Diffstat (limited to 'server')
-rw-r--r-- | server/src/com/vaadin/Application.java | 290 | ||||
-rw-r--r-- | server/src/com/vaadin/server/AbstractUIProvider.java | 83 | ||||
-rw-r--r-- | server/src/com/vaadin/server/BootstrapHandler.java | 15 | ||||
-rw-r--r-- | server/src/com/vaadin/server/UIProvider.java | 53 | ||||
-rw-r--r-- | server/src/com/vaadin/ui/UI.java | 3 |
5 files changed, 255 insertions, 189 deletions
diff --git a/server/src/com/vaadin/Application.java b/server/src/com/vaadin/Application.java index 9498534b4a..36a8db83a1 100644 --- a/server/src/com/vaadin/Application.java +++ b/server/src/com/vaadin/Application.java @@ -18,7 +18,6 @@ package com.vaadin; import java.io.IOException; import java.io.Serializable; -import java.lang.annotation.Annotation; import java.lang.reflect.Method; import java.net.SocketException; import java.net.URL; @@ -40,15 +39,12 @@ import java.util.logging.Logger; import java.util.regex.Matcher; import java.util.regex.Pattern; -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; import com.vaadin.data.util.converter.DefaultConverterFactory; import com.vaadin.event.EventRouter; import com.vaadin.server.AbstractErrorMessage; +import com.vaadin.server.AbstractUIProvider; import com.vaadin.server.ApplicationContext; import com.vaadin.server.BootstrapFragmentResponse; import com.vaadin.server.BootstrapListener; @@ -193,6 +189,47 @@ public class Application implements Terminal.ErrorListener, Serializable { this.mainWindow = mainWindow; } + @Override + public void start(ApplicationStartEvent event) { + super.start(event); + addUIProvider(new AbstractUIProvider() { + @Override + public Class<? extends UI> getUIClass(Application application, + WrappedRequest request) { + if (application == LegacyApplication.this) { + UI uiInstance = getUIInstance(request); + if (uiInstance != null) { + return uiInstance.getClass(); + } + } + return null; + } + + @Override + public UI createInstance(Application application, + Class<? extends UI> type, WrappedRequest request) { + return getUIInstance(request); + } + + @Override + public String getThemeForUI(WrappedRequest request, + Class<? extends UI> uiClass) { + return theme; + } + + @Override + public String getPageTitleForUI(WrappedRequest request, + Class<? extends UI> uiClass) { + UI uiInstance = getUIInstance(request); + if (uiInstance != null) { + return uiInstance.getCaption(); + } else { + return super.getPageTitleForUI(request, uiClass); + } + } + }); + } + /** * Gets the mainWindow of the application. * @@ -210,19 +247,6 @@ 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)}. - * <p> - * {@inheritDoc} - */ - @Override - protected <T extends UI> T createUIInstance(WrappedRequest request, - Class<T> uiClass) { - return uiClass.cast(getUIInstance(request)); - } - private UI getUIInstance(WrappedRequest request) { String pathInfo = request.getRequestPathInfo(); String name = null; @@ -261,19 +285,6 @@ 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)}. - * - * <p> - * {@inheritDoc} - */ - @Override - public Class<? extends UI> getUIClass(WrappedRequest request) { - return getUIInstance(request).getClass(); - } - - /** * Sets the application's theme. * <p> * Note that this theme can be overridden for a specific UI with @@ -302,18 +313,6 @@ public class Application implements Terminal.ErrorListener, Serializable { } /** - * This implementation returns the theme that has been set using - * {@link #setTheme(String)} - * <p> - * {@inheritDoc} - */ - @Override - public String getThemeForUI(WrappedRequest request, - Class<? extends UI> uiClass) { - return theme; - } - - /** * <p> * Gets a UI by name. Returns <code>null</code> if the application is * not running or it does not contain a window corresponding to the @@ -1601,23 +1600,8 @@ public class Application implements Terminal.ErrorListener, Serializable { * @since 7.0 */ public Class<? extends UI> 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<? extends UI> uiClass = provider.getUIClass(this, request); - - if (uiClass != null) { - return uiClass; - } - } - - throw new RuntimeException( - "No UI provider returned an UI class for request"); + UIProvider uiProvider = getUiProvider(request, null); + return uiProvider.getUIClass(this, request); } /** @@ -1639,6 +1623,59 @@ public class Application implements Terminal.ErrorListener, Serializable { */ protected <T extends UI> T createUIInstance(WrappedRequest request, Class<T> uiClass) { + UIProvider uiProvider = getUiProvider(request, uiClass); + return uiClass.cast(uiProvider.createInstance(this, uiClass, request)); + } + + /** + * Gets the {@link UIProvider} that should be used for a request. The + * selection can further be restricted by also requiring the UI provider to + * support a specific UI class. + * + * @see UIProvider + * @see #addUIProvider(UIProvider) + * + * @param request + * the request for which to get an UI provider + * @param uiClass + * the UI class for which a provider is required, or + * <code>null</code> to use the first UI provider supporting the + * request. + * @return an UI provider supporting the request (and the UI class if + * provided). + * + * @since 7.0.0 + */ + public UIProvider getUiProvider(WrappedRequest request, Class<?> uiClass) { + UIProvider provider = (UIProvider) request + .getAttribute(UIProvider.class.getName()); + if (provider != null) { + // Cached provider found, verify that it's a sensible selection + Class<? extends UI> providerClass = provider.getUIClass(this, + request); + if (uiClass == null && providerClass != null) { + // Use it if it gives any answer if no specific class is + // required + return provider; + } else if (uiClass == providerClass) { + // Use it if it gives the expected UI class + return provider; + } else { + // Don't keep it cached if it doesn't match the expectations + request.setAttribute(UIProvider.class.getName(), null); + } + } + + // Iterate all current providers if no matching cached provider found + provider = doGetUiProvider(request, uiClass); + + // Cache the found provider + request.setAttribute(UIProvider.class.getName(), provider); + + return provider; + } + + private UIProvider doGetUiProvider(WrappedRequest request, Class<?> uiClass) { int providersSize = uiProviders.size(); if (providersSize == 0) { throw new IllegalStateException("There are no UI providers"); @@ -1649,108 +1686,25 @@ public class Application implements Terminal.ErrorListener, Serializable { Class<? extends UI> providerClass = provider.getUIClass(this, request); + // If we found something if (providerClass != null) { - if (providerClass != uiClass) { + if (uiClass == null) { + // Not looking for anything particular -> anything is ok + return provider; + } else if (providerClass == uiClass) { + // Looking for a specific provider -> only use if matching + return provider; + } else { 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; + // Continue looking } - return uiClass.cast(provider.createInstance(this, uiClass, - request)); } } - throw new RuntimeException( - "No UI provider created an UI instance for request"); - } - - /** - * Finds the theme to use for a specific UI. If no specific theme is - * required, <code>null</code> is returned. - * - * TODO Tell what the default implementation does once it does something. - * - * @param uI - * the UI to get a theme for - * @return the name of the theme, or <code>null</code> if the default theme - * should be used - * - * @since 7.0 - */ - public String getThemeForUI(WrappedRequest request, - Class<? extends UI> uiClass) { - Theme uiTheme = getAnnotationFor(uiClass, Theme.class); - if (uiTheme != null) { - return uiTheme.value(); - } else { - return null; - } - } - - /** - * Finds the widgetset to use for a specific UI. If no specific widgetset is - * required, <code>null</code> is returned. - * <p> - * The default implementation uses the @{@link Widgetset} annotation if it's - * defined for the UI class. - * - * @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 <code>null</code> if the default - * widgetset should be used - * - * @since 7.0 - */ - public String getWidgetsetForUI(WrappedRequest request, - Class<? extends UI> uiClass) { - Widgetset uiWidgetset = getAnnotationFor(uiClass, Widgetset.class); - if (uiWidgetset != null) { - return uiWidgetset.value(); - } else { - return null; - } - } - - /** - * Helper to get an annotation for a class. If the annotation is not present - * on the target class, it's superclasses and implemented interfaces are - * also searched for the annotation. - * - * @param type - * the target class from which the annotation should be found - * @param annotationType - * the annotation type to look for - * @return an annotation of the given type, or <code>null</code> if the - * annotation is not present on the class - */ - private static <T extends Annotation> T getAnnotationFor(Class<?> type, - Class<T> annotationType) { - // Find from the class hierarchy - Class<?> currentType = type; - while (currentType != Object.class) { - T annotation = currentType.getAnnotation(annotationType); - if (annotation != null) { - return annotation; - } else { - currentType = currentType.getSuperclass(); - } - } - - // Find from an implemented interface - for (Class<?> iface : type.getInterfaces()) { - T annotation = iface.getAnnotation(annotationType); - if (annotation != null) { - return annotation; - } - } - - return null; + throw new RuntimeException("No UI provider found for request"); } /** @@ -1999,7 +1953,7 @@ public class Application implements Terminal.ErrorListener, Serializable { ui.doInit(request, uiId.intValue()); - if (isUiPreserved(request, uiClass)) { + if (getUiProvider(request, uiClass).isUiPreserved(request, uiClass)) { // Remember this UI String windowName = request.getBrowserDetails().getWindowName(); if (windowName == null) { @@ -2035,25 +1989,6 @@ public class Application implements Terminal.ErrorListener, Serializable { } /** - * 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 <code>true</code>if the same UI instance should be reused e.g. - * when the browser window is refreshed. - */ - public boolean isUiPreserved(WrappedRequest request, - Class<? extends UI> uiClass) { - PreserveOnRefresh preserveOnRefresh = getAnnotationFor(uiClass, - PreserveOnRefresh.class); - return preserveOnRefresh != null; - } - - /** * Gets all the uIs of this application. This includes uIs that have been * requested but not yet initialized. Please note, that uIs are not * automatically removed e.g. if the browser window is closed and that there @@ -2270,13 +2205,4 @@ public class Application implements Terminal.ErrorListener, Serializable { return globalResourceHandler; } - public String getPageTitleForUI(WrappedRequest request, - Class<? extends UI> uiClass) { - Title titleAnnotation = getAnnotationFor(uiClass, Title.class); - if (titleAnnotation == null) { - return null; - } else { - return titleAnnotation.value(); - } - } } diff --git a/server/src/com/vaadin/server/AbstractUIProvider.java b/server/src/com/vaadin/server/AbstractUIProvider.java index 59ce31891d..49f8e3ec77 100644 --- a/server/src/com/vaadin/server/AbstractUIProvider.java +++ b/server/src/com/vaadin/server/AbstractUIProvider.java @@ -16,7 +16,13 @@ package com.vaadin.server; +import java.lang.annotation.Annotation; + import com.vaadin.Application; +import com.vaadin.annotations.PreserveOnRefresh; +import com.vaadin.annotations.Theme; +import com.vaadin.annotations.Title; +import com.vaadin.annotations.Widgetset; import com.vaadin.ui.UI; public abstract class AbstractUIProvider implements UIProvider { @@ -32,4 +38,81 @@ public abstract class AbstractUIProvider implements UIProvider { throw new RuntimeException("Could not access root class", e); } } + + /** + * Helper to get an annotation for a class. If the annotation is not present + * on the target class, it's superclasses and implemented interfaces are + * also searched for the annotation. + * + * @param type + * the target class from which the annotation should be found + * @param annotationType + * the annotation type to look for + * @return an annotation of the given type, or <code>null</code> if the + * annotation is not present on the class + */ + protected static <T extends Annotation> T getAnnotationFor(Class<?> type, + Class<T> annotationType) { + // Find from the class hierarchy + Class<?> currentType = type; + while (currentType != Object.class) { + T annotation = currentType.getAnnotation(annotationType); + if (annotation != null) { + return annotation; + } else { + currentType = currentType.getSuperclass(); + } + } + + // Find from an implemented interface + for (Class<?> iface : type.getInterfaces()) { + T annotation = iface.getAnnotation(annotationType); + if (annotation != null) { + return annotation; + } + } + + return null; + } + + @Override + public String getThemeForUI(WrappedRequest request, + Class<? extends UI> uiClass) { + Theme uiTheme = getAnnotationFor(uiClass, Theme.class); + if (uiTheme != null) { + return uiTheme.value(); + } else { + return null; + } + } + + @Override + public String getWidgetsetForUI(WrappedRequest request, + Class<? extends UI> uiClass) { + Widgetset uiWidgetset = getAnnotationFor(uiClass, Widgetset.class); + if (uiWidgetset != null) { + return uiWidgetset.value(); + } else { + return null; + } + } + + @Override + public boolean isUiPreserved(WrappedRequest request, + Class<? extends UI> uiClass) { + PreserveOnRefresh preserveOnRefresh = getAnnotationFor(uiClass, + PreserveOnRefresh.class); + return preserveOnRefresh != null; + } + + @Override + public String getPageTitleForUI(WrappedRequest request, + Class<? extends UI> uiClass) { + Title titleAnnotation = getAnnotationFor(uiClass, Title.class); + if (titleAnnotation == null) { + return null; + } else { + return titleAnnotation.value(); + } + } } diff --git a/server/src/com/vaadin/server/BootstrapHandler.java b/server/src/com/vaadin/server/BootstrapHandler.java index a1438312b6..4d200b5063 100644 --- a/server/src/com/vaadin/server/BootstrapHandler.java +++ b/server/src/com/vaadin/server/BootstrapHandler.java @@ -218,8 +218,9 @@ public abstract class BootstrapHandler implements RequestHandler { head.appendElement("meta").attr("http-equiv", "X-UA-Compatible") .attr("content", "chrome=1"); - String title = context.getApplication().getPageTitleForUI( - context.getRequest(), context.getUIClass()); + String title = context.getApplication() + .getUiProvider(context.getRequest(), context.getUIClass()) + .getPageTitleForUI(context.getRequest(), context.getUIClass()); if (title != null) { head.appendElement("title").appendText(title); } @@ -270,8 +271,9 @@ public abstract class BootstrapHandler implements RequestHandler { public String getWidgetsetForUI(BootstrapContext context) { WrappedRequest request = context.getRequest(); - String widgetset = context.getApplication().getWidgetsetForUI( - context.getRequest(), context.getUIClass()); + String widgetset = context.getApplication() + .getUiProvider(context.getRequest(), context.getUIClass()) + .getWidgetsetForUI(context.getRequest(), context.getUIClass()); if (widgetset == null) { widgetset = request.getDeploymentConfiguration() .getConfiguredWidgetset(request); @@ -497,8 +499,9 @@ public abstract class BootstrapHandler implements RequestHandler { * @return */ public String getThemeName(BootstrapContext context) { - return context.getApplication().getThemeForUI(context.getRequest(), - context.getUIClass()); + return context.getApplication() + .getUiProvider(context.getRequest(), context.getUIClass()) + .getThemeForUI(context.getRequest(), context.getUIClass()); } /** diff --git a/server/src/com/vaadin/server/UIProvider.java b/server/src/com/vaadin/server/UIProvider.java index ea73a705ea..60b79cdbb9 100644 --- a/server/src/com/vaadin/server/UIProvider.java +++ b/server/src/com/vaadin/server/UIProvider.java @@ -17,6 +17,7 @@ package com.vaadin.server; import com.vaadin.Application; +import com.vaadin.annotations.Widgetset; import com.vaadin.ui.UI; public interface UIProvider { @@ -25,4 +26,56 @@ public interface UIProvider { public UI createInstance(Application application, Class<? extends UI> type, WrappedRequest request); + + public String getPageTitleForUI(WrappedRequest request, + Class<? extends UI> uiClass); + + /** + * 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 <code>true</code>if the same UI instance should be reused e.g. + * when the browser window is refreshed. + */ + public boolean isUiPreserved(WrappedRequest request, + Class<? extends UI> uiClass); + + /** + * Finds the widgetset to use for a specific UI. If no specific widgetset is + * required, <code>null</code> is returned. + * <p> + * The default implementation uses the @{@link Widgetset} annotation if it's + * defined for the UI class. + * + * @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 <code>null</code> if the default + * widgetset should be used + * + */ + public String getWidgetsetForUI(WrappedRequest request, + Class<? extends UI> uiClass); + + /** + * Finds the theme to use for a specific UI. If no specific theme is + * required, <code>null</code> is returned. + * + * TODO Tell what the default implementation does once it does something. + * + * @param uI + * the UI to get a theme for + * @return the name of the theme, or <code>null</code> if the default theme + * should be used + * + */ + public String getThemeForUI(WrappedRequest request, + Class<? extends UI> uiClass); + } diff --git a/server/src/com/vaadin/ui/UI.java b/server/src/com/vaadin/ui/UI.java index ee4cb9fd2c..7ae4e6bda3 100644 --- a/server/src/com/vaadin/ui/UI.java +++ b/server/src/com/vaadin/ui/UI.java @@ -940,7 +940,8 @@ public abstract class UI extends AbstractComponentContainer implements throw new IllegalStateException("UI id has already been defined"); } this.uiId = uiId; - theme = getApplication().getThemeForUI(request, getClass()); + theme = getApplication().getUiProvider(request, getClass()) + .getThemeForUI(request, getClass()); getPage().init(request); |