From 32a5d8f3827fbf0ba2c0c3102f0d818d7b7a3873 Mon Sep 17 00:00:00 2001 From: Artur Signell Date: Mon, 29 Dec 2014 14:11:12 +0200 Subject: Reformat project using Eclipse Luna SR1 Change-Id: I58748499c87d470e70304d882d3227cda5803481 --- .../converter/StringToBigIntegerConverter.java | 3 ++- .../query/generator/DefaultSQLGenerator.java | 2 +- .../com/vaadin/server/ClientMethodInvocation.java | 6 ++++-- .../vaadin/server/JavaScriptCallbackHelper.java | 3 ++- server/src/com/vaadin/server/JsonCodec.java | 22 +++++++++++++--------- .../vaadin/server/LegacyCommunicationManager.java | 3 ++- .../server/communication/ClientRpcWriter.java | 3 ++- .../server/communication/JSONSerializer.java | 7 ++++--- .../server/communication/ServerRpcHandler.java | 6 ++++-- .../vaadin/server/communication/UIInitHandler.java | 3 ++- server/src/com/vaadin/ui/UI.java | 2 +- 11 files changed, 37 insertions(+), 23 deletions(-) (limited to 'server/src/com') diff --git a/server/src/com/vaadin/data/util/converter/StringToBigIntegerConverter.java b/server/src/com/vaadin/data/util/converter/StringToBigIntegerConverter.java index 6695aa71ac..adaa8c6111 100644 --- a/server/src/com/vaadin/data/util/converter/StringToBigIntegerConverter.java +++ b/server/src/com/vaadin/data/util/converter/StringToBigIntegerConverter.java @@ -56,7 +56,8 @@ public class StringToBigIntegerConverter extends BigDecimal bigDecimalValue = (BigDecimal) convertToNumber(value, BigDecimal.class, locale); - return (bigDecimalValue != null) ? bigDecimalValue.toBigInteger() : null; + return (bigDecimalValue != null) ? bigDecimalValue.toBigInteger() + : null; } @Override diff --git a/server/src/com/vaadin/data/util/sqlcontainer/query/generator/DefaultSQLGenerator.java b/server/src/com/vaadin/data/util/sqlcontainer/query/generator/DefaultSQLGenerator.java index 21a486a017..2fc7ebd544 100644 --- a/server/src/com/vaadin/data/util/sqlcontainer/query/generator/DefaultSQLGenerator.java +++ b/server/src/com/vaadin/data/util/sqlcontainer/query/generator/DefaultSQLGenerator.java @@ -262,7 +262,7 @@ public class DefaultSQLGenerator implements SQLGenerator { count++; } if (versionColumn != null) { - if(!item.getItemPropertyIds().contains(versionColumn)) { + if (!item.getItemPropertyIds().contains(versionColumn)) { throw new IllegalArgumentException(String.format( "Table '%s' does not contain version column '%s'.", tableName, versionColumn)); diff --git a/server/src/com/vaadin/server/ClientMethodInvocation.java b/server/src/com/vaadin/server/ClientMethodInvocation.java index 97caa7614a..33b88a168b 100644 --- a/server/src/com/vaadin/server/ClientMethodInvocation.java +++ b/server/src/com/vaadin/server/ClientMethodInvocation.java @@ -109,7 +109,8 @@ public class ClientMethodInvocation implements Serializable, if (type instanceof Class) { Class clazz = (Class) type; if (JsonArray.class.isAssignableFrom(clazz)) { - parameters[i] = JsonUtil.stringify((JsonArray) parameters[i]); + parameters[i] = JsonUtil + .stringify((JsonArray) parameters[i]); } } } @@ -127,7 +128,8 @@ public class ClientMethodInvocation implements Serializable, Class clazz = (Class) type; if (JsonArray.class.isAssignableFrom(clazz)) { try { - parameters[i] = JsonUtil.parse((String) parameters[i]); + parameters[i] = JsonUtil + . parse((String) parameters[i]); } catch (JsonException e) { throw new IOException(e); } diff --git a/server/src/com/vaadin/server/JavaScriptCallbackHelper.java b/server/src/com/vaadin/server/JavaScriptCallbackHelper.java index 2552db6d13..ac4a586d00 100644 --- a/server/src/com/vaadin/server/JavaScriptCallbackHelper.java +++ b/server/src/com/vaadin/server/JavaScriptCallbackHelper.java @@ -94,7 +94,8 @@ public class JavaScriptCallbackHelper implements Serializable { + name + " on the client because a callback with the same name is registered on the server."); } - JsonArray args = (JsonArray) JsonCodec.encode(arguments, null, Object[].class, null).getEncodedValue(); + JsonArray args = (JsonArray) JsonCodec.encode(arguments, null, + Object[].class, null).getEncodedValue(); connector.addMethodInvocationToQueue( JavaScriptCallbackRpc.class.getName(), CALL_METHOD, new Object[] { name, args }); diff --git a/server/src/com/vaadin/server/JsonCodec.java b/server/src/com/vaadin/server/JsonCodec.java index 1e9438453a..1f7b4ead43 100644 --- a/server/src/com/vaadin/server/JsonCodec.java +++ b/server/src/com/vaadin/server/JsonCodec.java @@ -66,10 +66,12 @@ import elemental.json.impl.JreJsonArray; public class JsonCodec implements Serializable { /* Immutable Encode Result representing null */ - private static final EncodeResult ENCODE_RESULT_NULL = new EncodeResult(Json.createNull()); + private static final EncodeResult ENCODE_RESULT_NULL = new EncodeResult( + Json.createNull()); /* Immutable empty JSONArray */ - private static final JsonArray EMPTY_JSON_ARRAY = new JreJsonArray(Json.instance()) { + private static final JsonArray EMPTY_JSON_ARRAY = new JreJsonArray( + Json.instance()) { @Override public void set(int index, JsonValue value) { throw new UnsupportedOperationException( @@ -316,7 +318,8 @@ public class JsonCodec implements Serializable { .getGenericComponentType(); return decodeArray(componentType, (JsonArray) value, connectorTracker); - } else if (JsonValue.class.isAssignableFrom(getClassForType(targetType))) { + } else if (JsonValue.class + .isAssignableFrom(getClassForType(targetType))) { return value; } else if (Enum.class.isAssignableFrom(getClassForType(targetType))) { Class classForType = getClassForType(targetType); @@ -479,8 +482,7 @@ public class JsonCodec implements Serializable { } private static Map decodeObjectMap(Type keyType, - Type valueType, JsonArray jsonMap, ConnectorTracker connectorTracker) - { + Type valueType, JsonArray jsonMap, ConnectorTracker connectorTracker) { JsonArray keys = jsonMap.getArray(0); JsonArray values = jsonMap.getArray(1); @@ -766,7 +768,8 @@ public class JsonCodec implements Serializable { * @param referenceValue * @return */ - private static boolean jsonEquals(JsonValue fieldValue, JsonValue referenceValue) { + private static boolean jsonEquals(JsonValue fieldValue, + JsonValue referenceValue) { if (fieldValue instanceof JsonNull) { fieldValue = null; } @@ -795,13 +798,14 @@ public class JsonCodec implements Serializable { Collection collection, ConnectorTracker connectorTracker) { JsonArray jsonArray = Json.createArray(); for (Object o : collection) { - jsonArray.set(jsonArray.length(), encodeChild(targetType, 0, o, connectorTracker)); + jsonArray.set(jsonArray.length(), + encodeChild(targetType, 0, o, connectorTracker)); } return jsonArray; } - private static JsonValue encodeChild(Type targetType, int typeIndex, Object o, - ConnectorTracker connectorTracker) { + private static JsonValue encodeChild(Type targetType, int typeIndex, + Object o, ConnectorTracker connectorTracker) { if (targetType instanceof ParameterizedType) { Type childType = ((ParameterizedType) targetType) .getActualTypeArguments()[typeIndex]; diff --git a/server/src/com/vaadin/server/LegacyCommunicationManager.java b/server/src/com/vaadin/server/LegacyCommunicationManager.java index e1beb1153c..485084b515 100644 --- a/server/src/com/vaadin/server/LegacyCommunicationManager.java +++ b/server/src/com/vaadin/server/LegacyCommunicationManager.java @@ -85,7 +85,8 @@ public class LegacyCommunicationManager implements Serializable { * @deprecated As of 7.1. See #11411. */ @Deprecated - public static JsonObject encodeState(ClientConnector connector, SharedState state) { + public static JsonObject encodeState(ClientConnector connector, + SharedState state) { UI uI = connector.getUI(); ConnectorTracker connectorTracker = uI.getConnectorTracker(); Class stateType = connector.getStateType(); diff --git a/server/src/com/vaadin/server/communication/ClientRpcWriter.java b/server/src/com/vaadin/server/communication/ClientRpcWriter.java index 6631f6176d..2ecf81287e 100644 --- a/server/src/com/vaadin/server/communication/ClientRpcWriter.java +++ b/server/src/com/vaadin/server/communication/ClientRpcWriter.java @@ -67,7 +67,8 @@ public class ClientRpcWriter implements Serializable { // add invocation to rpcCalls try { JsonArray invocationJson = Json.createArray(); - invocationJson.set(0, invocation.getConnector().getConnectorId()); + invocationJson.set(0, invocation.getConnector() + .getConnectorId()); invocationJson.set(1, invocation.getInterfaceName()); invocationJson.set(2, invocation.getMethodName()); JsonArray paramJson = Json.createArray(); diff --git a/server/src/com/vaadin/server/communication/JSONSerializer.java b/server/src/com/vaadin/server/communication/JSONSerializer.java index e318b6b145..7f673d01e8 100644 --- a/server/src/com/vaadin/server/communication/JSONSerializer.java +++ b/server/src/com/vaadin/server/communication/JSONSerializer.java @@ -52,12 +52,13 @@ public interface JSONSerializer { * the connector tracker instance for the UI * @return A deserialized object */ - T deserialize(Type type, JsonValue jsonValue, ConnectorTracker connectorTracker); + T deserialize(Type type, JsonValue jsonValue, + ConnectorTracker connectorTracker); /** * Serialize the given object into JSON. Must be compatible with - * {@link #deserialize(Type, JsonValue, ConnectorTracker)} and the client side - * com.vaadin.client.communication.JSONSerializer + * {@link #deserialize(Type, JsonValue, ConnectorTracker)} and the client + * side com.vaadin.client.communication.JSONSerializer * * @param value * The object to serialize diff --git a/server/src/com/vaadin/server/communication/ServerRpcHandler.java b/server/src/com/vaadin/server/communication/ServerRpcHandler.java index d1b1be6b97..450c11f5c4 100644 --- a/server/src/com/vaadin/server/communication/ServerRpcHandler.java +++ b/server/src/com/vaadin/server/communication/ServerRpcHandler.java @@ -93,7 +93,8 @@ public class ServerRpcHandler implements Serializable { if (request.getService().getDeploymentConfiguration() .isSyncIdCheckEnabled()) { - syncId = (int) json.getNumber(ApplicationConstants.SERVER_SYNC_ID); + syncId = (int) json + .getNumber(ApplicationConstants.SERVER_SYNC_ID); } else { syncId = -1; } @@ -373,7 +374,8 @@ public class ServerRpcHandler implements Serializable { String methodName = invocationJson.getString(2); if (connectorTracker.getConnector(connectorId) == null - && !connectorId.equals(ApplicationConstants.DRAG_AND_DROP_CONNECTOR_ID)) { + && !connectorId + .equals(ApplicationConstants.DRAG_AND_DROP_CONNECTOR_ID)) { if (!connectorTracker.connectorWasPresentAsRequestWasSent( connectorId, lastSyncIdSeenByClient)) { diff --git a/server/src/com/vaadin/server/communication/UIInitHandler.java b/server/src/com/vaadin/server/communication/UIInitHandler.java index 1216d2b689..018274330f 100644 --- a/server/src/com/vaadin/server/communication/UIInitHandler.java +++ b/server/src/com/vaadin/server/communication/UIInitHandler.java @@ -80,7 +80,8 @@ public abstract class UIInitHandler extends SynchronizedRequestHandler { String initialUIDL = getInitialUidl(request, uI); params.put("uidl", initialUIDL); - return commitJsonResponse(request, response, JsonUtil.stringify(params)); + return commitJsonResponse(request, response, + JsonUtil.stringify(params)); } catch (JsonException e) { throw new IOException("Error producing initial UIDL", e); } diff --git a/server/src/com/vaadin/ui/UI.java b/server/src/com/vaadin/ui/UI.java index 4bd4b67259..66f893e04a 100644 --- a/server/src/com/vaadin/ui/UI.java +++ b/server/src/com/vaadin/ui/UI.java @@ -1164,7 +1164,7 @@ public abstract class UI extends AbstractSingleComponentContainer implements * The new theme name */ public void setTheme(String theme) { - if(theme == null) { + if (theme == null) { getState().theme = null; } else { getState().theme = VaadinServlet.stripSpecialChars(theme); -- cgit v1.2.3 From 26832b6947266ce5cffd92558c23e6556278038d Mon Sep 17 00:00:00 2001 From: Artur Signell Date: Fri, 19 Dec 2014 01:50:32 +0200 Subject: Option for rendering Calendar event captions as HTML (#9030) Change-Id: Ib7f6e67c242449e58a10359c596489fea2f679f6 --- WebContent/release-notes.html | 3 +- client/src/com/vaadin/client/ui/VCalendar.java | 30 ++++++ .../client/ui/calendar/CalendarConnector.java | 2 + .../ui/calendar/schedule/DateCellDayEvent.java | 14 ++- .../ui/calendar/schedule/MonthEventLabel.java | 15 ++- .../ui/calendar/schedule/WeeklyLongEvents.java | 6 +- server/src/com/vaadin/ui/Calendar.java | 37 +++++++- .../vaadin/shared/ui/calendar/CalendarState.java | 1 + .../components/calendar/CalendarHtmlInEvents.java | 101 ++++++++++++++++++++ .../calendar/CalendarHtmlInEventsTest.java | 103 +++++++++++++++++++++ 10 files changed, 302 insertions(+), 10 deletions(-) create mode 100644 uitest/src/com/vaadin/tests/components/calendar/CalendarHtmlInEvents.java create mode 100644 uitest/src/com/vaadin/tests/components/calendar/CalendarHtmlInEventsTest.java (limited to 'server/src/com') diff --git a/WebContent/release-notes.html b/WebContent/release-notes.html index a060372580..7be74ee1ed 100644 --- a/WebContent/release-notes.html +++ b/WebContent/release-notes.html @@ -112,7 +112,7 @@
  • Declarative layout support for initializing a component hierarchy from an HTML file.
  • Uses GWT 2.7 for improved compilation times when using Super Dev Mode.
  • @Viewport annotation for declaratively defining a mobile viewport definition for a UI.
  • -
  • Captions can be configured to be displayed as HTML.
  • +
  • Component captions, TabSheet/Accordion tab captions and Calendar event captions can be configured to be displayed as HTML.
  • Selects use converters when presenting itemids.
  • Improved performance when server response contains no visual changing (e.g. empty polling responses).
  • Unified JSON library for using the same API in both server-side and client-side code.
  • @@ -134,6 +134,7 @@

    Raw JSON values passed to AbstractJavaScriptComponent.callFunction and AbstractJavaScriptExtension.callFunction should be changed to use elemental.json types.

  • The semantics of empty and required for Field classes has been made more consistent. This mainly affects Checkbox which is now considered to be empty when it is not checked.
  • +
  • The previously inconsistent behavior in HTML vs plain text rendering of Calendar event captions has been made consistent.
  • Support for Opera 12 has been dropped. Newer versions based on the Blink rendering engine are still supported.
  • Known issues

    diff --git a/client/src/com/vaadin/client/ui/VCalendar.java b/client/src/com/vaadin/client/ui/VCalendar.java index c59a78108c..08d4351931 100644 --- a/client/src/com/vaadin/client/ui/VCalendar.java +++ b/client/src/com/vaadin/client/ui/VCalendar.java @@ -1342,6 +1342,7 @@ public class VCalendar extends Composite implements VHasDropHandler { private MouseEventListener mouseEventListener; private boolean forwardNavigationEnabled = true; private boolean backwardNavigationEnabled = true; + private boolean eventCaptionAsHtml = false; /** * Get the listener that listen to mouse events @@ -1467,4 +1468,33 @@ public class VCalendar extends Composite implements VHasDropHandler { public void setDropHandler(CalendarDropHandler dropHandler) { this.dropHandler = dropHandler; } + + /** + * Sets whether the event captions are rendered as HTML. + *

    + * 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. + *

    + * 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) { + this.eventCaptionAsHtml = eventCaptionAsHtml; + } + + /** + * Checks whether event captions are rendered as HTML + *

    + * 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 eventCaptionAsHtml; + } } diff --git a/client/src/com/vaadin/client/ui/calendar/CalendarConnector.java b/client/src/com/vaadin/client/ui/calendar/CalendarConnector.java index 8f5e9d9a59..8c92ef1233 100644 --- a/client/src/com/vaadin/client/ui/calendar/CalendarConnector.java +++ b/client/src/com/vaadin/client/ui/calendar/CalendarConnector.java @@ -345,6 +345,8 @@ public class CalendarConnector extends AbstractComponentConnector implements widget.setEventMoveAllowed(hasEventListener(CalendarEventId.EVENTMOVE)); widget.setEventResizeAllowed(hasEventListener(CalendarEventId.EVENTRESIZE)); + widget.setEventCaptionAsHtml(state.eventCaptionAsHtml); + List days = state.days; List events = state.events; diff --git a/client/src/com/vaadin/client/ui/calendar/schedule/DateCellDayEvent.java b/client/src/com/vaadin/client/ui/calendar/schedule/DateCellDayEvent.java index 3b168b636c..8b08e9bc7a 100644 --- a/client/src/com/vaadin/client/ui/calendar/schedule/DateCellDayEvent.java +++ b/client/src/com/vaadin/client/ui/calendar/schedule/DateCellDayEvent.java @@ -184,14 +184,20 @@ public class DateCellDayEvent extends FocusableHTML implements */ private void updateCaptions(boolean bigMode) { String innerHtml; - String escapedCaption = Util.escapeHTML(calendarEvent.getCaption()); String timeAsText = calendarEvent.getTimeAsText(); + String htmlOrText; + + if (dateCell.weekgrid.getCalendar().isEventCaptionAsHtml()) { + htmlOrText = calendarEvent.getCaption(); + } else { + htmlOrText = Util.escapeHTML(calendarEvent.getCaption()); + } + if (bigMode) { - innerHtml = "" + timeAsText + "
    " - + escapedCaption; + innerHtml = "" + timeAsText + "
    " + htmlOrText; } else { innerHtml = "" + timeAsText + ": " - + escapedCaption; + + htmlOrText; } caption.setInnerHTML(innerHtml); eventContent.setInnerHTML(""); diff --git a/client/src/com/vaadin/client/ui/calendar/schedule/MonthEventLabel.java b/client/src/com/vaadin/client/ui/calendar/schedule/MonthEventLabel.java index 6fc2e430cd..31e600c8f9 100644 --- a/client/src/com/vaadin/client/ui/calendar/schedule/MonthEventLabel.java +++ b/client/src/com/vaadin/client/ui/calendar/schedule/MonthEventLabel.java @@ -20,6 +20,7 @@ import java.util.Date; import com.google.gwt.event.dom.client.ContextMenuEvent; import com.google.gwt.event.dom.client.ContextMenuHandler; import com.google.gwt.user.client.ui.HTML; +import com.vaadin.client.Util; import com.vaadin.client.ui.VCalendar; /** @@ -75,7 +76,8 @@ public class MonthEventLabel extends HTML implements HasTooltipKey { * Set the caption of the event label * * @param caption - * The caption string, can be HTML + * The caption string, can be HTML if + * {@link VCalendar#isEventCaptionAsHtml()} is true */ public void setCaption(String caption) { this.caption = caption; @@ -87,13 +89,20 @@ public class MonthEventLabel extends HTML implements HasTooltipKey { */ private void renderCaption() { StringBuilder html = new StringBuilder(); + String textOrHtml; + if (calendar.isEventCaptionAsHtml()) { + textOrHtml = caption; + } else { + textOrHtml = Util.escapeHTML(caption); + } + if (caption != null && time != null) { html.append(""); html.append(calendar.getTimeFormat().format(time)); html.append(" "); - html.append(caption); + html.append(textOrHtml); } else if (caption != null) { - html.append(caption); + html.append(textOrHtml); } else if (time != null) { html.append(""); html.append(calendar.getTimeFormat().format(time)); diff --git a/client/src/com/vaadin/client/ui/calendar/schedule/WeeklyLongEvents.java b/client/src/com/vaadin/client/ui/calendar/schedule/WeeklyLongEvents.java index bd833e06a0..9488c8835a 100644 --- a/client/src/com/vaadin/client/ui/calendar/schedule/WeeklyLongEvents.java +++ b/client/src/com/vaadin/client/ui/calendar/schedule/WeeklyLongEvents.java @@ -102,7 +102,11 @@ public class WeeklyLongEvents extends HorizontalPanel implements HasTooltipKey { eventLabel.addStyleDependentName(extraStyle + "-all-day"); } if (!started) { - eventLabel.setText(calendarEvent.getCaption()); + if (calendar.isEventCaptionAsHtml()) { + eventLabel.setHTML(calendarEvent.getCaption()); + } else { + eventLabel.setText(calendarEvent.getCaption()); + } started = true; } } 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 @@ -296,6 +296,11 @@ public class Calendar extends AbstractComponent implements return (CalendarState) super.getState(); } + @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. + *

    + * 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. + *

    + * 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 + *

    + * 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; + } + } diff --git a/shared/src/com/vaadin/shared/ui/calendar/CalendarState.java b/shared/src/com/vaadin/shared/ui/calendar/CalendarState.java index 93bd05bc1e..c26c4ead16 100644 --- a/shared/src/com/vaadin/shared/ui/calendar/CalendarState.java +++ b/shared/src/com/vaadin/shared/ui/calendar/CalendarState.java @@ -38,6 +38,7 @@ public class CalendarState extends AbstractComponentState { public List days; public List events; public List actions; + public boolean eventCaptionAsHtml; public static class Day implements java.io.Serializable { public String date; diff --git a/uitest/src/com/vaadin/tests/components/calendar/CalendarHtmlInEvents.java b/uitest/src/com/vaadin/tests/components/calendar/CalendarHtmlInEvents.java new file mode 100644 index 0000000000..15cde71838 --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/calendar/CalendarHtmlInEvents.java @@ -0,0 +1,101 @@ +/* + * Copyright 2000-2014 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.tests.components.calendar; + +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +import com.vaadin.data.Property.ValueChangeEvent; +import com.vaadin.data.Property.ValueChangeListener; +import com.vaadin.data.util.MethodProperty; +import com.vaadin.server.VaadinRequest; +import com.vaadin.tests.components.AbstractTestUIWithLog; +import com.vaadin.ui.Alignment; +import com.vaadin.ui.Calendar; +import com.vaadin.ui.CheckBox; +import com.vaadin.ui.HorizontalLayout; +import com.vaadin.ui.NativeSelect; +import com.vaadin.ui.components.calendar.event.BasicEvent; +import com.vaadin.ui.components.calendar.event.CalendarEvent; +import com.vaadin.ui.components.calendar.event.CalendarEventProvider; + +public class CalendarHtmlInEvents extends AbstractTestUIWithLog { + + private Calendar calendar = new Calendar(); + + @Override + protected void setup(VaadinRequest request) { + final NativeSelect ns = new NativeSelect("Period"); + ns.addItems("Day", "Week", "Month"); + ns.addValueChangeListener(new ValueChangeListener() { + @Override + public void valueChange(ValueChangeEvent event) { + if ("Day".equals(ns.getValue())) { + calendar.setStartDate(new Date(2014 - 1900, 1 - 1, 1)); + calendar.setEndDate(new Date(2014 - 1900, 1 - 1, 1)); + } else if ("Week".equals(ns.getValue())) { + calendar.setStartDate(new Date(2014 - 1900, 1 - 1, 1)); + calendar.setEndDate(new Date(2014 - 1900, 1 - 1, 7)); + } else if ("Month".equals(ns.getValue())) { + calendar.setStartDate(new Date(2014 - 1900, 1 - 1, 1)); + calendar.setEndDate(new Date(2014 - 1900, 2 - 1, 1)); + } + } + }); + ns.setValue("Month"); + final CheckBox allowHtml = new CheckBox("Allow HTML in event caption", + new MethodProperty(calendar, "eventCaptionAsHtml")); + allowHtml.addValueChangeListener(new ValueChangeListener() { + @Override + public void valueChange(ValueChangeEvent event) { + log("HTML in event caption: " + allowHtml.getValue()); + } + }); + HorizontalLayout hl = new HorizontalLayout(); + hl.setDefaultComponentAlignment(Alignment.BOTTOM_LEFT); + hl.addComponents(ns, allowHtml); + hl.setSpacing(true); + hl.setMargin(true); + calendar.setEventProvider(new CalendarEventProvider() { + + @Override + public List getEvents(Date startDate, Date endDate) { + Date d = startDate; + ArrayList events = new ArrayList(); + while (d.before(endDate)) { + BasicEvent ce = new BasicEvent(); + ce.setAllDay(false); + ce.setCaption("Hello world!"); + ce.setDescription("Nothing really important"); + Date start = new Date(d.getTime()); + start.setHours(d.getDay()); + Date end = new Date(d.getTime()); + end.setHours(d.getDay() + 3); + ce.setStart(start); + ce.setEnd(end); + events.add(ce); + d.setTime(d.getTime() + 1000 * 60 * 60 * 24); + } + + return events; + } + + }); + addComponent(hl); + addComponent(calendar); + } +} diff --git a/uitest/src/com/vaadin/tests/components/calendar/CalendarHtmlInEventsTest.java b/uitest/src/com/vaadin/tests/components/calendar/CalendarHtmlInEventsTest.java new file mode 100644 index 0000000000..31e3f754e3 --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/calendar/CalendarHtmlInEventsTest.java @@ -0,0 +1,103 @@ +/* + * Copyright 2000-2014 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.tests.components.calendar; + +import org.junit.Assert; +import org.junit.Test; +import org.openqa.selenium.By; +import org.openqa.selenium.WebElement; + +import com.vaadin.testbench.elements.CalendarElement; +import com.vaadin.testbench.elements.CheckBoxElement; +import com.vaadin.testbench.elements.NativeSelectElement; +import com.vaadin.tests.tb3.SingleBrowserTest; + +public class CalendarHtmlInEventsTest extends SingleBrowserTest { + + private NativeSelectElement periodSelect; + private CheckBoxElement htmlAllowed; + private CalendarElement calendar; + + @Override + public void setup() throws Exception { + super.setup(); + openTestURL(); + periodSelect = $(NativeSelectElement.class).first(); + htmlAllowed = $(CheckBoxElement.class).first(); + calendar = $(CalendarElement.class).first(); + } + + @Test + public void monthViewEventCaptions() { + Assert.assertEquals(getMonthEvent(0).getText(), + "12:00 AM Hello world!"); + + // Switch to HTML mode + click(htmlAllowed); + Assert.assertEquals("1. HTML in event caption: true", getLogRow(0)); + + Assert.assertEquals(getMonthEvent(0).getText(), "12:00 AM Hello world!"); + } + + @Test + public void weekViewEventCaptions() { + periodSelect.selectByText("Week"); + Assert.assertEquals("4:00 AM\nHello world!", + getWeekEvent(1).getText()); + + // Switch to HTML mode + click(htmlAllowed); + Assert.assertEquals("1. HTML in event caption: true", getLogRow(0)); + + Assert.assertEquals("4:00 AM\nHello world!", getWeekEvent(1).getText()); + } + + @Test + public void dayViewEventCaptions() { + periodSelect.selectByText("Day"); + Assert.assertEquals("3:00 AM\nHello world!", + getWeekEvent(0).getText()); + + // Switch to HTML mode + click(htmlAllowed); + Assert.assertEquals("1. HTML in event caption: true", getLogRow(0)); + Assert.assertEquals("3:00 AM\nHello world!", getWeekEvent(0).getText()); + } + + private WebElement getMonthEvent(int dayInCalendar) { + return getMonthDay(dayInCalendar).findElement( + By.className("v-calendar-event")); + } + + private WebElement getWeekEvent(int dayInCalendar) { + return getWeekDay(dayInCalendar).findElement( + By.className("v-calendar-event")); + } + + private void click(CheckBoxElement htmlAllowed2) { + htmlAllowed2.findElement(By.xpath("input")).click(); + } + + private WebElement getMonthDay(int i) { + return calendar.findElements(By.className("v-calendar-month-day")).get( + i); + } + + private WebElement getWeekDay(int i) { + return calendar.findElements(By.className("v-calendar-day-times")).get( + i); + } +} -- cgit v1.2.3 From 5360e23a1a6d3f8df30c1b049f857e227b665501 Mon Sep 17 00:00:00 2001 From: Artur Signell Date: Wed, 7 Jan 2015 16:42:26 +0200 Subject: Use API for setting content length on responses (#15504) Change-Id: Ic8f29163442a1476406a1f2b617a4ecaf577ba93 --- server/src/com/vaadin/server/VaadinPortletResponse.java | 8 ++++++++ server/src/com/vaadin/server/VaadinResponse.java | 13 +++++++++++++ .../src/com/vaadin/server/communication/UIInitHandler.java | 2 +- 3 files changed, 22 insertions(+), 1 deletion(-) (limited to 'server/src/com') 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 @@ -96,6 +96,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) { 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/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); -- cgit v1.2.3 From 2e70d1cc9872f2833a07ebf0818b441077daec93 Mon Sep 17 00:00:00 2001 From: Artur Signell Date: Thu, 8 Jan 2015 08:54:05 +0200 Subject: Updated invalid @since Change-Id: I04b0ce4b2a46179d6eeb76d6cca891124cb00804 --- server/src/com/vaadin/ui/AbsoluteLayout.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'server/src/com') 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 -- cgit v1.2.3 From 07e00fe8e09a224be2631df2e1ae2b8cbb46d466 Mon Sep 17 00:00:00 2001 From: Leif Åstrand Date: Sat, 15 Nov 2014 18:24:17 +0200 Subject: Persist scss cache (#15228) Change-Id: I29bf746c3100df15bb04cc03b28ae64db4c5f987 --- .gitignore | 3 + server/src/com/vaadin/server/VaadinServlet.java | 124 +++++++++++++++++++++++- 2 files changed, 123 insertions(+), 4 deletions(-) (limited to 'server/src/com') diff --git a/.gitignore b/.gitignore index 11a0b3db84..1433651abc 100644 --- a/.gitignore +++ b/.gitignore @@ -44,6 +44,9 @@ /WebContent/VAADIN/themes/valo/styles.css /WebContent/VAADIN/themes/tests-valo*/styles.css +# Persisted scss cache files +/WebContent/VAADIN/themes/*/styles.scss.cache + # /WebContent/VAADIN/widgetsets/ /WebContent/VAADIN/widgetsets /WebContent/VAADIN/gwt-unitCache* 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 sourceUris; private final long timestamp; + private final String scssFileName; - public ScssCacheEntry(String css, List sourceUris) { + public ScssCacheEntry(String scssFileName, String css, + List 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(); + + 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 scssCache = new HashMap(); + private final Map scssCache = new HashMap(); + + /** + * 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. -- cgit v1.2.3 From acffa172b9027cc151cf752867eadabfe896c805 Mon Sep 17 00:00:00 2001 From: Denis Anisimov Date: Tue, 4 Nov 2014 13:09:03 +0200 Subject: Wrap null values into JsonNull json objects in bootstrap handler(#14594) Change-Id: I1e03bfd1b4eff77e920208892f030582ff877d78 --- server/src/com/vaadin/server/BootstrapHandler.java | 49 +++++----- .../vaadin/launcher/ApplicationRunnerServlet.java | 34 +++++++ .../tests/requesthandlers/CommunicationError.java | 107 +++++++++++++++++++++ .../requesthandlers/CommunicationErrorTest.java | 41 ++++++++ .../src/com/vaadin/tests/tb3/AbstractTB3Test.java | 3 +- 5 files changed, 208 insertions(+), 26 deletions(-) create mode 100644 uitest/src/com/vaadin/tests/requesthandlers/CommunicationError.java create mode 100644 uitest/src/com/vaadin/tests/requesthandlers/CommunicationErrorTest.java (limited to 'server/src/com') diff --git a/server/src/com/vaadin/server/BootstrapHandler.java b/server/src/com/vaadin/server/BootstrapHandler.java index bfe195ccf9..30e43f48a8 100644 --- a/server/src/com/vaadin/server/BootstrapHandler.java +++ b/server/src/com/vaadin/server/BootstrapHandler.java @@ -513,7 +513,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 +524,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); } @@ -648,4 +637,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/uitest/src/com/vaadin/launcher/ApplicationRunnerServlet.java b/uitest/src/com/vaadin/launcher/ApplicationRunnerServlet.java index 1cbb1aa039..e2b93ab7d2 100644 --- a/uitest/src/com/vaadin/launcher/ApplicationRunnerServlet.java +++ b/uitest/src/com/vaadin/launcher/ApplicationRunnerServlet.java @@ -46,6 +46,9 @@ import com.vaadin.server.LegacyVaadinServlet; import com.vaadin.server.ServiceException; import com.vaadin.server.SessionInitEvent; import com.vaadin.server.SessionInitListener; +import com.vaadin.server.SystemMessages; +import com.vaadin.server.SystemMessagesInfo; +import com.vaadin.server.SystemMessagesProvider; import com.vaadin.server.UIClassSelectionEvent; import com.vaadin.server.UIProvider; import com.vaadin.server.VaadinRequest; @@ -61,6 +64,9 @@ import com.vaadin.util.CurrentInstance; @SuppressWarnings("serial") public class ApplicationRunnerServlet extends LegacyVaadinServlet { + public static String CUSTOM_SYSTEM_MESSAGES_PROPERTY = "custom-" + + SystemMessages.class.getName(); + /** * The name of the application class currently used. Only valid within one * request. @@ -339,6 +345,34 @@ public class ApplicationRunnerServlet extends LegacyVaadinServlet { new ProxyDeploymentConfiguration(originalConfiguration)); } + @Override + protected VaadinServletService createServletService( + DeploymentConfiguration deploymentConfiguration) + throws ServiceException { + VaadinServletService service = super + .createServletService(deploymentConfiguration); + final SystemMessagesProvider provider = service + .getSystemMessagesProvider(); + service.setSystemMessagesProvider(new SystemMessagesProvider() { + + @Override + public SystemMessages getSystemMessages( + SystemMessagesInfo systemMessagesInfo) { + if (systemMessagesInfo.getRequest() == null) { + return provider.getSystemMessages(systemMessagesInfo); + } + Object messages = systemMessagesInfo.getRequest().getAttribute( + CUSTOM_SYSTEM_MESSAGES_PROPERTY); + if (messages instanceof SystemMessages) { + return (SystemMessages) messages; + } + return provider.getSystemMessages(systemMessagesInfo); + } + + }); + return service; + } + private static DeploymentConfiguration findDeploymentConfiguration( DeploymentConfiguration originalConfiguration) throws Exception { // First level of cache diff --git a/uitest/src/com/vaadin/tests/requesthandlers/CommunicationError.java b/uitest/src/com/vaadin/tests/requesthandlers/CommunicationError.java new file mode 100644 index 0000000000..31ec7658ee --- /dev/null +++ b/uitest/src/com/vaadin/tests/requesthandlers/CommunicationError.java @@ -0,0 +1,107 @@ +/* + * Copyright 2000-2014 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.tests.requesthandlers; + +import com.vaadin.launcher.ApplicationRunnerServlet; +import com.vaadin.server.CustomizedSystemMessages; +import com.vaadin.server.SystemMessages; +import com.vaadin.server.UIClassSelectionEvent; +import com.vaadin.server.UIProvider; +import com.vaadin.server.VaadinRequest; +import com.vaadin.server.VaadinService; +import com.vaadin.server.VaadinServletRequest; +import com.vaadin.tests.components.AbstractTestUI; +import com.vaadin.ui.Button; +import com.vaadin.ui.Button.ClickEvent; +import com.vaadin.ui.Label; +import com.vaadin.ui.UI; + +/** + * Test UI provider to check communication error json object null values. + * + * @author Vaadin Ltd + */ +public class CommunicationError extends UIProvider { + + @Override + public Class getUIClass(UIClassSelectionEvent event) { + VaadinServletRequest request = (VaadinServletRequest) event + .getRequest(); + String currentUrl = request.getRequestURL().toString(); + StringBuilder redirectClass = new StringBuilder( + CommunicationError.class.getSimpleName()); + redirectClass.append('$'); + redirectClass.append(RedirectedUI.class.getSimpleName()); + + String restartApplication = "?restartApplication"; + if (!currentUrl.contains(restartApplication)) { + redirectClass.append(restartApplication); + } + final String url = currentUrl.replace( + CommunicationError.class.getSimpleName(), redirectClass); + + request.setAttribute( + ApplicationRunnerServlet.CUSTOM_SYSTEM_MESSAGES_PROPERTY, + createSystemMessages(url)); + + return CommunicationErrorUI.class; + } + + public static class CommunicationErrorUI extends AbstractTestUI { + + @Override + protected void setup(VaadinRequest request) { + Button button = new Button("Send bad request", + new Button.ClickListener() { + + @Override + public void buttonClick(ClickEvent event) { + VaadinService.getCurrentResponse().setStatus(400); + } + }); + addComponent(button); + } + + @Override + protected Integer getTicketNumber() { + return 14594; + } + + @Override + protected String getTestDescription() { + return "Null values should be wrapped into JsonNull objects."; + } + } + + public static class RedirectedUI extends UI { + + @Override + protected void init(VaadinRequest request) { + Label label = new Label("redirected"); + label.addStyleName("redirected"); + setContent(label); + } + + } + + private SystemMessages createSystemMessages(String url) { + CustomizedSystemMessages messages = new CustomizedSystemMessages(); + messages.setCommunicationErrorCaption(null); + messages.setCommunicationErrorMessage(null); + messages.setCommunicationErrorURL(url); + return messages; + } +} diff --git a/uitest/src/com/vaadin/tests/requesthandlers/CommunicationErrorTest.java b/uitest/src/com/vaadin/tests/requesthandlers/CommunicationErrorTest.java new file mode 100644 index 0000000000..f295ec5ba3 --- /dev/null +++ b/uitest/src/com/vaadin/tests/requesthandlers/CommunicationErrorTest.java @@ -0,0 +1,41 @@ +/* + * Copyright 2000-2014 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.tests.requesthandlers; + +import org.junit.Assert; +import org.junit.Test; +import org.openqa.selenium.By; + +import com.vaadin.testbench.elements.ButtonElement; +import com.vaadin.tests.tb3.MultiBrowserTest; + +/** + * Test for null values in communication error json object . + * + * @author Vaadin Ltd + */ +public class CommunicationErrorTest extends MultiBrowserTest { + + @Test + public void testRedirection() { + openTestURL(); + + $(ButtonElement.class).first().click(); + + Assert.assertTrue(isElementPresent(By.className("redirected"))); + } + +} diff --git a/uitest/src/com/vaadin/tests/tb3/AbstractTB3Test.java b/uitest/src/com/vaadin/tests/tb3/AbstractTB3Test.java index b5a345bd30..2e3d25cbbe 100644 --- a/uitest/src/com/vaadin/tests/tb3/AbstractTB3Test.java +++ b/uitest/src/com/vaadin/tests/tb3/AbstractTB3Test.java @@ -837,7 +837,8 @@ public abstract class AbstractTB3Test extends TestBenchTestCase { runPath = "/run-push"; } - if (UI.class.isAssignableFrom(uiClass)) { + if (UI.class.isAssignableFrom(uiClass) + || UIProvider.class.isAssignableFrom(uiClass)) { return runPath + "/" + uiClass.getCanonicalName() + (isDebug() ? "?debug" : ""); } else if (LegacyApplication.class.isAssignableFrom(uiClass)) { -- cgit v1.2.3 From 65904ffbdebc861a45c1b504d244d02a12f4561b Mon Sep 17 00:00:00 2001 From: Fabian Lange Date: Wed, 23 Jul 2014 22:40:35 +0200 Subject: Appending query param with vaadin version to js files (#12210) while #7868 is supposed to solve the overall issue, this solves a big part of the upgrade + cached files issues quickly. When I use vaadin themes, I have control over how they are included, so I can add a vaadin version number to it. For the default JS I cannot. Change-Id: Ica1cddee417946aa32116eb09882a3dc6c2924a6 --- WebContent/VAADIN/vaadinBootstrap.js | 16 ++++++++++++---- .../communication/AtmospherePushConnection.java | 21 ++++++++++++++------- client/src/com/vaadin/client/ui/ui/UIConnector.java | 7 ++++++- server/src/com/vaadin/server/BootstrapHandler.java | 9 +++++++-- 4 files changed, 39 insertions(+), 14 deletions(-) (limited to 'server/src/com') diff --git a/WebContent/VAADIN/vaadinBootstrap.js b/WebContent/VAADIN/vaadinBootstrap.js index ced077138f..53b213e110 100644 --- a/WebContent/VAADIN/vaadinBootstrap.js +++ b/WebContent/VAADIN/vaadinBootstrap.js @@ -18,13 +18,19 @@ log = console.log; } - var loadTheme = function(url) { + var loadTheme = function(url, version) { if(!themesLoaded[url]) { - log("loadTheme", url); + log("loadTheme", url, version); + + var href = url + '/styles.css'; + if (version) { + href += '?v=' + version; + } + var stylesheet = document.createElement('link'); stylesheet.setAttribute('rel', 'stylesheet'); stylesheet.setAttribute('type', 'text/css'); - stylesheet.setAttribute('href', url + "/styles.css"); + stylesheet.setAttribute('href', href); document.getElementsByTagName('head')[0].appendChild(stylesheet); themesLoaded[url] = true; } @@ -200,8 +206,10 @@ var bootstrapApp = function(mayDefer) { var vaadinDir = getConfig('vaadinDir'); + var versionInfo = getConfig('versionInfo'); + var themeUri = vaadinDir + 'themes/' + getConfig('theme'); - loadTheme(themeUri); + loadTheme(themeUri, versionInfo && versionInfo['vaadinVersion']); var widgetset = getConfig('widgetset'); var widgetsetUrl = getConfig('widgetsetUrl'); diff --git a/client/src/com/vaadin/client/communication/AtmospherePushConnection.java b/client/src/com/vaadin/client/communication/AtmospherePushConnection.java index a2c4dd8323..d10449ccaa 100644 --- a/client/src/com/vaadin/client/communication/AtmospherePushConnection.java +++ b/client/src/com/vaadin/client/communication/AtmospherePushConnection.java @@ -31,6 +31,7 @@ import com.vaadin.client.ResourceLoader.ResourceLoadEvent; import com.vaadin.client.ResourceLoader.ResourceLoadListener; import com.vaadin.client.VConsole; import com.vaadin.shared.ApplicationConstants; +import com.vaadin.shared.Version; import com.vaadin.shared.communication.PushConstants; import com.vaadin.shared.ui.ui.UIConstants; import com.vaadin.shared.ui.ui.UIState.PushConfigurationState; @@ -514,16 +515,10 @@ public class AtmospherePushConnection implements PushConnection { }-*/; private void runWhenAtmosphereLoaded(final Command command) { - if (isAtmosphereLoaded()) { command.execute(); } else { - final String pushJs; - if (ApplicationConfiguration.isProductionMode()) { - pushJs = ApplicationConstants.VAADIN_PUSH_JS; - } else { - pushJs = ApplicationConstants.VAADIN_PUSH_DEBUG_JS; - } + final String pushJs = getVersionedPushJs(); VConsole.log("Loading " + pushJs); ResourceLoader.get().loadScript( @@ -553,6 +548,18 @@ public class AtmospherePushConnection implements PushConnection { } } + private String getVersionedPushJs() { + String pushJs; + if (ApplicationConfiguration.isProductionMode()) { + pushJs = ApplicationConstants.VAADIN_PUSH_JS; + } else { + pushJs = ApplicationConstants.VAADIN_PUSH_DEBUG_JS; + } + // Parameter appended to bypass caches after version upgrade. + pushJs += "?v=" + Version.getFullVersion(); + return pushJs; + } + /* * (non-Javadoc) * diff --git a/client/src/com/vaadin/client/ui/ui/UIConnector.java b/client/src/com/vaadin/client/ui/ui/UIConnector.java index d6f14bf158..9e1da113bf 100644 --- a/client/src/com/vaadin/client/ui/ui/UIConnector.java +++ b/client/src/com/vaadin/client/ui/ui/UIConnector.java @@ -76,6 +76,7 @@ import com.vaadin.client.ui.window.WindowConnector; import com.vaadin.server.Page.Styles; import com.vaadin.shared.ApplicationConstants; import com.vaadin.shared.MouseEventDetails; +import com.vaadin.shared.Version; import com.vaadin.shared.communication.MethodInvocation; import com.vaadin.shared.ui.ComponentStateUtil; import com.vaadin.shared.ui.Connect; @@ -1014,9 +1015,13 @@ public class UIConnector extends AbstractSingleComponentContainerConnector * @return The URL the theme can be loaded from */ private String getThemeUrl(String theme) { - return getConnection().translateVaadinUri( + String themeUrl = getConnection().translateVaadinUri( ApplicationConstants.VAADIN_PROTOCOL_PREFIX + "themes/" + theme + "/styles" + ".css"); + // Parameter appended to bypass caches after version upgrade. + themeUrl += "?v=" + Version.getFullVersion(); + return themeUrl; + } /** diff --git a/server/src/com/vaadin/server/BootstrapHandler.java b/server/src/com/vaadin/server/BootstrapHandler.java index 30e43f48a8..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( @@ -613,7 +618,7 @@ public abstract class BootstrapHandler extends SynchronizedRequestHandler { } /** - * Don not override. + * Do not override. * * @param context * @return -- cgit v1.2.3 From 3f27e02f121c0a39b217532afcf9530bfd2caba7 Mon Sep 17 00:00:00 2001 From: Leif Åstrand Date: Sat, 10 Jan 2015 13:36:51 +0200 Subject: Cache reference diffstate values (#15561) Benchmarked with the "Set 40 panels as content" action in BasicPerformanceTest. This is really a worst case scenario since it doesn't do anything else than create lots of components, whereas more common use cases would spend more time updating existing components or executing business logic instead. Without this patch, each action spent about 6 ms creating reference diffstate values, making up about 20% of the total processing time. With the patch applied, the time (including the new map lookup) was reduced to around 0.2 ms and the total processing time was also reduced accordingly. Change-Id: If22a73b591b87793c78cb360bcfa8e030f003730 --- .../vaadin/server/LegacyCommunicationManager.java | 33 ++++++++++++++-------- 1 file changed, 22 insertions(+), 11 deletions(-) (limited to 'server/src/com') 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, JsonValue> referenceDiffStates = new ConcurrentHashMap, 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 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 -- cgit v1.2.3