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) {
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;
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;
* 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) {
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>
* <p>
* {@inheritDoc}
*/
-
@Override
- public String getThemeForUI(UI uI) {
+ public String getThemeForUI(WrappedRequest request,
+ Class<? extends UI> uiClass) {
return theme;
}
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;
}
/**
- * 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");
}
/**
*
* @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 {
/**
* 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 {
*/
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
* @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;
&& 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;
}
/**
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;
}
/**
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;
+ }
}
+++ /dev/null
-/*
- * 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
-}
--- /dev/null
+/*
+ * 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 {
+
+}
--- /dev/null
+/*
+ * 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();
+}
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;
// 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
throws PortletException {
try {
final Application application = getApplicationClass().newInstance();
- application.setUiPreserved(true);
return application;
} catch (final IllegalAccessException e) {
throw new PortletException("getNewApplication failed", e);
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;
}
private String getTheme(UI uI) {
- String themeName = uI.getApplication().getThemeForUI(uI);
+ String themeName = uI.getTheme();
String requestThemeName = getRequestTheme();
if (requestThemeName != null) {
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
// 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();
import org.jsoup.nodes.Node;
import com.vaadin.Application;
+import com.vaadin.ui.UI;
/**
* A representation of a bootstrap fragment being generated. The bootstrap
* 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
* @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;
}
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 {
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;
}
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
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) {
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;}");
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;
}
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);
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()));
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;
}
* @return
*/
public String getThemeName(BootstrapContext context) {
- return context.getApplication().getThemeForUI(context.getUI());
+ return context.getApplication().getThemeForUI(context.getRequest(),
+ context.getUIClass());
}
/**
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;
-
}
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
* 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
* @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;
}
import java.util.EventObject;
import com.vaadin.Application;
-import com.vaadin.UIRequiresMoreInformationException;
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.
* @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;
}
/**
}
/**
- * 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();
- }
}
import javax.servlet.ServletContext;
import com.vaadin.Application;
-import com.vaadin.external.json.JSONException;
import com.vaadin.ui.UI;
/**
}
return themeName;
}
-
- @Override
- protected String getInitialUIDL(WrappedRequest request, UI uI)
- throws PaintException, JSONException {
- return CommunicationManager.this.getInitialUIDL(request, uI);
- }
};
}
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);
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,
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);
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;
* 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
* </p>
*
* @see #init(WrappedRequest)
- * @see Application#getUI(WrappedRequest)
+ * @see Application#createUI(WrappedRequest)
*
* @since 7.0
*/
* window in Vaadin 6 with {@link com.vaadin.Application.LegacyApplication}
*/
@Deprecated
- @EagerInit
public static class LegacyWindow extends UI {
private String name;
}
}
- /**
- * 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
* 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
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
*
* @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
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;
+ }
}
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;
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() {
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));
private Application createStubApplication() {
return new Application() {
- {
- addUIProvider(new DefaultUIProvider());
- }
-
@Override
public String getProperty(String name) {
if (name.equals(UI_PARAMETER)) {
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);
- }
};
}
}
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;
@Override
public Class<? extends UI> getUIClass(
- Application application, WrappedRequest request)
- throws UIRequiresMoreInformationException {
+ Application application, WrappedRequest request) {
return (Class<? extends UI>) classToRun;
}
});
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;
import com.vaadin.ui.UI;
public class RefreshStatePreserve extends AbstractTestApplication {
+ @PreserveOnRefresh
public static class RefreshStateUI extends UI {
@Override
public void init(WrappedRequest request) {
@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;
}
});
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;
@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
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;
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();
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;
}
@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();
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;
addUIProvider(new AbstractUIProvider() {
@Override
public Class<? extends UI> getUIClass(Application application,
- WrappedRequest request)
- throws UIRequiresMoreInformationException {
+ WrappedRequest request) {
return TabUI.class;
}
});
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
* @author Vaadin Ltd
* @since 7.0.0
*/
+@PreserveOnRefresh
public class CreatingPreserveState extends UI {
private static int windowCounter = 0;
TextField tf = new TextField("Window #" + (++windowCounter));
tf.setImmediate(true);
getContent().addComponent(tf);
- getApplication().setUiPreserved(true);
}
}
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;
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);
+ }
+ }
+ });
}
}
}
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;
}