Browse Source

Refactor UI bootstrap (#9443)

tags/7.0.0.beta1
Leif Åstrand 11 years ago
parent
commit
8679f49c5e
27 changed files with 440 additions and 481 deletions
  1. 2
    6
      WebContent/VAADIN/vaadinBootstrap.js
  2. 183
    158
      server/src/com/vaadin/Application.java
  3. 0
    37
      server/src/com/vaadin/UIRequiresMoreInformationException.java
  4. 28
    0
      server/src/com/vaadin/annotations/PreserveOnRefresh.java
  5. 38
    0
      server/src/com/vaadin/annotations/Title.java
  6. 1
    8
      server/src/com/vaadin/server/AbstractApplicationPortlet.java
  7. 8
    28
      server/src/com/vaadin/server/AbstractCommunicationManager.java
  8. 7
    6
      server/src/com/vaadin/server/BootstrapFragmentResponse.java
  9. 32
    75
      server/src/com/vaadin/server/BootstrapHandler.java
  10. 8
    6
      server/src/com/vaadin/server/BootstrapPageResponse.java
  11. 10
    30
      server/src/com/vaadin/server/BootstrapResponse.java
  12. 0
    7
      server/src/com/vaadin/server/CommunicationManager.java
  13. 1
    2
      server/src/com/vaadin/server/DefaultUIProvider.java
  14. 0
    7
      server/src/com/vaadin/server/PortletCommunicationManager.java
  15. 1
    2
      server/src/com/vaadin/server/UIProvider.java
  16. 2
    7
      server/src/com/vaadin/server/WrappedRequest.java
  17. 23
    27
      server/src/com/vaadin/ui/UI.java
  18. 10
    18
      server/tests/src/com/vaadin/tests/server/component/root/CustomUIClassLoader.java
  19. 1
    3
      uitest/src/com/vaadin/launcher/ApplicationRunnerServlet.java
  20. 3
    4
      uitest/src/com/vaadin/tests/application/RefreshStatePreserve.java
  21. 13
    6
      uitest/src/com/vaadin/tests/application/ThreadLocalInstances.java
  22. 10
    3
      uitest/src/com/vaadin/tests/components/loginform/LoginFormWithMultipleWindows.java
  23. 27
    17
      uitest/src/com/vaadin/tests/components/ui/LazyInitUIs.java
  24. 1
    3
      uitest/src/com/vaadin/tests/components/ui/UIsInMultipleTabs.java
  25. 3
    2
      uitest/src/com/vaadin/tests/minitutorials/v7a1/CreatingPreserveState.java
  26. 26
    16
      uitest/src/com/vaadin/tests/minitutorials/v7a1/DifferentFeaturesForDifferentClients.java
  27. 2
    3
      uitest/src/com/vaadin/tests/vaadincontext/TestAddonContextListener.java

+ 2
- 6
WebContent/VAADIN/vaadinBootstrap.js View File

@@ -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) {

+ 183
- 158
server/src/com/vaadin/Application.java View File

@@ -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)}.
*
* <p>
* {@inheritDoc}
*
* @see #getWindow(String)
* @see Application#getUI(WrappedRequest)
*/

@Override
public UI.LegacyWindow getUI(WrappedRequest request) {
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;
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)}.
*
* <p>
* {@inheritDoc}
*/
@Override
public Class<? extends UI> getUIClass(WrappedRequest request) {
return getUIInstance(request).getClass();
}

/**
* Sets the application's theme.
* <p>
@@ -269,9 +283,9 @@ public class Application implements Terminal.ErrorListener, Serializable {
* <p>
* {@inheritDoc}
*/

@Override
public String getThemeForUI(UI uI) {
public String getThemeForUI(WrappedRequest request,
Class<? extends UI> 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.
* <p>
* TODO Investigate whether this might be derived from the different states
* in getUIForRrequest.
* </p>
*/
private Set<Integer> initedUIs = new HashSet<Integer>();

private List<UIProvider> uiProviders = new LinkedList<UIProvider>();

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.
* <p>
* 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.
* </p>
*
* logic for choosing what kind of UI to use.
* <p>
* 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.
* </p>
* 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 <code>null</code>, the returned {@link ClassLoader} is used for
* loading the UI class. Otherwise the {@link ClassLoader} used to load this
* class is used.
*
* <p>
* 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.
* </p>
*
* @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<? 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 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.
* <p>
* 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.
* </p>
*
* @param request
* @param uiClass
* @return
*/
protected <T extends UI> T createUIInstance(WrappedRequest request,
Class<T> 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<? extends UI> 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<? extends UI> 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, <code>null</code> is returned.
* <p>
* 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 <code>null</code> 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<? extends UI> 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<Application> currentApplication = new ThreadLocal<Application>();

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<? extends UI> 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<? extends UI> 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.
* <p>
* 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.
* </p>
*
* @param uiPreserved
* <code>true</code>if 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 <code>true</code>if 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 <code>true</code> of the initialization is pending,
* <code>false</code> 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<? extends UI> 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<? extends UI> uiClass) {
Title titleAnnotation = getAnnotationFor(uiClass, Title.class);
if (titleAnnotation == null) {
return null;
} else {
return titleAnnotation.value();
}
}

public boolean isEagerInit(WrappedRequest request,
Class<? extends UI> uiClass) {
EagerInit eagerInit = getAnnotationFor(uiClass, EagerInit.class);
return eagerInit != null;
}
}

+ 0
- 37
server/src/com/vaadin/UIRequiresMoreInformationException.java View File

@@ -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
}

+ 28
- 0
server/src/com/vaadin/annotations/PreserveOnRefresh.java View File

@@ -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 {

}

+ 38
- 0
server/src/com/vaadin/annotations/Title.java View File

@@ -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();
}

+ 1
- 8
server/src/com/vaadin/server/AbstractApplicationPortlet.java View File

@@ -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);

+ 8
- 28
server/src/com/vaadin/server/AbstractCommunicationManager.java View File

@@ -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();

+ 7
- 6
server/src/com/vaadin/server/BootstrapFragmentResponse.java View File

@@ -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<Node> fragmentNodes) {
super(handler, request, application, uiId);
WrappedRequest request, Application application,
Class<? extends UI> uiClass, List<Node> fragmentNodes) {
super(handler, request, application, uiClass);
this.fragmentNodes = fragmentNodes;
}


+ 32
- 75
server/src/com/vaadin/server/BootstrapHandler.java View File

@@ -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<? extends UI> 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<? extends UI> 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<String, Object> headers = new LinkedHashMap<String, Object>();
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<Node> 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<? extends UI> uiClass) {
BootstrapContext context = new BootstrapContext(response,
new BootstrapFragmentResponse(this, request, application, uiId,
new ArrayList<Node>()));
new BootstrapFragmentResponse(this, request, application,
uiClass, new ArrayList<Node>()));
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<String, String[]> 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<String, String[]> 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;

}

+ 8
- 6
server/src/com/vaadin/server/BootstrapPageResponse.java View File

@@ -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<String, Object> headers) {
super(handler, request, application, uiId);
WrappedRequest request, Application application,
Class<? extends UI> uiClass, Document document,
Map<String, Object> headers) {
super(handler, request, application, uiClass);
this.headers = headers;
this.document = document;
}

+ 10
- 30
server/src/com/vaadin/server/BootstrapResponse.java View File

@@ -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<? extends UI> 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<? extends UI> 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<? extends UI> 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 <code>null</code> 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
* <code>null</code> if all required information is not yet
* available.
*/
public UI getUI() {
return UI.getCurrent();
}
}

+ 0
- 7
server/src/com/vaadin/server/CommunicationManager.java View File

@@ -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);
}
};
}


+ 1
- 2
server/src/com/vaadin/server/DefaultUIProvider.java View File

@@ -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<? extends UI> getUIClass(Application application,
WrappedRequest request) throws UIRequiresMoreInformationException {
WrappedRequest request) {
Object uiClassNameObj = application
.getProperty(Application.UI_PARAMETER);


+ 0
- 7
server/src/com/vaadin/server/PortletCommunicationManager.java View File

@@ -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,

+ 1
- 2
server/src/com/vaadin/server/UIProvider.java View File

@@ -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<? extends UI> getUIClass(Application application,
WrappedRequest request) throws UIRequiresMoreInformationException;
WrappedRequest request);

public UI instantiateUI(Application application, Class<? extends UI> type,
WrappedRequest request);

+ 2
- 7
server/src/com/vaadin/server/WrappedRequest.java View File

@@ -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 <code>null</code> if details are not
* available

+ 23
- 27
server/src/com/vaadin/ui/UI.java View File

@@ -85,7 +85,7 @@ import com.vaadin.tools.ReflectTools;
* </p>
*
* @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.
* <p>
* This method is mainly intended for internal use by the framework.
* </p>
*
* @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;
}
}

+ 10
- 18
server/tests/src/com/vaadin/tests/server/component/root/CustomUIClassLoader.java View File

@@ -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<? extends UI> 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<? extends UI> 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);
}
};
}
}

+ 1
- 3
uitest/src/com/vaadin/launcher/ApplicationRunnerServlet.java View File

@@ -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<? extends UI> getUIClass(
Application application, WrappedRequest request)
throws UIRequiresMoreInformationException {
Application application, WrappedRequest request) {
return (Class<? extends UI>) classToRun;
}
});

+ 3
- 4
uitest/src/com/vaadin/tests/application/RefreshStatePreserve.java View File

@@ -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<? extends UI> getUIClass(Application application,
WrappedRequest request)
throws UIRequiresMoreInformationException {
WrappedRequest request) {
return RefreshStateUI.class;
}
});

+ 13
- 6
uitest/src/com/vaadin/tests/application/ThreadLocalInstances.java View File

@@ -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<? extends UI> type, WrappedRequest request) {
return mainWindow;
}

@Override
protected UI getUI(WrappedRequest request)
throws UIRequiresMoreInformationException {
return mainWindow;
@Override
public Class<? extends UI> getUIClass(Application application,
WrappedRequest request) {
return mainWindow.getClass();
}
});
}

@Override

+ 10
- 3
uitest/src/com/vaadin/tests/components/loginform/LoginFormWithMultipleWindows.java View File

@@ -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<? extends UI> getUIClass(Application application,
WrappedRequest request) {
return LoginFormWindow.class;
}
});
}

public class LoginFormWindow extends LegacyWindow {
public static class LoginFormWindow extends LegacyWindow {
public LoginFormWindow() {
super();


+ 27
- 17
uitest/src/com/vaadin/tests/components/ui/LazyInitUIs.java View File

@@ -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<? extends UI> type, WrappedRequest request) {
return getUI(request);
}

@Override
public Class<? extends UI> 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();

+ 1
- 3
uitest/src/com/vaadin/tests/components/ui/UIsInMultipleTabs.java View File

@@ -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<? extends UI> getUIClass(Application application,
WrappedRequest request)
throws UIRequiresMoreInformationException {
WrappedRequest request) {
return TabUI.class;
}
});

+ 3
- 2
uitest/src/com/vaadin/tests/minitutorials/v7a1/CreatingPreserveState.java View File

@@ -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);
}

}

+ 26
- 16
uitest/src/com/vaadin/tests/minitutorials/v7a1/DifferentFeaturesForDifferentClients.java View File

@@ -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<? extends UI> 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<? extends UI> type, WrappedRequest request) {
try {
return type.newInstance();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
});
}
}


+ 2
- 3
uitest/src/com/vaadin/tests/vaadincontext/TestAddonContextListener.java View File

@@ -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<? extends UI> uiClass = response.getUiClass();
boolean shouldModify = uiClass == BootstrapModifyUI.class;
return shouldModify;
}


Loading…
Cancel
Save