/*
* Copyright 2000-2016 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.server;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.Serializable;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.logging.Logger;
import javax.servlet.http.HttpServletResponse;
import org.jsoup.nodes.DataNode;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.DocumentType;
import org.jsoup.nodes.Element;
import org.jsoup.nodes.Node;
import org.jsoup.parser.Tag;
import com.vaadin.annotations.Viewport;
import com.vaadin.annotations.ViewportGeneratorClass;
import com.vaadin.server.DependencyFilter.FilterContext;
import com.vaadin.server.communication.AtmospherePushConnection;
import com.vaadin.shared.ApplicationConstants;
import com.vaadin.shared.VaadinUriResolver;
import com.vaadin.shared.Version;
import com.vaadin.shared.communication.PushMode;
import com.vaadin.ui.Dependency;
import com.vaadin.ui.Dependency.Type;
import com.vaadin.ui.UI;
import elemental.json.Json;
import elemental.json.JsonException;
import elemental.json.JsonObject;
import elemental.json.impl.JsonUtil;
/**
* Handles the initial request to start the application.
*
* @author Vaadin Ltd
* @since 7.0.0
*
* @deprecated As of 7.0. Will likely change or be removed in a future version
*/
@Deprecated
public abstract class BootstrapHandler extends SynchronizedRequestHandler {
/**
* Parameter that is added to the UI init request if the session has already
* been restarted when generating the bootstrap HTML and ?restartApplication
* should thus be ignored when handling the UI init request.
*/
public static final String IGNORE_RESTART_PARAM = "ignoreRestart";
/**
* Provides context information for the bootstrap process.
*/
protected class BootstrapContext implements Serializable {
private final VaadinResponse response;
private final BootstrapFragmentResponse bootstrapResponse;
private String themeName;
private String appId;
private PushMode pushMode;
private JsonObject applicationParameters;
private BootstrapUriResolver uriResolver;
private WidgetsetInfo widgetsetInfo;
/**
* Creates a new context instance using the given Vaadin/HTTP response
* and bootstrap response.
*
* @param response
* the response object
* @param bootstrapResponse
* the bootstrap response object
*/
public BootstrapContext(VaadinResponse response,
BootstrapFragmentResponse bootstrapResponse) {
this.response = response;
this.bootstrapResponse = bootstrapResponse;
}
/**
* Gets the Vaadin/HTTP response.
*
* @return the Vaadin/HTTP response
*/
public VaadinResponse getResponse() {
return response;
}
/**
* Gets the Vaadin/HTTP request.
*
* @return the Vaadin/HTTP request
*/
public VaadinRequest getRequest() {
return bootstrapResponse.getRequest();
}
/**
* Gets the Vaadin session.
*
* @return the Vaadin session
*/
public VaadinSession getSession() {
return bootstrapResponse.getSession();
}
/**
* Gets the UI class which will be used.
*
* @return the UI class
*/
public Class<? extends UI> getUIClass() {
return bootstrapResponse.getUiClass();
}
/**
* Gets information about the widgetset to use.
*
* @return the widgetset which will be loaded
*/
public WidgetsetInfo getWidgetsetInfo() {
if (widgetsetInfo == null) {
widgetsetInfo = getWidgetsetForUI(this);
}
return widgetsetInfo;
}
/**
* @return returns the name of the widgetset to use
* @deprecated use {@link #getWidgetsetInfo()} instead
*/
@Deprecated
public String getWidgetsetName() {
return getWidgetsetInfo().getWidgetsetName();
}
/**
* Gets the name of the theme to use.
*
* @return the name of the theme, with special characters escaped or
* removed
*/
public String getThemeName() {
if (themeName == null) {
themeName = findAndEscapeThemeName(this);
}
return themeName;
}
/**
* Gets the push mode to use.
*
* @return the desired push mode
*/
public PushMode getPushMode() {
if (pushMode == null) {
UICreateEvent event = new UICreateEvent(getRequest(),
getUIClass());
pushMode = getBootstrapResponse().getUIProvider()
.getPushMode(event);
if (pushMode == null) {
pushMode = getRequest().getService()
.getDeploymentConfiguration().getPushMode();
}
if (pushMode.isEnabled()
&& !getRequest().getService().ensurePushAvailable()) {
/*
* Fall back if not supported (ensurePushAvailable will log
* information to the developer the first time this happens)
*/
pushMode = PushMode.DISABLED;
}
}
return pushMode;
}
/**
* Gets the application id.
*
* The application id is defined by
* {@link VaadinService#getMainDivId(VaadinSession, VaadinRequest, Class)}
*
* @return the application id
*/
public String getAppId() {
if (appId == null) {
appId = getRequest().getService().getMainDivId(getSession(),
getRequest(), getUIClass());
}
return appId;
}
/**
* Gets the bootstrap response object.
*
* @return the bootstrap response object
*/
public BootstrapFragmentResponse getBootstrapResponse() {
return bootstrapResponse;
}
/**
* Gets the application parameters specified by the BootstrapHandler.
*
* @return the application parameters which will be written on the page
*/
public JsonObject getApplicationParameters() {
if (applicationParameters == null) {
applicationParameters = BootstrapHandler.this
.getApplicationParameters(this);
}
return applicationParameters;
}
/**
* Gets the URI resolver to use for bootstrap resources.
*
* @return the URI resolver
* @since 8.1
*/
public BootstrapUriResolver getUriResolver() {
if (uriResolver == null) {
uriResolver = new BootstrapUriResolver(this);
}
return uriResolver;
}
}
/**
* The URI resolver used in the bootstrap process.
*
* @since 8.1
*/
protected static class BootstrapUriResolver extends VaadinUriResolver {
private final BootstrapContext context;
private String frontendUrl;
/**
* Creates a new bootstrap resolver based on the given bootstrap
* context.
*
* @param bootstrapContext
* the bootstrap context
*/
public BootstrapUriResolver(BootstrapContext bootstrapContext) {
context = bootstrapContext;
}
@Override
protected String getVaadinDirUrl() {
return context.getApplicationParameters()
.getString(ApplicationConstants.VAADIN_DIR_URL);
}
@Override
protected String getThemeUri() {
return getVaadinDirUrl() + "themes/" + context.getThemeName();
}
@Override
protected String getServiceUrlParameterName() {
return getConfigOrNull(
ApplicationConstants.SERVICE_URL_PARAMETER_NAME);
}
@Override
protected String getServiceUrl() {
String serviceUrl = getConfigOrNull(
ApplicationConstants.SERVICE_URL);
if (serviceUrl == null) {
return "./";
} else if (!serviceUrl.endsWith("/")) {
serviceUrl += "/";
}
return serviceUrl;
}
private String getConfigOrNull(String name) {
JsonObject parameters = context.getApplicationParameters();
if (parameters.hasKey(name)) {
return parameters.getString(name);
} else {
return null;
}
}
@Override
protected String encodeQueryStringParameterValue(String queryString) {
String encodedString = null;
try {
encodedString = URLEncoder.encode(queryString, "UTF-8");
} catch (UnsupportedEncodingException e) {
// should never happen
throw new RuntimeException("Could not find UTF-8", e);
}
return encodedString;
}
@Override
protected String getContextRootUrl() {
String root = context.getApplicationParameters()
.getString(ApplicationConstants.CONTEXT_ROOT_URL);
assert root.endsWith("/");
return root;
}
@Override
protected String getFrontendUrl() {
if (frontendUrl == null) {
frontendUrl = resolveFrontendUrl(context.getSession());
}
return frontendUrl;
}
}
/**
* Resolves the URL to use for the {@literal frontend://} protocol.
*
* @param session
* the session of the user to resolve the protocol for
* @return the URL that frontend:// resolves to, possibly using another
* internal protocol
* @since 8.1
*/
public static String resolveFrontendUrl(VaadinSession session) {
DeploymentConfiguration configuration = session.getConfiguration();
String frontendUrl;
if (session.getBrowser().isEs6Supported()) {
frontendUrl = configuration.getApplicationOrSystemProperty(
ApplicationConstants.FRONTEND_URL_ES6,
ApplicationConstants.FRONTEND_URL_ES6_DEFAULT_VALUE);
} else {
frontendUrl = configuration.getApplicationOrSystemProperty(
ApplicationConstants.FRONTEND_URL_ES5,
ApplicationConstants.FRONTEND_URL_ES5_DEFAULT_VALUE);
}
if (!frontendUrl.endsWith("/")) {
frontendUrl += "/";
}
return frontendUrl;
}
@Override
protected boolean canHandleRequest(VaadinRequest request) {
// We do not want to handle /APP requests here, instead let it fall
// through and produce a 404
return !ServletPortletHelper.isAppRequest(request);
}
@Override
public boolean synchronizedHandleRequest(VaadinSession session,
VaadinRequest request, VaadinResponse response) throws IOException {
try {
List<UIProvider> uiProviders = session.getUIProviders();
UIClassSelectionEvent classSelectionEvent = new UIClassSelectionEvent(
request);
// Find UI provider and UI class
Class<? extends UI> uiClass = null;
UIProvider provider = null;
for (UIProvider p : uiProviders) {
uiClass = p.getUIClass(classSelectionEvent);
// If we found something
if (uiClass != null) {
provider = p;
break;
}
}
if (provider == null) {
// Can't generate bootstrap if no UI provider matches
return false;
}
BootstrapFragmentResponse bootstrapResponse = new BootstrapFragmentResponse(
this, request, session, uiClass, new ArrayList<>(),
provider);
BootstrapContext context = new BootstrapContext(response,
bootstrapResponse);
bootstrapResponse.setUriResolver(context.getUriResolver());
setupMainDiv(context);
BootstrapFragmentResponse fragmentResponse = context
.getBootstrapResponse();
session.modifyBootstrapResponse(fragmentResponse);
String html = getBootstrapHtml(context);
writeBootstrapPage(response, html);
} catch (JsonException e) {
writeError(response, e);
}
return true;
}
private String getBootstrapHtml(BootstrapContext context) {
VaadinRequest request = context.getRequest();
VaadinResponse response = context.getResponse();
VaadinService vaadinService = request.getService();
BootstrapFragmentResponse fragmentResponse = context
.getBootstrapResponse();
if (vaadinService.isStandalone(request)) {
Map<String, Object> headers = new LinkedHashMap<>();
Document document = Document.createShell("");
BootstrapPageResponse pageResponse = new BootstrapPageResponse(this,
request, context.getSession(), context.getUIClass(),
document, headers, fragmentResponse.getUIProvider());
pageResponse.setUriResolver(context.getUriResolver());
List<Node> fragmentNodes = fragmentResponse.getFragmentNodes();
Element body = document.body();
for (Node node : fragmentNodes) {
body.appendChild(node);
}
setupStandaloneDocument(context, pageResponse);
context.getSession().modifyBootstrapResponse(pageResponse);
sendBootstrapHeaders(response, headers);
return document.outerHtml();
} else {
StringBuilder sb = new StringBuilder();
for (Node node : fragmentResponse.getFragmentNodes()) {
if (sb.length() != 0) {
sb.append('\n');
}
sb.append(node.outerHtml());
}
return sb.toString();
}
}
private void sendBootstrapHeaders(VaadinResponse response,
Map<String, Object> headers) {
Set<Entry<String, Object>> entrySet = headers.entrySet();
for (Entry<String, Object> header : entrySet) {
Object value = header.getValue();
if (value instanceof String) {
response.setHeader(header.getKey(), (String) value);
} else if (value instanceof Long) {
response.setDateHeader(header.getKey(),
((Long) value).longValue());
} else {
throw new RuntimeException(
"Unsupported header value: " + value);
}
}
}
private void writeBootstrapPage(VaadinResponse response, String html)
throws IOException {
response.setContentType(
ApplicationConstants.CONTENT_TYPE_TEXT_HTML_UTF_8);
try (BufferedWriter writer = new BufferedWriter(
new OutputStreamWriter(response.getOutputStream(), "UTF-8"))) {
writer.append(html);
}
}
private void setupStandaloneDocument(BootstrapContext context,
BootstrapPageResponse response) {
response.setHeader("Cache-Control", "no-cache");
response.setHeader("Pragma", "no-cache");
response.setDateHeader("Expires", 0);
Document document = response.getDocument();
DocumentType doctype = new DocumentType("html", "", "",
document.baseUri());
document.child(0).before(doctype);
Element head = document.head();
head.appendElement("meta").attr("http-equiv", "Content-Type").attr(
"content", ApplicationConstants.CONTENT_TYPE_TEXT_HTML_UTF_8);
/*
* Enable Chrome Frame in all versions of IE if installed.
*/
head.appendElement("meta").attr("http-equiv", "X-UA-Compatible")
.attr("content", "IE=11;chrome=1");
Class<? extends UI> uiClass = context.getUIClass();
String viewportContent = null;
Viewport viewportAnnotation = uiClass.getAnnotation(Viewport.class);
ViewportGeneratorClass viewportGeneratorClassAnnotation = uiClass
.getAnnotation(ViewportGeneratorClass.class);
if (viewportAnnotation != null
&& viewportGeneratorClassAnnotation != null) {
throw new IllegalStateException(uiClass.getCanonicalName()
+ " cannot be annotated with both @"
+ Viewport.class.getSimpleName() + " and @"
+ ViewportGeneratorClass.class.getSimpleName());
}
if (viewportAnnotation != null) {
viewportContent = viewportAnnotation.value();
} else if (viewportGeneratorClassAnnotation != null) {
Class<? extends ViewportGenerator> viewportGeneratorClass = viewportGeneratorClassAnnotation
.value();
try {
viewportContent = viewportGeneratorClass.newInstance()
.getViewport(context.getRequest());
} catch (Exception e) {
throw new RuntimeException(
"Error processing viewport generator "
+ viewportGeneratorClass.getCanonicalName(),
e);
}
}
if (viewportContent != null) {
head.appendElement("meta").attr("name", "viewport").attr("content",
viewportContent);
}
String title = response.getUIProvider().getPageTitle(
new UICreateEvent(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;}");
// Add favicon links
String themeName = context.getThemeName();
if (themeName != null) {
String themeUri = getThemeUri(context, themeName);
head.appendElement("link").attr("rel", "shortcut icon")
.attr("type", "image/vnd.microsoft.icon")
.attr("href", themeUri + "/favicon.ico");
head.appendElement("link").attr("rel", "icon")
.attr("type", "image/vnd.microsoft.icon")
.attr("href", themeUri + "/favicon.ico");
}
Collection<? extends Dependency> deps = Dependency
.findAndFilterDependencies(Collections.singletonList(uiClass),
context.getSession().getCommunicationManager(),
new FilterContext(context.getSession()));
for (Dependency dependency : deps) {
Type type = dependency.getType();
String url = context.getUriResolver()
.resolveVaadinUri(dependency.getUrl());
if (type == Type.HTMLIMPORT) {
head.appendElement("link").attr("rel", "import").attr("href",
url);
} else if (type == Type.JAVASCRIPT) {
head.appendElement("script").attr("type", "text/javascript")
.attr("src", url);
} else if (type == Type.STYLESHEET) {
head.appendElement("link").attr("rel", "stylesheet")
.attr("type", "text/css").attr("href", url);
} else {
getLogger().severe("Ignoring unknown dependency type "
+ dependency.getType());
}
}
Element body = document.body();
body.attr("scroll", "auto");
body.addClass(ApplicationConstants.GENERATED_BODY_CLASSNAME);
}
private static Logger getLogger() {
return Logger.getLogger(BootstrapHandler.class.getName());
}
protected String getMainDivStyle(BootstrapContext context) {
return null;
}
public WidgetsetInfo getWidgetsetForUI(BootstrapContext context) {
VaadinRequest request = context.getRequest();
UICreateEvent event = new UICreateEvent(context.getRequest(),
context.getUIClass());
WidgetsetInfo widgetset = context.getBootstrapResponse().getUIProvider()
.getWidgetsetInfo(event);
if (widgetset == null) {
// TODO do we want to move WidgetsetInfoImpl elsewhere?
widgetset = new WidgetsetInfoImpl(
request.getService().getConfiguredWidgetset(request));
}
return widgetset;
}
/**
* Method to write the div element into which that actual Vaadin application
* is rendered.
* <p>
* Override this method if you want to add some custom html around around
* the div element into which the actual Vaadin application will be
* rendered.
*
* @param context
*
* @throws IOException
*/
private void setupMainDiv(BootstrapContext context) throws IOException {
String style = getMainDivStyle(context);
/*- Add classnames;
* .v-app
* .v-app-loading
*- Additionally added from javascript:
* <themeName, remove non-alphanum>
*/
List<Node> fragmentNodes = context.getBootstrapResponse()
.getFragmentNodes();
Element mainDiv = new Element(Tag.valueOf("div"), "");
mainDiv.attr("id", context.getAppId());
mainDiv.addClass("v-app");
mainDiv.addClass(context.getThemeName());
mainDiv.addClass(context.getUIClass().getSimpleName()
.toLowerCase(Locale.ENGLISH));
if (style != null && style.length() != 0) {
mainDiv.attr("style", style);
}
mainDiv.appendElement("div").addClass("v-app-loading");
mainDiv.appendElement("noscript").append(
"You have to enable javascript in your browser to use an application built with Vaadin.");
fragmentNodes.add(mainDiv);
VaadinRequest request = context.getRequest();
VaadinService vaadinService = request.getService();
String vaadinLocation = vaadinService.getStaticFileLocation(request)
+ "/VAADIN/";
// Parameter appended to JS to bypass caches after version upgrade.
String versionQueryParam = "?v=" + Version.getFullVersion();
if (context.getPushMode().isEnabled()) {
// Load client-side dependencies for push support
String pushJS = vaadinLocation;
if (context.getRequest().getService().getDeploymentConfiguration()
.isProductionMode()) {
pushJS += ApplicationConstants.VAADIN_PUSH_JS;
} else {
pushJS += ApplicationConstants.VAADIN_PUSH_DEBUG_JS;
}
pushJS += versionQueryParam;
fragmentNodes.add(new Element(Tag.valueOf("script"), "")
.attr("type", "text/javascript").attr("src", pushJS));
}
String bootstrapLocation = vaadinLocation
+ ApplicationConstants.VAADIN_BOOTSTRAP_JS + versionQueryParam;
fragmentNodes.add(new Element(Tag.valueOf("script"), "")
.attr("type", "text/javascript")
.attr("src", bootstrapLocation));
Element mainScriptTag = new Element(Tag.valueOf("script"), "")
.attr("type", "text/javascript");
StringBuilder builder = new StringBuilder();
builder.append("//<![CDATA[\n");
builder.append("if (!window.vaadin) alert(" + JsonUtil.quote(
"Failed to load the bootstrap javascript: " + bootstrapLocation)
+ ");\n");
appendMainScriptTagContents(context, builder);
builder.append("//]]>");
mainScriptTag.appendChild(
new DataNode(builder.toString(), mainScriptTag.baseUri()));
fragmentNodes.add(mainScriptTag);
}
protected void appendMainScriptTagContents(BootstrapContext context,
StringBuilder builder) throws IOException {
JsonObject appConfig = context.getApplicationParameters();
boolean isDebug = !context.getSession().getConfiguration()
.isProductionMode();
if (isDebug) {
/*
* Add tracking needed for getting bootstrap metrics to the client
* side Profiler if another implementation hasn't already been
* added.
*/
builder.append(
"if (typeof window.__gwtStatsEvent != 'function') {\n");
builder.append("vaadin.gwtStatsEvents = [];\n");
builder.append(
"window.__gwtStatsEvent = function(event) {vaadin.gwtStatsEvents.push(event); return true;};\n");
builder.append("}\n");
}
builder.append("vaadin.initApplication(\"");
builder.append(context.getAppId());
builder.append("\",");
appendJsonObject(builder, appConfig, isDebug);
builder.append(");\n");
}
private static void appendJsonObject(StringBuilder builder,
JsonObject jsonObject, boolean isDebug) {
if (isDebug) {
builder.append(JsonUtil.stringify(jsonObject, 4));
} else {
builder.append(JsonUtil.stringify(jsonObject));
}
}
protected JsonObject getApplicationParameters(BootstrapContext context) {
VaadinRequest request = context.getRequest();
VaadinSession session = context.getSession();
VaadinService vaadinService = request.getService();
JsonObject appConfig = Json.createObject();
String themeName = context.getThemeName();
if (themeName != null) {
appConfig.put("theme", themeName);
}
// Ignore restartApplication that might be passed to UI init
if (request.getParameter(
VaadinService.URL_PARAMETER_RESTART_APPLICATION) != null) {
appConfig.put("extraParams", "&" + IGNORE_RESTART_PARAM + "=1");
}
JsonObject versionInfo = Json.createObject();
versionInfo.put("vaadinVersion", Version.getFullVersion());
String atmosphereVersion = AtmospherePushConnection
.getAtmosphereVersion();
if (atmosphereVersion != null) {
versionInfo.put("atmosphereVersion", atmosphereVersion);
}
appConfig.put("versionInfo", versionInfo);
WidgetsetInfo widgetsetInfo = context.getWidgetsetInfo();
appConfig.put("widgetset", VaadinServlet
.stripSpecialChars(widgetsetInfo.getWidgetsetName()));
// add widgetset url if not null
if (widgetsetInfo.getWidgetsetUrl() != null) {
appConfig.put("widgetsetUrl", widgetsetInfo.getWidgetsetUrl());
}
appConfig.put("widgetsetReady", !widgetsetInfo.isCdn());
// Use locale from session if set, else from the request
Locale locale = ServletPortletHelper.findLocale(null,
context.getSession(), context.getRequest());
// Get system messages
SystemMessages systemMessages = vaadinService.getSystemMessages(locale,
request);
if (systemMessages != null) {
// Write the CommunicationError -message to client
JsonObject comErrMsg = Json.createObject();
putValueOrNull(comErrMsg, "caption",
systemMessages.getCommunicationErrorCaption());
putValueOrNull(comErrMsg, "message",
systemMessages.getCommunicationErrorMessage());
putValueOrNull(comErrMsg, "url",
systemMessages.getCommunicationErrorURL());
appConfig.put("comErrMsg", comErrMsg);
JsonObject authErrMsg = Json.createObject();
putValueOrNull(authErrMsg, "caption",
systemMessages.getAuthenticationErrorCaption());
putValueOrNull(authErrMsg, "message",
systemMessages.getAuthenticationErrorMessage());
putValueOrNull(authErrMsg, "url",
systemMessages.getAuthenticationErrorURL());
appConfig.put("authErrMsg", authErrMsg);
JsonObject sessExpMsg = Json.createObject();
putValueOrNull(sessExpMsg, "caption",
systemMessages.getSessionExpiredCaption());
putValueOrNull(sessExpMsg, "message",
systemMessages.getSessionExpiredMessage());
putValueOrNull(sessExpMsg, "url",
systemMessages.getSessionExpiredURL());
appConfig.put("sessExpMsg", sessExpMsg);
}
appConfig.put(ApplicationConstants.CONTEXT_ROOT_URL,
getContextRootPath(context));
// getStaticFileLocation documented to never end with a slash
// vaadinDir should always end with a slash
String vaadinDir = vaadinService.getStaticFileLocation(request)
+ "/VAADIN/";
appConfig.put(ApplicationConstants.VAADIN_DIR_URL, vaadinDir);
appConfig.put(ApplicationConstants.FRONTEND_URL,
context.getUriResolver().getFrontendUrl());
if (!session.getConfiguration().isProductionMode()) {
appConfig.put("debug", true);
}
if (vaadinService.isStandalone(request)) {
appConfig.put("standalone", true);
}
appConfig.put("heartbeatInterval", vaadinService
.getDeploymentConfiguration().getHeartbeatInterval());
String serviceUrl = getServiceUrl(context);
if (serviceUrl != null) {
appConfig.put(ApplicationConstants.SERVICE_URL, serviceUrl);
}
boolean sendUrlsAsParameters = vaadinService
.getDeploymentConfiguration().isSendUrlsAsParameters();
if (!sendUrlsAsParameters) {
appConfig.put("sendUrlsAsParameters", false);
}
return appConfig;
}
/**
* @since 8.0.3
*/
protected abstract String getContextRootPath(BootstrapContext context);
protected abstract String getServiceUrl(BootstrapContext context);
/**
* Get the URI for the application theme.
*
* A portal-wide default theme is fetched from the portal shared resource
* directory (if any), other themes from the portlet.
*
* @param context
* @param themeName
*
* @return
*/
public String getThemeUri(BootstrapContext context, String themeName) {
VaadinRequest request = context.getRequest();
final String staticFilePath = request.getService()
.getStaticFileLocation(request);
return staticFilePath + "/" + VaadinServlet.THEME_DIR_PATH + '/'
+ themeName;
}
/**
* Override if required
*
* @param context
* @return
*/
public String getThemeName(BootstrapContext context) {
UICreateEvent event = new UICreateEvent(context.getRequest(),
context.getUIClass());
return context.getBootstrapResponse().getUIProvider().getTheme(event);
}
/**
* Do not override.
*
* @param context
* @return
*/
public String findAndEscapeThemeName(BootstrapContext context) {
String themeName = getThemeName(context);
if (themeName == null) {
VaadinRequest request = context.getRequest();
themeName = request.getService().getConfiguredTheme(request);
}
// XSS preventation, theme names shouldn't contain special chars anyway.
// The servlet denies them via url parameter.
themeName = VaadinServlet.stripSpecialChars(themeName);
return themeName;
}
protected void writeError(VaadinResponse response, Throwable e)
throws IOException {
response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
e.getLocalizedMessage());
}
private void putValueOrNull(JsonObject object, String key, String value) {
assert object != null;
assert key != null;
if (value == null) {
object.put(key, Json.createNull());
} else {
object.put(key, value);
}
}
}