summaryrefslogtreecommitdiffstats
path: root/server/src
diff options
context:
space:
mode:
authorTeemu Suo-Anttila <teemusa@vaadin.com>2015-01-12 11:28:55 +0200
committerTeemu Suo-Anttila <teemusa@vaadin.com>2015-01-12 11:28:55 +0200
commit2286f9871f7f77dea6139d0cd1dfc6754b1946d5 (patch)
treec8a978d77dff74788b5a290f6c7928e39932b8a5 /server/src
parent35d91245de3218283c8f4c733a3aa72ea395fb1c (diff)
parent3f27e02f121c0a39b217532afcf9530bfd2caba7 (diff)
downloadvaadin-framework-2286f9871f7f77dea6139d0cd1dfc6754b1946d5.tar.gz
vaadin-framework-2286f9871f7f77dea6139d0cd1dfc6754b1946d5.zip
Merge remote-tracking branch 'origin/master' into grid
Change-Id: Ic6b667ea6ceff43a609ce2037f656c6274871fb7
Diffstat (limited to 'server/src')
-rw-r--r--server/src/com/vaadin/server/BootstrapHandler.java58
-rw-r--r--server/src/com/vaadin/server/LegacyCommunicationManager.java33
-rw-r--r--server/src/com/vaadin/server/VaadinPortletResponse.java8
-rw-r--r--server/src/com/vaadin/server/VaadinResponse.java13
-rw-r--r--server/src/com/vaadin/server/VaadinServlet.java124
-rw-r--r--server/src/com/vaadin/server/communication/UIInitHandler.java2
-rw-r--r--server/src/com/vaadin/ui/AbsoluteLayout.java2
-rw-r--r--server/src/com/vaadin/ui/Calendar.java37
8 files changed, 232 insertions, 45 deletions
diff --git a/server/src/com/vaadin/server/BootstrapHandler.java b/server/src/com/vaadin/server/BootstrapHandler.java
index bfe195ccf9..c45e2b70e0 100644
--- a/server/src/com/vaadin/server/BootstrapHandler.java
+++ b/server/src/com/vaadin/server/BootstrapHandler.java
@@ -414,6 +414,9 @@ public abstract class BootstrapHandler extends SynchronizedRequestHandler {
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;
@@ -424,12 +427,14 @@ public abstract class BootstrapHandler extends SynchronizedRequestHandler {
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;
+ + 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(
@@ -513,7 +518,6 @@ public abstract class BootstrapHandler extends SynchronizedRequestHandler {
}
appConfig.put("versionInfo", versionInfo);
-
appConfig.put("widgetset", context.getWidgetsetName());
// Use locale from session if set, else from the request
@@ -525,42 +529,32 @@ public abstract class BootstrapHandler extends SynchronizedRequestHandler {
if (systemMessages != null) {
// Write the CommunicationError -message to client
JsonObject comErrMsg = Json.createObject();
- comErrMsg.put("caption",
+ putValueOrNull(comErrMsg, "caption",
systemMessages.getCommunicationErrorCaption());
- comErrMsg.put("message",
+ putValueOrNull(comErrMsg, "message",
systemMessages.getCommunicationErrorMessage());
- if (systemMessages.getCommunicationErrorURL() == null) {
- comErrMsg.put("url", Json.createNull());
- } else {
- comErrMsg.put("url", systemMessages.getCommunicationErrorURL());
- }
+ putValueOrNull(comErrMsg, "url",
+ systemMessages.getCommunicationErrorURL());
appConfig.put("comErrMsg", comErrMsg);
JsonObject authErrMsg = Json.createObject();
- authErrMsg.put("caption",
+ putValueOrNull(authErrMsg, "caption",
systemMessages.getAuthenticationErrorCaption());
- authErrMsg.put("message",
+ putValueOrNull(authErrMsg, "message",
systemMessages.getAuthenticationErrorMessage());
- if (systemMessages.getAuthenticationErrorURL() == null) {
- authErrMsg.put("url", Json.createNull());
- } else {
- authErrMsg.put("url",
- systemMessages.getAuthenticationErrorURL());
- }
+ putValueOrNull(authErrMsg, "url",
+ systemMessages.getAuthenticationErrorURL());
appConfig.put("authErrMsg", authErrMsg);
JsonObject sessExpMsg = Json.createObject();
- sessExpMsg
- .put("caption", systemMessages.getSessionExpiredCaption());
- sessExpMsg
- .put("message", systemMessages.getSessionExpiredMessage());
- if (systemMessages.getSessionExpiredURL() == null) {
- sessExpMsg.put("url", Json.createNull());
- } else {
- sessExpMsg.put("url", systemMessages.getSessionExpiredURL());
- }
+ putValueOrNull(sessExpMsg, "caption",
+ systemMessages.getSessionExpiredCaption());
+ putValueOrNull(sessExpMsg, "message",
+ systemMessages.getSessionExpiredMessage());
+ putValueOrNull(sessExpMsg, "url",
+ systemMessages.getSessionExpiredURL());
appConfig.put("sessExpMsg", sessExpMsg);
}
@@ -624,7 +618,7 @@ public abstract class BootstrapHandler extends SynchronizedRequestHandler {
}
/**
- * Don not override.
+ * Do not override.
*
* @param context
* @return
@@ -648,4 +642,14 @@ public abstract class BootstrapHandler extends SynchronizedRequestHandler {
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);
+ }
+ }
}
diff --git a/server/src/com/vaadin/server/LegacyCommunicationManager.java b/server/src/com/vaadin/server/LegacyCommunicationManager.java
index 485084b515..fda5ad444f 100644
--- a/server/src/com/vaadin/server/LegacyCommunicationManager.java
+++ b/server/src/com/vaadin/server/LegacyCommunicationManager.java
@@ -24,6 +24,7 @@ import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
import java.util.logging.Level;
import java.util.logging.Logger;
@@ -81,6 +82,8 @@ public class LegacyCommunicationManager implements Serializable {
return session;
}
+ private static final ConcurrentHashMap<Class<? extends SharedState>, JsonValue> referenceDiffStates = new ConcurrentHashMap<Class<? extends SharedState>, JsonValue>();
+
/**
* @deprecated As of 7.1. See #11411.
*/
@@ -96,17 +99,10 @@ public class LegacyCommunicationManager implements Serializable {
if (diffState == null && supportsDiffState) {
// Use an empty state object as reference for full
// repaints
-
- try {
- SharedState referenceState = stateType.newInstance();
- EncodeResult encodeResult = JsonCodec.encode(referenceState,
- null, stateType, uI.getConnectorTracker());
- diffState = encodeResult.getEncodedValue();
- } catch (Exception e) {
- getLogger()
- .log(Level.WARNING,
- "Error creating reference object for state of type {0}",
- stateType.getName());
+ diffState = referenceDiffStates.get(stateType);
+ if (diffState == null) {
+ diffState = createReferenceDiffStateState(stateType);
+ referenceDiffStates.put(stateType, diffState);
}
}
EncodeResult encodeResult = JsonCodec.encode(state, diffState,
@@ -118,6 +114,21 @@ public class LegacyCommunicationManager implements Serializable {
return (JsonObject) encodeResult.getDiff();
}
+ private static JsonValue createReferenceDiffStateState(
+ Class<? extends SharedState> stateType) {
+ try {
+ SharedState referenceState = stateType.newInstance();
+ EncodeResult encodeResult = JsonCodec.encode(referenceState, null,
+ stateType, null);
+ return encodeResult.getEncodedValue();
+ } catch (Exception e) {
+ getLogger().log(Level.WARNING,
+ "Error creating reference object for state of type {0}",
+ stateType.getName());
+ return null;
+ }
+ }
+
/**
* Resolves a dependency URI, registering the URI with this
* {@code LegacyCommunicationManager} if needed and returns a fully
diff --git a/server/src/com/vaadin/server/VaadinPortletResponse.java b/server/src/com/vaadin/server/VaadinPortletResponse.java
index d9f133ac8a..2b6e0c75fb 100644
--- a/server/src/com/vaadin/server/VaadinPortletResponse.java
+++ b/server/src/com/vaadin/server/VaadinPortletResponse.java
@@ -97,6 +97,14 @@ public class VaadinPortletResponse implements VaadinResponse {
}
@Override
+ public void setContentLength(int len) {
+ if (response instanceof ResourceResponse) {
+ ((ResourceResponse) response).setContentLength(len);
+ }
+
+ }
+
+ @Override
public PrintWriter getWriter() throws IOException {
if (response instanceof MimeResponse) {
return ((MimeResponse) response).getWriter();
diff --git a/server/src/com/vaadin/server/VaadinResponse.java b/server/src/com/vaadin/server/VaadinResponse.java
index 1d5fcf141f..c31c6c05d8 100644
--- a/server/src/com/vaadin/server/VaadinResponse.java
+++ b/server/src/com/vaadin/server/VaadinResponse.java
@@ -169,4 +169,17 @@ public interface VaadinResponse extends Serializable {
* @see PortletResponse#addProperty(Cookie)
*/
public void addCookie(Cookie cookie);
+
+ /**
+ * Sets the length of the content body in the response In HTTP servlets,
+ * this method sets the HTTP Content-Length header. For some portlet
+ * responses, this method sets the content-length header, for others this
+ * method does nothing.
+ *
+ * @param len
+ * an integer specifying the length of the content being returned
+ * to the client
+ * @since 7.3.8
+ */
+ public void setContentLength(int len);
}
diff --git a/server/src/com/vaadin/server/VaadinServlet.java b/server/src/com/vaadin/server/VaadinServlet.java
index d1242676da..aa76dc8e08 100644
--- a/server/src/com/vaadin/server/VaadinServlet.java
+++ b/server/src/com/vaadin/server/VaadinServlet.java
@@ -28,6 +28,7 @@ import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Enumeration;
@@ -45,14 +46,21 @@ import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
+import com.google.gwt.thirdparty.guava.common.base.Charsets;
+import com.google.gwt.thirdparty.guava.common.io.Files;
import com.vaadin.annotations.VaadinServletConfiguration;
import com.vaadin.annotations.VaadinServletConfiguration.InitParameterName;
import com.vaadin.sass.internal.ScssStylesheet;
import com.vaadin.server.communication.ServletUIInitHandler;
import com.vaadin.shared.JsonConstants;
+import com.vaadin.shared.Version;
import com.vaadin.ui.UI;
import com.vaadin.util.CurrentInstance;
+import elemental.json.Json;
+import elemental.json.JsonArray;
+import elemental.json.JsonObject;
+
@SuppressWarnings("serial")
public class VaadinServlet extends HttpServlet implements Constants {
@@ -61,14 +69,47 @@ public class VaadinServlet extends HttpServlet implements Constants {
private final String css;
private final List<String> sourceUris;
private final long timestamp;
+ private final String scssFileName;
- public ScssCacheEntry(String css, List<String> sourceUris) {
+ public ScssCacheEntry(String scssFileName, String css,
+ List<String> sourceUris) {
+ this.scssFileName = scssFileName;
this.css = css;
this.sourceUris = sourceUris;
timestamp = getLastModified();
}
+ public ScssCacheEntry(JsonObject json) {
+ css = json.getString("css");
+ timestamp = Long.parseLong(json.getString("timestamp"));
+
+ sourceUris = new ArrayList<String>();
+
+ JsonArray uris = json.getArray("uris");
+ for (int i = 0; i < uris.length(); i++) {
+ sourceUris.add(uris.getString(i));
+ }
+
+ // Not set for cache entries read from disk
+ scssFileName = null;
+ }
+
+ public String asJson() {
+ JsonArray uris = Json.createArray();
+ for (String uri : sourceUris) {
+ uris.set(uris.length(), uri);
+ }
+
+ JsonObject object = Json.createObject();
+ object.put("version", Version.getFullVersion());
+ object.put("timestamp", Long.toString(timestamp));
+ object.put("uris", uris);
+ object.put("css", css);
+
+ return object.toJson();
+ }
+
public String getCss() {
return css;
}
@@ -117,6 +158,10 @@ public class VaadinServlet extends HttpServlet implements Constants {
}
}
+ public String getScssFileName() {
+ return scssFileName;
+ }
+
}
private VaadinServletService servletService;
@@ -612,7 +657,14 @@ public class VaadinServlet extends HttpServlet implements Constants {
* Global cache of scss compilation results. This map is protected from
* concurrent access by {@link #SCSS_MUTEX}.
*/
- private static final Map<String, ScssCacheEntry> scssCache = new HashMap<String, ScssCacheEntry>();
+ private final Map<String, ScssCacheEntry> scssCache = new HashMap<String, ScssCacheEntry>();
+
+ /**
+ * Keeps track of whether a warning about not being able to persist cache
+ * files has already been printed. The flag is protected from concurrent
+ * access by {@link #SCSS_MUTEX}.
+ */
+ private static boolean scssCompileWarWarningEmitted = false;
/**
* Returns the default theme. Must never return null.
@@ -900,10 +952,20 @@ public class VaadinServlet extends HttpServlet implements Constants {
synchronized (SCSS_MUTEX) {
ScssCacheEntry cacheEntry = scssCache.get(scssFilename);
+ if (cacheEntry == null) {
+ try {
+ cacheEntry = loadPersistedScssCache(scssFilename, sc);
+ } catch (Exception e) {
+ getLogger().log(Level.WARNING,
+ "Could not read persisted scss cache", e);
+ }
+ }
+
if (cacheEntry == null || !cacheEntry.isStillValid()) {
cacheEntry = compileScssOnTheFly(filename, scssFilename, sc);
- scssCache.put(scssFilename, cacheEntry);
+ persistCacheEntry(cacheEntry);
}
+ scssCache.put(scssFilename, cacheEntry);
if (cacheEntry == null) {
// compilation did not produce any result, but logged a message
@@ -920,6 +982,29 @@ public class VaadinServlet extends HttpServlet implements Constants {
}
}
+ private ScssCacheEntry loadPersistedScssCache(String scssFilename,
+ ServletContext sc) throws IOException {
+ String realFilename = sc.getRealPath(scssFilename);
+
+ File scssCacheFile = getScssCacheFile(new File(realFilename));
+ if (!scssCacheFile.exists()) {
+ return null;
+ }
+
+ String jsonString = Files.toString(scssCacheFile, Charsets.UTF_8);
+
+ JsonObject entryJson = Json.parse(jsonString);
+
+ String cacheVersion = entryJson.getString("version");
+ if (!Version.getFullVersion().equals(cacheVersion)) {
+ // Compiled for some other Vaadin version, discard cache
+ scssCacheFile.delete();
+ return null;
+ }
+
+ return new ScssCacheEntry(entryJson);
+ }
+
private ScssCacheEntry compileScssOnTheFly(String filename,
String scssFilename, ServletContext sc) throws IOException {
String realFilename = sc.getRealPath(scssFilename);
@@ -951,7 +1036,8 @@ public class VaadinServlet extends HttpServlet implements Constants {
return null;
}
- return new ScssCacheEntry(scss.printState(), scss.getSourceUris());
+ return new ScssCacheEntry(realFilename, scss.printState(),
+ scss.getSourceUris());
}
/**
@@ -1196,6 +1282,36 @@ public class VaadinServlet extends HttpServlet implements Constants {
getService().destroy();
}
+ private static void persistCacheEntry(ScssCacheEntry cacheEntry) {
+ String scssFileName = cacheEntry.getScssFileName();
+ if (scssFileName == null) {
+ if (!scssCompileWarWarningEmitted) {
+ getLogger()
+ .warning(
+ "Could not persist scss cache because no real file was found for the compiled scss file. "
+ + "This might happen e.g. if serving the scss file directly from a .war file.");
+ scssCompileWarWarningEmitted = true;
+ }
+ return;
+ }
+
+ File scssFile = new File(scssFileName);
+ File cacheFile = getScssCacheFile(scssFile);
+
+ String cacheEntryJsonString = cacheEntry.asJson();
+
+ try {
+ Files.write(cacheEntryJsonString, cacheFile, Charsets.UTF_8);
+ } catch (IOException e) {
+ getLogger().log(Level.WARNING,
+ "Error persisting scss cache " + cacheFile, e);
+ }
+ }
+
+ private static File getScssCacheFile(File scssFile) {
+ return new File(scssFile.getParentFile(), scssFile.getName() + ".cache");
+ }
+
/**
* Escapes characters to html entities. An exception is made for some
* "safe characters" to keep the text somewhat readable.
diff --git a/server/src/com/vaadin/server/communication/UIInitHandler.java b/server/src/com/vaadin/server/communication/UIInitHandler.java
index 018274330f..3a6dc1e55f 100644
--- a/server/src/com/vaadin/server/communication/UIInitHandler.java
+++ b/server/src/com/vaadin/server/communication/UIInitHandler.java
@@ -112,7 +112,7 @@ public abstract class UIInitHandler extends SynchronizedRequestHandler {
response.setHeader("Cache-Control", "no-cache");
byte[] b = json.getBytes("UTF-8");
- response.setHeader("Content-Length", String.valueOf(b.length));
+ response.setContentLength(b.length);
OutputStream outputStream = response.getOutputStream();
outputStream.write(b);
diff --git a/server/src/com/vaadin/ui/AbsoluteLayout.java b/server/src/com/vaadin/ui/AbsoluteLayout.java
index 12aa8ea9a6..6353a4b25d 100644
--- a/server/src/com/vaadin/ui/AbsoluteLayout.java
+++ b/server/src/com/vaadin/ui/AbsoluteLayout.java
@@ -746,7 +746,7 @@ public class AbsoluteLayout extends AbstractLayout implements
/**
* Private method for writing position attributes
*
- * @since
+ * @since 7.4
* @param node
* target node
* @param key
diff --git a/server/src/com/vaadin/ui/Calendar.java b/server/src/com/vaadin/ui/Calendar.java
index 5b5c390fa1..206cc01d1a 100644
--- a/server/src/com/vaadin/ui/Calendar.java
+++ b/server/src/com/vaadin/ui/Calendar.java
@@ -297,6 +297,11 @@ public class Calendar extends AbstractComponent implements
}
@Override
+ protected CalendarState getState(boolean markAsDirty) {
+ return (CalendarState) super.getState(markAsDirty);
+ }
+
+ @Override
public void beforeClientResponse(boolean initial) {
super.beforeClientResponse(initial);
@@ -1667,7 +1672,7 @@ public class Calendar extends AbstractComponent implements
* weekly mode
*/
public boolean isMonthlyMode() {
- CalendarState state = (CalendarState) getState(false);
+ CalendarState state = getState(false);
if (state.days != null) {
return state.days.size() > 7;
} else {
@@ -1895,4 +1900,34 @@ public class Calendar extends AbstractComponent implements
dropHandler.getAcceptCriterion().paint(target);
}
}
+
+ /**
+ * Sets whether the event captions are rendered as HTML.
+ * <p>
+ * If set to true, the captions are rendered in the browser as HTML and the
+ * developer is responsible for ensuring no harmful HTML is used. If set to
+ * false, the caption is rendered in the browser as plain text.
+ * <p>
+ * The default is false, i.e. to render that caption as plain text.
+ *
+ * @param captionAsHtml
+ * true if the captions are rendered as HTML, false if rendered
+ * as plain text
+ */
+ public void setEventCaptionAsHtml(boolean eventCaptionAsHtml) {
+ getState().eventCaptionAsHtml = eventCaptionAsHtml;
+ }
+
+ /**
+ * Checks whether event captions are rendered as HTML
+ * <p>
+ * The default is false, i.e. to render that caption as plain text.
+ *
+ * @return true if the captions are rendered as HTML, false if rendered as
+ * plain text
+ */
+ public boolean isEventCaptionAsHtml() {
+ return getState(false).eventCaptionAsHtml;
+ }
+
}