From 2772641acf8f84046e3ac42c8386b65e4f2346f2 Mon Sep 17 00:00:00 2001 From: Johannes Dahlström Date: Mon, 13 May 2013 17:34:16 +0300 Subject: OSGi support for vaadin-push (#11691) * Require atmosphere-runtime in vaadin-push with visibility:=reexport * Require vaadin-push in vaadin-server with resolution:=optional Serving vaadinPush.js from vaadin-push will be handled by Florian's OSGi addon Change-Id: Ida3e1ae95eb17b0114e099d1425db73106aaeead --- push/build.xml | 11 +++++++---- push/ivy.xml | 3 +-- server/build.xml | 3 ++- 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/push/build.xml b/push/build.xml index 95284e6e37..d06b946dd1 100644 --- a/push/build.xml +++ b/push/build.xml @@ -11,6 +11,11 @@ + + + + + @@ -24,7 +29,7 @@ - + @@ -47,10 +52,8 @@ - - - + diff --git a/push/ivy.xml b/push/ivy.xml index 153c02e256..a5ca79d4a3 100644 --- a/push/ivy.xml +++ b/push/ivy.xml @@ -20,8 +20,6 @@ - - @@ -29,6 +27,7 @@ rev="2.4" conf="build-provided,ide,test -> default" /> + diff --git a/server/build.xml b/server/build.xml index d61f412883..1c84c7e6f5 100644 --- a/server/build.xml +++ b/server/build.xml @@ -24,8 +24,9 @@ + - + -- cgit v1.2.3 From 34e6c60a5a746c0306c3a84ae8d6c21dfd84d878 Mon Sep 17 00:00:00 2001 From: Leif Åstrand Date: Mon, 20 May 2013 16:45:56 +0300 Subject: Always add tooltip event handlers for Window (#11448) This is needed to ensure tooltips are closed when moving the mouse outside the component but still inside the window. In 7.1, this should instead be implemented by overriding hasTooltip() to return true. Merge: manual Change-Id: I48d47474a4e4f0303fd85552612f6960fcdce0a7 --- .../src/com/vaadin/client/ui/window/WindowConnector.java | 11 +++++++++++ .../vaadin/tests/components/window/TooltipInWindow.html | 16 ++++++++++++++++ 2 files changed, 27 insertions(+) diff --git a/client/src/com/vaadin/client/ui/window/WindowConnector.java b/client/src/com/vaadin/client/ui/window/WindowConnector.java index 8cfc25a9dc..a394a33882 100644 --- a/client/src/com/vaadin/client/ui/window/WindowConnector.java +++ b/client/src/com/vaadin/client/ui/window/WindowConnector.java @@ -29,6 +29,7 @@ import com.vaadin.client.ComponentConnector; import com.vaadin.client.ConnectorHierarchyChangeEvent; import com.vaadin.client.LayoutManager; import com.vaadin.client.Paintable; +import com.vaadin.client.TooltipInfo; import com.vaadin.client.UIDL; import com.vaadin.client.Util; import com.vaadin.client.ui.AbstractSingleComponentContainerConnector; @@ -312,4 +313,14 @@ public class WindowConnector extends AbstractSingleComponentContainerConnector public void setWindowOrderAndPosition() { getWidget().setWindowOrderAndPosition(); } + + @Override + public TooltipInfo getTooltipInfo(com.google.gwt.dom.client.Element element) { + /* + * Override method to make AbstractComponentConnector.hasTooltip() + * return true so there's a top level handler that takes care of hiding + * tooltips whenever the mouse is moved somewhere else. + */ + return super.getTooltipInfo(element); + } } diff --git a/uitest/src/com/vaadin/tests/components/window/TooltipInWindow.html b/uitest/src/com/vaadin/tests/components/window/TooltipInWindow.html index d734cab9ea..63e371e379 100644 --- a/uitest/src/com/vaadin/tests/components/window/TooltipInWindow.html +++ b/uitest/src/com/vaadin/tests/components/window/TooltipInWindow.html @@ -64,6 +64,22 @@ vaadin=runcomvaadintestscomponentswindowTooltipInWindow::Root/VTooltip[0]/FlowPanel[0]/domChild[1] My tooltip + + + showTooltip + vaadin=runcomvaadintestscomponentswindowTooltipInWindow::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0] + 0,0 + + + pause + 1000 + + + + assertElementNotPresent + vaadin=runcomvaadintestscomponentswindowTooltipInWindow::Root/VTooltip[0]/FlowPanel[0]/domChild[1] + + -- cgit v1.2.3 From 42c4b2097bc955ca18107c449e04f0d5d5683ca3 Mon Sep 17 00:00:00 2001 From: Johannes Dahlström Date: Mon, 20 May 2013 15:08:48 +0300 Subject: Use "\0" instead of "|" as a push message delimiter (#11692) Used with TrackMessageSizeInterceptor and with client-to-server Websocket message splitting (see #11648) The original issue that the delimiter can not appear in the message (unescaped) is apparently fixed in Atmosphere 1.0.13 Also ensure the max size of a websocket fragment in bytes does not exceed the buffer size (#11842) Change-Id: I768524bb54a5b8b9479dc7bda821256bd843dc52 --- .../communication/AtmospherePushConnection.java | 11 ++++-- .../communication/AtmospherePushConnection.java | 9 +++-- .../server/communication/PushRequestHandler.java | 17 +++++--- .../com/vaadin/shared/ApplicationConstants.java | 4 -- .../vaadin/shared/communication/PushConstants.java | 46 ++++++++++++++++++++++ 5 files changed, 69 insertions(+), 18 deletions(-) create mode 100644 shared/src/com/vaadin/shared/communication/PushConstants.java diff --git a/client/src/com/vaadin/client/communication/AtmospherePushConnection.java b/client/src/com/vaadin/client/communication/AtmospherePushConnection.java index bc7e0b3fd2..ce3253ed50 100644 --- a/client/src/com/vaadin/client/communication/AtmospherePushConnection.java +++ b/client/src/com/vaadin/client/communication/AtmospherePushConnection.java @@ -27,6 +27,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.communication.PushConstants; import com.vaadin.shared.ui.ui.UIConstants; /** @@ -67,8 +68,7 @@ public class AtmospherePushConnection implements PushConnection { */ protected static class FragmentedMessage { - // Jetty requires length less than buffer size - private int FRAGMENT_LENGTH = ApplicationConstants.WEBSOCKET_BUFFER_SIZE - 1; + private static final int FRAGMENT_LENGTH = PushConstants.WEBSOCKET_FRAGMENT_SIZE; private String message; private int index = 0; @@ -82,10 +82,12 @@ public class AtmospherePushConnection implements PushConnection { } public String getNextFragment() { + assert hasNextFragment(); + String result; if (index == 0) { String header = "" + message.length() - + ApplicationConstants.WEBSOCKET_MESSAGE_DELIMITER; + + PushConstants.MESSAGE_DELIMITER; int fragmentLen = FRAGMENT_LENGTH - header.length(); result = header + getFragment(0, fragmentLen); index += fragmentLen; @@ -384,7 +386,8 @@ public class AtmospherePushConnection implements PushConnection { contentType: 'application/json; charset=UTF-8', reconnectInterval: '5000', maxReconnectOnClose: 10000000, - trackMessageLength: true + trackMessageLength: true, + messageDelimiter: String.fromCharCode(@com.vaadin.shared.communication.PushConstants::MESSAGE_DELIMITER) }; }-*/; diff --git a/server/src/com/vaadin/server/communication/AtmospherePushConnection.java b/server/src/com/vaadin/server/communication/AtmospherePushConnection.java index 0bba65ff1d..96507b55f1 100644 --- a/server/src/com/vaadin/server/communication/AtmospherePushConnection.java +++ b/server/src/com/vaadin/server/communication/AtmospherePushConnection.java @@ -32,7 +32,7 @@ import org.atmosphere.cpr.AtmosphereResource; import org.atmosphere.cpr.AtmosphereResource.TRANSPORT; import org.json.JSONException; -import com.vaadin.shared.ApplicationConstants; +import com.vaadin.shared.communication.PushConstants; import com.vaadin.ui.UI; /** @@ -52,11 +52,12 @@ public class AtmospherePushConnection implements Serializable, PushConnection { private final int messageLength; public FragmentedMessage(Reader reader) throws IOException { - // Messages are prefixed by the total message length plus '|' + // Messages are prefixed by the total message length plus a + // delimiter String length = ""; int c; while ((c = reader.read()) != -1 - && c != ApplicationConstants.WEBSOCKET_MESSAGE_DELIMITER) { + && c != PushConstants.MESSAGE_DELIMITER) { length += (char) c; } try { @@ -76,7 +77,7 @@ public class AtmospherePushConnection implements Serializable, PushConnection { * @throws IOException */ public boolean append(Reader reader) throws IOException { - char[] buffer = new char[ApplicationConstants.WEBSOCKET_BUFFER_SIZE]; + char[] buffer = new char[PushConstants.WEBSOCKET_BUFFER_SIZE]; int read; while ((read = reader.read(buffer)) != -1) { message.append(buffer, 0, read); diff --git a/server/src/com/vaadin/server/communication/PushRequestHandler.java b/server/src/com/vaadin/server/communication/PushRequestHandler.java index 8360e08af9..e75798a980 100644 --- a/server/src/com/vaadin/server/communication/PushRequestHandler.java +++ b/server/src/com/vaadin/server/communication/PushRequestHandler.java @@ -23,6 +23,7 @@ import javax.servlet.ServletException; import org.atmosphere.client.TrackMessageSizeInterceptor; import org.atmosphere.cpr.ApplicationConfig; import org.atmosphere.cpr.AtmosphereFramework; +import org.atmosphere.cpr.AtmosphereInterceptor; import org.atmosphere.cpr.AtmosphereRequest; import org.atmosphere.cpr.AtmosphereResponse; @@ -36,7 +37,7 @@ import com.vaadin.server.VaadinServletRequest; import com.vaadin.server.VaadinServletResponse; import com.vaadin.server.VaadinServletService; import com.vaadin.server.VaadinSession; -import com.vaadin.shared.ApplicationConstants; +import com.vaadin.shared.communication.PushConstants; /** * Handles requests to open a push (bidirectional) communication channel between @@ -61,9 +62,11 @@ public class PushRequestHandler implements RequestHandler, atmosphere.addAtmosphereHandler("/*", pushHandler); atmosphere.addInitParameter(ApplicationConfig.PROPERTY_SESSION_SUPPORT, "true"); + atmosphere.addInitParameter(ApplicationConfig.MESSAGE_DELIMITER, + String.valueOf(PushConstants.MESSAGE_DELIMITER)); final String bufferSize = String - .valueOf(ApplicationConstants.WEBSOCKET_BUFFER_SIZE); + .valueOf(PushConstants.WEBSOCKET_BUFFER_SIZE); atmosphere.addInitParameter(ApplicationConfig.WEBSOCKET_BUFFER_SIZE, bufferSize); atmosphere.addInitParameter(ApplicationConfig.WEBSOCKET_MAXTEXTSIZE, @@ -75,12 +78,14 @@ public class PushRequestHandler implements RequestHandler, atmosphere.addInitParameter("org.atmosphere.cpr.showSupportMessage", "false"); - // Required to ensure the client-side knows at which points to split the - // message stream into individual messages when using certain transports - atmosphere.interceptor(new TrackMessageSizeInterceptor()); - try { atmosphere.init(service.getServlet().getServletConfig()); + + // Ensure the client-side knows how to split the message stream + // into individual messages when using certain transports + AtmosphereInterceptor trackMessageSize = new TrackMessageSizeInterceptor(); + trackMessageSize.configure(atmosphere.getAtmosphereConfig()); + atmosphere.interceptor(trackMessageSize); } catch (ServletException e) { throw new ServiceException("Could not read atmosphere settings", e); } diff --git a/shared/src/com/vaadin/shared/ApplicationConstants.java b/shared/src/com/vaadin/shared/ApplicationConstants.java index fc4abd1988..04cba79c0c 100644 --- a/shared/src/com/vaadin/shared/ApplicationConstants.java +++ b/shared/src/com/vaadin/shared/ApplicationConstants.java @@ -83,8 +83,4 @@ public class ApplicationConstants implements Serializable { * Name of the parameter used to transmit the CSRF token. */ public static final String CSRF_TOKEN_PARAMETER = "v-csrfToken"; - - public static final int WEBSOCKET_BUFFER_SIZE = 65536; - - public static final char WEBSOCKET_MESSAGE_DELIMITER = '|'; } diff --git a/shared/src/com/vaadin/shared/communication/PushConstants.java b/shared/src/com/vaadin/shared/communication/PushConstants.java new file mode 100644 index 0000000000..2d63621c12 --- /dev/null +++ b/shared/src/com/vaadin/shared/communication/PushConstants.java @@ -0,0 +1,46 @@ +/* + * Copyright 2000-2013 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.shared.communication; + +import java.io.Serializable; + +/** + * Shared constants used by push. + * + * @since 7.1 + * @author Vaadin Ltd + */ +public class PushConstants implements Serializable { + + /** + * The size, in bytes, of the receiving buffer used by some servers. + */ + public static final int WEBSOCKET_BUFFER_SIZE = 65536; + + /** + * The maximum size, in characters, of a websocket message fragment. + * This is a conservative maximum chosen so that the size in bytes will not + * exceed {@link PushConstants#WEBSOCKET_BUFFER_SIZE} given a UTF-8 encoded + * message. + */ + public static final int WEBSOCKET_FRAGMENT_SIZE = WEBSOCKET_BUFFER_SIZE / 4 - 1; + + /** + * The character used to mark message boundaries when messages may be split + * into multiple fragments. + */ + public static final char MESSAGE_DELIMITER = '\0'; +} -- cgit v1.2.3 From b1390c580cf5e9ad6adbb6067007d03fb69a92cc Mon Sep 17 00:00:00 2001 From: Marc Englund Date: Tue, 21 May 2013 11:39:09 +0300 Subject: Don't autoclose PopupView when changing fragment, fixes #10530 Change-Id: I83607c97db8499c5e3c76e6d4735a93b0754d580 Ticket: 10530 --- client/src/com/vaadin/client/ui/VPopupView.java | 2 + .../components/popupview/PopupViewAndFragment.html | 32 +++++++++++++ .../components/popupview/PopupViewAndFragment.java | 54 ++++++++++++++++++++++ 3 files changed, 88 insertions(+) create mode 100644 uitest/src/com/vaadin/tests/components/popupview/PopupViewAndFragment.html create mode 100644 uitest/src/com/vaadin/tests/components/popupview/PopupViewAndFragment.java diff --git a/client/src/com/vaadin/client/ui/VPopupView.java b/client/src/com/vaadin/client/ui/VPopupView.java index d983da2b62..737dc04968 100644 --- a/client/src/com/vaadin/client/ui/VPopupView.java +++ b/client/src/com/vaadin/client/ui/VPopupView.java @@ -102,6 +102,8 @@ public class VPopupView extends HTML implements Iterable { }); popup.setAnimationEnabled(true); + + popup.setAutoHideOnHistoryEventsEnabled(false); } /** For internal use only. May be removed or replaced in the future. */ diff --git a/uitest/src/com/vaadin/tests/components/popupview/PopupViewAndFragment.html b/uitest/src/com/vaadin/tests/components/popupview/PopupViewAndFragment.html new file mode 100644 index 0000000000..28af578bac --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/popupview/PopupViewAndFragment.html @@ -0,0 +1,32 @@ + + + + + + +PopupViewAndFragment + + + + + + + + + + + + + + + + + + + + + + +
PopupViewAndFragment
open/run/PopupViewAndFragment?restartApplication#
clickvaadin=runPopupViewAndFragment::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[1]/VButton[0]/domChild[0]/domChild[0]
screenCapture
+ + diff --git a/uitest/src/com/vaadin/tests/components/popupview/PopupViewAndFragment.java b/uitest/src/com/vaadin/tests/components/popupview/PopupViewAndFragment.java new file mode 100644 index 0000000000..1606b78604 --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/popupview/PopupViewAndFragment.java @@ -0,0 +1,54 @@ +/* + * Copyright 2000-2013 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.popupview; + +import com.vaadin.server.VaadinRequest; +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.PopupView; + +public class PopupViewAndFragment extends AbstractTestUI { + + @Override + protected void setup(VaadinRequest request) { + final PopupView pw = new PopupView("Open", new Label("Oh, hi")); + addComponent(pw); + + final Button button = new Button("Open and change fragment", + new Button.ClickListener() { + @Override + public void buttonClick(final ClickEvent event) { + pw.setPopupVisible(true); + getPage().setUriFragment( + String.valueOf(System.currentTimeMillis())); + } + }); + addComponent(button); + } + + @Override + protected String getTestDescription() { + return "Changing frament should not automatically close PopupView"; + } + + @Override + protected Integer getTicketNumber() { + return 10530; + } + +} -- cgit v1.2.3 From 778de066b1f8b1608b40bdd98b61b6fee078442d Mon Sep 17 00:00:00 2001 From: Leif Åstrand Date: Tue, 21 May 2013 13:33:44 +0300 Subject: Derive current servlet/portlet from the current service (#11779) Implement VaadinPortlet.getCurrent() to use VaadinService.getCurrent() instead of having a separate thread local variable. This is done to avoid classloading issues when determining which instances to preserve in CurrentInstance.setThreadLocals. The two current instances have previously been kept in sync in all cases except during VaadinPortlet.init where VaadinService has not yet been created. VaadinPortlet.setCurrent() is removed as no way of preserving its semantics has been found. This breaks API compatibility, but is probably better than having a deprecated implementation that can not work as expected in all situations. The same changes have also been made to VaadinServlet to maintain the symmetry. Change-Id: I0a1ccc07a4aeecec558a9aaae211bd56207313d8 --- server/src/com/vaadin/server/VaadinPortlet.java | 35 ++++++------------- server/src/com/vaadin/server/VaadinServlet.java | 45 ++++++++++--------------- server/src/com/vaadin/util/CurrentInstance.java | 26 -------------- 3 files changed, 28 insertions(+), 78 deletions(-) diff --git a/server/src/com/vaadin/server/VaadinPortlet.java b/server/src/com/vaadin/server/VaadinPortlet.java index 327ce78a6c..d86e5e6507 100644 --- a/server/src/com/vaadin/server/VaadinPortlet.java +++ b/server/src/com/vaadin/server/VaadinPortlet.java @@ -287,7 +287,6 @@ public class VaadinPortlet extends GenericPortlet implements Constants, @Override public void init(PortletConfig config) throws PortletException { CurrentInstance.clearAll(); - setCurrent(this); super.init(config); Properties initParameters = new Properties(); @@ -407,7 +406,6 @@ public class VaadinPortlet extends GenericPortlet implements Constants, PortletResponse response) throws PortletException, IOException { CurrentInstance.clearAll(); - setCurrent(this); try { getService().handleRequest(createVaadinRequest(request), createVaadinResponse(response)); @@ -495,36 +493,23 @@ public class VaadinPortlet extends GenericPortlet implements Constants, * portlet is defined (see {@link InheritableThreadLocal}). In other cases, * (e.g. from background threads started in some other way), the current * portlet is not automatically defined. + *

+ * The current portlet is derived from the current service using + * {@link VaadinService#getCurrent()} * * @return the current vaadin portlet instance if available, otherwise * null * - * @see #setCurrent(VaadinPortlet) - * * @since 7.0 */ public static VaadinPortlet getCurrent() { - return CurrentInstance.get(VaadinPortlet.class); - } - - /** - * Sets the current Vaadin portlet. This method is used by the framework to - * set the current portlet whenever a new request is processed and it is - * cleared when the request has been processed. - *

- * The application developer can also use this method to define the current - * portlet outside the normal request handling, e.g. when initiating custom - * background threads. - *

- * - * @param portlet - * the Vaadin portlet to register as the current portlet - * - * @see #getCurrent() - * @see InheritableThreadLocal - */ - public static void setCurrent(VaadinPortlet portlet) { - CurrentInstance.setInheritable(VaadinPortlet.class, portlet); + VaadinService vaadinService = CurrentInstance.get(VaadinService.class); + if (vaadinService instanceof VaadinPortletService) { + VaadinPortletService vps = (VaadinPortletService) vaadinService; + return vps.getPortlet(); + } else { + return null; + } } } diff --git a/server/src/com/vaadin/server/VaadinServlet.java b/server/src/com/vaadin/server/VaadinServlet.java index de074941c1..6f166db2b5 100644 --- a/server/src/com/vaadin/server/VaadinServlet.java +++ b/server/src/com/vaadin/server/VaadinServlet.java @@ -63,7 +63,6 @@ public class VaadinServlet extends HttpServlet implements Constants { public void init(javax.servlet.ServletConfig servletConfig) throws ServletException { CurrentInstance.clearAll(); - setCurrent(this); super.init(servletConfig); Properties initParameters = new Properties(); @@ -108,36 +107,23 @@ public class VaadinServlet extends HttpServlet implements Constants { * servlet is defined (see {@link InheritableThreadLocal}). In other cases, * (e.g. from background threads started in some other way), the current * servlet is not automatically defined. + *

+ * The current servlet is derived from the current service using + * {@link VaadinService#getCurrent()} * * @return the current Vaadin servlet instance if available, otherwise * null * - * @see #setCurrent(VaadinServlet) - * * @since 7.0 */ public static VaadinServlet getCurrent() { - return CurrentInstance.get(VaadinServlet.class); - } - - /** - * Sets the current Vaadin servlet. This method is used by the framework to - * set the current servlet whenever a new request is processed and it is - * cleared when the request has been processed. - *

- * The application developer can also use this method to define the current - * servlet outside the normal request handling, e.g. when initiating custom - * background threads. - *

- * - * @param servlet - * the Vaadin servlet to register as the current servlet - * - * @see #getCurrent() - * @see InheritableThreadLocal - */ - public static void setCurrent(VaadinServlet servlet) { - CurrentInstance.setInheritable(VaadinServlet.class, servlet); + VaadinService vaadinService = CurrentInstance.get(VaadinService.class); + if (vaadinService instanceof VaadinServletService) { + VaadinServletService vss = (VaadinServletService) vaadinService; + return vss.getServlet(); + } else { + return null; + } } protected DeploymentConfiguration createDeploymentConfiguration( @@ -179,7 +165,6 @@ public class VaadinServlet extends HttpServlet implements Constants { return; } CurrentInstance.clearAll(); - setCurrent(this); VaadinServletRequest vaadinRequest = createVaadinRequest(request); VaadinServletResponse vaadinResponse = createVaadinResponse(response); @@ -188,8 +173,14 @@ public class VaadinServlet extends HttpServlet implements Constants { } if (isStaticResourceRequest(request)) { - serveStaticResources(request, response); - return; + // Define current servlet and service, but no request and response + getService().setCurrentInstances(null, null); + try { + serveStaticResources(request, response); + return; + } finally { + CurrentInstance.clearAll(); + } } try { getService().handleRequest(vaadinRequest, vaadinResponse); diff --git a/server/src/com/vaadin/util/CurrentInstance.java b/server/src/com/vaadin/util/CurrentInstance.java index 60489d596e..0854d422fd 100644 --- a/server/src/com/vaadin/util/CurrentInstance.java +++ b/server/src/com/vaadin/util/CurrentInstance.java @@ -22,12 +22,10 @@ import java.util.Map; import java.util.Map.Entry; import com.vaadin.server.VaadinPortlet; -import com.vaadin.server.VaadinPortletService; import com.vaadin.server.VaadinRequest; import com.vaadin.server.VaadinResponse; import com.vaadin.server.VaadinService; import com.vaadin.server.VaadinServlet; -import com.vaadin.server.VaadinServletService; import com.vaadin.server.VaadinSession; import com.vaadin.ui.UI; @@ -52,18 +50,6 @@ public class CurrentInstance implements Serializable { private final Object instance; private final boolean inheritable; - private static boolean portletAvailable = false; - { - try { - /* - * VaadinPortlet depends on portlet API which is available only if - * running in a portal. - */ - portletAvailable = (VaadinPortlet.class.getName() != null); - } catch (Throwable t) { - } - } - private static InheritableThreadLocal, CurrentInstance>> instances = new InheritableThreadLocal, CurrentInstance>>() { @Override protected Map, CurrentInstance> childValue( @@ -236,18 +222,6 @@ public class CurrentInstance implements Serializable { VaadinSession.setCurrent(session); VaadinService.setCurrent(service); - if (service instanceof VaadinServletService) { - old.put(VaadinServlet.class, - new CurrentInstance(VaadinServlet.getCurrent(), true)); - VaadinServlet.setCurrent(((VaadinServletService) service) - .getServlet()); - } else if (portletAvailable && service instanceof VaadinPortletService) { - old.put(VaadinPortlet.class, - new CurrentInstance(VaadinPortlet.getCurrent(), true)); - VaadinPortlet.setCurrent(((VaadinPortletService) service) - .getPortlet()); - } - return old; } } -- cgit v1.2.3 From f8fb8b7bfdbf4d8c22ca512e937fe812803369c6 Mon Sep 17 00:00:00 2001 From: Johannes Dahlström Date: Tue, 21 May 2013 10:18:22 +0300 Subject: Upgrade to Atmosphere 1.0.13 (#11861) Change-Id: Ie9281ff5e9805be89942bf3ca8259740f49e15ab --- .classpath | 1 - WebContent/VAADIN/jquery.atmosphere.js | 553 +++--- push/build.xml | 3 +- push/ivy.xml | 2 +- .../org/atmosphere/cpr/AtmosphereFramework.java | 1779 -------------------- server/src/com/vaadin/server/Constants.java | 4 +- .../vaadin/shared/communication/PushConstants.java | 2 +- 7 files changed, 286 insertions(+), 2058 deletions(-) delete mode 100644 push/src/org/atmosphere/cpr/AtmosphereFramework.java diff --git a/.classpath b/.classpath index 381f0d280d..c6230a2c55 100644 --- a/.classpath +++ b/.classpath @@ -11,7 +11,6 @@ - diff --git a/WebContent/VAADIN/jquery.atmosphere.js b/WebContent/VAADIN/jquery.atmosphere.js index e9def6ae95..2b176668c1 100644 --- a/WebContent/VAADIN/jquery.atmosphere.js +++ b/WebContent/VAADIN/jquery.atmosphere.js @@ -49,7 +49,7 @@ jQuery.atmosphere = function() { }; return { - version : "1.0.12", + version : "1.0.13", requests : [], callbacks : [], @@ -138,13 +138,16 @@ jQuery.atmosphere = function() { */ var _response = { status: 200, + reasonPhrase : "OK", responseBody : '', + messages : [], headers : [], state : "messageReceived", transport : "polling", error: null, request : null, partialMessage : "", + errorHandled: false, id : 0 }; @@ -682,19 +685,21 @@ jQuery.atmosphere = function() { _close(); }; - _response.request = request; - var prevState = _response.state; - _response.state = state; - _response.status = 200; - var prevTransport = _response.transport; - _response.transport = transport; + if (_response.error == null) { + _response.request = request; + var prevState = _response.state; + _response.state = state; + _response.status = 200; + var prevTransport = _response.transport; + _response.transport = transport; - var _body = _response.responseBody; - _invokeCallback(); - _response.responseBody = _body; + var _body = _response.responseBody; + _invokeCallback(); + _response.responseBody = _body; - _response.state = prevState; - _response.transport = prevTransport; + _response.state = prevState; + _response.transport = prevTransport; + } } /** @@ -729,41 +734,43 @@ jQuery.atmosphere = function() { type : rq.method, dataType: "jsonp", error : function(jqXHR, textStatus, errorThrown) { - if (jqXHR.status < 300) { + _response.error = true; + if (jqXHR.status < 300 && rq.reconnect && _requestCount++ < rq.maxReconnectOnClose) { _reconnect(_jqxhr, rq); } else { - _prepareCallback(textStatus, "error", jqXHR.status, rq.transport); + _onError(jqXHR.status, errorThrown); } }, jsonp : "jsonpTransport", success: function(json) { + if (rq.reconnect) { + if (rq.maxRequest == -1 || rq.requestCount++ < rq.maxRequest) { + _readHeaders(_jqxhr, rq); - if (rq.reconnect && (rq.maxRequest == -1 || rq.requestCount++ < rq.maxRequest)) { - _readHeaders(_jqxhr, rq); - - if (!rq.executeCallbackBeforeReconnect) { - _reconnect(_jqxhr, rq); - } + if (!rq.executeCallbackBeforeReconnect) { + _reconnect(_jqxhr, rq); + } - var msg = json.message; - if (msg != null && typeof msg != 'string') { - try { - msg = jQuery.stringifyJSON(msg); - } catch (err) { - // The message was partial + var msg = json.message; + if (msg != null && typeof msg != 'string') { + try { + msg = jQuery.stringifyJSON(msg); + } catch (err) { + // The message was partial + } } - } - if (_handleProtocol(rq, msg)) { - _prepareCallback(msg, "messageReceived", 200, rq.transport); - } + if (_handleProtocol(rq, msg)) { + _prepareCallback(msg, "messageReceived", 200, rq.transport); + } - if (rq.executeCallbackBeforeReconnect) { - _reconnect(_jqxhr, rq); + if (rq.executeCallbackBeforeReconnect) { + _reconnect(_jqxhr, rq); + } + } else { + jQuery.atmosphere.log(_request.logLevel, ["JSONP reconnect maximum try reached " + _request.requestCount]); + _onError(0, "maxRequest reached"); } - } else { - jQuery.atmosphere.log(_request.logLevel, ["JSONP reconnect maximum try reached " + _request.requestCount]); - _onError(); } }, data : rq.data, @@ -802,29 +809,32 @@ jQuery.atmosphere = function() { url : url, type : rq.method, error : function(jqXHR, textStatus, errorThrown) { + _response.error = true; if (jqXHR.status < 300) { _reconnect(_jqxhr, rq); } else { - _prepareCallback(textStatus, "error", jqXHR.status, rq.transport); + _onError(jqXHR.status, errorThrown); } }, success: function(data, textStatus, jqXHR) { - if (rq.reconnect && (rq.maxRequest == -1 || rq.requestCount++ < rq.maxRequest)) { - if (!rq.executeCallbackBeforeReconnect) { - _reconnect(_jqxhr, rq); - } + if (rq.reconnect) { + if (rq.maxRequest == -1 || rq.requestCount++ < rq.maxRequest) { + if (!rq.executeCallbackBeforeReconnect) { + _reconnect(_jqxhr, rq); + } - if (_handleProtocol(rq, data)) { - _prepareCallback(data, "messageReceived", 200, rq.transport); - } + if (_handleProtocol(rq, data)) { + _prepareCallback(data, "messageReceived", 200, rq.transport); + } - if (rq.executeCallbackBeforeReconnect) { - _reconnect(_jqxhr, rq); + if (rq.executeCallbackBeforeReconnect) { + _reconnect(_jqxhr, rq); + } + } else { + jQuery.atmosphere.log(_request.logLevel, ["AJAX reconnect maximum try reached " + _request.requestCount]); + _onError(0, "maxRequest reached"); } - } else { - jQuery.atmosphere.log(_request.logLevel, ["AJAX reconnect maximum try reached " + _request.requestCount]); - _onError(); } }, beforeSend : function(jqXHR) { @@ -912,7 +922,14 @@ jQuery.atmosphere = function() { } return; } - _sse = new EventSource(location, {withCredentials: _request.withCredentials}); + + try { + _sse = new EventSource(location, {withCredentials: _request.withCredentials}); + } catch (e) { + _onError(0, e); + _reconnectWithFallbackTransport("SSE failed. Downgrading to fallback transport and resending"); + return; + } if (_request.connectTimeout > 0) { _request.id = setTimeout(function() { @@ -944,31 +961,25 @@ jQuery.atmosphere = function() { return; } - if (!_handleProtocol(_request, message.data)) return; + var data = message.data; + + if (!_handleProtocol(_request, data)) return; _response.state = 'messageReceived'; _response.status = 200; - var message = message.data; - var skipCallbackInvocation = _trackMessageSize(message, _request, _response); - - if (jQuery.trim(message).length == 0) { - skipCallbackInvocation = true; - } - + var skipCallbackInvocation = _trackMessageSize(data, _request, _response); if (!skipCallbackInvocation) { _invokeCallback(); _response.responseBody = ''; + _response.messages = []; } }; _sse.onerror = function(message) { clearTimeout(_request.id); - _response.state = 'closed'; - _response.responseBody = ""; - _response.status = !sseOpened ? 501 : 200; - _invokeCallback(); + _invokeClose(sseOpened); _clearState(); if (_abordingConnection) { @@ -981,9 +992,10 @@ jQuery.atmosphere = function() { _executeSSE(true); }, _request.reconnectInterval); _response.responseBody = ""; + _response.messages = []; } else { jQuery.atmosphere.log(_request.logLevel, ["SSE reconnect maximum try reached " + _requestCount]); - _onError(); + _onError(0, "maxReconnectOnClose reached"); } } }; @@ -1025,7 +1037,6 @@ jQuery.atmosphere = function() { } _websocket = _getWebSocket(location); - if (_request.connectTimeout > 0) { _request.id = setTimeout(function() { if (!webSocketOpened) { @@ -1062,6 +1073,7 @@ jQuery.atmosphere = function() { } webSocketOpened = true; + _websocket.webSocketOpened = webSocketOpened; if (_request.method == 'POST') { _response.state = "messageReceived"; @@ -1078,17 +1090,18 @@ jQuery.atmosphere = function() { }, _request.reconnectInterval) }, _request.timeout); - if (!_handleProtocol(_request, message.data)) return; + var data = message.data; + + if (!_handleProtocol(_request, data)) return; _response.state = 'messageReceived'; _response.status = 200; - var message = message.data; - var skipCallbackInvocation = _trackMessageSize(message, _request, _response); - + var skipCallbackInvocation = _trackMessageSize(data, _request, _response); if (!skipCallbackInvocation) { _invokeCallback(); _response.responseBody = ''; + _response.messages = []; } }; @@ -1098,6 +1111,7 @@ jQuery.atmosphere = function() { _websocket.onclose = function(message) { if (closed) return + clearTimeout(_request.id); var reason = message.reason; if (reason === "") { @@ -1133,12 +1147,7 @@ jQuery.atmosphere = function() { jQuery.atmosphere.warn("Websocket closed, reason: " + reason); jQuery.atmosphere.warn("Websocket closed, wasClean: " + message.wasClean); - _response.state = 'closed'; - _response.responseBody = ""; - _response.status = !webSocketOpened ? 501 : 200; - _invokeCallback(); - clearTimeout(_request.id); - + _invokeClose(webSocketOpened); closed = true; if (_abordingConnection) { @@ -1151,12 +1160,13 @@ jQuery.atmosphere = function() { if (_request.reconnect && _requestCount++ < _request.maxReconnectOnClose) { _request.id = setTimeout(function() { _response.responseBody = ""; + _response.messages = []; _executeWebSocket(true); }, _request.reconnectInterval); } else { jQuery.atmosphere.log(_request.logLevel, ["Websocket reconnect maximum try reached " + _requestCount]); jQuery.atmosphere.warn("Websocket error, reason: " + message.reason); - _onError(); + _onError(0, "maxReconnectOnClose reached"); } } }; @@ -1164,22 +1174,25 @@ jQuery.atmosphere = function() { function _handleProtocol(request, message) { // The first messages is always the uuid. - if (request.enableProtocol && request.firstMessage) { + if (jQuery.trim(message) != 0 && request.enableProtocol && request.firstMessage) { request.firstMessage = false; var messages = message.split(request.messageDelimiter); - request.uuid = messages[0]; - request.stime = messages[1]; + var pos = messages.length == 2 ? 0 : 1; + request.uuid = jQuery.trim(messages[pos]); + request.stime = jQuery.trim(messages[pos + 1]); return false; } return true; } - function _onError() { + function _onError(code, reason) { _clearState(); _response.state = 'error'; + _response.reasonPhrase = reason; _response.responseBody = ""; - _response.status = 500; + _response.messages = []; + _response.status = code; _invokeCallback(); } @@ -1203,7 +1216,7 @@ jQuery.atmosphere = function() { var messageLength = 0; var messageStart = message.indexOf(request.messageDelimiter); while (messageStart != -1) { - messageLength = message.substring(messageLength, messageStart); + messageLength = jQuery.trim(message.substring(messageLength, messageStart)); message = message.substring(messageStart + request.messageDelimiter.length, message.length); if (message.length == 0 || message.length < messageLength) break; @@ -1220,8 +1233,11 @@ jQuery.atmosphere = function() { if (messages.length != 0) { response.responseBody = messages.join(request.messageDelimiter); + response.messages = messages; return false; } else { + response.responseBody = ""; + response.messages = []; return true; } } else { @@ -1246,15 +1262,16 @@ jQuery.atmosphere = function() { } _request.transport = _request.fallbackTransport; - var reconnect = _request.reconnect && _requestCount++ < _request.maxReconnectOnClose; - if (reconnect && _request.transport != 'none' || _request.transport == null) { + var reconnectInterval = _request.connectTimeout == -1 ? 0 : _request.connectTimeout; + if (_request.reconnect && _request.transport != 'none' || _request.transport == null) { _request.method = _request.fallbackMethod; _response.transport = _request.fallbackTransport; + _request.fallbackTransport = 'none'; _request.id = setTimeout(function() { _execute(); - }, _request.reconnectInterval); - } else if (!reconnect) { - _onError(); + }, reconnectInterval); + } else { + _onError(500, "Unable to reconnect with fallback transport"); } } @@ -1357,6 +1374,9 @@ jQuery.atmosphere = function() { rq = request; } + rq.lastIndex = 0; + rq.readyState = 0; + // CORS fake using JSONP if ((rq.transport == 'jsonp') || ((rq.enableXDR) && (jQuery.atmosphere.checkCORSSupport()))) { _jsonp(rq); @@ -1380,6 +1400,14 @@ jQuery.atmosphere = function() { } } + var reconnectF = function() { + if (rq.reconnect && _requestCount++ < rq.maxReconnectOnClose) { + _reconnect(ajaxRequest, rq, true); + } else { + _onError(0, "maxReconnectOnClose reached"); + } + }; + if (rq.reconnect && ( rq.maxRequest == -1 || rq.requestCount++ < rq.maxRequest)) { var ajaxRequest = _buildAjaxRequest(); _doRequest(ajaxRequest, rq, true); @@ -1392,162 +1420,129 @@ jQuery.atmosphere = function() { _response.transport = rq.transport; } - if (!jQuery.browser.msie) { - ajaxRequest.onerror = function() { - try { - _response.status = XMLHttpRequest.status; - } catch(e) { - _response.status = 500; - } + ajaxRequest.onabort = function () { + _invokeClose(true); + }; - if (!_response.status) { - _response.status = 500; - } - _clearState(); + ajaxRequest.onerror = function() { + _response.error = true; + try { + _response.status = XMLHttpRequest.status; + } catch(e) { + _response.status = 500; + } - if (rq.reconnect) { - _reconnect(ajaxRequest, rq, true); - } else { - _onError(); - } - }; - } + if (!_response.status) { + _response.status = 500; + } + _clearState(); + if (!_response.errorHandled) { + reconnectF(); + } + }; ajaxRequest.onreadystatechange = function() { if (_abordingConnection) { return; } - + _response.error = null; var skipCallbackInvocation = false; var update = false; - // Remote server disconnected us, reconnect. - if (rq.transport == 'streaming' + + // Opera doesn't call onerror if the server disconnect. + if (jQuery.browser.opera + && rq.transport == 'streaming' && rq.readyState > 2 && ajaxRequest.readyState == 4) { rq.readyState = 0; rq.lastIndex = 0; - _reconnect(ajaxRequest, rq, true); + reconnectF(); return; } rq.readyState = ajaxRequest.readyState; - if (ajaxRequest.readyState == 4) { - if (jQuery.browser.msie) { - update = true; - } else if (rq.transport == 'streaming') { - update = true; - } else if (rq.transport == 'long-polling') { - update = true; - clearTimeout(rq.id); - } - } else if (rq.transport == 'streaming' && jQuery.browser.msie && ajaxRequest.readyState >= 3) { + if (rq.transport == 'streaming' && ajaxRequest.readyState >= 3) { update = true; - } else if (!jQuery.browser.msie && ajaxRequest.readyState == 3 && ajaxRequest.status == 200 && rq.transport != 'long-polling') { + } else if (rq.transport == 'long-polling' && ajaxRequest.readyState === 4) { update = true; - } else { - clearTimeout(rq.id); } + clearTimeout(rq.id); if (update) { + // MSIE 9 and lower status can be higher than 1000, Chrome can be 0 + var status = 0; + if (ajaxRequest.readyState != 0) { + status = ajaxRequest.status > 1000 ? 0 : ajaxRequest.status; + } + + if (status >= 300 || status == 0) { + // Prevent onerror callback to be called + _response.errorHandled = true; + _clearState(); + reconnectF(); + return; + } var responseText = ajaxRequest.responseText; - // MSIE status can be higher than 1000, Chrome can be 0 - if (ajaxRequest.status >= 500 || ajaxRequest.status == 0) { - if (rq.reconnect) { - _reconnect(ajaxRequest, rq, true); - } else { - _onError(); + if (jQuery.trim(responseText.length) == 0 && rq.transport == 'long-polling') { + // For browser that aren't support onabort + if (!ajaxRequest.hasData) { + reconnectF(); + } else { + ajaxRequest.hasData = false; } return; } + ajaxRequest.hasData = true; _readHeaders(ajaxRequest, _request); if (rq.transport == 'streaming') { - var text = responseText.substring(rq.lastIndex, responseText.length); - _response.isJunkEnded = true; - - //fix junk is comming in parts - if (!_response.junkFull && (text.indexOf("") == -1)) { - return; - } - _response.junkFull = true; - - //if it's the start and we see the junk start - //fix for reconnecting on chrome - junk is comming in parts - if (rq.lastIndex == 0 && text.indexOf("") != -1) { - _response.isJunkEnded = false; - } - - if (!_response.isJunkEnded) { - var endOfJunk = ""; - var endOfJunkLength = endOfJunk.length; - var junkEnd = text.indexOf(endOfJunk) + endOfJunkLength; - - if (junkEnd > endOfJunkLength && junkEnd != text.length) { - _response.responseBody = text.substring(junkEnd); - rq.lastIndex = responseText.length; - if (!_handleProtocol( _request, _response.responseBody)) { - return; - } - skipCallbackInvocation = _trackMessageSize(_response.responseBody, rq, _response); - } else { - skipCallbackInvocation = true; - } - } else { + if (!jQuery.browser.opera) { var message = responseText.substring(rq.lastIndex, responseText.length); rq.lastIndex = responseText.length; - if (!_handleProtocol( _request, message)) { + if (!_handleProtocol(_request, message)) { return; } skipCallbackInvocation = _trackMessageSize(message, rq, _response); - } - rq.lastIndex = responseText.length; - - if (jQuery.browser.opera) { - jQuery.atmosphere.iterate(function() { - if (ajaxRequest.responseText.length > rq.lastIndex) { + } else { + jQuery.atmosphere.iterate(function () { + if (_response.status != 500 && ajaxRequest.responseText.length > rq.lastIndex) { try { _response.status = ajaxRequest.status; - _response.headers = parseHeaders(ajaxRequest.getAllResponseHeaders()); - - _readHeaders(ajaxRequest, _request); } - catch(e) { + catch (e) { _response.status = 404; } _response.state = "messageReceived"; - _response.responseBody = ajaxRequest.responseText.substring(rq.lastIndex); + + var message = ajaxRequest.responseText.substring(rq.lastIndex); rq.lastIndex = ajaxRequest.responseText.length; + if (_handleProtocol(_request, message)) { + skipCallbackInvocation = _trackMessageSize(message, rq, _response); + if (!skipCallbackInvocation) { + _invokeCallback(); + } - if (!_handleProtocol( _request, _response.responseBody)) { - _reconnect(ajaxRequest, rq, false); - return; - } - _invokeCallback(); - if ((rq.transport == 'streaming') && (ajaxRequest.responseText.length > rq.maxStreamingLength)) { - // Close and reopen connection on large data received - _clearState(); - _doRequest(_buildAjaxRequest(), rq, true); + _verifyStreamingLength(ajaxRequest, rq); } + } else if (_response.status > 400){ + rq.lastIndex = ajaxRequest.responseText.length; + return false; } }, 0); } - - if (skipCallbackInvocation) { - return; - } } else { if (!_handleProtocol( _request, responseText)) { _reconnect(ajaxRequest, rq, false); return; } - _trackMessageSize(responseText, rq, _response); + skipCallbackInvocation = _trackMessageSize(responseText, rq, _response); rq.lastIndex = responseText.length; } @@ -1575,17 +1570,15 @@ jQuery.atmosphere = function() { jQuery.atmosphere.log(rq.logLevel, ["parent.callback no longer supported with 0.8 version and up. Please upgrade"]); } - _invokeCallback(); + if (!skipCallbackInvocation) { + _invokeCallback(); + } if (rq.executeCallbackBeforeReconnect) { _reconnect(ajaxRequest, rq, false); } - if ((rq.transport == 'streaming') && (responseText.length > rq.maxStreamingLength)) { - // Close and reopen connection on large data received - _clearState(); - _doRequest(_buildAjaxRequest(), rq, true); - } + _verifyStreamingLength(ajaxRequest, rq); } }; ajaxRequest.send(rq.data); @@ -1606,7 +1599,7 @@ jQuery.atmosphere = function() { if (rq.logLevel == 'debug') { jQuery.atmosphere.log(rq.logLevel, ["Max re-connection reached."]); } - _onError(); + _onError(0, "maxRequest reached"); } } @@ -1651,13 +1644,13 @@ jQuery.atmosphere = function() { if (request.trackMessageLength) { ajaxRequest.setRequestHeader("X-Atmosphere-TrackMessageSize", "true") } - - if (request.contentType != '') { - ajaxRequest.setRequestHeader("Content-Type", request.contentType); - } ajaxRequest.setRequestHeader("X-Atmosphere-tracking-id", request.uuid); } + if (request.contentType != '') { + ajaxRequest.setRequestHeader("Content-Type", request.contentType); + } + jQuery.each(request.headers, function(name, value) { var h = jQuery.isFunction(value) ? value.call(this, ajaxRequest, request, create, _response) : value; if (h != null) { @@ -1667,17 +1660,26 @@ jQuery.atmosphere = function() { } function _reconnect(ajaxRequest, request, force) { - var reconnect = request.reconnect && _requestCount++ < request.maxReconnectOnClose; + if (force || request.transport != 'streaming') { + if ( request.reconnect || (request.suspend && _subscribed)) { + var status = 0; + if (ajaxRequest.readyState != 0) { + status = ajaxRequest.status > 1000 ? 0 : ajaxRequest.status; + } + _response.status = status == 0 ? 204 : status; + _response.reason = status == 0 ? "Server resumed the connection or down." : "OK"; - if (reconnect && force || (request.suspend && ajaxRequest.status == 200 && request.transport != 'streaming' && _subscribed)) { - if (request.reconnect) { - _open('re-opening', request.transport, request); - request.id = setTimeout(function() { - _executeRequest(); - }, request.reconnectInterval); + var reconnectInterval = (request.connectTimeout == -1) ? 0 : request.connectTimeout; + + // Reconnect immedialtely + if (!force) { + request.id = setTimeout(function () { + _executeRequest(request); + }, reconnectInterval); + } else { + _executeRequest(request); + } } - } else if (!reconnect) { - _onError(); } } @@ -1702,21 +1704,6 @@ jQuery.atmosphere = function() { var lastIndex = 0; var xdrCallback = function (xdr) { var responseBody = xdr.responseText; - var isJunkEnded = false; - - if (responseBody.indexOf(""; - var endOfJunkLenght = endOfJunk.length; - var junkEnd = responseBody.indexOf(endOfJunk); - if (junkEnd !== -1) { - responseBody = responseBody.substring(junkEnd + endOfJunkLenght + lastIndex); - lastIndex += responseBody.length; - } - } if (!_handleProtocol(request, responseBody)) return; @@ -1747,10 +1734,8 @@ jQuery.atmosphere = function() { xdr.onerror = function() { // If the server doesn't send anything back to XDR will fail with polling if (rq.transport != 'polling') { - _prepareCallback(xdr.responseText, "error", 500, transport); + _reconnect(xdr, rq, false); } - - _reconnect(xdr, rq, false); }; // Handles close event @@ -1873,23 +1858,7 @@ jQuery.atmosphere = function() { clone.appendChild(cdoc.createTextNode(".")); var text = clone.innerText; - var isJunkEnded = true; - - if (text.indexOf(""; - var endOfJunkLength = endOfJunk.length; - var junkEnd = text.indexOf(endOfJunk) + endOfJunkLength; - - text = text.substring(junkEnd); - } - text = text.substring(0, text.length - 1); - - _handleProtocol(rq, text); return text; }; @@ -1918,11 +1887,14 @@ jQuery.atmosphere = function() { var text = readResponse(); if (text.length > rq.lastIndex) { _response.status = 200; + _response.error = null; - // Empties response every time that it is handled - res.innerText = ""; - _prepareCallback(text, "messageReceived", 200, rq.transport); - + var message = text; + if (message.length != 0 && _handleProtocol(rq, message)) { + // Empties response every time that it is handled + res.innerText = ""; + _prepareCallback(message, "messageReceived", 200, rq.transport); + } rq.lastIndex = 0; } @@ -1938,12 +1910,13 @@ jQuery.atmosphere = function() { return false; } catch (err) { + _response.error = true; if (_requestCount++ < rq.maxReconnectOnClose) { rq.id = setTimeout(function() { _ieStreaming(rq); }, rq.reconnectInterval); } else { - _onError(); + _onError(0, "maxReconnectOnClose reached"); } doc.execCommand("Stop"); doc.close(); @@ -2095,6 +2068,7 @@ jQuery.atmosphere = function() { attachHeadersAsQueryString: true, enableXDR: _request.enableXDR, uuid : _request.uuid, + messageDelimiter : '|', enableProtocol : false, maxReconnectOnClose : _request.maxReconnectOnClose }; @@ -2147,11 +2121,11 @@ jQuery.atmosphere = function() { } function _prepareCallback(messageBody, state, errorCode, transport) { - _response.responseBody = messageBody; + if (state == "messageReceived") { - if (_trackMessageSize(messageBody, _request, _response)) { - return; - } + if (_trackMessageSize(messageBody, _request, _response)) return; + } else { + _response.responseBody = messageBody; } _response.transport = transport; @@ -2225,6 +2199,14 @@ jQuery.atmosphere = function() { } } + function _invokeClose(wasOpen) { + _response.state = 'closed'; + _response.responseBody = ""; + _response.messages = []; + _response.status = !wasOpen ? 501 : 200; + _invokeCallback(); + } + /** * Invoke request callbacks. * @@ -2242,7 +2224,7 @@ jQuery.atmosphere = function() { _request.reconnect = _request.mrequest; var messages = (typeof(_response.responseBody) == 'string' && _request.trackMessageLength) ? - _response.responseBody.split(_request.messageDelimiter) : new Array(_response.responseBody); + (_response.messages.length>0 ? _response.messages : ['']) : new Array(_response.responseBody); for (var i = 0; i < messages.length; i++) { if (messages.length > 1 && messages[i].length == 0) { @@ -2250,13 +2232,8 @@ jQuery.atmosphere = function() { } _response.responseBody = jQuery.trim(messages[i]); - // Ugly see issue 400. - if (_response.responseBody.length == 0 && _response.transport == 'streaming' && _response.state == "messageReceived") { - var ua = navigator.userAgent.toLowerCase(); - var isAndroid = ua.indexOf("android") > -1; - if (isAndroid) { - continue; - } + if (_response.responseBody.length == 0 && _response.state == "messageReceived") { + continue; } _invokeFunction(_response); @@ -2288,17 +2265,53 @@ jQuery.atmosphere = function() { } + /** + * + * @private + */ + function _verifyStreamingLength(ajaxRequest, rq){ + // Wait to be sure we have the full message before closing. + if (_response.partialMessage == "" && + (rq.transport == 'streaming') && + (ajaxRequest.responseText.length > rq.maxStreamingLength)) { + _response.messages = []; + _invokeClose(true); + _disconnect(); + _clearState(); + _reconnect(ajaxRequest, rq, true); + } + } + + /** + * Disconnect + * @private + */ + function _disconnect() { + if (_request.enableProtocol) { + var query = "X-Atmosphere-Transport=close&X-Atmosphere-tracking-id=" + _request.uuid; + var url = _request.url.replace(/([?&])_=[^&]*/, query); + url = url + (url === _request.url ? (/\?/.test(_request.url) ? "&" : "?") + query : ""); + + if (_request.connectTimeout > -1) { + jQuery.ajax({url: url, async: false, timeout: _request.connectTimeout}); + } else { + jQuery.ajax({url: url, async: false}); + } + } + } + /** * Close request. * * @private */ function _close() { - _abordingConnection = true; _request.reconnect = false; + _abordingConnection = true; _response.request = _request; _response.state = 'unsubscribe'; _response.responseBody = ""; + _response.messages = []; _response.status = 408; _invokeCallback(); @@ -2319,7 +2332,9 @@ jQuery.atmosphere = function() { _activeRequest = null; } if (_websocket != null) { - _websocket.close(); + if (_websocket.webSocketOpened) { + _websocket.close(); + } _websocket = null; } if (_sse != null) { @@ -2343,7 +2358,7 @@ jQuery.atmosphere = function() { if (_localStorageService != null) { _localStorageService.close(); } - } + }; this.subscribe = function(options) { _subscribe(options); @@ -2362,6 +2377,10 @@ jQuery.atmosphere = function() { _close(); }; + this.disconnect = function () { + _disconnect(); + }; + this.getUrl = function() { return _request.url; }; @@ -2421,10 +2440,8 @@ jQuery.atmosphere = function() { var requestsClone = [].concat(jQuery.atmosphere.requests); for (var i = 0; i < requestsClone.length; i++) { var rq = requestsClone[i]; + rq.disconnect(); rq.close(); - if (rq.enableProtocol()) { - jQuery.ajax({url: this._closeUrl(rq), async:false}); - } clearTimeout(rq.response.request.id); } } @@ -2432,12 +2449,6 @@ jQuery.atmosphere = function() { jQuery.atmosphere.callbacks = []; }, - _closeUrl : function(rq) { - var query = "X-Atmosphere-Transport=close&X-Atmosphere-tracking-id=" + rq.getUUID(); - var url = rq.getUrl().replace(/([?&])_=[^&]*/, query); - return url + (url === rq.getUrl() ? (/\?/.test(rq.getUrl()) ? "&" : "?") + query : ""); - }, - unsubscribeUrl: function(url) { var idx = -1; if (jQuery.atmosphere.requests.length > 0) { @@ -2446,10 +2457,8 @@ jQuery.atmosphere = function() { // Suppose you can subscribe once to an url if (rq.getUrl() == url) { + rq.disconnect(); rq.close(); - if (rq.enableProtocol()) { - jQuery.ajax({url :this._closeUrl(rq), async:false}); - } clearTimeout(rq.response.request.id); idx = i; break; @@ -2643,8 +2652,8 @@ jQuery.atmosphere = function() { /* * jQuery stringifyJSON * http://github.com/flowersinthesand/jquery-stringifyJSON - * - * Copyright 2011, Donghwan Kim + * + * Copyright 2011, Donghwan Kim * Licensed under the Apache License, Version 2.0 * http://www.apache.org/licenses/LICENSE-2.0 */ @@ -2728,4 +2737,4 @@ jQuery.atmosphere = function() { return str("", {"": value}); }; -}(jQuery)); \ No newline at end of file +}(jQuery)); diff --git a/push/build.xml b/push/build.xml index d06b946dd1..953416cf2d 100644 --- a/push/build.xml +++ b/push/build.xml @@ -13,7 +13,7 @@ - + @@ -62,7 +62,6 @@ -
diff --git a/push/ivy.xml b/push/ivy.xml index a5ca79d4a3..4834342f00 100644 --- a/push/ivy.xml +++ b/push/ivy.xml @@ -28,7 +28,7 @@ -
diff --git a/push/src/org/atmosphere/cpr/AtmosphereFramework.java b/push/src/org/atmosphere/cpr/AtmosphereFramework.java deleted file mode 100644 index 62f867fc94..0000000000 --- a/push/src/org/atmosphere/cpr/AtmosphereFramework.java +++ /dev/null @@ -1,1779 +0,0 @@ -/* - * Copyright 2013 Jeanfrancois Arcand - * - * 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 org.atmosphere.cpr; - -import org.atmosphere.cache.UUIDBroadcasterCache; -import org.atmosphere.config.ApplicationConfiguration; -import org.atmosphere.config.AtmosphereHandlerConfig; -import org.atmosphere.config.AtmosphereHandlerProperty; -import org.atmosphere.config.FrameworkConfiguration; -import org.atmosphere.container.BlockingIOCometSupport; -import org.atmosphere.container.Tomcat7BIOSupportWithWebSocket; -import org.atmosphere.di.InjectorProvider; -import org.atmosphere.di.ServletContextHolder; -import org.atmosphere.di.ServletContextProvider; -import org.atmosphere.handler.AbstractReflectorAtmosphereHandler; -import org.atmosphere.handler.ReflectorServletProcessor; -import org.atmosphere.interceptor.AndroidAtmosphereInterceptor; -import org.atmosphere.interceptor.JSONPAtmosphereInterceptor; -import org.atmosphere.interceptor.JavaScriptProtocol; -import org.atmosphere.interceptor.OnDisconnectInterceptor; -import org.atmosphere.interceptor.SSEAtmosphereInterceptor; -import org.atmosphere.util.AtmosphereConfigReader; -import org.atmosphere.util.IntrospectionUtils; -import org.atmosphere.util.Version; -import org.atmosphere.websocket.DefaultWebSocketProcessor; -import org.atmosphere.websocket.WebSocket; -import org.atmosphere.websocket.WebSocketProtocol; -import org.atmosphere.websocket.protocol.SimpleHttpProtocol; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import javax.servlet.Servlet; -import javax.servlet.ServletConfig; -import javax.servlet.ServletContext; -import javax.servlet.ServletException; -import java.io.File; -import java.io.FilenameFilter; -import java.io.IOException; -import java.io.InputStream; -import java.lang.reflect.InvocationHandler; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.lang.reflect.Proxy; -import java.net.MalformedURLException; -import java.net.URISyntaxException; -import java.net.URL; -import java.net.URLClassLoader; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.Enumeration; -import java.util.HashMap; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.UUID; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentLinkedQueue; -import java.util.concurrent.atomic.AtomicBoolean; - -import static org.atmosphere.cpr.ApplicationConfig.ALLOW_QUERYSTRING_AS_REQUEST; -import static org.atmosphere.cpr.ApplicationConfig.ATMOSPHERE_HANDLER; -import static org.atmosphere.cpr.ApplicationConfig.ATMOSPHERE_HANDLER_MAPPING; -import static org.atmosphere.cpr.ApplicationConfig.ATMOSPHERE_HANDLER_PATH; -import static org.atmosphere.cpr.ApplicationConfig.BROADCASTER_CACHE; -import static org.atmosphere.cpr.ApplicationConfig.BROADCASTER_CLASS; -import static org.atmosphere.cpr.ApplicationConfig.BROADCASTER_FACTORY; -import static org.atmosphere.cpr.ApplicationConfig.BROADCASTER_LIFECYCLE_POLICY; -import static org.atmosphere.cpr.ApplicationConfig.BROADCAST_FILTER_CLASSES; -import static org.atmosphere.cpr.ApplicationConfig.DISABLE_ONSTATE_EVENT; -import static org.atmosphere.cpr.ApplicationConfig.PROPERTY_ATMOSPHERE_XML; -import static org.atmosphere.cpr.ApplicationConfig.PROPERTY_BLOCKING_COMETSUPPORT; -import static org.atmosphere.cpr.ApplicationConfig.PROPERTY_COMET_SUPPORT; -import static org.atmosphere.cpr.ApplicationConfig.PROPERTY_NATIVE_COMETSUPPORT; -import static org.atmosphere.cpr.ApplicationConfig.PROPERTY_SERVLET_MAPPING; -import static org.atmosphere.cpr.ApplicationConfig.PROPERTY_SESSION_SUPPORT; -import static org.atmosphere.cpr.ApplicationConfig.PROPERTY_USE_STREAM; -import static org.atmosphere.cpr.ApplicationConfig.RESUME_AND_KEEPALIVE; -import static org.atmosphere.cpr.ApplicationConfig.SUSPENDED_ATMOSPHERE_RESOURCE_UUID; -import static org.atmosphere.cpr.ApplicationConfig.WEBSOCKET_PROCESSOR; -import static org.atmosphere.cpr.ApplicationConfig.WEBSOCKET_PROTOCOL; -import static org.atmosphere.cpr.ApplicationConfig.WEBSOCKET_SUPPORT; -import static org.atmosphere.cpr.FrameworkConfig.ATMOSPHERE_CONFIG; -import static org.atmosphere.cpr.FrameworkConfig.HAZELCAST_BROADCASTER; -import static org.atmosphere.cpr.FrameworkConfig.JERSEY_BROADCASTER; -import static org.atmosphere.cpr.FrameworkConfig.JERSEY_CONTAINER; -import static org.atmosphere.cpr.FrameworkConfig.JGROUPS_BROADCASTER; -import static org.atmosphere.cpr.FrameworkConfig.JMS_BROADCASTER; -import static org.atmosphere.cpr.FrameworkConfig.REDIS_BROADCASTER; -import static org.atmosphere.cpr.FrameworkConfig.WRITE_HEADERS; -import static org.atmosphere.cpr.FrameworkConfig.XMPP_BROADCASTER; -import static org.atmosphere.cpr.HeaderConfig.ATMOSPHERE_POST_BODY; -import static org.atmosphere.cpr.HeaderConfig.X_ATMOSPHERE_TRACKING_ID; -import static org.atmosphere.websocket.WebSocket.WEBSOCKET_SUSPEND; - -/** - * The {@link AtmosphereFramework} is the entry point for the framework. This class can be used to from Servlet/filter - * to dispatch {@link AtmosphereRequest} and {@link AtmosphereResponse}. The framework can also be configured using - * the setXXX method. The life cycle of this class is - *
- * AtmosphereFramework f = new AtmosphereFramework();
- * f.init();
- * f.doCometSupport(AtmosphereRequest, AtmosphereResource);
- * f.destroy();
- * 
- * - * @author Jeanfrancois Arcand - */ -public class AtmosphereFramework implements ServletContextProvider { - public static final String DEFAULT_ATMOSPHERE_CONFIG_PATH = "/META-INF/atmosphere.xml"; - public static final String DEFAULT_LIB_PATH = "/WEB-INF/lib/"; - public static final String MAPPING_REGEX = "[a-zA-Z0-9-&.*=@~;\\?]+"; - - protected static final Logger logger = LoggerFactory.getLogger(AtmosphereFramework.class); - - protected final List broadcasterFilters = new ArrayList(); - protected final List asyncSupportListeners = new ArrayList(); - protected final ArrayList possibleComponentsCandidate = new ArrayList(); - protected final HashMap initParams = new HashMap(); - protected final AtmosphereConfig config; - protected final AtomicBoolean isCometSupportConfigured = new AtomicBoolean(false); - protected final boolean isFilter; - protected final Map atmosphereHandlers = new ConcurrentHashMap(); - protected final ConcurrentLinkedQueue broadcasterTypes = new ConcurrentLinkedQueue(); - - protected boolean useNativeImplementation = false; - protected boolean useBlockingImplementation = false; - protected boolean useStreamForFlushingComments = false; - protected AsyncSupport asyncSupport; - protected String broadcasterClassName = DefaultBroadcaster.class.getName(); - protected boolean isCometSupportSpecified = false; - protected boolean isBroadcasterSpecified = false; - protected boolean isSessionSupportSpecified = false; - protected BroadcasterFactory broadcasterFactory; - protected String broadcasterFactoryClassName; - protected String broadcasterCacheClassName; - protected boolean webSocketEnabled = true; - protected String broadcasterLifeCyclePolicy = "NEVER"; - protected String webSocketProtocolClassName = SimpleHttpProtocol.class.getName(); - protected WebSocketProtocol webSocketProtocol; - protected String handlersPath = "/WEB-INF/classes/"; - protected ServletConfig servletConfig; - protected boolean autoDetectHandlers = true; - private boolean hasNewWebSocketProtocol = false; - protected String atmosphereDotXmlPath = DEFAULT_ATMOSPHERE_CONFIG_PATH; - protected final LinkedList interceptors = new LinkedList(); - protected boolean scanDone = false; - protected String annotationProcessorClassName = "org.atmosphere.cpr.DefaultAnnotationProcessor"; - protected final List broadcasterListeners = new ArrayList(); - protected String webSocketProcessorClassName = DefaultWebSocketProcessor.class.getName(); - protected String libPath = DEFAULT_LIB_PATH; - protected boolean isInit; - protected boolean sharedThreadPools = true; - - public static final class AtmosphereHandlerWrapper { - - public final AtmosphereHandler atmosphereHandler; - public Broadcaster broadcaster; - public String mapping; - public List interceptors = Collections.emptyList(); - - public AtmosphereHandlerWrapper(BroadcasterFactory broadcasterFactory, AtmosphereHandler atmosphereHandler, String mapping) { - this.atmosphereHandler = atmosphereHandler; - try { - if (broadcasterFactory != null) { - this.broadcaster = broadcasterFactory.lookup(mapping, true); - } else { - this.mapping = mapping; - } - } catch (Exception t) { - throw new RuntimeException(t); - } - } - - public AtmosphereHandlerWrapper(AtmosphereHandler atmosphereHandler, Broadcaster broadcaster) { - this.atmosphereHandler = atmosphereHandler; - this.broadcaster = broadcaster; - } - - @Override - public String toString() { - return "AtmosphereHandlerWrapper{ atmosphereHandler=" + atmosphereHandler + ", broadcaster=" + - broadcaster + " }"; - } - } - - /** - * Create an AtmosphereFramework. - */ - public AtmosphereFramework() { - this(false, true); - } - - /** - * Create an AtmosphereFramework and initialize it via {@link AtmosphereFramework#init(javax.servlet.ServletConfig)} - */ - public AtmosphereFramework(ServletConfig sc) throws ServletException { - this(false, true); - init(sc); - } - - /** - * Create an AtmosphereFramework. - * - * @param isFilter true if this instance is used as an {@link AtmosphereFilter} - */ - public AtmosphereFramework(boolean isFilter, boolean autoDetectHandlers) { - this.isFilter = isFilter; - this.autoDetectHandlers = autoDetectHandlers; - readSystemProperties(); - populateBroadcasterType(); - config = new AtmosphereConfig(this); - } - - /** - * The order of addition is quite important here. - */ - private void populateBroadcasterType() { - broadcasterTypes.add(HAZELCAST_BROADCASTER); - broadcasterTypes.add(XMPP_BROADCASTER); - broadcasterTypes.add(REDIS_BROADCASTER); - broadcasterTypes.add(JGROUPS_BROADCASTER); - broadcasterTypes.add(JMS_BROADCASTER); - } - - /** - * Add an {@link AtmosphereHandler} serviced by the {@link Servlet} - * This API is exposed to allow embedding an Atmosphere application. - * - * @param mapping The servlet mapping (servlet path) - * @param h implementation of an {@link AtmosphereHandler} - * @param l An attay of {@link AtmosphereInterceptor} - */ - public AtmosphereFramework addAtmosphereHandler(String mapping, AtmosphereHandler h, List l) { - if (!mapping.startsWith("/")) { - mapping = "/" + mapping; - } - - AtmosphereHandlerWrapper w = new AtmosphereHandlerWrapper(broadcasterFactory, h, mapping); - w.interceptors = l; - addMapping(mapping, w); - - logger.info("Installed AtmosphereHandler {} mapped to context-path: {}", h.getClass().getName(), mapping); - if (l.size() > 0) { - logger.info("Installed AtmosphereInterceptor {} mapped to AtmosphereHandler {}", l, h.getClass().getName()); - } - return this; - } - - /** - * Add an {@link AtmosphereHandler} serviced by the {@link Servlet} - * This API is exposed to allow embedding an Atmosphere application. - * - * @param mapping The servlet mapping (servlet path) - * @param h implementation of an {@link AtmosphereHandler} - */ - public AtmosphereFramework addAtmosphereHandler(String mapping, AtmosphereHandler h) { - addAtmosphereHandler(mapping, h, Collections.emptyList()); - return this; - } - - private AtmosphereFramework addMapping(String path, AtmosphereHandlerWrapper w) { - // We are using JAXRS mapping algorithm. - if (path.contains("*")) { - path = path.replace("*", MAPPING_REGEX); - } - - if (path.endsWith("/")) { - path = path + MAPPING_REGEX; - } - - InjectorProvider.getInjector().inject(w.atmosphereHandler); - atmosphereHandlers.put(path, w); - return this; - } - - /** - * Add an {@link AtmosphereHandler} serviced by the {@link Servlet} - * This API is exposed to allow embedding an Atmosphere application. - * - * @param mapping The servlet mapping (servlet path) - * @param h implementation of an {@link AtmosphereHandler} - * @param broadcasterId The {@link Broadcaster#getID} value. - * @param l An attay of {@link AtmosphereInterceptor} - */ - public AtmosphereFramework addAtmosphereHandler(String mapping, AtmosphereHandler h, String broadcasterId, List l) { - if (!mapping.startsWith("/")) { - mapping = "/" + mapping; - } - - AtmosphereHandlerWrapper w = new AtmosphereHandlerWrapper(broadcasterFactory, h, mapping); - w.broadcaster.setID(broadcasterId); - w.interceptors = l; - addMapping(mapping, w); - logger.info("Installed AtmosphereHandler {} mapped to context-path: {}", h.getClass().getName(), mapping); - if (l.size() > 0) { - logger.info("Installed AtmosphereInterceptor {} mapped to AtmosphereHandler {}", l, h.getClass().getName()); - } - return this; - } - - /** - * Add an {@link AtmosphereHandler} serviced by the {@link Servlet} - * This API is exposed to allow embedding an Atmosphere application. - * - * @param mapping The servlet mapping (servlet path) - * @param h implementation of an {@link AtmosphereHandler} - * @param broadcasterId The {@link Broadcaster#getID} value. - */ - public AtmosphereFramework addAtmosphereHandler(String mapping, AtmosphereHandler h, String broadcasterId) { - addAtmosphereHandler(mapping, h, broadcasterId, Collections.emptyList()); - return this; - } - - /** - * Add an {@link AtmosphereHandler} serviced by the {@link Servlet} - * This API is exposed to allow embedding an Atmosphere application. - * - * @param mapping The servlet mapping (servlet path) - * @param h implementation of an {@link AtmosphereHandler} - * @param broadcaster The {@link Broadcaster} associated with AtmosphereHandler. - * @param l An attay of {@link AtmosphereInterceptor} - */ - public AtmosphereFramework addAtmosphereHandler(String mapping, AtmosphereHandler h, Broadcaster broadcaster, List l) { - if (!mapping.startsWith("/")) { - mapping = "/" + mapping; - } - - AtmosphereHandlerWrapper w = new AtmosphereHandlerWrapper(h, broadcaster); - w.interceptors = l; - - addMapping(mapping, w); - logger.info("Installed AtmosphereHandler {} mapped to context-path: {}", h.getClass().getName(), mapping); - if (l.size() > 0) { - logger.info("Installed AtmosphereInterceptor {} mapped to AtmosphereHandler {}", l, h.getClass().getName()); - } - return this; - } - - /** - * Add an {@link AtmosphereHandler} serviced by the {@link Servlet} - * This API is exposed to allow embedding an Atmosphere application. - * - * @param mapping The servlet mapping (servlet path) - * @param h implementation of an {@link AtmosphereHandler} - * @param broadcaster The {@link Broadcaster} associated with AtmosphereHandler. - */ - public AtmosphereFramework addAtmosphereHandler(String mapping, AtmosphereHandler h, Broadcaster broadcaster) { - addAtmosphereHandler(mapping, h, broadcaster, Collections.emptyList()); - return this; - } - - /** - * Remove an {@link AtmosphereHandler} - * - * @param mapping the mapping used when invoking {@link #addAtmosphereHandler(String, AtmosphereHandler)}; - * @return true if removed - */ - public AtmosphereFramework removeAtmosphereHandler(String mapping) { - - if (mapping.endsWith("/")) { - mapping += MAPPING_REGEX; - } - - atmosphereHandlers.remove(mapping); - return this; - } - - /** - * Remove all {@link AtmosphereHandler} - */ - public AtmosphereFramework removeAllAtmosphereHandler() { - atmosphereHandlers.clear(); - return this; - } - - /** - * Remove all init parameters. - */ - public AtmosphereFramework removeAllInitParams() { - initParams.clear(); - return this; - } - - /** - * Add init-param like if they were defined in web.xml - * - * @param name The name - * @param value The value - */ - public AtmosphereFramework addInitParameter(String name, String value) { - initParams.put(name, value); - return this; - } - - protected void readSystemProperties() { - if (System.getProperty(PROPERTY_NATIVE_COMETSUPPORT) != null) { - useNativeImplementation = Boolean - .parseBoolean(System.getProperty(PROPERTY_NATIVE_COMETSUPPORT)); - isCometSupportSpecified = true; - } - - if (System.getProperty(PROPERTY_BLOCKING_COMETSUPPORT) != null) { - useBlockingImplementation = Boolean - .parseBoolean(System.getProperty(PROPERTY_BLOCKING_COMETSUPPORT)); - isCometSupportSpecified = true; - } - atmosphereDotXmlPath = System.getProperty(PROPERTY_ATMOSPHERE_XML, atmosphereDotXmlPath); - - if (System.getProperty(DISABLE_ONSTATE_EVENT) != null) { - initParams.put(DISABLE_ONSTATE_EVENT, System.getProperty(DISABLE_ONSTATE_EVENT)); - } - } - - /** - * Path specific container using their own property. - */ - public void patchContainer() { - System.setProperty("org.apache.catalina.STRICT_SERVLET_COMPLIANCE", "false"); - } - - /** - * Initialize the AtmosphereFramework. Invoke that method after having properly configured this class using the setter. - */ - public AtmosphereFramework init() { - try { - init(new ServletConfig() { - - @Override - public String getServletName() { - return "AtmosphereFramework"; - } - - @Override - public ServletContext getServletContext() { - return (ServletContext) Proxy.newProxyInstance(getClass().getClassLoader(), new Class[]{ServletContext.class}, - new InvocationHandler() { - @Override - public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { - logger.trace("Method {} not supported", method.getName()); - return null; - } - }); - } - - @Override - public String getInitParameter(String name) { - return initParams.get(name); - } - - @Override - public Enumeration getInitParameterNames() { - return Collections.enumeration(initParams.values()); - } - }); - } catch (ServletException e) { - logger.error("", e); - } - return this; - } - - /** - * Initialize the AtmosphereFramework using the {@link ServletContext} - * - * @param sc the {@link ServletContext} - */ - public AtmosphereFramework init(final ServletConfig sc) throws ServletException { - - if (isInit) return this; - - try { - ServletContextHolder.register(this); - - ServletConfig scFacade = new ServletConfig() { - - public String getServletName() { - return sc.getServletName(); - } - - public ServletContext getServletContext() { - return sc.getServletContext(); - } - - public String getInitParameter(String name) { - String param = initParams.get(name); - if (param == null) { - return sc.getInitParameter(name); - } - return param; - } - - public Enumeration getInitParameterNames() { - Enumeration en = sc.getInitParameterNames(); - while (en.hasMoreElements()) { - String name = (String) en.nextElement(); - if (!initParams.containsKey(name)) { - initParams.put(name, sc.getInitParameter(name)); - } - } - return Collections.enumeration(initParams.keySet()); - } - }; - this.servletConfig = scFacade; - asyncSupportListener(new AsyncSupportListenerAdapter()); - - autoConfigureService(scFacade.getServletContext()); - patchContainer(); - doInitParams(scFacade); - doInitParamsForWebSocket(scFacade); - configureBroadcaster(); - loadConfiguration(scFacade); - initWebSocket(); - - autoDetectContainer(); - configureWebDotXmlAtmosphereHandler(sc); - asyncSupport.init(scFacade); - initAtmosphereHandler(scFacade); - configureAtmosphereInterceptor(sc); - - if (broadcasterCacheClassName == null) { - logger.warn("No BroadcasterCache configured. Broadcasted message between client reconnection will be LOST. " + - "It is recommended to configure the {}", UUIDBroadcasterCache.class.getName()); - } else { - logger.info("Using BroadcasterCache: {}", broadcasterCacheClassName); - } - - // http://java.net/jira/browse/ATMOSPHERE-157 - if (sc.getServletContext() != null) { - sc.getServletContext().setAttribute(BroadcasterFactory.class.getName(), broadcasterFactory); - } - - for (String i : broadcasterFilters) { - logger.info("Using BroadcastFilter: {}", i); - } - - String s = config.getInitParameter(ApplicationConfig.BROADCASTER_SHARABLE_THREAD_POOLS); - if (s != null) { - sharedThreadPools = Boolean.parseBoolean(s); - } - - logger.info("Shared ExecutorService supported: {}", sharedThreadPools); - logger.info("HttpSession supported: {}", config.isSupportSession()); - logger.info("Using BroadcasterFactory: {}", broadcasterFactory.getClass().getName()); - logger.info("Using WebSocketProcessor: {}", webSocketProcessorClassName); - logger.info("Using Broadcaster: {}", broadcasterClassName); - logger.info("Atmosphere Framework {} started.", Version.getRawVersion()); - - String showSupportMessage = config.getInitParameter("org.atmosphere.cpr.showSupportMessage"); - if (showSupportMessage == null || Boolean.parseBoolean(showSupportMessage)) { - logger.info("\n\n\tFor Commercial Support, visit \n\t{} " + - "or send an email to {}\n", "http://www.async-io.org/", "support@async-io.org"); - } - } catch (Throwable t) { - logger.error("Failed to initialize Atmosphere Framework", t); - - if (t instanceof ServletException) { - throw (ServletException) t; - } - - throw new ServletException(t); - } - isInit = true; - return this; - } - - /** - * Configure the list of {@link AtmosphereInterceptor}. - * - * @param sc a ServletConfig - */ - protected void configureAtmosphereInterceptor(ServletConfig sc) { - String s = sc.getInitParameter(ApplicationConfig.ATMOSPHERE_INTERCEPTORS); - if (s != null) { - String[] list = s.split(","); - for (String a : list) { - try { - AtmosphereInterceptor ai = (AtmosphereInterceptor) Thread.currentThread().getContextClassLoader() - .loadClass(a.trim()).newInstance(); - ai.configure(config); - interceptor(ai); - } catch (InstantiationException e) { - logger.warn("", e); - } catch (IllegalAccessException e) { - logger.warn("", e); - } catch (ClassNotFoundException e) { - logger.warn("", e); - } - } - } - - s = sc.getInitParameter(ApplicationConfig.DISABLE_ATMOSPHEREINTERCEPTOR); - if (s == null) { - // OnDisconnect - interceptors.addFirst(newAInterceptor(OnDisconnectInterceptor.class)); - // ADD Tracking ID Handshake - interceptors.addFirst(newAInterceptor(JavaScriptProtocol.class)); - // ADD JSONP support - interceptors.addFirst(newAInterceptor(JSONPAtmosphereInterceptor.class)); - // Add SSE support - interceptors.addFirst(newAInterceptor(SSEAtmosphereInterceptor.class)); - // Android 2.3.x streaming support - interceptors.addFirst(newAInterceptor(AndroidAtmosphereInterceptor.class)); - logger.info("Installed Default AtmosphereInterceptor {}. " + - "Set org.atmosphere.cpr.AtmosphereInterceptor.disableDefaults in your xml to disable them.", interceptors); - } - } - - protected AtmosphereInterceptor newAInterceptor(Class a) { - AtmosphereInterceptor ai = null; - try { - ai = (AtmosphereInterceptor) getClass().getClassLoader().loadClass(a.getName()).newInstance(); - ai.configure(config); - } catch (Exception ex) { - logger.warn("", ex); - } - return ai; - } - - protected void configureWebDotXmlAtmosphereHandler(ServletConfig sc) { - String s = sc.getInitParameter(ATMOSPHERE_HANDLER); - if (s != null) { - ClassLoader cl = Thread.currentThread().getContextClassLoader(); - try { - - String mapping = sc.getInitParameter(ATMOSPHERE_HANDLER_MAPPING); - if (mapping == null) { - mapping = "/*"; - } - addAtmosphereHandler(mapping, (AtmosphereHandler) cl.loadClass(s).newInstance()); - } catch (Exception ex) { - logger.warn("Unable to load WebSocketHandle instance", ex); - } - } - } - - protected void configureBroadcaster() { - - try { - // Check auto supported one - if (isBroadcasterSpecified == false) { - broadcasterClassName = lookupDefaultBroadcasterType(broadcasterClassName); - } - - Class bc = - (Class) Thread.currentThread().getContextClassLoader() - .loadClass(broadcasterClassName); - if (broadcasterFactoryClassName != null) { - broadcasterFactory = (BroadcasterFactory) Thread.currentThread().getContextClassLoader() - .loadClass(broadcasterFactoryClassName).newInstance(); - } - - if (broadcasterFactory == null) { - broadcasterFactory = new DefaultBroadcasterFactory(bc, broadcasterLifeCyclePolicy, config); - } - - for (BroadcasterListener b : broadcasterListeners) { - broadcasterFactory.addBroadcasterListener(b); - } - - BroadcasterFactory.setBroadcasterFactory(broadcasterFactory, config); - InjectorProvider.getInjector().inject(broadcasterFactory); - - Iterator> i = atmosphereHandlers.entrySet().iterator(); - AtmosphereHandlerWrapper w; - Entry e; - while (i.hasNext()) { - e = i.next(); - w = e.getValue(); - - if (w.broadcaster == null) { - w.broadcaster = broadcasterFactory.get(w.mapping); - } else { - if (broadcasterCacheClassName != null) { - BroadcasterCache cache = (BroadcasterCache) Thread.currentThread().getContextClassLoader() - .loadClass(broadcasterCacheClassName).newInstance(); - InjectorProvider.getInjector().inject(cache); - w.broadcaster.getBroadcasterConfig().setBroadcasterCache(cache); - } - } - } - } catch (Exception ex) { - logger.error("Unable to configure Broadcaster/Factory/Cache", ex); - } - } - - protected void doInitParamsForWebSocket(ServletConfig sc) { - String s = sc.getInitParameter(WEBSOCKET_SUPPORT); - if (s != null) { - webSocketEnabled = Boolean.parseBoolean(s); - sessionSupport(false); - } - s = sc.getInitParameter(WEBSOCKET_PROTOCOL); - if (s != null) { - webSocketProtocolClassName = s; - } - - s = sc.getInitParameter(WEBSOCKET_PROCESSOR); - if (s != null) { - webSocketProcessorClassName = s; - } - } - - /** - * Read init param from web.xml and apply them. - * - * @param sc {@link ServletConfig} - */ - protected void doInitParams(ServletConfig sc) { - String s = sc.getInitParameter(PROPERTY_NATIVE_COMETSUPPORT); - if (s != null) { - useNativeImplementation = Boolean.parseBoolean(s); - if (useNativeImplementation) isCometSupportSpecified = true; - } - s = sc.getInitParameter(PROPERTY_BLOCKING_COMETSUPPORT); - if (s != null) { - useBlockingImplementation = Boolean.parseBoolean(s); - if (useBlockingImplementation) isCometSupportSpecified = true; - } - s = sc.getInitParameter(PROPERTY_USE_STREAM); - if (s != null) { - useStreamForFlushingComments = Boolean.parseBoolean(s); - } - s = sc.getInitParameter(PROPERTY_COMET_SUPPORT); - if (s != null) { - asyncSupport = new DefaultAsyncSupportResolver(config).newCometSupport(s); - isCometSupportSpecified = true; - } - s = sc.getInitParameter(BROADCASTER_CLASS); - if (s != null) { - broadcasterClassName = s; - isBroadcasterSpecified = true; - } - s = sc.getInitParameter(BROADCASTER_CACHE); - if (s != null) { - broadcasterCacheClassName = s; - } - s = sc.getInitParameter(PROPERTY_SESSION_SUPPORT); - if (s != null) { - config.setSupportSession(Boolean.valueOf(s)); - isSessionSupportSpecified = true; - } - s = sc.getInitParameter(DISABLE_ONSTATE_EVENT); - if (s != null) { - initParams.put(DISABLE_ONSTATE_EVENT, s); - } else { - initParams.put(DISABLE_ONSTATE_EVENT, "false"); - } - s = sc.getInitParameter(RESUME_AND_KEEPALIVE); - if (s != null) { - initParams.put(RESUME_AND_KEEPALIVE, s); - } - s = sc.getInitParameter(BROADCAST_FILTER_CLASSES); - if (s != null) { - broadcasterFilters.addAll(Arrays.asList(s.split(","))); - logger.info("Installing BroadcastFilter class(es) {}", s); - } - s = sc.getInitParameter(BROADCASTER_LIFECYCLE_POLICY); - if (s != null) { - broadcasterLifeCyclePolicy = s; - } - s = sc.getInitParameter(BROADCASTER_FACTORY); - if (s != null) { - broadcasterFactoryClassName = s; - } - s = sc.getInitParameter(ATMOSPHERE_HANDLER_PATH); - if (s != null) { - handlersPath = s; - } - s = sc.getInitParameter(PROPERTY_ATMOSPHERE_XML); - if (s != null) { - atmosphereDotXmlPath = s; - } - } - - public void loadConfiguration(ServletConfig sc) throws ServletException { - - if (!autoDetectHandlers) return; - - try { - URL url = sc.getServletContext().getResource(handlersPath); - URLClassLoader urlC = new URLClassLoader(new URL[]{url}, - Thread.currentThread().getContextClassLoader()); - loadAtmosphereDotXml(sc.getServletContext(). - getResourceAsStream(atmosphereDotXmlPath), urlC); - - if (atmosphereHandlers.size() == 0) { - autoDetectAtmosphereHandlers(sc.getServletContext(), urlC); - - if (atmosphereHandlers.size() == 0) { - detectSupportedFramework(sc); - } - } - - autoDetectWebSocketHandler(sc.getServletContext(), urlC); - } catch (Throwable t) { - throw new ServletException(t); - } - } - - /** - * Auto-detect Jersey when no atmosphere.xml file are specified. - * - * @param sc {@link ServletConfig} - * @return true if Jersey classes are detected - * @throws ClassNotFoundException - */ - protected boolean detectSupportedFramework(ServletConfig sc) throws ClassNotFoundException, IllegalAccessException, - InstantiationException, NoSuchMethodException, InvocationTargetException { - - ClassLoader cl = Thread.currentThread().getContextClassLoader(); - String broadcasterClassNameTmp = null; - - try { - cl.loadClass(JERSEY_CONTAINER); - - if (!isBroadcasterSpecified) { - broadcasterClassNameTmp = lookupDefaultBroadcasterType(JERSEY_BROADCASTER); - - cl.loadClass(broadcasterClassNameTmp); - } - useStreamForFlushingComments = true; - } catch (Throwable t) { - logger.trace("", t); - return false; - } - - logger.warn("Missing META-INF/atmosphere.xml but found the Jersey runtime. Starting Jersey"); - - // Jersey will handle itself the headers. - initParams.put(WRITE_HEADERS, "false"); - - ReflectorServletProcessor rsp = new ReflectorServletProcessor(); - if (broadcasterClassNameTmp != null) broadcasterClassName = broadcasterClassNameTmp; - rsp.setServletClassName(JERSEY_CONTAINER); - sessionSupport(false); - initParams.put(DISABLE_ONSTATE_EVENT, "true"); - - String mapping = sc.getInitParameter(PROPERTY_SERVLET_MAPPING); - if (mapping == null) { - mapping = "/*"; - } - Class bc = (Class) cl.loadClass(broadcasterClassName); - - - if (broadcasterFactory != null) { - broadcasterFactory.destroy(); - } - broadcasterFactory = new DefaultBroadcasterFactory(bc, broadcasterLifeCyclePolicy, config); - BroadcasterFactory.setBroadcasterFactory(broadcasterFactory, config); - - for (BroadcasterListener b : broadcasterListeners) { - broadcasterFactory.addBroadcasterListener(b); - } - - Broadcaster b; - - try { - b = broadcasterFactory.get(bc, mapping); - } catch (IllegalStateException ex) { - logger.warn("Two Broadcaster's named {}. Renaming the second one to {}", mapping, sc.getServletName() + mapping); - b = broadcasterFactory.get(bc, sc.getServletName() + mapping); - } - - addAtmosphereHandler(mapping, rsp, b); - return true; - } - - protected String lookupDefaultBroadcasterType(String defaultB) { - for (String b : broadcasterTypes) { - try { - Class.forName(b); - return b; - } catch (ClassNotFoundException e) { - } - } - return defaultB; - } - - protected void sessionSupport(boolean sessionSupport) { - if (!isSessionSupportSpecified) { - config.setSupportSession(sessionSupport); - } else if (!config.isSupportSession()) { - // Don't turn off session support. Once it's on, leave it on. - config.setSupportSession(sessionSupport); - } - } - - /** - * Initialize {@link AtmosphereServletProcessor} - * - * @param sc the {@link ServletConfig} - * @throws javax.servlet.ServletException - */ - public void initAtmosphereHandler(ServletConfig sc) throws ServletException { - AtmosphereHandler a; - AtmosphereHandlerWrapper w; - for (Entry h : atmosphereHandlers.entrySet()) { - w = h.getValue(); - a = w.atmosphereHandler; - if (a instanceof AtmosphereServletProcessor) { - ((AtmosphereServletProcessor) a).init(sc); - } - } - - if (atmosphereHandlers.size() == 0 && !SimpleHttpProtocol.class.isAssignableFrom(webSocketProtocol.getClass())) { - logger.debug("Adding a void AtmosphereHandler mapped to /* to allow WebSocket application only"); - addAtmosphereHandler("/*", new AbstractReflectorAtmosphereHandler() { - @Override - public void onRequest(AtmosphereResource r) throws IOException { - logger.debug("No AtmosphereHandler defined."); - } - - @Override - public void destroy() { - } - }); - } - } - - protected void initWebSocket() { - if (webSocketProtocol == null) { - try { - webSocketProtocol = (WebSocketProtocol) Thread.currentThread().getContextClassLoader() - .loadClass(webSocketProtocolClassName).newInstance(); - logger.info("Installed WebSocketProtocol {} ", webSocketProtocolClassName); - } catch (Exception ex) { - try { - webSocketProtocol = (WebSocketProtocol) AtmosphereFramework.class.getClassLoader() - .loadClass(webSocketProtocolClassName).newInstance(); - logger.info("Installed WebSocketProtocol {} ", webSocketProtocolClassName); - } catch (Exception ex2) { - logger.error("Cannot load the WebSocketProtocol {}", getWebSocketProtocolClassName(), ex); - webSocketProtocol = new SimpleHttpProtocol(); - } - } - } - webSocketProtocol.configure(config); - } - - public AtmosphereFramework destroy() { - if (asyncSupport != null && AsynchronousProcessor.class.isAssignableFrom(asyncSupport.getClass())) { - ((AsynchronousProcessor) asyncSupport).shutdown(); - } - - // We just need one bc to shutdown the shared thread pool - for (Entry entry : atmosphereHandlers.entrySet()) { - AtmosphereHandlerWrapper handlerWrapper = entry.getValue(); - handlerWrapper.atmosphereHandler.destroy(); - } - - BroadcasterFactory factory = broadcasterFactory; - if (factory != null) { - factory.destroy(); - BroadcasterFactory.factory = null; - } - WebSocketProcessorFactory.getDefault().destroy(); - return this; - } - - /** - * Load AtmosphereHandler defined under META-INF/atmosphere.xml - * - * @param stream The input stream we read from. - * @param c The classloader - */ - protected void loadAtmosphereDotXml(InputStream stream, URLClassLoader c) - throws IOException, ServletException { - - if (stream == null) { - return; - } - - AtmosphereConfigReader.getInstance().parse(config, stream); - for (AtmosphereHandlerConfig atmoHandler : config.getAtmosphereHandlerConfig()) { - try { - AtmosphereHandler handler; - - if (!ReflectorServletProcessor.class.getName().equals(atmoHandler.getClassName())) { - handler = (AtmosphereHandler) c.loadClass(atmoHandler.getClassName()).newInstance(); - } else { - handler = new ReflectorServletProcessor(); - } - - logger.info("Installed AtmosphereHandler {} mapped to context-path: {}", handler, atmoHandler.getContextRoot()); - - for (ApplicationConfiguration a : atmoHandler.getApplicationConfig()) { - initParams.put(a.getParamName(), a.getParamValue()); - } - - for (FrameworkConfiguration a : atmoHandler.getFrameworkConfig()) { - initParams.put(a.getParamName(), a.getParamValue()); - } - - for (AtmosphereHandlerProperty handlerProperty : atmoHandler.getProperties()) { - - if (handlerProperty.getValue() != null && handlerProperty.getValue().indexOf("jersey") != -1) { - initParams.put(DISABLE_ONSTATE_EVENT, "true"); - useStreamForFlushingComments = true; - broadcasterClassName = lookupDefaultBroadcasterType(JERSEY_BROADCASTER); - broadcasterFactory = null; - configureBroadcaster(); - } - - IntrospectionUtils.setProperty(handler, handlerProperty.getName(), handlerProperty.getValue()); - IntrospectionUtils.addProperty(handler, handlerProperty.getName(), handlerProperty.getValue()); - } - - sessionSupport(Boolean.valueOf(atmoHandler.getSupportSession())); - - String broadcasterClass = atmoHandler.getBroadcaster(); - Broadcaster b; - /** - * If there is more than one AtmosphereHandler defined, their Broadcaster - * may clash each other with the BroadcasterFactory. In that case we will use the - * last one defined. - */ - if (broadcasterClass != null) { - broadcasterClassName = broadcasterClass; - ClassLoader cl = Thread.currentThread().getContextClassLoader(); - Class bc = (Class) cl.loadClass(broadcasterClassName); - broadcasterFactory = new DefaultBroadcasterFactory(bc, broadcasterLifeCyclePolicy, config); - BroadcasterFactory.setBroadcasterFactory(broadcasterFactory, config); - } - - b = broadcasterFactory.lookup(atmoHandler.getContextRoot(), true); - - AtmosphereHandlerWrapper wrapper = new AtmosphereHandlerWrapper(handler, b); - addMapping(atmoHandler.getContextRoot(), wrapper); - - String bc = atmoHandler.getBroadcasterCache(); - if (bc != null) { - broadcasterCacheClassName = bc; - } - - if (atmoHandler.getCometSupport() != null) { - asyncSupport = (AsyncSupport) c.loadClass(atmoHandler.getCometSupport()) - .getDeclaredConstructor(new Class[]{AtmosphereConfig.class}) - .newInstance(new Object[]{config}); - } - - if (atmoHandler.getBroadcastFilterClasses() != null) { - broadcasterFilters.addAll(atmoHandler.getBroadcastFilterClasses()); - } - - List l = new ArrayList(); - if (atmoHandler.getAtmosphereInterceptorClasses() != null) { - for (String a : atmoHandler.getAtmosphereInterceptorClasses()) { - try { - AtmosphereInterceptor ai = (AtmosphereInterceptor) c.loadClass(a).newInstance(); - ai.configure(config); - l.add(ai); - } catch (Throwable e) { - logger.warn("", e); - } - } - } - wrapper.interceptors = l; - if (l.size() > 0) { - logger.info("Installed AtmosphereInterceptor {} mapped to AtmosphereHandler {}", l, atmoHandler.getClassName()); - } - } catch (Throwable t) { - logger.warn("Unable to load AtmosphereHandler class: " + atmoHandler.getClassName(), t); - throw new ServletException(t); - } - - } - } - - /** - * Set the {@link AsyncSupport} implementation. Make sure you don't set - * an implementation that only works on some Container. See {@link BlockingIOCometSupport} - * for an example. - * - * @param asyncSupport - */ - public AtmosphereFramework setAsyncSupport(AsyncSupport asyncSupport) { - this.asyncSupport = asyncSupport; - return this; - } - - /** - * @param asyncSupport - * @return - * @Deprecated - Use {@link #setAsyncSupport(AsyncSupport)} - */ - public AtmosphereFramework setCometSupport(AsyncSupport asyncSupport) { - return setAsyncSupport(asyncSupport); - } - - /** - * Return the current {@link AsyncSupport} - * - * @return the current {@link AsyncSupport} - */ - public AsyncSupport getAsyncSupport() { - return asyncSupport; - } - - /** - * Return the current {@link AsyncSupport} - * - * @return the current {@link AsyncSupport} - * @deprecated Use getAsyncSupport - */ - public AsyncSupport getCometSupport() { - return asyncSupport; - } - - /** - * Returns an instance of AsyncSupportResolver {@link AsyncSupportResolver} - * - * @return CometSupportResolver - */ - protected AsyncSupportResolver createAsyncSupportResolver() { - return new DefaultAsyncSupportResolver(config); - } - - - /** - * Auto detect the underlying Servlet Container we are running on. - */ - protected void autoDetectContainer() { - // Was defined in atmosphere.xml - if (getAsyncSupport() == null) { - setAsyncSupport(createAsyncSupportResolver() - .resolve(useNativeImplementation, useBlockingImplementation, webSocketEnabled)); - } - - logger.info("Atmosphere is using async support: {} running under container: {}", - getAsyncSupport().getClass().getName(), asyncSupport.getContainerName()); - } - - /** - * Auto detect instance of {@link AtmosphereHandler} in case META-INF/atmosphere.xml - * is missing. - * - * @param servletContext {@link ServletContext} - * @param classloader {@link URLClassLoader} to load the class. - * @throws java.net.MalformedURLException - * @throws java.net.URISyntaxException - */ - public void autoDetectAtmosphereHandlers(ServletContext servletContext, URLClassLoader classloader) - throws MalformedURLException, URISyntaxException { - - // If Handler has been added - if (atmosphereHandlers.size() > 0) return; - - logger.info("Auto detecting atmosphere handlers {}", handlersPath); - - String realPath = servletContext.getRealPath(handlersPath); - - // Weblogic bug - if (realPath == null) { - URL u = servletContext.getResource(handlersPath); - if (u == null) return; - realPath = u.getPath(); - } - - loadAtmosphereHandlersFromPath(classloader, realPath); - } - - public void loadAtmosphereHandlersFromPath(URLClassLoader classloader, String realPath) { - File file = new File(realPath); - - if (file.isDirectory()) { - getFiles(file); - scanDone = true; - - for (String className : possibleComponentsCandidate) { - try { - className = className.replace('\\', '/'); - className = className.replaceFirst("^.*/(WEB-INF|target)(?:/scala-[^/]+)?/(test-)?classes/(.*)\\.class", "$3").replace("/", "."); - Class clazz = classloader.loadClass(className); - - if (AtmosphereHandler.class.isAssignableFrom(clazz)) { - AtmosphereHandler handler = (AtmosphereHandler) clazz.newInstance(); - InjectorProvider.getInjector().inject(handler); - addMapping("/" + handler.getClass().getSimpleName(), - new AtmosphereHandlerWrapper(broadcasterFactory, handler, "/" + handler.getClass().getSimpleName())); - logger.info("Installed AtmosphereHandler {} mapped to context-path: {}", handler, handler.getClass().getName()); - } - } catch (Throwable t) { - logger.trace("failed to load class as an AtmosphereHandler: " + className, t); - } - } - } - } - - /** - * Auto detect instance of {@link org.atmosphere.websocket.WebSocketHandler} in case META-INF/atmosphere.xml - * is missing. - * - * @param servletContext {@link ServletContext} - * @param classloader {@link URLClassLoader} to load the class. - * @throws java.net.MalformedURLException - * @throws java.net.URISyntaxException - */ - protected void autoDetectWebSocketHandler(ServletContext servletContext, URLClassLoader classloader) - throws MalformedURLException, URISyntaxException { - - if (hasNewWebSocketProtocol) return; - - logger.info("Auto detecting WebSocketHandler in {}", handlersPath); - - String realPath = servletContext.getRealPath(handlersPath); - - // Weblogic bug - if (realPath == null) { - URL u = servletContext.getResource(handlersPath); - if (u == null) return; - realPath = u.getPath(); - } - - loadWebSocketFromPath(classloader, realPath); - } - - protected void loadWebSocketFromPath(URLClassLoader classloader, String realPath) { - File file = new File(realPath); - - if (file.isDirectory()) { - getFiles(file); - scanDone = true; - - for (String className : possibleComponentsCandidate) { - try { - className = className.replace('\\', '/'); - className = className.replaceFirst("^.*/(WEB-INF|target)(?:/scala-[^/]+)?/(test-)?classes/(.*)\\.class", "$3").replace("/", "."); - Class clazz = classloader.loadClass(className); - - if (WebSocketProtocol.class.isAssignableFrom(clazz)) { - webSocketProtocol = (WebSocketProtocol) clazz.newInstance(); - InjectorProvider.getInjector().inject(webSocketProtocol); - logger.info("Installed WebSocketProtocol {}", webSocketProtocol); - } - } catch (Throwable t) { - logger.trace("failed to load class as an WebSocketProtocol: " + className, t); - } - } - } - } - - - /** - * Get the list of possible candidate to load as {@link AtmosphereHandler} - * - * @param f the real path {@link File} - */ - private void getFiles(File f) { - if (scanDone) return; - - File[] files = f.listFiles(); - for (File test : files) { - if (test.isDirectory()) { - getFiles(test); - } else { - String clazz = test.getAbsolutePath(); - if (clazz.endsWith(".class")) { - possibleComponentsCandidate.add(clazz); - } - } - } - } - - /** - * Invoke the proprietary {@link AsyncSupport} - * - * @param req - * @param res - * @return an {@link Action} - * @throws IOException - * @throws ServletException - */ - public Action doCometSupport(AtmosphereRequest req, AtmosphereResponse res) throws IOException, ServletException { - req.setAttribute(BROADCASTER_FACTORY, broadcasterFactory); - req.setAttribute(PROPERTY_USE_STREAM, useStreamForFlushingComments); - req.setAttribute(BROADCASTER_CLASS, broadcasterClassName); - req.setAttribute(ATMOSPHERE_CONFIG, config); - - Action a = null; - try { - boolean skip = true; - String s = config.getInitParameter(ALLOW_QUERYSTRING_AS_REQUEST); - if (s != null) { - skip = Boolean.valueOf(s); - } - if (!skip || req.getAttribute(WEBSOCKET_SUSPEND) == null) { - Map headers = configureQueryStringAsRequest(req); - String body = headers.remove(ATMOSPHERE_POST_BODY); - if (body != null && body.isEmpty()) { - body = null; - } - - req.headers(headers) - .method(body != null && req.getMethod().equalsIgnoreCase("GET") ? "POST" : req.getMethod()); - - if (body != null) { - req.body(body); - } - } - - s = req.getHeader(X_ATMOSPHERE_TRACKING_ID); - - // Lookup for websocket - if (s == null || s.equals("0")) { - String unique = config.getInitParameter(ApplicationConfig.UNIQUE_UUID_WEBSOCKET); - if (unique != null && Boolean.valueOf(unique)) { - s = (String) req.getAttribute(SUSPENDED_ATMOSPHERE_RESOURCE_UUID); - } - } - - if (s == null || s.equals("0")) { - s = UUID.randomUUID().toString(); - res.setHeader(X_ATMOSPHERE_TRACKING_ID, s); - } else { - // This may breaks 1.0.0 application because the WebSocket's associated AtmosphereResource will - // all have the same UUID, and retrieving the original one for WebSocket, so we don't set it at all. - // Null means it is not an HTTP request. - if (req.resource() == null) { - res.setHeader(X_ATMOSPHERE_TRACKING_ID, s); - } else if (req.getAttribute(WebSocket.WEBSOCKET_INITIATED) == null) { - // WebSocket reconnect, in case an application manually set the header - // (impossible to retrieve the headers normally with WebSocket or SSE) - res.setHeader(X_ATMOSPHERE_TRACKING_ID, s); - } - } - - if (req.getAttribute(SUSPENDED_ATMOSPHERE_RESOURCE_UUID) == null) { - req.setAttribute(SUSPENDED_ATMOSPHERE_RESOURCE_UUID, s); - } - - a = asyncSupport.service(req, res); - } catch (IllegalStateException ex) { - if (ex.getMessage() != null && (ex.getMessage().startsWith("Tomcat failed") || ex.getMessage().startsWith("JBoss failed"))) { - if (!isFilter) { - logger.warn("Failed using comet support: {}, error: {} Is the Nio or Apr Connector enabled?", asyncSupport.getClass().getName(), - ex.getMessage()); - } - logger.trace(ex.getMessage(), ex); - - AsyncSupport current = asyncSupport; - asyncSupport = asyncSupport.supportWebSocket() ? new Tomcat7BIOSupportWithWebSocket(config) : new BlockingIOCometSupport(config); - if (current instanceof AsynchronousProcessor) { - ((AsynchronousProcessor) current).shutdown(); - } - - asyncSupport.init(config.getServletConfig()); - logger.warn("Using " + asyncSupport.getClass().getName()); - - a = asyncSupport.service(req, res); - } else { - logger.error("AtmosphereFramework exception", ex); - throw ex; - } - } finally { - if (a != null) { - notify(a.type(), req, res); - } - - if (req != null && a != null && a.type() != Action.TYPE.SUSPEND) { - req.destroy(); - res.destroy(); - notify(Action.TYPE.DESTROYED, req, res); - } - } - return a; - } - - /** - * Return the default {@link Broadcaster} class name. - * - * @return the broadcasterClassName - */ - public String getDefaultBroadcasterClassName() { - return broadcasterClassName; - } - - /** - * Set the default {@link Broadcaster} class name - * - * @param bccn the broadcasterClassName to set - */ - public AtmosphereFramework setDefaultBroadcasterClassName(String bccn) { - broadcasterClassName = bccn; - return this; - } - - /** - * true if Atmosphere uses {@link AtmosphereResponse#getOutputStream()} - * by default for write operation. - * - * @return the useStreamForFlushingComments - */ - public boolean isUseStreamForFlushingComments() { - return useStreamForFlushingComments; - } - - /** - * Set to true so Atmosphere uses {@link AtmosphereResponse#getOutputStream()} - * by default for write operation. Default is false. - * - * @param useStreamForFlushingComments the useStreamForFlushingComments to set - */ - public AtmosphereFramework setUseStreamForFlushingComments(boolean useStreamForFlushingComments) { - this.useStreamForFlushingComments = useStreamForFlushingComments; - return this; - } - - /** - * Get the {@link BroadcasterFactory} which is used by Atmosphere to construct - * {@link Broadcaster} - * - * @return {@link BroadcasterFactory} - */ - public BroadcasterFactory getBroadcasterFactory() { - return broadcasterFactory; - } - - /** - * Set the {@link BroadcasterFactory} which is used by Atmosphere to construct - * {@link Broadcaster} - * - * @return {@link BroadcasterFactory} - */ - public AtmosphereFramework setBroadcasterFactory(final BroadcasterFactory broadcasterFactory) { - this.broadcasterFactory = broadcasterFactory; - configureBroadcaster(); - return this; - } - - /** - * Return the {@link org.atmosphere.cpr.BroadcasterCache} class name. - * - * @return the {@link org.atmosphere.cpr.BroadcasterCache} class name. - */ - public String getBroadcasterCacheClassName() { - return broadcasterCacheClassName; - } - - /** - * Set the {@link org.atmosphere.cpr.BroadcasterCache} class name. - * - * @param broadcasterCacheClassName - */ - public void setBroadcasterCacheClassName(String broadcasterCacheClassName) { - this.broadcasterCacheClassName = broadcasterCacheClassName; - configureBroadcaster(); - } - - /** - * Add a new Broadcaster class name AtmosphereServlet can use when initializing requests, and when - * atmosphere.xml broadcaster element is unspecified. - * - * @param broadcasterTypeString - */ - public AtmosphereFramework addBroadcasterType(String broadcasterTypeString) { - broadcasterTypes.add(broadcasterTypeString); - return this; - } - - public String getWebSocketProtocolClassName() { - return webSocketProtocolClassName; - } - - public AtmosphereFramework setWebSocketProtocolClassName(String webSocketProtocolClassName) { - hasNewWebSocketProtocol = true; - this.webSocketProtocolClassName = webSocketProtocolClassName; - return this; - } - - public Map getAtmosphereHandlers() { - return atmosphereHandlers; - } - - protected Map configureQueryStringAsRequest(AtmosphereRequest request) { - Map headers = new HashMap(); - - Enumeration e = request.getParameterNames(); - String s; - while (e.hasMoreElements()) { - s = e.nextElement(); - if (s.equalsIgnoreCase("Content-Type")) { - // Use the one set by the user first. - if (request.getContentType() == null || - !request.getContentType().equalsIgnoreCase(request.getParameter(s))) { - request.contentType(request.getParameter(s)); - } - } - headers.put(s, request.getParameter(s)); - } - logger.trace("Query String translated to headers {}", headers); - return headers; - } - - protected boolean isIECandidate(AtmosphereRequest request) { - String userAgent = request.getHeader("User-Agent"); - if (userAgent == null) return false; - - if (userAgent.contains("MSIE") || userAgent.contains(".NET")) { - // Now check the header - String transport = request.getHeader(HeaderConfig.X_ATMOSPHERE_TRANSPORT); - if (transport != null) { - return false; - } else { - return true; - } - } - return false; - } - - public WebSocketProtocol getWebSocketProtocol() { - // TODO: Spagetthi code, needs to rework. - // Make sure we initialized the WebSocketProtocol - initWebSocket(); - return webSocketProtocol; - } - - public boolean isUseNativeImplementation() { - return useNativeImplementation; - } - - public AtmosphereFramework setUseNativeImplementation(boolean useNativeImplementation) { - this.useNativeImplementation = useNativeImplementation; - return this; - } - - public boolean isUseBlockingImplementation() { - return useBlockingImplementation; - } - - public AtmosphereFramework setUseBlockingImplementation(boolean useBlockingImplementation) { - this.useBlockingImplementation = useBlockingImplementation; - return this; - } - - public String getAtmosphereDotXmlPath() { - return atmosphereDotXmlPath; - } - - public AtmosphereFramework setAtmosphereDotXmlPath(String atmosphereDotXmlPath) { - this.atmosphereDotXmlPath = atmosphereDotXmlPath; - return this; - } - - public String getHandlersPath() { - return handlersPath; - } - - public AtmosphereFramework setHandlersPath(String handlersPath) { - this.handlersPath = handlersPath; - return this; - } - - /** - * Return the location of the jars containing the application classes. Default is WEB-INF/lib - * - * @return the location of the jars containing the application classes. Default is WEB-INF/lib - */ - public String getLibPath() { - return libPath; - } - - /** - * Set the location of the jars containing the application. - * - * @param libPath the location of the jars containing the application. - * @return this - */ - public AtmosphereFramework setLibPath(String libPath) { - this.libPath = libPath; - return this; - } - - public String getWebSocketProcessorClassName() { - return webSocketProcessorClassName; - } - - public AtmosphereFramework setWebsocketProcessorClassName(String webSocketProcessorClassName) { - this.webSocketProcessorClassName = webSocketProcessorClassName; - return this; - } - - /** - * Add an {@link AtmosphereInterceptor} implementation. The adding order or {@link AtmosphereInterceptor} will be used, e.g - * the first added {@link AtmosphereInterceptor} will always be called first. - * - * @param c {@link AtmosphereInterceptor} - * @return this - */ - public AtmosphereFramework interceptor(AtmosphereInterceptor c) { - boolean found = false; - for (AtmosphereInterceptor interceptor : interceptors) { - if (interceptor.getClass().equals(c.getClass())) { - found = true; - break; - } - } - - if (!found) { - interceptors.addLast(c); - logger.info("Installed AtmosphereInterceptor {}. ", c); - } - return this; - } - - /** - * Return the list of {@link AtmosphereInterceptor} - * - * @return the list of {@link AtmosphereInterceptor} - */ - public LinkedList interceptors() { - return interceptors; - } - - /** - * Set the {@link AnnotationProcessor} class name. - * - * @param annotationProcessorClassName the {@link AnnotationProcessor} class name. - * @return this - */ - public AtmosphereFramework annotationProcessorClassName(String annotationProcessorClassName) { - this.annotationProcessorClassName = annotationProcessorClassName; - return this; - } - - /** - * Add an {@link AsyncSupportListener} - * - * @param asyncSupportListener an {@link AsyncSupportListener} - * @return this; - */ - public AtmosphereFramework asyncSupportListener(AsyncSupportListener asyncSupportListener) { - asyncSupportListeners.add(asyncSupportListener); - return this; - } - - /** - * Return the list of an {@link AsyncSupportListener} - * - * @return - */ - public List asyncSupportListeners() { - return asyncSupportListeners; - } - - /** - * Add {@link BroadcasterListener} to all created {@link Broadcaster} - */ - public AtmosphereFramework addBroadcasterListener(BroadcasterListener b) { - if (isInit) { - broadcasterFactory.addBroadcasterListener(b); - } else { - broadcasterListeners.add(b); - } - return this; - } - - /** - * Return a configured instance of {@link AtmosphereConfig} - * - * @return a configured instance of {@link AtmosphereConfig} - */ - public AtmosphereConfig getAtmosphereConfig() { - return config; - } - - @Override - public ServletContext getServletContext() { - return servletConfig.getServletContext(); - } - - public ServletConfig getServletConfig() { - return servletConfig; - } - - /** - * Return the list of {@link BroadcastFilter} - * - * @return the list of {@link BroadcastFilter - */ - public List broadcasterFilters() { - return broadcasterFilters; - } - - /** - * Returns true if {@link java.util.concurrent.ExecutorService} shared amongst all components. - * - * @return true if {@link java.util.concurrent.ExecutorService} shared amongst all components. - */ - public boolean isShareExecutorServices() { - return sharedThreadPools; - } - - /** - * Set to true to have a {@link java.util.concurrent.ExecutorService} shared amongst all components. - * - * @param sharedThreadPools - * @return this - */ - public AtmosphereFramework shareExecutorServices(boolean sharedThreadPools) { - this.sharedThreadPools = sharedThreadPools; - return this; - } - - protected void autoConfigureService(ServletContext sc) throws IOException { - final ClassLoader cl = Thread.currentThread().getContextClassLoader(); - - String path = libPath != DEFAULT_LIB_PATH ? libPath : sc.getRealPath(handlersPath); - try { - AnnotationProcessor p = (AnnotationProcessor) cl.loadClass(annotationProcessorClassName).newInstance(); - logger.info("Atmosphere is using {} for processing annotation", annotationProcessorClassName); - - p.configure(this); - if (path != null) { - p.scan(new File(path)); - } - - String pathLibs = sc.getRealPath(DEFAULT_LIB_PATH); - if (pathLibs != null) { - File libFolder = new File(pathLibs); - File jars[] = libFolder.listFiles(new FilenameFilter() { - - @Override - public boolean accept(File arg0, String arg1) { - return arg1.endsWith(".jar"); - } - }); - - for (File file : jars) { - p.scan(file); - } - } - } catch (Throwable e) { - logger.debug("Atmosphere's Service Annotation Not Supported. Please add https://github.com/rmuller/infomas-asl as dependencies or your own AnnotationProcessor to support @Service"); - logger.trace("", e); - return; - } - } - - protected void notify(Action.TYPE type, AtmosphereRequest request, AtmosphereResponse response) { - for (AsyncSupportListener l : asyncSupportListeners()) { - try { - switch (type) { - case TIMEOUT: - l.onTimeout(request, response); - break; - case CANCELLED: - l.onClose(request, response); - break; - case SUSPEND: - l.onSuspend(request, response); - break; - case RESUME: - l.onSuspend(request, response); - break; - case DESTROYED: - l.onDestroyed(request, response); - break; - } - } catch (Throwable t) { - logger.warn("", t); - } - } - } -} \ No newline at end of file diff --git a/server/src/com/vaadin/server/Constants.java b/server/src/com/vaadin/server/Constants.java index f8d8105286..cf1031dab2 100644 --- a/server/src/com/vaadin/server/Constants.java +++ b/server/src/com/vaadin/server/Constants.java @@ -65,11 +65,11 @@ public interface Constants { + " Widgetset version: %s\n" + "================================================================="; - static final String REQUIRED_ATMOSPHERE_VERSION = "1.0.12"; + static final String REQUIRED_ATMOSPHERE_VERSION = "1.0.13"; static final String INVALID_ATMOSPHERE_VERSION_WARNING = "\n" + "=================================================================\n" - + "Vaadin depends on Atomsphere {0} but version {1} was found.\n" + + "Vaadin depends on Atmosphere {0} but version {1} was found.\n" + "This might cause compatibility problems if push is used.\n" + "================================================================="; diff --git a/shared/src/com/vaadin/shared/communication/PushConstants.java b/shared/src/com/vaadin/shared/communication/PushConstants.java index 2d63621c12..f16cbb7390 100644 --- a/shared/src/com/vaadin/shared/communication/PushConstants.java +++ b/shared/src/com/vaadin/shared/communication/PushConstants.java @@ -42,5 +42,5 @@ public class PushConstants implements Serializable { * The character used to mark message boundaries when messages may be split * into multiple fragments. */ - public static final char MESSAGE_DELIMITER = '\0'; + public static final char MESSAGE_DELIMITER = '|'; } -- cgit v1.2.3 From fea4c5e4f7170a302df2d72441f94dccbab95b4e Mon Sep 17 00:00:00 2001 From: Leif Åstrand Date: Tue, 21 May 2013 15:13:07 +0300 Subject: Don't build and publish sources for package without source files Change-Id: If8c4a5d9ff470703943f6f6f9cd599ecd1d4be49 --- push/build.xml | 3 --- push/ivy.xml | 2 ++ 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/push/build.xml b/push/build.xml index 953416cf2d..3e750b67cd 100644 --- a/push/build.xml +++ b/push/build.xml @@ -59,9 +59,6 @@ - - - diff --git a/push/ivy.xml b/push/ivy.xml index 4834342f00..69b7661fca 100644 --- a/push/ivy.xml +++ b/push/ivy.xml @@ -15,8 +15,10 @@ + -- cgit v1.2.3 From 158c162d688fdfa701f9c6c9035e27d9f64a312f Mon Sep 17 00:00:00 2001 From: Henri Sara Date: Tue, 21 May 2013 15:57:18 +0300 Subject: Do not clear combobox text unnecessarily (#10924, #11887) Change-Id: Ica66c1d7ca05874ca5a05fb2c9651a6e4758e1d9 --- client/src/com/vaadin/client/ui/combobox/ComboBoxConnector.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/client/src/com/vaadin/client/ui/combobox/ComboBoxConnector.java b/client/src/com/vaadin/client/ui/combobox/ComboBoxConnector.java index 345bdc0cbb..d9eac91e2b 100644 --- a/client/src/com/vaadin/client/ui/combobox/ComboBoxConnector.java +++ b/client/src/com/vaadin/client/ui/combobox/ComboBoxConnector.java @@ -252,8 +252,11 @@ public class ComboBoxConnector extends AbstractFieldConnector implements getWidget().setPromptingOn(); } else { // we have focus in field, prompting can't be set on, instead - // just clear the input - getWidget().tb.setValue(""); + // just clear the input if the value has changed from something + // else to null + if (getWidget().selectedOptionKey != null) { + getWidget().tb.setValue(""); + } } getWidget().setSelectedItemIcon(null); getWidget().selectedOptionKey = null; -- cgit v1.2.3 From 6a7683bedbdc745a6296a44a0328d61172181442 Mon Sep 17 00:00:00 2001 From: Leif Åstrand Date: Tue, 21 May 2013 15:57:33 +0300 Subject: Disable Atmosphere version number check (#11890) Change-Id: I8f04cc0ddc034ce7cb43cc7f6646ddffcba64a4b --- server/src/com/vaadin/server/communication/PushRequestHandler.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/server/src/com/vaadin/server/communication/PushRequestHandler.java b/server/src/com/vaadin/server/communication/PushRequestHandler.java index e75798a980..8d0da24896 100644 --- a/server/src/com/vaadin/server/communication/PushRequestHandler.java +++ b/server/src/com/vaadin/server/communication/PushRequestHandler.java @@ -56,7 +56,12 @@ public class PushRequestHandler implements RequestHandler, public PushRequestHandler(VaadinServletService service) throws ServiceException { - atmosphere = new AtmosphereFramework(); + atmosphere = new AtmosphereFramework() { + @Override + protected void analytics() { + // Overridden to disable version number check + } + }; pushHandler = new PushHandler(service); atmosphere.addAtmosphereHandler("/*", pushHandler); -- cgit v1.2.3 From ebb92e621a3dee4253f3618a32edcd59ee51ef69 Mon Sep 17 00:00:00 2001 From: Johannes Dahlström Date: Wed, 22 May 2013 12:09:00 +0300 Subject: Improve error message if vaadinPush.js failed to load (#11673) Change-Id: I46a2622585ed69a1db4c6abf4aca4387387a0f97 --- .../com/vaadin/client/ApplicationConnection.java | 8 +++++- .../communication/AtmospherePushConnection.java | 31 +++++++++++++++------- .../client/communication/PushConnection.java | 4 ++- 3 files changed, 32 insertions(+), 11 deletions(-) diff --git a/client/src/com/vaadin/client/ApplicationConnection.java b/client/src/com/vaadin/client/ApplicationConnection.java index 4141f9f2dc..087ee87262 100644 --- a/client/src/com/vaadin/client/ApplicationConnection.java +++ b/client/src/com/vaadin/client/ApplicationConnection.java @@ -3404,7 +3404,13 @@ public class ApplicationConnection { public void setPushEnabled(boolean enabled) { if (enabled && push == null) { push = GWT.create(PushConnection.class); - push.init(this); + push.init(this, new CommunicationErrorHandler() { + @Override + public boolean onError(String details, int statusCode) { + showCommunicationError(details, statusCode); + return true; + } + }); } else if (!enabled && push != null && push.isActive()) { push.disconnect(new Command() { @Override diff --git a/client/src/com/vaadin/client/communication/AtmospherePushConnection.java b/client/src/com/vaadin/client/communication/AtmospherePushConnection.java index ce3253ed50..997e84145c 100644 --- a/client/src/com/vaadin/client/communication/AtmospherePushConnection.java +++ b/client/src/com/vaadin/client/communication/AtmospherePushConnection.java @@ -22,6 +22,7 @@ import com.google.gwt.core.client.JavaScriptObject; import com.google.gwt.core.client.Scheduler; import com.google.gwt.user.client.Command; import com.vaadin.client.ApplicationConnection; +import com.vaadin.client.ApplicationConnection.CommunicationErrorHandler; import com.vaadin.client.ResourceLoader; import com.vaadin.client.ResourceLoader.ResourceLoadEvent; import com.vaadin.client.ResourceLoader.ResourceLoadListener; @@ -117,6 +118,8 @@ public class AtmospherePushConnection implements PushConnection { private String transport; + private CommunicationErrorHandler errorHandler; + /** * Keeps track of the disconnect confirmation command for cases where * pending messages should be pushed before actually disconnecting. @@ -134,8 +137,10 @@ public class AtmospherePushConnection implements PushConnection { * .ApplicationConnection) */ @Override - public void init(final ApplicationConnection connection) { + public void init(final ApplicationConnection connection, + CommunicationErrorHandler errorHandler) { this.connection = connection; + this.errorHandler = errorHandler; runWhenAtmosphereLoaded(new Command() { @Override @@ -433,22 +438,30 @@ public class AtmospherePushConnection implements PushConnection { if (isAtmosphereLoaded()) { command.execute(); } else { - VConsole.log("Loading " + ApplicationConstants.VAADIN_PUSH_JS); + final String pushJs = ApplicationConstants.VAADIN_PUSH_JS; + VConsole.log("Loading " + pushJs); ResourceLoader.get().loadScript( - connection.getConfiguration().getVaadinDirUrl() - + ApplicationConstants.VAADIN_PUSH_JS, + connection.getConfiguration().getVaadinDirUrl() + pushJs, new ResourceLoadListener() { @Override public void onLoad(ResourceLoadEvent event) { - VConsole.log(ApplicationConstants.VAADIN_PUSH_JS - + " loaded"); - command.execute(); + if (isAtmosphereLoaded()) { + VConsole.log(pushJs + " loaded"); + command.execute(); + } else { + // If bootstrap tried to load vaadinPush.js, + // ResourceLoader assumes it succeeded even if + // it failed (#11673) + onError(event); + } } @Override public void onError(ResourceLoadEvent event) { - VConsole.error(event.getResourceUrl() - + " could not be loaded. Push will not work."); + errorHandler.onError( + event.getResourceUrl() + + " could not be loaded. Push will not work.", + 0); } }); } diff --git a/client/src/com/vaadin/client/communication/PushConnection.java b/client/src/com/vaadin/client/communication/PushConnection.java index 61656242bd..a4a3bbc0cc 100644 --- a/client/src/com/vaadin/client/communication/PushConnection.java +++ b/client/src/com/vaadin/client/communication/PushConnection.java @@ -18,6 +18,7 @@ package com.vaadin.client.communication; import com.google.gwt.user.client.Command; import com.vaadin.client.ApplicationConnection; +import com.vaadin.client.ApplicationConnection.CommunicationErrorHandler; /** * Represents the client-side endpoint of a bidirectional ("push") communication @@ -37,7 +38,8 @@ public interface PushConnection { * @param connection * The ApplicationConnection */ - public void init(ApplicationConnection connection); + public void init(ApplicationConnection connection, + CommunicationErrorHandler errorHandler); /** * Pushes a message to the server. Will throw an exception if the connection -- cgit v1.2.3 From 70131cdb9ba6ecb505a7b627db03ad9d739d7c66 Mon Sep 17 00:00:00 2001 From: Artur Signell Date: Tue, 18 Dec 2012 10:00:14 +0200 Subject: Extracted common code for number conveters to abstract super class (#11900) Change-Id: I53e413f8e9c8754915d80c30d3dca97eb1881c74 --- .../converter/AbstractStringToNumberConverter.java | 120 +++++++++++++++++++++ .../util/converter/StringToDoubleConverter.java | 67 +----------- .../util/converter/StringToFloatConverter.java | 67 +----------- .../util/converter/StringToIntegerConverter.java | 54 +++------- .../util/converter/StringToNumberConverter.java | 69 +----------- 5 files changed, 148 insertions(+), 229 deletions(-) create mode 100644 server/src/com/vaadin/data/util/converter/AbstractStringToNumberConverter.java diff --git a/server/src/com/vaadin/data/util/converter/AbstractStringToNumberConverter.java b/server/src/com/vaadin/data/util/converter/AbstractStringToNumberConverter.java new file mode 100644 index 0000000000..b9a122ecb5 --- /dev/null +++ b/server/src/com/vaadin/data/util/converter/AbstractStringToNumberConverter.java @@ -0,0 +1,120 @@ +/* + * Copyright 2012 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.data.util.converter; + +import java.text.NumberFormat; +import java.text.ParsePosition; +import java.util.Locale; + +/** + * A converter that converts from the number type T to {@link String} and back. + * Uses the given locale and {@link NumberFormat} for formatting and parsing. + * Automatically trims the input string, removing any leading and trailing white + * space. + *

+ * Override and overwrite {@link #getFormat(Locale)} to use a different format. + *

+ * + * @author Vaadin Ltd + * @since 7.1 + */ +public abstract class AbstractStringToNumberConverter implements + Converter { + + /** + * Returns the format used by {@link #convertToPresentation(Object, Locale)} + * and {@link #convertToModel(Object, Locale)}. + * + * @param locale + * The locale to use + * @return A NumberFormat instance + * @since 7.1 + */ + protected NumberFormat getFormat(Locale locale) { + if (locale == null) { + locale = Locale.getDefault(); + } + + return NumberFormat.getNumberInstance(locale); + } + + /** + * Convert the value to a Number using the given locale and + * {@link #getFormat(Locale)}. + * + * @param value + * The value to convert + * @param locale + * The locale to use for conversion + * @return The converted value + * @throws ConversionException + * If there was a problem converting the value + * @since 7.1 + */ + protected Number convertToNumber(String value, Locale locale) + throws ConversionException { + if (value == null) { + return null; + } + + // Remove leading and trailing white space + value = value.trim(); + + // Parse and detect errors. If the full string was not used, it is + // an error. + ParsePosition parsePosition = new ParsePosition(0); + Number parsedValue = getFormat(locale).parse(value, parsePosition); + if (parsePosition.getIndex() != value.length()) { + throw new ConversionException("Could not convert '" + value + + "' to " + getModelType().getName()); + } + + if (parsedValue == null) { + // Convert "" to null + return null; + } + return parsedValue; + } + + /* + * (non-Javadoc) + * + * @see + * com.vaadin.data.util.converter.Converter#convertToPresentation(java.lang + * .Object, java.util.Locale) + */ + @Override + public String convertToPresentation(T value, Locale locale) + throws ConversionException { + if (value == null) { + return null; + } + + return getFormat(locale).format(value); + } + + /* + * (non-Javadoc) + * + * @see com.vaadin.data.util.converter.Converter#getPresentationType() + */ + @Override + public Class getPresentationType() { + return String.class; + } + +} diff --git a/server/src/com/vaadin/data/util/converter/StringToDoubleConverter.java b/server/src/com/vaadin/data/util/converter/StringToDoubleConverter.java index 69a0faf8f4..8bb82498b9 100644 --- a/server/src/com/vaadin/data/util/converter/StringToDoubleConverter.java +++ b/server/src/com/vaadin/data/util/converter/StringToDoubleConverter.java @@ -17,7 +17,6 @@ package com.vaadin.data.util.converter; import java.text.NumberFormat; -import java.text.ParsePosition; import java.util.Locale; /** @@ -34,23 +33,8 @@ import java.util.Locale; * @author Vaadin Ltd * @since 7.0 */ -public class StringToDoubleConverter implements Converter { - - /** - * Returns the format used by {@link #convertToPresentation(Double, Locale)} - * and {@link #convertToModel(String, Locale)}. - * - * @param locale - * The locale to use - * @return A NumberFormat instance - */ - protected NumberFormat getFormat(Locale locale) { - if (locale == null) { - locale = Locale.getDefault(); - } - - return NumberFormat.getNumberInstance(locale); - } +public class StringToDoubleConverter extends + AbstractStringToNumberConverter { /* * (non-Javadoc) @@ -62,42 +46,8 @@ public class StringToDoubleConverter implements Converter { @Override public Double convertToModel(String value, Locale locale) throws ConversionException { - if (value == null) { - return null; - } - - // Remove leading and trailing white space - value = value.trim(); - - ParsePosition parsePosition = new ParsePosition(0); - Number parsedValue = getFormat(locale).parse(value, parsePosition); - if (parsePosition.getIndex() != value.length()) { - throw new ConversionException("Could not convert '" + value - + "' to " + getModelType().getName()); - } - if (parsedValue == null) { - // Convert "" to null - return null; - } - - return parsedValue.doubleValue(); - } - - /* - * (non-Javadoc) - * - * @see - * com.vaadin.data.util.converter.Converter#convertToPresentation(java.lang - * .Object, java.util.Locale) - */ - @Override - public String convertToPresentation(Double value, Locale locale) - throws ConversionException { - if (value == null) { - return null; - } - - return getFormat(locale).format(value); + Number n = convertToNumber(value, locale); + return n == null ? null : n.doubleValue(); } /* @@ -110,13 +60,4 @@ public class StringToDoubleConverter implements Converter { return Double.class; } - /* - * (non-Javadoc) - * - * @see com.vaadin.data.util.converter.Converter#getPresentationType() - */ - @Override - public Class getPresentationType() { - return String.class; - } } diff --git a/server/src/com/vaadin/data/util/converter/StringToFloatConverter.java b/server/src/com/vaadin/data/util/converter/StringToFloatConverter.java index 1adfd87565..a207654358 100644 --- a/server/src/com/vaadin/data/util/converter/StringToFloatConverter.java +++ b/server/src/com/vaadin/data/util/converter/StringToFloatConverter.java @@ -17,7 +17,6 @@ package com.vaadin.data.util.converter; import java.text.NumberFormat; -import java.text.ParsePosition; import java.util.Locale; /** @@ -34,23 +33,8 @@ import java.util.Locale; * @author Vaadin Ltd * @since 7.0 */ -public class StringToFloatConverter implements Converter { - - /** - * Returns the format used by {@link #convertToPresentation(Float, Locale)} - * and {@link #convertToModel(String, Locale)}. - * - * @param locale - * The locale to use - * @return A NumberFormat instance - */ - protected NumberFormat getFormat(Locale locale) { - if (locale == null) { - locale = Locale.getDefault(); - } - - return NumberFormat.getNumberInstance(locale); - } +public class StringToFloatConverter extends + AbstractStringToNumberConverter { /* * (non-Javadoc) @@ -62,42 +46,8 @@ public class StringToFloatConverter implements Converter { @Override public Float convertToModel(String value, Locale locale) throws ConversionException { - if (value == null) { - return null; - } - - // Remove leading and trailing white space - value = value.trim(); - - ParsePosition parsePosition = new ParsePosition(0); - Number parsedValue = getFormat(locale).parse(value, parsePosition); - if (parsePosition.getIndex() != value.length()) { - throw new ConversionException("Could not convert '" + value - + "' to " + getModelType().getName()); - } - if (parsedValue == null) { - // Convert "" to null - return null; - } - - return parsedValue.floatValue(); - } - - /* - * (non-Javadoc) - * - * @see - * com.vaadin.data.util.converter.Converter#convertToPresentation(java.lang - * .Object, java.util.Locale) - */ - @Override - public String convertToPresentation(Float value, Locale locale) - throws ConversionException { - if (value == null) { - return null; - } - - return getFormat(locale).format(value); + Number n = convertToNumber(value, locale); + return n == null ? null : n.floatValue(); } /* @@ -110,13 +60,4 @@ public class StringToFloatConverter implements Converter { return Float.class; } - /* - * (non-Javadoc) - * - * @see com.vaadin.data.util.converter.Converter#getPresentationType() - */ - @Override - public Class getPresentationType() { - return String.class; - } } diff --git a/server/src/com/vaadin/data/util/converter/StringToIntegerConverter.java b/server/src/com/vaadin/data/util/converter/StringToIntegerConverter.java index 4bb933bcc8..4f34cf1cd3 100644 --- a/server/src/com/vaadin/data/util/converter/StringToIntegerConverter.java +++ b/server/src/com/vaadin/data/util/converter/StringToIntegerConverter.java @@ -17,7 +17,6 @@ package com.vaadin.data.util.converter; import java.text.NumberFormat; -import java.text.ParsePosition; import java.util.Locale; /** @@ -31,7 +30,8 @@ import java.util.Locale; * @author Vaadin Ltd * @since 7.0 */ -public class StringToIntegerConverter implements Converter { +public class StringToIntegerConverter extends + AbstractStringToNumberConverter { /** * Returns the format used by @@ -42,6 +42,7 @@ public class StringToIntegerConverter implements Converter { * The locale to use * @return A NumberFormat instance */ + @Override protected NumberFormat getFormat(Locale locale) { if (locale == null) { locale = Locale.getDefault(); @@ -49,50 +50,29 @@ public class StringToIntegerConverter implements Converter { return NumberFormat.getIntegerInstance(locale); } + /* + * (non-Javadoc) + * + * @see + * com.vaadin.data.util.converter.Converter#convertToModel(java.lang.Object, + * java.util.Locale) + */ @Override public Integer convertToModel(String value, Locale locale) throws ConversionException { - if (value == null) { - return null; - } - - // Remove leading and trailing white space - value = value.trim(); + Number n = convertToNumber(value, locale); + return n == null ? null : n.intValue(); - // Parse and detect errors. If the full string was not used, it is - // an error. - ParsePosition parsePosition = new ParsePosition(0); - Number parsedValue = getFormat(locale).parse(value, parsePosition); - if (parsePosition.getIndex() != value.length()) { - throw new ConversionException("Could not convert '" + value - + "' to " + getModelType().getName()); - } - - if (parsedValue == null) { - // Convert "" to null - return null; - } - return parsedValue.intValue(); - } - - @Override - public String convertToPresentation(Integer value, Locale locale) - throws ConversionException { - if (value == null) { - return null; - } - - return getFormat(locale).format(value); } + /* + * (non-Javadoc) + * + * @see com.vaadin.data.util.converter.Converter#getModelType() + */ @Override public Class getModelType() { return Integer.class; } - @Override - public Class getPresentationType() { - return String.class; - } - } diff --git a/server/src/com/vaadin/data/util/converter/StringToNumberConverter.java b/server/src/com/vaadin/data/util/converter/StringToNumberConverter.java index 99ff7007ad..eae73e4cfa 100644 --- a/server/src/com/vaadin/data/util/converter/StringToNumberConverter.java +++ b/server/src/com/vaadin/data/util/converter/StringToNumberConverter.java @@ -17,7 +17,6 @@ package com.vaadin.data.util.converter; import java.text.NumberFormat; -import java.text.ParsePosition; import java.util.Locale; /** @@ -30,23 +29,8 @@ import java.util.Locale; * @author Vaadin Ltd * @since 7.0 */ -public class StringToNumberConverter implements Converter { - - /** - * Returns the format used by {@link #convertToPresentation(Number, Locale)} - * and {@link #convertToModel(String, Locale)}. - * - * @param locale - * The locale to use - * @return A NumberFormat instance - */ - protected NumberFormat getFormat(Locale locale) { - if (locale == null) { - locale = Locale.getDefault(); - } - - return NumberFormat.getNumberInstance(locale); - } +public class StringToNumberConverter extends + AbstractStringToNumberConverter { /* * (non-Javadoc) @@ -58,44 +42,7 @@ public class StringToNumberConverter implements Converter { @Override public Number convertToModel(String value, Locale locale) throws ConversionException { - if (value == null) { - return null; - } - - // Remove leading and trailing white space - value = value.trim(); - - // Parse and detect errors. If the full string was not used, it is - // an error. - ParsePosition parsePosition = new ParsePosition(0); - Number parsedValue = getFormat(locale).parse(value, parsePosition); - if (parsePosition.getIndex() != value.length()) { - throw new ConversionException("Could not convert '" + value - + "' to " + getModelType().getName()); - } - - if (parsedValue == null) { - // Convert "" to null - return null; - } - return parsedValue; - } - - /* - * (non-Javadoc) - * - * @see - * com.vaadin.data.util.converter.Converter#convertToPresentation(java.lang - * .Object, java.util.Locale) - */ - @Override - public String convertToPresentation(Number value, Locale locale) - throws ConversionException { - if (value == null) { - return null; - } - - return getFormat(locale).format(value); + return convertToNumber(value, locale); } /* @@ -108,14 +55,4 @@ public class StringToNumberConverter implements Converter { return Number.class; } - /* - * (non-Javadoc) - * - * @see com.vaadin.data.util.converter.Converter#getPresentationType() - */ - @Override - public Class getPresentationType() { - return String.class; - } - } -- cgit v1.2.3 From 0b635061bb9b30e9f28d49fe9606eb3cab2fd3f1 Mon Sep 17 00:00:00 2001 From: Artur Signell Date: Wed, 22 May 2013 16:36:33 +0300 Subject: Fixed order of parameters in javadoc (#11158) Change-Id: I523140051e1034b5fab501517e70209f29b6b869 --- server/src/com/vaadin/data/util/converter/Converter.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/server/src/com/vaadin/data/util/converter/Converter.java b/server/src/com/vaadin/data/util/converter/Converter.java index be9bb32413..ded7da7fb5 100644 --- a/server/src/com/vaadin/data/util/converter/Converter.java +++ b/server/src/com/vaadin/data/util/converter/Converter.java @@ -38,12 +38,12 @@ import java.util.Locale; * If conversion of a value fails, a {@link ConversionException} is thrown. *

* - * @param - * The model type. Must be compatible with what - * {@link #getModelType()} returns. * @param * The presentation type. Must be compatible with what * {@link #getPresentationType()} returns. + * @param + * The model type. Must be compatible with what + * {@link #getModelType()} returns. * @author Vaadin Ltd. * @since 7.0 */ -- cgit v1.2.3 From 6bf83a428aa747f6b46d1d4c4ad2e279971d14e7 Mon Sep 17 00:00:00 2001 From: Artur Signell Date: Tue, 21 May 2013 16:51:32 +0300 Subject: Modified the logic in setPropertyDatasource which determines if a new converter is needed (#11863) The previous logic had two flaws * It allowed converter model type to be a sub type of the model type but not vice versa. Similarly for presentation type. * If the user has set a converter it should be used and not be replaced unless it is absolutely sure that it cannot in any possible way handle conversion (e.g. converter from integer to double cannot handle string to list conversion). If there is a slight chance that it can handle conversion, let it be and let the user set another converter when needed. Change-Id: I2e1c0b3aac90be63ddbc780195f8428398e28ada --- .../vaadin/data/util/converter/ConverterUtil.java | 50 +++++++- server/src/com/vaadin/ui/AbstractField.java | 15 +-- server/src/com/vaadin/ui/Label.java | 9 +- .../tests/data/converter/AnotherTestEnum.java | 16 +++ .../converter/TestAnyEnumToStringConverter.java | 128 +++++++++++++++++++++ .../com/vaadin/tests/data/converter/TestEnum.java | 16 +++ .../TestSpecificEnumToStringConverter.java | 119 +++++++++++++++++++ 7 files changed, 337 insertions(+), 16 deletions(-) create mode 100644 server/tests/src/com/vaadin/tests/data/converter/AnotherTestEnum.java create mode 100644 server/tests/src/com/vaadin/tests/data/converter/TestAnyEnumToStringConverter.java create mode 100644 server/tests/src/com/vaadin/tests/data/converter/TestEnum.java create mode 100644 server/tests/src/com/vaadin/tests/data/converter/TestSpecificEnumToStringConverter.java diff --git a/server/src/com/vaadin/data/util/converter/ConverterUtil.java b/server/src/com/vaadin/data/util/converter/ConverterUtil.java index 61d155bc9a..08d7363084 100644 --- a/server/src/com/vaadin/data/util/converter/ConverterUtil.java +++ b/server/src/com/vaadin/data/util/converter/ConverterUtil.java @@ -151,10 +151,14 @@ public class ConverterUtil implements Serializable { /** * Checks if the given converter can handle conversion between the given - * presentation and model type + * presentation and model type. Does strict type checking and only returns + * true if the converter claims it can handle exactly the given types. + * + * @see #canConverterPossiblyHandle(Converter, Class, Class) * * @param converter - * The converter to check + * The converter to check. If this is null the result is always + * false. * @param presentationType * The presentation type * @param modelType @@ -168,10 +172,48 @@ public class ConverterUtil implements Serializable { return false; } - if (!modelType.isAssignableFrom(converter.getModelType())) { + if (modelType != converter.getModelType()) { + return false; + } + if (presentationType != converter.getPresentationType()) { return false; } - if (!presentationType.isAssignableFrom(converter.getPresentationType())) { + + return true; + } + + /** + * Checks if it possible that the given converter can handle conversion + * between the given presentation and model type somehow. + * + * @param converter + * The converter to check. If this is null the result is always + * false. + * @param presentationType + * The presentation type + * @param modelType + * The model type + * @return true if the converter possibly support conversion between the + * given presentation and model type, false otherwise + */ + public static boolean canConverterPossiblyHandle(Converter converter, + Class presentationType, Class modelType) { + if (converter == null) { + return false; + } + Class converterModelType = converter.getModelType(); + + if (!modelType.isAssignableFrom(converterModelType) + && !converterModelType.isAssignableFrom(modelType)) { + // model types are not compatible in any way + return false; + } + + Class converterPresentationType = converter.getPresentationType(); + if (!presentationType.isAssignableFrom(converterPresentationType) + && !converterPresentationType + .isAssignableFrom(presentationType)) { + // presentation types are not compatible in any way return false; } diff --git a/server/src/com/vaadin/ui/AbstractField.java b/server/src/com/vaadin/ui/AbstractField.java index 3bca63a3b7..606bf5fb21 100644 --- a/server/src/com/vaadin/ui/AbstractField.java +++ b/server/src/com/vaadin/ui/AbstractField.java @@ -616,17 +616,14 @@ public abstract class AbstractField extends AbstractComponent implements // Check if the current converter is compatible. if (newDataSource != null - && !ConverterUtil.canConverterHandle(getConverter(), getType(), - newDataSource.getType())) { - // Changing from e.g. Number -> Double should set a new converter, - // changing from Double -> Number can keep the old one (Property - // accepts Number) - - // Set a new converter if there is a new data source and - // there is no old converter or the old is incompatible. + && !ConverterUtil.canConverterPossiblyHandle(getConverter(), + getType(), newDataSource.getType())) { + // There is no converter set or there is no way the current + // converter can be compatible. setConverter(newDataSource.getType()); } - // Gets the value from source + // Gets the value from source. This requires that a valid converter has + // been set. try { if (dataSource != null) { T fieldValue = convertFromModel(getDataSourceValue()); diff --git a/server/src/com/vaadin/ui/Label.java b/server/src/com/vaadin/ui/Label.java index d037652a09..d7cee2a80d 100644 --- a/server/src/com/vaadin/ui/Label.java +++ b/server/src/com/vaadin/ui/Label.java @@ -242,14 +242,17 @@ public class Label extends AbstractComponent implements Property, ((Property.ValueChangeNotifier) dataSource).removeListener(this); } + // Check if the current converter is compatible. if (newDataSource != null - && !ConverterUtil.canConverterHandle(getConverter(), - String.class, newDataSource.getType())) { - // Try to find a converter + && !ConverterUtil.canConverterPossiblyHandle(getConverter(), + getType(), newDataSource.getType())) { + // There is no converter set or there is no way the current + // converter can be compatible. Converter c = ConverterUtil.getConverter(String.class, newDataSource.getType(), getSession()); setConverter(c); } + dataSource = newDataSource; if (dataSource != null) { // Update the value from the data source. If data source was set to diff --git a/server/tests/src/com/vaadin/tests/data/converter/AnotherTestEnum.java b/server/tests/src/com/vaadin/tests/data/converter/AnotherTestEnum.java new file mode 100644 index 0000000000..33a6a87359 --- /dev/null +++ b/server/tests/src/com/vaadin/tests/data/converter/AnotherTestEnum.java @@ -0,0 +1,16 @@ +package com.vaadin.tests.data.converter; + +public enum AnotherTestEnum { + ONE("ONE"), TWO("TWO"); + + private String id; + + private AnotherTestEnum(String id) { + this.id = id; + } + + @Override + public String toString() { + return id; + } +} diff --git a/server/tests/src/com/vaadin/tests/data/converter/TestAnyEnumToStringConverter.java b/server/tests/src/com/vaadin/tests/data/converter/TestAnyEnumToStringConverter.java new file mode 100644 index 0000000000..baa81ce656 --- /dev/null +++ b/server/tests/src/com/vaadin/tests/data/converter/TestAnyEnumToStringConverter.java @@ -0,0 +1,128 @@ +/* + * Copyright 2000-2013 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.data.converter; + +import java.util.Locale; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +import com.vaadin.data.util.ObjectProperty; +import com.vaadin.data.util.converter.Converter; +import com.vaadin.data.util.converter.ReverseConverter; +import com.vaadin.ui.TextField; + +public class TestAnyEnumToStringConverter { + + public class AnyEnumToStringConverter implements Converter { + + private Class[] enumClass; + + public AnyEnumToStringConverter(Class... enumClass) { + this.enumClass = enumClass; + } + + @Override + public String convertToModel(Enum value, Locale locale) + throws com.vaadin.data.util.converter.Converter.ConversionException { + if (value == null) { + return null; + } + + return value.toString(); + } + + @Override + public Enum convertToPresentation(String value, Locale locale) + throws com.vaadin.data.util.converter.Converter.ConversionException { + if (value == null) { + return null; + } + for (Class candidate : enumClass) { + for (Enum e : candidate.getEnumConstants()) { + if (e.toString().equals(value)) { + return e; + } + } + } + + return null; + } + + @Override + public Class getModelType() { + return String.class; + } + + @Override + public Class getPresentationType() { + return Enum.class; + } + + } + + private AnyEnumToStringConverter converter; + + @Before + public void setup() { + converter = new AnyEnumToStringConverter(TestEnum.class, + AnotherTestEnum.class); + } + + @Test + public void nullConversion() { + Assert.assertEquals(null, converter.convertToModel(null, null)); + } + + @Test + public void enumToStringConversion() { + Assert.assertEquals(TestEnum.TWO.toString(), + converter.convertToModel(TestEnum.TWO, null)); + Assert.assertEquals(AnotherTestEnum.TWO.toString(), + converter.convertToModel(AnotherTestEnum.TWO, null)); + } + + @Test + public void stringToEnumConversion() { + Assert.assertEquals(TestEnum.TWO, + converter.convertToPresentation(TestEnum.TWO.toString(), null)); + Assert.assertEquals(AnotherTestEnum.TWO, converter + .convertToPresentation(AnotherTestEnum.TWO.toString(), null)); + } + + @Test + public void stringToEnumWithField() { + TextField tf = new TextField(); + tf.setConverter(new ReverseConverter(converter)); + tf.setPropertyDataSource(new ObjectProperty(AnotherTestEnum.TWO)); + Assert.assertEquals(AnotherTestEnum.TWO.toString(), tf.getValue()); + tf.setValue(AnotherTestEnum.ONE.toString()); + Assert.assertEquals(AnotherTestEnum.ONE.toString(), tf.getValue()); + Assert.assertEquals(AnotherTestEnum.ONE, tf.getConvertedValue()); + Assert.assertEquals(AnotherTestEnum.ONE, tf.getPropertyDataSource() + .getValue()); + + tf.setPropertyDataSource(new ObjectProperty(TestEnum.TWO)); + Assert.assertEquals(TestEnum.TWO.toString(), tf.getValue()); + tf.setValue(TestEnum.ONE.toString()); + Assert.assertEquals(TestEnum.ONE.toString(), tf.getValue()); + Assert.assertEquals(TestEnum.ONE, tf.getConvertedValue()); + Assert.assertEquals(TestEnum.ONE, tf.getPropertyDataSource().getValue()); + + } +} diff --git a/server/tests/src/com/vaadin/tests/data/converter/TestEnum.java b/server/tests/src/com/vaadin/tests/data/converter/TestEnum.java new file mode 100644 index 0000000000..a4b709a843 --- /dev/null +++ b/server/tests/src/com/vaadin/tests/data/converter/TestEnum.java @@ -0,0 +1,16 @@ +package com.vaadin.tests.data.converter; + +public enum TestEnum { + ONE("1"), TWO("2"); + + private String id; + + private TestEnum(String id) { + this.id = id; + } + + @Override + public String toString() { + return id; + } +} diff --git a/server/tests/src/com/vaadin/tests/data/converter/TestSpecificEnumToStringConverter.java b/server/tests/src/com/vaadin/tests/data/converter/TestSpecificEnumToStringConverter.java new file mode 100644 index 0000000000..ef8c57f7f1 --- /dev/null +++ b/server/tests/src/com/vaadin/tests/data/converter/TestSpecificEnumToStringConverter.java @@ -0,0 +1,119 @@ +/* + * Copyright 2000-2013 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.data.converter; + +import java.util.Locale; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +import com.vaadin.data.util.ObjectProperty; +import com.vaadin.data.util.converter.Converter; +import com.vaadin.data.util.converter.ReverseConverter; +import com.vaadin.ui.TextField; + +public class TestSpecificEnumToStringConverter { + + public class SpecificEnumToStringConverter implements + Converter { + + private Class enumClass; + + public SpecificEnumToStringConverter(Class enumClass) { + this.enumClass = enumClass; + } + + @Override + public String convertToModel(Enum value, Locale locale) + throws com.vaadin.data.util.converter.Converter.ConversionException { + if (value == null) { + return null; + } + + return value.toString(); + } + + @Override + public Enum convertToPresentation(String value, Locale locale) + throws com.vaadin.data.util.converter.Converter.ConversionException { + if (value == null) { + return null; + } + + for (Enum e : enumClass.getEnumConstants()) { + if (e.toString().equals(value)) { + return e; + } + } + + return null; + } + + @Override + public Class getModelType() { + return String.class; + } + + @Override + public Class getPresentationType() { + return (Class) enumClass; + } + + } + + SpecificEnumToStringConverter testEnumConverter; + SpecificEnumToStringConverter anotherTestEnumConverter; + + @Before + public void setup() { + testEnumConverter = new SpecificEnumToStringConverter(TestEnum.class); + anotherTestEnumConverter = new SpecificEnumToStringConverter( + AnotherTestEnum.class); + } + + @Test + public void nullConversion() { + Assert.assertEquals(null, testEnumConverter.convertToModel(null, null)); + } + + @Test + public void enumToStringConversion() { + Assert.assertEquals(TestEnum.TWO.toString(), + testEnumConverter.convertToModel(TestEnum.TWO, null)); + } + + @Test + public void stringToEnumConversion() { + Assert.assertEquals(TestEnum.TWO, testEnumConverter + .convertToPresentation(TestEnum.TWO.toString(), null)); + } + + @Test + public void stringToEnumWithField() { + TextField tf = new TextField(); + tf.setConverter(new ReverseConverter(anotherTestEnumConverter)); + tf.setPropertyDataSource(new ObjectProperty(AnotherTestEnum.TWO)); + Assert.assertEquals(AnotherTestEnum.TWO.toString(), tf.getValue()); + tf.setValue(AnotherTestEnum.ONE.toString()); + Assert.assertEquals(AnotherTestEnum.ONE.toString(), tf.getValue()); + Assert.assertEquals(AnotherTestEnum.ONE, tf.getConvertedValue()); + Assert.assertEquals(AnotherTestEnum.ONE, tf.getPropertyDataSource() + .getValue()); + + } +} -- cgit v1.2.3 From 53a9c1123a9bfbf73b9d46a58a38913845a319ed Mon Sep 17 00:00:00 2001 From: Johannes Dahlström Date: Wed, 22 May 2013 16:50:17 +0300 Subject: Fix TestingPushConnection.init signature (#11673) Change-Id: I7f5736fd456c21878a0eabdbff46a648932d3516 --- .../com/vaadin/tests/widgetset/client/TestingPushConnection.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/uitest/src/com/vaadin/tests/widgetset/client/TestingPushConnection.java b/uitest/src/com/vaadin/tests/widgetset/client/TestingPushConnection.java index 8d00598907..e255a5f95a 100644 --- a/uitest/src/com/vaadin/tests/widgetset/client/TestingPushConnection.java +++ b/uitest/src/com/vaadin/tests/widgetset/client/TestingPushConnection.java @@ -2,6 +2,7 @@ package com.vaadin.tests.widgetset.client; import com.google.gwt.user.client.Window; import com.vaadin.client.ApplicationConnection; +import com.vaadin.client.ApplicationConnection.CommunicationErrorHandler; import com.vaadin.client.communication.AtmospherePushConnection; public class TestingPushConnection extends AtmospherePushConnection { @@ -9,8 +10,9 @@ public class TestingPushConnection extends AtmospherePushConnection { private String transport; @Override - public void init(ApplicationConnection connection) { - super.init(connection); + public void init(ApplicationConnection connection, + CommunicationErrorHandler errorHandler) { + super.init(connection, errorHandler); transport = Window.Location.getParameter("transport"); } -- cgit v1.2.3 From 05ef43f8bfccbe1cbb0e48a0a96204a0485c3f49 Mon Sep 17 00:00:00 2001 From: John Ahlroos Date: Wed, 22 May 2013 11:40:12 +0300 Subject: Updated client-compiler to depend on client-compiler-deps 1.0.2 #11879 Change-Id: I1c98c353314197047265d26a0464ab7cc9c79520 --- client-compiler/ivy.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client-compiler/ivy.xml b/client-compiler/ivy.xml index b26de51aca..64c0de2830 100644 --- a/client-compiler/ivy.xml +++ b/client-compiler/ivy.xml @@ -55,7 +55,7 @@ rev="0.6" conf="build,ide -> default" /> + rev="1.0.2" conf="build,ide -> default" />
-- cgit v1.2.3 From 9686323c4ae29a708ea0a5e8cf39b60881d6f7ba Mon Sep 17 00:00:00 2001 From: Artur Signell Date: Wed, 22 May 2013 16:44:01 +0300 Subject: Added isInitialStateChange to StateChangeEvent (#10477) Change-Id: I6b9fb8a664974b68b35050a40ba19bce440b6b3c --- .../client/communication/StateChangeEvent.java | 25 ++++++++++++++++------ .../client/ui/AbstractComponentConnector.java | 6 +----- 2 files changed, 20 insertions(+), 11 deletions(-) diff --git a/client/src/com/vaadin/client/communication/StateChangeEvent.java b/client/src/com/vaadin/client/communication/StateChangeEvent.java index e17a56aa69..e8fd95e818 100644 --- a/client/src/com/vaadin/client/communication/StateChangeEvent.java +++ b/client/src/com/vaadin/client/communication/StateChangeEvent.java @@ -52,7 +52,7 @@ public class StateChangeEvent extends @Deprecated private Set changedPropertiesSet; - private boolean isNewConnector = false; + private boolean initialStateChange = false; private JSONObject stateJson; @@ -110,15 +110,15 @@ public class StateChangeEvent extends * the event whose state has changed * @param stateJson * the JSON representation of the state change - * @param isNewConnector + * @param initialStateChange * true if the state change is for a new connector, * otherwise false */ public StateChangeEvent(ServerConnector connector, JSONObject stateJson, - boolean isNewConnector) { + boolean initialStateChange) { setConnector(connector); this.stateJson = stateJson; - this.isNewConnector = isNewConnector; + this.initialStateChange = initialStateChange; } @Override @@ -178,7 +178,7 @@ public class StateChangeEvent extends changedProperties = FastStringSet.create(); addJsonFields(stateJson, changedProperties, ""); - if (isNewConnector) { + if (isInitialStateChange()) { addAllStateFields( AbstractConnector.getStateType(getConnector()), changedProperties, ""); @@ -198,7 +198,7 @@ public class StateChangeEvent extends * false> */ public boolean hasPropertyChanged(String property) { - if (isNewConnector) { + if (isInitialStateChange()) { // Everything has changed for a new connector return true; } else if (stateJson != null) { @@ -309,4 +309,17 @@ public class StateChangeEvent extends } } } + + /** + * Checks if the state change event is the first one for the given + * connector. + * + * @since 7.1 + * @return true if this is the first state change event for the connector, + * false otherwise + */ + public boolean isInitialStateChange() { + return initialStateChange; + } + } diff --git a/client/src/com/vaadin/client/ui/AbstractComponentConnector.java b/client/src/com/vaadin/client/ui/AbstractComponentConnector.java index 13d1e6d56c..ebc80c4728 100644 --- a/client/src/com/vaadin/client/ui/AbstractComponentConnector.java +++ b/client/src/com/vaadin/client/ui/AbstractComponentConnector.java @@ -51,8 +51,6 @@ public abstract class AbstractComponentConnector extends AbstractConnector private String lastKnownWidth = ""; private String lastKnownHeight = ""; - private boolean initialStateEvent = true; - private boolean tooltipListenersAttached = false; /** @@ -124,7 +122,7 @@ public abstract class AbstractComponentConnector extends AbstractConnector if (stateChangeEvent.hasPropertyChanged("id")) { if (getState().id != null) { getWidget().getElement().setId(getState().id); - } else if (!initialStateEvent) { + } else if (!stateChangeEvent.isInitialStateChange()) { getWidget().getElement().removeAttribute("id"); } } @@ -175,8 +173,6 @@ public abstract class AbstractComponentConnector extends AbstractConnector } Profiler.leave("AbstractComponentContainer.onStateChanged check tooltip"); - initialStateEvent = false; - Profiler.leave("AbstractComponentConnector.onStateChanged"); } -- cgit v1.2.3 From 7cced5e30efbd51bca240aa7324a7edde2b97272 Mon Sep 17 00:00:00 2001 From: Artur Signell Date: Wed, 22 May 2013 11:19:22 +0300 Subject: Fixed test which had never passed Change-Id: Ice20a168dd8c0dc14f8e4600f24e2b788cb38bc4 --- .../src/com/vaadin/server/MockServletConfig.java | 77 ++++++ .../src/com/vaadin/server/MockServletContext.java | 304 +++++++++++++++++++++ .../src/com/vaadin/server/VaadinSessionTest.java | 23 +- 3 files changed, 392 insertions(+), 12 deletions(-) create mode 100644 server/tests/src/com/vaadin/server/MockServletConfig.java create mode 100644 server/tests/src/com/vaadin/server/MockServletContext.java diff --git a/server/tests/src/com/vaadin/server/MockServletConfig.java b/server/tests/src/com/vaadin/server/MockServletConfig.java new file mode 100644 index 0000000000..b1e046c812 --- /dev/null +++ b/server/tests/src/com/vaadin/server/MockServletConfig.java @@ -0,0 +1,77 @@ +/* + * Copyright 2000-2013 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.util.Collections; +import java.util.Enumeration; + +import javax.servlet.ServletConfig; +import javax.servlet.ServletContext; + +/** + * + * @since + * @author Vaadin Ltd + */ +public class MockServletConfig implements ServletConfig { + + private ServletContext context = new MockServletContext(); + + /* + * (non-Javadoc) + * + * @see javax.servlet.ServletConfig#getServletName() + */ + @Override + public String getServletName() { + return "Mock Servlet"; + } + + /* + * (non-Javadoc) + * + * @see javax.servlet.ServletConfig#getServletContext() + */ + @Override + public ServletContext getServletContext() { + return context; + } + + /* + * (non-Javadoc) + * + * @see javax.servlet.ServletConfig#getInitParameter(java.lang.String) + */ + @Override + public String getInitParameter(String name) { + return null; + } + + /* + * (non-Javadoc) + * + * @see javax.servlet.ServletConfig#getInitParameterNames() + */ + @Override + public Enumeration getInitParameterNames() { + return Collections.enumeration(Collections.EMPTY_LIST); + } + +} diff --git a/server/tests/src/com/vaadin/server/MockServletContext.java b/server/tests/src/com/vaadin/server/MockServletContext.java new file mode 100644 index 0000000000..40d79190f6 --- /dev/null +++ b/server/tests/src/com/vaadin/server/MockServletContext.java @@ -0,0 +1,304 @@ +/* + * Copyright 2000-2013 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.InputStream; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.Collections; +import java.util.Enumeration; +import java.util.Set; + +import javax.servlet.RequestDispatcher; +import javax.servlet.Servlet; +import javax.servlet.ServletContext; +import javax.servlet.ServletException; + +/** + * + * @since + * @author Vaadin Ltd + */ +public class MockServletContext implements ServletContext { + + /* + * (non-Javadoc) + * + * @see javax.servlet.ServletContext#getContext(java.lang.String) + */ + @Override + public ServletContext getContext(String uripath) { + // TODO Auto-generated method stub + return null; + } + + /* + * (non-Javadoc) + * + * @see javax.servlet.ServletContext#getMajorVersion() + */ + @Override + public int getMajorVersion() { + return 2; + } + + /* + * (non-Javadoc) + * + * @see javax.servlet.ServletContext#getMinorVersion() + */ + @Override + public int getMinorVersion() { + return 4; + } + + /* + * (non-Javadoc) + * + * @see javax.servlet.ServletContext#getMimeType(java.lang.String) + */ + @Override + public String getMimeType(String file) { + // TODO Auto-generated method stub + return null; + } + + /* + * (non-Javadoc) + * + * @see javax.servlet.ServletContext#getResourcePaths(java.lang.String) + */ + @Override + public Set getResourcePaths(String path) { + // TODO Auto-generated method stub + return null; + } + + /* + * (non-Javadoc) + * + * @see javax.servlet.ServletContext#getResource(java.lang.String) + */ + @Override + public URL getResource(String path) throws MalformedURLException { + // TODO Auto-generated method stub + return null; + } + + /* + * (non-Javadoc) + * + * @see javax.servlet.ServletContext#getResourceAsStream(java.lang.String) + */ + @Override + public InputStream getResourceAsStream(String path) { + // TODO Auto-generated method stub + return null; + } + + /* + * (non-Javadoc) + * + * @see javax.servlet.ServletContext#getRequestDispatcher(java.lang.String) + */ + @Override + public RequestDispatcher getRequestDispatcher(String path) { + // TODO Auto-generated method stub + return null; + } + + /* + * (non-Javadoc) + * + * @see javax.servlet.ServletContext#getNamedDispatcher(java.lang.String) + */ + @Override + public RequestDispatcher getNamedDispatcher(String name) { + // TODO Auto-generated method stub + return null; + } + + /* + * (non-Javadoc) + * + * @see javax.servlet.ServletContext#getServlet(java.lang.String) + */ + @Override + public Servlet getServlet(String name) throws ServletException { + // TODO Auto-generated method stub + return null; + } + + /* + * (non-Javadoc) + * + * @see javax.servlet.ServletContext#getServlets() + */ + @Override + public Enumeration getServlets() { + // TODO Auto-generated method stub + return null; + } + + /* + * (non-Javadoc) + * + * @see javax.servlet.ServletContext#getServletNames() + */ + @Override + public Enumeration getServletNames() { + // TODO Auto-generated method stub + return null; + } + + /* + * (non-Javadoc) + * + * @see javax.servlet.ServletContext#log(java.lang.String) + */ + @Override + public void log(String msg) { + // TODO Auto-generated method stub + + } + + /* + * (non-Javadoc) + * + * @see javax.servlet.ServletContext#log(java.lang.Exception, + * java.lang.String) + */ + @Override + public void log(Exception exception, String msg) { + // TODO Auto-generated method stub + + } + + /* + * (non-Javadoc) + * + * @see javax.servlet.ServletContext#log(java.lang.String, + * java.lang.Throwable) + */ + @Override + public void log(String message, Throwable throwable) { + // TODO Auto-generated method stub + + } + + /* + * (non-Javadoc) + * + * @see javax.servlet.ServletContext#getRealPath(java.lang.String) + */ + @Override + public String getRealPath(String path) { + // TODO Auto-generated method stub + return null; + } + + /* + * (non-Javadoc) + * + * @see javax.servlet.ServletContext#getServerInfo() + */ + @Override + public String getServerInfo() { + // TODO Auto-generated method stub + return null; + } + + /* + * (non-Javadoc) + * + * @see javax.servlet.ServletContext#getInitParameter(java.lang.String) + */ + @Override + public String getInitParameter(String name) { + return null; + } + + /* + * (non-Javadoc) + * + * @see javax.servlet.ServletContext#getInitParameterNames() + */ + @Override + public Enumeration getInitParameterNames() { + return Collections.enumeration(Collections.EMPTY_LIST); + } + + /* + * (non-Javadoc) + * + * @see javax.servlet.ServletContext#getAttribute(java.lang.String) + */ + @Override + public Object getAttribute(String name) { + // TODO Auto-generated method stub + return null; + } + + /* + * (non-Javadoc) + * + * @see javax.servlet.ServletContext#getAttributeNames() + */ + @Override + public Enumeration getAttributeNames() { + // TODO Auto-generated method stub + return null; + } + + /* + * (non-Javadoc) + * + * @see javax.servlet.ServletContext#setAttribute(java.lang.String, + * java.lang.Object) + */ + @Override + public void setAttribute(String name, Object object) { + // TODO Auto-generated method stub + + } + + /* + * (non-Javadoc) + * + * @see javax.servlet.ServletContext#removeAttribute(java.lang.String) + */ + @Override + public void removeAttribute(String name) { + // TODO Auto-generated method stub + + } + + /* + * (non-Javadoc) + * + * @see javax.servlet.ServletContext#getServletContextName() + */ + @Override + public String getServletContextName() { + // TODO Auto-generated method stub + return null; + } + +} diff --git a/server/tests/src/com/vaadin/server/VaadinSessionTest.java b/server/tests/src/com/vaadin/server/VaadinSessionTest.java index 61a1581a6f..68f198410c 100644 --- a/server/tests/src/com/vaadin/server/VaadinSessionTest.java +++ b/server/tests/src/com/vaadin/server/VaadinSessionTest.java @@ -18,6 +18,7 @@ package com.vaadin.server; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.locks.ReentrantLock; +import javax.servlet.ServletConfig; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpSession; import javax.servlet.http.HttpSessionBindingEvent; @@ -30,7 +31,6 @@ import org.junit.Test; import com.vaadin.server.ClientConnector.DetachEvent; import com.vaadin.server.ClientConnector.DetachListener; -import com.vaadin.tests.util.MockDeploymentConfiguration; import com.vaadin.ui.UI; import com.vaadin.util.CurrentInstance; @@ -39,6 +39,7 @@ public class VaadinSessionTest { private VaadinSession session; private VaadinServlet mockServlet; private VaadinServletService mockService; + private ServletConfig mockServletConfig; private HttpSession mockHttpSession; private WrappedSession mockWrappedSession; private VaadinServletRequest vaadinRequest; @@ -46,24 +47,22 @@ public class VaadinSessionTest { @Before public void setup() throws Exception { - mockServlet = new VaadinServlet() { - @Override - public String getServletName() { - return "mockServlet"; - }; - }; - - mockService = new VaadinServletService(mockServlet, - new MockDeploymentConfiguration()); - mockService.init(); + mockServletConfig = new MockServletConfig(); + mockServlet = new VaadinServlet(); + mockServlet.init(mockServletConfig); + mockService = mockServlet.getService(); mockHttpSession = EasyMock.createMock(HttpSession.class); mockWrappedSession = new WrappedHttpSession(mockHttpSession) { final ReentrantLock lock = new ReentrantLock(); + { + lock.lock(); + } @Override public Object getAttribute(String name) { - if ("mockServlet.lock".equals(name)) { + String lockAttribute = mockService.getServiceName() + ".lock"; + if (lockAttribute.equals(name)) { return lock; } return super.getAttribute(name); -- cgit v1.2.3 From ada3311f7846e812a10547756ce7724f3d4dba6a Mon Sep 17 00:00:00 2001 From: Artur Signell Date: Wed, 22 May 2013 17:24:33 +0300 Subject: Avoid creating an instance of every view while searching for the correct view (#11722) Change-Id: Ifab9aa0021bde58280fd75370e5df46fb5efa7a7 --- server/src/com/vaadin/navigator/Navigator.java | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/server/src/com/vaadin/navigator/Navigator.java b/server/src/com/vaadin/navigator/Navigator.java index df05a9fbce..540a3ee302 100644 --- a/server/src/com/vaadin/navigator/Navigator.java +++ b/server/src/com/vaadin/navigator/Navigator.java @@ -497,19 +497,22 @@ public class Navigator implements Serializable { */ public void navigateTo(String navigationState) { String longestViewName = null; + ViewProvider longestViewNameProvider = null; View viewWithLongestName = null; for (ViewProvider provider : providers) { String viewName = provider.getViewName(navigationState); if (null != viewName && (longestViewName == null || viewName.length() > longestViewName .length())) { - View view = provider.getView(viewName); - if (null != view) { - longestViewName = viewName; - viewWithLongestName = view; - } + longestViewName = viewName; + longestViewNameProvider = provider; } } + if (longestViewName != null) { + viewWithLongestName = longestViewNameProvider + .getView(longestViewName); + } + if (viewWithLongestName == null && errorProvider != null) { longestViewName = errorProvider.getViewName(navigationState); viewWithLongestName = errorProvider.getView(longestViewName); -- cgit v1.2.3 From 5b35dd9364f5cebecb3ead602e7f707c596fc1da Mon Sep 17 00:00:00 2001 From: Artur Signell Date: Thu, 23 May 2013 10:03:00 +0300 Subject: Added text file encoding and line delimiter info (#11907) Change-Id: Iaefdebfb24bedff95239ea8813b29723b3437f5b --- README.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 5b56333cdb..63f39cbb36 100644 --- a/README.md +++ b/README.md @@ -23,11 +23,12 @@ Start Eclipse ------------- Start Eclipse and use the root checkout folder (the one containing the *vaadin*, *gwt* and *gwt-tools* folders) as the workspace folder -Define Required Variables for the GWT Eclipse Projects +Set up the Workspace and define required variables for projects -------- -To be able to find all files, the GWT project requires you to define a couple of variables: - 1. Open *Window* -> *Preferences* (Windows) or *Eclipse* -> *Preferences* (Mac) +1. Go to *General* -> *Workspace* + 1. Set *Text file encoding* to *UTF-8* + 1. Set *New text file line delimiter* to *Unix* 1. Go to *General* -> *Workspace* -> *Linked Resources* 1. Add a new Path Variable **GWT_ROOT** referring to the gwt folder containing the gwt project ![GWT_ROOT](http://f.cl.ly/items/430q0H0z3t362Z1A1n3L/LinkedResources.png "Defining GWT_ROOT") -- cgit v1.2.3 From f8c4f9916526a6ffae4b5fc67b601cd36ca064be Mon Sep 17 00:00:00 2001 From: Johannes Dahlström Date: Thu, 23 May 2013 12:59:14 +0300 Subject: Prevent spurious "Could not determine ApplicationConnection" error when using the debug window Change-Id: I3b5a8ac4f33c7e8828e34c46056b8ecd6c05a436 --- .../src/com/vaadin/client/debug/internal/VDebugWindow.java | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/client/src/com/vaadin/client/debug/internal/VDebugWindow.java b/client/src/com/vaadin/client/debug/internal/VDebugWindow.java index 5aab95616a..6c05658fe1 100644 --- a/client/src/com/vaadin/client/debug/internal/VDebugWindow.java +++ b/client/src/com/vaadin/client/debug/internal/VDebugWindow.java @@ -45,6 +45,7 @@ import com.google.gwt.user.client.Window; import com.google.gwt.user.client.Window.Location; import com.google.gwt.user.client.ui.Button; import com.google.gwt.user.client.ui.FlowPanel; +import com.google.gwt.user.client.ui.RootPanel; import com.google.gwt.user.client.ui.SimplePanel; import com.google.gwt.user.client.ui.Widget; import com.vaadin.client.ApplicationConnection; @@ -714,6 +715,18 @@ public final class VDebugWindow extends VOverlay { } } + /** + * Gets the container element for this window. The debug window is always + * global to the document and not related to any + * {@link ApplicationConnection} in particular. + * + * @return The global overlay container element. + */ + @Override + public com.google.gwt.user.client.Element getOverlayContainer() { + return RootPanel.get().getElement(); + } + /* * Inner classes */ -- cgit v1.2.3 From 8a42394c6341f26066f41d3560f2419658a67a62 Mon Sep 17 00:00:00 2001 From: Artur Signell Date: Wed, 22 May 2013 10:54:20 +0300 Subject: Fixed locators in test (aria div conflict) Change-Id: Iaeef438de48ef9bda33fb81b0bb7f71d134b17ca --- .../tests/components/datefield/DateFieldPrimaryStyleNames.html | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/uitest/src/com/vaadin/tests/components/datefield/DateFieldPrimaryStyleNames.html b/uitest/src/com/vaadin/tests/components/datefield/DateFieldPrimaryStyleNames.html index 31216ed1b0..38034fd0c8 100644 --- a/uitest/src/com/vaadin/tests/components/datefield/DateFieldPrimaryStyleNames.html +++ b/uitest/src/com/vaadin/tests/components/datefield/DateFieldPrimaryStyleNames.html @@ -68,12 +68,12 @@ assertCSSClass - //body/div[last()]/div[last()] + //body/div[2]/div[last()] my-datefield-popup assertCSSClass - //body/div[last()]/div[last()] + //body/div[2]/div[last()] my-datefield-day @@ -188,12 +188,12 @@ assertCSSClass - //body/div[last()]/div[last()] + //body/div[2]/div[last()] my-second-datefield-popup assertCSSClass - //body/div[last()]/div[last()] + //body/div[2]/div[last()] my-second-datefield-day -- cgit v1.2.3 From 6de01ac07153002f3752a0571a0060c21ed37230 Mon Sep 17 00:00:00 2001 From: Artur Signell Date: Thu, 23 May 2013 22:27:16 +0300 Subject: Fix text / javascript mismatch issue in Chrome (#11275) Change-Id: I7516be18401640ded3eb6174b5375bb452a2ba00 --- client/src/com/vaadin/client/ResourceLoader.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/client/src/com/vaadin/client/ResourceLoader.java b/client/src/com/vaadin/client/ResourceLoader.java index 7fc8b4f9f3..3d8eb739b1 100644 --- a/client/src/com/vaadin/client/ResourceLoader.java +++ b/client/src/com/vaadin/client/ResourceLoader.java @@ -323,7 +323,11 @@ public class ResourceLoader { } else { ObjectElement element = Document.get().createObjectElement(); element.setData(url); - element.setType("text/plain"); + if (BrowserInfo.get().isChrome()) { + element.setType("text/cache"); + } else { + element.setType("text/plain"); + } element.setHeight("0px"); element.setWidth("0px"); return element; -- cgit v1.2.3 From f7f1e3ece5206c335487ce25f4e709370024109d Mon Sep 17 00:00:00 2001 From: Artur Signell Date: Fri, 24 May 2013 13:48:09 +0300 Subject: Added Java Date to Sql Date converter to better support sql dates (#11224) Change-Id: I83d8c96a6877ea33b270a1a4a2c6f360a8147518 --- .../util/converter/DateToSqlDateConverter.java | 59 +++++++++ .../util/converter/DefaultConverterFactory.java | 2 + .../tests/components/table/TableSqlContainer.html | 72 +++++++++++ .../tests/components/table/TableSqlContainer.java | 142 +++++++++++++++++++++ 4 files changed, 275 insertions(+) create mode 100644 server/src/com/vaadin/data/util/converter/DateToSqlDateConverter.java create mode 100644 uitest/src/com/vaadin/tests/components/table/TableSqlContainer.html create mode 100644 uitest/src/com/vaadin/tests/components/table/TableSqlContainer.java diff --git a/server/src/com/vaadin/data/util/converter/DateToSqlDateConverter.java b/server/src/com/vaadin/data/util/converter/DateToSqlDateConverter.java new file mode 100644 index 0000000000..97027cc05b --- /dev/null +++ b/server/src/com/vaadin/data/util/converter/DateToSqlDateConverter.java @@ -0,0 +1,59 @@ +/* + * Copyright 2000-2013 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.data.util.converter; + +import java.util.Date; +import java.util.Locale; + +/** + * Converter for handling conversion between {@link java.util.Date} and + * {@link java.sql.Date}. This is used when a PopupDateField or InlineDateField + * is connected to a java.sql.Date property, typically through a JPAContainer or + * SQLContainer. Note that information (time information) is lost when + * converting from {@link java.util.Date} to {@link java.sql.Date}. + * + * @since 7.1 + * @author Vaadin Ltd + */ +public class DateToSqlDateConverter implements Converter { + + @Override + public java.sql.Date convertToModel(Date value, Locale locale) + throws ConversionException { + return new java.sql.Date(value.getTime()); + } + + @Override + public Date convertToPresentation(java.sql.Date value, Locale locale) + throws ConversionException { + return new Date(value.getTime()); + } + + @Override + public Class getModelType() { + return java.sql.Date.class; + } + + @Override + public Class getPresentationType() { + return Date.class; + } + +} diff --git a/server/src/com/vaadin/data/util/converter/DefaultConverterFactory.java b/server/src/com/vaadin/data/util/converter/DefaultConverterFactory.java index de183dd342..bbd3945a37 100644 --- a/server/src/com/vaadin/data/util/converter/DefaultConverterFactory.java +++ b/server/src/com/vaadin/data/util/converter/DefaultConverterFactory.java @@ -87,6 +87,8 @@ public class DefaultConverterFactory implements ConverterFactory { protected Converter createDateConverter(Class sourceType) { if (Long.class.isAssignableFrom(sourceType)) { return new DateToLongConverter(); + } else if (java.sql.Date.class.isAssignableFrom(sourceType)) { + return new DateToSqlDateConverter(); } else { return null; } diff --git a/uitest/src/com/vaadin/tests/components/table/TableSqlContainer.html b/uitest/src/com/vaadin/tests/components/table/TableSqlContainer.html new file mode 100644 index 0000000000..96df94148c --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/table/TableSqlContainer.html @@ -0,0 +1,72 @@ + + + + + + +New Test + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
New Test
open/run/com.vaadin.tests.components.table.TableSqlContainer?restartApplication
assertTextvaadin=runcomvaadintestscomponentstableTableSqlContainer::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VVerticalLayout[0]/Slot[0]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[0]/domChild[1]/domChild[0]May 24, 2013 12:00:00 AM
mouseClickvaadin=runcomvaadintestscomponentstableTableSqlContainer::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[1]/VCheckBox[0]/domChild[0]12,7
assertValuevaadin=runcomvaadintestscomponentstableTableSqlContainer::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VVerticalLayout[0]/Slot[0]/VScrollTable[0]/FocusableScrollPanel[0]/VScrollTable$VScrollTableBody[0]/VScrollTable$VScrollTableBody$VScrollTableRow[0]/VPopupCalendar[0]#field5/24/13
mouseClickvaadin=runcomvaadintestscomponentstableTableSqlContainer::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VVerticalLayout[0]/Slot[0]/VScrollTable[0]/FocusableScrollPanel[0]/VScrollTable$VScrollTableBody[0]/VScrollTable$VScrollTableBody$VScrollTableRow[0]/VPopupCalendar[0]#popupButton9,7
mouseClick//table[@id='PID_VAADIN_POPUPCAL']/tbody/tr[2]/td/table/tbody/tr[4]/td[5]/span11,10
mouseClickvaadin=runcomvaadintestscomponentstableTableSqlContainer::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[1]/VCheckBox[0]/domChild[0]9,12
assertTextvaadin=runcomvaadintestscomponentstableTableSqlContainer::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VVerticalLayout[0]/Slot[0]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[0]/domChild[1]/domChild[0]May 15, 2013 12:00:00 AM
assertTextvaadin=runcomvaadintestscomponentstableTableSqlContainer::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VVerticalLayout[0]/Slot[0]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[1]/domChild[1]/domChild[0]Apr 26, 2013 12:00:00 AM
assertTextvaadin=runcomvaadintestscomponentstableTableSqlContainer::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VVerticalLayout[0]/Slot[0]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[2]/domChild[1]/domChild[0]May 27, 2013 12:00:00 AM
assertTextvaadin=runcomvaadintestscomponentstableTableSqlContainer::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VVerticalLayout[0]/Slot[0]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[3]/domChild[1]/domChild[0]Apr 28, 2013 12:00:00 AM
+ + diff --git a/uitest/src/com/vaadin/tests/components/table/TableSqlContainer.java b/uitest/src/com/vaadin/tests/components/table/TableSqlContainer.java new file mode 100644 index 0000000000..5191b1b86e --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/table/TableSqlContainer.java @@ -0,0 +1,142 @@ +package com.vaadin.tests.components.table; + +import java.sql.Connection; +import java.sql.SQLException; +import java.sql.Statement; +import java.util.Locale; + +import com.vaadin.data.Property; +import com.vaadin.data.Property.ValueChangeEvent; +import com.vaadin.data.Property.ValueChangeListener; +import com.vaadin.data.util.sqlcontainer.SQLContainer; +import com.vaadin.data.util.sqlcontainer.connection.JDBCConnectionPool; +import com.vaadin.data.util.sqlcontainer.connection.SimpleJDBCConnectionPool; +import com.vaadin.data.util.sqlcontainer.query.TableQuery; +import com.vaadin.server.VaadinRequest; +import com.vaadin.tests.components.AbstractTestUI; +import com.vaadin.ui.CheckBox; +import com.vaadin.ui.Label; +import com.vaadin.ui.Table; +import com.vaadin.ui.VerticalLayout; + +public class TableSqlContainer extends AbstractTestUI { + + @Override + protected void setup(VaadinRequest request) { + setLocale(Locale.ENGLISH); + VerticalLayout layout = new VerticalLayout(); + addComponent(layout); + + final Table table = new Table("Table with SQLContainer"); + layout.addComponent(table); + + final Label selectedLabel = new Label("Selected: null"); + layout.addComponent(selectedLabel); + + try { + JDBCConnectionPool connectionPool = new SimpleJDBCConnectionPool( + "org.hsqldb.jdbc.JDBCDriver", + "jdbc:hsqldb:mem:sqlcontainer", "SA", "", 2, 20); + + createTestTable(connectionPool); + insertTestData(connectionPool); + + TableQuery q = new TableQuery("mytable", connectionPool); + q.setVersionColumn("version"); + SQLContainer myContainer = new SQLContainer(q); + + table.setContainerDataSource(myContainer); + + } catch (SQLException e) { + e.printStackTrace(); + } + + table.setImmediate(true); + table.setSizeFull(); + table.setSelectable(true); + table.addValueChangeListener(new Property.ValueChangeListener() { + @Override + public void valueChange(ValueChangeEvent event) { + selectedLabel.setValue("Selected: " + + event.getProperty().getValue()); + } + }); + + final CheckBox editMode = new CheckBox("Edit mode"); + editMode.addValueChangeListener(new ValueChangeListener() { + @Override + public void valueChange(ValueChangeEvent event) { + table.setEditable(editMode.getValue()); + } + }); + addComponent(editMode); + } + + /** + * (Re)creates the test table + * + * @param connectionPool + */ + private void createTestTable(JDBCConnectionPool connectionPool) { + Connection conn = null; + try { + conn = connectionPool.reserveConnection(); + Statement statement = conn.createStatement(); + try { + statement.executeUpdate("DROP TABLE mytable"); + } catch (SQLException e) { + } + statement.execute("CREATE TABLE mytable " + + "(id INTEGER GENERATED BY DEFAULT AS IDENTITY, D DATE," + + "MYFIELD VARCHAR(45), " + "PRIMARY KEY(ID))"); + statement.close(); + conn.commit(); + } catch (SQLException e) { + e.printStackTrace(); + } finally { + connectionPool.releaseConnection(conn); + } + } + + /** + * Adds test data to the test table + * + * @param connectionPool + * @throws SQLException + */ + private void insertTestData(JDBCConnectionPool connectionPool) + throws SQLException { + Connection conn = null; + try { + conn = connectionPool.reserveConnection(); + Statement statement = conn.createStatement(); + + statement + .executeUpdate("INSERT INTO mytable VALUES(1, '2013-05-24', 'A0')"); + statement + .executeUpdate("INSERT INTO mytable VALUES(2, '2013-04-26', 'A1')"); + statement + .executeUpdate("INSERT INTO mytable VALUES(3, '2013-05-27', 'B0')"); + statement + .executeUpdate("INSERT INTO mytable VALUES(4, '2013-04-28', 'B1')"); + + statement.close(); + conn.commit(); + } catch (SQLException e) { + e.printStackTrace(); + } finally { + connectionPool.releaseConnection(conn); + } + } + + @Override + protected String getTestDescription() { + return "A test with Table connected to a SQLContainer using TableQuery"; + } + + @Override + protected Integer getTicketNumber() { + return 11224; + } + +} \ No newline at end of file -- cgit v1.2.3 From 2882cf98756974f40ba98d66c7d7318db6acd538 Mon Sep 17 00:00:00 2001 From: Artur Signell Date: Mon, 27 May 2013 21:38:25 +0300 Subject: Added Serializable where missing and ignore classes which do not need Serializable Change-Id: I197b2d62282ee957458e05d9cac357df47f05e85 --- .../com/vaadin/data/util/LegacyPropertyHelper.java | 3 ++- .../communication/AtmospherePushConnection.java | 4 ++-- .../server/communication/PushConnection.java | 4 +++- .../tests/server/TestClassesSerializable.java | 22 ++++++++++++++++++++++ .../vaadin/shared/ui/calendar/CalendarEventId.java | 4 +++- .../vaadin/shared/ui/calendar/DateConstants.java | 4 +++- shared/src/com/vaadin/shared/util/SharedUtil.java | 4 +++- 7 files changed, 38 insertions(+), 7 deletions(-) diff --git a/server/src/com/vaadin/data/util/LegacyPropertyHelper.java b/server/src/com/vaadin/data/util/LegacyPropertyHelper.java index 0276e35dbf..3eb22524f8 100644 --- a/server/src/com/vaadin/data/util/LegacyPropertyHelper.java +++ b/server/src/com/vaadin/data/util/LegacyPropertyHelper.java @@ -15,6 +15,7 @@ */ package com.vaadin.data.util; +import java.io.Serializable; import java.util.logging.Level; import java.util.logging.Logger; @@ -32,7 +33,7 @@ import com.vaadin.server.VaadinService; * @deprecated This is only used internally for backwards compatibility */ @Deprecated -public class LegacyPropertyHelper { +public class LegacyPropertyHelper implements Serializable { /** * Returns the property value converted to a String. diff --git a/server/src/com/vaadin/server/communication/AtmospherePushConnection.java b/server/src/com/vaadin/server/communication/AtmospherePushConnection.java index 96507b55f1..e967dd925a 100644 --- a/server/src/com/vaadin/server/communication/AtmospherePushConnection.java +++ b/server/src/com/vaadin/server/communication/AtmospherePushConnection.java @@ -42,12 +42,12 @@ import com.vaadin.ui.UI; * @author Vaadin Ltd * @since 7.1 */ -public class AtmospherePushConnection implements Serializable, PushConnection { +public class AtmospherePushConnection implements PushConnection { /** * Represents a message that can arrive as multiple fragments. */ - protected static class FragmentedMessage { + protected static class FragmentedMessage implements Serializable { private final StringBuilder message = new StringBuilder(); private final int messageLength; diff --git a/server/src/com/vaadin/server/communication/PushConnection.java b/server/src/com/vaadin/server/communication/PushConnection.java index 4e043f565f..bb88998402 100644 --- a/server/src/com/vaadin/server/communication/PushConnection.java +++ b/server/src/com/vaadin/server/communication/PushConnection.java @@ -16,6 +16,8 @@ package com.vaadin.server.communication; +import java.io.Serializable; + import com.vaadin.ui.UI; /** @@ -25,7 +27,7 @@ import com.vaadin.ui.UI; * @author Vaadin Ltd * @since 7.1 */ -public interface PushConnection { +public interface PushConnection extends Serializable { /** * Pushes pending state changes and client RPC calls to the client. It is diff --git a/server/tests/src/com/vaadin/tests/server/TestClassesSerializable.java b/server/tests/src/com/vaadin/tests/server/TestClassesSerializable.java index 90cb6b9994..af6d9ed732 100644 --- a/server/tests/src/com/vaadin/tests/server/TestClassesSerializable.java +++ b/server/tests/src/com/vaadin/tests/server/TestClassesSerializable.java @@ -7,6 +7,7 @@ import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; +import java.util.Comparator; import java.util.Enumeration; import java.util.Iterator; import java.util.List; @@ -33,6 +34,7 @@ public class TestClassesSerializable extends TestCase { "com\\.vaadin\\.launcher\\..*", // "com\\.vaadin\\.client\\..*", // "com\\.vaadin\\.server\\.widgetsetutils\\..*", // + "com\\.vaadin\\.server\\.themeutils\\..*", // "com\\.vaadin\\.tests\\..*", // exclude automated tests "com\\.vaadin\\.tools\\..*", // "com\\.vaadin\\.ui\\.themes\\..*", // @@ -41,7 +43,13 @@ public class TestClassesSerializable extends TestCase { "com\\.vaadin\\.event\\.LayoutEvents", // "com\\.vaadin\\.event\\.MouseEvents", // "com\\.vaadin\\.server\\.VaadinPortlet", // + "com\\.vaadin\\.server\\.MockServletConfig", // + "com\\.vaadin\\.server\\.MockServletContext", // "com\\.vaadin\\.server\\.Constants", // + "com\\.vaadin\\.server\\.communication\\.FileUploadHandler\\$SimpleMultiPartInputStream", // + "com\\.vaadin\\.server\\.communication\\.PushRequestHandler.*", + "com\\.vaadin\\.server\\.communication\\.PushHandler.*", // PushHandler + // and its inner classes do not need to be serializable "com\\.vaadin\\.util\\.SerializerHelper", // fully static // class level filtering, also affecting nested classes and // interfaces @@ -50,6 +58,7 @@ public class TestClassesSerializable extends TestCase { "com\\.vaadin\\.util\\.ReflectTools.*", // "com\\.vaadin\\.data\\.util\\.ReflectTools.*", // "com\\.vaadin\\.sass.*", // + "com\\.vaadin\\.testbench.*", // "com\\.vaadin\\.util\\.CurrentInstance\\$1", // }; @@ -88,6 +97,19 @@ public class TestClassesSerializable extends TestCase { // report non-serializable classes and interfaces if (!Serializable.class.isAssignableFrom(cls)) { + if (cls.getSuperclass() == Object.class + && cls.getInterfaces().length == 1) { + // Single interface implementors + Class iface = cls.getInterfaces()[0]; + + if (iface == Runnable.class) { + // Ignore Runnables used with access() + continue; + } else if (iface == Comparator.class) { + // Ignore inline comparators + continue; + } + } nonSerializableClasses.add(cls); // TODO easier to read when testing // System.err.println(cls); diff --git a/shared/src/com/vaadin/shared/ui/calendar/CalendarEventId.java b/shared/src/com/vaadin/shared/ui/calendar/CalendarEventId.java index 6f52aabf43..27f1cdd341 100644 --- a/shared/src/com/vaadin/shared/ui/calendar/CalendarEventId.java +++ b/shared/src/com/vaadin/shared/ui/calendar/CalendarEventId.java @@ -15,6 +15,8 @@ */ package com.vaadin.shared.ui.calendar; +import java.io.Serializable; + /** * CalendarEventId contains static String identifiers for all Calendar events. * These are used both in the client and server side code. @@ -22,7 +24,7 @@ package com.vaadin.shared.ui.calendar; * @since 7.1 * @author Vaadin Ltd. */ -public class CalendarEventId { +public class CalendarEventId implements Serializable { public static final String EVENTMOVE = "eventMove"; public static final String RANGESELECT = "rangeSelect"; diff --git a/shared/src/com/vaadin/shared/ui/calendar/DateConstants.java b/shared/src/com/vaadin/shared/ui/calendar/DateConstants.java index 8a840274c2..9b1c995642 100644 --- a/shared/src/com/vaadin/shared/ui/calendar/DateConstants.java +++ b/shared/src/com/vaadin/shared/ui/calendar/DateConstants.java @@ -15,12 +15,14 @@ */ package com.vaadin.shared.ui.calendar; +import java.io.Serializable; + /** * * @since 7.1 * */ -public class DateConstants { +public class DateConstants implements Serializable { public static final String ACTION_DATE_FORMAT_PATTERN = "yyyy-MM-dd HH:mm:ss"; public static final String CLIENT_DATE_FORMAT = "yyyy-MM-dd"; diff --git a/shared/src/com/vaadin/shared/util/SharedUtil.java b/shared/src/com/vaadin/shared/util/SharedUtil.java index 2242fa4363..80efe68d83 100644 --- a/shared/src/com/vaadin/shared/util/SharedUtil.java +++ b/shared/src/com/vaadin/shared/util/SharedUtil.java @@ -15,6 +15,8 @@ */ package com.vaadin.shared.util; +import java.io.Serializable; + /** * Misc internal utility methods used by both the server and the client package. * @@ -22,7 +24,7 @@ package com.vaadin.shared.util; * @since 7.1 * */ -public class SharedUtil { +public class SharedUtil implements Serializable { /** * Checks if a and b are equals using {@link #equals(Object)}. Handles null * values as well. Does not ensure that objects are of the same type. -- cgit v1.2.3 From 4d7f190b7f36a10b16e74b1dab8ed0a274841ae1 Mon Sep 17 00:00:00 2001 From: Leif Åstrand Date: Wed, 22 May 2013 15:56:29 +0300 Subject: Make access() enqueue the runnable if the session is locked (#11897) Change-Id: If162e81a29bbc982857e2a165a983e161ea837ee --- server/src/com/vaadin/server/RequestHandler.java | 3 +- server/src/com/vaadin/server/VaadinService.java | 15 +- server/src/com/vaadin/server/VaadinSession.java | 174 +++++++++++++-- .../server/communication/FileUploadHandler.java | 2 +- .../vaadin/server/communication/UidlWriter.java | 7 +- server/src/com/vaadin/ui/LoginForm.java | 2 +- server/src/com/vaadin/ui/UI.java | 118 +++++++++-- .../vaadin/tests/applicationcontext/CloseUI.java | 2 +- .../applicationcontext/UIRunSafelyThread.java | 2 +- .../com/vaadin/tests/components/ui/UiAccess.html | 127 +++++++++++ .../com/vaadin/tests/components/ui/UiAccess.java | 235 +++++++++++++++++++++ 11 files changed, 632 insertions(+), 55 deletions(-) create mode 100644 uitest/src/com/vaadin/tests/components/ui/UiAccess.html create mode 100644 uitest/src/com/vaadin/tests/components/ui/UiAccess.java diff --git a/server/src/com/vaadin/server/RequestHandler.java b/server/src/com/vaadin/server/RequestHandler.java index 873752c5f2..097a3e034b 100644 --- a/server/src/com/vaadin/server/RequestHandler.java +++ b/server/src/com/vaadin/server/RequestHandler.java @@ -37,7 +37,8 @@ public interface RequestHandler extends Serializable { * using VaadinSession or anything inside the VaadinSession you must ensure * the session is locked. This can be done by extending * {@link SynchronizedRequestHandler} or by using - * {@link VaadinSession#access(Runnable)} or {@link UI#access(Runnable)}. + * {@link VaadinSession#accessSynchronously(Runnable)} or + * {@link UI#accessSynchronously(Runnable)}. *

* * @param session diff --git a/server/src/com/vaadin/server/VaadinService.java b/server/src/com/vaadin/server/VaadinService.java index af0c280c19..2cb7f9059e 100644 --- a/server/src/com/vaadin/server/VaadinService.java +++ b/server/src/com/vaadin/server/VaadinService.java @@ -407,12 +407,12 @@ public abstract class VaadinService implements Serializable { */ public void fireSessionDestroy(VaadinSession vaadinSession) { final VaadinSession session = vaadinSession; - session.access(new Runnable() { + session.accessSynchronously(new Runnable() { @Override public void run() { ArrayList uis = new ArrayList(session.getUIs()); for (final UI ui : uis) { - ui.access(new Runnable() { + ui.accessSynchronously(new Runnable() { @Override public void run() { /* @@ -1087,7 +1087,7 @@ public abstract class VaadinService implements Serializable { private void removeClosedUIs(final VaadinSession session) { ArrayList uis = new ArrayList(session.getUIs()); for (final UI ui : uis) { - ui.access(new Runnable() { + ui.accessSynchronously(new Runnable() { @Override public void run() { if (ui.isClosing()) { @@ -1245,7 +1245,7 @@ public abstract class VaadinService implements Serializable { if (session != null) { final VaadinSession finalSession = session; - session.access(new Runnable() { + session.accessSynchronously(new Runnable() { @Override public void run() { cleanupSession(finalSession); @@ -1254,7 +1254,7 @@ public abstract class VaadinService implements Serializable { final long duration = (System.nanoTime() - (Long) request .getAttribute(REQUEST_START_TIME_ATTRIBUTE)) / 1000000; - session.access(new Runnable() { + session.accessSynchronously(new Runnable() { @Override public void run() { finalSession.setLastRequestDuration(duration); @@ -1542,8 +1542,9 @@ public abstract class VaadinService implements Serializable { /** * Checks that another {@link VaadinSession} instance is not locked. This is - * internally used by {@link VaadinSession#access(Runnable)} and - * {@link UI#access(Runnable)} to help avoid causing deadlocks. + * internally used by {@link VaadinSession#accessSynchronously(Runnable)} + * and {@link UI#accessSynchronously(Runnable)} to help avoid causing + * deadlocks. * * @since 7.1 * @param session diff --git a/server/src/com/vaadin/server/VaadinSession.java b/server/src/com/vaadin/server/VaadinSession.java index 317ea6cf7b..9625a3f350 100644 --- a/server/src/com/vaadin/server/VaadinSession.java +++ b/server/src/com/vaadin/server/VaadinSession.java @@ -26,6 +26,11 @@ import java.util.List; import java.util.Locale; import java.util.Map; import java.util.UUID; +import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Future; +import java.util.concurrent.FutureTask; +import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; import java.util.logging.Logger; @@ -130,6 +135,13 @@ public class VaadinSession implements HttpSessionBindingListener, Serializable { private transient Lock lock; + /* + * Pending tasks can't be serialized and the queue should be empty when the + * session is serialized as long as it doesn't happen while some other + * thread has the lock. + */ + private transient final ConcurrentLinkedQueue> pendingAccessQueue = new ConcurrentLinkedQueue>(); + /** * Create a new service session tied to a Vaadin service * @@ -820,9 +832,13 @@ public class VaadinSession implements HttpSessionBindingListener, Serializable { public void unlock() { assert hasLock(); try { + /* + * Run pending tasks and push if the reentrant lock will actually be + * released by this unlock() invocation. + */ if (((ReentrantLock) getLockInstance()).getHoldCount() == 1) { - // Only push if the reentrant lock will actually be released by - // this unlock() invocation. + runPendingAccessTasks(); + for (UI ui : getUIs()) { if (ui.getPushMode() == PushMode.AUTOMATIC) { ui.push(); @@ -1063,23 +1079,30 @@ public class VaadinSession implements HttpSessionBindingListener, Serializable { } /** - * Provides exclusive access to this session from outside a request handling - * thread. + * Locks this session and runs the provided Runnable right away. *

- * The given runnable is executed while holding the session lock to ensure - * exclusive access to this session. The session and related thread locals - * are set properly before executing the runnable. + * It is generally recommended to use {@link #access(Runnable)} instead of + * this method for accessing a session from a different thread as + * {@link #access(Runnable)} can be used while holding the lock of another + * session. To avoid causing deadlocks, this methods throws an exception if + * it is detected than another session is also locked by the current thread. *

*

- * RPC handlers for components inside this session do not need this method - * as the session is automatically locked by the framework during request - * handling. - *

- *

- * Note that calling this method while another session is locked by the - * current thread will cause an exception. This is to prevent deadlock - * situations when two threads have locked one session each and are both - * waiting for the lock for the other session. + * This method behaves differently than {@link #access(Runnable)} in some + * situations: + *

    + *
  • If the current thread is currently holding the lock of this session, + * {@link #accessSynchronously(Runnable)} runs the task right away whereas + * {@link #access(Runnable)} defers the task to a later point in time.
  • + *
  • If some other thread is currently holding the lock for this session, + * {@link #accessSynchronously(Runnable)} blocks while waiting for the lock + * to be available whereas {@link #access(Runnable)} defers the task to a + * later point in time.
  • + *
  • If this session is currently not locked, + * {@link #accessSynchronously(Runnable)} runs the task right away whereas + * {@link #access(Runnable)} defers the task to a later point in time unless + * there are UIs with automatic push enabled.
  • + *
*

* * @param runnable @@ -1088,12 +1111,14 @@ public class VaadinSession implements HttpSessionBindingListener, Serializable { * @throws IllegalStateException * if the current thread holds the lock for another session * + * @since 7.1 * * @see #lock() * @see #getCurrent() - * @see UI#access(Runnable) + * @see #access(Runnable) + * @see UI#accessSynchronously(Runnable) */ - public void access(Runnable runnable) { + public void accessSynchronously(Runnable runnable) { VaadinService.verifyNoOtherSessionLocked(this); Map, CurrentInstance> old = null; @@ -1111,12 +1136,119 @@ public class VaadinSession implements HttpSessionBindingListener, Serializable { } /** - * @deprecated As of 7.1.0.beta1, use {@link #access(Runnable)} instead. - * This method will be removed before the final 7.1.0 release. + * Provides exclusive access to this session from outside a request handling + * thread. + *

+ * The given runnable is executed while holding the session lock to ensure + * exclusive access to this session. If this session is not locked, the lock + * will be acquired and the runnable is run right away. If this session is + * currently locked, the runnable will be run before that lock is released. + *

+ *

+ * RPC handlers for components inside this session do not need to use this + * method as the session is automatically locked by the framework during RPC + * handling. + *

+ *

+ * Please note that the runnable might be invoked on a different thread or + * later on the current thread, which means that custom thread locals might + * not have the expected values when the runnable is executed. The session + * and other thread locals provided by Vaadin are set properly before + * executing the runnable. + *

+ *

+ * The returned future can be used to check for task completion and to + * cancel the task. To help avoiding deadlocks, {@link Future#get()} throws + * an exception if it is detected that the current thread holds the lock for + * some other session. + *

+ * + * @see #lock() + * @see #getCurrent() + * @see #accessSynchronously(Runnable) + * @see UI#access(Runnable) + * + * @since 7.1 + * + * @param runnable + * the runnable which accesses the session + * @return a future that can be used to check for task completion and to + * cancel the task + */ + public Future access(Runnable runnable) { + FutureTask future = new FutureTask(runnable, null) { + @Override + public Void get() throws InterruptedException, ExecutionException { + /* + * Help the developer avoid programming patterns that cause + * deadlocks unless implemented very carefully. get(long, + * TimeUnit) does not have the same detection since a sensible + * timeout should avoid completely locking up the application. + * + * Even though no deadlock could occur after the runnable has + * been run, the check is always done as the deterministic + * behavior makes it easier to detect potential problems. + */ + VaadinService.verifyNoOtherSessionLocked(VaadinSession.this); + return super.get(); + } + }; + pendingAccessQueue.add(future); + + /* + * If no thread is currently holding the lock, pending changes for UIs + * with automatic push would not be processed and pushed until the next + * time there is a request or someone does an explicit push call. + * + * To remedy this, we try to get the lock at this point. If the lock is + * currently held by another thread, we just back out as the queue will + * get purged once it is released. If the lock is held by the current + * thread, we just release it knowing that the queue gets purged once + * the lock is ultimately released. If the lock is not held by any + * thread and we acquire it, we just release it again to purge the queue + * right away. + */ + try { + // tryLock() would be shorter, but it does not guarantee fairness + if (getLockInstance().tryLock(0, TimeUnit.SECONDS)) { + // unlock triggers runPendingAccessTasks + unlock(); + } + } catch (InterruptedException e) { + // Just ignore + } + + return future; + } + + /** + * Purges the queue of pending access invocations enqueued with + * {@link #access(Runnable)}. + *

+ * This method is automatically run by the framework at appropriate + * situations and is not intended to be used by application developers. + * + * @since 7.1 + */ + public void runPendingAccessTasks() { + assert hasLock(); + + FutureTask pendingAccess; + while ((pendingAccess = pendingAccessQueue.poll()) != null) { + if (!pendingAccess.isCancelled()) { + accessSynchronously(pendingAccess); + } + } + } + + /** + * @deprecated As of 7.1.0.beta1, use {@link #accessSynchronously(Runnable)} + * or {@link #access(Runnable)} instead. This method will be + * removed before the final 7.1.0 release. */ @Deprecated public void runSafely(Runnable runnable) { - access(runnable); + accessSynchronously(runnable); } /** diff --git a/server/src/com/vaadin/server/communication/FileUploadHandler.java b/server/src/com/vaadin/server/communication/FileUploadHandler.java index e875a4e861..e9569d45a1 100644 --- a/server/src/com/vaadin/server/communication/FileUploadHandler.java +++ b/server/src/com/vaadin/server/communication/FileUploadHandler.java @@ -632,7 +632,7 @@ public class FileUploadHandler implements RequestHandler { private void cleanStreamVariable(VaadinSession session, final ClientConnector owner, final String variableName) { - session.access(new Runnable() { + session.accessSynchronously(new Runnable() { @Override public void run() { owner.getUI() diff --git a/server/src/com/vaadin/server/communication/UidlWriter.java b/server/src/com/vaadin/server/communication/UidlWriter.java index fbe2fb86d5..60a884a635 100644 --- a/server/src/com/vaadin/server/communication/UidlWriter.java +++ b/server/src/com/vaadin/server/communication/UidlWriter.java @@ -74,9 +74,14 @@ public class UidlWriter implements Serializable { public void write(UI ui, Writer writer, boolean repaintAll, boolean analyzeLayouts, boolean async) throws IOException, JSONException { + VaadinSession session = ui.getSession(); + + // Purge pending access calls as they might produce additional changes + // to write out + session.runPendingAccessTasks(); + ArrayList dirtyVisibleConnectors = ui .getConnectorTracker().getDirtyVisibleConnectors(); - VaadinSession session = ui.getSession(); LegacyCommunicationManager manager = session.getCommunicationManager(); // Paints components ConnectorTracker uiConnectorTracker = ui.getConnectorTracker(); diff --git a/server/src/com/vaadin/ui/LoginForm.java b/server/src/com/vaadin/ui/LoginForm.java index d06882927e..67d7182ecb 100644 --- a/server/src/com/vaadin/ui/LoginForm.java +++ b/server/src/com/vaadin/ui/LoginForm.java @@ -68,7 +68,7 @@ public class LoginForm extends CustomComponent { } final StringBuilder responseBuilder = new StringBuilder(); - getUI().access(new Runnable() { + getUI().accessSynchronously(new Runnable() { @Override public void run() { String method = VaadinServletService.getCurrentServletRequest() diff --git a/server/src/com/vaadin/ui/UI.java b/server/src/com/vaadin/ui/UI.java index e077b003b8..234a309c06 100644 --- a/server/src/com/vaadin/ui/UI.java +++ b/server/src/com/vaadin/ui/UI.java @@ -22,6 +22,7 @@ import java.util.Collections; import java.util.Iterator; import java.util.LinkedHashSet; import java.util.Map; +import java.util.concurrent.Future; import com.vaadin.event.Action; import com.vaadin.event.Action.Handler; @@ -86,7 +87,7 @@ public abstract class UI extends AbstractSingleComponentContainer implements /** * The application to which this UI belongs */ - private VaadinSession session; + private volatile VaadinSession session; /** * List of windows in this UI. @@ -1098,24 +1099,34 @@ public abstract class UI extends AbstractSingleComponentContainer implements } /** - * Provides exclusive access to this UI from outside a request handling - * thread. + * Locks the session of this UI and runs the provided Runnable right away. *

- * The given runnable is executed while holding the session lock to ensure - * exclusive access to this UI and its session. The UI and related thread - * locals are set properly before executing the runnable. + * It is generally recommended to use {@link #access(Runnable)} instead of + * this method for accessing a session from a different thread as + * {@link #access(Runnable)} can be used while holding the lock of another + * session. To avoid causing deadlocks, this methods throws an exception if + * it is detected than another session is also locked by the current thread. *

*

- * RPC handlers for components inside this UI do not need this method as the - * session is automatically locked by the framework during request handling. - *

- *

- * Note that calling this method while another session is locked by the - * current thread will cause an exception. This is to prevent deadlock - * situations when two threads have locked one session each and are both - * waiting for the lock for the other session. + * This method behaves differently than {@link #access(Runnable)} in some + * situations: + *

    + *
  • If the current thread is currently holding the lock of the session, + * {@link #accessSynchronously(Runnable)} runs the task right away whereas + * {@link #access(Runnable)} defers the task to a later point in time.
  • + *
  • If some other thread is currently holding the lock for the session, + * {@link #accessSynchronously(Runnable)} blocks while waiting for the lock + * to be available whereas {@link #access(Runnable)} defers the task to a + * later point in time.
  • + *
  • If the session is currently not locked, + * {@link #accessSynchronously(Runnable)} runs the task right away whereas + * {@link #access(Runnable)} defers the task to a later point in time unless + * there are UIs with automatic push enabled.
  • + *
*

* + * @since 7.1 + * * @param runnable * the runnable which accesses the UI * @throws UIDetachedException @@ -1124,11 +1135,11 @@ public abstract class UI extends AbstractSingleComponentContainer implements * @throws IllegalStateException * if the current thread holds the lock for another session * - * @see #getCurrent() - * @see VaadinSession#access(Runnable) - * @see VaadinSession#lock() + * @see #access(Runnable) + * @see VaadinSession#accessSynchronously(Runnable) */ - public void access(Runnable runnable) throws UIDetachedException { + public void accessSynchronously(Runnable runnable) + throws UIDetachedException { Map, CurrentInstance> old = null; VaadinSession session = getSession(); @@ -1158,12 +1169,69 @@ public abstract class UI extends AbstractSingleComponentContainer implements } /** - * @deprecated As of 7.1.0.beta1, use {@link #access(Runnable)} instead. - * This method will be removed before the final 7.1.0 release. + * Provides exclusive access to this UI from outside a request handling + * thread. + *

+ * The given runnable is executed while holding the session lock to ensure + * exclusive access to this UI. If the session is not locked, the lock will + * be acquired and the runnable is run right away. If the session is + * currently locked, the runnable will be run before that lock is released. + *

+ *

+ * RPC handlers for components inside this UI do not need to use this method + * as the session is automatically locked by the framework during RPC + * handling. + *

+ *

+ * Please note that the runnable might be invoked on a different thread or + * later on the current thread, which means that custom thread locals might + * not have the expected values when the runnable is executed. The UI and + * other thread locals provided by Vaadin are set properly before executing + * the runnable. + *

+ *

+ * The returned future can be used to check for task completion and to + * cancel the task. + *

+ * + * @see #getCurrent() + * @see #accessSynchronously(Runnable) + * @see VaadinSession#access(Runnable) + * @see VaadinSession#lock() + * + * @since 7.1 + * + * @param runnable + * the runnable which accesses the UI + * @throws UIDetachedException + * if the UI is not attached to a session (and locking can + * therefore not be done) + * @return a future that can be used to check for task completion and to + * cancel the task + */ + public Future access(final Runnable runnable) { + VaadinSession session = getSession(); + + if (session == null) { + throw new UIDetachedException(); + } + + return session.access(new Runnable() { + @Override + public void run() { + accessSynchronously(runnable); + } + }); + } + + /** + * @deprecated As of 7.1.0.beta1, use {@link #accessSynchronously(Runnable)} + * or {@link #access(Runnable)} instead. This method will be + * removed before the final 7.1.0 release. */ @Deprecated public void runSafely(Runnable runnable) throws UIDetachedException { - access(runnable); + accessSynchronously(runnable); } /** @@ -1204,6 +1272,14 @@ public abstract class UI extends AbstractSingleComponentContainer implements VaadinSession session = getSession(); if (session != null) { assert session.hasLock(); + + /* + * Purge the pending access queue as it might mark a connector as + * dirty when the push would otherwise be ignored because there are + * no changes to push. + */ + session.runPendingAccessTasks(); + if (!getConnectorTracker().hasDirtyConnectors()) { // Do not push if there is nothing to push return; diff --git a/uitest/src/com/vaadin/tests/applicationcontext/CloseUI.java b/uitest/src/com/vaadin/tests/applicationcontext/CloseUI.java index bec8c0a10f..c88f482a7b 100644 --- a/uitest/src/com/vaadin/tests/applicationcontext/CloseUI.java +++ b/uitest/src/com/vaadin/tests/applicationcontext/CloseUI.java @@ -119,7 +119,7 @@ public class CloseUI extends AbstractTestUI { @Override public void run() { - ui.access(new Runnable() { + ui.accessSynchronously(new Runnable() { @Override public void run() { diff --git a/uitest/src/com/vaadin/tests/applicationcontext/UIRunSafelyThread.java b/uitest/src/com/vaadin/tests/applicationcontext/UIRunSafelyThread.java index ddc0f28664..c9af2c000d 100644 --- a/uitest/src/com/vaadin/tests/applicationcontext/UIRunSafelyThread.java +++ b/uitest/src/com/vaadin/tests/applicationcontext/UIRunSafelyThread.java @@ -11,7 +11,7 @@ public abstract class UIRunSafelyThread extends Thread { @Override public void run() { - ui.access(new Runnable() { + ui.accessSynchronously(new Runnable() { @Override public void run() { diff --git a/uitest/src/com/vaadin/tests/components/ui/UiAccess.html b/uitest/src/com/vaadin/tests/components/ui/UiAccess.html new file mode 100644 index 0000000000..664b15c16f --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/ui/UiAccess.html @@ -0,0 +1,127 @@ + + + + + + +New Test + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
New Test
open/run/com.vaadin.tests.components.ui.UiAccess?restartApplication
clickvaadin=runcomvaadintestscomponentsuiUiAccess::/VVerticalLayout[0]/Slot[2]/VVerticalLayout[0]/Slot[0]/VButton[0]/domChild[0]/domChild[0]
assertTextvaadin=runcomvaadintestscomponentsuiUiAccess::PID_SLog_row_2exact:0. Access from UI thread future is done? false
assertTextvaadin=runcomvaadintestscomponentsuiUiAccess::PID_SLog_row_11. Access from UI thread is run
assertTextvaadin=runcomvaadintestscomponentsuiUiAccess::PID_SLog_row_0exact:2. beforeClientResponse future is done? true
clickvaadin=runcomvaadintestscomponentsuiUiAccess::/VVerticalLayout[0]/Slot[2]/VVerticalLayout[0]/Slot[1]/VButton[0]/domChild[0]/domChild[0]
assertTextvaadin=runcomvaadintestscomponentsuiUiAccess::PID_SLog_row_10. Initial background message
assertTextvaadin=runcomvaadintestscomponentsuiUiAccess::PID_SLog_row_0exact:1. Thread has current response? false
waitForTextvaadin=runcomvaadintestscomponentsuiUiAccess::PID_SLog_row_40. Initial background message
assertTextvaadin=runcomvaadintestscomponentsuiUiAccess::PID_SLog_row_2exact:2. Thread got lock, inital future done? true
assertTextvaadin=runcomvaadintestscomponentsuiUiAccess::PID_SLog_row_1exact:3. Access has current response? true
assertTextvaadin=runcomvaadintestscomponentsuiUiAccess::PID_SLog_row_0exact:4. Thread is still alive? false
clickvaadin=runcomvaadintestscomponentsuiUiAccess::/VVerticalLayout[0]/Slot[2]/VVerticalLayout[0]/Slot[2]/VButton[0]/domChild[0]/domChild[0]
assertTextvaadin=runcomvaadintestscomponentsuiUiAccess::PID_SLog_row_20. Throwing exception in access
assertTextvaadin=runcomvaadintestscomponentsuiUiAccess::PID_SLog_row_1exact:1. firstFuture is done? true
assertTextvaadin=runcomvaadintestscomponentsuiUiAccess::PID_SLog_row_02. Got exception from firstFuture: java.lang.RuntimeException: Catch me if you can
clickvaadin=runcomvaadintestscomponentsuiUiAccess::/VVerticalLayout[0]/Slot[2]/VVerticalLayout[0]/Slot[3]/VButton[0]/domChild[0]/domChild[0]
assertTextvaadin=runcomvaadintestscomponentsuiUiAccess::PID_SLog_row_00. future was cancled, should not start
clickvaadin=runcomvaadintestscomponentsuiUiAccess::/VVerticalLayout[0]/Slot[2]/VVerticalLayout[0]/Slot[4]/VButton[0]/domChild[0]/domChild[0]
assertTextvaadin=runcomvaadintestscomponentsuiUiAccess::PID_SLog_row_20. Waiting for thread to start
assertTextvaadin=runcomvaadintestscomponentsuiUiAccess::PID_SLog_row_11. Thread started, waiting for interruption
assertTextvaadin=runcomvaadintestscomponentsuiUiAccess::PID_SLog_row_02. I was interrupted
+ + diff --git a/uitest/src/com/vaadin/tests/components/ui/UiAccess.java b/uitest/src/com/vaadin/tests/components/ui/UiAccess.java new file mode 100644 index 0000000000..c68da6ee54 --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/ui/UiAccess.java @@ -0,0 +1,235 @@ +/* + * Copyright 2000-2013 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.ui; + +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Future; +import java.util.concurrent.locks.ReentrantLock; + +import com.vaadin.server.VaadinRequest; +import com.vaadin.server.VaadinService; +import com.vaadin.tests.components.AbstractTestUIWithLog; +import com.vaadin.ui.Button; +import com.vaadin.ui.Button.ClickEvent; + +public class UiAccess extends AbstractTestUIWithLog { + + private Future checkFromBeforeClientResponse; + + @Override + protected void setup(VaadinRequest request) { + addComponent(new Button("Access from UI thread", + new Button.ClickListener() { + + @Override + public void buttonClick(ClickEvent event) { + log.clear(); + // Ensure beforeClientResponse is invoked + markAsDirty(); + checkFromBeforeClientResponse = access(new Runnable() { + @Override + public void run() { + log("Access from UI thread is run"); + } + }); + log("Access from UI thread future is done? " + + checkFromBeforeClientResponse.isDone()); + } + })); + addComponent(new Button("Access from background thread", + new Button.ClickListener() { + @Override + public void buttonClick(ClickEvent event) { + log.clear(); + final CountDownLatch latch = new CountDownLatch(1); + + new Thread() { + @Override + public void run() { + final boolean threadHasCurrentResponse = VaadinService + .getCurrentResponse() != null; + // session is locked by request thread at this + // point + final Future initialFuture = access(new Runnable() { + @Override + public void run() { + log("Initial background message"); + log("Thread has current response? " + + threadHasCurrentResponse); + } + }); + + // Let request thread continue + latch.countDown(); + + // Wait until thread can be locked + while (!getSession().getLockInstance() + .tryLock()) { + try { + Thread.sleep(100); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + } + try { + log("Thread got lock, inital future done? " + + initialFuture.isDone()); + setPollInterval(-1); + } finally { + getSession().unlock(); + } + final Thread thisThread = this; + access(new Runnable() { + @Override + public void run() { + log("Access has current response? " + + (VaadinService + .getCurrentResponse() != null)); + log("Thread is still alive? " + + thisThread.isAlive()); + } + }); + } + }.start(); + + // Wait for thread to do initialize before continuing + try { + latch.await(); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + + setPollInterval(3000); + } + })); + addComponent(new Button("Access throwing exception", + new Button.ClickListener() { + @Override + public void buttonClick(ClickEvent event) { + log.clear(); + final Future firstFuture = access(new Runnable() { + @Override + public void run() { + log("Throwing exception in access"); + throw new RuntimeException( + "Catch me if you can"); + } + }); + access(new Runnable() { + @Override + public void run() { + log("firstFuture is done? " + + firstFuture.isDone()); + try { + firstFuture.get(); + log("Should not get here"); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } catch (ExecutionException e) { + log("Got exception from firstFuture: " + + e.getMessage()); + } + } + }); + } + })); + addComponent(new Button("Cancel future before started", + new Button.ClickListener() { + @Override + public void buttonClick(ClickEvent event) { + log.clear(); + Future future = access(new Runnable() { + @Override + public void run() { + log("Should not get here"); + } + }); + future.cancel(false); + log("future was cancled, should not start"); + } + })); + addComponent(new Button("Cancel running future", + new Button.ClickListener() { + @Override + public void buttonClick(ClickEvent event) { + log.clear(); + final ReentrantLock interruptLock = new ReentrantLock(); + + final Future future = access(new Runnable() { + @Override + public void run() { + log("Waiting for thread to start"); + while (!interruptLock.isLocked()) { + try { + Thread.sleep(100); + } catch (InterruptedException e) { + log("Premature interruption"); + throw new RuntimeException(e); + } + } + + log("Thread started, waiting for interruption"); + try { + interruptLock.lockInterruptibly(); + } catch (InterruptedException e) { + log("I was interrupted"); + } + } + }); + + new Thread() { + @Override + public void run() { + interruptLock.lock(); + // Wait until UI thread has started waiting for + // the lock + while (!interruptLock.hasQueuedThreads()) { + try { + Thread.sleep(100); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + } + + future.cancel(true); + } + }.start(); + } + })); + } + + @Override + public void beforeClientResponse(boolean initial) { + if (checkFromBeforeClientResponse != null) { + log("beforeClientResponse future is done? " + + checkFromBeforeClientResponse.isDone()); + checkFromBeforeClientResponse = null; + } + } + + @Override + protected String getTestDescription() { + return "Test for various ways of using UI.access"; + } + + @Override + protected Integer getTicketNumber() { + return Integer.valueOf(11897); + } + +} -- cgit v1.2.3 From 4c2b86d7d191cdb012f382e5478abf9b3b5b32f1 Mon Sep 17 00:00:00 2001 From: Leif Åstrand Date: Tue, 21 May 2013 15:06:21 +0300 Subject: Stop using PlaceHolder widgets in VTabsheet (#11026) Vaadin 7.0 disabled rendering of tabs that are not shown, but the place holder mechanism was still retained. Now it is removed. Change-Id: Ic15b7f56852816d73916ef78f5997eb5e40f9cab --- client/src/com/vaadin/client/ui/VTabsheet.java | 82 +++++++------------------- 1 file changed, 20 insertions(+), 62 deletions(-) diff --git a/client/src/com/vaadin/client/ui/VTabsheet.java b/client/src/com/vaadin/client/ui/VTabsheet.java index ea1cb282a6..fe29e2ebc0 100644 --- a/client/src/com/vaadin/client/ui/VTabsheet.java +++ b/client/src/com/vaadin/client/ui/VTabsheet.java @@ -860,57 +860,17 @@ public class VTabsheet extends VTabsheetBase implements Focusable, */ tab.recalculateCaptionWidth(); - UIDL tabContentUIDL = null; - ComponentConnector tabContentPaintable = null; - Widget tabContentWidget = null; - if (tabUidl.getChildCount() > 0) { - tabContentUIDL = tabUidl.getChildUIDL(0); - tabContentPaintable = client.getPaintable(tabContentUIDL); - tabContentWidget = tabContentPaintable.getWidget(); - } - - if (tabContentPaintable != null) { - /* This is a tab with content information */ - - int oldIndex = tp.getWidgetIndex(tabContentWidget); - if (oldIndex != -1 && oldIndex != index) { - /* - * The tab has previously been rendered in another position so - * we must move the cached content to correct position - */ - tp.insert(tabContentWidget, index); - } - } else { - /* A tab whose content has not yet been loaded */ - - /* - * Make sure there is a corresponding empty tab in tp. The same - * operation as the moving above but for not-loaded tabs. - */ - if (index < tp.getWidgetCount()) { - Widget oldWidget = tp.getWidget(index); - if (!(oldWidget instanceof PlaceHolder)) { - tp.insert(new PlaceHolder(), index); - } - } - - } - if (selected) { - renderContent(tabContentUIDL); + renderContent(tabUidl.getChildUIDL(0)); tb.selectTab(index); - } else { - if (tabContentUIDL != null) { - // updating a drawn child on hidden tab - if (tp.getWidgetIndex(tabContentWidget) < 0) { - tp.insert(tabContentWidget, index); - } - } else if (tp.getWidgetCount() <= index) { - tp.add(new PlaceHolder()); - } } } + /** + * @deprecated as of 7.1, VTabsheet only keeps the active tab in the DOM + * without any place holders. + */ + @Deprecated public class PlaceHolder extends VLabel { public PlaceHolder() { super(""); @@ -920,17 +880,20 @@ public class VTabsheet extends VTabsheetBase implements Focusable, private void renderContent(final UIDL contentUIDL) { final ComponentConnector content = client.getPaintable(contentUIDL); Widget newWidget = content.getWidget(); - if (tp.getWidgetCount() > activeTabIndex) { - Widget old = tp.getWidget(activeTabIndex); - if (old != newWidget) { - tp.remove(activeTabIndex); - tp.insert(content.getWidget(), activeTabIndex); - } - } else { - tp.add(content.getWidget()); + + assert tp.getWidgetCount() <= 1; + + if (tp.getWidgetCount() == 0) { + tp.add(newWidget); + } else if (tp.getWidget(0) != newWidget) { + tp.remove(0); + tp.add(newWidget); } - tp.showWidget(activeTabIndex); + assert tp.getWidgetCount() <= 1; + + // There's never any other index than 0, but maintaining API for now + tp.showWidget(0); VTabsheet.this.iLayout(); updateOpenTabSize(); @@ -1114,13 +1077,8 @@ public class VTabsheet extends VTabsheetBase implements Focusable, @Override public void removeTab(int index) { tb.removeTab(index); - /* - * This must be checked because renderTab automatically removes the - * active tab content when it changes - */ - if (tp.getWidgetCount() > index) { - tp.remove(index); - } + + // Removing content from tp is handled by the connector } @Override -- cgit v1.2.3 From 87018cdca42491d192fa3ecdeb6d64d952cee517 Mon Sep 17 00:00:00 2001 From: Artur Signell Date: Mon, 27 May 2013 19:40:51 +0300 Subject: Add missing license header Change-Id: Iadf8831b01a292d5e29fea26c877541ab4dc5919 --- .../com/vaadin/data/util/converter/AbstractStringToNumberConverter.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/src/com/vaadin/data/util/converter/AbstractStringToNumberConverter.java b/server/src/com/vaadin/data/util/converter/AbstractStringToNumberConverter.java index b9a122ecb5..5999d850b4 100644 --- a/server/src/com/vaadin/data/util/converter/AbstractStringToNumberConverter.java +++ b/server/src/com/vaadin/data/util/converter/AbstractStringToNumberConverter.java @@ -1,5 +1,5 @@ /* - * Copyright 2012 Vaadin Ltd. + * Copyright 2000-2013 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 -- cgit v1.2.3 From cb1f63b8606ae23088a62f26dc8979885c5cd19c Mon Sep 17 00:00:00 2001 From: Leif Åstrand Date: Wed, 22 May 2013 13:59:44 +0300 Subject: Send window mode changes to the server immediately (#11737) Change-Id: Icfaa8f97824d8ed92eaee786cee8c92083dc1084 --- .../vaadin/shared/ui/window/WindowServerRpc.java | 2 -- .../window/WindowMaximizeRestoreTest.html | 42 ++++++++++++++++------ 2 files changed, 31 insertions(+), 13 deletions(-) diff --git a/shared/src/com/vaadin/shared/ui/window/WindowServerRpc.java b/shared/src/com/vaadin/shared/ui/window/WindowServerRpc.java index cfb10ad86a..b43765274e 100644 --- a/shared/src/com/vaadin/shared/ui/window/WindowServerRpc.java +++ b/shared/src/com/vaadin/shared/ui/window/WindowServerRpc.java @@ -15,13 +15,11 @@ */ package com.vaadin.shared.ui.window; -import com.vaadin.shared.annotations.Delayed; import com.vaadin.shared.communication.ServerRpc; import com.vaadin.shared.ui.ClickRpc; public interface WindowServerRpc extends ClickRpc, ServerRpc { - @Delayed(lastOnly = true) public void windowModeChanged(WindowMode newState); } \ No newline at end of file diff --git a/uitest/src/com/vaadin/tests/components/window/WindowMaximizeRestoreTest.html b/uitest/src/com/vaadin/tests/components/window/WindowMaximizeRestoreTest.html index 945564f298..dcdfa05687 100644 --- a/uitest/src/com/vaadin/tests/components/window/WindowMaximizeRestoreTest.html +++ b/uitest/src/com/vaadin/tests/components/window/WindowMaximizeRestoreTest.html @@ -162,17 +162,6 @@ vaadin=runcomvaadintestscomponentswindowWindowMaximizeRestoreTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/Slot[0]/VNativeButton[0] 43,12 - - - mouseClick - vaadin=runcomvaadintestscomponentswindowWindowMaximizeRestoreTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/Slot[0]/VNativeButton[0] - 43,12 - - - mouseClick - vaadin=runcomvaadintestscomponentswindowWindowMaximizeRestoreTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/Slot[0]/VNativeButton[0] - 43,12 - mouseClick @@ -234,6 +223,37 @@ window-1-maximized-with-doubleclick + + + mouseClick + vaadin=runcomvaadintestscomponentswindowWindowMaximizeRestoreTest::/VWindow[0]/domChild[0]/domChild[0]/domChild[1] + 8,4 + + + dragAndDrop + vaadin=runcomvaadintestscomponentswindowWindowMaximizeRestoreTest::/VWindow[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0] + -200,-200 + + + dragAndDrop + vaadin=runcomvaadintestscomponentswindowWindowMaximizeRestoreTest::/VWindow[0]/domChild[0]/domChild[0]/domChild[4]/domChild[0] + +100,+100 + + + mouseClick + vaadin=runcomvaadintestscomponentswindowWindowMaximizeRestoreTest::/VWindow[0]/domChild[0]/domChild[0]/domChild[1] + 6,5 + + + mouseClick + vaadin=runcomvaadintestscomponentswindowWindowMaximizeRestoreTest::/VWindow[0]/domChild[0]/domChild[0]/domChild[1] + 5,8 + + + screenCapture + + window-1-moved-maximized-restored + -- cgit v1.2.3 From e52df7cdf8bbee662f539b1cee7344debb07c586 Mon Sep 17 00:00:00 2001 From: Artur Signell Date: Mon, 27 May 2013 16:37:32 +0300 Subject: Added ComponentConnector.isAttached (#11928) Change-Id: I70d7d78a0d9de76080f6e0770a48504af8abdd84 --- .../vaadin/event/dd/acceptcriteria/SourceIs.java | 2 +- .../com/vaadin/server/AbstractClientConnector.java | 14 ++++++++++-- server/src/com/vaadin/server/ClientConnector.java | 26 ++++++++++++++-------- .../src/com/vaadin/server/DragAndDropService.java | 10 +++++++++ .../src/com/vaadin/server/LegacyApplication.java | 2 +- server/src/com/vaadin/ui/LegacyWindow.java | 2 +- server/src/com/vaadin/ui/UI.java | 2 +- .../components/colorpicker/ColorPickerHistory.java | 2 +- 8 files changed, 44 insertions(+), 16 deletions(-) diff --git a/server/src/com/vaadin/event/dd/acceptcriteria/SourceIs.java b/server/src/com/vaadin/event/dd/acceptcriteria/SourceIs.java index 65c1050fb0..0cc2f0a1a5 100644 --- a/server/src/com/vaadin/event/dd/acceptcriteria/SourceIs.java +++ b/server/src/com/vaadin/event/dd/acceptcriteria/SourceIs.java @@ -48,7 +48,7 @@ public class SourceIs extends ClientSideCriterion { int paintedComponents = 0; for (int i = 0; i < components.length; i++) { Component c = components[i]; - if (c.getUI() != null && c.getUI().getSession() != null) { + if (c.isAttached()) { target.addAttribute("component" + paintedComponents++, c); } else { Logger.getLogger(SourceIs.class.getName()) diff --git a/server/src/com/vaadin/server/AbstractClientConnector.java b/server/src/com/vaadin/server/AbstractClientConnector.java index e998b8ed55..01f7d9af42 100644 --- a/server/src/com/vaadin/server/AbstractClientConnector.java +++ b/server/src/com/vaadin/server/AbstractClientConnector.java @@ -577,7 +577,7 @@ public abstract class AbstractClientConnector implements ClientConnector, } // Send detach event if the component have been connected to a window - if (getSession() != null) { + if (isAttached()) { detach(); } @@ -585,7 +585,7 @@ public abstract class AbstractClientConnector implements ClientConnector, this.parent = parent; // Send attach event if connected to an application - if (getSession() != null) { + if (isAttached()) { attach(); } } @@ -595,6 +595,16 @@ public abstract class AbstractClientConnector implements ClientConnector, return parent; } + /* + * (non-Javadoc) + * + * @see com.vaadin.server.ClientConnector#isAttached() + */ + @Override + public boolean isAttached() { + return getSession() != null; + } + @Override public void attach() { markAsDirty(); diff --git a/server/src/com/vaadin/server/ClientConnector.java b/server/src/com/vaadin/server/ClientConnector.java index 3b52fbc730..9e328bb6ef 100644 --- a/server/src/com/vaadin/server/ClientConnector.java +++ b/server/src/com/vaadin/server/ClientConnector.java @@ -226,14 +226,22 @@ public interface ClientConnector extends Connector { public void setParent(ClientConnector parent); /** - * Notifies the connector that it is connected to an application. + * Checks if the connector is attached to a VaadinSession. * + * @since 7.1 + * @return true if the connector is attached to a session, false otherwise + */ + public boolean isAttached(); + + /** + * Notifies the connector that it is connected to a VaadinSession (and + * therefore also to a UI). *

* The caller of this method is {@link #setParent(ClientConnector)} if the - * parent is itself already attached to the application. If not, the parent - * will call the {@link #attach()} for all its children when it is attached - * to the application. This method is always called before the connector's - * data is sent to the client-side for the first time. + * parent is itself already attached to the session. If not, the parent will + * call the {@link #attach()} for all its children when it is attached to + * the session. This method is always called before the connector's data is + * sent to the client-side for the first time. *

* *

@@ -243,13 +251,13 @@ public interface ClientConnector extends Connector { public void attach(); /** - * Notifies the connector that it is detached from the application. + * Notifies the connector that it is detached from its VaadinSession. * *

* The caller of this method is {@link #setParent(ClientConnector)} if the - * parent is in the application. When the parent is detached from the - * application it is its responsibility to call {@link #detach()} for each - * of its children. + * parent is in the session. When the parent is detached from the session it + * is its responsibility to call {@link #detach()} for each of its children. + * *

*/ public void detach(); diff --git a/server/src/com/vaadin/server/DragAndDropService.java b/server/src/com/vaadin/server/DragAndDropService.java index a83e83ef7f..cc571853fe 100644 --- a/server/src/com/vaadin/server/DragAndDropService.java +++ b/server/src/com/vaadin/server/DragAndDropService.java @@ -375,4 +375,14 @@ public class DragAndDropService implements VariableOwner, ClientConnector { @Override public void removeDetachListener(DetachListener listener) { } + + /* + * (non-Javadoc) + * + * @see com.vaadin.server.ClientConnector#isAttached() + */ + @Override + public boolean isAttached() { + return true; + } } diff --git a/server/src/com/vaadin/server/LegacyApplication.java b/server/src/com/vaadin/server/LegacyApplication.java index 54550ce134..44649067c5 100644 --- a/server/src/com/vaadin/server/LegacyApplication.java +++ b/server/src/com/vaadin/server/LegacyApplication.java @@ -64,7 +64,7 @@ public abstract class LegacyApplication implements ErrorHandler { if (this.mainWindow != null) { throw new IllegalStateException("mainWindow has already been set"); } - if (mainWindow.getSession() != null) { + if (mainWindow.isAttached()) { throw new IllegalStateException( "mainWindow is attached to another application"); } diff --git a/server/src/com/vaadin/ui/LegacyWindow.java b/server/src/com/vaadin/ui/LegacyWindow.java index 1b66b608c1..458b09390d 100644 --- a/server/src/com/vaadin/ui/LegacyWindow.java +++ b/server/src/com/vaadin/ui/LegacyWindow.java @@ -125,7 +125,7 @@ public class LegacyWindow extends UI { public void setName(String name) { this.name = name; // The name can not be changed in application - if (getSession() != null) { + if (isAttached()) { throw new IllegalStateException( "Window name can not be changed while " + "the window is in application"); diff --git a/server/src/com/vaadin/ui/UI.java b/server/src/com/vaadin/ui/UI.java index 234a309c06..bbc1d0cd33 100644 --- a/server/src/com/vaadin/ui/UI.java +++ b/server/src/com/vaadin/ui/UI.java @@ -419,7 +419,7 @@ public abstract class UI extends AbstractSingleComponentContainer implements throw new NullPointerException("Argument must not be null"); } - if (window.getUI() != null && window.getUI().getSession() != null) { + if (window.isAttached()) { throw new IllegalArgumentException( "Window is already attached to an application."); } diff --git a/server/src/com/vaadin/ui/components/colorpicker/ColorPickerHistory.java b/server/src/com/vaadin/ui/components/colorpicker/ColorPickerHistory.java index 2902585f56..de8c5db195 100644 --- a/server/src/com/vaadin/ui/components/colorpicker/ColorPickerHistory.java +++ b/server/src/com/vaadin/ui/components/colorpicker/ColorPickerHistory.java @@ -95,7 +95,7 @@ public class ColorPickerHistory extends CustomComponent implements @SuppressWarnings("unchecked") private ArrayBlockingQueue getColorHistory() { - if (getSession() != null) { + if (isAttached()) { Object colorHistory = getSession().getAttribute( "colorPickerHistory"); if (colorHistory instanceof ArrayBlockingQueue) { -- cgit v1.2.3 From 2b5ba963af81bb8a21f51ab29bd47ecd0054daa6 Mon Sep 17 00:00:00 2001 From: Leif Åstrand Date: Tue, 28 May 2013 14:55:35 +0300 Subject: Define how CurrentInstance works with access() (#11897) Change-Id: I7ca62c5706fd37e7c44ed46703bcdce159b367f4 --- server/src/com/vaadin/server/VaadinSession.java | 82 +++++++++++++++------- server/src/com/vaadin/ui/UI.java | 11 ++- server/src/com/vaadin/util/CurrentInstance.java | 46 ++++++++++-- .../com/vaadin/tests/components/ui/UiAccess.html | 51 +++++++++++++- .../com/vaadin/tests/components/ui/UiAccess.java | 82 ++++++++++++++++++++++ 5 files changed, 236 insertions(+), 36 deletions(-) diff --git a/server/src/com/vaadin/server/VaadinSession.java b/server/src/com/vaadin/server/VaadinSession.java index 9625a3f350..eaf611caad 100644 --- a/server/src/com/vaadin/server/VaadinSession.java +++ b/server/src/com/vaadin/server/VaadinSession.java @@ -67,6 +67,35 @@ import com.vaadin.util.ReflectTools; @SuppressWarnings("serial") public class VaadinSession implements HttpSessionBindingListener, Serializable { + private class FutureAccess extends FutureTask { + /** + * Snapshot of all non-inheritable current instances at the time this + * object was created. + */ + private final Map, CurrentInstance> instances = CurrentInstance + .getInstances(true); + + public FutureAccess(Runnable arg0) { + super(arg0, null); + } + + @Override + public Void get() throws InterruptedException, ExecutionException { + /* + * Help the developer avoid programming patterns that cause + * deadlocks unless implemented very carefully. get(long, TimeUnit) + * does not have the same detection since a sensible timeout should + * avoid completely locking up the application. + * + * Even though no deadlock could occur after the runnable has been + * run, the check is always done as the deterministic behavior makes + * it easier to detect potential problems. + */ + VaadinService.verifyNoOtherSessionLocked(VaadinSession.this); + return super.get(); + } + } + /** * The name of the parameter that is by default used in e.g. web.xml to * define the name of the default {@link UI} class. @@ -140,7 +169,7 @@ public class VaadinSession implements HttpSessionBindingListener, Serializable { * session is serialized as long as it doesn't happen while some other * thread has the lock. */ - private transient final ConcurrentLinkedQueue> pendingAccessQueue = new ConcurrentLinkedQueue>(); + private transient final ConcurrentLinkedQueue pendingAccessQueue = new ConcurrentLinkedQueue(); /** * Create a new service session tied to a Vaadin service @@ -1152,9 +1181,13 @@ public class VaadinSession implements HttpSessionBindingListener, Serializable { *

* Please note that the runnable might be invoked on a different thread or * later on the current thread, which means that custom thread locals might - * not have the expected values when the runnable is executed. The session - * and other thread locals provided by Vaadin are set properly before - * executing the runnable. + * not have the expected values when the runnable is executed. Inheritable + * values in {@link CurrentInstance} will have the same values as when this + * method was invoked. {@link VaadinSession#getCurrent()} and + * {@link VaadinService#getCurrent()} are set according to this session + * before executing the runnable. Non-inheritable CurrentInstance values + * including {@link VaadinService#getCurrentRequest()} and + * {@link VaadinService#getCurrentResponse()} will not be defined. *

*

* The returned future can be used to check for task completion and to @@ -1176,23 +1209,7 @@ public class VaadinSession implements HttpSessionBindingListener, Serializable { * cancel the task */ public Future access(Runnable runnable) { - FutureTask future = new FutureTask(runnable, null) { - @Override - public Void get() throws InterruptedException, ExecutionException { - /* - * Help the developer avoid programming patterns that cause - * deadlocks unless implemented very carefully. get(long, - * TimeUnit) does not have the same detection since a sensible - * timeout should avoid completely locking up the application. - * - * Even though no deadlock could occur after the runnable has - * been run, the check is always done as the deterministic - * behavior makes it easier to detect potential problems. - */ - VaadinService.verifyNoOtherSessionLocked(VaadinSession.this); - return super.get(); - } - }; + FutureAccess future = new FutureAccess(runnable); pendingAccessQueue.add(future); /* @@ -1233,11 +1250,26 @@ public class VaadinSession implements HttpSessionBindingListener, Serializable { public void runPendingAccessTasks() { assert hasLock(); - FutureTask pendingAccess; - while ((pendingAccess = pendingAccessQueue.poll()) != null) { - if (!pendingAccess.isCancelled()) { - accessSynchronously(pendingAccess); + if (pendingAccessQueue.isEmpty()) { + return; + } + + Map, CurrentInstance> oldInstances = CurrentInstance + .getInstances(false); + + FutureAccess pendingAccess; + try { + while ((pendingAccess = pendingAccessQueue.poll()) != null) { + if (!pendingAccess.isCancelled()) { + CurrentInstance.clearAll(); + CurrentInstance + .restoreThreadLocals(pendingAccess.instances); + accessSynchronously(pendingAccess); + } } + } finally { + CurrentInstance.clearAll(); + CurrentInstance.restoreThreadLocals(oldInstances); } } diff --git a/server/src/com/vaadin/ui/UI.java b/server/src/com/vaadin/ui/UI.java index bbc1d0cd33..0b21112c97 100644 --- a/server/src/com/vaadin/ui/UI.java +++ b/server/src/com/vaadin/ui/UI.java @@ -1185,9 +1185,14 @@ public abstract class UI extends AbstractSingleComponentContainer implements *

* Please note that the runnable might be invoked on a different thread or * later on the current thread, which means that custom thread locals might - * not have the expected values when the runnable is executed. The UI and - * other thread locals provided by Vaadin are set properly before executing - * the runnable. + * not have the expected values when the runnable is executed. Inheritable + * values in {@link CurrentInstance} will have the same values as when this + * method was invoked. {@link UI#getCurrent()}, + * {@link VaadinSession#getCurrent()} and {@link VaadinService#getCurrent()} + * are set according to this UI before executing the runnable. + * Non-inheritable CurrentInstance values including + * {@link VaadinService#getCurrentRequest()} and + * {@link VaadinService#getCurrentResponse()} will not be defined. *

*

* The returned future can be used to check for task completion and to diff --git a/server/src/com/vaadin/util/CurrentInstance.java b/server/src/com/vaadin/util/CurrentInstance.java index 0854d422fd..8e6ef8266e 100644 --- a/server/src/com/vaadin/util/CurrentInstance.java +++ b/server/src/com/vaadin/util/CurrentInstance.java @@ -17,33 +17,35 @@ package com.vaadin.util; import java.io.Serializable; +import java.util.Collections; import java.util.HashMap; import java.util.Map; import java.util.Map.Entry; -import com.vaadin.server.VaadinPortlet; import com.vaadin.server.VaadinRequest; import com.vaadin.server.VaadinResponse; import com.vaadin.server.VaadinService; -import com.vaadin.server.VaadinServlet; import com.vaadin.server.VaadinSession; import com.vaadin.ui.UI; /** - * Keeps track of various thread local instances used by the framework. + * Keeps track of various current instances for the current thread. All the + * instances are automatically cleared after handling a request from the client + * to avoid leaking memory. The inheritable values are also maintained when + * execution is moved to another thread, both when a new thread is created and + * when {@link VaadinSession#access(Runnable)} or {@link UI#access(Runnable)} is + * used. *

* Currently the framework uses the following instances: *

*

- * Inheritable: {@link UI}, {@link VaadinPortlet}, {@link VaadinService}, - * {@link VaadinServlet}, {@link VaadinSession}. + * Inheritable: {@link UI}, {@link VaadinService}, {@link VaadinSession}. *

*

* Non-inheritable: {@link VaadinRequest}, {@link VaadinResponse}. *

* * @author Vaadin Ltd - * @version @VERSION@ * @since 7.0.0 */ public class CurrentInstance implements Serializable { @@ -115,7 +117,9 @@ public class CurrentInstance implements Serializable { /** * Sets the current inheritable instance of the given type. A current - * instance that is inheritable will be available for child threads. + * instance that is inheritable will be available for child threads and in + * code run by {@link VaadinSession#access(Runnable)} and + * {@link UI#access(Runnable)}. * * @see #set(Class, Object) * @see InheritableThreadLocal @@ -183,6 +187,34 @@ public class CurrentInstance implements Serializable { } } + /** + * Gets the currently set instances so that they can later be restored using + * {@link #restoreThreadLocals(Map)}. + * + * @since 7.1 + * + * @param onlyInheritable + * true if only the inheritable instances should be + * included; false to get all instances. + * @return a map containing the current instances + */ + public static Map, CurrentInstance> getInstances( + boolean onlyInheritable) { + Map, CurrentInstance> map = instances.get(); + if (map == null) { + return Collections.emptyMap(); + } else { + Map, CurrentInstance> copy = new HashMap, CurrentInstance>(); + for (Class c : map.keySet()) { + CurrentInstance ci = map.get(c); + if (ci.inheritable || !onlyInheritable) { + copy.put(c, ci); + } + } + return copy; + } + } + /** * Sets thread locals for the UI and all related classes * diff --git a/uitest/src/com/vaadin/tests/components/ui/UiAccess.html b/uitest/src/com/vaadin/tests/components/ui/UiAccess.html index 664b15c16f..8ae2f2f48e 100644 --- a/uitest/src/com/vaadin/tests/components/ui/UiAccess.html +++ b/uitest/src/com/vaadin/tests/components/ui/UiAccess.html @@ -121,7 +121,56 @@ vaadin=runcomvaadintestscomponentsuiUiAccess::PID_SLog_row_0 2. I was interrupted - + + click + vaadin=runcomvaadintestscomponentsuiUiAccess::/VVerticalLayout[0]/Slot[2]/VVerticalLayout[0]/Slot[5]/VButton[0]/domChild[0]/domChild[0] + + + + assertText + vaadin=runcomvaadintestscomponentsuiUiAccess::PID_SLog_row_3 + 0. accessSynchronously has request? true + + + assertText + vaadin=runcomvaadintestscomponentsuiUiAccess::PID_SLog_row_2 + 1. Test value in accessSynchronously: Set before accessSynchronosly + + + assertText + vaadin=runcomvaadintestscomponentsuiUiAccess::PID_SLog_row_1 + 2. has request after accessSynchronously? true + + + assertText + vaadin=runcomvaadintestscomponentsuiUiAccess::PID_SLog_row_0 + 3. Test value after accessSynchornously: Set in accessSynchronosly + + + click + vaadin=runcomvaadintestscomponentsuiUiAccess::/VVerticalLayout[0]/Slot[2]/VVerticalLayout[0]/Slot[6]/VButton[0]/domChild[0]/domChild[0] + + + + assertText + vaadin=runcomvaadintestscomponentsuiUiAccess::PID_SLog_row_3 + 0. access has request? false + + + assertText + vaadin=runcomvaadintestscomponentsuiUiAccess::PID_SLog_row_2 + 1. Test value in access: Set before access + + + assertText + vaadin=runcomvaadintestscomponentsuiUiAccess::PID_SLog_row_1 + 2. has request after access? true + + + assertText + vaadin=runcomvaadintestscomponentsuiUiAccess::PID_SLog_row_0 + 3. Test value after access: Set before run pending + diff --git a/uitest/src/com/vaadin/tests/components/ui/UiAccess.java b/uitest/src/com/vaadin/tests/components/ui/UiAccess.java index c68da6ee54..c39f65243d 100644 --- a/uitest/src/com/vaadin/tests/components/ui/UiAccess.java +++ b/uitest/src/com/vaadin/tests/components/ui/UiAccess.java @@ -26,11 +26,25 @@ import com.vaadin.server.VaadinService; import com.vaadin.tests.components.AbstractTestUIWithLog; import com.vaadin.ui.Button; import com.vaadin.ui.Button.ClickEvent; +import com.vaadin.util.CurrentInstance; public class UiAccess extends AbstractTestUIWithLog { private Future checkFromBeforeClientResponse; + private class CurrentInstanceTestType { + private String value; + + public CurrentInstanceTestType(String value) { + this.value = value; + } + + @Override + public String toString() { + return value; + } + } + @Override protected void setup(VaadinRequest request) { addComponent(new Button("Access from UI thread", @@ -211,6 +225,74 @@ public class UiAccess extends AbstractTestUIWithLog { }.start(); } })); + addComponent(new Button("CurrentInstance accessSynchronously values", + new Button.ClickListener() { + @Override + public void buttonClick(ClickEvent event) { + log.clear(); + // accessSynchronously should maintain values + CurrentInstance.set(CurrentInstanceTestType.class, + new CurrentInstanceTestType( + "Set before accessSynchronosly")); + accessSynchronously(new Runnable() { + @Override + public void run() { + log.log("accessSynchronously has request? " + + (VaadinService.getCurrentRequest() != null)); + log.log("Test value in accessSynchronously: " + + CurrentInstance + .get(CurrentInstanceTestType.class)); + CurrentInstance.set( + CurrentInstanceTestType.class, + new CurrentInstanceTestType( + "Set in accessSynchronosly")); + } + }); + log.log("has request after accessSynchronously? " + + (VaadinService.getCurrentRequest() != null)); + log("Test value after accessSynchornously: " + + CurrentInstance + .get(CurrentInstanceTestType.class)); + } + })); + addComponent(new Button("CurrentInstance access values", + new Button.ClickListener() { + @Override + public void buttonClick(ClickEvent event) { + log.clear(); + // accessSynchronously should maintain values + CurrentInstance + .setInheritable(CurrentInstanceTestType.class, + new CurrentInstanceTestType( + "Set before access")); + access(new Runnable() { + @Override + public void run() { + log.log("access has request? " + + (VaadinService.getCurrentRequest() != null)); + log.log("Test value in access: " + + CurrentInstance + .get(CurrentInstanceTestType.class)); + CurrentInstance.setInheritable( + CurrentInstanceTestType.class, + new CurrentInstanceTestType( + "Set in access")); + } + }); + CurrentInstance.setInheritable( + CurrentInstanceTestType.class, + new CurrentInstanceTestType( + "Set before run pending")); + + getSession().runPendingAccessTasks(); + + log.log("has request after access? " + + (VaadinService.getCurrentRequest() != null)); + log("Test value after access: " + + CurrentInstance + .get(CurrentInstanceTestType.class)); + } + })); } @Override -- cgit v1.2.3 From d34583895c884767537ad866de942d23c044af52 Mon Sep 17 00:00:00 2001 From: Leif Åstrand Date: Tue, 28 May 2013 15:39:02 +0300 Subject: Remove ThreadLocal references from CurrentInstance (#11914) Change-Id: Ic7389a06726026383b96de80b0d038ed11e9d273 --- .../vaadin/server/ConnectorResourceHandler.java | 6 ++-- .../com/vaadin/server/GlobalResourceHandler.java | 8 ++--- server/src/com/vaadin/server/VaadinSession.java | 11 ++++--- server/src/com/vaadin/ui/UI.java | 4 +-- server/src/com/vaadin/util/CurrentInstance.java | 34 ++++++++++++++-------- 5 files changed, 36 insertions(+), 27 deletions(-) diff --git a/server/src/com/vaadin/server/ConnectorResourceHandler.java b/server/src/com/vaadin/server/ConnectorResourceHandler.java index 00d82988d3..3f3f41a179 100644 --- a/server/src/com/vaadin/server/ConnectorResourceHandler.java +++ b/server/src/com/vaadin/server/ConnectorResourceHandler.java @@ -77,8 +77,8 @@ public class ConnectorResourceHandler implements RequestHandler { session.unlock(); } - Map, CurrentInstance> oldThreadLocals = CurrentInstance - .setThreadLocals(ui); + Map, CurrentInstance> oldInstances = CurrentInstance + .setCurrent(ui); try { if (!connector.handleConnectorRequest(request, response, key)) { return error(request, response, connector.getClass() @@ -88,7 +88,7 @@ public class ConnectorResourceHandler implements RequestHandler { + ") did not handle connector request for " + key); } } finally { - CurrentInstance.restoreThreadLocals(oldThreadLocals); + CurrentInstance.restoreInstances(oldInstances); } return true; diff --git a/server/src/com/vaadin/server/GlobalResourceHandler.java b/server/src/com/vaadin/server/GlobalResourceHandler.java index d411b286d0..4235d85024 100644 --- a/server/src/com/vaadin/server/GlobalResourceHandler.java +++ b/server/src/com/vaadin/server/GlobalResourceHandler.java @@ -87,14 +87,14 @@ public class GlobalResourceHandler implements RequestHandler { + " is not a valid global resource path"); } session.lock(); - Map, CurrentInstance> oldThreadLocals = null; + Map, CurrentInstance> oldInstances = null; DownloadStream stream = null; try { UI ui = session.getUIById(Integer.parseInt(uiid)); if (ui == null) { return error(request, response, "No UI found for id " + uiid); } - oldThreadLocals = CurrentInstance.setThreadLocals(ui); + oldInstances = CurrentInstance.setCurrent(ui); ConnectorResource resource; if (LEGACY_TYPE.equals(type)) { resource = legacyResources.get(key); @@ -115,8 +115,8 @@ public class GlobalResourceHandler implements RequestHandler { } } finally { session.unlock(); - if (oldThreadLocals != null) { - CurrentInstance.restoreThreadLocals(oldThreadLocals); + if (oldInstances != null) { + CurrentInstance.restoreInstances(oldInstances); } } diff --git a/server/src/com/vaadin/server/VaadinSession.java b/server/src/com/vaadin/server/VaadinSession.java index eaf611caad..9939ad709e 100644 --- a/server/src/com/vaadin/server/VaadinSession.java +++ b/server/src/com/vaadin/server/VaadinSession.java @@ -1153,15 +1153,15 @@ public class VaadinSession implements HttpSessionBindingListener, Serializable { Map, CurrentInstance> old = null; lock(); try { - old = CurrentInstance.setThreadLocals(this); + old = CurrentInstance.setCurrent(this); runnable.run(); } finally { unlock(); if (old != null) { - CurrentInstance.restoreThreadLocals(old); + CurrentInstance.restoreInstances(old); } } - + } /** @@ -1262,14 +1262,13 @@ public class VaadinSession implements HttpSessionBindingListener, Serializable { while ((pendingAccess = pendingAccessQueue.poll()) != null) { if (!pendingAccess.isCancelled()) { CurrentInstance.clearAll(); - CurrentInstance - .restoreThreadLocals(pendingAccess.instances); + CurrentInstance.restoreInstances(pendingAccess.instances); accessSynchronously(pendingAccess); } } } finally { CurrentInstance.clearAll(); - CurrentInstance.restoreThreadLocals(oldInstances); + CurrentInstance.restoreInstances(oldInstances); } } diff --git a/server/src/com/vaadin/ui/UI.java b/server/src/com/vaadin/ui/UI.java index 0b21112c97..508564ac0f 100644 --- a/server/src/com/vaadin/ui/UI.java +++ b/server/src/com/vaadin/ui/UI.java @@ -1157,12 +1157,12 @@ public abstract class UI extends AbstractSingleComponentContainer implements // acquired the lock. throw new UIDetachedException(); } - old = CurrentInstance.setThreadLocals(this); + old = CurrentInstance.setCurrent(this); runnable.run(); } finally { session.unlock(); if (old != null) { - CurrentInstance.restoreThreadLocals(old); + CurrentInstance.restoreInstances(old); } } diff --git a/server/src/com/vaadin/util/CurrentInstance.java b/server/src/com/vaadin/util/CurrentInstance.java index 8e6ef8266e..b97bab3d8a 100644 --- a/server/src/com/vaadin/util/CurrentInstance.java +++ b/server/src/com/vaadin/util/CurrentInstance.java @@ -174,13 +174,15 @@ public class CurrentInstance implements Serializable { } /** - * Restores the given thread locals to the given values. Note that this - * should only be used internally to restore Vaadin classes. + * Restores the given instances to the given values. Note that this should + * only be used internally to restore Vaadin classes. + * + * @since 7.1 * * @param old - * A Class -> Object map to set as thread locals + * A Class -> CurrentInstance map to set as current instances */ - public static void restoreThreadLocals(Map, CurrentInstance> old) { + public static void restoreInstances(Map, CurrentInstance> old) { for (Class c : old.keySet()) { CurrentInstance ci = old.get(c); set(c, ci.instance, ci.inheritable); @@ -189,7 +191,7 @@ public class CurrentInstance implements Serializable { /** * Gets the currently set instances so that they can later be restored using - * {@link #restoreThreadLocals(Map)}. + * {@link #restoreInstances(Map)}. * * @since 7.1 * @@ -216,30 +218,38 @@ public class CurrentInstance implements Serializable { } /** - * Sets thread locals for the UI and all related classes + * Sets current instances for the UI and all related classes. The previously + * defined values can be restored by passing the returned map to + * {@link #restoreInstances(Map)}. + * + * @since 7.1 * * @param ui * The UI - * @return A map containing the old values of the thread locals this method + * @return A map containing the old values of the instances that this method * updated. */ - public static Map, CurrentInstance> setThreadLocals(UI ui) { + public static Map, CurrentInstance> setCurrent(UI ui) { Map, CurrentInstance> old = new HashMap, CurrentInstance>(); old.put(UI.class, new CurrentInstance(UI.getCurrent(), true)); UI.setCurrent(ui); - old.putAll(setThreadLocals(ui.getSession())); + old.putAll(setCurrent(ui.getSession())); return old; } /** - * Sets thread locals for the {@link VaadinSession} and all related classes + * Sets current instances for the {@link VaadinSession} and all related + * classes. The previously defined values can be restored by passing the + * returned map to {@link #restoreInstances(Map)}. + * + * @since 7.1 * * @param session * The VaadinSession - * @return A map containing the old values of the thread locals this method + * @return A map containing the old values of the instances this method * updated. */ - public static Map, CurrentInstance> setThreadLocals( + public static Map, CurrentInstance> setCurrent( VaadinSession session) { Map, CurrentInstance> old = new HashMap, CurrentInstance>(); old.put(VaadinSession.class, -- cgit v1.2.3 From bb7b40487f728f60e910b51d5c236f4fb699cb01 Mon Sep 17 00:00:00 2001 From: Leif Åstrand Date: Tue, 28 May 2013 15:36:16 +0300 Subject: Remove outdated testing (#11897) * access is run right away instead of the next time there's a request from the server. * Non-inheritable CurrentInstance values are not carried over to access Change-Id: I6a9f3f2a74647357fe02c43e96878d803cfaf207 --- uitest/src/com/vaadin/tests/components/ui/UiAccess.html | 14 ++------------ uitest/src/com/vaadin/tests/components/ui/UiAccess.java | 11 ----------- 2 files changed, 2 insertions(+), 23 deletions(-) diff --git a/uitest/src/com/vaadin/tests/components/ui/UiAccess.html b/uitest/src/com/vaadin/tests/components/ui/UiAccess.html index 8ae2f2f48e..613691623c 100644 --- a/uitest/src/com/vaadin/tests/components/ui/UiAccess.html +++ b/uitest/src/com/vaadin/tests/components/ui/UiAccess.html @@ -53,23 +53,13 @@ waitForText - vaadin=runcomvaadintestscomponentsuiUiAccess::PID_SLog_row_4 - 0. Initial background message - - - assertText vaadin=runcomvaadintestscomponentsuiUiAccess::PID_SLog_row_2 - exact:2. Thread got lock, inital future done? true - - - assertText - vaadin=runcomvaadintestscomponentsuiUiAccess::PID_SLog_row_1 - exact:3. Access has current response? true + 0. Initial background message assertText vaadin=runcomvaadintestscomponentsuiUiAccess::PID_SLog_row_0 - exact:4. Thread is still alive? false + exact:2. Thread got lock, inital future done? true click diff --git a/uitest/src/com/vaadin/tests/components/ui/UiAccess.java b/uitest/src/com/vaadin/tests/components/ui/UiAccess.java index c39f65243d..297a985778 100644 --- a/uitest/src/com/vaadin/tests/components/ui/UiAccess.java +++ b/uitest/src/com/vaadin/tests/components/ui/UiAccess.java @@ -107,17 +107,6 @@ public class UiAccess extends AbstractTestUIWithLog { } finally { getSession().unlock(); } - final Thread thisThread = this; - access(new Runnable() { - @Override - public void run() { - log("Access has current response? " - + (VaadinService - .getCurrentResponse() != null)); - log("Thread is still alive? " - + thisThread.isAlive()); - } - }); } }.start(); -- cgit v1.2.3 From f64d944b257436da21afd547f8ea5a9dd4a425e7 Mon Sep 17 00:00:00 2001 From: Leif Åstrand Date: Tue, 21 May 2013 13:47:20 +0300 Subject: Merge "event not reported as target when context clicking in month view" to Vaadin 7.1 (#10217) Originally fixed as #10189. Change-Id: I0fe6fbb2452bcdb75fed4ea9ef92ea7b739cbb22 --- .../client/ui/calendar/CalendarConnector.java | 12 +++++++++++- .../ui/calendar/schedule/MonthEventLabel.java | 22 ++++++++++++++++++++++ .../client/ui/calendar/schedule/SimpleDayCell.java | 1 + 3 files changed, 34 insertions(+), 1 deletion(-) diff --git a/client/src/com/vaadin/client/ui/calendar/CalendarConnector.java b/client/src/com/vaadin/client/ui/calendar/CalendarConnector.java index 285d15792b..be3abb39ea 100644 --- a/client/src/com/vaadin/client/ui/calendar/CalendarConnector.java +++ b/client/src/com/vaadin/client/ui/calendar/CalendarConnector.java @@ -57,6 +57,7 @@ import com.vaadin.client.ui.calendar.schedule.DateCell.DateCellSlot; import com.vaadin.client.ui.calendar.schedule.DateCellDayEvent; import com.vaadin.client.ui.calendar.schedule.DateUtil; import com.vaadin.client.ui.calendar.schedule.HasTooltipKey; +import com.vaadin.client.ui.calendar.schedule.MonthEventLabel; import com.vaadin.client.ui.calendar.schedule.SimpleDayCell; import com.vaadin.client.ui.calendar.schedule.dd.CalendarDropHandler; import com.vaadin.client.ui.dd.VHasDropHandler; @@ -287,7 +288,16 @@ public class CalendarConnector extends AbstractComponentConnector implements ((VCalendarAction) action).setEvent(event); } return actions; - + } else if (widget instanceof MonthEventLabel) { + MonthEventLabel mel = (MonthEventLabel) widget; + CalendarEvent event = mel.getCalendarEvent(); + Action[] actions = CalendarConnector.this + .getActionsBetween(event.getStartTime(), + event.getEndTime()); + for (Action action : actions) { + ((VCalendarAction) action).setEvent(event); + } + return actions; } return null; } 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 b7f6ee7a3c..928ff85f18 100644 --- a/client/src/com/vaadin/client/ui/calendar/schedule/MonthEventLabel.java +++ b/client/src/com/vaadin/client/ui/calendar/schedule/MonthEventLabel.java @@ -17,6 +17,8 @@ package com.vaadin.client.ui.calendar.schedule; 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.ui.VCalendar; @@ -35,11 +37,27 @@ public class MonthEventLabel extends HTML implements HasTooltipKey { private String caption; private Date time; + private CalendarEvent calendarEvent; + /** * Default constructor */ public MonthEventLabel() { setStylePrimaryName(STYLENAME); + + addDomHandler(new ContextMenuHandler() { + @Override + public void onContextMenu(ContextMenuEvent event) { + calendar.getMouseEventListener().contextMenu(event, + MonthEventLabel.this); + event.stopPropagation(); + event.preventDefault(); + } + }, ContextMenuEvent.getType()); + } + + public void setCalendarEvent(CalendarEvent e) { + calendarEvent = e; } /** @@ -139,4 +157,8 @@ public class MonthEventLabel extends HTML implements HasTooltipKey { public Object getTooltipKey() { return eventIndex; } + + public CalendarEvent getCalendarEvent() { + return calendarEvent; + } } \ No newline at end of file diff --git a/client/src/com/vaadin/client/ui/calendar/schedule/SimpleDayCell.java b/client/src/com/vaadin/client/ui/calendar/schedule/SimpleDayCell.java index a2bd008d01..cf8006ef66 100644 --- a/client/src/com/vaadin/client/ui/calendar/schedule/SimpleDayCell.java +++ b/client/src/com/vaadin/client/ui/calendar/schedule/SimpleDayCell.java @@ -264,6 +264,7 @@ public class SimpleDayCell extends FocusableFlowPanel implements eventDiv.addMouseUpHandler(this); eventDiv.setCalendar(calendar); eventDiv.setEventIndex(e.getIndex()); + eventDiv.setCalendarEvent(e); if (timeEvent) { eventDiv.setTimeSpecificEvent(true); -- cgit v1.2.3 From 51c9fb5322c450ab51de728a735cc6ad6975ca00 Mon Sep 17 00:00:00 2001 From: Johannes Dahlström Date: Tue, 28 May 2013 15:31:30 +0300 Subject: Fix debug window SEVERE style, add styles for FINE, FINER and FINEST (#11891) Change-Id: Ibbe209a6a67e594318a7ac50f962c48aeab4730d --- WebContent/VAADIN/themes/base/debug/debug.scss | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/WebContent/VAADIN/themes/base/debug/debug.scss b/WebContent/VAADIN/themes/base/debug/debug.scss index 687370270e..209c3e0469 100644 --- a/WebContent/VAADIN/themes/base/debug/debug.scss +++ b/WebContent/VAADIN/themes/base/debug/debug.scss @@ -207,13 +207,22 @@ .v-debugwindow-row:nth-child(odd) { background-color: rgba(0, 61, 255, 0.11); } - .v-debugwindow-row.ERROR { + .v-debugwindow-row.SEVERE { color: #550000; background-color: #FFC5C5; } .v-debugwindow-row.WARNING { background-color: #FFFF99; } + .v-debugwindow-row.FINE { + color: lighten($maincolor, 5%); + } + .v-debugwindow-row.FINER { + color: lighten($maincolor, 10%); + } + .v-debugwindow-row.FINEST { + color: lighten($maincolor, 15%); + } .v-debugwindow-row > span { display: table-cell; -- cgit v1.2.3 From 3b888fe28b22de289ac658e9d36073d751705c70 Mon Sep 17 00:00:00 2001 From: Henri Sara Date: Thu, 23 May 2013 12:42:14 +0300 Subject: Support nested SASS imports (#11909) Change-Id: I05f88e398e7e28f476d8c0d50b7f9ac54a7cba0b --- .../com/vaadin/sass/internal/parser/Parser.java | 16 ++++++++---- .../src/com/vaadin/sass/internal/parser/Parser.jj | 6 +++-- .../com/vaadin/sass/internal/tree/ImportNode.java | 5 ++-- .../sass/internal/visitor/ImportNodeHandler.java | 29 +++++++++++++++++++--- .../resources/automatic/css/nested-import.css | 5 ++++ .../resources/automatic/scss/nested-import.scss | 3 +++ 6 files changed, 51 insertions(+), 13 deletions(-) create mode 100644 theme-compiler/tests/resources/automatic/css/nested-import.css create mode 100644 theme-compiler/tests/resources/automatic/scss/nested-import.scss diff --git a/theme-compiler/src/com/vaadin/sass/internal/parser/Parser.java b/theme-compiler/src/com/vaadin/sass/internal/parser/Parser.java index d938dfefe8..382e8e6711 100755 --- a/theme-compiler/src/com/vaadin/sass/internal/parser/Parser.java +++ b/theme-compiler/src/com/vaadin/sass/internal/parser/Parser.java @@ -136,6 +136,7 @@ public class Parser implements org.w3c.css.sac.Parser, ParserConstants { * @exception IOException the source can't be parsed. * @exception CSSException the source is not CSS valid. */ + // TODO required by original parser but not used by Vaadin? public void parseRule(InputSource source) throws CSSException, IOException { this.source = source; @@ -1870,6 +1871,7 @@ char connector = ' '; case IDENT: case VARIABLE: case HASH: + case IMPORT_SYM: case MEDIA_SYM: case KEY_FRAME_SYM: ; @@ -1907,6 +1909,9 @@ char connector = ' '; case MICROSOFT_RULE: microsoftExtension(); break; + case IMPORT_SYM: + importDeclaration(); + break; default: jj_la1[69] = jj_gen; jj_consume_token(-1); @@ -6080,6 +6085,7 @@ LexicalUnitImpl result = null; * The following functions are useful for a DOM CSS implementation only and are * not part of the general CSS2 parser. */ +// TODO required by original parser but not used by Vaadin? final public void _parseRule() throws ParseException { String ret = null; label_168: @@ -7364,13 +7370,13 @@ LexicalUnitImpl result = null; return false; } - private boolean jj_3R_261() { - if (jj_scan_token(INTERPOLATION)) return true; + private boolean jj_3_9() { + if (jj_3R_184()) return true; return false; } - private boolean jj_3_9() { - if (jj_3R_184()) return true; + private boolean jj_3R_261() { + if (jj_scan_token(INTERPOLATION)) return true; return false; } @@ -7529,7 +7535,7 @@ LexicalUnitImpl result = null; jj_la1_2 = new int[] {0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x401,0x4000,0x0,0x0,0x0,0x0,0x2200,0x0,0x0,0x0,0x400,0x400,0x0,0x0,0x8000,0x0,0x8000,0x0,0x0,0x4465,0x4465,0x0,0x0,0x0,0xae00,0xae00,0x0,0x0,0x0,0x400,0x0,0x0,0x400,0x0,0x0,0x400,0x0,0x0,0x0,0x0,0x400,0x0,0x0,0x400,0x0,0xaa00,0x0,0x0,0x0,0x0,0x0,0xe00,0xe00,0x0,0x400,0x400,0x0,0x0,0x0,0x0,0x4465,0x4465,0x0,0x0,0x0,0x400,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x400,0x400,0x400,0x400,0x400,0x400,0x0,0x0,0x0,0x0,0x600,0x0,0x0,0x0,0x0,0x400,0x0,0x100,0x0,0x0,0x1,0x424,0x4000,0x4c00,0x0,0x4424,0x0,0x2,0x0,0x4c00,0x80,0x0,0x4424,0x0,0x4c00,0x0,0x0,0x0,0x4400,0x0,0x4424,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x400,0x0,0x4425,0x4425,0x0,0x0,0x0,0x0,0x0,0x0,0x4000,0x4000,0xffffee00,0x0,0x0,0x0,0x0,0xffffee00,0x0,0x0,0x0,0x4400,0x0,0x0,0x0,0x400,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x4000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x400,0x0,0x0,0x400,0x0,0x0,0x400,0x0,0x0,0x0,0x400,0x0,0x0,0x400,0x0,0xffffee00,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xffffee00,0x0,0xffff8800,0x0,0x400,0x2600,0xffffae00,0x0,0x0,0xffffee00,0x0,0x400,0x0,0x0,0x0,0x400,0x0,0x0,0x400,0x0,}; } private static void jj_la1_init_3() { - jj_la1_3 = new int[] {0x20,0x200,0x200,0x8,0x200,0x0,0x0,0x0,0x1d4,0x0,0x200,0x0,0x200,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x114,0x114,0x0,0x0,0x0,0x31006fc,0x31006fc,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x31006f8,0x0,0x0,0x0,0x0,0x0,0x1000000,0x1000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x114,0x114,0x0,0x0,0x0,0x4,0x0,0x4,0x4,0x0,0x0,0x4,0x4,0x4,0x4,0x4,0x4,0x4,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1000000,0x0,0x0,0x0,0x0,0x0,0x114,0x0,0x800000,0x0,0x114,0x0,0x0,0x0,0x800000,0x0,0x0,0x114,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x114,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1000000,0x0,0x1d4,0x1d4,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1100007,0x0,0x0,0x0,0x0,0x1100007,0x0,0x0,0x0,0x1000000,0x0,0x0,0x0,0x4,0x0,0x0,0x0,0x0,0xe00000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x4,0x0,0x400,0x0,0x0,0x0,0x0,0x0,0x0,0x1100007,0x0,0x400,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1100007,0x0,0x1000003,0x0,0x0,0x100004,0x1100007,0x0,0x0,0x1100007,0x0,0xdc,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,}; + jj_la1_3 = new int[] {0x20,0x200,0x200,0x8,0x200,0x0,0x0,0x0,0x1d4,0x0,0x200,0x0,0x200,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x114,0x114,0x0,0x0,0x0,0x31006fc,0x31006fc,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x31006f8,0x0,0x0,0x0,0x0,0x0,0x1000000,0x1000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x11c,0x11c,0x0,0x0,0x0,0x4,0x0,0x4,0x4,0x0,0x0,0x4,0x4,0x4,0x4,0x4,0x4,0x4,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1000000,0x0,0x0,0x0,0x0,0x0,0x114,0x0,0x800000,0x0,0x114,0x0,0x0,0x0,0x800000,0x0,0x0,0x114,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x114,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1000000,0x0,0x1d4,0x1d4,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1100007,0x0,0x0,0x0,0x0,0x1100007,0x0,0x0,0x0,0x1000000,0x0,0x0,0x0,0x4,0x0,0x0,0x0,0x0,0xe00000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x4,0x0,0x400,0x0,0x0,0x0,0x0,0x0,0x0,0x1100007,0x0,0x400,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1100007,0x0,0x1000003,0x0,0x0,0x100004,0x1100007,0x0,0x0,0x1100007,0x0,0xdc,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,}; } final private JJCalls[] jj_2_rtns = new JJCalls[9]; private boolean jj_rescan = false; diff --git a/theme-compiler/src/com/vaadin/sass/internal/parser/Parser.jj b/theme-compiler/src/com/vaadin/sass/internal/parser/Parser.jj index 7f86527015..daf20423d6 100644 --- a/theme-compiler/src/com/vaadin/sass/internal/parser/Parser.jj +++ b/theme-compiler/src/com/vaadin/sass/internal/parser/Parser.jj @@ -169,6 +169,7 @@ public class Parser implements org.w3c.css.sac.Parser { * @exception IOException the source can't be parsed. * @exception CSSException the source is not CSS valid. */ + // TODO required by original parser but not used by Vaadin? public void parseRule(InputSource source) throws CSSException, IOException { this.source = source; @@ -1188,7 +1189,8 @@ void styleRule() : start = true; documentHandler.startSelector(l); } - ( ifContentStatement() | controlDirective() | microsoftExtension() )* + // a CSS import here will not work + ( ifContentStatement() | controlDirective() | microsoftExtension() | importDeclaration() )* ()* } catch (ThrowedParseException e) { if (errorHandler != null) { @@ -2947,7 +2949,7 @@ String skipAfterExpression() { * The following functions are useful for a DOM CSS implementation only and are * not part of the general CSS2 parser. */ - +// TODO required by original parser but not used by Vaadin? void _parseRule() : {String ret = null; } diff --git a/theme-compiler/src/com/vaadin/sass/internal/tree/ImportNode.java b/theme-compiler/src/com/vaadin/sass/internal/tree/ImportNode.java index f7d664d54d..6dc95db5c2 100644 --- a/theme-compiler/src/com/vaadin/sass/internal/tree/ImportNode.java +++ b/theme-compiler/src/com/vaadin/sass/internal/tree/ImportNode.java @@ -18,7 +18,6 @@ package com.vaadin.sass.internal.tree; import org.w3c.css.sac.SACMediaList; -import com.vaadin.sass.internal.ScssStylesheet; import com.vaadin.sass.internal.visitor.ImportNodeHandler; public class ImportNode extends Node { @@ -74,7 +73,7 @@ public class ImportNode extends Node { @Override public void traverse() { - // TODO shouldn't be reached with current setup, try anyway? - ImportNodeHandler.traverse((ScssStylesheet) getParentNode()); + // nested imports + ImportNodeHandler.traverse(getParentNode()); } } diff --git a/theme-compiler/src/com/vaadin/sass/internal/visitor/ImportNodeHandler.java b/theme-compiler/src/com/vaadin/sass/internal/visitor/ImportNodeHandler.java index e356ed3525..cb9896967a 100644 --- a/theme-compiler/src/com/vaadin/sass/internal/visitor/ImportNodeHandler.java +++ b/theme-compiler/src/com/vaadin/sass/internal/visitor/ImportNodeHandler.java @@ -26,6 +26,7 @@ import org.w3c.css.sac.LexicalUnit; import com.vaadin.sass.internal.ScssStylesheet; import com.vaadin.sass.internal.parser.LexicalUnitImpl; +import com.vaadin.sass.internal.parser.ParseException; import com.vaadin.sass.internal.tree.ImportNode; import com.vaadin.sass.internal.tree.Node; import com.vaadin.sass.internal.tree.RuleNode; @@ -33,7 +34,23 @@ import com.vaadin.sass.internal.util.StringUtil; public class ImportNodeHandler { - public static void traverse(ScssStylesheet node) { + public static void traverse(Node node) { + ScssStylesheet styleSheet = null; + if (node instanceof ScssStylesheet) { + styleSheet = (ScssStylesheet) node; + } else { + // iterate to parents of node, find ScssStylesheet + Node parent = node.getParentNode(); + while (parent != null && !(parent instanceof ScssStylesheet)) { + parent = parent.getParentNode(); + } + if (parent instanceof ScssStylesheet) { + styleSheet = (ScssStylesheet) parent; + } + } + if (styleSheet == null) { + throw new ParseException("Nested import in an invalid context"); + } ArrayList c = new ArrayList(node.getChildren()); for (Node n : c) { if (n instanceof ImportNode) { @@ -41,7 +58,7 @@ public class ImportNodeHandler { if (!importNode.isPureCssImport()) { try { StringBuilder filePathBuilder = new StringBuilder( - node.getFileName()); + styleSheet.getFileName()); filePathBuilder.append(File.separatorChar).append( importNode.getUri()); if (!filePathBuilder.toString().endsWith(".scss")) { @@ -50,7 +67,8 @@ public class ImportNodeHandler { // set parent's charset to imported node. ScssStylesheet imported = ScssStylesheet.get( - filePathBuilder.toString(), node.getCharset()); + filePathBuilder.toString(), + styleSheet.getCharset()); if (imported == null) { imported = ScssStylesheet.get(importNode.getUri()); } @@ -76,6 +94,11 @@ public class ImportNodeHandler { } catch (IOException e) { e.printStackTrace(); } + } else { + if (styleSheet != node) { + throw new ParseException( + "CSS imports can only be used at the top level, not as nested imports. Within style rules, use SCSS imports."); + } } } } diff --git a/theme-compiler/tests/resources/automatic/css/nested-import.css b/theme-compiler/tests/resources/automatic/css/nested-import.css new file mode 100644 index 0000000000..7c6793f9ed --- /dev/null +++ b/theme-compiler/tests/resources/automatic/css/nested-import.css @@ -0,0 +1,5 @@ +.foo .bar { + background: url(foo/lorem.png); + background: url(foo/lorem.png); + background: url(foo/lorem.png); +} \ No newline at end of file diff --git a/theme-compiler/tests/resources/automatic/scss/nested-import.scss b/theme-compiler/tests/resources/automatic/scss/nested-import.scss new file mode 100644 index 0000000000..605d64a13a --- /dev/null +++ b/theme-compiler/tests/resources/automatic/scss/nested-import.scss @@ -0,0 +1,3 @@ +.foo { + @import "foo/bar.scss"; +} \ No newline at end of file -- cgit v1.2.3 From b2137f5d4bd00e11142f31f542b0f8d6ea98f518 Mon Sep 17 00:00:00 2001 From: Artur Signell Date: Tue, 28 May 2013 17:55:44 +0300 Subject: Ensure calendar panel is updated when range changes (#11940) Change-Id: Ic270e5c0aa1b28947b735fcb258bc9629d53cc21 --- .../src/com/vaadin/client/ui/VCalendarPanel.java | 11 +- .../datefield/DynamicallyChangeDateRange.html | 121 +++++++++++++++++++++ .../datefield/DynamicallyChangeDateRange.java | 91 ++++++++++++++++ 3 files changed, 222 insertions(+), 1 deletion(-) create mode 100644 uitest/src/com/vaadin/tests/components/datefield/DynamicallyChangeDateRange.html create mode 100644 uitest/src/com/vaadin/tests/components/datefield/DynamicallyChangeDateRange.java diff --git a/client/src/com/vaadin/client/ui/VCalendarPanel.java b/client/src/com/vaadin/client/ui/VCalendarPanel.java index 311932b819..1f40298760 100644 --- a/client/src/com/vaadin/client/ui/VCalendarPanel.java +++ b/client/src/com/vaadin/client/ui/VCalendarPanel.java @@ -2216,6 +2216,11 @@ public class VCalendarPanel extends FocusableFlexTable implements */ public void setRangeStart(Date rangeStart) { this.rangeStart = rangeStart; + if (initialRenderDone) { + // Dynamic updates to the range needs to render the calendar to + // update the element stylenames + renderCalendar(); + } } @@ -2228,6 +2233,10 @@ public class VCalendarPanel extends FocusableFlexTable implements */ public void setRangeEnd(Date rangeEnd) { this.rangeEnd = rangeEnd; - + if (initialRenderDone) { + // Dynamic updates to the range needs to render the calendar to + // update the element stylenames + renderCalendar(); + } } } diff --git a/uitest/src/com/vaadin/tests/components/datefield/DynamicallyChangeDateRange.html b/uitest/src/com/vaadin/tests/components/datefield/DynamicallyChangeDateRange.html new file mode 100644 index 0000000000..77c610f211 --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/datefield/DynamicallyChangeDateRange.html @@ -0,0 +1,121 @@ + + + + + + +New Test + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
New Test
open/run/com.vaadin.tests.components.datefield.DynamicallyChangeDateRange?restartApplication
mouseClickvaadin=runcomvaadintestscomponentsdatefieldDynamicallyChangeDateRange::/VVerticalLayout[0]/Slot[0]/VPopupCalendar[0]#popupButton11,8
assertCSSClass//table[@id='PID_VAADIN_POPUPCAL']/tbody/tr[2]/td/table/tbody/tr[3]/td[2]/spanv-datefield-calendarpanel-day-outside-range
assertNotCSSClass//table[@id='PID_VAADIN_POPUPCAL']/tbody/tr[2]/td/table/tbody/tr[3]/td[3]/spanv-datefield-calendarpanel-day-outside-range
assertNotCSSClass//table[@id='PID_VAADIN_POPUPCAL']/tbody/tr[2]/td/table/tbody/tr[4]/td[6]/spanv-datefield-calendarpanel-day-outside-range
assertCSSClass//table[@id='PID_VAADIN_POPUPCAL']/tbody/tr[2]/td/table/tbody/tr[4]/td[7]/spanv-datefield-calendarpanel-day-outside-range
mouseClickvaadin=runcomvaadintestscomponentsdatefieldDynamicallyChangeDateRange::201,401
clickvaadin=runcomvaadintestscomponentsdatefieldDynamicallyChangeDateRange::/VVerticalLayout[0]/Slot[2]/VButton[0]/domChild[0]/domChild[0]
mouseClickvaadin=runcomvaadintestscomponentsdatefieldDynamicallyChangeDateRange::/VVerticalLayout[0]/Slot[0]/VPopupCalendar[0]#popupButton14,16
assertCSSClass//table[@id='PID_VAADIN_POPUPCAL']/tbody/tr[2]/td/table/tbody/tr[2]/td[4]/spanv-datefield-calendarpanel-day-outside-range
assertNotCSSClass//table[@id='PID_VAADIN_POPUPCAL']/tbody/tr[2]/td/table/tbody/tr[2]/td[5]/spanv-datefield-calendarpanel-day-outside-range
assertNotCSSClass//table[@id='PID_VAADIN_POPUPCAL']/tbody/tr[2]/td/table/tbody/tr[5]/td[4]/spanv-datefield-calendarpanel-day-outside-range
assertCSSClass//table[@id='PID_VAADIN_POPUPCAL']/tbody/tr[2]/td/table/tbody/tr[5]/td[5]/spanv-datefield-calendarpanel-day-outside-range
mouseClickvaadin=runcomvaadintestscomponentsdatefieldDynamicallyChangeDateRange::237,338
clickvaadin=runcomvaadintestscomponentsdatefieldDynamicallyChangeDateRange::/VVerticalLayout[0]/Slot[1]/VButton[0]/domChild[0]/domChild[0]
mouseClickvaadin=runcomvaadintestscomponentsdatefieldDynamicallyChangeDateRange::/VVerticalLayout[0]/Slot[0]/VPopupCalendar[0]#popupButton14,15
assertCSSClass//table[@id='PID_VAADIN_POPUPCAL']/tbody/tr[2]/td/table/tbody/tr[3]/td[2]/spanv-datefield-calendarpanel-day-outside-range
assertNotCSSClass//table[@id='PID_VAADIN_POPUPCAL']/tbody/tr[2]/td/table/tbody/tr[3]/td[3]/spanv-datefield-calendarpanel-day-outside-range
assertNotCSSClass//table[@id='PID_VAADIN_POPUPCAL']/tbody/tr[2]/td/table/tbody/tr[4]/td[6]/spanv-datefield-calendarpanel-day-outside-range
assertCSSClass//table[@id='PID_VAADIN_POPUPCAL']/tbody/tr[2]/td/table/tbody/tr[4]/td[7]/spanv-datefield-calendarpanel-day-outside-range
assertCSSClass//table[@id='PID_VAADIN_POPUPCAL']/tbody/tr[2]/td/table/tbody/tr[3]/td[2]/spanv-datefield-calendarpanel-day-outside-range
+ + diff --git a/uitest/src/com/vaadin/tests/components/datefield/DynamicallyChangeDateRange.java b/uitest/src/com/vaadin/tests/components/datefield/DynamicallyChangeDateRange.java new file mode 100644 index 0000000000..9288b0428e --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/datefield/DynamicallyChangeDateRange.java @@ -0,0 +1,91 @@ +package com.vaadin.tests.components.datefield; + +import java.util.Date; + +import com.vaadin.server.VaadinRequest; +import com.vaadin.tests.components.AbstractTestUI; +import com.vaadin.ui.Button; +import com.vaadin.ui.Button.ClickEvent; +import com.vaadin.ui.DateField; +import com.vaadin.ui.InlineDateField; +import com.vaadin.ui.PopupDateField; +import com.vaadin.ui.VerticalLayout; + +/** + * Main UI class + */ +@SuppressWarnings("serial") +public class DynamicallyChangeDateRange extends AbstractTestUI { + + @Override + protected void setup(VaadinRequest request) { + final VerticalLayout layout = new VerticalLayout(); + layout.setMargin(true); + setContent(layout); + + final PopupDateField df = new PopupDateField(); + df.setValue(new Date(2012 - 1900, 5 - 1, 12)); + setRange(df, 5); + layout.addComponent(df); + + final InlineDateField df2 = new InlineDateField(); + df2.setValue(new Date(2012 - 1900, 11 - 1, 16)); + + setRange(df2, 5); + // layout.addComponent(df2); + + Button button1 = new Button("Set Range Now+/-5d"); + button1.addClickListener(new Button.ClickListener() { + @Override + public void buttonClick(ClickEvent event) { + setRange(df, 5); + setRange(df2, 5); + } + }); + layout.addComponent(button1); + + Button button2 = new Button("Set Range Now+/-10d"); + button2.addClickListener(new Button.ClickListener() { + @Override + public void buttonClick(ClickEvent event) { + setRange(df, 10); + setRange(df2, 10); + } + }); + layout.addComponent(button2); + } + + /** + * @since + * @param df + * @param i + */ + private void setRange(DateField df, int days) { + df.setRangeStart(new Date(df.getValue().getTime() - days * 24 * 60 * 60 + * 1000)); + df.setRangeEnd(new Date(df.getValue().getTime() + days * 24 * 60 * 60 + * 1000)); + + } + + /* + * (non-Javadoc) + * + * @see com.vaadin.tests.components.AbstractTestUI#getTestDescription() + */ + @Override + protected String getTestDescription() { + return "Verifies that the allowed date range can be updated dynamically"; + } + + /* + * (non-Javadoc) + * + * @see com.vaadin.tests.components.AbstractTestUI#getTicketNumber() + */ + @Override + protected Integer getTicketNumber() { + return 11940; + } + +} \ No newline at end of file -- cgit v1.2.3 From f8319ebede962a9c89e192ab0496ba67fe2e4575 Mon Sep 17 00:00:00 2001 From: Leif Åstrand Date: Tue, 28 May 2013 16:52:10 +0300 Subject: Avoid deadlock checking in runPendingAccessTasks() (#11897) The deadlock check in accessSynchronously() was triggered in cases where one session was locked and tryLock() in access() did manage to lock another session and thus attempted to run the runnable right away. runPendingAccessTasks() needed accessSynchronously() just for setting up the current session instance - the session was already locked and cleaning up the CurrentInstance values afterwards was not needed. Just setting the current session without accessSynchronously() gets rid of the inappropriate deadlock detection as well as some overhead with managing locks and CurrentInstance values. Change-Id: Ib956d68884d6703dce2633a455c4857bb06651af --- server/src/com/vaadin/server/VaadinSession.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/server/src/com/vaadin/server/VaadinSession.java b/server/src/com/vaadin/server/VaadinSession.java index 9939ad709e..551031b947 100644 --- a/server/src/com/vaadin/server/VaadinSession.java +++ b/server/src/com/vaadin/server/VaadinSession.java @@ -1263,7 +1263,8 @@ public class VaadinSession implements HttpSessionBindingListener, Serializable { if (!pendingAccess.isCancelled()) { CurrentInstance.clearAll(); CurrentInstance.restoreInstances(pendingAccess.instances); - accessSynchronously(pendingAccess); + CurrentInstance.setCurrent(this); + pendingAccess.run(); } } } finally { -- cgit v1.2.3 From 51a98a3d3cad3af06366e219b36acf1fd063c986 Mon Sep 17 00:00:00 2001 From: Artur Signell Date: Tue, 28 May 2013 18:51:41 +0300 Subject: Moved enums to avoid running them as tests Change-Id: I52cbd9582345a3c0d49caf2ad265a659bf3fe0f1 --- .../src/com/vaadin/tests/data/bean/AnotherTestEnum.java | 16 ++++++++++++++++ .../tests/src/com/vaadin/tests/data/bean/TestEnum.java | 16 ++++++++++++++++ .../com/vaadin/tests/data/converter/AnotherTestEnum.java | 16 ---------------- .../data/converter/TestAnyEnumToStringConverter.java | 2 ++ .../src/com/vaadin/tests/data/converter/TestEnum.java | 16 ---------------- .../converter/TestSpecificEnumToStringConverter.java | 2 ++ 6 files changed, 36 insertions(+), 32 deletions(-) create mode 100644 server/tests/src/com/vaadin/tests/data/bean/AnotherTestEnum.java create mode 100644 server/tests/src/com/vaadin/tests/data/bean/TestEnum.java delete mode 100644 server/tests/src/com/vaadin/tests/data/converter/AnotherTestEnum.java delete mode 100644 server/tests/src/com/vaadin/tests/data/converter/TestEnum.java diff --git a/server/tests/src/com/vaadin/tests/data/bean/AnotherTestEnum.java b/server/tests/src/com/vaadin/tests/data/bean/AnotherTestEnum.java new file mode 100644 index 0000000000..fc8f22a947 --- /dev/null +++ b/server/tests/src/com/vaadin/tests/data/bean/AnotherTestEnum.java @@ -0,0 +1,16 @@ +package com.vaadin.tests.data.bean; + +public enum AnotherTestEnum { + ONE("ONE"), TWO("TWO"); + + private String id; + + private AnotherTestEnum(String id) { + this.id = id; + } + + @Override + public String toString() { + return id; + } +} diff --git a/server/tests/src/com/vaadin/tests/data/bean/TestEnum.java b/server/tests/src/com/vaadin/tests/data/bean/TestEnum.java new file mode 100644 index 0000000000..bf6f721052 --- /dev/null +++ b/server/tests/src/com/vaadin/tests/data/bean/TestEnum.java @@ -0,0 +1,16 @@ +package com.vaadin.tests.data.bean; + +public enum TestEnum { + ONE("1"), TWO("2"); + + private String id; + + private TestEnum(String id) { + this.id = id; + } + + @Override + public String toString() { + return id; + } +} diff --git a/server/tests/src/com/vaadin/tests/data/converter/AnotherTestEnum.java b/server/tests/src/com/vaadin/tests/data/converter/AnotherTestEnum.java deleted file mode 100644 index 33a6a87359..0000000000 --- a/server/tests/src/com/vaadin/tests/data/converter/AnotherTestEnum.java +++ /dev/null @@ -1,16 +0,0 @@ -package com.vaadin.tests.data.converter; - -public enum AnotherTestEnum { - ONE("ONE"), TWO("TWO"); - - private String id; - - private AnotherTestEnum(String id) { - this.id = id; - } - - @Override - public String toString() { - return id; - } -} diff --git a/server/tests/src/com/vaadin/tests/data/converter/TestAnyEnumToStringConverter.java b/server/tests/src/com/vaadin/tests/data/converter/TestAnyEnumToStringConverter.java index baa81ce656..c267e012e8 100644 --- a/server/tests/src/com/vaadin/tests/data/converter/TestAnyEnumToStringConverter.java +++ b/server/tests/src/com/vaadin/tests/data/converter/TestAnyEnumToStringConverter.java @@ -25,6 +25,8 @@ import org.junit.Test; import com.vaadin.data.util.ObjectProperty; import com.vaadin.data.util.converter.Converter; import com.vaadin.data.util.converter.ReverseConverter; +import com.vaadin.tests.data.bean.AnotherTestEnum; +import com.vaadin.tests.data.bean.TestEnum; import com.vaadin.ui.TextField; public class TestAnyEnumToStringConverter { diff --git a/server/tests/src/com/vaadin/tests/data/converter/TestEnum.java b/server/tests/src/com/vaadin/tests/data/converter/TestEnum.java deleted file mode 100644 index a4b709a843..0000000000 --- a/server/tests/src/com/vaadin/tests/data/converter/TestEnum.java +++ /dev/null @@ -1,16 +0,0 @@ -package com.vaadin.tests.data.converter; - -public enum TestEnum { - ONE("1"), TWO("2"); - - private String id; - - private TestEnum(String id) { - this.id = id; - } - - @Override - public String toString() { - return id; - } -} diff --git a/server/tests/src/com/vaadin/tests/data/converter/TestSpecificEnumToStringConverter.java b/server/tests/src/com/vaadin/tests/data/converter/TestSpecificEnumToStringConverter.java index ef8c57f7f1..93dbe96b56 100644 --- a/server/tests/src/com/vaadin/tests/data/converter/TestSpecificEnumToStringConverter.java +++ b/server/tests/src/com/vaadin/tests/data/converter/TestSpecificEnumToStringConverter.java @@ -25,6 +25,8 @@ import org.junit.Test; import com.vaadin.data.util.ObjectProperty; import com.vaadin.data.util.converter.Converter; import com.vaadin.data.util.converter.ReverseConverter; +import com.vaadin.tests.data.bean.AnotherTestEnum; +import com.vaadin.tests.data.bean.TestEnum; import com.vaadin.ui.TextField; public class TestSpecificEnumToStringConverter { -- cgit v1.2.3 From 7c613d107e8318799521a1243b5e480a0c21e2d9 Mon Sep 17 00:00:00 2001 From: Artur Signell Date: Mon, 27 May 2013 20:35:20 +0300 Subject: Exclude parsers from checkstyle as they are generated Change-Id: I91489d73bec165b5e755b5d76bf220043bee0d66 --- common.xml | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/common.xml b/common.xml index d673273a53..c0c5ca5eb5 100644 --- a/common.xml +++ b/common.xml @@ -69,7 +69,7 @@ - + @@ -391,12 +391,16 @@ - + ##teamcity[importData type='checkstyle' path='${result.dir.full}/checkstyle-errors.xml'] - - + + + + + + -- cgit v1.2.3 From 35f353274f2132086f8ee0bb6e6e73712a59b173 Mon Sep 17 00:00:00 2001 From: John Ahlroos Date: Tue, 28 May 2013 12:39:20 +0300 Subject: Fixes current text being overwritten in server update on RTA #11741 If the server happens to update the state of the RTA while a user is typing then the users text will be replaced by the value on the server. To fix this the RTA should not update if the value is the same as the one cached on the client side. Also moves blur handling and server<->client syncronization to the connector. Change-Id: Ia807b1e2aa210eb881e4b9cea0870c0c5a9254b2 --- client/src/com/vaadin/client/ui/VPopupView.java | 8 +- client/src/com/vaadin/client/ui/VRichTextArea.java | 165 ++++++++++++--------- .../ui/richtextarea/RichTextAreaConnector.java | 42 ++++-- .../RichTextAreaUpdateWhileTyping.html | 42 ++++++ .../RichTextAreaUpdateWhileTyping.java | 51 +++++++ 5 files changed, 229 insertions(+), 79 deletions(-) create mode 100644 uitest/src/com/vaadin/tests/components/richtextarea/RichTextAreaUpdateWhileTyping.html create mode 100644 uitest/src/com/vaadin/tests/components/richtextarea/RichTextAreaUpdateWhileTyping.java diff --git a/client/src/com/vaadin/client/ui/VPopupView.java b/client/src/com/vaadin/client/ui/VPopupView.java index 05fbd2c073..626780efee 100644 --- a/client/src/com/vaadin/client/ui/VPopupView.java +++ b/client/src/com/vaadin/client/ui/VPopupView.java @@ -40,6 +40,7 @@ import com.google.gwt.user.client.ui.RootPanel; import com.google.gwt.user.client.ui.Widget; import com.vaadin.client.ApplicationConnection; import com.vaadin.client.ComponentConnector; +import com.vaadin.client.Util; import com.vaadin.client.VCaptionWrapper; import com.vaadin.client.VConsole; import com.vaadin.client.ui.ShortcutActionHandler.ShortcutActionHandlerOwner; @@ -313,8 +314,11 @@ public class VPopupView extends HTML implements Iterable { private void checkForRTE(Widget popupComponentWidget2) { if (popupComponentWidget2 instanceof VRichTextArea) { - ((VRichTextArea) popupComponentWidget2) - .synchronizeContentToServer(); + ComponentConnector rtaConnector = Util + .findConnectorFor(popupComponentWidget2); + if (rtaConnector != null) { + rtaConnector.flush(); + } } else if (popupComponentWidget2 instanceof HasWidgets) { HasWidgets hw = (HasWidgets) popupComponentWidget2; Iterator iterator = hw.iterator(); diff --git a/client/src/com/vaadin/client/ui/VRichTextArea.java b/client/src/com/vaadin/client/ui/VRichTextArea.java index 1498c096ed..7ed6e7c78a 100644 --- a/client/src/com/vaadin/client/ui/VRichTextArea.java +++ b/client/src/com/vaadin/client/ui/VRichTextArea.java @@ -16,11 +16,12 @@ package com.vaadin.client.ui; +import java.util.HashMap; +import java.util.Map; +import java.util.Map.Entry; + import com.google.gwt.core.client.Scheduler; -import com.google.gwt.event.dom.client.BlurEvent; import com.google.gwt.event.dom.client.BlurHandler; -import com.google.gwt.event.dom.client.ChangeEvent; -import com.google.gwt.event.dom.client.ChangeHandler; import com.google.gwt.event.dom.client.KeyDownEvent; import com.google.gwt.event.dom.client.KeyDownHandler; import com.google.gwt.event.dom.client.KeyPressEvent; @@ -49,8 +50,8 @@ import com.vaadin.client.ui.richtextarea.VRichTextToolbar; * @author Vaadin Ltd. * */ -public class VRichTextArea extends Composite implements Field, ChangeHandler, - BlurHandler, KeyPressHandler, KeyDownHandler, Focusable { +public class VRichTextArea extends Composite implements Field, KeyPressHandler, + KeyDownHandler, Focusable { /** * The input node CSS classname. @@ -91,11 +92,10 @@ public class VRichTextArea extends Composite implements Field, ChangeHandler, private ShortcutActionHandlerOwner hasShortcutActionHandler; - /** For internal use only. May be removed or replaced in the future. */ - public String currentValue = ""; - private boolean readOnly = false; + private final Map blurHandlers = new HashMap(); + public VRichTextArea() { createRTAComponents(); fp.add(formatter); @@ -110,9 +110,19 @@ public class VRichTextArea extends Composite implements Field, ChangeHandler, private void createRTAComponents() { rta = new RichTextArea(); rta.setWidth("100%"); - rta.addBlurHandler(this); rta.addKeyDownHandler(this); formatter = new VRichTextToolbar(rta); + + // Add blur handlers + for (Entry handler : blurHandlers + .entrySet()) { + + // Remove old registration + handler.getValue().removeHandler(); + + // Add blur handlers + addBlurHandler(handler.getKey()); + } } public void setEnabled(boolean enabled) { @@ -127,6 +137,7 @@ public class VRichTextArea extends Composite implements Field, ChangeHandler, * Swaps html to rta and visa versa. */ private void swapEditableArea() { + String value = getValue(); if (html.isAttached()) { fp.remove(html); if (BrowserInfo.get().isWebkit()) { @@ -134,13 +145,12 @@ public class VRichTextArea extends Composite implements Field, ChangeHandler, createRTAComponents(); // recreate new RTA to bypass #5379 fp.add(formatter); } - rta.setHTML(currentValue); fp.add(rta); } else { - html.setHTML(currentValue); fp.remove(rta); fp.add(html); } + setValue(value); } /** For internal use only. May be removed or replaced in the future. */ @@ -180,62 +190,6 @@ public class VRichTextArea extends Composite implements Field, ChangeHandler, return readOnly; } - // TODO is this really used, or does everything go via onBlur() only? - @Override - public void onChange(ChangeEvent event) { - synchronizeContentToServer(); - } - - /** - * Method is public to let popupview force synchronization on close. - */ - public void synchronizeContentToServer() { - if (client != null && id != null) { - final String html = sanitizeRichTextAreaValue(rta.getHTML()); - if (!html.equals(currentValue)) { - client.updateVariable(id, "text", html, immediate); - currentValue = html; - } - } - } - - /** - * Browsers differ in what they return as the content of a visually empty - * rich text area. This method is used to normalize these to an empty - * string. See #8004. - * - * @param html - * @return cleaned html string - */ - private String sanitizeRichTextAreaValue(String html) { - BrowserInfo browser = BrowserInfo.get(); - String result = html; - if (browser.isFirefox()) { - if ("
".equals(html)) { - result = ""; - } - } else if (browser.isWebkit()) { - if ("

".equals(html)) { - result = ""; - } - } else if (browser.isIE()) { - if ("

 

".equals(html)) { - result = ""; - } - } else if (browser.isOpera()) { - if ("
".equals(html) || "


".equals(html)) { - result = ""; - } - } - return result; - } - - @Override - public void onBlur(BlurEvent event) { - synchronizeContentToServer(); - // TODO notify possible server side blur/focus listeners - } - /** * @return space used by components paddings and borders */ @@ -409,4 +363,81 @@ public class VRichTextArea extends Composite implements Field, ChangeHandler, rta.setTabIndex(index); } + /** + * Set the value of the text area + * + * @param value + * The text value. Can be html. + */ + public void setValue(String value) { + if (rta.isAttached()) { + rta.setHTML(value); + } else { + html.setHTML(value); + } + } + + /** + * Get the value the text area + */ + public String getValue() { + if (rta.isAttached()) { + return rta.getHTML(); + } else { + return html.getHTML(); + } + } + + /** + * Browsers differ in what they return as the content of a visually empty + * rich text area. This method is used to normalize these to an empty + * string. See #8004. + * + * @return cleaned html string + */ + public String getSanitazedValue() { + BrowserInfo browser = BrowserInfo.get(); + String result = getValue(); + if (browser.isFirefox()) { + if ("
".equals(html)) { + result = ""; + } + } else if (browser.isWebkit()) { + if ("

".equals(html)) { + result = ""; + } + } else if (browser.isIE()) { + if ("

 

".equals(html)) { + result = ""; + } + } else if (browser.isOpera()) { + if ("
".equals(html) || "


".equals(html)) { + result = ""; + } + } + return result; + } + + /** + * Adds a blur handler to the component. + * + * @param blurHandler + * the blur handler to add + */ + public void addBlurHandler(BlurHandler blurHandler) { + blurHandlers.put(blurHandler, rta.addBlurHandler(blurHandler)); + } + + /** + * Removes a blur handler. + * + * @param blurHandler + * the handler to remove + */ + public void removeBlurHandler(BlurHandler blurHandler) { + HandlerRegistration registration = blurHandlers.remove(blurHandler); + if (registration != null) { + registration.removeHandler(); + } + } } diff --git a/client/src/com/vaadin/client/ui/richtextarea/RichTextAreaConnector.java b/client/src/com/vaadin/client/ui/richtextarea/RichTextAreaConnector.java index 36182464a3..8135777c0a 100644 --- a/client/src/com/vaadin/client/ui/richtextarea/RichTextAreaConnector.java +++ b/client/src/com/vaadin/client/ui/richtextarea/RichTextAreaConnector.java @@ -15,6 +15,8 @@ */ package com.vaadin.client.ui.richtextarea; +import com.google.gwt.event.dom.client.BlurEvent; +import com.google.gwt.event.dom.client.BlurHandler; import com.google.gwt.user.client.Event; import com.vaadin.client.ApplicationConnection; import com.vaadin.client.Paintable; @@ -24,33 +26,47 @@ import com.vaadin.client.ui.ShortcutActionHandler.BeforeShortcutActionListener; import com.vaadin.client.ui.VRichTextArea; import com.vaadin.shared.ui.Connect; import com.vaadin.shared.ui.Connect.LoadStyle; +import com.vaadin.shared.util.SharedUtil; import com.vaadin.ui.RichTextArea; @Connect(value = RichTextArea.class, loadStyle = LoadStyle.LAZY) public class RichTextAreaConnector extends AbstractFieldConnector implements Paintable, BeforeShortcutActionListener { + /* + * Last value received from the server + */ + private String cachedValue = ""; + + @Override + protected void init() { + getWidget().addBlurHandler(new BlurHandler() { + + @Override + public void onBlur(BlurEvent event) { + flush(); + } + }); + } + @Override public void updateFromUIDL(final UIDL uidl, ApplicationConnection client) { getWidget().client = client; getWidget().id = uidl.getId(); if (uidl.hasVariable("text")) { - getWidget().currentValue = uidl.getStringVariable("text"); - if (getWidget().rta.isAttached()) { - getWidget().rta.setHTML(getWidget().currentValue); - } else { - getWidget().html.setHTML(getWidget().currentValue); + String newValue = uidl.getStringVariable("text"); + if (!SharedUtil.equals(newValue, cachedValue)) { + getWidget().setValue(newValue); + cachedValue = newValue; } } - if (isRealUpdate(uidl)) { - getWidget().setEnabled(isEnabled()); - } if (!isRealUpdate(uidl)) { return; } + getWidget().setEnabled(isEnabled()); getWidget().setReadOnly(isReadOnly()); getWidget().immediate = getState().immediate; int newMaxLength = uidl.hasAttribute("maxLength") ? uidl @@ -85,7 +101,13 @@ public class RichTextAreaConnector extends AbstractFieldConnector implements @Override public void flush() { - getWidget().synchronizeContentToServer(); + if (getConnection() != null && getConnectorId() != null) { + final String html = getWidget().getSanitazedValue(); + if (!html.equals(cachedValue)) { + getConnection().updateVariable(getConnectorId(), "text", html, + getState().immediate); + getWidget().setValue(html); + } + } }; - } diff --git a/uitest/src/com/vaadin/tests/components/richtextarea/RichTextAreaUpdateWhileTyping.html b/uitest/src/com/vaadin/tests/components/richtextarea/RichTextAreaUpdateWhileTyping.html new file mode 100644 index 0000000000..6ddd1b4097 --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/richtextarea/RichTextAreaUpdateWhileTyping.html @@ -0,0 +1,42 @@ + + + + + + +New Test + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
New Test
open/run/com.vaadin.tests.components.richtextarea.RichTextAreaUpdateWhileTyping?restartApplication
selectFramexpath=//div[@id='rta']/iframe
type//bodyThis text should be visible, even after an update while I type.
pause2000
assertText//bodyThis text should be visible, even after an update while I type.
+ + diff --git a/uitest/src/com/vaadin/tests/components/richtextarea/RichTextAreaUpdateWhileTyping.java b/uitest/src/com/vaadin/tests/components/richtextarea/RichTextAreaUpdateWhileTyping.java new file mode 100644 index 0000000000..df1d6df463 --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/richtextarea/RichTextAreaUpdateWhileTyping.java @@ -0,0 +1,51 @@ +package com.vaadin.tests.components.richtextarea; + +import com.vaadin.data.Property; +import com.vaadin.data.Property.ValueChangeEvent; +import com.vaadin.server.VaadinRequest; +import com.vaadin.shared.ui.progressindicator.ProgressIndicatorServerRpc; +import com.vaadin.tests.components.AbstractComponentTest; +import com.vaadin.tests.components.AbstractTestCase; +import com.vaadin.tests.components.AbstractTestUI; +import com.vaadin.ui.ProgressIndicator; +import com.vaadin.ui.RichTextArea; + +public class RichTextAreaUpdateWhileTyping extends AbstractTestUI { + + private RichTextArea rta; + + @Override + protected void setup(VaadinRequest request) { + + // Progress indicator for changing the value of the RTA + ProgressIndicator pi = new ProgressIndicator() { + { + registerRpc(new ProgressIndicatorServerRpc() { + + @Override + public void poll() { + rta.markAsDirty(); + } + }); + } + }; + pi.setHeight("0px"); + addComponent(pi); + + rta = new RichTextArea(); + rta.setId("rta"); + rta.setImmediate(true); + addComponent(rta); + } + + @Override + protected String getTestDescription() { + // TODO Auto-generated method stub + return null; + } + + @Override + protected Integer getTicketNumber() { + return 11741; + } +} -- cgit v1.2.3 From a744d21c632f70534307c17e8a58499fa2ca9237 Mon Sep 17 00:00:00 2001 From: Leif Åstrand Date: Wed, 29 May 2013 12:36:46 +0300 Subject: Remove UI.runSafely and VaadinSession.runSafely (#11901) Change-Id: Ie72e1a3ab72be00c99548a740f16721fb7edab00 --- server/src/com/vaadin/server/VaadinSession.java | 12 +----------- server/src/com/vaadin/ui/UI.java | 10 ---------- 2 files changed, 1 insertion(+), 21 deletions(-) diff --git a/server/src/com/vaadin/server/VaadinSession.java b/server/src/com/vaadin/server/VaadinSession.java index 551031b947..b4afc914eb 100644 --- a/server/src/com/vaadin/server/VaadinSession.java +++ b/server/src/com/vaadin/server/VaadinSession.java @@ -1161,7 +1161,7 @@ public class VaadinSession implements HttpSessionBindingListener, Serializable { CurrentInstance.restoreInstances(old); } } - + } /** @@ -1273,16 +1273,6 @@ public class VaadinSession implements HttpSessionBindingListener, Serializable { } } - /** - * @deprecated As of 7.1.0.beta1, use {@link #accessSynchronously(Runnable)} - * or {@link #access(Runnable)} instead. This method will be - * removed before the final 7.1.0 release. - */ - @Deprecated - public void runSafely(Runnable runnable) { - accessSynchronously(runnable); - } - /** * Gets the CSRF token (aka double submit cookie) that is used to protect * against Cross Site Request Forgery attacks. diff --git a/server/src/com/vaadin/ui/UI.java b/server/src/com/vaadin/ui/UI.java index 508564ac0f..545c2c7365 100644 --- a/server/src/com/vaadin/ui/UI.java +++ b/server/src/com/vaadin/ui/UI.java @@ -1229,16 +1229,6 @@ public abstract class UI extends AbstractSingleComponentContainer implements }); } - /** - * @deprecated As of 7.1.0.beta1, use {@link #accessSynchronously(Runnable)} - * or {@link #access(Runnable)} instead. This method will be - * removed before the final 7.1.0 release. - */ - @Deprecated - public void runSafely(Runnable runnable) throws UIDetachedException { - accessSynchronously(runnable); - } - /** * Retrieves the object used for configuring tooltips. * -- cgit v1.2.3 From 84edd1952c0ee8eb826d78483c96bf87678d7124 Mon Sep 17 00:00:00 2001 From: Artur Signell Date: Tue, 28 May 2013 20:18:25 +0300 Subject: Make test independent of browser language (#11940) Change-Id: Ibcabe18581e4ad021ad1b58919c77fd97f2ad47c --- .../vaadin/tests/components/datefield/DynamicallyChangeDateRange.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/uitest/src/com/vaadin/tests/components/datefield/DynamicallyChangeDateRange.java b/uitest/src/com/vaadin/tests/components/datefield/DynamicallyChangeDateRange.java index 9288b0428e..fb0fb2a546 100644 --- a/uitest/src/com/vaadin/tests/components/datefield/DynamicallyChangeDateRange.java +++ b/uitest/src/com/vaadin/tests/components/datefield/DynamicallyChangeDateRange.java @@ -1,6 +1,7 @@ package com.vaadin.tests.components.datefield; import java.util.Date; +import java.util.Locale; import com.vaadin.server.VaadinRequest; import com.vaadin.tests.components.AbstractTestUI; @@ -19,6 +20,7 @@ public class DynamicallyChangeDateRange extends AbstractTestUI { @Override protected void setup(VaadinRequest request) { + setLocale(Locale.ENGLISH); final VerticalLayout layout = new VerticalLayout(); layout.setMargin(true); setContent(layout); -- cgit v1.2.3 From a3ad62d947c86d3f53f333ca9bc36e4544cd5d46 Mon Sep 17 00:00:00 2001 From: Artur Signell Date: Wed, 29 May 2013 14:59:28 +0300 Subject: Updated to custom build of Smartsprites 0.2.10 which includes a fix for SMARTSPRITES-36 (#9959) Change-Id: Ibf549acba14a8b884424a5e2c98f3a4aac5de84c --- ivysettings.xml | 12 +++---- theme-compiler/ivy.xml | 8 ++--- .../ivymodule/smartsprites-ivy-0.2.3-itmill.xml | 38 ---------------------- 3 files changed, 9 insertions(+), 49 deletions(-) delete mode 100644 theme-compiler/ivymodule/smartsprites-ivy-0.2.3-itmill.xml diff --git a/ivysettings.xml b/ivysettings.xml index 288eae9036..88c38ff33e 100644 --- a/ivysettings.xml +++ b/ivysettings.xml @@ -16,12 +16,12 @@ pattern="${user.home}/.m2/repository/[organisation]/[module]/[revision]/[artifact]-[revision](-[classifier]).[ext]" /> - - - + + + + pattern="http://vaadin.com/download/external/[artifact](-[revision]).[ext]" /> @@ -32,9 +32,9 @@ - + + revision="0.2.10-vaadin" resolver="custom-smartsprites" /> - - + rev="0.2.10-vaadin" /> + + diff --git a/theme-compiler/ivymodule/smartsprites-ivy-0.2.3-itmill.xml b/theme-compiler/ivymodule/smartsprites-ivy-0.2.3-itmill.xml deleted file mode 100644 index 29dc2d3474..0000000000 --- a/theme-compiler/ivymodule/smartsprites-ivy-0.2.3-itmill.xml +++ /dev/null @@ -1,38 +0,0 @@ - - - - - - CSS Sprites Generator Done Right. SmartSprites maintains CSS sprites in your designs, - fully automatically. No tedious copying and pasting to your CSS when adding or changing - sprited images. - - - - - - - - - - - - - - - - - - - - - - - - - - -- cgit v1.2.3 From a9afca67ba942afa287be3507eb225e0a7b954e6 Mon Sep 17 00:00:00 2001 From: Artur Signell Date: Tue, 28 May 2013 12:00:15 +0300 Subject: Moved Locale data handling to LocaleService (#11378) The locale data is now tracked per UI instance and no longer sent in every request. Change-Id: I4bebd00327da6f8d812181fd76a85eb6196d0010 --- .../com/vaadin/client/ApplicationConnection.java | 21 +- client/src/com/vaadin/client/LocaleService.java | 54 +++--- server/src/com/vaadin/server/JsonPaintTarget.java | 4 - .../vaadin/server/LegacyCommunicationManager.java | 61 ------ server/src/com/vaadin/server/LocaleService.java | 211 +++++++++++++++++++++ .../vaadin/server/communication/LocaleWriter.java | 204 -------------------- .../vaadin/server/communication/UidlWriter.java | 4 - server/src/com/vaadin/ui/AbstractComponent.java | 9 +- server/src/com/vaadin/ui/UI.java | 17 ++ shared/src/com/vaadin/shared/ui/ui/UIState.java | 28 +++ .../components/datefield/DateFieldLocale.java | 2 +- 11 files changed, 300 insertions(+), 315 deletions(-) create mode 100644 server/src/com/vaadin/server/LocaleService.java delete mode 100644 server/src/com/vaadin/server/communication/LocaleWriter.java diff --git a/client/src/com/vaadin/client/ApplicationConnection.java b/client/src/com/vaadin/client/ApplicationConnection.java index 087ee87262..24275dadb9 100644 --- a/client/src/com/vaadin/client/ApplicationConnection.java +++ b/client/src/com/vaadin/client/ApplicationConnection.java @@ -1350,16 +1350,6 @@ public class ApplicationConnection { handleUIDLDuration.logDuration(" * Loading widgets completed", 10); - Profiler.enter("Handling locales"); - if (json.containsKey("locales")) { - VConsole.log(" * Handling locales"); - // Store locale data - JsArray valueMapArray = json - .getJSValueMapArray("locales"); - LocaleService.addLocales(valueMapArray); - } - Profiler.leave("Handling locales"); - Profiler.enter("Handling meta information"); ValueMap meta = null; if (json.containsKey("meta")) { @@ -1399,6 +1389,17 @@ public class ApplicationConnection { JsArrayObject pendingStateChangeEvents = updateConnectorState( json, createdConnectorIds); + /* + * Doing this here so that locales are available also to the + * connectors which get a state change event before the UI. + */ + Profiler.enter("Handling locales"); + VConsole.log(" * Handling locales"); + // Store locale data + LocaleService + .addLocales(getUIConnector().getState().localeServiceState.localeData); + Profiler.leave("Handling locales"); + // Update hierarchy, do not fire events ConnectorHierarchyUpdateResult connectorHierarchyUpdateResult = updateConnectorHierarchy(json); diff --git a/client/src/com/vaadin/client/LocaleService.java b/client/src/com/vaadin/client/LocaleService.java index 4009c95531..69345d7174 100644 --- a/client/src/com/vaadin/client/LocaleService.java +++ b/client/src/com/vaadin/client/LocaleService.java @@ -17,10 +17,12 @@ package com.vaadin.client; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.Set; +import java.util.logging.Logger; -import com.google.gwt.core.client.JsArray; +import com.vaadin.shared.ui.ui.UIState.LocaleData; /** * Date / time etc. localisation service for all widgets. Caches all loaded @@ -31,16 +33,17 @@ import com.google.gwt.core.client.JsArray; */ public class LocaleService { - private static Map cache = new HashMap(); - private static String defaultLocale; + private static Map cache = new HashMap(); - public static void addLocale(ValueMap valueMap) { + private static String defaultLocale; - final String key = valueMap.getString("name"); + public static void addLocale(LocaleData localeData) { + final String key = localeData.name; if (cache.containsKey(key)) { cache.remove(key); } - cache.put(key, valueMap); + getLogger().fine("Received locale data for " + localeData.name); + cache.put(key, localeData); if (cache.size() == 1) { setDefaultLocale(key); } @@ -61,8 +64,7 @@ public class LocaleService { public static String[] getMonthNames(String locale) throws LocaleNotLoadedException { if (cache.containsKey(locale)) { - final ValueMap l = cache.get(locale); - return l.getStringArray("mn"); + return cache.get(locale).monthNames; } else { throw new LocaleNotLoadedException(locale); } @@ -71,8 +73,7 @@ public class LocaleService { public static String[] getShortMonthNames(String locale) throws LocaleNotLoadedException { if (cache.containsKey(locale)) { - final ValueMap l = cache.get(locale); - return l.getStringArray("smn"); + return cache.get(locale).shortMonthNames; } else { throw new LocaleNotLoadedException(locale); } @@ -81,8 +82,7 @@ public class LocaleService { public static String[] getDayNames(String locale) throws LocaleNotLoadedException { if (cache.containsKey(locale)) { - final ValueMap l = cache.get(locale); - return l.getStringArray("dn"); + return cache.get(locale).dayNames; } else { throw new LocaleNotLoadedException(locale); } @@ -91,8 +91,7 @@ public class LocaleService { public static String[] getShortDayNames(String locale) throws LocaleNotLoadedException { if (cache.containsKey(locale)) { - final ValueMap l = cache.get(locale); - return l.getStringArray("sdn"); + return cache.get(locale).shortDayNames; } else { throw new LocaleNotLoadedException(locale); } @@ -101,8 +100,7 @@ public class LocaleService { public static int getFirstDayOfWeek(String locale) throws LocaleNotLoadedException { if (cache.containsKey(locale)) { - final ValueMap l = cache.get(locale); - return l.getInt("fdow"); + return cache.get(locale).firstDayOfWeek; } else { throw new LocaleNotLoadedException(locale); } @@ -111,8 +109,7 @@ public class LocaleService { public static String getDateFormat(String locale) throws LocaleNotLoadedException { if (cache.containsKey(locale)) { - final ValueMap l = cache.get(locale); - return l.getString("df"); + return cache.get(locale).dateFormat; } else { throw new LocaleNotLoadedException(locale); } @@ -121,8 +118,7 @@ public class LocaleService { public static boolean isTwelveHourClock(String locale) throws LocaleNotLoadedException { if (cache.containsKey(locale)) { - final ValueMap l = cache.get(locale); - return l.getBoolean("thc"); + return cache.get(locale).twelveHourClock; } else { throw new LocaleNotLoadedException(locale); } @@ -131,8 +127,7 @@ public class LocaleService { public static String getClockDelimiter(String locale) throws LocaleNotLoadedException { if (cache.containsKey(locale)) { - final ValueMap l = cache.get(locale); - return l.getString("hmd"); + return cache.get(locale).hourMinuteDelimiter; } else { throw new LocaleNotLoadedException(locale); } @@ -141,20 +136,19 @@ public class LocaleService { public static String[] getAmPmStrings(String locale) throws LocaleNotLoadedException { if (cache.containsKey(locale)) { - final ValueMap l = cache.get(locale); - return l.getStringArray("ampm"); + return new String[] { cache.get(locale).am, cache.get(locale).pm }; } else { throw new LocaleNotLoadedException(locale); } - } - public static void addLocales(JsArray valueMapArray) { - for (int i = 0; i < valueMapArray.length(); i++) { - addLocale(valueMapArray.get(i)); - + public static void addLocales(List localeDatas) { + for (LocaleData localeData : localeDatas) { + addLocale(localeData); } - } + private static Logger getLogger() { + return Logger.getLogger(LocaleService.class.getName()); + } } diff --git a/server/src/com/vaadin/server/JsonPaintTarget.java b/server/src/com/vaadin/server/JsonPaintTarget.java index ca70391f64..cd09b2a44b 100644 --- a/server/src/com/vaadin/server/JsonPaintTarget.java +++ b/server/src/com/vaadin/server/JsonPaintTarget.java @@ -388,10 +388,6 @@ public class JsonPaintTarget implements PaintTarget { getUsedResources().add("layouts/" + value + ".html"); } - if (name.equals("locale")) { - manager.requireLocale(value); - } - } @Override diff --git a/server/src/com/vaadin/server/LegacyCommunicationManager.java b/server/src/com/vaadin/server/LegacyCommunicationManager.java index c0194db243..ad662cf6df 100644 --- a/server/src/com/vaadin/server/LegacyCommunicationManager.java +++ b/server/src/com/vaadin/server/LegacyCommunicationManager.java @@ -16,18 +16,12 @@ package com.vaadin.server; -import java.io.IOException; -import java.io.PrintWriter; import java.io.Serializable; -import java.io.Writer; import java.net.URI; import java.net.URISyntaxException; import java.security.GeneralSecurityException; -import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; -import java.util.List; -import java.util.Locale; import java.util.Map; import java.util.Set; import java.util.logging.Level; @@ -37,7 +31,6 @@ import org.json.JSONException; import org.json.JSONObject; import com.vaadin.server.ClientConnector.ConnectorErrorEvent; -import com.vaadin.server.communication.LocaleWriter; import com.vaadin.shared.ApplicationConstants; import com.vaadin.shared.JavaScriptConnectorState; import com.vaadin.shared.communication.SharedState; @@ -69,9 +62,6 @@ public class LegacyCommunicationManager implements Serializable { */ private final VaadinSession session; - // TODO Refactor to UI shared state (#11378) - private List locales; - // TODO Move to VaadinSession (#11409) private DragAndDropService dragAndDropService; @@ -88,7 +78,6 @@ public class LegacyCommunicationManager implements Serializable { */ public LegacyCommunicationManager(VaadinSession session) { this.session = session; - requireLocale(session.getLocale().toString()); } protected VaadinSession getSession() { @@ -312,52 +301,6 @@ public class LegacyCommunicationManager implements Serializable { return dragAndDropService; } - /** - * Prints the queued (pending) locale definitions to a {@link PrintWriter} - * in a (UIDL) format that can be sent to the client and used there in - * formatting dates, times etc. - * - * @deprecated As of 7.1. See #11378. - * - * @param outWriter - */ - @Deprecated - public void printLocaleDeclarations(Writer writer) throws IOException { - new LocaleWriter().write(locales, writer); - } - - /** - * Queues a locale to be sent to the client (browser) for date and time - * entry etc. All locale specific information is derived from server-side - * {@link Locale} instances and sent to the client when needed, eliminating - * the need to use the {@link Locale} class and all the framework behind it - * on the client. - * - * @deprecated As of 7.1. See #11378. - * - * @see Locale#toString() - * - * @param value - */ - @Deprecated - public void requireLocale(String value) { - if (locales == null) { - locales = new ArrayList(); - locales.add(session.getLocale().toString()); - } - if (!locales.contains(value)) { - locales.add(value); - } - } - - /** - * @deprecated As of 7.1. See #11378. - */ - @Deprecated - public void resetLocales() { - locales = null; - } - /** * @deprecated As of 7.1. Will be removed in the future. */ @@ -486,10 +429,6 @@ public class LegacyCommunicationManager implements Serializable { getClientCache(ui).clear(); ui.getConnectorTracker().markAllConnectorsDirty(); ui.getConnectorTracker().markAllClientSidesUninitialized(); - - // Reset sent locales - resetLocales(); - requireLocale(session.getLocale().toString()); } private static final Logger getLogger() { diff --git a/server/src/com/vaadin/server/LocaleService.java b/server/src/com/vaadin/server/LocaleService.java new file mode 100644 index 0000000000..347c4da5c6 --- /dev/null +++ b/server/src/com/vaadin/server/LocaleService.java @@ -0,0 +1,211 @@ +/* + * Copyright 2000-2013 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.text.DateFormat; +import java.text.DateFormatSymbols; +import java.text.SimpleDateFormat; +import java.util.GregorianCalendar; +import java.util.Locale; +import java.util.logging.Logger; + +import com.vaadin.shared.ui.ui.UIState.LocaleData; +import com.vaadin.shared.ui.ui.UIState.LocaleServiceState; +import com.vaadin.ui.UI; + +/** + * Server side service which handles locale and the transmission of locale date + * to the client side LocaleService. + * + * @since 7.1 + * @author Vaadin Ltd + */ +public class LocaleService { + + private UI ui; + + private LocaleServiceState state; + + /** + * Creates a LocaleService bound to the given UI + * + * @since 7.1 + * @param ui + * The UI which owns the LocaleService + */ + public LocaleService(UI ui, LocaleServiceState state) { + this.ui = ui; + this.state = state; + } + + /** + * Retrieves the UI this service is bound to + * + * @since 7.1 + * @return the UI for this service + */ + public UI getUI() { + return ui; + } + + /** + * Adds a locale to be sent to the client (browser) for date and time entry + * etc. All locale specific information is derived from server-side + * {@link Locale} instances and sent to the client when needed, eliminating + * the need to use the {@link Locale} class and all the framework behind it + * on the client. + * + * @param locale + * The locale which is required on the client side + */ + public void addLocale(Locale locale) { + for (LocaleData data : getState(false).localeData) { + if (data.name.equals(locale.toString())) { + // Already there + return; + } + } + + getState(true).localeData.add(createLocaleData(locale)); + } + + /** + * Returns the state for this service + *

+ * The state is transmitted inside the UI state rather than as an individual + * entity. + *

+ * + * @since 7.1 + * @param markAsDirty + * true to mark the state as dirty + * @return a LocaleServiceState object that can be read in any case and + * modified if markAsDirty is true + */ + private LocaleServiceState getState(boolean markAsDirty) { + if (markAsDirty) { + getUI().markAsDirty(); + } + + return state; + } + + /** + * Creates a LocaleData instance for transportation to the client + * + * @since 7.1 + * @param locale + * The locale for which to create a LocaleData object + * @return A LocaleData object with information about the given locale + */ + protected LocaleData createLocaleData(Locale locale) { + LocaleData localeData = new LocaleData(); + localeData.name = locale.toString(); + + final DateFormatSymbols dfs = new DateFormatSymbols(locale); + localeData.shortMonthNames = dfs.getShortMonths(); + localeData.monthNames = dfs.getMonths(); + // Client expects 0 based indexing, DateFormatSymbols use 1 based + localeData.shortDayNames = new String[7]; + localeData.dayNames = new String[7]; + String[] sDayNames = dfs.getShortWeekdays(); + String[] lDayNames = dfs.getWeekdays(); + for (int i = 0; i < 7; i++) { + localeData.shortDayNames[i] = sDayNames[i + 1]; + localeData.dayNames[i] = lDayNames[i + 1]; + } + + /* + * First day of week (0 = sunday, 1 = monday) + */ + final java.util.Calendar cal = new GregorianCalendar(locale); + localeData.firstDayOfWeek = cal.getFirstDayOfWeek() - 1; + + /* + * Date formatting (MM/DD/YYYY etc.) + */ + + DateFormat dateFormat = DateFormat.getDateTimeInstance( + DateFormat.SHORT, DateFormat.SHORT, locale); + if (!(dateFormat instanceof SimpleDateFormat)) { + getLogger().warning( + "Unable to get default date pattern for locale " + + locale.toString()); + dateFormat = new SimpleDateFormat(); + } + final String df = ((SimpleDateFormat) dateFormat).toPattern(); + + int timeStart = df.indexOf("H"); + if (timeStart < 0) { + timeStart = df.indexOf("h"); + } + final int ampm_first = df.indexOf("a"); + // E.g. in Korean locale AM/PM is before h:mm + // TODO should take that into consideration on client-side as well, + // now always h:mm a + if (ampm_first > 0 && ampm_first < timeStart) { + timeStart = ampm_first; + } + // Hebrew locale has time before the date + final boolean timeFirst = timeStart == 0; + String dateformat; + if (timeFirst) { + int dateStart = df.indexOf(' '); + if (ampm_first > dateStart) { + dateStart = df.indexOf(' ', ampm_first); + } + dateformat = df.substring(dateStart + 1); + } else { + dateformat = df.substring(0, timeStart - 1); + } + + localeData.dateFormat = dateformat.trim(); + + /* + * Time formatting (24 or 12 hour clock and AM/PM suffixes) + */ + final String timeformat = df.substring(timeStart, df.length()); + /* + * Doesn't return second or milliseconds. + * + * We use timeformat to determine 12/24-hour clock + */ + final boolean twelve_hour_clock = timeformat.indexOf("a") > -1; + // TODO there are other possibilities as well, like 'h' in french + // (ignore them, too complicated) + final String hour_min_delimiter = timeformat.indexOf(".") > -1 ? "." + : ":"; + // outWriter.print("\"tf\":\"" + timeformat + "\","); + localeData.twelveHourClock = twelve_hour_clock; + localeData.hourMinuteDelimiter = hour_min_delimiter; + if (twelve_hour_clock) { + final String[] ampm = dfs.getAmPmStrings(); + localeData.am = ampm[0]; + localeData.pm = ampm[1]; + } + + return localeData; + } + + private static Logger getLogger() { + return Logger.getLogger(LocaleService.class.getName()); + } + +} diff --git a/server/src/com/vaadin/server/communication/LocaleWriter.java b/server/src/com/vaadin/server/communication/LocaleWriter.java deleted file mode 100644 index c05649da19..0000000000 --- a/server/src/com/vaadin/server/communication/LocaleWriter.java +++ /dev/null @@ -1,204 +0,0 @@ -/* - * Copyright 2000-2013 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.communication; - -import java.io.IOException; -import java.io.Serializable; -import java.io.Writer; -import java.text.DateFormat; -import java.text.DateFormatSymbols; -import java.text.SimpleDateFormat; -import java.util.Calendar; -import java.util.GregorianCalendar; -import java.util.List; -import java.util.Locale; -import java.util.logging.Logger; - -/** - * Serializes locale information to JSON. - * - * @author Vaadin Ltd - * @since 7.1 - * @deprecated See ticket - * #11378. - */ -@Deprecated -public class LocaleWriter implements Serializable { - - /** - * Writes a JSON object containing localized strings of the given locales. - * - * @param locales - * The list of {@link Locale}s to write. - * @param writer - * The {@link Writer} used to write the JSON. - * @throws IOException - * If the serialization fails. - * - */ - public void write(List locales, Writer writer) throws IOException { - - // Send locale informations to client - writer.write("["); - // TODO locales are currently sent on each request; this will be fixed - // by implementing #11378. - for (int pendingLocalesIndex = 0; pendingLocalesIndex < locales.size(); pendingLocalesIndex++) { - - final Locale l = generateLocale(locales.get(pendingLocalesIndex)); - // Locale name - writer.write("{\"name\":\"" + l.toString() + "\","); - - /* - * Month names (both short and full) - */ - final DateFormatSymbols dfs = new DateFormatSymbols(l); - final String[] short_months = dfs.getShortMonths(); - final String[] months = dfs.getMonths(); - writer.write("\"smn\":[\"" - + // ShortMonthNames - short_months[0] + "\",\"" + short_months[1] + "\",\"" - + short_months[2] + "\",\"" + short_months[3] + "\",\"" - + short_months[4] + "\",\"" + short_months[5] + "\",\"" - + short_months[6] + "\",\"" + short_months[7] + "\",\"" - + short_months[8] + "\",\"" + short_months[9] + "\",\"" - + short_months[10] + "\",\"" + short_months[11] + "\"" - + "],"); - writer.write("\"mn\":[\"" - + // MonthNames - months[0] + "\",\"" + months[1] + "\",\"" + months[2] - + "\",\"" + months[3] + "\",\"" + months[4] + "\",\"" - + months[5] + "\",\"" + months[6] + "\",\"" + months[7] - + "\",\"" + months[8] + "\",\"" + months[9] + "\",\"" - + months[10] + "\",\"" + months[11] + "\"" + "],"); - - /* - * Weekday names (both short and full) - */ - final String[] short_days = dfs.getShortWeekdays(); - final String[] days = dfs.getWeekdays(); - writer.write("\"sdn\":[\"" - + // ShortDayNames - short_days[1] + "\",\"" + short_days[2] + "\",\"" - + short_days[3] + "\",\"" + short_days[4] + "\",\"" - + short_days[5] + "\",\"" + short_days[6] + "\",\"" - + short_days[7] + "\"" + "],"); - writer.write("\"dn\":[\"" - + // DayNames - days[1] + "\",\"" + days[2] + "\",\"" + days[3] + "\",\"" - + days[4] + "\",\"" + days[5] + "\",\"" + days[6] + "\",\"" - + days[7] + "\"" + "],"); - - /* - * First day of week (0 = sunday, 1 = monday) - */ - final Calendar cal = new GregorianCalendar(l); - writer.write("\"fdow\":" + (cal.getFirstDayOfWeek() - 1) + ","); - - /* - * Date formatting (MM/DD/YYYY etc.) - */ - - DateFormat dateFormat = DateFormat.getDateTimeInstance( - DateFormat.SHORT, DateFormat.SHORT, l); - if (!(dateFormat instanceof SimpleDateFormat)) { - getLogger().warning( - "Unable to get default date pattern for locale " - + l.toString()); - dateFormat = new SimpleDateFormat(); - } - final String df = ((SimpleDateFormat) dateFormat).toPattern(); - - int timeStart = df.indexOf("H"); - if (timeStart < 0) { - timeStart = df.indexOf("h"); - } - final int ampm_first = df.indexOf("a"); - // E.g. in Korean locale AM/PM is before h:mm - // TODO should take that into consideration on client-side as well, - // now always h:mm a - if (ampm_first > 0 && ampm_first < timeStart) { - timeStart = ampm_first; - } - // Hebrew locale has time before the date - final boolean timeFirst = timeStart == 0; - String dateformat; - if (timeFirst) { - int dateStart = df.indexOf(' '); - if (ampm_first > dateStart) { - dateStart = df.indexOf(' ', ampm_first); - } - dateformat = df.substring(dateStart + 1); - } else { - dateformat = df.substring(0, timeStart - 1); - } - - writer.write("\"df\":\"" + dateformat.trim() + "\","); - - /* - * Time formatting (24 or 12 hour clock and AM/PM suffixes) - */ - final String timeformat = df.substring(timeStart, df.length()); - /* - * Doesn't return second or milliseconds. - * - * We use timeformat to determine 12/24-hour clock - */ - final boolean twelve_hour_clock = timeformat.indexOf("a") > -1; - // TODO there are other possibilities as well, like 'h' in french - // (ignore them, too complicated) - final String hour_min_delimiter = timeformat.indexOf(".") > -1 ? "." - : ":"; - // outWriter.print("\"tf\":\"" + timeformat + "\","); - writer.write("\"thc\":" + twelve_hour_clock + ","); - writer.write("\"hmd\":\"" + hour_min_delimiter + "\""); - if (twelve_hour_clock) { - final String[] ampm = dfs.getAmPmStrings(); - writer.write(",\"ampm\":[\"" + ampm[0] + "\",\"" + ampm[1] - + "\"]"); - } - writer.write("}"); - if (pendingLocalesIndex < locales.size() - 1) { - writer.write(","); - } - } - writer.write("]"); // Close locales - } - - /** - * Constructs a {@link Locale} instance to be sent to the client based on a - * short locale description string. - * - * @see #requireLocale(String) - * - * @param value - * @return - */ - private Locale generateLocale(String value) { - final String[] temp = value.split("_"); - if (temp.length == 1) { - return new Locale(temp[0]); - } else if (temp.length == 2) { - return new Locale(temp[0], temp[1]); - } else { - return new Locale(temp[0], temp[1], temp[2]); - } - } - - private static final Logger getLogger() { - return Logger.getLogger(LocaleWriter.class.getName()); - } -} diff --git a/server/src/com/vaadin/server/communication/UidlWriter.java b/server/src/com/vaadin/server/communication/UidlWriter.java index 60a884a635..f715569424 100644 --- a/server/src/com/vaadin/server/communication/UidlWriter.java +++ b/server/src/com/vaadin/server/communication/UidlWriter.java @@ -283,10 +283,6 @@ public class UidlWriter implements Serializable { + new JSONArray(styleDependencies).toString()); } - // add any pending locale definitions requested by the client - writer.write(", \"locales\": "); - manager.printLocaleDeclarations(writer); - if (manager.getDragAndDropService() != null) { manager.getDragAndDropService().printJSONResponse(writer); } diff --git a/server/src/com/vaadin/ui/AbstractComponent.java b/server/src/com/vaadin/ui/AbstractComponent.java index 06060dbf91..9ff36a42d2 100644 --- a/server/src/com/vaadin/ui/AbstractComponent.java +++ b/server/src/com/vaadin/ui/AbstractComponent.java @@ -291,7 +291,10 @@ public abstract class AbstractComponent extends AbstractClientConnector public void setLocale(Locale locale) { this.locale = locale; - // FIXME: Reload value if there is a converter + if (locale != null && isAttached()) { + getUI().getLocaleService().addLocale(locale); + } + markAsDirty(); } @@ -556,6 +559,10 @@ public abstract class AbstractComponent extends AbstractClientConnector focus(); } setActionManagerViewer(); + if (locale != null) { + getUI().getLocaleService().addLocale(locale); + } + } /* diff --git a/server/src/com/vaadin/ui/UI.java b/server/src/com/vaadin/ui/UI.java index 545c2c7365..706f7c436b 100644 --- a/server/src/com/vaadin/ui/UI.java +++ b/server/src/com/vaadin/ui/UI.java @@ -30,6 +30,7 @@ import com.vaadin.event.ActionManager; import com.vaadin.event.MouseEvents.ClickEvent; import com.vaadin.event.MouseEvents.ClickListener; import com.vaadin.navigator.Navigator; +import com.vaadin.server.LocaleService; import com.vaadin.server.Page; import com.vaadin.server.PaintException; import com.vaadin.server.PaintTarget; @@ -494,6 +495,9 @@ public abstract class UI extends AbstractSingleComponentContainer implements private boolean hasPendingPush = false; + private LocaleService localeService = new LocaleService(this, + getState(false).localeServiceState); + /** * This method is used by Component.Focusable objects to request focus to * themselves. Focus renders must be handled at window level (instead of @@ -1052,6 +1056,7 @@ public abstract class UI extends AbstractSingleComponentContainer implements @Override public void attach() { super.attach(); + getLocaleService().addLocale(getLocale()); } /** @@ -1428,4 +1433,16 @@ public abstract class UI extends AbstractSingleComponentContainer implements public void setOverlayContainerLabel(String overlayContainerLabel) { getState().overlayContainerLabel = overlayContainerLabel; } + + /** + * Returns the locale service which handles transmission of Locale data to + * the client. + * + * @since 7.1 + * @return The LocaleService for this UI + */ + public LocaleService getLocaleService() { + return localeService; + } + } diff --git a/shared/src/com/vaadin/shared/ui/ui/UIState.java b/shared/src/com/vaadin/shared/ui/ui/UIState.java index 16c1ed16c7..f01d5d8100 100644 --- a/shared/src/com/vaadin/shared/ui/ui/UIState.java +++ b/shared/src/com/vaadin/shared/ui/ui/UIState.java @@ -16,7 +16,11 @@ package com.vaadin.shared.ui.ui; import java.io.Serializable; +import java.util.ArrayList; +import java.util.List; +import com.vaadin.server.LocaleService; +import com.vaadin.server.Page; import com.vaadin.shared.communication.PushMode; import com.vaadin.shared.ui.TabIndexState; @@ -50,10 +54,34 @@ public class UIState extends TabIndexState { * State related to the {@link Page} class. */ public PageState pageState = new PageState(); + /** + * State related to the {@link LocaleService} class. + */ + public LocaleServiceState localeServiceState = new LocaleServiceState(); { primaryStyleName = "v-ui"; // Default is 1 for legacy reasons tabIndex = 1; } + + public static class LocaleServiceState implements Serializable { + public List localeData = new ArrayList(); + } + + public static class LocaleData implements Serializable { + public String name; + public String[] monthNames; + public String[] shortMonthNames; + public String[] shortDayNames; + public String[] dayNames; + public int firstDayOfWeek; + public String dateFormat; + public boolean twelveHourClock; + public String hourMinuteDelimiter; + public String am; + public String pm; + + } + } diff --git a/uitest/src/com/vaadin/tests/components/datefield/DateFieldLocale.java b/uitest/src/com/vaadin/tests/components/datefield/DateFieldLocale.java index 5d06895d11..a4fe2b0285 100644 --- a/uitest/src/com/vaadin/tests/components/datefield/DateFieldLocale.java +++ b/uitest/src/com/vaadin/tests/components/datefield/DateFieldLocale.java @@ -16,7 +16,7 @@ public class DateFieldLocale extends TestBase { final DateField dateField = new DateField("DateField"); dateField.setLocale(new Locale("fi", "FI")); dateField.setCaption(dateField.getLocale().toString()); - dateField.setValue(new Date()); + dateField.setValue(new Date(2013 - 1900, 7 - 1, 27)); dateField.setResolution(DateField.RESOLUTION_DAY); addComponent(new Button("Change locale", new ClickListener() { -- cgit v1.2.3 From 5e548ae0dd34a34f6d463af2acc06bd735f957d4 Mon Sep 17 00:00:00 2001 From: Artur Signell Date: Wed, 29 May 2013 16:11:48 +0300 Subject: Fixed javadoc compilation error Change-Id: Ic834ddabdeeb2a9cc453b67e5202ff1aab44dffd --- shared/src/com/vaadin/shared/ui/ui/UIState.java | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/shared/src/com/vaadin/shared/ui/ui/UIState.java b/shared/src/com/vaadin/shared/ui/ui/UIState.java index f01d5d8100..177fe2e7bd 100644 --- a/shared/src/com/vaadin/shared/ui/ui/UIState.java +++ b/shared/src/com/vaadin/shared/ui/ui/UIState.java @@ -19,8 +19,6 @@ import java.io.Serializable; import java.util.ArrayList; import java.util.List; -import com.vaadin.server.LocaleService; -import com.vaadin.server.Page; import com.vaadin.shared.communication.PushMode; import com.vaadin.shared.ui.TabIndexState; @@ -51,11 +49,11 @@ public class UIState extends TabIndexState { } /** - * State related to the {@link Page} class. + * State related to the Page class. */ public PageState pageState = new PageState(); /** - * State related to the {@link LocaleService} class. + * State related to the LocaleService class. */ public LocaleServiceState localeServiceState = new LocaleServiceState(); -- cgit v1.2.3 From 91182e237f2f4f8784582887970c32b5be3ad7c5 Mon Sep 17 00:00:00 2001 From: Leif Åstrand Date: Tue, 28 May 2013 11:01:31 +0300 Subject: Extract ProgressBar and deprecate ProgressIndicator (#11925) Change-Id: Id9eaee65762b0dadd59f3e730d3ff11712ab87fe --- client/src/com/vaadin/client/ui/VProgressBar.java | 85 ++++++++++++ .../com/vaadin/client/ui/VProgressIndicator.java | 62 ++------- .../ui/progressindicator/ProgressBarConnector.java | 56 ++++++++ .../ProgressIndicatorConnector.java | 21 +-- server/src/com/vaadin/ui/ProgressBar.java | 152 +++++++++++++++++++++ server/src/com/vaadin/ui/ProgressIndicator.java | 105 +++----------- .../ui/progressindicator/ProgressBarState.java | 33 +++++ .../progressindicator/ProgressIndicatorState.java | 7 +- .../progressindicator/ProgressBarTest.html | 62 +++++++++ .../progressindicator/ProgressBarTest.java | 125 +++++++++++++++++ 10 files changed, 552 insertions(+), 156 deletions(-) create mode 100644 client/src/com/vaadin/client/ui/VProgressBar.java create mode 100644 client/src/com/vaadin/client/ui/progressindicator/ProgressBarConnector.java create mode 100644 server/src/com/vaadin/ui/ProgressBar.java create mode 100644 shared/src/com/vaadin/shared/ui/progressindicator/ProgressBarState.java create mode 100644 uitest/src/com/vaadin/tests/components/progressindicator/ProgressBarTest.html create mode 100644 uitest/src/com/vaadin/tests/components/progressindicator/ProgressBarTest.java diff --git a/client/src/com/vaadin/client/ui/VProgressBar.java b/client/src/com/vaadin/client/ui/VProgressBar.java new file mode 100644 index 0000000000..3eb8725520 --- /dev/null +++ b/client/src/com/vaadin/client/ui/VProgressBar.java @@ -0,0 +1,85 @@ +/* + * Copyright 2000-2013 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.client.ui; + +import com.google.gwt.dom.client.Style.Unit; +import com.google.gwt.user.client.DOM; +import com.google.gwt.user.client.Element; +import com.google.gwt.user.client.ui.HasEnabled; +import com.google.gwt.user.client.ui.Widget; + +/** + * Widget for showing the current progress of a long running task. + *

+ * The default mode is to show the current progress internally represented by a + * floating point value between 0 and 1 (inclusive). The progress bar can also + * be in an indeterminate mode showing an animation indicating that the task is + * running but without providing any information about the current progress. + * + * @since 7.1 + * @author Vaadin Ltd + */ +public class VProgressBar extends Widget implements HasEnabled { + + public static final String CLASSNAME = "v-progressindicator"; + Element wrapper = DOM.createDiv(); + Element indicator = DOM.createDiv(); + + protected boolean indeterminate = false; + protected float state = 0.0f; + private boolean enabled; + + public VProgressBar() { + setElement(DOM.createDiv()); + getElement().appendChild(wrapper); + setStyleName(CLASSNAME); + wrapper.appendChild(indicator); + indicator.setClassName(CLASSNAME + "-indicator"); + wrapper.setClassName(CLASSNAME + "-wrapper"); + } + + public void setIndeterminate(boolean indeterminate) { + this.indeterminate = indeterminate; + setStyleName(CLASSNAME + "-indeterminate", indeterminate); + } + + public void setState(float state) { + final int size = Math.round(100 * state); + indicator.getStyle().setWidth(size, Unit.PCT); + } + + public boolean isIndeterminate() { + return indeterminate; + } + + public float getState() { + return state; + } + + @Override + public boolean isEnabled() { + return enabled; + } + + @Override + public void setEnabled(boolean enabled) { + this.enabled = enabled; + setStyleName("v-disabled", !enabled); + + } + +} diff --git a/client/src/com/vaadin/client/ui/VProgressIndicator.java b/client/src/com/vaadin/client/ui/VProgressIndicator.java index d6b25cb016..500a5def30 100644 --- a/client/src/com/vaadin/client/ui/VProgressIndicator.java +++ b/client/src/com/vaadin/client/ui/VProgressIndicator.java @@ -16,59 +16,13 @@ package com.vaadin.client.ui; -import com.google.gwt.dom.client.Style.Unit; -import com.google.gwt.user.client.DOM; -import com.google.gwt.user.client.Element; -import com.google.gwt.user.client.ui.HasEnabled; -import com.google.gwt.user.client.ui.Widget; - -public class VProgressIndicator extends Widget implements HasEnabled { - - public static final String CLASSNAME = "v-progressindicator"; - Element wrapper = DOM.createDiv(); - Element indicator = DOM.createDiv(); - - protected boolean indeterminate = false; - protected float state = 0.0f; - private boolean enabled; - - public VProgressIndicator() { - setElement(DOM.createDiv()); - getElement().appendChild(wrapper); - setStyleName(CLASSNAME); - wrapper.appendChild(indicator); - indicator.setClassName(CLASSNAME + "-indicator"); - wrapper.setClassName(CLASSNAME + "-wrapper"); - } - - public void setIndeterminate(boolean indeterminate) { - this.indeterminate = indeterminate; - setStyleName(CLASSNAME + "-indeterminate", indeterminate); - } - - public void setState(float state) { - final int size = Math.round(100 * state); - indicator.getStyle().setWidth(size, Unit.PCT); - } - - public boolean isIndeterminate() { - return indeterminate; - } - - public float getState() { - return state; - } - - @Override - public boolean isEnabled() { - return enabled; - } - - @Override - public void setEnabled(boolean enabled) { - this.enabled = enabled; - setStyleName("v-disabled", !enabled); - - } +/** + * + * @author Vaadin Ltd + * + * @deprecated as of 7.1, renamed to VProgressBar + */ +@Deprecated +public class VProgressIndicator extends VProgressBar { } diff --git a/client/src/com/vaadin/client/ui/progressindicator/ProgressBarConnector.java b/client/src/com/vaadin/client/ui/progressindicator/ProgressBarConnector.java new file mode 100644 index 0000000000..91f3da5323 --- /dev/null +++ b/client/src/com/vaadin/client/ui/progressindicator/ProgressBarConnector.java @@ -0,0 +1,56 @@ +/* + * Copyright 2000-2013 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.client.ui.progressindicator; + +import com.vaadin.client.communication.StateChangeEvent; +import com.vaadin.client.ui.AbstractFieldConnector; +import com.vaadin.client.ui.VProgressBar; +import com.vaadin.shared.ui.Connect; +import com.vaadin.shared.ui.progressindicator.ProgressBarState; +import com.vaadin.ui.ProgressBar; + +/** + * Connector for {@link VProgressBar}. + * + * @since 7.1 + * @author Vaadin Ltd + */ +@Connect(ProgressBar.class) +public class ProgressBarConnector extends AbstractFieldConnector { + + public ProgressBarConnector() { + super(); + } + + @Override + public void onStateChanged(StateChangeEvent stateChangeEvent) { + super.onStateChanged(stateChangeEvent); + getWidget().setIndeterminate(getState().indeterminate); + getWidget().setState(getState().state); + } + + @Override + public ProgressBarState getState() { + return (ProgressBarState) super.getState(); + } + + @Override + public VProgressBar getWidget() { + return (VProgressBar) super.getWidget(); + } + +} \ No newline at end of file diff --git a/client/src/com/vaadin/client/ui/progressindicator/ProgressIndicatorConnector.java b/client/src/com/vaadin/client/ui/progressindicator/ProgressIndicatorConnector.java index ac5c3f5f6b..9e14f082e0 100644 --- a/client/src/com/vaadin/client/ui/progressindicator/ProgressIndicatorConnector.java +++ b/client/src/com/vaadin/client/ui/progressindicator/ProgressIndicatorConnector.java @@ -18,15 +18,23 @@ package com.vaadin.client.ui.progressindicator; import com.google.gwt.user.client.Timer; import com.vaadin.client.communication.StateChangeEvent; -import com.vaadin.client.ui.AbstractFieldConnector; -import com.vaadin.client.ui.VProgressIndicator; +import com.vaadin.client.ui.VProgressBar; import com.vaadin.shared.ui.Connect; import com.vaadin.shared.ui.progressindicator.ProgressIndicatorServerRpc; import com.vaadin.shared.ui.progressindicator.ProgressIndicatorState; import com.vaadin.ui.ProgressIndicator; +/** + * Connector for {@link VProgressBar} with polling support. + * + * @since 7.0 + * @author Vaadin Ltd + * @deprecated as of 7.1, use {@link ProgressBarConnector} combined with server + * push or UI polling. + */ @Connect(ProgressIndicator.class) -public class ProgressIndicatorConnector extends AbstractFieldConnector { +@Deprecated +public class ProgressIndicatorConnector extends ProgressBarConnector { @Override public ProgressIndicatorState getState() { @@ -45,8 +53,6 @@ public class ProgressIndicatorConnector extends AbstractFieldConnector { @Override public void onStateChanged(StateChangeEvent stateChangeEvent) { super.onStateChanged(stateChangeEvent); - getWidget().setIndeterminate(getState().indeterminate); - getWidget().setState(getState().state); if (isEnabled()) { poller.scheduleRepeating(getState().pollingInterval); @@ -60,9 +66,4 @@ public class ProgressIndicatorConnector extends AbstractFieldConnector { super.onUnregister(); poller.cancel(); } - - @Override - public VProgressIndicator getWidget() { - return (VProgressIndicator) super.getWidget(); - } } diff --git a/server/src/com/vaadin/ui/ProgressBar.java b/server/src/com/vaadin/ui/ProgressBar.java new file mode 100644 index 0000000000..3f8aab6d7c --- /dev/null +++ b/server/src/com/vaadin/ui/ProgressBar.java @@ -0,0 +1,152 @@ +/* + * Copyright 2000-2013 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.ui; + +import com.vaadin.data.Property; +import com.vaadin.shared.ui.progressindicator.ProgressBarState; + +/** + * Shows the current progress of a long running task. + *

+ * The default mode is to show the current progress internally represented by a + * floating point value between 0 and 1 (inclusive). The progress bar can also + * be in an indeterminate mode showing an animation indicating that the task is + * running but without providing any information about the current progress. + * + * @since 7.1 + * @author Vaadin Ltd + */ +public class ProgressBar extends AbstractField implements + Property.Viewer, Property.ValueChangeListener { + + /** + * Creates a new progress bar initially set to 0% progress. + */ + public ProgressBar() { + this(0); + } + + /** + * Creates a new progress bar with the given initial value. + * + * @param progress + * the initial progress value + */ + public ProgressBar(float progress) { + setValue(Float.valueOf(progress)); + } + + /** + * Creates a new progress bar bound to the given data source. + * + * @param dataSource + * the property to bind this progress bar to + */ + public ProgressBar(Property dataSource) { + setPropertyDataSource(dataSource); + } + + @Override + public void beforeClientResponse(boolean initial) { + super.beforeClientResponse(initial); + + // Update value in state even if the property hasn't fired any event + getState().state = getValue(); + } + + /** + * Gets the value of this progress bar. The value is a float + * between 0 and 1 where 0 represents no progress at all and 1 represents + * fully completed. + * + * @return the current progress value + */ + @Override + public Float getValue() { + return super.getValue(); + } + + /** + * Sets the value of this progress bar. The value is a float + * between 0 and 1 where 0 represents no progress at all and 1 represents + * fully completed. + * + * @param newValue + * the current progress value + */ + @Override + public void setValue(Float newValue) { + super.setValue(newValue); + } + + @Override + public Class getType() { + return Float.class; + } + + @Override + protected ProgressBarState getState() { + return (ProgressBarState) super.getState(); + } + + @Override + protected ProgressBarState getState(boolean markAsDirty) { + return (ProgressBarState) super.getState(markAsDirty); + } + + /** + * Sets whether or not this progress indicator is indeterminate. In + * indeterminate mode there is an animation indicating that the task is + * running but without providing any information about the current progress. + * + * @param indeterminate + * true to set to indeterminate mode; otherwise + * false + */ + public void setIndeterminate(boolean indeterminate) { + getState().indeterminate = indeterminate; + } + + /** + * Gets whether or not this progress indicator is indeterminate. In + * indeterminate mode there is an animation indicating that the task is + * running but without providing any information about the current progress. + * + * @return true if set to indeterminate mode; otherwise + * false + */ + public boolean isIndeterminate() { + return getState(false).indeterminate; + } + + /* + * Overridden to keep the shared state in sync with the AbstractField + * internal value. Should be removed once AbstractField is refactored to use + * shared state. + * + * See tickets #10921 and #11064. + */ + @Override + protected void setInternalValue(Float newValue) { + super.setInternalValue(newValue); + if (newValue == null) { + newValue = Float.valueOf(0); + } + getState().state = newValue; + } + +} \ No newline at end of file diff --git a/server/src/com/vaadin/ui/ProgressIndicator.java b/server/src/com/vaadin/ui/ProgressIndicator.java index c481aa1e8f..6da18fc29d 100644 --- a/server/src/com/vaadin/ui/ProgressIndicator.java +++ b/server/src/com/vaadin/ui/ProgressIndicator.java @@ -17,24 +17,27 @@ package com.vaadin.ui; import com.vaadin.data.Property; +import com.vaadin.shared.communication.PushMode; import com.vaadin.shared.ui.progressindicator.ProgressIndicatorServerRpc; import com.vaadin.shared.ui.progressindicator.ProgressIndicatorState; /** - * ProgressIndicator is component that shows user state of a - * process (like long computing or file upload) - * - * ProgressIndicator has two main modes. One for indeterminate - * processes and other (default) for processes which progress can be measured - * - * May view an other property that indicates progress 0...1 + * A {@link ProgressBar} which polls the server for updates. + *

+ * Polling in this way is generally not recommended since there is no + * centralized management of when messages are sent to the server. Furthermore, + * polling might not be needed at all if {@link UI#setPushMode(PushMode)} or + * {@link UI#setPollInterval(int)} is used. * * @author Vaadin Ltd. * @since 4 + * @deprecated as of 7.1, use {@link ProgressBar} combined with + * {@link UI#setPushMode(PushMode)} or + * {@link UI#setPollInterval(int)} instead. */ +@Deprecated @SuppressWarnings("serial") -public class ProgressIndicator extends AbstractField implements - Property.Viewer, Property.ValueChangeListener { +public class ProgressIndicator extends ProgressBar { private ProgressIndicatorServerRpc rpc = new ProgressIndicatorServerRpc() { @@ -57,7 +60,7 @@ public class ProgressIndicator extends AbstractField implements * @param value */ public ProgressIndicator(float value) { - setValue(value); + super(value); registerRpc(rpc); } @@ -68,74 +71,18 @@ public class ProgressIndicator extends AbstractField implements * @param contentSource */ public ProgressIndicator(Property contentSource) { - setPropertyDataSource(contentSource); + super(contentSource); registerRpc(rpc); } - @Override - public void beforeClientResponse(boolean initial) { - super.beforeClientResponse(initial); - - getState().state = getValue(); - } - - /** - * Gets the value of the ProgressIndicator. Value of the ProgressIndicator - * is Float between 0 and 1. - * - * @return the Value of the ProgressIndicator. - * @see com.vaadin.ui.AbstractField#getValue() - */ - @Override - public Float getValue() { - return super.getValue(); - } - - /** - * Sets the value of the ProgressIndicator. Value of the ProgressIndicator - * is the Float between 0 and 1. - * - * @param newValue - * the New value of the ProgressIndicator. - * @see com.vaadin.ui.AbstractField#setValue() - */ - @Override - public void setValue(Float newValue) { - super.setValue(newValue); - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.ui.AbstractField#getType() - */ - @Override - public Class getType() { - return Float.class; - } - @Override protected ProgressIndicatorState getState() { return (ProgressIndicatorState) super.getState(); } - /** - * Sets whether or not the ProgressIndicator is indeterminate. - * - * @param indeterminate - * true to set to indeterminate mode. - */ - public void setIndeterminate(boolean indeterminate) { - getState().indeterminate = indeterminate; - } - - /** - * Gets whether or not the ProgressIndicator is indeterminate. - * - * @return true to set to indeterminate mode. - */ - public boolean isIndeterminate() { - return getState().indeterminate; + @Override + protected ProgressIndicatorState getState(boolean markAsDirty) { + return (ProgressIndicatorState) super.getState(markAsDirty); } /** @@ -154,22 +101,6 @@ public class ProgressIndicator extends AbstractField implements * @return the interval in milliseconds. */ public int getPollingInterval() { - return getState().pollingInterval; - } - - /* - * Overridden to keep the shared state in sync with the AbstractField - * internal value. Should be removed once AbstractField is refactored to use - * shared state. - * - * See tickets #10921 and #11064. - */ - @Override - protected void setInternalValue(Float newValue) { - super.setInternalValue(newValue); - if (newValue == null) { - newValue = 0.0f; - } - getState().state = newValue; + return getState(false).pollingInterval; } } diff --git a/shared/src/com/vaadin/shared/ui/progressindicator/ProgressBarState.java b/shared/src/com/vaadin/shared/ui/progressindicator/ProgressBarState.java new file mode 100644 index 0000000000..fef1030c63 --- /dev/null +++ b/shared/src/com/vaadin/shared/ui/progressindicator/ProgressBarState.java @@ -0,0 +1,33 @@ +/* + * Copyright 2000-2013 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.shared.ui.progressindicator; + +import com.vaadin.shared.AbstractFieldState; +import com.vaadin.shared.communication.SharedState; + +/** + * {@link SharedState} for {@link com.vaadin.ui.ProgressBar} + * + * @since 7.1 + * @author Vaadin Ltd + */ +public class ProgressBarState extends AbstractFieldState { + + public boolean indeterminate = false; + public Float state = 0.0f; + +} \ No newline at end of file diff --git a/shared/src/com/vaadin/shared/ui/progressindicator/ProgressIndicatorState.java b/shared/src/com/vaadin/shared/ui/progressindicator/ProgressIndicatorState.java index 4126b994d8..f555476be8 100644 --- a/shared/src/com/vaadin/shared/ui/progressindicator/ProgressIndicatorState.java +++ b/shared/src/com/vaadin/shared/ui/progressindicator/ProgressIndicatorState.java @@ -15,10 +15,7 @@ */ package com.vaadin.shared.ui.progressindicator; -import com.vaadin.shared.AbstractFieldState; - -public class ProgressIndicatorState extends AbstractFieldState { - public boolean indeterminate = false; +@Deprecated +public class ProgressIndicatorState extends ProgressBarState { public int pollingInterval = 1000; - public Float state = 0.0f; } diff --git a/uitest/src/com/vaadin/tests/components/progressindicator/ProgressBarTest.html b/uitest/src/com/vaadin/tests/components/progressindicator/ProgressBarTest.html new file mode 100644 index 0000000000..b7add101f9 --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/progressindicator/ProgressBarTest.html @@ -0,0 +1,62 @@ + + + + + + +New Test + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
New Test
open/run/com.vaadin.tests.components.progressindicator.ProgressBarTest?restartApplication
clickvaadin=runcomvaadintestscomponentsprogressindicatorProgressBarTest::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[1]/VButton[0]/domChild[0]/domChild[0]
pause1000
assertTextvaadin=runcomvaadintestscomponentsprogressindicatorProgressBarTest::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VLabel[0]0
clickvaadin=runcomvaadintestscomponentsprogressindicatorProgressBarTest::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[2]/VButton[0]/domChild[0]/domChild[0]
pause1000
assertNotTextvaadin=runcomvaadintestscomponentsprogressindicatorProgressBarTest::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VLabel[0]0
clickvaadin=runcomvaadintestscomponentsprogressindicatorProgressBarTest::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[3]/VButton[0]/domChild[0]/domChild[0]
+ + diff --git a/uitest/src/com/vaadin/tests/components/progressindicator/ProgressBarTest.java b/uitest/src/com/vaadin/tests/components/progressindicator/ProgressBarTest.java new file mode 100644 index 0000000000..5afa874220 --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/progressindicator/ProgressBarTest.java @@ -0,0 +1,125 @@ +/* + * Copyright 2000-2013 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.progressindicator; + +import com.vaadin.server.VaadinRequest; +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.ProgressBar; +import com.vaadin.ui.ProgressIndicator; + +public class ProgressBarTest extends AbstractTestUI { + + private Label updatedFromBackround; + private Thread updateThread = new Thread() { + @Override + public void run() { + Runnable updateTask = new Runnable() { + @Override + public void run() { + counter++; + updateLabel(); + } + }; + + while (true) { + access(updateTask); + try { + Thread.sleep(500); + } catch (InterruptedException e) { + break; + } + } + } + }; + private ProgressBar progressBar; + private int counter = 0; + + @Override + protected void setup(VaadinRequest request) { + updatedFromBackround = new Label(); + updatedFromBackround.setCaption("Updated from background thread"); + updateLabel(); + addComponent(updatedFromBackround); + + addComponent(new Button("Use ProgressBar", new Button.ClickListener() { + @Override + public void buttonClick(ClickEvent event) { + useComponent(new ProgressBar()); + } + })); + + addComponent(new Button("Use ProgressIndicator", + new Button.ClickListener() { + @Override + public void buttonClick(ClickEvent event) { + useComponent(new ProgressIndicator()); + } + })); + + addComponent(new Button("Stop background thread", + new Button.ClickListener() { + @Override + public void buttonClick(ClickEvent event) { + stopUpdateThread(); + } + })); + updateThread.setDaemon(true); + updateThread.start(); + } + + private void useComponent(ProgressBar progressBar) { + if (this.progressBar != null) { + removeComponent(this.progressBar); + } + this.progressBar = progressBar; + addComponent(progressBar); + + counter = 0; + updateLabel(); + } + + @Override + public void detach() { + super.detach(); + stopUpdateThread(); + } + + private void stopUpdateThread() { + if (updateThread != null) { + updateThread.interrupt(); + updateThread = null; + } + } + + private void updateLabel() { + updatedFromBackround.setValue(String.valueOf(counter)); + } + + @Override + protected String getTestDescription() { + return "ProgressBar should work just as ProgressIndicator, just without the polling"; + } + + @Override + protected Integer getTicketNumber() { + return Integer.valueOf(11925); + } + +} -- cgit v1.2.3 From a5b8209d928815aab9eee2151bdd00686a2b0ff7 Mon Sep 17 00:00:00 2001 From: Artur Signell Date: Tue, 28 May 2013 19:52:21 +0300 Subject: Add primary style name support for ProgressBar/Indicator (#9913) Change-Id: I3d773640d2f1c8cd1b71c673685afd7059811d16 --- WebContent/VAADIN/themes/base/base.scss | 5 +- .../themes/chameleon/components/components.scss | 6 +- WebContent/VAADIN/themes/liferay/liferay.scss | 4 +- WebContent/VAADIN/themes/reindeer/reindeer.scss | 5 +- WebContent/VAADIN/themes/runo/runo.scss | 6 +- client/src/com/vaadin/client/ui/VProgressBar.java | 32 ++++-- .../com/vaadin/client/ui/VProgressIndicator.java | 6 + .../ui/progressindicator/ProgressBarState.java | 4 + .../progressindicator/ProgressIndicatorState.java | 6 + .../components/AbstractComponentTestCase.java | 7 ++ .../progressindicator/ProgressBarGenericTest.java | 55 ++++++++++ .../ProgressBarPrimaryStyleName.html | 121 +++++++++++++++++++++ 12 files changed, 243 insertions(+), 14 deletions(-) create mode 100644 uitest/src/com/vaadin/tests/components/progressindicator/ProgressBarGenericTest.java create mode 100644 uitest/src/com/vaadin/tests/components/progressindicator/ProgressBarPrimaryStyleName.html diff --git a/WebContent/VAADIN/themes/base/base.scss b/WebContent/VAADIN/themes/base/base.scss index 83e463fa00..514579830d 100644 --- a/WebContent/VAADIN/themes/base/base.scss +++ b/WebContent/VAADIN/themes/base/base.scss @@ -88,7 +88,10 @@ $line-height: normal; @include base-orderedlayout; @include base-panel; @include base-popupview; - @include base-progressindicator; + @include base-progressindicator(v-progressbar); + /* For legacy ProgressIndicator component */ + @include base-progressindicator(v-progressindicator); + @include base-select; @include base-shadow; @include base-slider; diff --git a/WebContent/VAADIN/themes/chameleon/components/components.scss b/WebContent/VAADIN/themes/chameleon/components/components.scss index 9f29827de0..9c8a56b33d 100644 --- a/WebContent/VAADIN/themes/chameleon/components/components.scss +++ b/WebContent/VAADIN/themes/chameleon/components/components.scss @@ -29,7 +29,11 @@ @include chameleon-notification; @include chameleon-panel; @include chameleon-popupview; - @include chameleon-progressindicator; + + @include chameleon-progressindicator(v-progressbar); + /* For legacy ProgressIndicator component */ + @include chameleon-progressindicator(v-progressindicator); + @include chameleon-slider; @include chameleon-splitpanel; @include chameleon-table; diff --git a/WebContent/VAADIN/themes/liferay/liferay.scss b/WebContent/VAADIN/themes/liferay/liferay.scss index 7d7665ad86..273c065772 100644 --- a/WebContent/VAADIN/themes/liferay/liferay.scss +++ b/WebContent/VAADIN/themes/liferay/liferay.scss @@ -42,7 +42,9 @@ @include liferay-notification; @include liferay-panel; @include liferay-popupview; - @include liferay-progressindicator; + @include liferay-progressindicator(v-progressbar); + /* For legacy ProgressIndicator component */ + @include liferay-progressindicator(v-progressindicator); @include liferay-select; @include liferay-slider; @include liferay-splitpanel; diff --git a/WebContent/VAADIN/themes/reindeer/reindeer.scss b/WebContent/VAADIN/themes/reindeer/reindeer.scss index 3cf1c392e3..485839ecc7 100644 --- a/WebContent/VAADIN/themes/reindeer/reindeer.scss +++ b/WebContent/VAADIN/themes/reindeer/reindeer.scss @@ -56,7 +56,10 @@ $line-height: normal; @include reindeer-notification; @include reindeer-panel; @include reindeer-popupview; - @include reindeer-progressindicator; + @include reindeer-progressindicator(v-progressbar); + /* For legacy ProgressIndicator component */ + @include reindeer-progressindicator(v-progressindicator); + @include reindeer-select; @include reindeer-slider; @include reindeer-splitpanel; diff --git a/WebContent/VAADIN/themes/runo/runo.scss b/WebContent/VAADIN/themes/runo/runo.scss index 6e88b14eb4..33ad35a8af 100644 --- a/WebContent/VAADIN/themes/runo/runo.scss +++ b/WebContent/VAADIN/themes/runo/runo.scss @@ -58,7 +58,11 @@ $line-height: 18px; @include runo-orderedlayout; @include runo-panel; @include runo-popupview; - @include runo-progressindicator; + + @include runo-progressindicator(v-progressbar); + /* For legacy ProgressIndicator component */ + @include runo-progressindicator(v-progressindicator); + @include runo-select; @include runo-shadow; @include runo-slider; diff --git a/client/src/com/vaadin/client/ui/VProgressBar.java b/client/src/com/vaadin/client/ui/VProgressBar.java index 3eb8725520..8cfc28005c 100644 --- a/client/src/com/vaadin/client/ui/VProgressBar.java +++ b/client/src/com/vaadin/client/ui/VProgressBar.java @@ -21,6 +21,8 @@ import com.google.gwt.user.client.DOM; import com.google.gwt.user.client.Element; import com.google.gwt.user.client.ui.HasEnabled; import com.google.gwt.user.client.ui.Widget; +import com.vaadin.client.ApplicationConnection; +import com.vaadin.shared.ui.progressindicator.ProgressBarState; /** * Widget for showing the current progress of a long running task. @@ -35,26 +37,39 @@ import com.google.gwt.user.client.ui.Widget; */ public class VProgressBar extends Widget implements HasEnabled { - public static final String CLASSNAME = "v-progressindicator"; Element wrapper = DOM.createDiv(); Element indicator = DOM.createDiv(); - protected boolean indeterminate = false; - protected float state = 0.0f; + private boolean indeterminate = false; + private float state = 0.0f; private boolean enabled; public VProgressBar() { setElement(DOM.createDiv()); getElement().appendChild(wrapper); - setStyleName(CLASSNAME); wrapper.appendChild(indicator); - indicator.setClassName(CLASSNAME + "-indicator"); - wrapper.setClassName(CLASSNAME + "-wrapper"); + + setStylePrimaryName(ProgressBarState.PRIMARY_STYLE_NAME); + } + + /* + * (non-Javadoc) + * + * @see + * com.google.gwt.user.client.ui.UIObject#setStylePrimaryName(java.lang. + * String) + */ + @Override + public void setStylePrimaryName(String style) { + super.setStylePrimaryName(style); + indicator.setClassName(getStylePrimaryName() + "-indicator"); + wrapper.setClassName(getStylePrimaryName() + "-wrapper"); + } public void setIndeterminate(boolean indeterminate) { this.indeterminate = indeterminate; - setStyleName(CLASSNAME + "-indeterminate", indeterminate); + setStyleName(getStylePrimaryName() + "-indeterminate", indeterminate); } public void setState(float state) { @@ -78,8 +93,7 @@ public class VProgressBar extends Widget implements HasEnabled { @Override public void setEnabled(boolean enabled) { this.enabled = enabled; - setStyleName("v-disabled", !enabled); - + setStyleName(ApplicationConnection.DISABLED_CLASSNAME, !enabled); } } diff --git a/client/src/com/vaadin/client/ui/VProgressIndicator.java b/client/src/com/vaadin/client/ui/VProgressIndicator.java index 500a5def30..c75113b5f4 100644 --- a/client/src/com/vaadin/client/ui/VProgressIndicator.java +++ b/client/src/com/vaadin/client/ui/VProgressIndicator.java @@ -16,6 +16,8 @@ package com.vaadin.client.ui; +import com.vaadin.shared.ui.progressindicator.ProgressIndicatorState; + /** * * @author Vaadin Ltd @@ -25,4 +27,8 @@ package com.vaadin.client.ui; @Deprecated public class VProgressIndicator extends VProgressBar { + public VProgressIndicator() { + super(); + setStylePrimaryName(ProgressIndicatorState.PRIMARY_STYLE_NAME); + } } diff --git a/shared/src/com/vaadin/shared/ui/progressindicator/ProgressBarState.java b/shared/src/com/vaadin/shared/ui/progressindicator/ProgressBarState.java index fef1030c63..1cc8d7d9ae 100644 --- a/shared/src/com/vaadin/shared/ui/progressindicator/ProgressBarState.java +++ b/shared/src/com/vaadin/shared/ui/progressindicator/ProgressBarState.java @@ -26,7 +26,11 @@ import com.vaadin.shared.communication.SharedState; * @author Vaadin Ltd */ public class ProgressBarState extends AbstractFieldState { + public static final String PRIMARY_STYLE_NAME = "v-progressbar"; + { + primaryStyleName = PRIMARY_STYLE_NAME; + } public boolean indeterminate = false; public Float state = 0.0f; diff --git a/shared/src/com/vaadin/shared/ui/progressindicator/ProgressIndicatorState.java b/shared/src/com/vaadin/shared/ui/progressindicator/ProgressIndicatorState.java index f555476be8..2ca7627f4f 100644 --- a/shared/src/com/vaadin/shared/ui/progressindicator/ProgressIndicatorState.java +++ b/shared/src/com/vaadin/shared/ui/progressindicator/ProgressIndicatorState.java @@ -17,5 +17,11 @@ package com.vaadin.shared.ui.progressindicator; @Deprecated public class ProgressIndicatorState extends ProgressBarState { + public static final String PRIMARY_STYLE_NAME = "v-progressindicator"; + + { + primaryStyleName = PRIMARY_STYLE_NAME; + } + public int pollingInterval = 1000; } diff --git a/uitest/src/com/vaadin/tests/components/AbstractComponentTestCase.java b/uitest/src/com/vaadin/tests/components/AbstractComponentTestCase.java index 81ec4a9da4..8666956bdb 100644 --- a/uitest/src/com/vaadin/tests/components/AbstractComponentTestCase.java +++ b/uitest/src/com/vaadin/tests/components/AbstractComponentTestCase.java @@ -226,6 +226,13 @@ public abstract class AbstractComponentTestCase } }; + protected Command primaryStyleNameCommand = new Command() { + @Override + public void execute(T c, String value, Object data) { + c.setPrimaryStyleName(value); + } + }; + @Override protected String getDescription() { return "Generic test case for " + getTestClass().getSimpleName(); diff --git a/uitest/src/com/vaadin/tests/components/progressindicator/ProgressBarGenericTest.java b/uitest/src/com/vaadin/tests/components/progressindicator/ProgressBarGenericTest.java new file mode 100644 index 0000000000..79797c60a2 --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/progressindicator/ProgressBarGenericTest.java @@ -0,0 +1,55 @@ +package com.vaadin.tests.components.progressindicator; + +import java.util.LinkedHashMap; + +import com.vaadin.tests.components.abstractfield.AbstractFieldTest; +import com.vaadin.ui.ProgressBar; + +public class ProgressBarGenericTest extends AbstractFieldTest { + + private Command indeterminate = new Command() { + + @Override + public void execute(ProgressBar c, Boolean value, Object data) { + c.setIndeterminate(value); + } + }; + + @Override + protected Class getTestClass() { + return ProgressBar.class; + } + + @Override + protected void createActions() { + super.createActions(); + createBooleanAction("Indeterminate", CATEGORY_FEATURES, false, + indeterminate, null); + createValueSelection(CATEGORY_FEATURES); + createPrimaryStyleNameSelect(); + } + + /** + * @since + */ + protected void createPrimaryStyleNameSelect() { + LinkedHashMap options = new LinkedHashMap(); + String primaryStyle = getComponent().getPrimaryStyleName(); + options.put(primaryStyle, primaryStyle); + options.put(primaryStyle + "-foo", primaryStyle + "-foo"); + options.put("foo", "foo"); + createSelectAction("Primary style name", CATEGORY_DECORATIONS, options, + primaryStyle, primaryStyleNameCommand); + + } + + private void createValueSelection(String categorySelection) { + LinkedHashMap options = new LinkedHashMap(); + options.put("null", null); + for (float f = 0; f <= 1; f += 0.1) { + options.put("" + f, f); + } + createSelectAction("Value", categorySelection, options, null, + setValueCommand); + } +} diff --git a/uitest/src/com/vaadin/tests/components/progressindicator/ProgressBarPrimaryStyleName.html b/uitest/src/com/vaadin/tests/components/progressindicator/ProgressBarPrimaryStyleName.html new file mode 100644 index 0000000000..92f678947a --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/progressindicator/ProgressBarPrimaryStyleName.html @@ -0,0 +1,121 @@ + + + + + + +New Test + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
New Test
open/run/com.vaadin.tests.components.progressindicator.ProgressBarGenericTest?restartApplication
assertCSSClassvaadin=runcomvaadintestscomponentsprogressindicatorProgressBarGenericTest::PID_StestComponentv-progressbar
assertCSSClassvaadin=runcomvaadintestscomponentsprogressindicatorProgressBarGenericTest::PID_StestComponent/domChild[0]v-progressbar-wrapper
assertCSSClassvaadin=runcomvaadintestscomponentsprogressindicatorProgressBarGenericTest::PID_StestComponent/domChild[0]/domChild[0]v-progressbar-indicator
mouseClickvaadin=runcomvaadintestscomponentsprogressindicatorProgressBarGenericTest::PID_Smenu#item036,8
mouseClickvaadin=runcomvaadintestscomponentsprogressindicatorProgressBarGenericTest::Root/VOverlay[0]/VMenuBar[0]#item145,4
mouseClickvaadin=runcomvaadintestscomponentsprogressindicatorProgressBarGenericTest::Root/VOverlay[1]/VMenuBar[0]#item667,10
mouseClickvaadin=runcomvaadintestscomponentsprogressindicatorProgressBarGenericTest::Root/VOverlay[2]/VMenuBar[0]#item237,7
assertNotCSSClassvaadin=runcomvaadintestscomponentsprogressindicatorProgressBarGenericTest::PID_StestComponentv-progressbar
assertCSSClassvaadin=runcomvaadintestscomponentsprogressindicatorProgressBarGenericTest::PID_StestComponentfoo
assertNotCSSClassvaadin=runcomvaadintestscomponentsprogressindicatorProgressBarGenericTest::PID_StestComponent/domChild[0]v-progressbar-wrapper
assertCSSClassvaadin=runcomvaadintestscomponentsprogressindicatorProgressBarGenericTest::PID_StestComponent/domChild[0]foo-wrapper
assertNotCSSClassvaadin=runcomvaadintestscomponentsprogressindicatorProgressBarGenericTest::PID_StestComponent/domChild[0]/domChild[0]v-progressbar-indicator
assertCSSClassvaadin=runcomvaadintestscomponentsprogressindicatorProgressBarGenericTest::PID_StestComponent/domChild[0]/domChild[0]foo-indicator
mouseClickvaadin=runcomvaadintestscomponentsprogressindicatorProgressBarGenericTest::PID_Smenu#item020,13
mouseClickvaadin=runcomvaadintestscomponentsprogressindicatorProgressBarGenericTest::Root/VOverlay[0]/VMenuBar[0]#item134,11
mouseClickvaadin=runcomvaadintestscomponentsprogressindicatorProgressBarGenericTest::Root/VOverlay[1]/VMenuBar[0]#item651,4
mouseClickvaadin=runcomvaadintestscomponentsprogressindicatorProgressBarGenericTest::Root/VOverlay[2]/VMenuBar[0]#item038,6
assertCSSClassvaadin=runcomvaadintestscomponentsprogressindicatorProgressBarGenericTest::PID_StestComponentv-progressbar
assertCSSClassvaadin=runcomvaadintestscomponentsprogressindicatorProgressBarGenericTest::PID_StestComponent/domChild[0]v-progressbar-wrapper
assertCSSClassvaadin=runcomvaadintestscomponentsprogressindicatorProgressBarGenericTest::PID_StestComponent/domChild[0]/domChild[0]v-progressbar-indicator
+ + -- cgit v1.2.3 From 86b368948d29bfc482f89a2dc5ebdfbe0697e26c Mon Sep 17 00:00:00 2001 From: Leif Åstrand Date: Thu, 30 May 2013 10:25:23 +0300 Subject: Make ProgressInidcatorConnector use VProgressIndicator (#11925) When ProgressBar was split out from ProgressIndicator, ProgressIndicatorConnector was accidentally left inheriting the VProgressBar widget from ProgressBarConnector instead of using its own VProgressIndicator. Change-Id: Ie7c5d3b68af871d5eb2a86f3d720af3b23048793 --- .../client/ui/progressindicator/ProgressIndicatorConnector.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/client/src/com/vaadin/client/ui/progressindicator/ProgressIndicatorConnector.java b/client/src/com/vaadin/client/ui/progressindicator/ProgressIndicatorConnector.java index 9e14f082e0..23b71868e0 100644 --- a/client/src/com/vaadin/client/ui/progressindicator/ProgressIndicatorConnector.java +++ b/client/src/com/vaadin/client/ui/progressindicator/ProgressIndicatorConnector.java @@ -19,6 +19,7 @@ package com.vaadin.client.ui.progressindicator; import com.google.gwt.user.client.Timer; import com.vaadin.client.communication.StateChangeEvent; import com.vaadin.client.ui.VProgressBar; +import com.vaadin.client.ui.VProgressIndicator; import com.vaadin.shared.ui.Connect; import com.vaadin.shared.ui.progressindicator.ProgressIndicatorServerRpc; import com.vaadin.shared.ui.progressindicator.ProgressIndicatorState; @@ -61,6 +62,11 @@ public class ProgressIndicatorConnector extends ProgressBarConnector { } } + @Override + public VProgressIndicator getWidget() { + return (VProgressIndicator) super.getWidget(); + } + @Override public void onUnregister() { super.onUnregister(); -- cgit v1.2.3 From 29fcadc569c7e45c7d913b18469fbe55b9b7adc3 Mon Sep 17 00:00:00 2001 From: Johannes Dahlström Date: Thu, 30 May 2013 15:42:25 +0300 Subject: Flush the output writer in case of SSE transport as well (#11955) Change-Id: Id0d82eabab63681b9d01c0312588fdfe1659860f --- server/src/com/vaadin/server/communication/PushHandler.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/src/com/vaadin/server/communication/PushHandler.java b/server/src/com/vaadin/server/communication/PushHandler.java index e740db410d..37adc1a108 100644 --- a/server/src/com/vaadin/server/communication/PushHandler.java +++ b/server/src/com/vaadin/server/communication/PushHandler.java @@ -331,9 +331,9 @@ public class PushHandler implements AtmosphereHandler { writer.write(event.getMessage().toString()); switch (resource.transport()) { - case SSE: case WEBSOCKET: break; + case SSE: case STREAMING: writer.flush(); break; -- cgit v1.2.3 From 5e26b0b6d9c97210d97e3e81f1af33feaa4751eb Mon Sep 17 00:00:00 2001 From: Artur Signell Date: Thu, 30 May 2013 16:04:33 +0300 Subject: Fix streaming issue with iOS6 (#11934) It appears that iOS6 will not make new request (at least for images) to a server to which there is already a connection open which possibly will be kept alive after the current request is done (Connection: Keep-alive asked by the client and not denied by the server) Change-Id: If4e6233457fced3760a931b7953fa1713fee3452 --- server/src/com/vaadin/server/communication/PushHandler.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/server/src/com/vaadin/server/communication/PushHandler.java b/server/src/com/vaadin/server/communication/PushHandler.java index 37adc1a108..a44df79221 100644 --- a/server/src/com/vaadin/server/communication/PushHandler.java +++ b/server/src/com/vaadin/server/communication/PushHandler.java @@ -84,6 +84,13 @@ public class PushHandler implements AtmosphereHandler { if (browser.isIE() && browser.getBrowserMajorVersion() == 8) { resource.padding(LONG_PADDING); } + + // Must ensure that the streaming response contains + // "Connection: close", otherwise iOS 6 will wait for the + // response to this request before sending another request to + // the same server (as it will apparently try to reuse the same + // connection) + resource.getResponse().addHeader("Connection", "close"); } String requestToken = resource.getRequest().getParameter( -- cgit v1.2.3 From 1b274c40e6c3a57367e4f012a014a9b86e8ea909 Mon Sep 17 00:00:00 2001 From: Leif Åstrand Date: Wed, 29 May 2013 15:59:06 +0300 Subject: Limit sub window minimum size (#11510) Change-Id: I8ad89e74b058246939d77165f2d4b5abc3417886 --- client/src/com/vaadin/client/ui/VWindow.java | 20 +++++++++++++++++++- .../com/vaadin/client/ui/window/WindowConnector.java | 8 ++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/client/src/com/vaadin/client/ui/VWindow.java b/client/src/com/vaadin/client/ui/VWindow.java index 38dfdba1b8..1331eb106a 100644 --- a/client/src/com/vaadin/client/ui/VWindow.java +++ b/client/src/com/vaadin/client/ui/VWindow.java @@ -38,7 +38,6 @@ import com.google.gwt.user.client.DOM; import com.google.gwt.user.client.Element; import com.google.gwt.user.client.Event; import com.google.gwt.user.client.Window; -import com.google.gwt.user.client.ui.RootPanel; import com.google.gwt.user.client.ui.Widget; import com.vaadin.client.ApplicationConnection; import com.vaadin.client.BrowserInfo; @@ -793,6 +792,9 @@ public class VWindow extends VOverlay implements ShortcutActionHandlerOwner, int w = Util.getTouchOrMouseClientX(event) - startX + origW; int h = Util.getTouchOrMouseClientY(event) - startY + origH; + w = Math.max(w, getMinWidth()); + h = Math.max(h, getMinHeight()); + setWidth(w + "px"); setHeight(h + "px"); @@ -811,6 +813,22 @@ public class VWindow extends VOverlay implements ShortcutActionHandlerOwner, } } + private int getMinHeight() { + return getPixelValue(getElement().getStyle().getProperty("minHeight")); + } + + private int getMinWidth() { + return getPixelValue(getElement().getStyle().getProperty("minWidth")); + } + + private static int getPixelValue(String size) { + if (size == null || !size.endsWith("px")) { + return -1; + } else { + return Integer.parseInt(size.substring(0, size.length() - 2)); + } + } + public void updateContentsSize() { LayoutManager layoutManager = getLayoutManager(); layoutManager.setNeedsMeasure(ConnectorMap.get(client).getConnector( diff --git a/client/src/com/vaadin/client/ui/window/WindowConnector.java b/client/src/com/vaadin/client/ui/window/WindowConnector.java index 90311e30ad..beaf549dcf 100644 --- a/client/src/com/vaadin/client/ui/window/WindowConnector.java +++ b/client/src/com/vaadin/client/ui/window/WindowConnector.java @@ -207,6 +207,14 @@ public class WindowConnector extends AbstractSingleComponentContainerConnector contentStyle.setPaddingBottom(footerHeight, Unit.PX); contentStyle.setMarginBottom(-footerHeight, Unit.PX); + int minWidth = lm.getOuterWidth(window.header) + - lm.getInnerWidth(window.header); + int minHeight = footerHeight + headerHeight; + + getWidget().getElement().getStyle().setPropertyPx("minWidth", minWidth); + getWidget().getElement().getStyle() + .setPropertyPx("minHeight", minHeight); + /* * Must set absolute position if the child has relative height and * there's a chance of horizontal scrolling as some browsers will -- cgit v1.2.3 From 46cc08b5374f2d60de6825e88287da2b83a095c1 Mon Sep 17 00:00:00 2001 From: Leif Åstrand Date: Thu, 30 May 2013 11:55:31 +0300 Subject: Remove workarounds for broken Timer.cancel in IE (#11872) Change-Id: Ib60d6131d36e794bcf72d5f498bb59fafdbf7d0e --- .../com/vaadin/client/ApplicationConnection.java | 8 --- .../src/com/vaadin/client/VLoadingIndicator.java | 57 ++-------------------- .../src/com/vaadin/client/ui/ui/UIConnector.java | 13 ++--- 3 files changed, 6 insertions(+), 72 deletions(-) diff --git a/client/src/com/vaadin/client/ApplicationConnection.java b/client/src/com/vaadin/client/ApplicationConnection.java index 24275dadb9..ed9fe88269 100644 --- a/client/src/com/vaadin/client/ApplicationConnection.java +++ b/client/src/com/vaadin/client/ApplicationConnection.java @@ -3277,14 +3277,6 @@ public class ApplicationConnection { Timer forceHandleMessage = new Timer() { @Override public void run() { - if (responseHandlingLocks.isEmpty()) { - /* - * Timer fired but there's nothing to clear. This can happen - * with IE8 as Timer.cancel is not always effective (see GWT - * issue 8101). - */ - return; - } VConsole.log("WARNING: reponse handling was never resumed, forcibly removing locks..."); responseHandlingLocks.clear(); handlePendingMessages(); diff --git a/client/src/com/vaadin/client/VLoadingIndicator.java b/client/src/com/vaadin/client/VLoadingIndicator.java index fcce35781d..3b6cf2252c 100644 --- a/client/src/com/vaadin/client/VLoadingIndicator.java +++ b/client/src/com/vaadin/client/VLoadingIndicator.java @@ -42,75 +42,24 @@ public class VLoadingIndicator { private int secondDelay = 1500; private int thirdDelay = 5000; - /** - * Timer with method for checking if it has been cancelled. This class is a - * workaround for a IE8 problem which causes a timer to be fired even if it - * has been cancelled. - * - * @author Vaadin Ltd - * @since 7.1 - */ - private abstract static class LoadingIndicatorTimer extends Timer { - private boolean cancelled = false; - - @Override - public void cancel() { - super.cancel(); - cancelled = true; - } - - @Override - public void schedule(int delayMillis) { - super.schedule(delayMillis); - cancelled = false; - } - - @Override - public void scheduleRepeating(int periodMillis) { - super.scheduleRepeating(periodMillis); - cancelled = false; - } - - /** - * Checks if this timer has been cancelled. - * - * @return true if the timer has been cancelled, false otherwise - */ - public boolean isCancelled() { - return cancelled; - } - } - - private Timer firstTimer = new LoadingIndicatorTimer() { + private Timer firstTimer = new Timer() { @Override public void run() { - if (isCancelled()) { - // IE8 does not properly cancel the timer in all cases. - return; - } show(); } }; - private Timer secondTimer = new LoadingIndicatorTimer() { + private Timer secondTimer = new Timer() { @Override public void run() { - if (isCancelled()) { - // IE8 does not properly cancel the timer in all cases. - return; - } getElement().setClassName(PRIMARY_STYLE_NAME); getElement().addClassName("second"); // For backwards compatibility only getElement().addClassName(PRIMARY_STYLE_NAME + "-delay"); } }; - private Timer thirdTimer = new LoadingIndicatorTimer() { + private Timer thirdTimer = new Timer() { @Override public void run() { - if (isCancelled()) { - // IE8 does not properly cancel the timer in all cases. - return; - } getElement().setClassName(PRIMARY_STYLE_NAME); getElement().addClassName("third"); // For backwards compatibility only diff --git a/client/src/com/vaadin/client/ui/ui/UIConnector.java b/client/src/com/vaadin/client/ui/ui/UIConnector.java index 643d687f1d..e734d420f2 100644 --- a/client/src/com/vaadin/client/ui/ui/UIConnector.java +++ b/client/src/com/vaadin/client/ui/ui/UIConnector.java @@ -645,16 +645,9 @@ public class UIConnector extends AbstractSingleComponentContainerConnector pollTimer = new Timer() { @Override public void run() { - /* - * Verify that polling has not recently been canceled. This - * is needed because Timer.cancel() does not always work - * properly in IE 8 until GWT issue 8101 has been fixed. - */ - if (pollTimer != null) { - getRpcProxy(UIServerRpc.class).poll(); - // Send changes even though poll is @Delayed - getConnection().sendPendingVariableChanges(); - } + getRpcProxy(UIServerRpc.class).poll(); + // Send changes even though poll is @Delayed + getConnection().sendPendingVariableChanges(); } }; pollTimer.scheduleRepeating(getState().pollInterval); -- cgit v1.2.3 From d850db60f9f7e144307bcf525d96665d1be64fc8 Mon Sep 17 00:00:00 2001 From: Artur Signell Date: Thu, 30 May 2013 17:01:26 +0300 Subject: Add XML formatting instructions (#11956) Change-Id: Ifac318e1e422d39776196fd8f9b4bb670d504578 --- README.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/README.md b/README.md index 63f39cbb36..808c1ef741 100644 --- a/README.md +++ b/README.md @@ -39,6 +39,15 @@ Set up the Workspace and define required variables for projects ![GWT_TOOLS](http://f.cl.ly/items/1k2Z1n2v0p0y3l0X0D1G/ClasspathVars.png "Defining GWT_TOOLS") 1. Go to Java -> Compiler 1. Check that the compliance level has been set to 1.6 (or higher) +1. Go to XML -> XML Files -> Editor + 1. Ensure the settings are follows: +

Line width: 72
+Format comments: true
+Join lines: true
+Insert whitespace before closing empty end-tags: true
+Indent-using spaces: true
+Indentation size: 4
+
Import the Projects into the Workspace ------------ -- cgit v1.2.3 From 9a3dc4e99c7a417778342db83cd6e7c05558e5fb Mon Sep 17 00:00:00 2001 From: Artur Signell Date: Thu, 30 May 2013 17:06:30 +0300 Subject: Formatted XML files using defined rules (#11956) Change-Id: Iecd621321fdde29d2d89d910ba46e9dadee58995 --- WebContent/WEB-INF/liferay-display.xml | 2 +- WebContent/WEB-INF/liferay-portlet.xml | 6 +- WebContent/WEB-INF/portlet.xml | 116 +- WebContent/WEB-INF/web.xml | 232 ++-- all/build.xml | 249 +++-- all/ivy.xml | 17 +- build.xml | 131 +-- build/common.xml | 80 +- build/ide.xml | 311 +++--- buildhelpers/build.xml | 93 +- buildhelpers/ivy.xml | 2 +- client-compiled/build.xml | 280 ++--- client-compiled/ivy.xml | 4 +- client-compiler/build.xml | 108 +- client-compiler/ivy.xml | 106 +- client/build.xml | 117 +- client/src/com/vaadin/DefaultWidgetSet.gwt.xml | 14 +- client/src/com/vaadin/Vaadin.gwt.xml | 25 +- .../vaadin/VaadinBrowserSpecificOverrides.gwt.xml | 101 +- common.xml | 875 ++++++++------- gwt-files.xml | 370 ++++--- ivy-taskdefs.xml | 38 +- ivysettings.xml | 3 +- publish.xml | 127 ++- push/build.xml | 131 ++- push/ivy.xml | 17 +- server/build.xml | 113 +- server/ivy.xml | 12 +- shared/build.xml | 106 +- theme-compiler/build.xml | 114 +- themes/build.xml | 214 ++-- themes/ivy.xml | 4 +- uitest/build.xml | 301 ++--- uitest/integration_base_files/base.xml | 253 ++--- uitest/integration_tests.xml | 1169 +++++++++++--------- uitest/ivy.xml | 10 +- .../tests/widgetset/TestingWidgetSet.gwt.xml | 15 +- uitest/test.xml | 412 +++---- uitest/vaadin-server.xml | 58 +- 39 files changed, 3327 insertions(+), 3009 deletions(-) diff --git a/WebContent/WEB-INF/liferay-display.xml b/WebContent/WEB-INF/liferay-display.xml index 12a8e4315b..014ed31b47 100644 --- a/WebContent/WEB-INF/liferay-display.xml +++ b/WebContent/WEB-INF/liferay-display.xml @@ -4,6 +4,6 @@ - + \ No newline at end of file diff --git a/WebContent/WEB-INF/liferay-portlet.xml b/WebContent/WEB-INF/liferay-portlet.xml index 5a8d6fac8e..ea060ce44a 100644 --- a/WebContent/WEB-INF/liferay-portlet.xml +++ b/WebContent/WEB-INF/liferay-portlet.xml @@ -4,7 +4,7 @@ JSR286TestPortlet - false + false false @@ -12,7 +12,7 @@ false false - + administrator Administrator @@ -29,5 +29,5 @@ user User - + \ No newline at end of file diff --git a/WebContent/WEB-INF/portlet.xml b/WebContent/WEB-INF/portlet.xml index 45ce1eee83..3a603c43ae 100644 --- a/WebContent/WEB-INF/portlet.xml +++ b/WebContent/WEB-INF/portlet.xml @@ -1,85 +1,79 @@ + version="2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://java.sun.com/xml/ns/portlet/portlet-app_2_0.xsd http://java.sun.com/xml/ns/portlet/portlet-app_2_0.xsd"> - - JSR286TestPortlet - Vaadin Portlet 2.0 Test - com.vaadin.server.VaadinPortlet - - ui - com.vaadin.tests.integration.JSR286Portlet - - - widgetset - com.vaadin.DefaultWidgetSet - - - text/html - view - edit - help - - - Vaadin Portlet 2.0 Test - Vaadin Portlet 2.0 Test - + + JSR286TestPortlet + Vaadin Portlet 2.0 Test + com.vaadin.server.VaadinPortlet + + ui + com.vaadin.tests.integration.JSR286Portlet + + + widgetset + com.vaadin.DefaultWidgetSet + + + text/html + view + edit + help + + + Vaadin Portlet 2.0 Test + Vaadin Portlet 2.0 Test + - - administrator - - - guest - - - power-user - - - user - - + + administrator + + + guest + + + power-user + + + user + + - + Vaadin Liferay Theme Portlet Vaadin Liferay Theme - + com.vaadin.server.LegacyVaadinPortlet application com.vaadin.tests.integration.LiferayThemeDemo - + text/html view - + Vaadin Liferay Theme Vaadin Liferay Theme - + + + administrator + + + guest + - administrator - - - guest - - - power-user - - - user - + power-user + + + user + - + \ No newline at end of file diff --git a/WebContent/WEB-INF/web.xml b/WebContent/WEB-INF/web.xml index 848baea318..ba948968e2 100644 --- a/WebContent/WEB-INF/web.xml +++ b/WebContent/WEB-INF/web.xml @@ -1,134 +1,134 @@ + xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"> - + - Vaadin - Vaadin examples + Vaadin + Vaadin examples - - productionMode - false - + + productionMode + false + - - resourceCacheTime - 3600 - - - Embed App 1 - com.vaadin.server.LegacyVaadinServlet - - application - com.vaadin.tests.components.button.Buttons - - - - Embed App 2 - com.vaadin.server.VaadinServlet - - UI - com.vaadin.tests.components.label.MarginsInLabels - - - - UI provider app - com.vaadin.server.VaadinServlet - - UIProvider - com.vaadin.tests.applicationservlet.InitParamUIProvider - - - UI - com.vaadin.tests.VerifyAssertionsEnabled - - + + resourceCacheTime + 3600 + + + Embed App 1 + com.vaadin.server.LegacyVaadinServlet + + application + com.vaadin.tests.components.button.Buttons + + + + Embed App 2 + com.vaadin.server.VaadinServlet + + UI + com.vaadin.tests.components.label.MarginsInLabels + + + + UI provider app + com.vaadin.server.VaadinServlet + + UIProvider + com.vaadin.tests.applicationservlet.InitParamUIProvider + + + UI + com.vaadin.tests.VerifyAssertionsEnabled + + - - VaadinApplicationRunner - com.vaadin.launcher.ApplicationRunnerServlet - - - legacyPropertyToString - false - - - heartbeatInterval - 301 - - - resourceCacheTime - 3601 - - - closeIdleSessions - true - - - testParam - 42 - - + + VaadinApplicationRunner + com.vaadin.launcher.ApplicationRunnerServlet + + + legacyPropertyToString + false + + + heartbeatInterval + 301 + + + resourceCacheTime + 3601 + + + closeIdleSessions + true + + + testParam + 42 + + - - VaadinApplicationRunnerWithPush - com.vaadin.launcher.ApplicationRunnerServlet - - pushmode - automatic - - true - + + VaadinApplicationRunnerWithPush + com.vaadin.launcher.ApplicationRunnerServlet + + pushmode + automatic + + true + - - - IntegrationTest - com.vaadin.server.VaadinServlet - - UI - com.vaadin.tests.integration.IntegrationTestUI - - true - - - Embed App 1 - /embed1/* - + + + IntegrationTest + com.vaadin.server.VaadinServlet + + UI + com.vaadin.tests.integration.IntegrationTestUI + + true + + + Embed App 1 + /embed1/* + - - Embed App 2 - /embed2/* - + + Embed App 2 + /embed2/* + - - UI provider app - /uiprovider/* - + + UI provider app + /uiprovider/* + - - VaadinApplicationRunner - /run/* - + + VaadinApplicationRunner + /run/* + - - VaadinApplicationRunnerWithPush - /run-push/* - + + VaadinApplicationRunnerWithPush + /run-push/* + - - IntegrationTest - /integration/* - + + IntegrationTest + /integration/* + - - IntegrationTest - /VAADIN/* - + + IntegrationTest + /VAADIN/* + - - index.html - + + index.html + diff --git a/all/build.xml b/all/build.xml index 4e1a557e53..a83d60b382 100644 --- a/all/build.xml +++ b/all/build.xml @@ -1,120 +1,137 @@ - - - Compiles a zip containing all jars + dependencies - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - <h1>${title}</h1> - - ${javadoc.bottom} - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + Compiles a zip containing all jars + dependencies + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + <h1>${title}</h1> + + ${javadoc.bottom} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/all/ivy.xml b/all/ivy.xml index 2b212f6675..3c49e9a884 100644 --- a/all/ivy.xml +++ b/all/ivy.xml @@ -19,21 +19,20 @@ + rev="${vaadin.version}" /> + rev="${vaadin.version}" /> + rev="${vaadin.version}" /> + rev="${vaadin.version}" /> + rev="${vaadin.version}" /> + rev="${vaadin.version}" /> - + rev="${vaadin.version}" /> + diff --git a/build.xml b/build.xml index 37e4afd03b..192d034b9b 100644 --- a/build.xml +++ b/build.xml @@ -1,71 +1,78 @@ - - + + - + - - - - - - + + + + + + - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + - - - - - - Java version is ${ant.java.version} as required. - + + + + + + Java version is ${ant.java.version} as required. + diff --git a/build/common.xml b/build/common.xml index 1fc6349a46..ee60c1ff42 100644 --- a/build/common.xml +++ b/build/common.xml @@ -1,59 +1,65 @@ - - - + xmlns:artifact="antlib:org.apache.maven.artifact.ant" xmlns:ivy="antlib:org.apache.ivy.ant" + name="common" basedir="../" default="init-deps"> + + + - - + + - + - - - - + + + + - - + + + + + + + + + + - - - - - - - - Loading Ant tasks - + - - - - + + + + - - + + - - + uri="antlib:org.apache.maven.artifact.ant" classpathref="taskdefs.classpath" /> + + + classpathref="taskdefs.classpath" /> diff --git a/build/ide.xml b/build/ide.xml index b1845020f3..5380536e2e 100755 --- a/build/ide.xml +++ b/build/ide.xml @@ -1,152 +1,165 @@ - - - - - - - - - - - - - Using gwt files from ${gwt.user.classes} and ${gwt.dev.classes} - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Compiling ${module} to ${module.output.dir} with parameters -logLevel TRACE -style ${style} -localWorkers ${localWorkers} -strict ${extraParams} - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ${vaadinPush.js.contents} - + + + + + + + + + + + + + Using gwt files from ${gwt.user.classes} and + ${gwt.dev.classes} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Compiling ${module} to ${module.output.dir} with + parameters -logLevel TRACE -style ${style} -localWorkers + ${localWorkers} -strict ${extraParams} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ${vaadinPush.js.contents} + \ No newline at end of file diff --git a/buildhelpers/build.xml b/buildhelpers/build.xml index a101bff191..aa1eb8cb0d 100644 --- a/buildhelpers/build.xml +++ b/buildhelpers/build.xml @@ -1,50 +1,51 @@ - - Compiles build helpers used when building other modules. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - WHAT? No JUnit tests for ${module.name}! - + + Compiles build helpers used when building other modules. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + WHAT? No JUnit tests for ${module.name}! + \ No newline at end of file diff --git a/buildhelpers/ivy.xml b/buildhelpers/ivy.xml index 7c0a7b82a7..21c2a808cc 100644 --- a/buildhelpers/ivy.xml +++ b/buildhelpers/ivy.xml @@ -28,7 +28,7 @@ - + diff --git a/client-compiled/build.xml b/client-compiled/build.xml index c9c3244c0e..01bf2fa15e 100644 --- a/client-compiled/build.xml +++ b/client-compiled/build.xml @@ -1,139 +1,149 @@ - - - Compiled (JS+HTML) version of client side - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Creating gwtar files for ${module} in ${gwtar.dir} - - - - - - - - - - - - - - - - - - - - - - - - - - Compiling ${module} to ${module.output.dir} - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - No java files in module - - - - WHAT? No tests for ${module.name}! - + + + Compiled (JS+HTML) version of client side + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Creating gwtar files for ${module} in ${gwtar.dir} + + + + + + + + + + + + + + + + + + + + + + + + + + Compiling ${module} to ${module.output.dir} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + No java files in module + + + + WHAT? No tests for ${module.name}! + diff --git a/client-compiled/ivy.xml b/client-compiled/ivy.xml index 7802775f70..2f1dcfd22f 100644 --- a/client-compiled/ivy.xml +++ b/client-compiled/ivy.xml @@ -14,8 +14,8 @@ - - + + diff --git a/client-compiler/build.xml b/client-compiler/build.xml index cd8433f1cf..0ed4d7b0e3 100644 --- a/client-compiler/build.xml +++ b/client-compiler/build.xml @@ -1,68 +1,70 @@ - - - Compiles build helpers used when building other modules. - - - - + + + Compiles build helpers used when building other modules. + + + + - - - - - - - + + + + + + + - - - - - - + + + + + + - - - - - - - - + + + + + + + + - gwt.version=${vaadin.version} -gwt.svnrev=${git.revision} + gwt.version=${vaadin.version} + gwt.svnrev=${git.revision} - - - + + + - + - - - - - + + + + + - - + + - - - + + + - - - - - + + + + + - - - WHAT? No tests for ${module.name}! - + + + WHAT? No tests for ${module.name}! + \ No newline at end of file diff --git a/client-compiler/ivy.xml b/client-compiler/ivy.xml index 64c0de2830..f66a2e0255 100644 --- a/client-compiler/ivy.xml +++ b/client-compiler/ivy.xml @@ -1,62 +1,64 @@ + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="http://ant.apache.org/ivy/schemas/ivy.xsd" + xmlns:m="http://ant.apache.org/ivy/maven"> - + - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + - - + + - - - - - - - - - - - + + + + + + + + + + + - + - + diff --git a/client/build.xml b/client/build.xml index a2262eed7d..a027d00f60 100644 --- a/client/build.xml +++ b/client/build.xml @@ -1,43 +1,46 @@ - - - Compiles build helpers used when building other modules. - - - - + + + Compiles build helpers used when building other modules. + + + + - - - - + + + + - - - - - + + + + + - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + - - - - +
+ + + - - - - - + + + + + - - + + - - - + + + - - - - - + + + + + - - - + + + \ No newline at end of file diff --git a/client/src/com/vaadin/DefaultWidgetSet.gwt.xml b/client/src/com/vaadin/DefaultWidgetSet.gwt.xml index 26ab7478e0..3aba1f6fee 100755 --- a/client/src/com/vaadin/DefaultWidgetSet.gwt.xml +++ b/client/src/com/vaadin/DefaultWidgetSet.gwt.xml @@ -1,13 +1,13 @@ - + - - + + - + - + diff --git a/client/src/com/vaadin/Vaadin.gwt.xml b/client/src/com/vaadin/Vaadin.gwt.xml index a4eb88d9b4..31eb703e3c 100644 --- a/client/src/com/vaadin/Vaadin.gwt.xml +++ b/client/src/com/vaadin/Vaadin.gwt.xml @@ -12,13 +12,14 @@ - + - + - + @@ -40,19 +41,21 @@ - - + + - - - + + + - - + + - + diff --git a/client/src/com/vaadin/VaadinBrowserSpecificOverrides.gwt.xml b/client/src/com/vaadin/VaadinBrowserSpecificOverrides.gwt.xml index ba6c171a7d..45ede928f5 100644 --- a/client/src/com/vaadin/VaadinBrowserSpecificOverrides.gwt.xml +++ b/client/src/com/vaadin/VaadinBrowserSpecificOverrides.gwt.xml @@ -1,54 +1,55 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/common.xml b/common.xml index c0c5ca5eb5..e46cefd895 100644 --- a/common.xml +++ b/common.xml @@ -1,407 +1,472 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - <h1>${module.name}</h1> - - ${javadoc.bottom} - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ##teamcity[importData type='checkstyle' path='${result.dir.full}/checkstyle-errors.xml'] - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + <h1>${module.name}</h1> + + ${javadoc.bottom} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ##teamcity[importData type='checkstyle' + path='${result.dir.full}/checkstyle-errors.xml'] + + + + + + + + + + diff --git a/gwt-files.xml b/gwt-files.xml index cc4b4a1e96..4f9f746c99 100644 --- a/gwt-files.xml +++ b/gwt-files.xml @@ -1,189 +1,191 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ivy-taskdefs.xml b/ivy-taskdefs.xml index 64d5ec1be1..3c04e5a051 100644 --- a/ivy-taskdefs.xml +++ b/ivy-taskdefs.xml @@ -1,24 +1,24 @@ + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="http://ant.apache.org/ivy/schemas/ivy.xsd"> - - - - - - - - - - - - + + + + + + + + + + + + diff --git a/ivysettings.xml b/ivysettings.xml index 88c38ff33e..6c230b9fd8 100644 --- a/ivysettings.xml +++ b/ivysettings.xml @@ -17,7 +17,8 @@ - + - - - + + + - - - + + + - - - + + + - - - - + + + + - + - + - - - - + + + + - Installing ${src} to ${target} + Installing ${src} to ${target} - - - + + + - - - + + + - - - + + + - - - - - - - + + + + + + + - - - + + + - - - + + + - - - - - - - - - - + + + + + + + + + + \ No newline at end of file diff --git a/push/build.xml b/push/build.xml index 3e750b67cd..ad27599d36 100644 --- a/push/build.xml +++ b/push/build.xml @@ -1,73 +1,84 @@ - - - Meta package which defines dependencies needed for push - - - + + + Meta package which defines dependencies needed for push + + + - - - - + + + + - - - + + + - + - - - - - + + + + + - - - - + + + + - - - - - - - - - - - ${vaadinPush.js.contents} + + + + + + + + + + + ${vaadinPush.js.contents} - - - - - - - - - - - - - - - - + + + + + + + + + - - - + + + + + + - - - - - + + + - - + + + + + + + + \ No newline at end of file diff --git a/push/ivy.xml b/push/ivy.xml index 69b7661fca..e2ba3a63f7 100644 --- a/push/ivy.xml +++ b/push/ivy.xml @@ -4,8 +4,7 @@ xsi:noNamespaceSchemaLocation="http://ant.apache.org/ivy/schemas/ivy.xsd" xmlns:m="http://ant.apache.org/ivy/maven"> - + @@ -15,23 +14,21 @@ - + - + - + - + diff --git a/server/build.xml b/server/build.xml index 1c84c7e6f5..a812404862 100644 --- a/server/build.xml +++ b/server/build.xml @@ -1,60 +1,63 @@ - - - Compiles build helpers used when building other modules. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + Compiles build helpers used when building other modules. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/server/ivy.xml b/server/ivy.xml index 46d9e4c9f5..db7e953371 100644 --- a/server/ivy.xml +++ b/server/ivy.xml @@ -45,8 +45,8 @@ rev="${vaadin.version}" conf="build,test->build" /> - + - + - + diff --git a/shared/build.xml b/shared/build.xml index 8520ee6eba..67dd3e9843 100644 --- a/shared/build.xml +++ b/shared/build.xml @@ -1,64 +1,66 @@ - - - Compiles build helpers used when building other modules. - - - - + + + Compiles build helpers used when building other modules. + + + + - - - - - - - + + + + + + + - - - - - - - - - - - - - + + + + + + + + + + + + + - - - - - + + + + + - - - - - + + + + + - - + + - - - - - - - - - + + + - - - WHAT? No tests for ${module.name}! - + + + + + + + + + WHAT? No tests for ${module.name}! + \ No newline at end of file diff --git a/theme-compiler/build.xml b/theme-compiler/build.xml index 277929d160..b28eca8cf7 100644 --- a/theme-compiler/build.xml +++ b/theme-compiler/build.xml @@ -1,58 +1,64 @@ - - - Compiles build helpers used when building other modules. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + Compiles build helpers used when building other modules. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/themes/build.xml b/themes/build.xml index 75b3e5a903..5bca50e5f5 100644 --- a/themes/build.xml +++ b/themes/build.xml @@ -1,107 +1,115 @@ - - - Themes compiled to CSS - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Compiling ${theme} - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - No java files in module - - - - WHAT? No tests for ${module.name}! - + + + Themes compiled to CSS + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Compiling ${theme} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + No java files in module + + + + WHAT? No tests for ${module.name}! + diff --git a/themes/ivy.xml b/themes/ivy.xml index e0e22429ab..beb1b16a00 100644 --- a/themes/ivy.xml +++ b/themes/ivy.xml @@ -14,8 +14,8 @@ - - + + diff --git a/uitest/build.xml b/uitest/build.xml index 453fc26ea5..dc9258a807 100644 --- a/uitest/build.xml +++ b/uitest/build.xml @@ -1,148 +1,161 @@ - - - Provides a uitest WAR containing Vaadin UI tests - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Compiling ${module} to ${module.output.dir} - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Checkstyle is disabled for uitest for now - - - - WHAT? No JUnit tests for ${module.name}! - + + + Provides a uitest WAR containing Vaadin UI tests + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Compiling ${module} to ${module.output.dir} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Checkstyle is disabled for uitest for now + + + + WHAT? No JUnit tests for ${module.name}! + \ No newline at end of file diff --git a/uitest/integration_base_files/base.xml b/uitest/integration_base_files/base.xml index 5196aecfa9..d8ba018b75 100644 --- a/uitest/integration_base_files/base.xml +++ b/uitest/integration_base_files/base.xml @@ -1,138 +1,143 @@ - + - - - + + + + - - + - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ${server}: Getting the lock + + + + + + + + ${server}: Got the lock + + + + + + + + + + + + ${server}: Released the lock - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ${server}: Getting the lock - - - - - - - - ${server}: Got the lock - - - - - - - - - - - - ${server}: Released the lock - - - - - - + + + + + diff --git a/uitest/integration_tests.xml b/uitest/integration_tests.xml index cb96834307..ba353dbdbb 100644 --- a/uitest/integration_tests.xml +++ b/uitest/integration_tests.xml @@ -1,541 +1,634 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Delaying startup of ${target-server} with ${sleepTime} seconds - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ##teamcity[testStarted name='${target-server}' flowId='${target-server}'] - - - - - - - - - - ##teamcity[testFailed name='${target-server}' flowId='${target-server}' message='Integration test for ${target-server} failed.' details='${tried-escaped}'] - - - ##teamcity[testFinished name='${target-server}' flowId='${target-server}']" - - - - - - - - - - - - - - - - ##teamcity[testStarted name='${target-server}' flowId='${target-server}'] - - - - - - - - - - ##teamcity[testFailed name='${target-server}' flowId='${target-server}' message='Integration test for ${target-server} failed.' details='${tried-escaped}']" - - - ##teamcity[testFinished name='${target-server}' flowId='${target-server}']" - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Delaying startup of ${target-server} with + ${sleepTime} seconds + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ##teamcity[testStarted name='${target-server}' + flowId='${target-server}'] + + + + + + + + + + ##teamcity[testFailed name='${target-server}' + flowId='${target-server}' message='Integration test + for ${target-server} failed.' + details='${tried-escaped}'] + + + ##teamcity[testFinished name='${target-server}' + flowId='${target-server}']" + + + + + + + + + + + + + + + + ##teamcity[testStarted name='${target-server}' + flowId='${target-server}'] + + + + + + + + + + ##teamcity[testFailed name='${target-server}' + flowId='${target-server}' message='Integration test + for ${target-server} failed.' + details='${tried-escaped}']" + + + ##teamcity[testFinished name='${target-server}' + flowId='${target-server}']" + + + + + + + + + + + + + + diff --git a/uitest/ivy.xml b/uitest/ivy.xml index bb54232852..7ff83324ae 100644 --- a/uitest/ivy.xml +++ b/uitest/ivy.xml @@ -14,8 +14,8 @@ - - + + - - + + diff --git a/uitest/src/com/vaadin/tests/widgetset/TestingWidgetSet.gwt.xml b/uitest/src/com/vaadin/tests/widgetset/TestingWidgetSet.gwt.xml index 1b47a86113..fd52e5cd0e 100644 --- a/uitest/src/com/vaadin/tests/widgetset/TestingWidgetSet.gwt.xml +++ b/uitest/src/com/vaadin/tests/widgetset/TestingWidgetSet.gwt.xml @@ -1,15 +1,16 @@ - + + + + - - - - - + + - + diff --git a/uitest/test.xml b/uitest/test.xml index 8228bd9d70..44dac13d90 100644 --- a/uitest/test.xml +++ b/uitest/test.xml @@ -1,189 +1,227 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/uitest/vaadin-server.xml b/uitest/vaadin-server.xml index 5741d78525..4b32cebe26 100644 --- a/uitest/vaadin-server.xml +++ b/uitest/vaadin-server.xml @@ -1,34 +1,38 @@ - - - + + + - - + + - - - - - - - - - - - - - - + + + + + + + + + + + + + + - + - - Waiting for Servlet Container to start up. - - - - - + + Waiting for Servlet Container to start up. + + + + + -- cgit v1.2.3 From 57b7335f647dcb8343d35b975b138c361de28326 Mon Sep 17 00:00:00 2001 From: John Ahlroos Date: Fri, 31 May 2013 09:15:20 +0300 Subject: Fixed spelling mistake in API #11741 Change-Id: I1bf04abd4c49a452f00fb0ab07b20f82ad6d62a2 --- client/src/com/vaadin/client/ui/VRichTextArea.java | 2 +- client/src/com/vaadin/client/ui/richtextarea/RichTextAreaConnector.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/client/src/com/vaadin/client/ui/VRichTextArea.java b/client/src/com/vaadin/client/ui/VRichTextArea.java index 7ed6e7c78a..8a6ba3fc1e 100644 --- a/client/src/com/vaadin/client/ui/VRichTextArea.java +++ b/client/src/com/vaadin/client/ui/VRichTextArea.java @@ -395,7 +395,7 @@ public class VRichTextArea extends Composite implements Field, KeyPressHandler, * * @return cleaned html string */ - public String getSanitazedValue() { + public String getSanitizedValue() { BrowserInfo browser = BrowserInfo.get(); String result = getValue(); if (browser.isFirefox()) { diff --git a/client/src/com/vaadin/client/ui/richtextarea/RichTextAreaConnector.java b/client/src/com/vaadin/client/ui/richtextarea/RichTextAreaConnector.java index 8135777c0a..20dfc74c69 100644 --- a/client/src/com/vaadin/client/ui/richtextarea/RichTextAreaConnector.java +++ b/client/src/com/vaadin/client/ui/richtextarea/RichTextAreaConnector.java @@ -102,7 +102,7 @@ public class RichTextAreaConnector extends AbstractFieldConnector implements @Override public void flush() { if (getConnection() != null && getConnectorId() != null) { - final String html = getWidget().getSanitazedValue(); + final String html = getWidget().getSanitizedValue(); if (!html.equals(cachedValue)) { getConnection().updateVariable(getConnectorId(), "text", html, getState().immediate); -- cgit v1.2.3 From 587e10b92dbaf3e90b288ead55a5b83f54743bd2 Mon Sep 17 00:00:00 2001 From: Leif Åstrand Date: Fri, 31 May 2013 09:44:56 +0300 Subject: Fix stale info in javadoc for accessSynchronously (#11897) Change-Id: I0d562a5f617850e2e862f86758dbca0fc4c947a0 --- server/src/com/vaadin/server/VaadinSession.java | 4 ---- server/src/com/vaadin/ui/UI.java | 4 ---- 2 files changed, 8 deletions(-) diff --git a/server/src/com/vaadin/server/VaadinSession.java b/server/src/com/vaadin/server/VaadinSession.java index b4afc914eb..9ef3d33195 100644 --- a/server/src/com/vaadin/server/VaadinSession.java +++ b/server/src/com/vaadin/server/VaadinSession.java @@ -1127,10 +1127,6 @@ public class VaadinSession implements HttpSessionBindingListener, Serializable { * {@link #accessSynchronously(Runnable)} blocks while waiting for the lock * to be available whereas {@link #access(Runnable)} defers the task to a * later point in time. - *
  • If this session is currently not locked, - * {@link #accessSynchronously(Runnable)} runs the task right away whereas - * {@link #access(Runnable)} defers the task to a later point in time unless - * there are UIs with automatic push enabled.
  • * *

    * diff --git a/server/src/com/vaadin/ui/UI.java b/server/src/com/vaadin/ui/UI.java index 706f7c436b..d1d8dd1df1 100644 --- a/server/src/com/vaadin/ui/UI.java +++ b/server/src/com/vaadin/ui/UI.java @@ -1123,10 +1123,6 @@ public abstract class UI extends AbstractSingleComponentContainer implements * {@link #accessSynchronously(Runnable)} blocks while waiting for the lock * to be available whereas {@link #access(Runnable)} defers the task to a * later point in time. - *
  • If the session is currently not locked, - * {@link #accessSynchronously(Runnable)} runs the task right away whereas - * {@link #access(Runnable)} defers the task to a later point in time unless - * there are UIs with automatic push enabled.
  • * *

    * -- cgit v1.2.3 From 36fd94ad9a72db9d2368ea08d69d636c00eea1c4 Mon Sep 17 00:00:00 2001 From: Artur Signell Date: Thu, 30 May 2013 13:28:04 +0300 Subject: Remove IE6/IE7 permutation (#11954) Change-Id: Id6eae2e71f322d9750c95b381eefd28e41624139 --- client/src/com/vaadin/Vaadin.gwt.xml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/client/src/com/vaadin/Vaadin.gwt.xml b/client/src/com/vaadin/Vaadin.gwt.xml index 31eb703e3c..776886bb1b 100644 --- a/client/src/com/vaadin/Vaadin.gwt.xml +++ b/client/src/com/vaadin/Vaadin.gwt.xml @@ -60,4 +60,7 @@ + + +
    -- cgit v1.2.3 From cccff37c0c679515491a2cdd4244dbcd7e038629 Mon Sep 17 00:00:00 2001 From: Artur Signell Date: Fri, 31 May 2013 13:46:27 +0300 Subject: Do not log legacy warnings in JUnit tests (#11963) Change-Id: I5549a524d7fae32b1ef201073ab48cadcc4e8212 --- server/src/com/vaadin/data/util/LegacyPropertyHelper.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/server/src/com/vaadin/data/util/LegacyPropertyHelper.java b/server/src/com/vaadin/data/util/LegacyPropertyHelper.java index 3eb22524f8..551d7223d6 100644 --- a/server/src/com/vaadin/data/util/LegacyPropertyHelper.java +++ b/server/src/com/vaadin/data/util/LegacyPropertyHelper.java @@ -77,8 +77,8 @@ public class LegacyPropertyHelper implements Serializable { */ public static boolean isLegacyToStringEnabled() { if (VaadinService.getCurrent() == null) { - // This should really not happen but we need to handle it somehow. - // IF it happens it seems more safe to use the legacy mode and log. + // This will happen at least in JUnit tests. We do not what the real + // value should be but it seems more safe to use the legacy mode. return true; } return VaadinService.getCurrent().getDeploymentConfiguration() @@ -87,9 +87,9 @@ public class LegacyPropertyHelper implements Serializable { private static boolean logLegacyToStringWarning() { if (VaadinService.getCurrent() == null) { - // This should really not happen but we need to handle it somehow. - // IF it happens it seems more safe to use the legacy mode and log. - return true; + // This will happen at least in JUnit tests. We do not want to spam + // the log with these messages in this case. + return false; } return VaadinService.getCurrent().getDeploymentConfiguration() .getLegacyPropertyToStringMode() == LegacyProperyToStringMode.WARNING; -- cgit v1.2.3 From 0f9b689130aa1fc1405cc10cf2d840bc98298eec Mon Sep 17 00:00:00 2001 From: Leif Åstrand Date: Fri, 31 May 2013 13:36:20 +0300 Subject: Throw exception if VaadinService has not been initialized (#11961) Change-Id: I754c73790aae197a262d6cc8b88751290efbe127 --- server/src/com/vaadin/server/VaadinService.java | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/server/src/com/vaadin/server/VaadinService.java b/server/src/com/vaadin/server/VaadinService.java index 2cb7f9059e..f9b17537df 100644 --- a/server/src/com/vaadin/server/VaadinService.java +++ b/server/src/com/vaadin/server/VaadinService.java @@ -109,6 +109,11 @@ public abstract class VaadinService implements Serializable { */ private boolean pushWarningEmitted = false; + /** + * Has {@link #init()} been run? + */ + private boolean initialized = false; + /** * Creates a new vaadin service based on a deployment configuration * @@ -148,6 +153,8 @@ public abstract class VaadinService implements Serializable { List handlers = createRequestHandlers(); Collections.reverse(handlers); requestHandlers = Collections.unmodifiableCollection(handlers); + + initialized = true; } /** @@ -1224,6 +1231,10 @@ public abstract class VaadinService implements Serializable { * The response */ public void requestStart(VaadinRequest request, VaadinResponse response) { + if (!initialized) { + throw new IllegalStateException( + "Can not process requests before init() has been called"); + } setCurrentInstances(request, response); request.setAttribute(REQUEST_START_TIME_ATTRIBUTE, System.nanoTime()); } -- cgit v1.2.3 From 1ed09802b376c61bef15579ff4ca9261dffff927 Mon Sep 17 00:00:00 2001 From: Leif Åstrand Date: Fri, 31 May 2013 15:26:11 +0300 Subject: Move ApplicationConnection.setOverlayContainerLabel to VOverlay (#11965) Change-Id: I747097fe7be8872f6c2ab04b272f88677b6e0663 --- .../src/com/vaadin/client/ApplicationConnection.java | 16 ++-------------- client/src/com/vaadin/client/ui/VOverlay.java | 18 ++++++++++++++++++ client/src/com/vaadin/client/ui/ui/UIConnector.java | 3 ++- 3 files changed, 22 insertions(+), 15 deletions(-) diff --git a/client/src/com/vaadin/client/ApplicationConnection.java b/client/src/com/vaadin/client/ApplicationConnection.java index ed9fe88269..2f5401a75b 100644 --- a/client/src/com/vaadin/client/ApplicationConnection.java +++ b/client/src/com/vaadin/client/ApplicationConnection.java @@ -466,7 +466,8 @@ public class ApplicationConnection { Element overlayContainer = VOverlay.getOverlayContainer(this); Roles.getAlertRole().setAriaLiveProperty(overlayContainer, LiveValue.ASSERTIVE); - setOverlayContainerLabel(getUIConnector().getState().overlayContainerLabel); + VOverlay.setOverlayContainerLabel(this, + getUIConnector().getState().overlayContainerLabel); Roles.getAlertRole().setAriaRelevantProperty(overlayContainer, RelevantValue.ADDITIONS); } @@ -3433,17 +3434,4 @@ public class ApplicationConnection { public void handlePushMessage(String message) { handleJSONText(message, 200); } - - /** - * Set the label of the container element, where tooltip, notification and - * dialgs are added to. - * - * @param overlayContainerLabel - * label for the container - */ - public void setOverlayContainerLabel(String overlayContainerLabel) { - Roles.getAlertRole().setAriaLabelProperty( - VOverlay.getOverlayContainer(this), - getUIConnector().getState().overlayContainerLabel); - } } diff --git a/client/src/com/vaadin/client/ui/VOverlay.java b/client/src/com/vaadin/client/ui/VOverlay.java index 9e809758ca..ced476f9dd 100644 --- a/client/src/com/vaadin/client/ui/VOverlay.java +++ b/client/src/com/vaadin/client/ui/VOverlay.java @@ -17,6 +17,7 @@ package com.vaadin.client.ui; import com.google.gwt.animation.client.Animation; +import com.google.gwt.aria.client.Roles; import com.google.gwt.dom.client.Document; import com.google.gwt.dom.client.IFrameElement; import com.google.gwt.dom.client.Style; @@ -690,6 +691,23 @@ public class VOverlay extends PopupPanel implements CloseHandler { return container; } + /** + * Set the label of the container element, where tooltip, notification and + * dialgs are added to. + * + * @param applicationConnection + * the application connection for which to change the label + * @param overlayContainerLabel + * label for the container + */ + public static void setOverlayContainerLabel( + ApplicationConnection applicationConnection, + String overlayContainerLabel) { + Roles.getAlertRole().setAriaLabelProperty( + VOverlay.getOverlayContainer(applicationConnection), + overlayContainerLabel); + } + @Override public void center() { super.center(); diff --git a/client/src/com/vaadin/client/ui/ui/UIConnector.java b/client/src/com/vaadin/client/ui/ui/UIConnector.java index e734d420f2..bba9252d47 100644 --- a/client/src/com/vaadin/client/ui/ui/UIConnector.java +++ b/client/src/com/vaadin/client/ui/ui/UIConnector.java @@ -58,6 +58,7 @@ import com.vaadin.client.ui.AbstractSingleComponentContainerConnector; import com.vaadin.client.ui.ClickEventHandler; import com.vaadin.client.ui.ShortcutActionHandler; import com.vaadin.client.ui.VNotification; +import com.vaadin.client.ui.VOverlay; import com.vaadin.client.ui.VUI; import com.vaadin.client.ui.layout.MayScrollChildren; import com.vaadin.client.ui.window.WindowConnector; @@ -631,7 +632,7 @@ public class UIConnector extends AbstractSingleComponentContainerConnector } if (stateChangeEvent.hasPropertyChanged("overlayContainerLabel")) { - getConnection().setOverlayContainerLabel( + VOverlay.setOverlayContainerLabel(getConnection(), getState().overlayContainerLabel); } } -- cgit v1.2.3 From 0014563d493b4c40db4aa7255b00a3224637d10a Mon Sep 17 00:00:00 2001 From: Artur Signell Date: Thu, 30 May 2013 18:04:41 +0300 Subject: Extracted dialog style to a separate block (#11734) Change-Id: I3f57188cde30122b56bb6f8cea435cd4c56b58e2 --- WebContent/VAADIN/themes/runo/window/window.scss | 48 ++++++++++++------------ 1 file changed, 25 insertions(+), 23 deletions(-) diff --git a/WebContent/VAADIN/themes/runo/window/window.scss b/WebContent/VAADIN/themes/runo/window/window.scss index d2048e027e..302cb69877 100644 --- a/WebContent/VAADIN/themes/runo/window/window.scss +++ b/WebContent/VAADIN/themes/runo/window/window.scss @@ -99,30 +99,32 @@ /* Dialog style */ .#{$primaryStyleName}-dialog { background-image: url(img/dialog/bottom-left.png); + + .#{$primaryStyleName}-outerheader { + height: 32px; + padding: 13px 30px 5px 8px; + background: transparent url(img/top-right.png) no-repeat right top; + } + .#{$primaryStyleName}-header { + font-size: 12px; + line-height: normal; + font-weight: bold; + letter-spacing: 0; + text-shadow: 0 1px 0 #fff; + } + .#{$primaryStyleName}-contents > div { + background: #f1f3f3; + } + div.#{$primaryStyleName}-footer { + background-image: url(img/dialog/bottom-right.png); + } + .#{$primaryStyleName}-closebox { + top: 14px; + right: 16px; + background-image: url(img/dialog/close.png); + } } -.#{$primaryStyleName}-dialog .#{$primaryStyleName}-outerheader { - height: 32px; - padding: 13px 30px 5px 8px; - background: transparent url(img/top-right.png) no-repeat right top; -} -.#{$primaryStyleName}-dialog .#{$primaryStyleName}-header { - font-size: 12px; - line-height: normal; - font-weight: bold; - letter-spacing: 0; - text-shadow: 0 1px 0 #fff; -} -.#{$primaryStyleName}-dialog .#{$primaryStyleName}-contents > div { - background: #f1f3f3; -} -.#{$primaryStyleName}-dialog div.#{$primaryStyleName}-footer { - background-image: url(img/dialog/bottom-right.png); -} -.#{$primaryStyleName}-dialog .#{$primaryStyleName}-closebox { - top: 14px; - right: 16px; - background-image: url(img/dialog/close.png); -} + /* Shadow for window */ .v-shadow-window .top-left { top: -13px; left: -20px; -- cgit v1.2.3 From b82e60b8d6315b4d6e9e62ebf72fc0c09ebd42d2 Mon Sep 17 00:00:00 2001 From: Artur Signell Date: Thu, 30 May 2013 18:07:39 +0300 Subject: Add missing dialog maximize/restore icons for Runo (#11734) Change-Id: If8ebbdb7cd8e6a6acfb15fcdc48a41489ab059c6 --- .../themes/runo/window/img/dialog/maximize.png | Bin 0 -> 268 bytes .../themes/runo/window/img/dialog/restore.png | Bin 0 -> 262 bytes WebContent/VAADIN/themes/runo/window/window.scss | 25 ++++++++++++++++++++- 3 files changed, 24 insertions(+), 1 deletion(-) create mode 100644 WebContent/VAADIN/themes/runo/window/img/dialog/maximize.png create mode 100644 WebContent/VAADIN/themes/runo/window/img/dialog/restore.png diff --git a/WebContent/VAADIN/themes/runo/window/img/dialog/maximize.png b/WebContent/VAADIN/themes/runo/window/img/dialog/maximize.png new file mode 100644 index 0000000000..cbbc0f6691 Binary files /dev/null and b/WebContent/VAADIN/themes/runo/window/img/dialog/maximize.png differ diff --git a/WebContent/VAADIN/themes/runo/window/img/dialog/restore.png b/WebContent/VAADIN/themes/runo/window/img/dialog/restore.png new file mode 100644 index 0000000000..a4e9d257e1 Binary files /dev/null and b/WebContent/VAADIN/themes/runo/window/img/dialog/restore.png differ diff --git a/WebContent/VAADIN/themes/runo/window/window.scss b/WebContent/VAADIN/themes/runo/window/window.scss index 302cb69877..1a7cfd3b01 100644 --- a/WebContent/VAADIN/themes/runo/window/window.scss +++ b/WebContent/VAADIN/themes/runo/window/window.scss @@ -57,7 +57,6 @@ position: absolute; top: 21px; height: 12px; - background: transparent url(img/close.png); } .#{$primaryStyleName}-closebox { width: 12px; @@ -123,6 +122,30 @@ right: 16px; background-image: url(img/dialog/close.png); } + + .#{$primaryStyleName}-restorebox { + width: 12px; + height: 12px; + top: 15px; + right: 32px; + + background: transparent url(img/dialog/restore.png); + &:hover { + background-position: 0 -12px; + } + } + + .#{$primaryStyleName}-maximizebox { + width: 11px; + height: 10px; + top: 15px; + right: 32px; + + background: transparent url(img/dialog/maximize.png); + &:hover { + background-position: 0 -10px; + } + } } /* Shadow for window */ -- cgit v1.2.3 From 0d046d61c0c76073624feef7780256cb61561ce4 Mon Sep 17 00:00:00 2001 From: Leif Åstrand Date: Thu, 16 May 2013 16:51:33 +0300 Subject: Add a separate debug window section for profiler output (#11950) Change-Id: I115f440d6dda5fac0788d3376f01e405e413c482 --- .../vaadin/client/ApplicationConfiguration.java | 4 + client/src/com/vaadin/client/Profiler.java | 245 ++++----------- .../client/debug/internal/ProfilerSection.java | 336 +++++++++++++++++++++ 3 files changed, 400 insertions(+), 185 deletions(-) create mode 100644 client/src/com/vaadin/client/debug/internal/ProfilerSection.java diff --git a/client/src/com/vaadin/client/ApplicationConfiguration.java b/client/src/com/vaadin/client/ApplicationConfiguration.java index adf5e1de9d..9152e5ab23 100644 --- a/client/src/com/vaadin/client/ApplicationConfiguration.java +++ b/client/src/com/vaadin/client/ApplicationConfiguration.java @@ -38,6 +38,7 @@ import com.vaadin.client.debug.internal.ErrorNotificationHandler; import com.vaadin.client.debug.internal.HierarchySection; import com.vaadin.client.debug.internal.LogSection; import com.vaadin.client.debug.internal.NetworkSection; +import com.vaadin.client.debug.internal.ProfilerSection; import com.vaadin.client.debug.internal.Section; import com.vaadin.client.debug.internal.VDebugWindow; import com.vaadin.client.metadata.BundleLoadCallback; @@ -578,6 +579,9 @@ public class ApplicationConfiguration implements EntryPoint { } window.addSection((Section) GWT.create(HierarchySection.class)); window.addSection((Section) GWT.create(NetworkSection.class)); + if (Profiler.isEnabled()) { + window.addSection((Section) GWT.create(ProfilerSection.class)); + } if (isQuietDebugMode()) { window.close(); diff --git a/client/src/com/vaadin/client/Profiler.java b/client/src/com/vaadin/client/Profiler.java index 95b3232723..caa512b34e 100644 --- a/client/src/com/vaadin/client/Profiler.java +++ b/client/src/com/vaadin/client/Profiler.java @@ -23,13 +23,14 @@ import java.util.HashMap; import java.util.LinkedHashMap; import java.util.LinkedList; import java.util.Map; +import java.util.logging.Logger; import com.google.gwt.core.client.Duration; import com.google.gwt.core.client.JavaScriptObject; import com.google.gwt.core.client.JsArray; import com.google.gwt.core.shared.GWT; -import com.google.gwt.user.client.ui.Label; -import com.google.gwt.user.client.ui.Widget; +import com.vaadin.client.debug.internal.ProfilerSection.Node; +import com.vaadin.client.debug.internal.ProfilerSection.ProfilerResultConsumer; /** * Lightweight profiling tool that can be used to collect profiling data with @@ -96,137 +97,7 @@ public class Profiler { } } - private static class Node { - - private final String name; - private final LinkedHashMap children = new LinkedHashMap(); - private double time = 0; - private int count = 0; - - public Node(String name) { - this.name = name; - } - - public String getName() { - return name; - } - - private Node accessChild(String name, double time) { - Node child = children.get(name); - if (child == null) { - child = new Node(name); - children.put(name, child); - } - child.time -= time; - child.count++; - return child; - } - - public double getTimeSpent() { - return time; - } - - public int getCount() { - return count; - } - - public double getOwnTime() { - double time = getTimeSpent(); - for (Node node : children.values()) { - time -= node.getTimeSpent(); - } - return time; - } - - public Widget buildTree() { - String message = getStringRepresentation(""); - - if (getName() == null || !children.isEmpty()) { - SimpleTree tree = new SimpleTree(message); - for (Node node : children.values()) { - Widget child = node.buildTree(); - tree.add(child); - } - return tree; - } else { - return new Label(message); - } - } - - public void buildRecursiveString(StringBuilder builder, String prefix) { - if (getName() != null) { - String msg = getStringRepresentation(prefix); - builder.append(msg + '\n'); - } - String childPrefix = prefix + "*"; - for (Node node : children.values()) { - node.buildRecursiveString(builder, childPrefix); - } - } - - @Override - public String toString() { - return getStringRepresentation(""); - } - - private String getStringRepresentation(String prefix) { - if (getName() == null) { - return ""; - } - String msg = prefix + " " + getName() + " in " + getTimeSpent() - + " ms."; - if (getCount() > 1) { - msg += " Invoked " - + getCount() - + " times (" - + roundToSignificantFigures(getTimeSpent() / getCount()) - + " ms per time)."; - } - if (!children.isEmpty()) { - double ownTime = getOwnTime(); - msg += " " + ownTime + " ms spent in own code"; - if (getCount() > 1) { - msg += " (" - + roundToSignificantFigures(ownTime / getCount()) - + " ms per time)"; - } - msg += '.'; - } - return msg; - } - - public static double roundToSignificantFigures(double num) { - // Number of significant digits - int n = 3; - if (num == 0) { - return 0; - } - - final double d = Math.ceil(Math.log10(num < 0 ? -num : num)); - final int power = n - (int) d; - - final double magnitude = Math.pow(10, power); - final long shifted = Math.round(num * magnitude); - return shifted / magnitude; - } - - public void sumUpTotals(Map totals) { - String name = getName(); - if (name != null) { - Node totalNode = totals.get(name); - if (totalNode == null) { - totalNode = new Node(name); - totals.put(name, totalNode); - } - - totalNode.time += getOwnTime(); - totalNode.count += getCount(); - } - for (Node node : children.values()) { - node.sumUpTotals(totals); - } - } - } + private static ProfilerResultConsumer consumer; /** * Checks whether the profiling gathering is enabled. @@ -323,7 +194,8 @@ public class Profiler { */ public static void logTimings() { if (!isEnabled()) { - VConsole.log("Profiler is not enabled, no data has been collected."); + getLogger().warning( + "Profiler is not enabled, no data has been collected."); return; } @@ -332,7 +204,9 @@ public class Profiler { stack.add(rootNode); JsArray gwtStatsEvents = getGwtStatsEvents(); if (gwtStatsEvents.length() == 0) { - VConsole.log("No profiling events recorded, this might happen if another __gwtStatsEvent handler is installed."); + getLogger() + .warning( + "No profiling events recorded, this might happen if another __gwtStatsEvent handler is installed."); return; } @@ -347,10 +221,10 @@ public class Profiler { && !isBeginEvent; if (!inEvent && stack.size() >= 2 - && eventName.equals(stack.get(stack.size() - 2).name) + && eventName.equals(stack.get(stack.size() - 2).getName()) && !isBeginEvent) { // back out of sub event - stackTop.time += gwtStatsEvent.getMillis(); + stackTop.addTime(gwtStatsEvent.getMillis()); stack.removeLast(); stackTop = stack.getLast(); @@ -359,41 +233,35 @@ public class Profiler { if (type.equals("end")) { if (!inEvent) { - VConsole.error("Got end event for " + eventName - + " but is currently in " + stackTop.getName()); + getLogger().severe( + "Got end event for " + eventName + + " but is currently in " + + stackTop.getName()); return; } Node previousStackTop = stack.removeLast(); - previousStackTop.time += gwtStatsEvent.getMillis(); + previousStackTop.addTime(gwtStatsEvent.getMillis()); } else { if (!inEvent) { - stackTop = stackTop.accessChild(eventName, + stackTop = stackTop.enterChild(eventName, gwtStatsEvent.getMillis()); stack.add(stackTop); } if (!isBeginEvent) { // Create sub event - stack.add(stackTop.accessChild(eventName + "." + type, + stack.add(stackTop.enterChild(eventName + "." + type, gwtStatsEvent.getMillis())); } } } if (stack.size() != 1) { - VConsole.log("Not all nodes are left, the last node is " - + stack.getLast().getName()); + getLogger().warning( + "Not all nodes are left, the last node is " + + stack.getLast().getName()); return; } - StringBuilder stringBuilder = new StringBuilder(); - rootNode.buildRecursiveString(stringBuilder, ""); - - /* - * Should really output to a separate section in the debug window, but - * just dump it to the log for now. - */ - VConsole.log(stringBuilder.toString()); - Map totals = new HashMap(); rootNode.sumUpTotals(totals); @@ -405,27 +273,7 @@ public class Profiler { } }); - double total = 0; - double top20total = 0; - for (int i = 0; i < totalList.size(); i++) { - Node node = totalList.get(i); - double timeSpent = node.getTimeSpent(); - total += timeSpent; - if (i < 20) { - top20total += timeSpent; - } - } - - VConsole.log("Largest individual contributors using " + top20total - + " ms out of " + total + " ms"); - for (int i = 0; i < 20 && i < totalList.size(); i++) { - Node node = totalList.get(i); - double timeSpent = node.getTimeSpent(); - total += timeSpent; - VConsole.log(" * " + node.getName() + ": " + timeSpent + " ms in " - + node.getCount() + " invokations."); - } - + getConsumer().addProfilerData(stack.getFirst(), totalList); } /** @@ -460,28 +308,24 @@ public class Profiler { "domContentLoadedEventStart", "domContentLoadedEventEnd", "domComplete", "loadEventStart", "loadEventEnd" }; + LinkedHashMap timings = new LinkedHashMap(); + for (String key : keys) { double value = getPerformanceTiming(key); if (value == 0) { // Ignore missing value continue; } - String text = key + ": " + (now - value); - tree.add(new Label(text)); - stringBuilder.append("\n * "); - stringBuilder.append(text); + timings.put(key, Double.valueOf(now - value)); } - if (tree.getWidgetCount() == 0) { - VConsole.log("Bootstrap timings not supported, please ensure your browser supports performance.timing"); + if (timings.isEmpty()) { + getLogger() + .info("Bootstrap timings not supported, please ensure your browser supports performance.timing"); return; } - /* - * Should really output to a separate section in the debug window, - * but just dump it to the log for now. - */ - VConsole.log(stringBuilder.toString()); + getConsumer().addBootstrapData(timings); } } @@ -535,4 +379,35 @@ public class Profiler { $wnd.vaadin.gwtStatsEvents = []; }-*/; + /** + * Sets the profiler result consumer that is used to output the profiler + * data to the user. + *

    + * Warning! This is internal API and should not be used by + * applications or add-ons. + * + * @since 7.1 + * @param profilerResultConsumer + * the consumer that gets profiler data + */ + public static void setProfilerResultConsuer( + ProfilerResultConsumer profilerResultConsumer) { + if (consumer != null) { + throw new IllegalStateException("The consumer has already been set"); + } + consumer = profilerResultConsumer; + } + + private static ProfilerResultConsumer getConsumer() { + if (consumer == null) { + throw new IllegalStateException("No consumer has been registered"); + } else { + return consumer; + } + } + + private static Logger getLogger() { + return Logger.getLogger(Profiler.class.getName()); + } + } diff --git a/client/src/com/vaadin/client/debug/internal/ProfilerSection.java b/client/src/com/vaadin/client/debug/internal/ProfilerSection.java new file mode 100644 index 0000000000..f9d401de88 --- /dev/null +++ b/client/src/com/vaadin/client/debug/internal/ProfilerSection.java @@ -0,0 +1,336 @@ +package com.vaadin.client.debug.internal; + +import java.util.Collection; +import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; + +import com.google.gwt.user.client.ui.FlowPanel; +import com.google.gwt.user.client.ui.HorizontalPanel; +import com.google.gwt.user.client.ui.Label; +import com.google.gwt.user.client.ui.Widget; +import com.vaadin.client.ApplicationConnection; +import com.vaadin.client.Profiler; +import com.vaadin.client.SimpleTree; +import com.vaadin.client.ValueMap; + +/** + * Debug window section for investigating {@link Profiler} data. This section is + * only visible if the profiler is enabled ({@link Profiler#isEnabled()}). + * + * @since 7.1 + * @author Vaadin Ltd + * + * @see Profiler + */ +public class ProfilerSection implements Section { + /** + * Interface for getting data from the {@link Profiler}. + *

    + * Warning! This interface is most likely to change in the future and + * is therefore defined in this class in an internal package instead of + * Profiler where it might seem more logical. + * + * @since 7.1 + * @author Vaadin Ltd + */ + public interface ProfilerResultConsumer { + public void addProfilerData(Node rootNode, List totals); + + public void addBootstrapData(LinkedHashMap timings); + } + + /** + * A hierarchical representation of the time spent running a named block of + * code. + *

    + * Warning! This class is most likely to change in the future and is + * therefore defined in this class in an internal package instead of + * Profiler where it might seem more logical. + */ + public static class Node { + private final String name; + private final LinkedHashMap children = new LinkedHashMap(); + private double time = 0; + private int count = 0; + + /** + * Create a new node with the given name. + * + * @param name + */ + public Node(String name) { + this.name = name; + } + + /** + * Gets the name of the node + * + * @return the name of the node + */ + public String getName() { + return name; + } + + /** + * Creates a new child node or retrieves and existing child and updates + * its total time and hit count. + * + * @param name + * the name of the child + * @param time + * the timestamp for when the node is entered + * @return the child node object + */ + public Node enterChild(String name, double time) { + Node child = children.get(name); + if (child == null) { + child = new Node(name); + children.put(name, child); + } + child.time -= time; + child.count++; + return child; + } + + /** + * Gets the total time spent in this node, including time spent in sub + * nodes + * + * @return the total time spent, in milliseconds + */ + public double getTimeSpent() { + return time; + } + + /** + * Gets the number of times this node has been entered + * + * @return the number of times the node has been entered + */ + public int getCount() { + return count; + } + + /** + * Gets the total time spent in this node, excluding time spent in sub + * nodes + * + * @return the total time spent, in milliseconds + */ + public double getOwnTime() { + double time = getTimeSpent(); + for (Node node : children.values()) { + time -= node.getTimeSpent(); + } + return time; + } + + /** + * Gets the child nodes of this node + * + * @return a collection of child nodes + */ + public Collection getChildren() { + return Collections.unmodifiableCollection(children.values()); + } + + private void buildRecursiveString(StringBuilder builder, String prefix) { + if (getName() != null) { + String msg = getStringRepresentation(prefix); + builder.append(msg + '\n'); + } + String childPrefix = prefix + "*"; + for (Node node : children.values()) { + node.buildRecursiveString(builder, childPrefix); + } + } + + @Override + public String toString() { + return getStringRepresentation(""); + } + + public String getStringRepresentation(String prefix) { + if (getName() == null) { + return ""; + } + String msg = prefix + " " + getName() + " in " + getTimeSpent() + + " ms."; + if (getCount() > 1) { + msg += " Invoked " + + getCount() + + " times (" + + roundToSignificantFigures(getTimeSpent() / getCount()) + + " ms per time)."; + } + if (!children.isEmpty()) { + double ownTime = getOwnTime(); + msg += " " + ownTime + " ms spent in own code"; + if (getCount() > 1) { + msg += " (" + + roundToSignificantFigures(ownTime / getCount()) + + " ms per time)"; + } + msg += '.'; + } + return msg; + } + + private static double roundToSignificantFigures(double num) { + // Number of significant digits + int n = 3; + if (num == 0) { + return 0; + } + + final double d = Math.ceil(Math.log10(num < 0 ? -num : num)); + final int power = n - (int) d; + + final double magnitude = Math.pow(10, power); + final long shifted = Math.round(num * magnitude); + return shifted / magnitude; + } + + public void sumUpTotals(Map totals) { + String name = getName(); + if (name != null) { + Node totalNode = totals.get(name); + if (totalNode == null) { + totalNode = new Node(name); + totals.put(name, totalNode); + } + + totalNode.time += getOwnTime(); + totalNode.count += getCount(); + } + for (Node node : children.values()) { + node.sumUpTotals(totals); + } + } + + /** + * @since + * @param time + */ + public void addTime(double time) { + this.time += time; + } + } + + private static final int MAX_ROWS = 10; + + private final DebugButton tabButton = new DebugButton(Icon.RESET_TIMER, + "Profiler"); + + private final HorizontalPanel controls = new HorizontalPanel(); + private final FlowPanel content = new FlowPanel(); + + public ProfilerSection() { + Profiler.setProfilerResultConsuer(new ProfilerResultConsumer() { + @Override + public void addProfilerData(Node rootNode, List totals) { + double totalTime = 0; + int eventCount = 0; + for (Node node : totals) { + totalTime += node.getTimeSpent(); + eventCount += node.getCount(); + } + + SimpleTree drillDownTree = (SimpleTree) buildTree(rootNode); + drillDownTree.setText("Drill down"); + + SimpleTree offendersTree = new SimpleTree("Longest events"); + for (int i = 0; i < totals.size() && i < 20; i++) { + Node node = totals.get(i); + offendersTree.add(new Label(node + .getStringRepresentation(""))); + } + + SimpleTree root = new SimpleTree(eventCount + + " profiler events using " + totalTime + " ms"); + root.add(drillDownTree); + root.add(offendersTree); + root.open(false); + + content.add(root); + applyLimit(); + } + + @Override + public void addBootstrapData(LinkedHashMap timings) { + SimpleTree tree = new SimpleTree( + "Time since window.performance.timing events"); + Set> entrySet = timings.entrySet(); + for (Entry entry : entrySet) { + tree.add(new Label(entry.getValue() + " " + entry.getKey())); + } + + tree.open(false); + content.add(tree); + applyLimit(); + } + }); + } + + private Widget buildTree(Node node) { + String message = node.getStringRepresentation(""); + + Collection children = node.getChildren(); + if (node.getName() == null || !children.isEmpty()) { + SimpleTree tree = new SimpleTree(message); + for (Node childNode : children) { + Widget child = buildTree(childNode); + tree.add(child); + } + return tree; + } else { + return new Label(message); + } + } + + private void applyLimit() { + while (content.getWidgetCount() > MAX_ROWS) { + content.remove(0); + } + } + + @Override + public DebugButton getTabButton() { + return tabButton; + } + + @Override + public Widget getControls() { + return controls; + } + + @Override + public Widget getContent() { + return content; + } + + @Override + public void show() { + // Nothing to do + } + + @Override + public void hide() { + // Nothing to do + } + + @Override + public void meta(ApplicationConnection ac, ValueMap meta) { + // Nothing to do + } + + @Override + public void uidl(ApplicationConnection ac, ValueMap uidl) { + // Nothing to do + } + +} -- cgit v1.2.3 From 03830aeb46d93d675fa01c35ce3700e30a4a9c7d Mon Sep 17 00:00:00 2001 From: Leif Åstrand Date: Fri, 31 May 2013 15:16:16 +0300 Subject: Ignore style resource that has already been added (#11667) Change-Id: I828166f69c3ad1ac7e24c00de640c8645d2f2153 --- server/src/com/vaadin/server/Page.java | 111 ++++++++++++++------- .../src/com/vaadin/tests/themes/CSSInjectTest.html | 11 +- .../src/com/vaadin/tests/themes/CSSInjectTest.java | 24 +++-- 3 files changed, 101 insertions(+), 45 deletions(-) diff --git a/server/src/com/vaadin/server/Page.java b/server/src/com/vaadin/server/Page.java index d4c16fe7f7..11553527e0 100644 --- a/server/src/com/vaadin/server/Page.java +++ b/server/src/com/vaadin/server/Page.java @@ -21,11 +21,10 @@ import java.lang.reflect.Method; import java.net.URI; import java.net.URISyntaxException; import java.util.EventObject; -import java.util.HashMap; import java.util.Iterator; +import java.util.LinkedHashSet; import java.util.LinkedList; import java.util.List; -import java.util.Map; import com.vaadin.event.EventRouter; import com.vaadin.shared.ui.BorderStyle; @@ -307,6 +306,61 @@ public class Page implements Serializable { } } + private static interface InjectedStyle { + public void paint(int id, PaintTarget target) throws PaintException; + } + + private static class InjectedStyleString implements InjectedStyle { + + private String css; + + public InjectedStyleString(String css) { + this.css = css; + } + + @Override + public void paint(int id, PaintTarget target) throws PaintException { + target.startTag("css-string"); + target.addAttribute("id", id); + target.addText(css); + target.endTag("css-string"); + } + } + + private static class InjectedStyleResource implements InjectedStyle { + + private final Resource resource; + + public InjectedStyleResource(Resource resource) { + this.resource = resource; + } + + @Override + public void paint(int id, PaintTarget target) throws PaintException { + target.startTag("css-resource"); + target.addAttribute("id", id); + target.addAttribute("url", resource); + target.endTag("css-resource"); + } + + @Override + public boolean equals(Object obj) { + if (obj == this) { + return true; + } else if (obj instanceof InjectedStyleResource) { + InjectedStyleResource that = (InjectedStyleResource) obj; + return resource.equals(that.resource); + } else { + return false; + } + } + + @Override + public int hashCode() { + return resource.hashCode(); + } + } + /** * Contains dynamically injected styles injected in the HTML document at * runtime. @@ -315,16 +369,9 @@ public class Page implements Serializable { */ public static class Styles implements Serializable { - private final Map stringInjections = new HashMap(); - - private final Map resourceInjections = new HashMap(); + private LinkedHashSet injectedStyles = new LinkedHashSet(); - // The combined injection counter between both string and resource - // injections. Used as the key for the injection maps - private int injectionCounter = 0; - - // Points to the next injection that has not yet been made into the Page - private int nextInjectionPosition = 0; + private LinkedHashSet pendingInjections = new LinkedHashSet(); private final UI ui; @@ -344,7 +391,7 @@ public class Page implements Serializable { "Cannot inject null CSS string"); } - stringInjections.put(injectionCounter++, css); + pendingInjections.add(new InjectedStyleString(css)); ui.markAsDirty(); } @@ -360,43 +407,33 @@ public class Page implements Serializable { "Cannot inject null resource"); } - resourceInjections.put(injectionCounter++, resource); - ui.markAsDirty(); + InjectedStyleResource injection = new InjectedStyleResource( + resource); + if (!injectedStyles.contains(injection) + && pendingInjections.add(injection)) { + ui.markAsDirty(); + } } private void paint(PaintTarget target) throws PaintException { // If full repaint repaint all injections if (target.isFullRepaint()) { - nextInjectionPosition = 0; + injectedStyles.addAll(pendingInjections); + pendingInjections = injectedStyles; + injectedStyles = new LinkedHashSet(); } - if (injectionCounter > nextInjectionPosition) { + if (!pendingInjections.isEmpty()) { target.startTag("css-injections"); - while (injectionCounter > nextInjectionPosition) { - - String stringInjection = stringInjections - .get(nextInjectionPosition); - if (stringInjection != null) { - target.startTag("css-string"); - target.addAttribute("id", nextInjectionPosition); - target.addText(stringInjection); - target.endTag("css-string"); - } - - Resource resourceInjection = resourceInjections - .get(nextInjectionPosition); - if (resourceInjection != null) { - target.startTag("css-resource"); - target.addAttribute("id", nextInjectionPosition); - target.addAttribute("url", resourceInjection); - target.endTag("css-resource"); - } - - nextInjectionPosition++; + for (InjectedStyle pending : pendingInjections) { + int id = injectedStyles.size(); + pending.paint(id, target); + injectedStyles.add(pending); } + pendingInjections.clear(); target.endTag("css-injections"); } diff --git a/uitest/src/com/vaadin/tests/themes/CSSInjectTest.html b/uitest/src/com/vaadin/tests/themes/CSSInjectTest.html index 05a0f256c2..0c70d6f711 100644 --- a/uitest/src/com/vaadin/tests/themes/CSSInjectTest.html +++ b/uitest/src/com/vaadin/tests/themes/CSSInjectTest.html @@ -51,7 +51,16 @@ world-red - + + click + vaadin=runcomvaadinteststhemesCSSInjectTest::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[4]/VButton[0]/domChild[0]/domChild[0] + + + + screenCapture + + world-still-red + diff --git a/uitest/src/com/vaadin/tests/themes/CSSInjectTest.java b/uitest/src/com/vaadin/tests/themes/CSSInjectTest.java index f4448bf326..738d8fc681 100644 --- a/uitest/src/com/vaadin/tests/themes/CSSInjectTest.java +++ b/uitest/src/com/vaadin/tests/themes/CSSInjectTest.java @@ -22,14 +22,16 @@ public class CSSInjectTest extends TestBase { final Styles stylesheet = Page.getCurrent().getStyles(); // Inject some resources initially - stylesheet.add(new StreamResource(new StreamResource.StreamSource() { + final StreamResource initialResource = new StreamResource( + new StreamResource.StreamSource() { - @Override - public InputStream getStream() { - return new ByteArrayInputStream( - ".hello, .world { color:silver; }".getBytes()); - } - }, "mystyles-" + System.currentTimeMillis() + ".css")); + @Override + public InputStream getStream() { + return new ByteArrayInputStream( + ".hello, .world { color:silver; }".getBytes()); + } + }, "mystyles-" + System.currentTimeMillis() + ".css"); + stylesheet.add(initialResource); Label hello = new Label( "Hello world", @@ -72,6 +74,14 @@ public class CSSInjectTest extends TestBase { } }); addComponent(injectRandom); + + addComponent(new Button("Inject initial again!", + new Button.ClickListener() { + @Override + public void buttonClick(ClickEvent event) { + stylesheet.add(initialResource); + } + })); } @Override -- cgit v1.2.3 From 84bf5a77e678f6d8a73f71d42fea2300b4f174cc Mon Sep 17 00:00:00 2001 From: John Ahlroos Date: Thu, 30 May 2013 16:19:47 +0300 Subject: Enabled drag & drop to Calendar #11048 Change-Id: I2dcc1f7159a6283cfbc0baafe6cba66530bf0a45 --- client/src/com/vaadin/client/ui/VCalendar.java | 26 ++++- .../client/ui/calendar/CalendarConnector.java | 88 ++++++--------- .../calendar/schedule/dd/CalendarDropHandler.java | 11 +- .../schedule/dd/CalendarMonthDropHandler.java | 5 + .../schedule/dd/CalendarWeekDropHandler.java | 5 + server/src/com/vaadin/ui/Calendar.java | 31 +++++- .../components/calendar/CalendarDragAndDrop.html | 59 ++++++++++ .../components/calendar/CalendarDragAndDrop.java | 123 +++++++++++++++++++++ 8 files changed, 289 insertions(+), 59 deletions(-) create mode 100644 uitest/src/com/vaadin/tests/components/calendar/CalendarDragAndDrop.html create mode 100644 uitest/src/com/vaadin/tests/components/calendar/CalendarDragAndDrop.java diff --git a/client/src/com/vaadin/client/ui/VCalendar.java b/client/src/com/vaadin/client/ui/VCalendar.java index c5c12f2d72..38bcc0b14f 100644 --- a/client/src/com/vaadin/client/ui/VCalendar.java +++ b/client/src/com/vaadin/client/ui/VCalendar.java @@ -39,6 +39,8 @@ import com.vaadin.client.ui.calendar.schedule.SimpleDayToolbar; import com.vaadin.client.ui.calendar.schedule.SimpleWeekToolbar; import com.vaadin.client.ui.calendar.schedule.WeekGrid; import com.vaadin.client.ui.calendar.schedule.WeeklyLongEvents; +import com.vaadin.client.ui.calendar.schedule.dd.CalendarDropHandler; +import com.vaadin.client.ui.dd.VHasDropHandler; import com.vaadin.shared.ui.calendar.DateConstants; /** @@ -47,7 +49,7 @@ import com.vaadin.shared.ui.calendar.DateConstants; * @since 7.1 * @author Vaadin Ltd. */ -public class VCalendar extends Composite { +public class VCalendar extends Composite implements VHasDropHandler { public static final String ATTR_FIRSTDAYOFWEEK = "firstDay"; public static final String ATTR_LASTDAYOFWEEK = "lastDay"; @@ -96,6 +98,8 @@ public class VCalendar extends Composite { private int firstHour; private int lastHour; + private CalendarDropHandler dropHandler; + /** * Listener interface for listening to event click events */ @@ -1443,4 +1447,24 @@ public class VCalendar extends Composite { public void setForwardNavigationEnabled(boolean enabled) { forwardNavigationEnabled = enabled; } + + /* + * (non-Javadoc) + * + * @see com.vaadin.client.ui.dd.VHasDropHandler#getDropHandler() + */ + @Override + public CalendarDropHandler getDropHandler() { + return dropHandler; + } + + /** + * Set the drop handler + * + * @param dropHandler + * The drophandler to use + */ + public void setDropHandler(CalendarDropHandler dropHandler) { + this.dropHandler = dropHandler; + } } diff --git a/client/src/com/vaadin/client/ui/calendar/CalendarConnector.java b/client/src/com/vaadin/client/ui/calendar/CalendarConnector.java index be3abb39ea..5a83579d46 100644 --- a/client/src/com/vaadin/client/ui/calendar/CalendarConnector.java +++ b/client/src/com/vaadin/client/ui/calendar/CalendarConnector.java @@ -19,6 +19,7 @@ import java.text.ParseException; import java.util.ArrayList; import java.util.Date; import java.util.HashMap; +import java.util.Iterator; import java.util.List; import com.google.gwt.core.shared.GWT; @@ -30,6 +31,7 @@ import com.google.gwt.user.client.Element; import com.google.gwt.user.client.Window; import com.google.gwt.user.client.ui.Widget; import com.vaadin.client.ApplicationConnection; +import com.vaadin.client.Paintable; import com.vaadin.client.TooltipInfo; import com.vaadin.client.UIDL; import com.vaadin.client.Util; @@ -60,7 +62,8 @@ import com.vaadin.client.ui.calendar.schedule.HasTooltipKey; import com.vaadin.client.ui.calendar.schedule.MonthEventLabel; import com.vaadin.client.ui.calendar.schedule.SimpleDayCell; import com.vaadin.client.ui.calendar.schedule.dd.CalendarDropHandler; -import com.vaadin.client.ui.dd.VHasDropHandler; +import com.vaadin.client.ui.calendar.schedule.dd.CalendarMonthDropHandler; +import com.vaadin.client.ui.calendar.schedule.dd.CalendarWeekDropHandler; import com.vaadin.shared.ui.Connect; import com.vaadin.shared.ui.Connect.LoadStyle; import com.vaadin.shared.ui.calendar.CalendarClientRpc; @@ -79,16 +82,16 @@ import com.vaadin.ui.Calendar; */ @Connect(value = Calendar.class, loadStyle = LoadStyle.LAZY) public class CalendarConnector extends AbstractComponentConnector implements - VHasDropHandler, ActionOwner, SimpleManagedLayout { + ActionOwner, SimpleManagedLayout, Paintable { private CalendarServerRpc rpc = RpcProxy.create(CalendarServerRpc.class, this); - private CalendarDropHandler dropHandler; - private final HashMap actionMap = new HashMap(); private HashMap tooltips = new HashMap(); + private static final String DROPHANDLER_ACCEPT_CRITERIA_PAINT_TAG = "-ac"; + /** * */ @@ -306,13 +309,16 @@ public class CalendarConnector extends AbstractComponentConnector implements }); } + private boolean showingMonthView() { + return getState().days.size() > 7; + } + @Override public void onStateChanged(StateChangeEvent stateChangeEvent) { super.onStateChanged(stateChangeEvent); CalendarState state = getState(); VCalendar widget = getWidget(); - boolean monthView = state.days.size() > 7; // Enable or disable the forward and backward navigation buttons widget.setForwardNavigationEnabled(hasEventListener(CalendarEventId.FORWARD)); @@ -336,10 +342,19 @@ public class CalendarConnector extends AbstractComponentConnector implements List days = state.days; List events = state.events; - if (monthView) { + CalendarDropHandler dropHandler = getWidget().getDropHandler(); + if (showingMonthView()) { updateMonthView(days, events); + if (dropHandler != null + && !(dropHandler instanceof CalendarMonthDropHandler)) { + getWidget().setDropHandler(new CalendarMonthDropHandler(this)); + } } else { updateWeekView(days, events); + if (dropHandler != null + && !(dropHandler instanceof CalendarWeekDropHandler)) { + getWidget().setDropHandler(new CalendarWeekDropHandler(this)); + } } updateSizes(); @@ -355,32 +370,22 @@ public class CalendarConnector extends AbstractComponentConnector implements * com.vaadin.terminal.gwt.client.Paintable#updateFromUIDL(com.vaadin.terminal * .gwt.client.UIDL, com.vaadin.terminal.gwt.client.ApplicationConnection) */ + @Override public void updateFromUIDL(UIDL uidl, ApplicationConnection client) { - - // check for DD -related access criteria - // Iterator childIterator = uidl.getChildIterator(); - // while (childIterator.hasNext()) { - // UIDL child = (UIDL) childIterator.next(); - // - // // Drag&drop - // if (ACCESSCRITERIA.equals(child.getTag())) { - // if (monthView - // && !(getDropHandler() instanceof CalendarMonthDropHandler)) { - // setDropHandler(new CalendarMonthDropHandler()); - // - // } else if (!monthView - // && !(getDropHandler() instanceof CalendarWeekDropHandler)) { - // setDropHandler(new CalendarWeekDropHandler()); - // } - // - // getDropHandler().setCalendarPaintable(this); - // getDropHandler().updateAcceptRules(child); - // - // } else { - // setDropHandler(null); - // } - // - // } + Iterator childIterator = uidl.getChildIterator(); + while (childIterator.hasNext()) { + UIDL child = (UIDL) childIterator.next(); + if (DROPHANDLER_ACCEPT_CRITERIA_PAINT_TAG.equals(child.getTag())) { + if (getWidget().getDropHandler() == null) { + getWidget().setDropHandler( + showingMonthView() ? new CalendarMonthDropHandler( + this) : new CalendarWeekDropHandler(this)); + } + getWidget().getDropHandler().updateAcceptRules(child); + } else { + getWidget().setDropHandler(null); + } + } } /** @@ -449,27 +454,6 @@ public class CalendarConnector extends AbstractComponentConnector implements calendarDayListOf(days)); } - /* - * (non-Javadoc) - * - * @see - * com.vaadin.terminal.gwt.client.ui.dd.VHasDropHandler#getDropHandler() - */ - @Override - public CalendarDropHandler getDropHandler() { - return dropHandler; - } - - /** - * Set the drop handler - * - * @param dropHandler - * The drophandler to use - */ - public void setDropHandler(CalendarDropHandler dropHandler) { - this.dropHandler = dropHandler; - } - private Action[] getActionsBetween(Date start, Date end) { List actions = new ArrayList(); for (int i = 0; i < actionKeys.size(); i++) { diff --git a/client/src/com/vaadin/client/ui/calendar/schedule/dd/CalendarDropHandler.java b/client/src/com/vaadin/client/ui/calendar/schedule/dd/CalendarDropHandler.java index aab9ca9c38..ab0c9f2e9a 100644 --- a/client/src/com/vaadin/client/ui/calendar/schedule/dd/CalendarDropHandler.java +++ b/client/src/com/vaadin/client/ui/calendar/schedule/dd/CalendarDropHandler.java @@ -28,15 +28,16 @@ import com.vaadin.client.ui.dd.VAbstractDropHandler; */ public abstract class CalendarDropHandler extends VAbstractDropHandler { - protected CalendarConnector calendarConnector; + protected final CalendarConnector calendarConnector; /** - * Set the calendar instance + * Constructor * - * @param calendarPaintable + * @param connector + * The connector of the calendar */ - public void setConnector(CalendarConnector calendarConnector) { - this.calendarConnector = calendarConnector; + public CalendarDropHandler(CalendarConnector connector) { + calendarConnector = connector; } /* diff --git a/client/src/com/vaadin/client/ui/calendar/schedule/dd/CalendarMonthDropHandler.java b/client/src/com/vaadin/client/ui/calendar/schedule/dd/CalendarMonthDropHandler.java index 913477ee14..fd0be4881e 100644 --- a/client/src/com/vaadin/client/ui/calendar/schedule/dd/CalendarMonthDropHandler.java +++ b/client/src/com/vaadin/client/ui/calendar/schedule/dd/CalendarMonthDropHandler.java @@ -18,6 +18,7 @@ package com.vaadin.client.ui.calendar.schedule.dd; import com.google.gwt.user.client.DOM; import com.google.gwt.user.client.Element; import com.vaadin.client.Util; +import com.vaadin.client.ui.calendar.CalendarConnector; import com.vaadin.client.ui.calendar.schedule.SimpleDayCell; import com.vaadin.client.ui.dd.VAcceptCallback; import com.vaadin.client.ui.dd.VDragEvent; @@ -32,6 +33,10 @@ import com.vaadin.client.ui.dd.VDragEvent; */ public class CalendarMonthDropHandler extends CalendarDropHandler { + public CalendarMonthDropHandler(CalendarConnector connector) { + super(connector); + } + private Element currentTargetElement; private SimpleDayCell currentTargetDay; diff --git a/client/src/com/vaadin/client/ui/calendar/schedule/dd/CalendarWeekDropHandler.java b/client/src/com/vaadin/client/ui/calendar/schedule/dd/CalendarWeekDropHandler.java index 0ea683dc3c..cede1827a2 100644 --- a/client/src/com/vaadin/client/ui/calendar/schedule/dd/CalendarWeekDropHandler.java +++ b/client/src/com/vaadin/client/ui/calendar/schedule/dd/CalendarWeekDropHandler.java @@ -18,6 +18,7 @@ package com.vaadin.client.ui.calendar.schedule.dd; import com.google.gwt.user.client.DOM; import com.google.gwt.user.client.Element; import com.vaadin.client.Util; +import com.vaadin.client.ui.calendar.CalendarConnector; import com.vaadin.client.ui.calendar.schedule.DateCell; import com.vaadin.client.ui.calendar.schedule.DateCellDayEvent; import com.vaadin.client.ui.dd.VAcceptCallback; @@ -36,6 +37,10 @@ public class CalendarWeekDropHandler extends CalendarDropHandler { private com.google.gwt.user.client.Element currentTargetElement; private DateCell currentTargetDay; + public CalendarWeekDropHandler(CalendarConnector connector) { + super(connector); + } + /* * (non-Javadoc) * diff --git a/server/src/com/vaadin/ui/Calendar.java b/server/src/com/vaadin/ui/Calendar.java index 38fa355dd8..c3385baa2c 100644 --- a/server/src/com/vaadin/ui/Calendar.java +++ b/server/src/com/vaadin/ui/Calendar.java @@ -45,6 +45,8 @@ import com.vaadin.event.dd.DropHandler; import com.vaadin.event.dd.DropTarget; import com.vaadin.event.dd.TargetDetails; import com.vaadin.server.KeyMapper; +import com.vaadin.server.PaintException; +import com.vaadin.server.PaintTarget; import com.vaadin.shared.ui.calendar.CalendarEventId; import com.vaadin.shared.ui.calendar.CalendarServerRpc; import com.vaadin.shared.ui.calendar.CalendarState; @@ -114,7 +116,7 @@ public class Calendar extends AbstractComponent implements CalendarComponentEvents.RangeSelectNotifier, CalendarComponentEvents.EventResizeNotifier, CalendarEventProvider.EventSetChangeListener, DropTarget, - CalendarEditableEventProvider, Action.Container { + CalendarEditableEventProvider, Action.Container, LegacyComponent { /** * Calendar can use either 12 hours clock or 24 hours clock. @@ -1842,4 +1844,31 @@ public class Calendar extends AbstractComponent implements } } } + + /* + * (non-Javadoc) + * + * @see com.vaadin.server.VariableOwner#changeVariables(java.lang.Object, + * java.util.Map) + */ + @Override + public void changeVariables(Object source, Map variables) { + /* + * Only defined to fulfill the LegacyComponent interface used for + * calendar drag & drop. No implementation required. + */ + } + + /* + * (non-Javadoc) + * + * @see + * com.vaadin.ui.LegacyComponent#paintContent(com.vaadin.server.PaintTarget) + */ + @Override + public void paintContent(PaintTarget target) throws PaintException { + if (dropHandler != null) { + dropHandler.getAcceptCriterion().paint(target); + } + } } \ No newline at end of file diff --git a/uitest/src/com/vaadin/tests/components/calendar/CalendarDragAndDrop.html b/uitest/src/com/vaadin/tests/components/calendar/CalendarDragAndDrop.html new file mode 100644 index 0000000000..425f95c529 --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/calendar/CalendarDragAndDrop.html @@ -0,0 +1,59 @@ + + + + + + +New Test + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    New Test
    open/run/com.vaadin.tests.components.calendar.CalendarDragAndDrop?restartApplication
    dragvaadin=runcomvaadintestscomponentscalendarCalendarDragAndDrop::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[1]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[9]/domChild[0]/domChild[0]76,7
    dropvaadin=runcomvaadintestscomponentscalendarCalendarDragAndDrop::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[0]/VCalendar[0]/domChild[0]/domChild[1]/domChild[1]/domChild[0]/domChild[1]/domChild[1]/domChild[5]/domChild[0]/domChild[2]54,9
    assertTextvaadin=runcomvaadintestscomponentscalendarCalendarDragAndDrop::PID_SCalendar/domChild[0]/domChild[1]/domChild[1]/domChild[0]/domChild[1]/domChild[1]/domChild[5]/domChild[0]/domChild[1]12:00 AM Event 10
    mouseClickvaadin=runcomvaadintestscomponentscalendarCalendarDragAndDrop::PID_SCalendar/domChild[0]/domChild[1]/domChild[0]/domChild[0]/domChild[1]/domChild[1]/domChild[0]/domChild[0]7,85
    dragvaadin=runcomvaadintestscomponentscalendarCalendarDragAndDrop::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[1]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[11]/domChild[0]/domChild[0]34,12
    dropvaadin=runcomvaadintestscomponentscalendarCalendarDragAndDrop::PID_SCalendar/domChild[0]/domChild[3]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[2]/domChild[0]/domChild[15]75,9
    assertTextvaadin=runcomvaadintestscomponentscalendarCalendarDragAndDrop::PID_SCalendar/domChild[0]/domChild[3]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[2]/domChild[0]/domChild[48]/domChild[0]7:30 AM: Event 13
    + + diff --git a/uitest/src/com/vaadin/tests/components/calendar/CalendarDragAndDrop.java b/uitest/src/com/vaadin/tests/components/calendar/CalendarDragAndDrop.java new file mode 100644 index 0000000000..7477fc84ce --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/calendar/CalendarDragAndDrop.java @@ -0,0 +1,123 @@ +/* + * Copyright 2000-2013 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.GregorianCalendar; +import java.util.Locale; + +import com.vaadin.event.dd.DragAndDropEvent; +import com.vaadin.event.dd.DropHandler; +import com.vaadin.event.dd.acceptcriteria.AcceptAll; +import com.vaadin.event.dd.acceptcriteria.AcceptCriterion; +import com.vaadin.server.VaadinRequest; +import com.vaadin.tests.components.AbstractTestUI; +import com.vaadin.ui.Calendar; +import com.vaadin.ui.HorizontalLayout; +import com.vaadin.ui.Table; +import com.vaadin.ui.Table.TableDragMode; +import com.vaadin.ui.Table.TableTransferable; +import com.vaadin.ui.components.calendar.CalendarTargetDetails; +import com.vaadin.ui.components.calendar.event.BasicEvent; + +public class CalendarDragAndDrop extends AbstractTestUI { + + private Calendar calendar; + + private Table table; + + private class TestDropHandler implements DropHandler { + + @Override + public void drop(DragAndDropEvent event) { + CalendarTargetDetails details = (CalendarTargetDetails) event + .getTargetDetails(); + + TableTransferable transferable = (TableTransferable) event + .getTransferable(); + + calendar.addEvent(new BasicEvent(transferable.getItemId() + .toString(), "This event was dragged here", details + .getDropTime())); + + table.removeItem(transferable.getItemId()); + } + + @Override + public AcceptCriterion getAcceptCriterion() { + return AcceptAll.get(); + } + } + + @Override + protected void setup(VaadinRequest request) { + setSizeFull(); + getContent().setSizeFull(); + getLayout().setSizeFull(); + + HorizontalLayout root = new HorizontalLayout(); + root.setSizeFull(); + addComponent(root); + + Locale locale = new Locale("en", "US"); + GregorianCalendar cal = new GregorianCalendar(locale); + cal.set(2013, 0, 1); + + calendar = new Calendar(); + calendar.setId("Calendar"); + calendar.setLocale(locale); + calendar.setDropHandler(new TestDropHandler()); + calendar.setSizeFull(); + root.addComponent(calendar); + + calendar.setStartDate(cal.getTime()); + cal.add(java.util.Calendar.MONTH, 1); + calendar.setEndDate(cal.getTime()); + + table = new Table(); + table.setSizeFull(); + table.setDragMode(TableDragMode.ROW); + table.addGeneratedColumn("COLUMN", new Table.ColumnGenerator() { + + @Override + public Object generateCell(Table source, Object itemId, + Object columnId) { + return itemId; + } + }); + + for (int eventNum = 1; eventNum < 50; eventNum++) { + table.addItem("Event " + eventNum); + } + + root.addComponent(table); + } + + @Override + protected String getTestDescription() { + // TODO Auto-generated method stub + return null; + } + + @Override + protected Integer getTicketNumber() { + return 11048; + } + +} -- cgit v1.2.3 From 666dbb5f6b80a83c01140159901754fa317a977e Mon Sep 17 00:00:00 2001 From: Johannes Dahlström Date: Tue, 4 Jun 2013 15:20:15 +0300 Subject: Use window.console instead of just console in vaadinPush to appease IE (#11980) Change-Id: I6f363e9afc550d70eb451005dcfdfb53e5533273 --- WebContent/VAADIN/vaadinPush.js.tpl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/WebContent/VAADIN/vaadinPush.js.tpl b/WebContent/VAADIN/vaadinPush.js.tpl index 3928fba1b6..43dfd18b40 100644 --- a/WebContent/VAADIN/vaadinPush.js.tpl +++ b/WebContent/VAADIN/vaadinPush.js.tpl @@ -3,6 +3,6 @@ window.jQueryVaadin = window.jQuery.noConflict(true); (function(jQuery, undefined) { @jquery.atmosphere.js@ })(jQueryVaadin); -if (console) { - console.log("Vaadin push loaded"); -} \ No newline at end of file +if (window.console) { + window.console.log("Vaadin push loaded"); +} -- cgit v1.2.3 From 93751c13557a5dc7cbf853327b73d5b272f1f0d5 Mon Sep 17 00:00:00 2001 From: Artur Signell Date: Mon, 3 Jun 2013 12:18:57 +0300 Subject: Use correct day names when formatting dates (#6207) Change-Id: I2010f87ef4f9359cdc95104cc02c83355a8630ed --- client/src/com/vaadin/client/DateTimeService.java | 48 +++++++++++++++++++++- .../components/datefield/CustomDateFormats.java | 1 + 2 files changed, 47 insertions(+), 2 deletions(-) diff --git a/client/src/com/vaadin/client/DateTimeService.java b/client/src/com/vaadin/client/DateTimeService.java index 53e8f81a38..5fd0574d3e 100644 --- a/client/src/com/vaadin/client/DateTimeService.java +++ b/client/src/com/vaadin/client/DateTimeService.java @@ -308,10 +308,11 @@ public class DateTimeService { */ public String formatDate(Date date, String formatStr) { /* - * Format month names separately when locale for the DateTimeService is - * not the same as the browser locale + * Format month and day names separately when locale for the + * DateTimeService is not the same as the browser locale */ formatStr = formatMonthNames(date, formatStr); + formatStr = formatDayNames(date, formatStr); // Format uses the browser locale DateTimeFormat format = DateTimeFormat.getFormat(formatStr); @@ -321,6 +322,49 @@ public class DateTimeService { return result; } + private String formatDayNames(Date date, String formatStr) { + if (formatStr.contains("EEEE")) { + String dayName = getDay(date.getDay()); + + if (dayName != null) { + /* + * Replace 4 or more E:s with the quoted day name. Also + * concatenate generated string with any other string prepending + * or following the EEEE pattern, i.e. 'EEEE'ta ' becomes 'DAYta + * ' and not 'DAY''ta ', 'ab'EEEE becomes 'abDAY', 'x'EEEE'y' + * becomes 'xDAYy'. + */ + formatStr = formatStr.replaceAll("'([E]{4,})'", dayName); + formatStr = formatStr.replaceAll("([E]{4,})'", "'" + dayName); + formatStr = formatStr.replaceAll("'([E]{4,})", dayName + "'"); + formatStr = formatStr + .replaceAll("[E]{4,}", "'" + dayName + "'"); + } + } + + if (formatStr.contains("EEE")) { + + String dayName = getShortDay(date.getMonth()); + + if (dayName != null) { + /* + * Replace 3 or more E:s with the quoted month name. Also + * concatenate generated string with any other string prepending + * or following the EEE pattern, i.e. 'EEE'ta ' becomes 'DAYta ' + * and not 'DAY''ta ', 'ab'EEE becomes 'abDAY', 'x'EEE'y' + * becomes 'xDAYy'. + */ + formatStr = formatStr.replaceAll("'([E]{3,})'", dayName); + formatStr = formatStr.replaceAll("([E]{3,})'", "'" + dayName); + formatStr = formatStr.replaceAll("'([E]{3,})", dayName + "'"); + formatStr = formatStr + .replaceAll("[E]{3,}", "'" + dayName + "'"); + } + } + + return formatStr; + } + private String formatMonthNames(Date date, String formatStr) { if (formatStr.contains("MMMM")) { String monthName = getMonth(date.getMonth()); diff --git a/uitest/src/com/vaadin/tests/components/datefield/CustomDateFormats.java b/uitest/src/com/vaadin/tests/components/datefield/CustomDateFormats.java index 247478256f..015a974b3e 100644 --- a/uitest/src/com/vaadin/tests/components/datefield/CustomDateFormats.java +++ b/uitest/src/com/vaadin/tests/components/datefield/CustomDateFormats.java @@ -104,6 +104,7 @@ public class CustomDateFormats extends TestBase { locale); addDateField(gridLayout, getDatePattern(locale, DateFormat.SHORT), locale); + addDateField(gridLayout, "EEE d MMMM yyyy", locale); } -- cgit v1.2.3 From 19d00822a1ec86e762cf1cab31a5fd5705fb42c1 Mon Sep 17 00:00:00 2001 From: Artur Signell Date: Tue, 4 Jun 2013 17:57:38 +0300 Subject: Fixed javadoc references Change-Id: If20a5db3ee42608fbb246e6d56125e335c616887 --- shared/src/com/vaadin/shared/communication/SharedState.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/shared/src/com/vaadin/shared/communication/SharedState.java b/shared/src/com/vaadin/shared/communication/SharedState.java index 17b6fd7ab4..57c3e801b5 100644 --- a/shared/src/com/vaadin/shared/communication/SharedState.java +++ b/shared/src/com/vaadin/shared/communication/SharedState.java @@ -54,9 +54,9 @@ public class SharedState implements Serializable { /** * The automatically managed resources used by the connector. * - * @see com.vaadin.terminal.AbstractClientConnector#setResource(String, - * com.vaadin.terminal.Resource) - * @see com.vaadin.terminal.gwt.client.ui.AbstractConnector#getResourceUrl(String) + * @see com.vaadin.server.AbstractClientConnector#setResource(String, + * com.vaadin.server.Resource) + * @see com.vaadin.client.ui.AbstractConnector#getResourceUrl(String) */ public Map resources = new HashMap(); -- cgit v1.2.3 From e6e752d4ad2d89c6df416fd7c17d6f18df0b33c5 Mon Sep 17 00:00:00 2001 From: Artur Signell Date: Tue, 4 Jun 2013 21:33:05 +0300 Subject: Correctly decode summaries containing quotes (#11769) Change-Id: I98031bab90d3aa3f37e7dc71a9104f7b7a956590 --- .../src/com/vaadin/buildhelpers/FetchReleaseNotesTickets.java | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/buildhelpers/src/com/vaadin/buildhelpers/FetchReleaseNotesTickets.java b/buildhelpers/src/com/vaadin/buildhelpers/FetchReleaseNotesTickets.java index 588fe1aba1..5c3810099a 100644 --- a/buildhelpers/src/com/vaadin/buildhelpers/FetchReleaseNotesTickets.java +++ b/buildhelpers/src/com/vaadin/buildhelpers/FetchReleaseNotesTickets.java @@ -46,8 +46,15 @@ public class FetchReleaseNotesTickets { // This is the header continue; } + String summary = fields[1]; + if (summary.startsWith("\"") && summary.endsWith("\"")) { + // If a summary starts with " and ends with " then all quotes in + // the summary are encoded as double quotes + summary = summary.substring(1, summary.length() - 1); + summary = summary.replace("\"\"", "\""); + } System.out.println(ticketTemplate.replace("@ticket@", fields[0]) - .replace("@description@", fields[1])); + .replace("@description@", summary)); } urlStream.close(); } -- cgit v1.2.3 From 54ed269820fa503b2289327457324477bb24f6f9 Mon Sep 17 00:00:00 2001 From: Artur Signell Date: Tue, 4 Jun 2013 16:49:24 +0300 Subject: Log stack trace using fine when logging toString warnings Change-Id: I4dbb5e84df78bad25fa90fc802309e433d516fd6 --- server/src/com/vaadin/data/util/LegacyPropertyHelper.java | 5 +++++ server/src/com/vaadin/server/Constants.java | 3 ++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/server/src/com/vaadin/data/util/LegacyPropertyHelper.java b/server/src/com/vaadin/data/util/LegacyPropertyHelper.java index 551d7223d6..76bd57117d 100644 --- a/server/src/com/vaadin/data/util/LegacyPropertyHelper.java +++ b/server/src/com/vaadin/data/util/LegacyPropertyHelper.java @@ -60,6 +60,11 @@ public class LegacyPropertyHelper implements Serializable { getLogger().log(Level.WARNING, Constants.WARNING_LEGACY_PROPERTY_TOSTRING, p.getClass().getName()); + if (getLogger().isLoggable(Level.FINE)) { + getLogger().log(Level.FINE, + "Strack trace for legacy toString to ease debugging", + new Throwable()); + } } /** diff --git a/server/src/com/vaadin/server/Constants.java b/server/src/com/vaadin/server/Constants.java index cf1031dab2..2c041e3cf8 100644 --- a/server/src/com/vaadin/server/Constants.java +++ b/server/src/com/vaadin/server/Constants.java @@ -106,7 +106,8 @@ public interface Constants { + "\" to \"true\". To disable the legacy functionality, set \"" + Constants.SERVLET_PARAMETER_LEGACY_PROPERTY_TOSTRING + "\" to false." - + " (Note that your debugger might call toString() and trigger this message)."; + + " (Note that your debugger might call toString() and trigger this message)." + + " To find out who is calling toString(), enable FINE level logging."; static final String WARNING_UNKNOWN_LEGACY_PROPERTY_TOSTRING_VALUE = "Unknown value '{0}' for parameter " + Constants.SERVLET_PARAMETER_LEGACY_PROPERTY_TOSTRING -- cgit v1.2.3 From 8d655f617fe09b65982b259ba8d402e3f1d6bf24 Mon Sep 17 00:00:00 2001 From: Leif Åstrand Date: Fri, 31 May 2013 16:12:16 +0300 Subject: Move VaadinSession.runPendingAccessTasks to VaadinService (#11964) Change-Id: Idb893baec693d0aaa3ccba1d3f61a62922e0a1ce --- server/src/com/vaadin/server/VaadinService.java | 88 +++++++++++++++++ server/src/com/vaadin/server/VaadinSession.java | 107 +++++++++------------ .../vaadin/server/communication/UidlWriter.java | 2 +- server/src/com/vaadin/ui/UI.java | 2 +- .../com/vaadin/tests/components/ui/UiAccess.java | 3 +- 5 files changed, 137 insertions(+), 65 deletions(-) diff --git a/server/src/com/vaadin/server/VaadinService.java b/server/src/com/vaadin/server/VaadinService.java index f9b17537df..a040c72175 100644 --- a/server/src/com/vaadin/server/VaadinService.java +++ b/server/src/com/vaadin/server/VaadinService.java @@ -33,6 +33,9 @@ import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Locale; +import java.util.Map; +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; import java.util.logging.Level; @@ -47,6 +50,7 @@ import org.json.JSONObject; import com.vaadin.annotations.PreserveOnRefresh; import com.vaadin.event.EventRouter; +import com.vaadin.server.VaadinSession.FutureAccess; import com.vaadin.server.communication.FileUploadHandler; import com.vaadin.server.communication.HeartbeatHandler; import com.vaadin.server.communication.PublishedFileHandler; @@ -1609,4 +1613,88 @@ public abstract class VaadinService implements Serializable { return true; } + /** + * Implementation for {@link VaadinSession#access(Runnable)}. This method is + * implemented here instead of in {@link VaadinSession} to enable overriding + * the implementation without using a custom subclass of VaadinSession. + * + * @since 7.1 + * @see VaadinSession#access(Runnable) + * + * @param session + * the vaadin session to access + * @param runnable + * the runnable to run with the session locked + * + * @return a future that can be used to check for task completion and to + * cancel the task + */ + public Future accessSession(VaadinSession session, Runnable runnable) { + FutureAccess future = new FutureAccess(session, runnable); + session.getPendingAccessQueue().add(future); + + /* + * If no thread is currently holding the lock, pending changes for UIs + * with automatic push would not be processed and pushed until the next + * time there is a request or someone does an explicit push call. + * + * To remedy this, we try to get the lock at this point. If the lock is + * currently held by another thread, we just back out as the queue will + * get purged once it is released. If the lock is held by the current + * thread, we just release it knowing that the queue gets purged once + * the lock is ultimately released. If the lock is not held by any + * thread and we acquire it, we just release it again to purge the queue + * right away. + */ + try { + // tryLock() would be shorter, but it does not guarantee fairness + if (session.getLockInstance().tryLock(0, TimeUnit.SECONDS)) { + // unlock triggers runPendingAccessTasks + session.unlock(); + } + } catch (InterruptedException e) { + // Just ignore + } + + return future; + } + + /** + * Purges the queue of pending access invocations enqueued with + * {@link VaadinSession#access(Runnable)}. + *

    + * This method is automatically run by the framework at appropriate + * situations and is not intended to be used by application developers. + * + * @param session + * the vaadin session to purge the queue for + * @since 7.1 + */ + public void runPendingAccessTasks(VaadinSession session) { + assert session.hasLock(); + + if (session.getPendingAccessQueue().isEmpty()) { + return; + } + + Map, CurrentInstance> oldInstances = CurrentInstance + .getInstances(false); + + FutureAccess pendingAccess; + try { + while ((pendingAccess = session.getPendingAccessQueue().poll()) != null) { + if (!pendingAccess.isCancelled()) { + CurrentInstance.clearAll(); + CurrentInstance.restoreInstances(pendingAccess + .getCurrentInstances()); + CurrentInstance.setCurrent(session); + pendingAccess.run(); + } + } + } finally { + CurrentInstance.clearAll(); + CurrentInstance.restoreInstances(oldInstances); + } + } + } diff --git a/server/src/com/vaadin/server/VaadinSession.java b/server/src/com/vaadin/server/VaadinSession.java index 9ef3d33195..17b696b17a 100644 --- a/server/src/com/vaadin/server/VaadinSession.java +++ b/server/src/com/vaadin/server/VaadinSession.java @@ -25,12 +25,12 @@ import java.util.LinkedList; import java.util.List; import java.util.Locale; import java.util.Map; +import java.util.Queue; import java.util.UUID; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; import java.util.concurrent.FutureTask; -import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; import java.util.logging.Logger; @@ -67,16 +67,37 @@ import com.vaadin.util.ReflectTools; @SuppressWarnings("serial") public class VaadinSession implements HttpSessionBindingListener, Serializable { - private class FutureAccess extends FutureTask { + /** + * Encapsulates a {@link Runnable} submitted using + * {@link VaadinSession#access(Runnable)}. This class is used internally by + * the framework and is not intended to be directly used by application + * developers. + * + * @since 7.1 + * @author Vaadin Ltd + */ + public static class FutureAccess extends FutureTask { /** * Snapshot of all non-inheritable current instances at the time this * object was created. */ private final Map, CurrentInstance> instances = CurrentInstance .getInstances(true); + private final VaadinSession session; - public FutureAccess(Runnable arg0) { - super(arg0, null); + /** + * Creates an instance for the given runnable + * + * @param session + * the session to which the task belongs + * + * @param runnable + * the runnable to run when this task is purged from the + * queue + */ + public FutureAccess(VaadinSession session, Runnable runnable) { + super(runnable, null); + this.session = session; } @Override @@ -91,9 +112,21 @@ public class VaadinSession implements HttpSessionBindingListener, Serializable { * run, the check is always done as the deterministic behavior makes * it easier to detect potential problems. */ - VaadinService.verifyNoOtherSessionLocked(VaadinSession.this); + VaadinService.verifyNoOtherSessionLocked(session); return super.get(); } + + /** + * Gets the current instance values that should be used when running + * this task. + * + * @see CurrentInstance#restoreInstances(Map) + * + * @return a map of current instances. + */ + public Map, CurrentInstance> getCurrentInstances() { + return instances; + } } /** @@ -866,7 +899,7 @@ public class VaadinSession implements HttpSessionBindingListener, Serializable { * released by this unlock() invocation. */ if (((ReentrantLock) getLockInstance()).getHoldCount() == 1) { - runPendingAccessTasks(); + getService().runPendingAccessTasks(this); for (UI ui : getUIs()) { if (ui.getPushMode() == PushMode.AUTOMATIC) { @@ -1205,68 +1238,18 @@ public class VaadinSession implements HttpSessionBindingListener, Serializable { * cancel the task */ public Future access(Runnable runnable) { - FutureAccess future = new FutureAccess(runnable); - pendingAccessQueue.add(future); - - /* - * If no thread is currently holding the lock, pending changes for UIs - * with automatic push would not be processed and pushed until the next - * time there is a request or someone does an explicit push call. - * - * To remedy this, we try to get the lock at this point. If the lock is - * currently held by another thread, we just back out as the queue will - * get purged once it is released. If the lock is held by the current - * thread, we just release it knowing that the queue gets purged once - * the lock is ultimately released. If the lock is not held by any - * thread and we acquire it, we just release it again to purge the queue - * right away. - */ - try { - // tryLock() would be shorter, but it does not guarantee fairness - if (getLockInstance().tryLock(0, TimeUnit.SECONDS)) { - // unlock triggers runPendingAccessTasks - unlock(); - } - } catch (InterruptedException e) { - // Just ignore - } - - return future; + return getService().accessSession(this, runnable); } /** - * Purges the queue of pending access invocations enqueued with - * {@link #access(Runnable)}. - *

    - * This method is automatically run by the framework at appropriate - * situations and is not intended to be used by application developers. + * Gets the queue of tasks submitted using {@link #access(Runnable)}. * * @since 7.1 + * + * @return the pending access queue */ - public void runPendingAccessTasks() { - assert hasLock(); - - if (pendingAccessQueue.isEmpty()) { - return; - } - - Map, CurrentInstance> oldInstances = CurrentInstance - .getInstances(false); - - FutureAccess pendingAccess; - try { - while ((pendingAccess = pendingAccessQueue.poll()) != null) { - if (!pendingAccess.isCancelled()) { - CurrentInstance.clearAll(); - CurrentInstance.restoreInstances(pendingAccess.instances); - CurrentInstance.setCurrent(this); - pendingAccess.run(); - } - } - } finally { - CurrentInstance.clearAll(); - CurrentInstance.restoreInstances(oldInstances); - } + public Queue getPendingAccessQueue() { + return pendingAccessQueue; } /** diff --git a/server/src/com/vaadin/server/communication/UidlWriter.java b/server/src/com/vaadin/server/communication/UidlWriter.java index f715569424..9c736d8dd9 100644 --- a/server/src/com/vaadin/server/communication/UidlWriter.java +++ b/server/src/com/vaadin/server/communication/UidlWriter.java @@ -78,7 +78,7 @@ public class UidlWriter implements Serializable { // Purge pending access calls as they might produce additional changes // to write out - session.runPendingAccessTasks(); + session.getService().runPendingAccessTasks(session); ArrayList dirtyVisibleConnectors = ui .getConnectorTracker().getDirtyVisibleConnectors(); diff --git a/server/src/com/vaadin/ui/UI.java b/server/src/com/vaadin/ui/UI.java index d1d8dd1df1..d4ac156787 100644 --- a/server/src/com/vaadin/ui/UI.java +++ b/server/src/com/vaadin/ui/UI.java @@ -1274,7 +1274,7 @@ public abstract class UI extends AbstractSingleComponentContainer implements * dirty when the push would otherwise be ignored because there are * no changes to push. */ - session.runPendingAccessTasks(); + session.getService().runPendingAccessTasks(session); if (!getConnectorTracker().hasDirtyConnectors()) { // Do not push if there is nothing to push diff --git a/uitest/src/com/vaadin/tests/components/ui/UiAccess.java b/uitest/src/com/vaadin/tests/components/ui/UiAccess.java index 297a985778..2bc91fa7b4 100644 --- a/uitest/src/com/vaadin/tests/components/ui/UiAccess.java +++ b/uitest/src/com/vaadin/tests/components/ui/UiAccess.java @@ -273,7 +273,8 @@ public class UiAccess extends AbstractTestUIWithLog { new CurrentInstanceTestType( "Set before run pending")); - getSession().runPendingAccessTasks(); + getSession().getService().runPendingAccessTasks( + getSession()); log.log("has request after access? " + (VaadinService.getCurrentRequest() != null)); -- cgit v1.2.3 From b1ab27a8fe2e06ab4d16f5b6f4ff107d694e19a6 Mon Sep 17 00:00:00 2001 From: Leif Åstrand Date: Wed, 29 May 2013 10:43:07 +0300 Subject: Update broadcaster tutorial code * Don't need to start a thread for broadcasting with the new UI.access * Add @Push to the UI * Use CopyOnWriteArrayList instead of synchronized methods Change-Id: I63fad6977c1a3e504fc60445c3147b5a241c3132 --- .../broadcastingmessages/Broadcaster.java | 33 +++++----------------- .../broadcastingmessages/BroadcasterUI.java | 2 ++ 2 files changed, 9 insertions(+), 26 deletions(-) diff --git a/uitest/src/com/vaadin/tests/minitutorials/broadcastingmessages/Broadcaster.java b/uitest/src/com/vaadin/tests/minitutorials/broadcastingmessages/Broadcaster.java index 57ad0d97ba..78d0af6283 100644 --- a/uitest/src/com/vaadin/tests/minitutorials/broadcastingmessages/Broadcaster.java +++ b/uitest/src/com/vaadin/tests/minitutorials/broadcastingmessages/Broadcaster.java @@ -16,44 +16,25 @@ package com.vaadin.tests.minitutorials.broadcastingmessages; -import java.util.ArrayList; import java.util.List; +import java.util.concurrent.CopyOnWriteArrayList; public class Broadcaster { - private static List listeners = new ArrayList(); + private static final List listeners = new CopyOnWriteArrayList(); - public synchronized static void register(BroadcastListener listener) { + public static void register(BroadcastListener listener) { listeners.add(listener); } - public synchronized static void unregister(BroadcastListener listener) { + public static void unregister(BroadcastListener listener) { listeners.remove(listener); } - private synchronized static List getListeners() { - List listenerCopy = new ArrayList(); - listenerCopy.addAll(listeners); - return listenerCopy; - } - public static void broadcast(final String message) { - // Make a copy of the listener list while synchronized, can't be - // synchronized while firing the event or we would have to fire each - // event in a separate thread. - final List listenerCopy = getListeners(); - - // We spawn another thread to avoid potential deadlocks with - // multiple UIs locked simultaneously - Thread eventThread = new Thread() { - @Override - public void run() { - for (BroadcastListener listener : listenerCopy) { - listener.receiveBroadcast(message); - } - } - }; - eventThread.start(); + for (BroadcastListener listener : listeners) { + listener.receiveBroadcast(message); + } } public interface BroadcastListener { diff --git a/uitest/src/com/vaadin/tests/minitutorials/broadcastingmessages/BroadcasterUI.java b/uitest/src/com/vaadin/tests/minitutorials/broadcastingmessages/BroadcasterUI.java index 06ead20db3..68b5925f48 100644 --- a/uitest/src/com/vaadin/tests/minitutorials/broadcastingmessages/BroadcasterUI.java +++ b/uitest/src/com/vaadin/tests/minitutorials/broadcastingmessages/BroadcasterUI.java @@ -1,5 +1,6 @@ package com.vaadin.tests.minitutorials.broadcastingmessages; +import com.vaadin.annotations.Push; import com.vaadin.server.VaadinRequest; import com.vaadin.tests.minitutorials.broadcastingmessages.Broadcaster.BroadcastListener; import com.vaadin.ui.Button; @@ -10,6 +11,7 @@ import com.vaadin.ui.TextArea; import com.vaadin.ui.UI; import com.vaadin.ui.VerticalLayout; +@Push public class BroadcasterUI extends UI implements BroadcastListener { @Override -- cgit v1.2.3 From e63edcc6cb4a3dd5253999319831b93a764eabb4 Mon Sep 17 00:00:00 2001 From: Leif Åstrand Date: Wed, 5 Jun 2013 09:52:06 +0300 Subject: Update deprecation javadoc for VaadinSession.getBrowser() Change-Id: I7c8d2e08d7efed90578489e90885c1c3c6201f64 --- server/src/com/vaadin/server/VaadinSession.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/server/src/com/vaadin/server/VaadinSession.java b/server/src/com/vaadin/server/VaadinSession.java index 17b696b17a..889eadcd6f 100644 --- a/server/src/com/vaadin/server/VaadinSession.java +++ b/server/src/com/vaadin/server/VaadinSession.java @@ -263,9 +263,9 @@ public class VaadinSession implements HttpSessionBindingListener, Serializable { /** * Get the web browser associated with this session. * - * @return - * @deprecated As of 7.0. Will likely change or be removed in a future - * version + * @return the web browser object + * + * @deprecated As of 7.0, use {@link Page#getWebBrowser()} instead. */ @Deprecated public WebBrowser getBrowser() { -- cgit v1.2.3 From 132eee59b8914fdbf9c42a9314e3db95f2f51520 Mon Sep 17 00:00:00 2001 From: Leif Åstrand Date: Tue, 4 Jun 2013 16:17:23 +0300 Subject: Add @VaadinServletConfiguration (#11970) Change-Id: Ic902028826adae8132bfa18b6cde7d80a2e876c4 --- .../annotations/VaadinServletConfiguration.java | 143 +++++++++++++++++++++ .../server/DefaultDeploymentConfiguration.java | 56 +++++--- server/src/com/vaadin/server/VaadinServlet.java | 38 ++++++ .../src/com/vaadin/server/MockServletConfig.java | 15 ++- .../server/VaadinServletConfigurationTest.java | 98 ++++++++++++++ 5 files changed, 328 insertions(+), 22 deletions(-) create mode 100644 server/src/com/vaadin/annotations/VaadinServletConfiguration.java create mode 100644 server/tests/src/com/vaadin/server/VaadinServletConfigurationTest.java diff --git a/server/src/com/vaadin/annotations/VaadinServletConfiguration.java b/server/src/com/vaadin/annotations/VaadinServletConfiguration.java new file mode 100644 index 0000000000..38e3ff2ef0 --- /dev/null +++ b/server/src/com/vaadin/annotations/VaadinServletConfiguration.java @@ -0,0 +1,143 @@ +/* + * Copyright 2000-2013 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ + +package com.vaadin.annotations; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import com.vaadin.server.Constants; +import com.vaadin.server.DefaultDeploymentConfiguration; +import com.vaadin.server.DeploymentConfiguration; +import com.vaadin.server.DeploymentConfiguration.LegacyProperyToStringMode; +import com.vaadin.server.VaadinServlet; +import com.vaadin.server.VaadinSession; +import com.vaadin.ui.UI; + +/** + * Annotation for configuring subclasses of {@link VaadinServlet}. For a + * {@link VaadinServlet} class that has this annotation, the defined values are + * read during initialization and will be available using + * {@link DeploymentConfiguration#getApplicationOrSystemProperty(String, String)} + * as well as from specific methods in {@link DeploymentConfiguration}. Init + * params defined in web.xml or the @WebServlet + * annotation take precedence over values defined in this annotation. + * + * @since 7.1 + * @author Vaadin Ltd + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.TYPE) +public @interface VaadinServletConfiguration { + /** + * Defines the init parameter name for methods in + * {@link VaadinServletConfiguration}. + * + * @since 7.1 + * @author Vaadin Ltd + */ + @Retention(RetentionPolicy.RUNTIME) + @Target(ElementType.METHOD) + @Documented + public @interface InitParameterName { + /** + * The name of the init parameter that the annotated method controls. + * + * @return the parameter name + */ + public String value(); + } + + /** + * Whether Vaadin is in production mode. + * + * @return true if in production mode, false otherwise. + * + * @see DeploymentConfiguration#isProductionMode() + */ + @InitParameterName(Constants.SERVLET_PARAMETER_PRODUCTION_MODE) + public boolean productionMode(); + + /** + * Gets the default UI class to use for the servlet. + * + * @return the default UI class + */ + @InitParameterName(VaadinSession.UI_PARAMETER) + public Class ui(); + + /** + * The time resources can be cached in the browser, in seconds. The default + * value is + * {@value DefaultDeploymentConfiguration#DEFAULT_RESOURCE_CACHE_TIME}. + * + * @return the resource cache time + * + * @see DeploymentConfiguration#getResourceCacheTime() + */ + @InitParameterName(Constants.SERVLET_PARAMETER_RESOURCE_CACHE_TIME) + public int resourceCacheTime() default DefaultDeploymentConfiguration.DEFAULT_RESOURCE_CACHE_TIME; + + /** + * The number of seconds between heartbeat requests of a UI, or a + * non-positive number if heartbeat is disabled. The default value is + * {@value DefaultDeploymentConfiguration#DEFAULT_HEARTBEAT_INTERVAL}. + * + * @return the time between heartbeats + * + * @see DeploymentConfiguration#getHeartbeatInterval() + */ + @InitParameterName(Constants.SERVLET_PARAMETER_HEARTBEAT_INTERVAL) + public int heartbeatInterval() default DefaultDeploymentConfiguration.DEFAULT_HEARTBEAT_INTERVAL; + + /** + * Whether a session should be closed when all its open UIs have been idle + * for longer than its configured maximum inactivity time. The default value + * is {@value DefaultDeploymentConfiguration#DEFAULT_CLOSE_IDLE_SESSIONS}. + * + * @return true if UIs and sessions receiving only heartbeat requests are + * eventually closed; false if heartbeat requests extend UI and + * session lifetime indefinitely + * + * @see DeploymentConfiguration#isCloseIdleSessions() + */ + @InitParameterName(Constants.SERVLET_PARAMETER_CLOSE_IDLE_SESSIONS) + public boolean closeIdleSessions() default DefaultDeploymentConfiguration.DEFAULT_CLOSE_IDLE_SESSIONS; + + /** + * The default widgetset to use for the servlet. The default value is + * {@value VaadinServlet#DEFAULT_WIDGETSET}. + * + * @return the default widgetset name + */ + @InitParameterName(VaadinServlet.PARAMETER_WIDGETSET) + public String widgetset() default VaadinServlet.DEFAULT_WIDGETSET; + + /** + * The legacy Property.toString() mode used. The default value is + * {@link LegacyProperyToStringMode#DISABLED} + * + * @return The Property.toString() mode in use. + * + * @deprecated as of 7.1, should only be used to ease migration + */ + @Deprecated + @InitParameterName(Constants.SERVLET_PARAMETER_LEGACY_PROPERTY_TOSTRING) + public LegacyProperyToStringMode legacyPropertyToStringMode() default LegacyProperyToStringMode.DISABLED; +} diff --git a/server/src/com/vaadin/server/DefaultDeploymentConfiguration.java b/server/src/com/vaadin/server/DefaultDeploymentConfiguration.java index 80c3644d77..a55c3231f3 100644 --- a/server/src/com/vaadin/server/DefaultDeploymentConfiguration.java +++ b/server/src/com/vaadin/server/DefaultDeploymentConfiguration.java @@ -30,6 +30,27 @@ import com.vaadin.shared.communication.PushMode; * @since 7.0.0 */ public class DefaultDeploymentConfiguration implements DeploymentConfiguration { + /** + * Default value for {@link #getResourceCacheTime()} = {@value} . + */ + public static final int DEFAULT_RESOURCE_CACHE_TIME = 3600; + + /** + * Default value for {@link #getHeartbeatInterval()} = {@value} . + */ + public static final int DEFAULT_HEARTBEAT_INTERVAL = 300; + + /** + * Default value for {@link #isCloseIdleSessions()} = {@value} . + */ + public static final boolean DEFAULT_CLOSE_IDLE_SESSIONS = false; + + /** + * Default value for {@link #getLegacyPropertyToStringMode()} = + * {@link LegacyProperyToStringMode#WARNING}. + */ + public static final LegacyProperyToStringMode DEFAULT_LEGACY_PROPERTY_TO_STRING = LegacyProperyToStringMode.WARNING; + private final Properties initParameters; private boolean productionMode; private boolean xsrfProtectionEnabled; @@ -66,20 +87,17 @@ public class DefaultDeploymentConfiguration implements DeploymentConfiguration { private void checkLegacyPropertyToString() { String param = getApplicationOrSystemProperty( - Constants.SERVLET_PARAMETER_LEGACY_PROPERTY_TOSTRING, "warning"); - if ("true".equals(param)) { - legacyPropertyToStringMode = LegacyProperyToStringMode.ENABLED; - } else if ("false".equals(param)) { - legacyPropertyToStringMode = LegacyProperyToStringMode.DISABLED; - } else { - if (!"warning".equals(param)) { - getLogger() - .log(Level.WARNING, - Constants.WARNING_UNKNOWN_LEGACY_PROPERTY_TOSTRING_VALUE, - param); - } - legacyPropertyToStringMode = LegacyProperyToStringMode.WARNING; + Constants.SERVLET_PARAMETER_LEGACY_PROPERTY_TOSTRING, + DEFAULT_LEGACY_PROPERTY_TO_STRING.name().toLowerCase()); + try { + legacyPropertyToStringMode = LegacyProperyToStringMode + .valueOf(param.toUpperCase()); + } catch (IllegalArgumentException e) { + getLogger().log(Level.WARNING, + Constants.WARNING_UNKNOWN_LEGACY_PROPERTY_TOSTRING_VALUE, + param); + legacyPropertyToStringMode = DEFAULT_LEGACY_PROPERTY_TO_STRING; } } @@ -250,11 +268,11 @@ public class DefaultDeploymentConfiguration implements DeploymentConfiguration { resourceCacheTime = Integer .parseInt(getApplicationOrSystemProperty( Constants.SERVLET_PARAMETER_RESOURCE_CACHE_TIME, - "3600")); + Integer.toString(DEFAULT_RESOURCE_CACHE_TIME))); } catch (NumberFormatException e) { getLogger().warning( Constants.WARNING_RESOURCE_CACHING_TIME_NOT_NUMERIC); - resourceCacheTime = 3600; + resourceCacheTime = DEFAULT_RESOURCE_CACHE_TIME; } } @@ -263,18 +281,18 @@ public class DefaultDeploymentConfiguration implements DeploymentConfiguration { heartbeatInterval = Integer .parseInt(getApplicationOrSystemProperty( Constants.SERVLET_PARAMETER_HEARTBEAT_INTERVAL, - "300")); + Integer.toString(DEFAULT_HEARTBEAT_INTERVAL))); } catch (NumberFormatException e) { getLogger().warning( Constants.WARNING_HEARTBEAT_INTERVAL_NOT_NUMERIC); - heartbeatInterval = 300; + heartbeatInterval = DEFAULT_HEARTBEAT_INTERVAL; } } private void checkCloseIdleSessions() { closeIdleSessions = getApplicationOrSystemProperty( - Constants.SERVLET_PARAMETER_CLOSE_IDLE_SESSIONS, "false") - .equals("true"); + Constants.SERVLET_PARAMETER_CLOSE_IDLE_SESSIONS, + Boolean.toString(DEFAULT_CLOSE_IDLE_SESSIONS)).equals("true"); } private void checkPushMode() { diff --git a/server/src/com/vaadin/server/VaadinServlet.java b/server/src/com/vaadin/server/VaadinServlet.java index 6f166db2b5..05e3335c00 100644 --- a/server/src/com/vaadin/server/VaadinServlet.java +++ b/server/src/com/vaadin/server/VaadinServlet.java @@ -21,6 +21,7 @@ import java.io.InputStream; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.io.PrintWriter; +import java.lang.reflect.Method; import java.net.MalformedURLException; import java.net.URL; import java.net.URLConnection; @@ -38,6 +39,8 @@ import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +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; @@ -66,6 +69,8 @@ public class VaadinServlet extends HttpServlet implements Constants { super.init(servletConfig); Properties initParameters = new Properties(); + readConfigurationAnnotation(initParameters); + // Read default parameters from server.xml final ServletContext context = servletConfig.getServletContext(); for (final Enumeration e = context.getInitParameterNames(); e @@ -96,6 +101,39 @@ public class VaadinServlet extends HttpServlet implements Constants { CurrentInstance.clearAll(); } + private void readConfigurationAnnotation(Properties initParameters) + throws ServletException { + VaadinServletConfiguration configAnnotation = UIProvider + .getAnnotationFor(getClass(), VaadinServletConfiguration.class); + if (configAnnotation != null) { + Method[] methods = VaadinServletConfiguration.class + .getDeclaredMethods(); + for (Method method : methods) { + InitParameterName name = method + .getAnnotation(InitParameterName.class); + assert name != null : "All methods declared in VaadinServletConfiguration should have a @InitParameterName annotation"; + + try { + Object value = method.invoke(configAnnotation); + + String stringValue; + if (value instanceof Class) { + stringValue = ((Class) value).getName(); + } else { + stringValue = value.toString(); + } + + initParameters.setProperty(name.value(), stringValue); + } catch (Exception e) { + // This should never happen + throw new ServletException( + "Could not read @VaadinServletConfiguration value " + + method.getName(), e); + } + } + } + } + protected void servletInitialized() throws ServletException { // Empty by default } diff --git a/server/tests/src/com/vaadin/server/MockServletConfig.java b/server/tests/src/com/vaadin/server/MockServletConfig.java index b1e046c812..cd1201c249 100644 --- a/server/tests/src/com/vaadin/server/MockServletConfig.java +++ b/server/tests/src/com/vaadin/server/MockServletConfig.java @@ -19,8 +19,8 @@ */ package com.vaadin.server; -import java.util.Collections; import java.util.Enumeration; +import java.util.Properties; import javax.servlet.ServletConfig; import javax.servlet.ServletContext; @@ -33,6 +33,15 @@ import javax.servlet.ServletContext; public class MockServletConfig implements ServletConfig { private ServletContext context = new MockServletContext(); + private final Properties initParameters; + + public MockServletConfig() { + this(new Properties()); + } + + public MockServletConfig(Properties initParameters) { + this.initParameters = initParameters; + } /* * (non-Javadoc) @@ -61,7 +70,7 @@ public class MockServletConfig implements ServletConfig { */ @Override public String getInitParameter(String name) { - return null; + return initParameters.getProperty(name); } /* @@ -71,7 +80,7 @@ public class MockServletConfig implements ServletConfig { */ @Override public Enumeration getInitParameterNames() { - return Collections.enumeration(Collections.EMPTY_LIST); + return initParameters.propertyNames(); } } diff --git a/server/tests/src/com/vaadin/server/VaadinServletConfigurationTest.java b/server/tests/src/com/vaadin/server/VaadinServletConfigurationTest.java new file mode 100644 index 0000000000..80cb1d7b0c --- /dev/null +++ b/server/tests/src/com/vaadin/server/VaadinServletConfigurationTest.java @@ -0,0 +1,98 @@ +/* + * Copyright 2000-2013 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.util.Properties; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; + +import junit.framework.Assert; + +import org.easymock.EasyMock; +import org.junit.Test; + +import com.vaadin.annotations.VaadinServletConfiguration; +import com.vaadin.server.DeploymentConfiguration.LegacyProperyToStringMode; +import com.vaadin.server.VaadinServletConfigurationTest.MockUI; +import com.vaadin.ui.UI; + +public class VaadinServletConfigurationTest { + public static class MockUI extends UI { + @Override + protected void init(VaadinRequest request) { + // Do nothing + } + } + + @Test + public void testValuesFromAnnotation() throws ServletException { + TestServlet servlet = new TestServlet(); + servlet.init(new MockServletConfig()); + DeploymentConfiguration configuration = servlet.getService() + .getDeploymentConfiguration(); + + Assert.assertEquals(true, configuration.isProductionMode()); + Assert.assertEquals(LegacyProperyToStringMode.DISABLED, + configuration.getLegacyPropertyToStringMode()); + Assert.assertEquals(true, configuration.isCloseIdleSessions()); + Assert.assertEquals(1234, configuration.getHeartbeatInterval()); + Assert.assertEquals(4321, configuration.getResourceCacheTime()); + + Class uiClass = new DefaultUIProvider() + .getUIClass(new UIClassSelectionEvent(new VaadinServletRequest( + EasyMock.createMock(HttpServletRequest.class), servlet + .getService()))); + Assert.assertEquals(MockUI.class, uiClass); + } + + @Test + public void testValuesOverriddenForServlet() throws ServletException { + Properties servletInitParams = new Properties(); + servletInitParams.setProperty("productionMode", "false"); + servletInitParams.setProperty("heartbeatInterval", "1111"); + + TestServlet servlet = new TestServlet(); + servlet.init(new MockServletConfig(servletInitParams)); + DeploymentConfiguration configuration = servlet.getService() + .getDeploymentConfiguration(); + + // Values from servlet init params take precedence + Assert.assertEquals(1111, configuration.getHeartbeatInterval()); + Assert.assertEquals(false, configuration.isProductionMode()); + + // Other params are as defined in the annotation + Assert.assertEquals(LegacyProperyToStringMode.DISABLED, + configuration.getLegacyPropertyToStringMode()); + Assert.assertEquals(true, configuration.isCloseIdleSessions()); + Assert.assertEquals(4321, configuration.getResourceCacheTime()); + + Class uiClass = new DefaultUIProvider() + .getUIClass(new UIClassSelectionEvent(new VaadinServletRequest( + EasyMock.createMock(HttpServletRequest.class), servlet + .getService()))); + Assert.assertEquals(MockUI.class, uiClass); + } +} + +@VaadinServletConfiguration(productionMode = true, ui = MockUI.class, closeIdleSessions = true, heartbeatInterval = 1234, resourceCacheTime = 4321) +class TestServlet extends VaadinServlet { + +} -- cgit v1.2.3 From aa99259eac14854e1e9a33fbbd429d0c5ffa9c52 Mon Sep 17 00:00:00 2001 From: Artur Signell Date: Tue, 4 Jun 2013 22:29:26 +0300 Subject: Send connector debug (highlight) using RPC (#11536) Change-Id: I8995e9affd371543457f16568f1245f7467e0804 --- .../com/vaadin/client/ApplicationConnection.java | 8 +- .../src/com/vaadin/client/ui/ui/UIConnector.java | 16 ++++ .../server/communication/MetadataWriter.java | 12 +-- .../server/communication/UidlRequestHandler.java | 71 +-------------- .../vaadin/server/communication/UidlWriter.java | 2 +- server/src/com/vaadin/ui/UI.java | 17 ++++ server/src/com/vaadin/util/ConnectorHelper.java | 101 +++++++++++++++++++++ .../com/vaadin/shared/ApplicationConstants.java | 1 - .../vaadin/shared/ui/ui/DebugWindowServerRpc.java | 43 +++++++++ 9 files changed, 184 insertions(+), 87 deletions(-) create mode 100644 server/src/com/vaadin/util/ConnectorHelper.java create mode 100644 shared/src/com/vaadin/shared/ui/ui/DebugWindowServerRpc.java diff --git a/client/src/com/vaadin/client/ApplicationConnection.java b/client/src/com/vaadin/client/ApplicationConnection.java index 2f5401a75b..4dd68cc24f 100644 --- a/client/src/com/vaadin/client/ApplicationConnection.java +++ b/client/src/com/vaadin/client/ApplicationConnection.java @@ -691,12 +691,12 @@ public class ApplicationConnection { * source code. * * @param serverConnector + * @deprecated as of 7.1. Replaced by + * {@link UIConnector#showServerDebugInfo(ServerConnector)} */ + @Deprecated void highlightConnector(ServerConnector serverConnector) { - String params = getRepaintAllParameters() + "&" - + ApplicationConstants.PARAM_HIGHLIGHT_CONNECTOR + "=" - + serverConnector.getConnectorId(); - makeUidlRequest("", params); + getUIConnector().showServerDebugInfo(serverConnector); } /** diff --git a/client/src/com/vaadin/client/ui/ui/UIConnector.java b/client/src/com/vaadin/client/ui/ui/UIConnector.java index bba9252d47..38c26a77e6 100644 --- a/client/src/com/vaadin/client/ui/ui/UIConnector.java +++ b/client/src/com/vaadin/client/ui/ui/UIConnector.java @@ -50,6 +50,7 @@ import com.vaadin.client.ConnectorHierarchyChangeEvent; import com.vaadin.client.ConnectorMap; import com.vaadin.client.Focusable; import com.vaadin.client.Paintable; +import com.vaadin.client.ServerConnector; import com.vaadin.client.UIDL; import com.vaadin.client.VConsole; import com.vaadin.client.communication.StateChangeEvent; @@ -68,6 +69,7 @@ import com.vaadin.shared.communication.MethodInvocation; import com.vaadin.shared.ui.ComponentStateUtil; import com.vaadin.shared.ui.Connect; import com.vaadin.shared.ui.Connect.LoadStyle; +import com.vaadin.shared.ui.ui.DebugWindowServerRpc; import com.vaadin.shared.ui.ui.PageClientRpc; import com.vaadin.shared.ui.ui.PageState; import com.vaadin.shared.ui.ui.ScrollClientRpc; @@ -659,4 +661,18 @@ public class UIConnector extends AbstractSingleComponentContainerConnector .getName(), "poll")); } } + + /** + * Sends a request to the server to print details to console that will help + * the developer to locate the corresponding server-side connector in the + * source code. + * + * @since 7.1 + * @param serverConnector + * the connector to locate + */ + public void showServerDebugInfo(ServerConnector serverConnector) { + getRpcProxy(DebugWindowServerRpc.class).showServerDebugInfo( + serverConnector); + } } diff --git a/server/src/com/vaadin/server/communication/MetadataWriter.java b/server/src/com/vaadin/server/communication/MetadataWriter.java index 1a3f0e946a..9993ef1e44 100644 --- a/server/src/com/vaadin/server/communication/MetadataWriter.java +++ b/server/src/com/vaadin/server/communication/MetadataWriter.java @@ -22,7 +22,6 @@ import java.io.Serializable; import java.io.Writer; import java.util.List; -import com.vaadin.server.ClientConnector; import com.vaadin.server.ComponentSizeValidator; import com.vaadin.server.ComponentSizeValidator.InvalidLayout; import com.vaadin.server.SystemMessages; @@ -54,9 +53,6 @@ public class MetadataWriter implements Serializable { * @param async * True if this message is sent by the server asynchronously, * false if it is a response to a client message. - * @param hilightedConnector - * The connector that should be highlighted on the client or null - * if none. * @param messages * a {@link SystemMessages} containing client-side error * messages. @@ -65,8 +61,7 @@ public class MetadataWriter implements Serializable { * */ public void write(UI ui, Writer writer, boolean repaintAll, - boolean analyzeLayouts, boolean async, - ClientConnector hilightedConnector, SystemMessages messages) + boolean analyzeLayouts, boolean async, SystemMessages messages) throws IOException { List invalidComponentRelativeSizes = null; @@ -109,11 +104,6 @@ public class MetadataWriter implements Serializable { } writer.write("]"); } - if (hilightedConnector != null) { - writer.write(", \"hl\":\""); - writer.write(hilightedConnector.getConnectorId()); - writer.write("\""); - } } if (async) { diff --git a/server/src/com/vaadin/server/communication/UidlRequestHandler.java b/server/src/com/vaadin/server/communication/UidlRequestHandler.java index 73ff92f8bd..55fb473998 100644 --- a/server/src/com/vaadin/server/communication/UidlRequestHandler.java +++ b/server/src/com/vaadin/server/communication/UidlRequestHandler.java @@ -19,13 +19,11 @@ package com.vaadin.server.communication; import java.io.IOException; import java.io.StringWriter; import java.io.Writer; -import java.util.LinkedList; import java.util.logging.Level; import java.util.logging.Logger; import org.json.JSONException; -import com.vaadin.server.ClientConnector; import com.vaadin.server.Constants; import com.vaadin.server.LegacyCommunicationManager.InvalidUIDLSecurityKeyException; import com.vaadin.server.ServletPortletHelper; @@ -39,7 +37,6 @@ import com.vaadin.server.VaadinSession; import com.vaadin.shared.ApplicationConstants; import com.vaadin.shared.JsonConstants; import com.vaadin.shared.Version; -import com.vaadin.ui.Component; import com.vaadin.ui.UI; /** @@ -79,11 +76,10 @@ public class UidlRequestHandler extends SynchronizedRequestHandler implements checkWidgetsetVersion(request); String requestThemeName = request.getParameter("theme"); - ClientConnector highlightedConnector; // repaint requested or session has timed out and new one is created boolean repaintAll; - // TODO PUSH repaintAll, analyzeLayouts, highlightConnector should be + // TODO PUSH repaintAll, analyzeLayouts should be // part of the message payload to make the functionality transport // agnostic @@ -95,14 +91,6 @@ public class UidlRequestHandler extends SynchronizedRequestHandler implements // analyzing can be done only with repaintAll analyzeLayouts = (request .getParameter(ApplicationConstants.PARAM_ANALYZE_LAYOUTS) != null); - - String pid = request - .getParameter(ApplicationConstants.PARAM_HIGHLIGHT_CONNECTOR); - if (pid != null) { - highlightedConnector = uI.getConnectorTracker().getConnector( - pid); - highlightConnector(highlightedConnector); - } } StringWriter stringWriter = new StringWriter(); @@ -190,63 +178,6 @@ public class UidlRequestHandler extends SynchronizedRequestHandler implements outWriter.write("for(;;);[{"); } - // TODO Does this belong here? - protected void highlightConnector(ClientConnector highlightedConnector) { - StringBuilder sb = new StringBuilder(); - sb.append("*** Debug details of a connector: *** \n"); - sb.append("Type: "); - sb.append(highlightedConnector.getClass().getName()); - sb.append("\nId:"); - sb.append(highlightedConnector.getConnectorId()); - if (highlightedConnector instanceof Component) { - Component component = (Component) highlightedConnector; - if (component.getCaption() != null) { - sb.append("\nCaption:"); - sb.append(component.getCaption()); - } - } - printHighlightedConnectorHierarchy(sb, highlightedConnector); - getLogger().info(sb.toString()); - } - - // TODO Does this belong here? - protected void printHighlightedConnectorHierarchy(StringBuilder sb, - ClientConnector connector) { - LinkedList h = new LinkedList(); - h.add(connector); - ClientConnector parent = connector.getParent(); - while (parent != null) { - h.addFirst(parent); - parent = parent.getParent(); - } - - sb.append("\nConnector hierarchy:\n"); - VaadinSession session2 = connector.getUI().getSession(); - sb.append(session2.getClass().getName()); - sb.append("("); - sb.append(session2.getClass().getSimpleName()); - sb.append(".java"); - sb.append(":1)"); - int l = 1; - for (ClientConnector connector2 : h) { - sb.append("\n"); - for (int i = 0; i < l; i++) { - sb.append(" "); - } - l++; - Class connectorClass = connector2 - .getClass(); - Class topClass = connectorClass; - while (topClass.getEnclosingClass() != null) { - topClass = topClass.getEnclosingClass(); - } - sb.append(connectorClass.getName()); - sb.append("("); - sb.append(topClass.getSimpleName()); - sb.append(".java:1)"); - } - } - private static final Logger getLogger() { return Logger.getLogger(UidlRequestHandler.class.getName()); } diff --git a/server/src/com/vaadin/server/communication/UidlWriter.java b/server/src/com/vaadin/server/communication/UidlWriter.java index 9c736d8dd9..a915501056 100644 --- a/server/src/com/vaadin/server/communication/UidlWriter.java +++ b/server/src/com/vaadin/server/communication/UidlWriter.java @@ -162,7 +162,7 @@ public class UidlWriter implements Serializable { .getSystemMessages(ui.getLocale(), null); // TODO hilightedConnector new MetadataWriter().write(ui, writer, repaintAll, analyzeLayouts, - async, null, messages); + async, messages); writer.write(", "); writer.write("\"resources\" : "); diff --git a/server/src/com/vaadin/ui/UI.java b/server/src/com/vaadin/ui/UI.java index d4ac156787..3194786431 100644 --- a/server/src/com/vaadin/ui/UI.java +++ b/server/src/com/vaadin/ui/UI.java @@ -23,6 +23,7 @@ import java.util.Iterator; import java.util.LinkedHashSet; import java.util.Map; import java.util.concurrent.Future; +import java.util.logging.Logger; import com.vaadin.event.Action; import com.vaadin.event.Action.Handler; @@ -30,6 +31,7 @@ import com.vaadin.event.ActionManager; import com.vaadin.event.MouseEvents.ClickEvent; import com.vaadin.event.MouseEvents.ClickListener; import com.vaadin.navigator.Navigator; +import com.vaadin.server.ClientConnector; import com.vaadin.server.LocaleService; import com.vaadin.server.Page; import com.vaadin.server.PaintException; @@ -40,15 +42,18 @@ import com.vaadin.server.VaadinService; import com.vaadin.server.VaadinServlet; import com.vaadin.server.VaadinSession; import com.vaadin.server.communication.PushConnection; +import com.vaadin.shared.Connector; import com.vaadin.shared.EventId; import com.vaadin.shared.MouseEventDetails; import com.vaadin.shared.communication.PushMode; +import com.vaadin.shared.ui.ui.DebugWindowServerRpc; import com.vaadin.shared.ui.ui.ScrollClientRpc; import com.vaadin.shared.ui.ui.UIClientRpc; import com.vaadin.shared.ui.ui.UIConstants; import com.vaadin.shared.ui.ui.UIServerRpc; import com.vaadin.shared.ui.ui.UIState; import com.vaadin.ui.Component.Focusable; +import com.vaadin.util.ConnectorHelper; import com.vaadin.util.CurrentInstance; /** @@ -161,6 +166,14 @@ public abstract class UI extends AbstractSingleComponentContainer implements */ } }; + private DebugWindowServerRpc debugRpc = new DebugWindowServerRpc() { + @Override + public void showServerDebugInfo(Connector connector) { + String info = ConnectorHelper + .getDebugInformation((ClientConnector) connector); + getLogger().info(info); + } + }; /** * Timestamp keeping track of the last heartbeat of this UI. Updated to the @@ -193,6 +206,7 @@ public abstract class UI extends AbstractSingleComponentContainer implements */ public UI(Component content) { registerRpc(rpc); + registerRpc(debugRpc); setSizeFull(); setContent(content); } @@ -1441,4 +1455,7 @@ public abstract class UI extends AbstractSingleComponentContainer implements return localeService; } + private static Logger getLogger() { + return Logger.getLogger(UI.class.getName()); + } } diff --git a/server/src/com/vaadin/util/ConnectorHelper.java b/server/src/com/vaadin/util/ConnectorHelper.java new file mode 100644 index 0000000000..e698e9222a --- /dev/null +++ b/server/src/com/vaadin/util/ConnectorHelper.java @@ -0,0 +1,101 @@ +/* + * Copyright 2000-2013 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.util; + +import java.util.LinkedList; + +import com.vaadin.server.ClientConnector; +import com.vaadin.ui.Component; + +/** + * Provides various helper methods for connectors. Meant for internal use. + * + * @since 7.1 + * @author Vaadin Ltd + */ +public class ConnectorHelper { + + /** + * Creates a string containing debug info for the connector + * + * @since 7.1 + * @param connector + * The connector to print debug info about + * @return A string with debug information + */ + public static String getDebugInformation(ClientConnector connector) { + StringBuilder sb = new StringBuilder(); + sb.append("*** Debug details of a connector: *** \n"); + sb.append("Type: "); + sb.append(connector.getClass().getName()); + sb.append("\nId:"); + sb.append(connector.getConnectorId()); + if (connector instanceof Component) { + Component component = (Component) connector; + if (component.getCaption() != null) { + sb.append("\nCaption:"); + sb.append(component.getCaption()); + } + } + writeHierarchyInformation(connector, sb); + return sb.toString(); + } + + /** + * Creates a string containing hierarchy information for the connector + * + * @since 7.1 + * @param connector + * The connector to get hierarchy information for + * @param builder + * The StringBuilder where the information should be written + */ + public static void writeHierarchyInformation(ClientConnector connector, + StringBuilder builder) { + LinkedList h = new LinkedList(); + h.add(connector); + ClientConnector parent = connector.getParent(); + while (parent != null) { + h.addFirst(parent); + parent = parent.getParent(); + } + + builder.append("\nConnector hierarchy:\n"); + + int l = 0; + for (ClientConnector connector2 : h) { + if (l != 0) { + builder.append("\n"); + for (int i = 0; i < l; i++) { + builder.append(" "); + } + } + l++; + Class connectorClass = connector2 + .getClass(); + Class topClass = connectorClass; + while (topClass.getEnclosingClass() != null) { + topClass = topClass.getEnclosingClass(); + } + builder.append(connectorClass.getName()); + builder.append("("); + builder.append(topClass.getSimpleName()); + builder.append(".java:1)"); + } + } + +} diff --git a/shared/src/com/vaadin/shared/ApplicationConstants.java b/shared/src/com/vaadin/shared/ApplicationConstants.java index 04cba79c0c..6124b71d34 100644 --- a/shared/src/com/vaadin/shared/ApplicationConstants.java +++ b/shared/src/com/vaadin/shared/ApplicationConstants.java @@ -40,7 +40,6 @@ public class ApplicationConstants implements Serializable { public static final String UIDL_SECURITY_TOKEN_ID = "Vaadin-Security-Key"; public static final String PARAM_ANALYZE_LAYOUTS = "analyzeLayouts"; - public static final String PARAM_HIGHLIGHT_CONNECTOR = "highlightConnector"; @Deprecated public static final String UPDATE_VARIABLE_INTERFACE = "v"; diff --git a/shared/src/com/vaadin/shared/ui/ui/DebugWindowServerRpc.java b/shared/src/com/vaadin/shared/ui/ui/DebugWindowServerRpc.java new file mode 100644 index 0000000000..ec8bc45b81 --- /dev/null +++ b/shared/src/com/vaadin/shared/ui/ui/DebugWindowServerRpc.java @@ -0,0 +1,43 @@ +/* + * Copyright 2000-2013 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.shared.ui.ui; + +import com.vaadin.shared.Connector; +import com.vaadin.shared.communication.ServerRpc; + +/** + * Server RPC methods for the Debug Window. + * + * @since 7.1 + * @author Vaadin Ltd + */ +public interface DebugWindowServerRpc extends ServerRpc { + /** + * Sends a request to the server to print details to console that will help + * the developer to locate the corresponding server-side connector in the + * source code. + * + * @since 7.1 + * @param connector + * the connector to locate + **/ + public void showServerDebugInfo(Connector connector); + +} -- cgit v1.2.3 From 6d4582eea9e19518c7341ec65357b1d04a1a37c6 Mon Sep 17 00:00:00 2001 From: Artur Signell Date: Tue, 4 Jun 2013 23:13:29 +0300 Subject: Change analyze layouts to use RPC (#11536) Change-Id: I80d39e4ce4e0576b98ad095efce03740291d3de5 --- .../com/vaadin/client/ApplicationConnection.java | 45 ++------------------ client/src/com/vaadin/client/VConsole.java | 5 +-- .../src/com/vaadin/client/ui/ui/UIConnector.java | 24 +++++++++++ .../com/vaadin/server/ComponentSizeValidator.java | 48 +++++++++++++++++----- .../communication/AtmospherePushConnection.java | 2 +- .../server/communication/MetadataWriter.java | 44 +------------------- .../vaadin/server/communication/UIInitHandler.java | 2 +- .../server/communication/UidlRequestHandler.java | 16 ++------ .../vaadin/server/communication/UidlWriter.java | 8 ++-- server/src/com/vaadin/ui/UI.java | 30 ++++++++++++++ .../com/vaadin/shared/ApplicationConstants.java | 2 - .../vaadin/shared/ui/ui/DebugWindowServerRpc.java | 7 ++++ 12 files changed, 115 insertions(+), 118 deletions(-) diff --git a/client/src/com/vaadin/client/ApplicationConnection.java b/client/src/com/vaadin/client/ApplicationConnection.java index 4dd68cc24f..a3279e5631 100644 --- a/client/src/com/vaadin/client/ApplicationConnection.java +++ b/client/src/com/vaadin/client/ApplicationConnection.java @@ -221,8 +221,6 @@ public class ApplicationConnection { private Date requestStartTime; - private boolean validatingLayouts = false; - private final LayoutManager layoutManager; private final RpcManager rpcManager; @@ -678,11 +676,12 @@ public class ApplicationConnection { /** * Requests an analyze of layouts, to find inconsistencies. Exclusively used * for debugging during development. + * + * @deprecated as of 7.1. Replaced by {@link UIConnector#analyzeLayouts()} */ + @Deprecated public void analyzeLayouts() { - String params = getRepaintAllParameters() + "&" - + ApplicationConstants.PARAM_ANALYZE_LAYOUTS + "=1"; - makeUidlRequest("", params); + getUIConnector().analyzeLayouts(); } /** @@ -1358,9 +1357,6 @@ public class ApplicationConnection { meta = json.getValueMap("meta"); if (meta.containsKey("repaintAll")) { prepareRepaintAll(); - if (meta.containsKey("invalidLayouts")) { - validatingLayouts = true; - } } if (meta.containsKey("timedRedirect")) { final ValueMap timedRedirect = meta @@ -1461,17 +1457,6 @@ public class ApplicationConnection { applicationRunning = false; } - if (validatingLayouts) { - Set zeroHeightComponents = new HashSet(); - Set zeroWidthComponents = new HashSet(); - findZeroSizeComponents(zeroHeightComponents, - zeroWidthComponents, getUIConnector()); - VConsole.printLayoutProblems(meta, - ApplicationConnection.this, - zeroHeightComponents, zeroWidthComponents); - validatingLayouts = false; - - } Profiler.leave("Error handling"); } @@ -2226,28 +2211,6 @@ public class ApplicationConnection { ApplicationConfiguration.runWhenDependenciesLoaded(c); } - private void findZeroSizeComponents( - Set zeroHeightComponents, - Set zeroWidthComponents, - ComponentConnector connector) { - Widget widget = connector.getWidget(); - ComputedStyle computedStyle = new ComputedStyle(widget.getElement()); - if (computedStyle.getIntProperty("height") == 0) { - zeroHeightComponents.add(connector); - } - if (computedStyle.getIntProperty("width") == 0) { - zeroWidthComponents.add(connector); - } - List children = connector.getChildren(); - for (ServerConnector serverConnector : children) { - if (serverConnector instanceof ComponentConnector) { - findZeroSizeComponents(zeroHeightComponents, - zeroWidthComponents, - (ComponentConnector) serverConnector); - } - } - } - private void loadStyleDependencies(JsArrayString dependencies) { // Assuming no reason to interpret in a defined order ResourceLoadListener resourceLoadListener = new ResourceLoadListener() { diff --git a/client/src/com/vaadin/client/VConsole.java b/client/src/com/vaadin/client/VConsole.java index f7a7554e34..37ed8e6370 100644 --- a/client/src/com/vaadin/client/VConsole.java +++ b/client/src/com/vaadin/client/VConsole.java @@ -15,7 +15,6 @@ */ package com.vaadin.client; -import java.util.Set; import java.util.logging.Level; import java.util.logging.Logger; @@ -81,9 +80,7 @@ public class VConsole { } public static void printLayoutProblems(ValueMap meta, - ApplicationConnection applicationConnection, - Set zeroHeightComponents, - Set zeroWidthComponents) { + ApplicationConnection applicationConnection) { if (impl != null) { impl.meta(applicationConnection, meta); } diff --git a/client/src/com/vaadin/client/ui/ui/UIConnector.java b/client/src/com/vaadin/client/ui/ui/UIConnector.java index 38c26a77e6..1c2c6ddeb8 100644 --- a/client/src/com/vaadin/client/ui/ui/UIConnector.java +++ b/client/src/com/vaadin/client/ui/ui/UIConnector.java @@ -53,6 +53,7 @@ import com.vaadin.client.Paintable; import com.vaadin.client.ServerConnector; import com.vaadin.client.UIDL; import com.vaadin.client.VConsole; +import com.vaadin.client.ValueMap; import com.vaadin.client.communication.StateChangeEvent; import com.vaadin.client.communication.StateChangeEvent.StateChangeHandler; import com.vaadin.client.ui.AbstractSingleComponentContainerConnector; @@ -69,6 +70,7 @@ import com.vaadin.shared.communication.MethodInvocation; import com.vaadin.shared.ui.ComponentStateUtil; import com.vaadin.shared.ui.Connect; import com.vaadin.shared.ui.Connect.LoadStyle; +import com.vaadin.shared.ui.ui.DebugWindowClientRpc; import com.vaadin.shared.ui.ui.DebugWindowServerRpc; import com.vaadin.shared.ui.ui.PageClientRpc; import com.vaadin.shared.ui.ui.PageState; @@ -136,6 +138,19 @@ public class UIConnector extends AbstractSingleComponentContainerConnector }); } }); + registerRpc(DebugWindowClientRpc.class, new DebugWindowClientRpc() { + + @Override + public void reportLayoutProblems(String json) { + VConsole.printLayoutProblems(getValueMap(json), getConnection()); + } + + private native ValueMap getValueMap(String json) + /*-{ + return JSON.parse(json); + }-*/; + }); + getWidget().addResizeHandler(new ResizeHandler() { @Override public void onResize(ResizeEvent event) { @@ -662,6 +677,15 @@ public class UIConnector extends AbstractSingleComponentContainerConnector } } + /** + * Invokes the layout analyzer on the server + * + * @since 7.1 + */ + public void analyzeLayouts() { + getRpcProxy(DebugWindowServerRpc.class).analyzeLayouts(); + } + /** * Sends a request to the server to print details to console that will help * the developer to locate the corresponding server-side connector in the diff --git a/server/src/com/vaadin/server/ComponentSizeValidator.java b/server/src/com/vaadin/server/ComponentSizeValidator.java index 27d087a2b2..07c195a1c1 100644 --- a/server/src/com/vaadin/server/ComponentSizeValidator.java +++ b/server/src/com/vaadin/server/ComponentSizeValidator.java @@ -16,8 +16,8 @@ package com.vaadin.server; import java.io.PrintStream; -import java.io.PrintWriter; import java.io.Serializable; +import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.LinkedList; @@ -40,6 +40,7 @@ import com.vaadin.ui.GridLayout.Area; import com.vaadin.ui.Layout; import com.vaadin.ui.Panel; import com.vaadin.ui.TabSheet; +import com.vaadin.ui.UI; import com.vaadin.ui.VerticalLayout; import com.vaadin.ui.Window; @@ -190,14 +191,14 @@ public class ComponentSizeValidator implements Serializable { subErrors.add(error); } - public void reportErrors(PrintWriter clientJSON, + public void reportErrors(StringBuilder clientJSON, PrintStream serverErrorStream) { - clientJSON.write("{"); + clientJSON.append("{"); Component parent = component.getParent(); String paintableId = component.getConnectorId(); - clientJSON.print("id:\"" + paintableId + "\""); + clientJSON.append("\"id\":\"" + paintableId + "\""); if (invalidHeight) { Stack attributes = null; @@ -227,7 +228,7 @@ public class ComponentSizeValidator implements Serializable { attributes = getHeightAttributes(component); } printServerError(msg, attributes, false, serverErrorStream); - clientJSON.print(",\"heightMsg\":\"" + msg + "\""); + clientJSON.append(",\"heightMsg\":\"" + msg + "\""); } if (invalidWidth) { Stack attributes = null; @@ -255,25 +256,25 @@ public class ComponentSizeValidator implements Serializable { msg = "A component with relative width needs a parent with defined width."; attributes = getWidthAttributes(component); } - clientJSON.print(",\"widthMsg\":\"" + msg + "\""); + clientJSON.append(",\"widthMsg\":\"" + msg + "\""); printServerError(msg, attributes, true, serverErrorStream); } if (subErrors.size() > 0) { serverErrorStream.println("Sub errors >>"); - clientJSON.write(", \"subErrors\" : ["); + clientJSON.append(", \"subErrors\" : ["); boolean first = true; for (InvalidLayout subError : subErrors) { if (!first) { - clientJSON.print(","); + clientJSON.append(","); } else { first = false; } subError.reportErrors(clientJSON, serverErrorStream); } - clientJSON.write("]"); + clientJSON.append("]"); serverErrorStream.println("<< Sub erros"); } - clientJSON.write("}"); + clientJSON.append("}"); } } @@ -673,4 +674,31 @@ public class ComponentSizeValidator implements Serializable { return Logger.getLogger(ComponentSizeValidator.class.getName()); } + /** + * Validates the layout and returns a collection of errors + * + * @since 7.1 + * @param ui + * The UI to validate + * @return A collection of errors. An empty collection if there are no + * errors. + */ + public static List validateLayouts(UI ui) { + List invalidRelativeSizes = ComponentSizeValidator + .validateComponentRelativeSizes(ui.getContent(), + new ArrayList(), + null); + + // Also check any existing subwindows + if (ui.getWindows() != null) { + for (Window subWindow : ui.getWindows()) { + invalidRelativeSizes = ComponentSizeValidator + .validateComponentRelativeSizes(subWindow.getContent(), + invalidRelativeSizes, null); + } + } + return invalidRelativeSizes; + + } + } diff --git a/server/src/com/vaadin/server/communication/AtmospherePushConnection.java b/server/src/com/vaadin/server/communication/AtmospherePushConnection.java index e967dd925a..9e57ccb45d 100644 --- a/server/src/com/vaadin/server/communication/AtmospherePushConnection.java +++ b/server/src/com/vaadin/server/communication/AtmospherePushConnection.java @@ -123,7 +123,7 @@ public class AtmospherePushConnection implements PushConnection { protected void push(boolean async) throws IOException { Writer writer = new StringWriter(); try { - new UidlWriter().write(getUI(), writer, false, false, async); + new UidlWriter().write(getUI(), writer, false, async); } catch (JSONException e) { throw new IOException("Error writing UIDL", e); } diff --git a/server/src/com/vaadin/server/communication/MetadataWriter.java b/server/src/com/vaadin/server/communication/MetadataWriter.java index 9993ef1e44..5ad7186c24 100644 --- a/server/src/com/vaadin/server/communication/MetadataWriter.java +++ b/server/src/com/vaadin/server/communication/MetadataWriter.java @@ -17,16 +17,11 @@ package com.vaadin.server.communication; import java.io.IOException; -import java.io.PrintWriter; import java.io.Serializable; import java.io.Writer; -import java.util.List; -import com.vaadin.server.ComponentSizeValidator; -import com.vaadin.server.ComponentSizeValidator.InvalidLayout; import com.vaadin.server.SystemMessages; import com.vaadin.ui.UI; -import com.vaadin.ui.Window; /** * Serializes miscellaneous metadata to JSON. @@ -60,26 +55,8 @@ public class MetadataWriter implements Serializable { * If the serialization fails. * */ - public void write(UI ui, Writer writer, boolean repaintAll, - boolean analyzeLayouts, boolean async, SystemMessages messages) - throws IOException { - - List invalidComponentRelativeSizes = null; - - if (analyzeLayouts) { - invalidComponentRelativeSizes = ComponentSizeValidator - .validateComponentRelativeSizes(ui.getContent(), null, null); - - // Also check any existing subwindows - if (ui.getWindows() != null) { - for (Window subWindow : ui.getWindows()) { - invalidComponentRelativeSizes = ComponentSizeValidator - .validateComponentRelativeSizes( - subWindow.getContent(), - invalidComponentRelativeSizes, null); - } - } - } + public void write(UI ui, Writer writer, boolean repaintAll, boolean async, + SystemMessages messages) throws IOException { writer.write("{"); @@ -87,23 +64,6 @@ public class MetadataWriter implements Serializable { if (repaintAll) { metaOpen = true; writer.write("\"repaintAll\":true"); - if (analyzeLayouts) { - writer.write(", \"invalidLayouts\":"); - writer.write("["); - if (invalidComponentRelativeSizes != null) { - boolean first = true; - for (InvalidLayout invalidLayout : invalidComponentRelativeSizes) { - if (!first) { - writer.write(","); - } else { - first = false; - } - invalidLayout.reportErrors(new PrintWriter(writer), - System.err); - } - } - writer.write("]"); - } } if (async) { diff --git a/server/src/com/vaadin/server/communication/UIInitHandler.java b/server/src/com/vaadin/server/communication/UIInitHandler.java index e4b5360b49..8507bf40cc 100644 --- a/server/src/com/vaadin/server/communication/UIInitHandler.java +++ b/server/src/com/vaadin/server/communication/UIInitHandler.java @@ -273,7 +273,7 @@ public abstract class UIInitHandler extends SynchronizedRequestHandler { if (session.getConfiguration().isXsrfProtectionEnabled()) { writer.write(getSecurityKeyUIDL(session)); } - new UidlWriter().write(uI, writer, true, false, false); + new UidlWriter().write(uI, writer, true, false); writer.write("}"); String initialUIDL = writer.toString(); diff --git a/server/src/com/vaadin/server/communication/UidlRequestHandler.java b/server/src/com/vaadin/server/communication/UidlRequestHandler.java index 55fb473998..3564aa65b5 100644 --- a/server/src/com/vaadin/server/communication/UidlRequestHandler.java +++ b/server/src/com/vaadin/server/communication/UidlRequestHandler.java @@ -86,13 +86,6 @@ public class UidlRequestHandler extends SynchronizedRequestHandler implements repaintAll = (request .getParameter(ApplicationConstants.URL_PARAMETER_REPAINT_ALL) != null); - boolean analyzeLayouts = false; - if (repaintAll) { - // analyzing can be done only with repaintAll - analyzeLayouts = (request - .getParameter(ApplicationConstants.PARAM_ANALYZE_LAYOUTS) != null); - } - StringWriter stringWriter = new StringWriter(); try { @@ -102,8 +95,7 @@ public class UidlRequestHandler extends SynchronizedRequestHandler implements session.getCommunicationManager().repaintAll(uI); } - writeUidl(request, response, uI, stringWriter, repaintAll, - analyzeLayouts); + writeUidl(request, response, uI, stringWriter, repaintAll); } catch (JSONException e) { getLogger().log(Level.SEVERE, "Error writing JSON to response", e); // Refresh on client side @@ -152,11 +144,11 @@ public class UidlRequestHandler extends SynchronizedRequestHandler implements } private void writeUidl(VaadinRequest request, VaadinResponse response, - UI ui, Writer writer, boolean repaintAll, boolean analyzeLayouts) - throws IOException, JSONException { + UI ui, Writer writer, boolean repaintAll) throws IOException, + JSONException { openJsonMessage(writer, response); - new UidlWriter().write(ui, writer, repaintAll, analyzeLayouts, false); + new UidlWriter().write(ui, writer, repaintAll, false); closeJsonMessage(writer); } diff --git a/server/src/com/vaadin/server/communication/UidlWriter.java b/server/src/com/vaadin/server/communication/UidlWriter.java index a915501056..60933a75c2 100644 --- a/server/src/com/vaadin/server/communication/UidlWriter.java +++ b/server/src/com/vaadin/server/communication/UidlWriter.java @@ -71,9 +71,8 @@ public class UidlWriter implements Serializable { * @throws JSONException * If the JSON serialization fails. */ - public void write(UI ui, Writer writer, boolean repaintAll, - boolean analyzeLayouts, boolean async) throws IOException, - JSONException { + public void write(UI ui, Writer writer, boolean repaintAll, boolean async) + throws IOException, JSONException { VaadinSession session = ui.getSession(); // Purge pending access calls as they might produce additional changes @@ -161,8 +160,7 @@ public class UidlWriter implements Serializable { SystemMessages messages = ui.getSession().getService() .getSystemMessages(ui.getLocale(), null); // TODO hilightedConnector - new MetadataWriter().write(ui, writer, repaintAll, analyzeLayouts, - async, messages); + new MetadataWriter().write(ui, writer, repaintAll, async, messages); writer.write(", "); writer.write("\"resources\" : "); diff --git a/server/src/com/vaadin/ui/UI.java b/server/src/com/vaadin/ui/UI.java index 3194786431..2c6283377a 100644 --- a/server/src/com/vaadin/ui/UI.java +++ b/server/src/com/vaadin/ui/UI.java @@ -21,6 +21,7 @@ import java.util.Collection; import java.util.Collections; import java.util.Iterator; import java.util.LinkedHashSet; +import java.util.List; import java.util.Map; import java.util.concurrent.Future; import java.util.logging.Logger; @@ -32,6 +33,8 @@ import com.vaadin.event.MouseEvents.ClickEvent; import com.vaadin.event.MouseEvents.ClickListener; import com.vaadin.navigator.Navigator; import com.vaadin.server.ClientConnector; +import com.vaadin.server.ComponentSizeValidator; +import com.vaadin.server.ComponentSizeValidator.InvalidLayout; import com.vaadin.server.LocaleService; import com.vaadin.server.Page; import com.vaadin.server.PaintException; @@ -46,6 +49,7 @@ import com.vaadin.shared.Connector; import com.vaadin.shared.EventId; import com.vaadin.shared.MouseEventDetails; import com.vaadin.shared.communication.PushMode; +import com.vaadin.shared.ui.ui.DebugWindowClientRpc; import com.vaadin.shared.ui.ui.DebugWindowServerRpc; import com.vaadin.shared.ui.ui.ScrollClientRpc; import com.vaadin.shared.ui.ui.UIClientRpc; @@ -173,6 +177,32 @@ public abstract class UI extends AbstractSingleComponentContainer implements .getDebugInformation((ClientConnector) connector); getLogger().info(info); } + + @Override + public void analyzeLayouts() { + // TODO Move to client side + List invalidSizes = ComponentSizeValidator + .validateLayouts(UI.this); + StringBuilder json = new StringBuilder(); + json.append("{\"invalidLayouts\":"); + json.append("["); + + if (invalidSizes != null) { + boolean first = true; + for (InvalidLayout invalidSize : invalidSizes) { + if (!first) { + json.append(","); + } else { + first = false; + } + invalidSize.reportErrors(json, System.err); + } + } + json.append("]}"); + getRpcProxy(DebugWindowClientRpc.class).reportLayoutProblems( + json.toString()); + } + }; /** diff --git a/shared/src/com/vaadin/shared/ApplicationConstants.java b/shared/src/com/vaadin/shared/ApplicationConstants.java index 6124b71d34..e51139dac7 100644 --- a/shared/src/com/vaadin/shared/ApplicationConstants.java +++ b/shared/src/com/vaadin/shared/ApplicationConstants.java @@ -39,8 +39,6 @@ public class ApplicationConstants implements Serializable { + "://"; public static final String UIDL_SECURITY_TOKEN_ID = "Vaadin-Security-Key"; - public static final String PARAM_ANALYZE_LAYOUTS = "analyzeLayouts"; - @Deprecated public static final String UPDATE_VARIABLE_INTERFACE = "v"; @Deprecated diff --git a/shared/src/com/vaadin/shared/ui/ui/DebugWindowServerRpc.java b/shared/src/com/vaadin/shared/ui/ui/DebugWindowServerRpc.java index ec8bc45b81..76e7d23379 100644 --- a/shared/src/com/vaadin/shared/ui/ui/DebugWindowServerRpc.java +++ b/shared/src/com/vaadin/shared/ui/ui/DebugWindowServerRpc.java @@ -40,4 +40,11 @@ public interface DebugWindowServerRpc extends ServerRpc { **/ public void showServerDebugInfo(Connector connector); + /** + * Invokes the layout analyzer on the server + * + * @since 7.1 + */ + public void analyzeLayouts(); + } -- cgit v1.2.3 From 6f912b18129fe7c0f7d78407dafb472e1a75f6aa Mon Sep 17 00:00:00 2001 From: Artur Signell Date: Wed, 5 Jun 2013 13:40:38 +0300 Subject: Rename tests so they are run during build (Abstract* is ignored) Change-Id: I2f5eee8926b3ba194160b85c33176029850ca8ed --- .../abstractfield/AbsFieldValidators.java | 64 +++++ .../abstractfield/AbsFieldValueConversions.java | 260 +++++++++++++++++++++ .../abstractfield/AbstractFieldValidators.java | 64 ----- .../AbstractFieldValueConversions.java | 260 --------------------- .../vaadin/ui/AbsFieldDataSourceLocaleChange.java | 63 +++++ .../ui/AbstractFieldDataSourceLocaleChange.java | 63 ----- 6 files changed, 387 insertions(+), 387 deletions(-) create mode 100644 server/tests/src/com/vaadin/tests/server/component/abstractfield/AbsFieldValidators.java create mode 100644 server/tests/src/com/vaadin/tests/server/component/abstractfield/AbsFieldValueConversions.java delete mode 100644 server/tests/src/com/vaadin/tests/server/component/abstractfield/AbstractFieldValidators.java delete mode 100644 server/tests/src/com/vaadin/tests/server/component/abstractfield/AbstractFieldValueConversions.java create mode 100644 server/tests/src/com/vaadin/ui/AbsFieldDataSourceLocaleChange.java delete mode 100644 server/tests/src/com/vaadin/ui/AbstractFieldDataSourceLocaleChange.java diff --git a/server/tests/src/com/vaadin/tests/server/component/abstractfield/AbsFieldValidators.java b/server/tests/src/com/vaadin/tests/server/component/abstractfield/AbsFieldValidators.java new file mode 100644 index 0000000000..764446f7aa --- /dev/null +++ b/server/tests/src/com/vaadin/tests/server/component/abstractfield/AbsFieldValidators.java @@ -0,0 +1,64 @@ +package com.vaadin.tests.server.component.abstractfield; + +import junit.framework.TestCase; + +import org.easymock.EasyMock; + +import com.vaadin.data.Validator; +import com.vaadin.ui.AbstractField; +import com.vaadin.ui.Field; + +public class AbsFieldValidators extends TestCase { + + Field field = new AbstractField() { + @Override + public Class getType() { + return Object.class; + } + }; + + Validator validator = EasyMock.createMock(Validator.class); + Validator validator2 = EasyMock.createMock(Validator.class); + + public void testAddValidator() { + assertNotNull(field.getValidators()); + assertEquals(0, field.getValidators().size()); + + field.addValidator(validator); + assertEquals(1, field.getValidators().size()); + assertTrue(field.getValidators().contains(validator)); + + field.addValidator(validator2); + assertEquals(2, field.getValidators().size()); + assertTrue(field.getValidators().contains(validator)); + assertTrue(field.getValidators().contains(validator2)); + } + + public void testRemoveValidator() { + field.addValidator(validator); + field.addValidator(validator2); + + field.removeValidator(validator); + assertNotNull(field.getValidators()); + assertEquals(1, field.getValidators().size()); + assertFalse(field.getValidators().contains(validator)); + assertTrue(field.getValidators().contains(validator2)); + + field.removeValidator(validator2); + assertNotNull(field.getValidators()); + assertEquals(0, field.getValidators().size()); + assertFalse(field.getValidators().contains(validator)); + assertFalse(field.getValidators().contains(validator2)); + } + + public void testRemoveAllValidators() { + field.addValidator(validator); + field.addValidator(validator2); + + field.removeAllValidators(); + assertNotNull(field.getValidators()); + assertEquals(0, field.getValidators().size()); + assertFalse(field.getValidators().contains(validator)); + assertFalse(field.getValidators().contains(validator2)); + } +} diff --git a/server/tests/src/com/vaadin/tests/server/component/abstractfield/AbsFieldValueConversions.java b/server/tests/src/com/vaadin/tests/server/component/abstractfield/AbsFieldValueConversions.java new file mode 100644 index 0000000000..b5e937f27d --- /dev/null +++ b/server/tests/src/com/vaadin/tests/server/component/abstractfield/AbsFieldValueConversions.java @@ -0,0 +1,260 @@ +package com.vaadin.tests.server.component.abstractfield; + +import java.util.Locale; + +import junit.framework.Assert; +import junit.framework.TestCase; + +import org.junit.Test; + +import com.vaadin.data.util.MethodProperty; +import com.vaadin.data.util.ObjectProperty; +import com.vaadin.data.util.converter.Converter; +import com.vaadin.data.util.converter.Converter.ConversionException; +import com.vaadin.data.util.converter.StringToIntegerConverter; +import com.vaadin.server.VaadinSession; +import com.vaadin.tests.data.bean.Address; +import com.vaadin.tests.data.bean.Country; +import com.vaadin.tests.data.bean.Person; +import com.vaadin.tests.data.bean.Sex; +import com.vaadin.tests.util.AlwaysLockedVaadinSession; +import com.vaadin.ui.CheckBox; +import com.vaadin.ui.TextField; + +public class AbsFieldValueConversions extends TestCase { + + Person paulaBean = new Person("Paula", "Brilliant", "paula@brilliant.com", + 34, Sex.FEMALE, new Address("Paula street 1", 12345, "P-town", + Country.FINLAND)); + + /** + * Java uses a non-breaking space (ascii 160) instead of space when + * formatting + */ + private static final char FORMATTED_SPACE = 160; + + public void testWithoutConversion() { + TextField tf = new TextField(); + tf.setPropertyDataSource(new MethodProperty(paulaBean, + "firstName")); + assertEquals("Paula", tf.getValue()); + assertEquals("Paula", tf.getPropertyDataSource().getValue()); + tf.setValue("abc"); + assertEquals("abc", tf.getValue()); + assertEquals("abc", tf.getPropertyDataSource().getValue()); + assertEquals("abc", paulaBean.getFirstName()); + } + + public void testNonmodifiedBufferedFieldConversion() { + VaadinSession.setCurrent(new AlwaysLockedVaadinSession(null)); + TextField tf = new TextField("salary"); + tf.setBuffered(true); + tf.setLocale(new Locale("en", "US")); + ObjectProperty ds = new ObjectProperty(123456789); + tf.setPropertyDataSource(ds); + assertEquals((Integer) 123456789, ds.getValue()); + assertEquals("123,456,789", tf.getValue()); + tf.setLocale(new Locale("fi", "FI")); + assertEquals((Integer) 123456789, ds.getValue()); + assertEquals("123" + FORMATTED_SPACE + "456" + FORMATTED_SPACE + "789", + tf.getValue()); + + } + + public void testModifiedBufferedFieldConversion() { + VaadinSession.setCurrent(new AlwaysLockedVaadinSession(null)); + TextField tf = new TextField("salary"); + tf.setBuffered(true); + tf.setLocale(new Locale("en", "US")); + ObjectProperty ds = new ObjectProperty(123456789); + tf.setPropertyDataSource(ds); + assertEquals((Integer) 123456789, ds.getValue()); + assertEquals("123,456,789", tf.getValue()); + tf.setValue("123,123"); + assertEquals((Integer) 123456789, ds.getValue()); + assertEquals("123,123", tf.getValue()); + + tf.setLocale(new Locale("fi", "FI")); + assertEquals((Integer) 123456789, ds.getValue()); + // Value should not be updated when field is buffered + assertEquals("123,123", tf.getValue()); + } + + public void testStringIdentityConversion() { + TextField tf = new TextField(); + tf.setConverter(new Converter() { + + @Override + public String convertToModel(String value, Locale locale) { + return value; + } + + @Override + public String convertToPresentation(String value, Locale locale) { + return value; + } + + @Override + public Class getModelType() { + return String.class; + } + + @Override + public Class getPresentationType() { + return String.class; + } + }); + tf.setPropertyDataSource(new MethodProperty(paulaBean, + "firstName")); + assertEquals("Paula", tf.getValue()); + assertEquals("Paula", tf.getPropertyDataSource().getValue()); + tf.setValue("abc"); + assertEquals("abc", tf.getValue()); + assertEquals("abc", tf.getPropertyDataSource().getValue()); + assertEquals("abc", paulaBean.getFirstName()); + } + + public void testIntegerStringConversion() { + TextField tf = new TextField(); + + tf.setConverter(new StringToIntegerConverter()); + tf.setPropertyDataSource(new MethodProperty(paulaBean, "age")); + assertEquals(34, tf.getPropertyDataSource().getValue()); + assertEquals("34", tf.getValue()); + tf.setValue("12"); + assertEquals(12, tf.getPropertyDataSource().getValue()); + assertEquals("12", tf.getValue()); + tf.getPropertyDataSource().setValue(42); + assertEquals(42, tf.getPropertyDataSource().getValue()); + assertEquals("42", tf.getValue()); + } + + public void testChangeReadOnlyFieldLocale() { + VaadinSession.setCurrent(new AlwaysLockedVaadinSession(null)); + + TextField tf = new TextField("salary"); + tf.setLocale(new Locale("en", "US")); + ObjectProperty ds = new ObjectProperty(123456789); + ds.setReadOnly(true); + tf.setPropertyDataSource(ds); + assertEquals((Integer) 123456789, ds.getValue()); + assertEquals("123,456,789", tf.getValue()); + tf.setLocale(new Locale("fi", "FI")); + assertEquals((Integer) 123456789, ds.getValue()); + assertEquals("123" + FORMATTED_SPACE + "456" + FORMATTED_SPACE + "789", + tf.getValue()); + } + + public void testBooleanNullConversion() { + CheckBox cb = new CheckBox(); + cb.setConverter(new Converter() { + + @Override + public Boolean convertToModel(Boolean value, Locale locale) { + // value from a CheckBox should never be null as long as it is + // not set to null (handled by conversion below). + assertNotNull(value); + return value; + } + + @Override + public Boolean convertToPresentation(Boolean value, Locale locale) { + // Datamodel -> field + if (value == null) { + return false; + } + + return value; + } + + @Override + public Class getModelType() { + return Boolean.class; + } + + @Override + public Class getPresentationType() { + return Boolean.class; + } + + }); + MethodProperty property = new MethodProperty( + paulaBean, "deceased"); + cb.setPropertyDataSource(property); + assertEquals(Boolean.FALSE, property.getValue()); + assertEquals(Boolean.FALSE, cb.getValue()); + Boolean newDmValue = cb.getConverter().convertToPresentation( + cb.getValue(), new Locale("fi", "FI")); + assertEquals(Boolean.FALSE, newDmValue); + + // FIXME: Should be able to set to false here to cause datamodel to be + // set to false but the change will not be propagated to the Property + // (field value is already false) + + cb.setValue(true); + assertEquals(Boolean.TRUE, cb.getValue()); + assertEquals(Boolean.TRUE, property.getValue()); + + cb.setValue(false); + assertEquals(Boolean.FALSE, cb.getValue()); + assertEquals(Boolean.FALSE, property.getValue()); + + } + + public static class NumberBean { + private Number number; + + public Number getNumber() { + return number; + } + + public void setNumber(Number number) { + this.number = number; + } + + } + + public void testNumberDoubleConverterChange() { + final VaadinSession a = new AlwaysLockedVaadinSession(null); + VaadinSession.setCurrent(a); + TextField tf = new TextField() { + @Override + public VaadinSession getSession() { + return a; + } + }; + NumberBean nb = new NumberBean(); + nb.setNumber(490); + + tf.setPropertyDataSource(new MethodProperty(nb, "number")); + assertEquals(490, tf.getPropertyDataSource().getValue()); + assertEquals("490", tf.getValue()); + + Converter c1 = tf.getConverter(); + + tf.setPropertyDataSource(new MethodProperty(nb, "number")); + Converter c2 = tf.getConverter(); + assertTrue( + "StringToNumber converter is ok for integer types and should stay even though property is changed", + c1 == c2); + assertEquals(490, tf.getPropertyDataSource().getValue()); + assertEquals("490", tf.getValue()); + + } + + @Test + public void testNullConverter() { + TextField tf = new TextField("foo"); + tf.setPropertyDataSource(new ObjectProperty(12)); + tf.setConverter((Converter) null); + try { + Object v = tf.getConvertedValue(); + System.out.println(v); + Assert.fail("Trying to convert String -> Integer should fail when there is no converter"); + } catch (ConversionException e) { + // ok, should happen when there is no converter but conversion is + // needed + } + } + +} diff --git a/server/tests/src/com/vaadin/tests/server/component/abstractfield/AbstractFieldValidators.java b/server/tests/src/com/vaadin/tests/server/component/abstractfield/AbstractFieldValidators.java deleted file mode 100644 index 19c58fe6d3..0000000000 --- a/server/tests/src/com/vaadin/tests/server/component/abstractfield/AbstractFieldValidators.java +++ /dev/null @@ -1,64 +0,0 @@ -package com.vaadin.tests.server.component.abstractfield; - -import junit.framework.TestCase; - -import org.easymock.EasyMock; - -import com.vaadin.data.Validator; -import com.vaadin.ui.AbstractField; -import com.vaadin.ui.Field; - -public class AbstractFieldValidators extends TestCase { - - Field field = new AbstractField() { - @Override - public Class getType() { - return Object.class; - } - }; - - Validator validator = EasyMock.createMock(Validator.class); - Validator validator2 = EasyMock.createMock(Validator.class); - - public void testAddValidator() { - assertNotNull(field.getValidators()); - assertEquals(0, field.getValidators().size()); - - field.addValidator(validator); - assertEquals(1, field.getValidators().size()); - assertTrue(field.getValidators().contains(validator)); - - field.addValidator(validator2); - assertEquals(2, field.getValidators().size()); - assertTrue(field.getValidators().contains(validator)); - assertTrue(field.getValidators().contains(validator2)); - } - - public void testRemoveValidator() { - field.addValidator(validator); - field.addValidator(validator2); - - field.removeValidator(validator); - assertNotNull(field.getValidators()); - assertEquals(1, field.getValidators().size()); - assertFalse(field.getValidators().contains(validator)); - assertTrue(field.getValidators().contains(validator2)); - - field.removeValidator(validator2); - assertNotNull(field.getValidators()); - assertEquals(0, field.getValidators().size()); - assertFalse(field.getValidators().contains(validator)); - assertFalse(field.getValidators().contains(validator2)); - } - - public void testRemoveAllValidators() { - field.addValidator(validator); - field.addValidator(validator2); - - field.removeAllValidators(); - assertNotNull(field.getValidators()); - assertEquals(0, field.getValidators().size()); - assertFalse(field.getValidators().contains(validator)); - assertFalse(field.getValidators().contains(validator2)); - } -} diff --git a/server/tests/src/com/vaadin/tests/server/component/abstractfield/AbstractFieldValueConversions.java b/server/tests/src/com/vaadin/tests/server/component/abstractfield/AbstractFieldValueConversions.java deleted file mode 100644 index 3c4d43543b..0000000000 --- a/server/tests/src/com/vaadin/tests/server/component/abstractfield/AbstractFieldValueConversions.java +++ /dev/null @@ -1,260 +0,0 @@ -package com.vaadin.tests.server.component.abstractfield; - -import java.util.Locale; - -import junit.framework.Assert; -import junit.framework.TestCase; - -import org.junit.Test; - -import com.vaadin.data.util.MethodProperty; -import com.vaadin.data.util.ObjectProperty; -import com.vaadin.data.util.converter.Converter; -import com.vaadin.data.util.converter.Converter.ConversionException; -import com.vaadin.data.util.converter.StringToIntegerConverter; -import com.vaadin.server.VaadinSession; -import com.vaadin.tests.data.bean.Address; -import com.vaadin.tests.data.bean.Country; -import com.vaadin.tests.data.bean.Person; -import com.vaadin.tests.data.bean.Sex; -import com.vaadin.tests.util.AlwaysLockedVaadinSession; -import com.vaadin.ui.CheckBox; -import com.vaadin.ui.TextField; - -public class AbstractFieldValueConversions extends TestCase { - - Person paulaBean = new Person("Paula", "Brilliant", "paula@brilliant.com", - 34, Sex.FEMALE, new Address("Paula street 1", 12345, "P-town", - Country.FINLAND)); - - /** - * Java uses a non-breaking space (ascii 160) instead of space when - * formatting - */ - private static final char FORMATTED_SPACE = 160; - - public void testWithoutConversion() { - TextField tf = new TextField(); - tf.setPropertyDataSource(new MethodProperty(paulaBean, - "firstName")); - assertEquals("Paula", tf.getValue()); - assertEquals("Paula", tf.getPropertyDataSource().getValue()); - tf.setValue("abc"); - assertEquals("abc", tf.getValue()); - assertEquals("abc", tf.getPropertyDataSource().getValue()); - assertEquals("abc", paulaBean.getFirstName()); - } - - public void testNonmodifiedBufferedFieldConversion() { - VaadinSession.setCurrent(new AlwaysLockedVaadinSession(null)); - TextField tf = new TextField("salary"); - tf.setBuffered(true); - tf.setLocale(new Locale("en", "US")); - ObjectProperty ds = new ObjectProperty(123456789); - tf.setPropertyDataSource(ds); - assertEquals((Integer) 123456789, ds.getValue()); - assertEquals("123,456,789", tf.getValue()); - tf.setLocale(new Locale("fi", "FI")); - assertEquals((Integer) 123456789, ds.getValue()); - assertEquals("123" + FORMATTED_SPACE + "456" + FORMATTED_SPACE + "789", - tf.getValue()); - - } - - public void testModifiedBufferedFieldConversion() { - VaadinSession.setCurrent(new AlwaysLockedVaadinSession(null)); - TextField tf = new TextField("salary"); - tf.setBuffered(true); - tf.setLocale(new Locale("en", "US")); - ObjectProperty ds = new ObjectProperty(123456789); - tf.setPropertyDataSource(ds); - assertEquals((Integer) 123456789, ds.getValue()); - assertEquals("123,456,789", tf.getValue()); - tf.setValue("123,123"); - assertEquals((Integer) 123456789, ds.getValue()); - assertEquals("123,123", tf.getValue()); - - tf.setLocale(new Locale("fi", "FI")); - assertEquals((Integer) 123456789, ds.getValue()); - // Value should not be updated when field is buffered - assertEquals("123,123", tf.getValue()); - } - - public void testStringIdentityConversion() { - TextField tf = new TextField(); - tf.setConverter(new Converter() { - - @Override - public String convertToModel(String value, Locale locale) { - return value; - } - - @Override - public String convertToPresentation(String value, Locale locale) { - return value; - } - - @Override - public Class getModelType() { - return String.class; - } - - @Override - public Class getPresentationType() { - return String.class; - } - }); - tf.setPropertyDataSource(new MethodProperty(paulaBean, - "firstName")); - assertEquals("Paula", tf.getValue()); - assertEquals("Paula", tf.getPropertyDataSource().getValue()); - tf.setValue("abc"); - assertEquals("abc", tf.getValue()); - assertEquals("abc", tf.getPropertyDataSource().getValue()); - assertEquals("abc", paulaBean.getFirstName()); - } - - public void testIntegerStringConversion() { - TextField tf = new TextField(); - - tf.setConverter(new StringToIntegerConverter()); - tf.setPropertyDataSource(new MethodProperty(paulaBean, "age")); - assertEquals(34, tf.getPropertyDataSource().getValue()); - assertEquals("34", tf.getValue()); - tf.setValue("12"); - assertEquals(12, tf.getPropertyDataSource().getValue()); - assertEquals("12", tf.getValue()); - tf.getPropertyDataSource().setValue(42); - assertEquals(42, tf.getPropertyDataSource().getValue()); - assertEquals("42", tf.getValue()); - } - - public void testChangeReadOnlyFieldLocale() { - VaadinSession.setCurrent(new AlwaysLockedVaadinSession(null)); - - TextField tf = new TextField("salary"); - tf.setLocale(new Locale("en", "US")); - ObjectProperty ds = new ObjectProperty(123456789); - ds.setReadOnly(true); - tf.setPropertyDataSource(ds); - assertEquals((Integer) 123456789, ds.getValue()); - assertEquals("123,456,789", tf.getValue()); - tf.setLocale(new Locale("fi", "FI")); - assertEquals((Integer) 123456789, ds.getValue()); - assertEquals("123" + FORMATTED_SPACE + "456" + FORMATTED_SPACE + "789", - tf.getValue()); - } - - public void testBooleanNullConversion() { - CheckBox cb = new CheckBox(); - cb.setConverter(new Converter() { - - @Override - public Boolean convertToModel(Boolean value, Locale locale) { - // value from a CheckBox should never be null as long as it is - // not set to null (handled by conversion below). - assertNotNull(value); - return value; - } - - @Override - public Boolean convertToPresentation(Boolean value, Locale locale) { - // Datamodel -> field - if (value == null) { - return false; - } - - return value; - } - - @Override - public Class getModelType() { - return Boolean.class; - } - - @Override - public Class getPresentationType() { - return Boolean.class; - } - - }); - MethodProperty property = new MethodProperty( - paulaBean, "deceased"); - cb.setPropertyDataSource(property); - assertEquals(Boolean.FALSE, property.getValue()); - assertEquals(Boolean.FALSE, cb.getValue()); - Boolean newDmValue = cb.getConverter().convertToPresentation( - cb.getValue(), new Locale("fi", "FI")); - assertEquals(Boolean.FALSE, newDmValue); - - // FIXME: Should be able to set to false here to cause datamodel to be - // set to false but the change will not be propagated to the Property - // (field value is already false) - - cb.setValue(true); - assertEquals(Boolean.TRUE, cb.getValue()); - assertEquals(Boolean.TRUE, property.getValue()); - - cb.setValue(false); - assertEquals(Boolean.FALSE, cb.getValue()); - assertEquals(Boolean.FALSE, property.getValue()); - - } - - public static class NumberBean { - private Number number; - - public Number getNumber() { - return number; - } - - public void setNumber(Number number) { - this.number = number; - } - - } - - public void testNumberDoubleConverterChange() { - final VaadinSession a = new AlwaysLockedVaadinSession(null); - VaadinSession.setCurrent(a); - TextField tf = new TextField() { - @Override - public VaadinSession getSession() { - return a; - } - }; - NumberBean nb = new NumberBean(); - nb.setNumber(490); - - tf.setPropertyDataSource(new MethodProperty(nb, "number")); - assertEquals(490, tf.getPropertyDataSource().getValue()); - assertEquals("490", tf.getValue()); - - Converter c1 = tf.getConverter(); - - tf.setPropertyDataSource(new MethodProperty(nb, "number")); - Converter c2 = tf.getConverter(); - assertTrue( - "StringToNumber converter is ok for integer types and should stay even though property is changed", - c1 == c2); - assertEquals(490, tf.getPropertyDataSource().getValue()); - assertEquals("490", tf.getValue()); - - } - - @Test - public void testNullConverter() { - TextField tf = new TextField("foo"); - tf.setPropertyDataSource(new ObjectProperty(12)); - tf.setConverter((Converter) null); - try { - Object v = tf.getConvertedValue(); - System.out.println(v); - Assert.fail("Trying to convert String -> Integer should fail when there is no converter"); - } catch (ConversionException e) { - // ok, should happen when there is no converter but conversion is - // needed - } - } - -} diff --git a/server/tests/src/com/vaadin/ui/AbsFieldDataSourceLocaleChange.java b/server/tests/src/com/vaadin/ui/AbsFieldDataSourceLocaleChange.java new file mode 100644 index 0000000000..acea0a84c7 --- /dev/null +++ b/server/tests/src/com/vaadin/ui/AbsFieldDataSourceLocaleChange.java @@ -0,0 +1,63 @@ +package com.vaadin.ui; + +import java.text.NumberFormat; +import java.util.Locale; + +import junit.framework.Assert; + +import org.junit.Before; +import org.junit.Test; + +import com.vaadin.data.util.converter.StringToIntegerConverter; +import com.vaadin.server.VaadinRequest; +import com.vaadin.server.VaadinSession; + +public class AbsFieldDataSourceLocaleChange { + + private VaadinSession vaadinSession; + private UI ui; + + @Before + public void setup() { + vaadinSession = new VaadinSession(null); + VaadinSession.setCurrent(vaadinSession); + ui = new UI() { + + @Override + protected void init(VaadinRequest request) { + + } + }; + ui.setSession(vaadinSession); + UI.setCurrent(ui); + } + + @Test + public void localeChangesOnAttach() { + TextField tf = new TextField(); + + ; + tf.setConverter(new StringToIntegerConverter() { + @Override + protected NumberFormat getFormat(Locale locale) { + if (locale == null) { + NumberFormat format = super.getFormat(locale); + format.setGroupingUsed(false); + format.setMinimumIntegerDigits(10); + return format; + } + return super.getFormat(locale); + } + }); + tf.setImmediate(true); + tf.setConvertedValue(10000); + Assert.assertEquals("0000010000", tf.getValue()); + + VerticalLayout vl = new VerticalLayout(); + ui.setContent(vl); + ui.setLocale(new Locale("en", "US")); + + vl.addComponent(tf); + Assert.assertEquals("10,000", tf.getValue()); + } +} diff --git a/server/tests/src/com/vaadin/ui/AbstractFieldDataSourceLocaleChange.java b/server/tests/src/com/vaadin/ui/AbstractFieldDataSourceLocaleChange.java deleted file mode 100644 index 9810873f0b..0000000000 --- a/server/tests/src/com/vaadin/ui/AbstractFieldDataSourceLocaleChange.java +++ /dev/null @@ -1,63 +0,0 @@ -package com.vaadin.ui; - -import java.text.NumberFormat; -import java.util.Locale; - -import junit.framework.Assert; - -import org.junit.Before; -import org.junit.Test; - -import com.vaadin.data.util.converter.StringToIntegerConverter; -import com.vaadin.server.VaadinRequest; -import com.vaadin.server.VaadinSession; - -public class AbstractFieldDataSourceLocaleChange { - - private VaadinSession vaadinSession; - private UI ui; - - @Before - public void setup() { - vaadinSession = new VaadinSession(null); - VaadinSession.setCurrent(vaadinSession); - ui = new UI() { - - @Override - protected void init(VaadinRequest request) { - - } - }; - ui.setSession(vaadinSession); - UI.setCurrent(ui); - } - - @Test - public void localeChangesOnAttach() { - TextField tf = new TextField(); - - ; - tf.setConverter(new StringToIntegerConverter() { - @Override - protected NumberFormat getFormat(Locale locale) { - if (locale == null) { - NumberFormat format = super.getFormat(locale); - format.setGroupingUsed(false); - format.setMinimumIntegerDigits(10); - return format; - } - return super.getFormat(locale); - } - }); - tf.setImmediate(true); - tf.setConvertedValue(10000); - Assert.assertEquals("0000010000", tf.getValue()); - - VerticalLayout vl = new VerticalLayout(); - ui.setContent(vl); - ui.setLocale(new Locale("en", "US")); - - vl.addComponent(tf); - Assert.assertEquals("10,000", tf.getValue()); - } -} -- cgit v1.2.3 From ebd4a5c0ae6e61c20283ba5b866fe51e3576a179 Mon Sep 17 00:00:00 2001 From: Artur Signell Date: Wed, 5 Jun 2013 15:03:11 +0300 Subject: Added missing rpc interface (#11536) Change-Id: Ia53f76068d132f4f8eafa79e79922e6eb5762045 --- .../vaadin/shared/ui/ui/DebugWindowClientRpc.java | 39 ++++++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 shared/src/com/vaadin/shared/ui/ui/DebugWindowClientRpc.java diff --git a/shared/src/com/vaadin/shared/ui/ui/DebugWindowClientRpc.java b/shared/src/com/vaadin/shared/ui/ui/DebugWindowClientRpc.java new file mode 100644 index 0000000000..7e76a6a459 --- /dev/null +++ b/shared/src/com/vaadin/shared/ui/ui/DebugWindowClientRpc.java @@ -0,0 +1,39 @@ +/* + * Copyright 2000-2013 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.shared.ui.ui; + +import com.vaadin.shared.communication.ClientRpc; + +/** + * Client RPC methods for the Debug Window. + * + * @since 7.1 + * @author Vaadin Ltd + */ +public interface DebugWindowClientRpc extends ClientRpc { + + /** + * Send results from {@link DebugWindowServerRpc#analyzeLayouts()} back to + * the client. + * + * @since 7.1 + * @param json + * JSON containing list of found problems + */ + public void reportLayoutProblems(String json); + +} -- cgit v1.2.3 From edca4095d2e75d73f9d6a5acb2da9009129b4db2 Mon Sep 17 00:00:00 2001 From: Artur Signell Date: Wed, 5 Jun 2013 14:27:09 +0300 Subject: Allow customizing client-side push config on server side (#11867) Change-Id: I212067aa0bd04e3e73844ef57963b5622291986a --- .../com/vaadin/client/ApplicationConnection.java | 7 +- .../communication/AtmospherePushConnection.java | 15 +- .../client/communication/PushConnection.java | 2 + .../src/com/vaadin/client/ui/ui/UIConnector.java | 5 +- server/src/com/vaadin/server/VaadinSession.java | 2 +- .../vaadin/server/communication/PushHandler.java | 2 +- .../vaadin/server/communication/UIInitHandler.java | 2 +- server/src/com/vaadin/ui/PushConfiguration.java | 282 +++++++++++++++++++++ server/src/com/vaadin/ui/UI.java | 55 +--- shared/src/com/vaadin/shared/ui/ui/Transport.java | 55 ++++ shared/src/com/vaadin/shared/ui/ui/UIState.java | 22 +- .../com/vaadin/tests/push/PushConfiguration.html | 130 ++++++++++ .../vaadin/tests/push/PushConfigurationTest.java | 102 ++++++++ .../com/vaadin/tests/push/PushConfigurator.java | 152 +++++++++++ uitest/src/com/vaadin/tests/push/TogglePush.java | 13 +- .../widgetset/client/TestingPushConnection.java | 4 +- 16 files changed, 784 insertions(+), 66 deletions(-) create mode 100644 server/src/com/vaadin/ui/PushConfiguration.java create mode 100644 shared/src/com/vaadin/shared/ui/ui/Transport.java create mode 100644 uitest/src/com/vaadin/tests/push/PushConfiguration.html create mode 100644 uitest/src/com/vaadin/tests/push/PushConfigurationTest.java create mode 100644 uitest/src/com/vaadin/tests/push/PushConfigurator.java diff --git a/client/src/com/vaadin/client/ApplicationConnection.java b/client/src/com/vaadin/client/ApplicationConnection.java index a3279e5631..ac058b5536 100644 --- a/client/src/com/vaadin/client/ApplicationConnection.java +++ b/client/src/com/vaadin/client/ApplicationConnection.java @@ -95,6 +95,7 @@ import com.vaadin.shared.communication.LegacyChangeVariablesInvocation; import com.vaadin.shared.communication.MethodInvocation; import com.vaadin.shared.communication.SharedState; import com.vaadin.shared.ui.ui.UIConstants; +import com.vaadin.shared.ui.ui.UIState.PushConfigurationState; /** * This is the client side communication "engine", managing client-server @@ -3359,9 +3360,11 @@ public class ApplicationConnection { * false to disable the push connection. */ public void setPushEnabled(boolean enabled) { + final PushConfigurationState pushState = uIConnector.getState().pushConfiguration; + if (enabled && push == null) { push = GWT.create(PushConnection.class); - push.init(this, new CommunicationErrorHandler() { + push.init(this, pushState, new CommunicationErrorHandler() { @Override public boolean onError(String details, int statusCode) { showCommunicationError(details, statusCode); @@ -3378,7 +3381,7 @@ public class ApplicationConnection { * the old connection to disconnect, now is the right time * to open a new connection */ - if (uIConnector.getState().pushMode.isEnabled()) { + if (pushState.mode.isEnabled()) { setPushEnabled(true); } diff --git a/client/src/com/vaadin/client/communication/AtmospherePushConnection.java b/client/src/com/vaadin/client/communication/AtmospherePushConnection.java index 997e84145c..f7936f8717 100644 --- a/client/src/com/vaadin/client/communication/AtmospherePushConnection.java +++ b/client/src/com/vaadin/client/communication/AtmospherePushConnection.java @@ -30,6 +30,7 @@ import com.vaadin.client.VConsole; import com.vaadin.shared.ApplicationConstants; import com.vaadin.shared.communication.PushConstants; import com.vaadin.shared.ui.ui.UIConstants; +import com.vaadin.shared.ui.ui.UIState.PushConfigurationState; /** * The default {@link PushConnection} implementation that uses Atmosphere for @@ -133,15 +134,22 @@ public class AtmospherePushConnection implements PushConnection { * (non-Javadoc) * * @see - * com.vaadin.client.communication.PushConenction#init(com.vaadin.client - * .ApplicationConnection) + * com.vaadin.client.communication.PushConnection#init(ApplicationConnection + * , Map, CommunicationErrorHandler) */ @Override public void init(final ApplicationConnection connection, + final PushConfigurationState pushConfiguration, CommunicationErrorHandler errorHandler) { this.connection = connection; this.errorHandler = errorHandler; + config = createConfig(); + for (String param : pushConfiguration.parameters.keySet()) { + config.setStringValue(param, + pushConfiguration.parameters.get(param)); + } + runWhenAtmosphereLoaded(new Command() { @Override public void execute() { @@ -216,9 +224,6 @@ public class AtmospherePushConnection implements PushConnection { } protected AtmosphereConfiguration getConfig() { - if (config == null) { - config = createConfig(); - } return config; } diff --git a/client/src/com/vaadin/client/communication/PushConnection.java b/client/src/com/vaadin/client/communication/PushConnection.java index a4a3bbc0cc..bc2af98f1a 100644 --- a/client/src/com/vaadin/client/communication/PushConnection.java +++ b/client/src/com/vaadin/client/communication/PushConnection.java @@ -19,6 +19,7 @@ package com.vaadin.client.communication; import com.google.gwt.user.client.Command; import com.vaadin.client.ApplicationConnection; import com.vaadin.client.ApplicationConnection.CommunicationErrorHandler; +import com.vaadin.shared.ui.ui.UIState.PushConfigurationState; /** * Represents the client-side endpoint of a bidirectional ("push") communication @@ -39,6 +40,7 @@ public interface PushConnection { * The ApplicationConnection */ public void init(ApplicationConnection connection, + PushConfigurationState pushConfigurationState, CommunicationErrorHandler errorHandler); /** diff --git a/client/src/com/vaadin/client/ui/ui/UIConnector.java b/client/src/com/vaadin/client/ui/ui/UIConnector.java index 1c2c6ddeb8..45b0a7ab9d 100644 --- a/client/src/com/vaadin/client/ui/ui/UIConnector.java +++ b/client/src/com/vaadin/client/ui/ui/UIConnector.java @@ -644,8 +644,9 @@ public class UIConnector extends AbstractSingleComponentContainerConnector configurePolling(); } - if (stateChangeEvent.hasPropertyChanged("pushMode")) { - getConnection().setPushEnabled(getState().pushMode.isEnabled()); + if (stateChangeEvent.hasPropertyChanged("pushConfiguration")) { + getConnection().setPushEnabled( + getState().pushConfiguration.mode.isEnabled()); } if (stateChangeEvent.hasPropertyChanged("overlayContainerLabel")) { diff --git a/server/src/com/vaadin/server/VaadinSession.java b/server/src/com/vaadin/server/VaadinSession.java index 889eadcd6f..e0a5b51baa 100644 --- a/server/src/com/vaadin/server/VaadinSession.java +++ b/server/src/com/vaadin/server/VaadinSession.java @@ -902,7 +902,7 @@ public class VaadinSession implements HttpSessionBindingListener, Serializable { getService().runPendingAccessTasks(this); for (UI ui : getUIs()) { - if (ui.getPushMode() == PushMode.AUTOMATIC) { + if (ui.getPushConfiguration().getPushMode() == PushMode.AUTOMATIC) { ui.push(); } } diff --git a/server/src/com/vaadin/server/communication/PushHandler.java b/server/src/com/vaadin/server/communication/PushHandler.java index a44df79221..7efcb8fd8c 100644 --- a/server/src/com/vaadin/server/communication/PushHandler.java +++ b/server/src/com/vaadin/server/communication/PushHandler.java @@ -171,7 +171,7 @@ public class PushHandler implements AtmosphereHandler { PushEventCallback disconnectCallback = new PushEventCallback() { @Override public void run(AtmosphereResource resource, UI ui) throws IOException { - PushMode pushMode = ui.getPushMode(); + PushMode pushMode = ui.getPushConfiguration().getPushMode(); AtmospherePushConnection pushConnection = getConnectionForUI(ui); String id = resource.uuid(); diff --git a/server/src/com/vaadin/server/communication/UIInitHandler.java b/server/src/com/vaadin/server/communication/UIInitHandler.java index 8507bf40cc..9807ea6a9f 100644 --- a/server/src/com/vaadin/server/communication/UIInitHandler.java +++ b/server/src/com/vaadin/server/communication/UIInitHandler.java @@ -209,7 +209,7 @@ public abstract class UIInitHandler extends SynchronizedRequestHandler { pushMode = session.getService().getDeploymentConfiguration() .getPushMode(); } - ui.setPushMode(pushMode); + ui.getPushConfiguration().setPushMode(pushMode); // Set thread local here so it is available in init UI.setCurrent(ui); diff --git a/server/src/com/vaadin/ui/PushConfiguration.java b/server/src/com/vaadin/ui/PushConfiguration.java new file mode 100644 index 0000000000..a592b39bef --- /dev/null +++ b/server/src/com/vaadin/ui/PushConfiguration.java @@ -0,0 +1,282 @@ +/* + * Copyright 2000-2013 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.ui; + +import java.io.Serializable; +import java.util.Collection; +import java.util.Collections; + +import com.vaadin.server.VaadinSession; +import com.vaadin.shared.communication.PushMode; +import com.vaadin.shared.ui.ui.Transport; +import com.vaadin.shared.ui.ui.UIState.PushConfigurationState; + +/** + * Provides method for configuring the push channel. + * + * @since 7.1 + * @author Vaadin Ltd + */ +public interface PushConfiguration extends Serializable { + + /** + * Returns the mode of bidirectional ("push") communication that is used. + * + * @return The push mode. + */ + public PushMode getPushMode(); + + /** + * Sets the mode of bidirectional ("push") communication that should be + * used. + *

    + * Add-on developers should note that this method is only meant for the + * application developer. An add-on should not set the push mode directly, + * rather instruct the user to set it. + *

    + * + * @param pushMode + * The push mode to use. + * + * @throws IllegalArgumentException + * if the argument is null. + * @throws IllegalStateException + * if push support is not available. + */ + public void setPushMode(PushMode pushMode); + + /** + * Returns the primary transport type for push. + *

    + * Note that if you set the transport type using + * {@link #setParameter(String, String)} to an unsupported type this method + * will return null. Supported types are defined by {@link Transport}. + * + * @return The primary transport type + */ + public Transport getTransport(); + + /** + * Sets the primary transport type for push. + *

    + * Note that the new transport type will not be used until the push channel + * is disconnected and reconnected if already active. + * + * @param transport + * The primary transport type + */ + public void setTransport(Transport transport); + + /** + * Returns the fallback transport type for push. + *

    + * Note that if you set the transport type using + * {@link #setParameter(String, String)} to an unsupported type this method + * will return null. Supported types are defined by {@link Transport}. + * + * @return The fallback transport type + */ + public Transport getFallbackTransport(); + + /** + * Sets the fallback transport type for push. + *

    + * Note that the new transport type will not be used until the push channel + * is disconnected and reconnected if already active. + * + * @param fallbackTransport + * The fallback transport type + */ + public void setFallbackTransport(Transport fallbackTransport); + + /** + * Returns the given parameter, if set. + *

    + * This method provides low level access to push parameters and is typically + * not needed for normal application development. + * + * @since 7.1 + * @param parameter + * The parameter name + * @return The parameter value or null if not set + */ + public String getParameter(String parameter); + + /** + * Returns the parameters which have been defined. + * + * @since 7.1 + * @return A collection of parameter names + */ + public Collection getParameterNames(); + + /** + * Sets the given parameter. + *

    + * This method provides low level access to push parameters and is typically + * not needed for normal application development. + * + * @since 7.1 + * @param parameter + * The parameter name + * @param value + * The value + */ + public void setParameter(String parameter, String value); + +} + +class PushConfigurationImpl implements PushConfiguration { + private UI ui; + + public PushConfigurationImpl(UI ui) { + this.ui = ui; + } + + /* + * (non-Javadoc) + * + * @see com.vaadin.ui.PushConfiguration#getPushMode() + */ + @Override + public PushMode getPushMode() { + return getState(false).mode; + } + + /* + * (non-Javadoc) + * + * @see + * com.vaadin.ui.PushConfiguration#setPushMode(com.vaadin.shared.communication + * .PushMode) + */ + @Override + public void setPushMode(PushMode pushMode) { + if (pushMode == null) { + throw new IllegalArgumentException("Push mode cannot be null"); + } + + if (pushMode.isEnabled()) { + VaadinSession session = ui.getSession(); + if (session != null && !session.getService().ensurePushAvailable()) { + throw new IllegalStateException( + "Push is not available. See previous log messages for more information."); + } + } + + /* + * Client-side will open a new connection or disconnect the old + * connection, so there's nothing more to do on the server at this + * point. + */ + getState().mode = pushMode; + } + + /* + * (non-Javadoc) + * + * @see com.vaadin.ui.PushConfiguration#getTransport() + */ + @Override + public Transport getTransport() { + try { + return Transport + .valueOf(getParameter(PushConfigurationState.TRANSPORT_PARAM)); + } catch (IllegalArgumentException e) { + return null; + } + } + + /* + * (non-Javadoc) + * + * @see + * com.vaadin.ui.PushConfiguration#setTransport(com.vaadin.shared.ui.ui. + * Transport) + */ + @Override + public void setTransport(Transport transport) { + setParameter(PushConfigurationState.TRANSPORT_PARAM, + transport.getIdentifier()); + } + + /* + * (non-Javadoc) + * + * @see com.vaadin.ui.PushConfiguration#getFallbackTransport() + */ + @Override + public Transport getFallbackTransport() { + try { + return Transport + .valueOf(getParameter(PushConfigurationState.FALLBACK_TRANSPORT_PARAM)); + } catch (IllegalArgumentException e) { + return null; + } + } + + /* + * (non-Javadoc) + * + * @see + * com.vaadin.ui.PushConfiguration#setFallbackTransport(com.vaadin.shared + * .ui.ui.Transport) + */ + @Override + public void setFallbackTransport(Transport fallbackTransport) { + setParameter(PushConfigurationState.FALLBACK_TRANSPORT_PARAM, + fallbackTransport.getIdentifier()); + } + + /* + * (non-Javadoc) + * + * @see com.vaadin.ui.PushConfiguration#getParameter(java.lang.String) + */ + @Override + public String getParameter(String parameter) { + return getState(false).parameters.get(parameter); + } + + /* + * (non-Javadoc) + * + * @see com.vaadin.ui.PushConfiguration#setParameter(java.lang.String, + * java.lang.String) + */ + @Override + public void setParameter(String parameter, String value) { + getState().parameters.put(parameter, value); + + } + + private PushConfigurationState getState() { + return ui.getState().pushConfiguration; + } + + private PushConfigurationState getState(boolean markAsDirty) { + return ui.getState(markAsDirty).pushConfiguration; + } + + @Override + public Collection getParameterNames() { + return Collections + .unmodifiableCollection(ui.getState(false).pushConfiguration.parameters + .keySet()); + } + +} diff --git a/server/src/com/vaadin/ui/UI.java b/server/src/com/vaadin/ui/UI.java index 2c6283377a..6159298a69 100644 --- a/server/src/com/vaadin/ui/UI.java +++ b/server/src/com/vaadin/ui/UI.java @@ -48,7 +48,6 @@ import com.vaadin.server.communication.PushConnection; import com.vaadin.shared.Connector; import com.vaadin.shared.EventId; import com.vaadin.shared.MouseEventDetails; -import com.vaadin.shared.communication.PushMode; import com.vaadin.shared.ui.ui.DebugWindowClientRpc; import com.vaadin.shared.ui.ui.DebugWindowServerRpc; import com.vaadin.shared.ui.ui.ScrollClientRpc; @@ -216,6 +215,8 @@ public abstract class UI extends AbstractSingleComponentContainer implements private TooltipConfiguration tooltipConfiguration = new TooltipConfigurationImpl( this); + private PushConfiguration pushConfiguration = new PushConfigurationImpl( + this); /** * Creates a new empty UI without a caption. The content of the UI must be @@ -1325,7 +1326,7 @@ public abstract class UI extends AbstractSingleComponentContainer implements return; } - if (!getPushMode().isEnabled()) { + if (!getPushConfiguration().getPushMode().isEnabled()) { throw new IllegalStateException("Push not enabled"); } @@ -1353,7 +1354,7 @@ public abstract class UI extends AbstractSingleComponentContainer implements */ public void setPushConnection(PushConnection pushConnection) { // If pushMode is disabled then there should never be a pushConnection - assert (getPushMode().isEnabled() || pushConnection == null); + assert (getPushConfiguration().getPushMode().isEnabled() || pushConnection == null); if (pushConnection == this.pushConnection) { return; @@ -1402,51 +1403,13 @@ public abstract class UI extends AbstractSingleComponentContainer implements } /** - * Returns the mode of bidirectional ("push") communication that is used in - * this UI. - * - * @return The push mode. - */ - public PushMode getPushMode() { - return getState(false).pushMode; - } - - /** - * Sets the mode of bidirectional ("push") communication that should be used - * in this UI. - *

    - * Add-on developers should note that this method is only meant for the - * application developer. An add-on should not set the push mode directly, - * rather instruct the user to set it. - *

    + * Retrieves the object used for configuring the push channel. * - * @param pushMode - * The push mode to use. - * - * @throws IllegalArgumentException - * if the argument is null. - * @throws IllegalStateException - * if push support is not available. + * @since 7.1 + * @return The instance used for push configuration */ - public void setPushMode(PushMode pushMode) { - if (pushMode == null) { - throw new IllegalArgumentException("Push mode cannot be null"); - } - - if (pushMode.isEnabled()) { - VaadinSession session = getSession(); - if (session != null && !session.getService().ensurePushAvailable()) { - throw new IllegalStateException( - "Push is not available. See previous log messages for more information."); - } - } - - /* - * Client-side will open a new connection or disconnect the old - * connection, so there's nothing more to do on the server at this - * point. - */ - getState().pushMode = pushMode; + public PushConfiguration getPushConfiguration() { + return pushConfiguration; } /** diff --git a/shared/src/com/vaadin/shared/ui/ui/Transport.java b/shared/src/com/vaadin/shared/ui/ui/Transport.java new file mode 100644 index 0000000000..69d713bcca --- /dev/null +++ b/shared/src/com/vaadin/shared/ui/ui/Transport.java @@ -0,0 +1,55 @@ +/* + * Copyright 2000-2013 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.shared.ui.ui; + +/** + * Transport modes for Push + * + * @since 7.1 + * @author Vaadin Ltd + */ +public enum Transport { + /** + * Websockets + */ + WEBSOCKET("websocket"), + /** + * HTTP streaming + */ + STREAMING("streaming"); + + /** + * The default transport mechanism for push + */ + public static final Transport DEFAULT = Transport.WEBSOCKET; + + /** + * The default fallback transport mechanism for push + */ + public static final Transport DEFAULT_FALLBACK = Transport.STREAMING; + + private String identifier; + + private Transport(String identifier) { + this.identifier = identifier; + } + + public String getIdentifier() { + return identifier; + } + +} diff --git a/shared/src/com/vaadin/shared/ui/ui/UIState.java b/shared/src/com/vaadin/shared/ui/ui/UIState.java index 177fe2e7bd..e19a87ada9 100644 --- a/shared/src/com/vaadin/shared/ui/ui/UIState.java +++ b/shared/src/com/vaadin/shared/ui/ui/UIState.java @@ -17,7 +17,9 @@ package com.vaadin.shared.ui.ui; import java.io.Serializable; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; import com.vaadin.shared.communication.PushMode; import com.vaadin.shared.ui.TabIndexState; @@ -27,8 +29,6 @@ public class UIState extends TabIndexState { public LoadingIndicatorConfigurationState loadingIndicatorConfiguration = new LoadingIndicatorConfigurationState(); public int pollInterval = -1; - public PushMode pushMode = PushMode.DISABLED; - // Informing users of assistive devices, that the content of this container // is announced automatically and does not need to be navigated into public String overlayContainerLabel = "This content is announced automatically and does not need to be navigated into."; @@ -48,6 +48,19 @@ public class UIState extends TabIndexState { public int maxWidth = 500; } + public static class PushConfigurationState implements Serializable { + public static final String TRANSPORT_PARAM = "transport"; + public static final String FALLBACK_TRANSPORT_PARAM = "fallbackTransport"; + + public PushMode mode = PushMode.DISABLED; + public Map parameters = new HashMap(); + { + parameters.put(TRANSPORT_PARAM, Transport.DEFAULT.getIdentifier()); + parameters.put(FALLBACK_TRANSPORT_PARAM, + Transport.DEFAULT_FALLBACK.getIdentifier()); + } + } + /** * State related to the Page class. */ @@ -57,6 +70,11 @@ public class UIState extends TabIndexState { */ public LocaleServiceState localeServiceState = new LocaleServiceState(); + /** + * Configuration for the push channel + */ + public PushConfigurationState pushConfiguration = new PushConfigurationState(); + { primaryStyleName = "v-ui"; // Default is 1 for legacy reasons diff --git a/uitest/src/com/vaadin/tests/push/PushConfiguration.html b/uitest/src/com/vaadin/tests/push/PushConfiguration.html new file mode 100644 index 0000000000..c3786b1cc1 --- /dev/null +++ b/uitest/src/com/vaadin/tests/push/PushConfiguration.html @@ -0,0 +1,130 @@ + + + + + + +New Test + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    New Test
    open/run/com.vaadin.tests.push.PushConfigurationTest?debug&restartApplication
    assertNotTextvaadin=runcomvaadintestspushPushConfigurationTest::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[5]/VLabel[0]4
    selectvaadin=runcomvaadintestspushPushConfigurationTest::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VVerticalLayout[0]/Slot[0]/VVerticalLayout[0]/Slot[1]/VNativeSelect[0]/domChild[0]label=WEBSOCKET
    assertNotTextvaadin=runcomvaadintestspushPushConfigurationTest::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[5]/VLabel[0]4
    selectvaadin=runcomvaadintestspushPushConfigurationTest::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VVerticalLayout[0]/Slot[0]/VVerticalLayout[0]/Slot[0]/VNativeSelect[0]/domChild[0]label=AUTOMATIC
    assertTextvaadin=runcomvaadintestspushPushConfigurationTest::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VVerticalLayout[0]/Slot[0]/VVerticalLayout[0]/Slot[5]/VLabel[0]/domChild[0]*fallbackTransport: streaming*transport: websocket*
    assertNotTextvaadin=runcomvaadintestspushPushConfigurationTest::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[5]/VLabel[0]4
    waitForTextvaadin=runcomvaadintestspushPushConfigurationTest::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[5]/VLabel[0]4
    assertTextPresentPush connection established using websocket
    assertTextNotPresentPush connection established using streamingPush connection established using streaming
    selectvaadin=runcomvaadintestspushPushConfigurationTest::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VVerticalLayout[0]/Slot[0]/VVerticalLayout[0]/Slot[0]/VNativeSelect[0]/domChild[0]label=DISABLED
    open/run/com.vaadin.tests.push.PushConfigurationTest?debug&restartApplication
    assertNotTextvaadin=runcomvaadintestspushPushConfigurationTest::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[5]/VLabel[0]4
    selectvaadin=runcomvaadintestspushPushConfigurationTest::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VVerticalLayout[0]/Slot[0]/VVerticalLayout[0]/Slot[1]/VNativeSelect[0]/domChild[0]label=STREAMING
    assertNotTextvaadin=runcomvaadintestspushPushConfigurationTest::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[5]/VLabel[0]4
    selectvaadin=runcomvaadintestspushPushConfigurationTest::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VVerticalLayout[0]/Slot[0]/VVerticalLayout[0]/Slot[0]/VNativeSelect[0]/domChild[0]label=AUTOMATIC
    assertNotTextvaadin=runcomvaadintestspushPushConfigurationTest::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[5]/VLabel[0]4
    assertTextvaadin=runcomvaadintestspushPushConfigurationTest::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VVerticalLayout[0]/Slot[0]/VVerticalLayout[0]/Slot[5]/VLabel[0]/domChild[0]*fallbackTransport: streaming*transport: streaming*
    waitForTextvaadin=runcomvaadintestspushPushConfigurationTest::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[5]/VLabel[0]4
    assertTextNotPresentPush connection established using websocket
    assertTextPresentPush connection established using streaming
    selectvaadin=runcomvaadintestspushPushConfigurationTest::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VVerticalLayout[0]/Slot[0]/VVerticalLayout[0]/Slot[0]/VNativeSelect[0]/domChild[0]label=DISABLED
    + + diff --git a/uitest/src/com/vaadin/tests/push/PushConfigurationTest.java b/uitest/src/com/vaadin/tests/push/PushConfigurationTest.java new file mode 100644 index 0000000000..b57e9732cc --- /dev/null +++ b/uitest/src/com/vaadin/tests/push/PushConfigurationTest.java @@ -0,0 +1,102 @@ +package com.vaadin.tests.push; + +import java.util.Date; +import java.util.Timer; +import java.util.TimerTask; + +import com.vaadin.data.util.ObjectProperty; +import com.vaadin.server.VaadinRequest; +import com.vaadin.shared.ui.label.ContentMode; +import com.vaadin.tests.components.AbstractTestUI; +import com.vaadin.ui.Button; +import com.vaadin.ui.Button.ClickEvent; +import com.vaadin.ui.Label; + +public class PushConfigurationTest extends AbstractTestUI { + + private ObjectProperty counter = new ObjectProperty(0); + + private ObjectProperty counter2 = new ObjectProperty(0); + + private final Timer timer = new Timer(true); + + private final TimerTask task = new TimerTask() { + + @Override + public void run() { + access(new Runnable() { + @Override + public void run() { + counter2.setValue(counter2.getValue() + 1); + } + }); + } + }; + + @Override + protected void setup(VaadinRequest request) { + addComponent(new PushConfigurator(this)); + spacer(); + + /* + * Client initiated push. + */ + Label lbl = new Label(counter); + lbl.setCaption("Client counter (click 'increment' to update):"); + addComponent(lbl); + + addComponent(new Button("Increment", new Button.ClickListener() { + + @Override + public void buttonClick(ClickEvent event) { + counter.setValue(counter.getValue() + 1); + } + })); + + spacer(); + + /* + * Server initiated push. + */ + lbl = new Label(counter2); + lbl.setCaption("Server counter (updates each 1s by server thread) :"); + addComponent(lbl); + + addComponent(new Button("Reset", new Button.ClickListener() { + + @Override + public void buttonClick(ClickEvent event) { + counter2.setValue(0); + } + })); + } + + @Override + protected String getTestDescription() { + return "This test tests the very basic operations of push. " + + "It tests that client initiated changes are " + + "recieved back to the client as well as server " + + "initiated changes are correctly updated to the client."; + } + + @Override + protected Integer getTicketNumber() { + return 11494; + } + + private void spacer() { + addComponent(new Label("
    ", ContentMode.HTML)); + } + + @Override + public void attach() { + super.attach(); + timer.scheduleAtFixedRate(task, new Date(), 1000); + } + + @Override + public void detach() { + super.detach(); + timer.cancel(); + } +} diff --git a/uitest/src/com/vaadin/tests/push/PushConfigurator.java b/uitest/src/com/vaadin/tests/push/PushConfigurator.java new file mode 100644 index 0000000000..6528366b59 --- /dev/null +++ b/uitest/src/com/vaadin/tests/push/PushConfigurator.java @@ -0,0 +1,152 @@ +/* + * Copyright 2000-2013 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.push; + +import java.util.ArrayList; +import java.util.Collections; + +import com.vaadin.data.Property.ValueChangeEvent; +import com.vaadin.data.Property.ValueChangeListener; +import com.vaadin.shared.communication.PushMode; +import com.vaadin.shared.ui.label.ContentMode; +import com.vaadin.shared.ui.ui.Transport; +import com.vaadin.ui.Alignment; +import com.vaadin.ui.Button; +import com.vaadin.ui.Button.ClickEvent; +import com.vaadin.ui.Button.ClickListener; +import com.vaadin.ui.HorizontalLayout; +import com.vaadin.ui.Label; +import com.vaadin.ui.NativeSelect; +import com.vaadin.ui.PushConfiguration; +import com.vaadin.ui.TextField; +import com.vaadin.ui.UI; +import com.vaadin.ui.VerticalLayout; + +/** + * + * @since 7.1 + * @author Vaadin Ltd + */ +public class PushConfigurator extends VerticalLayout { + private NativeSelect pushMode = new NativeSelect("Push mode"); + private NativeSelect transport = new NativeSelect("Transport"); + private NativeSelect fallbackTransport = new NativeSelect("Fallback"); + private TextField parameter = new TextField("Parameter"); + private TextField value = new TextField("Value"); + private Button set = new Button("Set"); + private HorizontalLayout paramValue = new HorizontalLayout(); + private VerticalLayout vl = new VerticalLayout(); + private UI ui; + + private Label status = new Label("", ContentMode.PREFORMATTED); + + public PushConfigurator(UI ui) { + this.ui = ui; + construct(); + refreshStatus(); + } + + /** + * @since + */ + private void refreshStatus() { + PushConfiguration pc = ui.getPushConfiguration(); + String value = ""; + ArrayList names = new ArrayList(); + names.addAll(pc.getParameterNames()); + Collections.sort(names); + for (String param : names) { + value += param + ": " + pc.getParameter(param) + "\n"; + } + status.setValue(value); + } + + /** + * @since + */ + private void construct() { + pushMode.addItem(PushMode.DISABLED); + pushMode.addItem(PushMode.MANUAL); + pushMode.addItem(PushMode.AUTOMATIC); + + for (Transport t : Transport.values()) { + transport.addItem(t.toString()); + fallbackTransport.addItem(t.toString()); + } + transport.addItem(""); + fallbackTransport.addItem(""); + + pushMode.setImmediate(true); + transport.setImmediate(true); + fallbackTransport.setImmediate(true); + + listeners(); + + paramValue.setDefaultComponentAlignment(Alignment.BOTTOM_RIGHT); + paramValue.addComponents(parameter, value, set); + vl.addComponents(pushMode, transport, fallbackTransport, paramValue, + new Label("
    ", ContentMode.HTML), status); + addComponent(vl); + + } + + /** + * @since + */ + private void listeners() { + pushMode.addValueChangeListener(new ValueChangeListener() { + @Override + public void valueChange(ValueChangeEvent event) { + ui.getPushConfiguration().setPushMode( + (PushMode) pushMode.getValue()); + refreshStatus(); + } + }); + + transport.addValueChangeListener(new ValueChangeListener() { + @Override + public void valueChange(ValueChangeEvent event) { + Transport t = Transport.valueOf((String) transport.getValue()); + ui.getPushConfiguration().setTransport(t); + refreshStatus(); + } + }); + + fallbackTransport.addValueChangeListener(new ValueChangeListener() { + @Override + public void valueChange(ValueChangeEvent event) { + Transport t = Transport.valueOf((String) fallbackTransport + .getValue()); + ui.getPushConfiguration().setFallbackTransport(t); + refreshStatus(); + } + }); + + set.addClickListener(new ClickListener() { + @Override + public void buttonClick(ClickEvent event) { + ui.getPushConfiguration().setParameter(parameter.getValue(), + value.getValue()); + refreshStatus(); + } + }); + + } +} diff --git a/uitest/src/com/vaadin/tests/push/TogglePush.java b/uitest/src/com/vaadin/tests/push/TogglePush.java index 37687260dd..c0bdc54ee0 100644 --- a/uitest/src/com/vaadin/tests/push/TogglePush.java +++ b/uitest/src/com/vaadin/tests/push/TogglePush.java @@ -22,19 +22,22 @@ public class TogglePush extends AbstractTestUI { updateCounter(); addComponent(counterLabel); - setPushMode("disabled".equals(request.getParameter("push")) ? PushMode.DISABLED - : PushMode.AUTOMATIC); + getPushConfiguration() + .setPushMode( + "disabled".equals(request.getParameter("push")) ? PushMode.DISABLED + : PushMode.AUTOMATIC); CheckBox pushSetting = new CheckBox("Push enabled"); - pushSetting.setValue(Boolean.valueOf(getPushMode().isEnabled())); + pushSetting.setValue(Boolean.valueOf(getPushConfiguration() + .getPushMode().isEnabled())); pushSetting.setImmediate(true); pushSetting.addValueChangeListener(new ValueChangeListener() { @Override public void valueChange(ValueChangeEvent event) { if (event.getProperty().getValue() == Boolean.TRUE) { - setPushMode(PushMode.AUTOMATIC); + getPushConfiguration().setPushMode(PushMode.AUTOMATIC); } else { - setPushMode(PushMode.DISABLED); + getPushConfiguration().setPushMode(PushMode.DISABLED); } } }); diff --git a/uitest/src/com/vaadin/tests/widgetset/client/TestingPushConnection.java b/uitest/src/com/vaadin/tests/widgetset/client/TestingPushConnection.java index e255a5f95a..4dae8892e7 100644 --- a/uitest/src/com/vaadin/tests/widgetset/client/TestingPushConnection.java +++ b/uitest/src/com/vaadin/tests/widgetset/client/TestingPushConnection.java @@ -4,6 +4,7 @@ import com.google.gwt.user.client.Window; import com.vaadin.client.ApplicationConnection; import com.vaadin.client.ApplicationConnection.CommunicationErrorHandler; import com.vaadin.client.communication.AtmospherePushConnection; +import com.vaadin.shared.ui.ui.UIState.PushConfigurationState; public class TestingPushConnection extends AtmospherePushConnection { @@ -11,8 +12,9 @@ public class TestingPushConnection extends AtmospherePushConnection { @Override public void init(ApplicationConnection connection, + PushConfigurationState pushConfiguration, CommunicationErrorHandler errorHandler) { - super.init(connection, errorHandler); + super.init(connection, pushConfiguration, errorHandler); transport = Window.Location.getParameter("transport"); } -- cgit v1.2.3 From b0574f7b33c4d3d437c8c11cd53389e5522f6999 Mon Sep 17 00:00:00 2001 From: Artur Signell Date: Mon, 3 Jun 2013 23:15:43 +0300 Subject: Add transport parameter to @Push (#11966) Change-Id: Ic47e68a41ba407917a990ef82a98c1526a9510ef --- server/src/com/vaadin/annotations/Push.java | 10 +++++ server/src/com/vaadin/server/UIProvider.java | 24 +++++++++++ .../vaadin/server/communication/UIInitHandler.java | 6 +++ .../com/vaadin/tests/push/BasicPushStreaming.java | 12 ++++++ .../com/vaadin/tests/push/BasicPushWebsocket.java | 8 ++++ .../vaadin/tests/push/PushTransportAnnotation.html | 46 ++++++++++++++++++++++ 6 files changed, 106 insertions(+) create mode 100644 uitest/src/com/vaadin/tests/push/BasicPushStreaming.java create mode 100644 uitest/src/com/vaadin/tests/push/BasicPushWebsocket.java create mode 100644 uitest/src/com/vaadin/tests/push/PushTransportAnnotation.html diff --git a/server/src/com/vaadin/annotations/Push.java b/server/src/com/vaadin/annotations/Push.java index 58e70acf21..d5e42d6f60 100644 --- a/server/src/com/vaadin/annotations/Push.java +++ b/server/src/com/vaadin/annotations/Push.java @@ -22,6 +22,7 @@ import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import com.vaadin.shared.communication.PushMode; +import com.vaadin.shared.ui.ui.Transport; import com.vaadin.ui.UI; /** @@ -46,4 +47,13 @@ public @interface Push { */ public PushMode value() default PushMode.AUTOMATIC; + /** + * Returns the transport type used for the push for the annotated UI. The + * default transport type when this annotation is present is + * {@link Transport#WEBSOCKET}. + * + * @return the transport type to use + */ + public Transport transport() default Transport.DEFAULT; + } diff --git a/server/src/com/vaadin/server/UIProvider.java b/server/src/com/vaadin/server/UIProvider.java index 0305b907e6..3e7c85aea9 100644 --- a/server/src/com/vaadin/server/UIProvider.java +++ b/server/src/com/vaadin/server/UIProvider.java @@ -25,6 +25,7 @@ import com.vaadin.annotations.Theme; import com.vaadin.annotations.Title; import com.vaadin.annotations.Widgetset; import com.vaadin.shared.communication.PushMode; +import com.vaadin.shared.ui.ui.Transport; import com.vaadin.ui.UI; public abstract class UIProvider implements Serializable { @@ -174,4 +175,27 @@ public abstract class UIProvider implements Serializable { return push.value(); } } + + /** + * Finds the {@link Transport} to use for a specific UI. If no transport is + * defined, null is returned. + *

    + * The default implementation uses the @{@link Push} annotation if it's + * defined for the UI class. + * + * @param event + * the UI create event with information about the UI and the + * current request. + * @return the transport type to use, or null if the default + * transport type should be used + */ + public Transport getPushTransport(UICreateEvent event) { + Push push = getAnnotationFor(event.getUIClass(), Push.class); + if (push == null) { + return null; + } else { + return push.transport(); + } + } + } diff --git a/server/src/com/vaadin/server/communication/UIInitHandler.java b/server/src/com/vaadin/server/communication/UIInitHandler.java index 9807ea6a9f..d4b0bc709f 100644 --- a/server/src/com/vaadin/server/communication/UIInitHandler.java +++ b/server/src/com/vaadin/server/communication/UIInitHandler.java @@ -39,6 +39,7 @@ import com.vaadin.server.VaadinService; import com.vaadin.server.VaadinSession; import com.vaadin.shared.ApplicationConstants; import com.vaadin.shared.communication.PushMode; +import com.vaadin.shared.ui.ui.Transport; import com.vaadin.shared.ui.ui.UIConstants; import com.vaadin.ui.UI; @@ -211,6 +212,11 @@ public abstract class UIInitHandler extends SynchronizedRequestHandler { } ui.getPushConfiguration().setPushMode(pushMode); + Transport transport = provider.getPushTransport(event); + if (transport != null) { + ui.getPushConfiguration().setTransport(transport); + } + // Set thread local here so it is available in init UI.setCurrent(ui); diff --git a/uitest/src/com/vaadin/tests/push/BasicPushStreaming.java b/uitest/src/com/vaadin/tests/push/BasicPushStreaming.java new file mode 100644 index 0000000000..37a8afd819 --- /dev/null +++ b/uitest/src/com/vaadin/tests/push/BasicPushStreaming.java @@ -0,0 +1,12 @@ +package com.vaadin.tests.push; + +import com.vaadin.annotations.Push; +import com.vaadin.shared.ui.ui.Transport; + +@Push(transport = Transport.STREAMING) +public class BasicPushStreaming extends BasicPush { + @Override + protected void setup(com.vaadin.server.VaadinRequest request) { + addComponent(new PushConfigurator(this)); + } +} diff --git a/uitest/src/com/vaadin/tests/push/BasicPushWebsocket.java b/uitest/src/com/vaadin/tests/push/BasicPushWebsocket.java new file mode 100644 index 0000000000..6fc27e8974 --- /dev/null +++ b/uitest/src/com/vaadin/tests/push/BasicPushWebsocket.java @@ -0,0 +1,8 @@ +package com.vaadin.tests.push; + +import com.vaadin.annotations.Push; +import com.vaadin.shared.ui.ui.Transport; + +@Push(transport = Transport.WEBSOCKET) +public class BasicPushWebsocket extends BasicPush { +} diff --git a/uitest/src/com/vaadin/tests/push/PushTransportAnnotation.html b/uitest/src/com/vaadin/tests/push/PushTransportAnnotation.html new file mode 100644 index 0000000000..854dd458bb --- /dev/null +++ b/uitest/src/com/vaadin/tests/push/PushTransportAnnotation.html @@ -0,0 +1,46 @@ + + + + + + +New Test + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    New Test
    open/run/com.vaadin.tests.push.BasicPushStreaming?debug&restartApplication
    waitForTextPresentPush connection established using streaming
    assertTextNotPresentPush connection established using websocket
    open/run/com.vaadin.tests.push.BasicPushWebsocket?debug&restartApplication
    assertTextNotPresentPush connection established using streaming
    waitForTextPresentPush connection established using websocket
    + + -- cgit v1.2.3