From dac74189ededf7d004b309215f7e9f64a3e4550c Mon Sep 17 00:00:00 2001 From: Fabian Lange Date: Mon, 24 Nov 2014 21:30:59 +0100 Subject: do not create a StringWriter when not needed (#15276) Change-Id: I528f4034ef5cf375be31750bbad9baddcd3a2b64 --- server/src/com/vaadin/server/communication/UIInitHandler.java | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) (limited to 'server/src') diff --git a/server/src/com/vaadin/server/communication/UIInitHandler.java b/server/src/com/vaadin/server/communication/UIInitHandler.java index 356ad25219..8e61370d85 100644 --- a/server/src/com/vaadin/server/communication/UIInitHandler.java +++ b/server/src/com/vaadin/server/communication/UIInitHandler.java @@ -65,8 +65,6 @@ public abstract class UIInitHandler extends SynchronizedRequestHandler { @Override public boolean synchronizedHandleRequest(VaadinSession session, VaadinRequest request, VaadinResponse response) throws IOException { - StringWriter stringWriter = new StringWriter(); - try { assert UI.getCurrent() == null; @@ -82,14 +80,10 @@ public abstract class UIInitHandler extends SynchronizedRequestHandler { String initialUIDL = getInitialUidl(request, uI); params.put("uidl", initialUIDL); - stringWriter.write(JsonUtil.stringify(params)); + return commitJsonResponse(request, response, JsonUtil.stringify(params)); } catch (JsonException e) { throw new IOException("Error producing initial UIDL", e); - } finally { - stringWriter.close(); } - - return commitJsonResponse(request, response, stringWriter.toString()); } /** -- cgit v1.2.3 From 75ca951246f4c40dbc6914539d2d2d4890d30089 Mon Sep 17 00:00:00 2001 From: Anna Koskinen Date: Tue, 25 Nov 2014 17:23:45 +0200 Subject: Add getter to SplitterState.positionReversed (#15285) Change-Id: I1e3783d21cb5f2832838dfe36c91c7f6a4ddb313 --- server/src/com/vaadin/ui/AbstractSplitPanel.java | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'server/src') diff --git a/server/src/com/vaadin/ui/AbstractSplitPanel.java b/server/src/com/vaadin/ui/AbstractSplitPanel.java index 09f881cf46..e9b37f8cff 100644 --- a/server/src/com/vaadin/ui/AbstractSplitPanel.java +++ b/server/src/com/vaadin/ui/AbstractSplitPanel.java @@ -342,11 +342,25 @@ public abstract class AbstractSplitPanel extends AbstractComponentContainer { * Returns the unit of position of the splitter * * @return unit of position of the splitter + * @see #setSplitPosition(float, Unit) */ public Unit getSplitPositionUnit() { return posUnit; } + /** + * Is the split position reversed. By default the split position is measured + * by the first region, but if split position is reversed the measuring is + * done by the second region instead. + * + * @since + * @return {@code true} if reversed, {@code false} otherwise. + * @see #setSplitPosition(float, boolean) + */ + public boolean isSplitPositionReversed() { + return getSplitterState(false).positionReversed; + } + /** * Sets the minimum split position to the given position and unit. If the * split position is reversed, maximum and minimum are also reversed. -- cgit v1.2.3 From f301dd8d759c5006cb411df0e424a876e04b84fb Mon Sep 17 00:00:00 2001 From: Fabian Lange Date: Mon, 10 Nov 2014 19:07:12 +0100 Subject: set Cache-Control and Expires header even when not-modified (#8757) Usually first a resource is served with the lower code block. this provides cache-control, expires and last-modification headers to the browser. But when a not-modified response was served, these headers were missing. This effectively caused the caching to no longer work once the not-modified responses are sent out. Change-Id: I9b1f0cacc91734f88bb0384872da0d426d4b5fe0 --- server/src/com/vaadin/server/VaadinServlet.java | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) (limited to 'server/src') diff --git a/server/src/com/vaadin/server/VaadinServlet.java b/server/src/com/vaadin/server/VaadinServlet.java index 4656f9a672..4fd1e97a40 100644 --- a/server/src/com/vaadin/server/VaadinServlet.java +++ b/server/src/com/vaadin/server/VaadinServlet.java @@ -704,6 +704,15 @@ public class VaadinServlet extends HttpServlet implements Constants { return; } + String cacheControl = "public, max-age=0, must-revalidate"; + int resourceCacheTime = getCacheTime(filename); + if (resourceCacheTime > 0) { + cacheControl = "max-age=" + String.valueOf(resourceCacheTime); + } + response.setHeader("Cache-Control", cacheControl); + response.setDateHeader("Expires", System.currentTimeMillis() + + (resourceCacheTime * 1000)); + // Find the modification timestamp long lastModifiedTime = 0; URLConnection connection = null; @@ -714,6 +723,7 @@ public class VaadinServlet extends HttpServlet implements Constants { // are not returned by the browser in the "If-Modified-Since" // header). lastModifiedTime = lastModifiedTime - lastModifiedTime % 1000; + response.setDateHeader("Last-Modified", lastModifiedTime); if (browserHasNewestVersion(request, lastModifiedTime)) { response.setStatus(HttpServletResponse.SC_NOT_MODIFIED); @@ -748,18 +758,6 @@ public class VaadinServlet extends HttpServlet implements Constants { response.setContentType(mimetype); } - // Provide modification timestamp to the browser if it is known. - if (lastModifiedTime > 0) { - response.setDateHeader("Last-Modified", lastModifiedTime); - - String cacheControl = "public, max-age=0, must-revalidate"; - int resourceCacheTime = getCacheTime(filename); - if (resourceCacheTime > 0) { - cacheControl = "max-age=" + String.valueOf(resourceCacheTime); - } - response.setHeader("Cache-Control", cacheControl); - } - writeStaticResourceResponse(request, response, resourceUrl); } -- cgit v1.2.3 From 58cf6113d02cb0331dae6d5ff46eb3e4a0ccdb01 Mon Sep 17 00:00:00 2001 From: Denis Anisimov Date: Wed, 5 Nov 2014 19:37:31 +0200 Subject: Prevent NPE in AbstractBeanContainer.getType() method (#15173). Change-Id: Ieaed329ed85c68d0da8bd169b4cc5c5886dde212 --- server/src/com/vaadin/data/util/AbstractBeanContainer.java | 8 ++++++-- .../tests/src/com/vaadin/data/util/BeanContainerTest.java | 13 +++++++++++++ .../src/com/vaadin/data/util/BeanItemContainerTest.java | 13 +++++++++++++ 3 files changed, 32 insertions(+), 2 deletions(-) (limited to 'server/src') diff --git a/server/src/com/vaadin/data/util/AbstractBeanContainer.java b/server/src/com/vaadin/data/util/AbstractBeanContainer.java index adf6313770..7d7d71c423 100644 --- a/server/src/com/vaadin/data/util/AbstractBeanContainer.java +++ b/server/src/com/vaadin/data/util/AbstractBeanContainer.java @@ -152,7 +152,7 @@ public abstract class AbstractBeanContainer extends * A description of the properties found in beans of type {@link #type}. * Determines the property ids that are present in the container. */ - private LinkedHashMap> model; + private final LinkedHashMap> model; /** * Constructs a {@code AbstractBeanContainer} for beans of the given type. @@ -178,7 +178,11 @@ public abstract class AbstractBeanContainer extends */ @Override public Class getType(Object propertyId) { - return model.get(propertyId).getPropertyType(); + VaadinPropertyDescriptor descriptor = model.get(propertyId); + if (descriptor == null) { + return null; + } + return descriptor.getPropertyType(); } /** diff --git a/server/tests/src/com/vaadin/data/util/BeanContainerTest.java b/server/tests/src/com/vaadin/data/util/BeanContainerTest.java index 4e0e98ec43..f22ab8478e 100644 --- a/server/tests/src/com/vaadin/data/util/BeanContainerTest.java +++ b/server/tests/src/com/vaadin/data/util/BeanContainerTest.java @@ -68,6 +68,19 @@ public class BeanContainerTest extends AbstractBeanContainerTest { return false; } + public void testGetType_existingProperty_typeReturned() { + BeanContainer container = getContainer(); + Assert.assertEquals( + "Unexpected type is returned for property 'simpleName'", + String.class, container.getType("simpleName")); + } + + public void testGetType_notExistingProperty_nullReturned() { + BeanContainer container = getContainer(); + Assert.assertNull("Not null type is returned for property ''", + container.getType("")); + } + public void testBasicOperations() { testBasicContainerOperations(getContainer()); } diff --git a/server/tests/src/com/vaadin/data/util/BeanItemContainerTest.java b/server/tests/src/com/vaadin/data/util/BeanItemContainerTest.java index b58d962d96..01c282e294 100644 --- a/server/tests/src/com/vaadin/data/util/BeanItemContainerTest.java +++ b/server/tests/src/com/vaadin/data/util/BeanItemContainerTest.java @@ -71,6 +71,19 @@ public class BeanItemContainerTest extends AbstractBeanContainerTest { return false; } + public void testGetType_existingProperty_typeReturned() { + BeanItemContainer container = getContainer(); + Assert.assertEquals( + "Unexpected type is returned for property 'simpleName'", + String.class, container.getType("simpleName")); + } + + public void testGetType_notExistingProperty_nullReturned() { + BeanItemContainer container = getContainer(); + Assert.assertNull("Not null type is returned for property ''", + container.getType("")); + } + public void testBasicOperations() { testBasicContainerOperations(getContainer()); } -- cgit v1.2.3 From 53f87e5bf3014382f0bf9cd7acb18c56709ba1f7 Mon Sep 17 00:00:00 2001 From: Denis Anisimov Date: Sun, 19 Oct 2014 14:54:47 +0300 Subject: Show push version information in debug window (#14904). Change-Id: Id1761abbf2b2dc29b4138520f11ce51bb4d423fc --- .../vaadin/client/ApplicationConfiguration.java | 45 +++++++++ .../vaadin/client/debug/internal/InfoSection.java | 8 ++ server/src/com/vaadin/server/BootstrapHandler.java | 2 + .../com/vaadin/tests/debug/PushVersionInfo.java | 51 +++++++++++ .../vaadin/tests/debug/PushVersionInfoTest.java | 102 +++++++++++++++++++++ 5 files changed, 208 insertions(+) create mode 100644 uitest/src/com/vaadin/tests/debug/PushVersionInfo.java create mode 100644 uitest/src/com/vaadin/tests/debug/PushVersionInfoTest.java (limited to 'server/src') diff --git a/client/src/com/vaadin/client/ApplicationConfiguration.java b/client/src/com/vaadin/client/ApplicationConfiguration.java index 12b1585292..4865e38a4a 100644 --- a/client/src/com/vaadin/client/ApplicationConfiguration.java +++ b/client/src/com/vaadin/client/ApplicationConfiguration.java @@ -172,6 +172,33 @@ public class ApplicationConfiguration implements EntryPoint { return this.getConfig("versionInfo").vaadinVersion; }-*/; + /** + * Gets the version of the Atmosphere framework. + * + * @return a string with the version + * + * @see org.atmosphere.util#getRawVersion() + */ + private native String getAtmosphereVersion() + /*-{ + return this.getConfig("versionInfo").atmosphereVersion; + }-*/; + + /** + * Gets the JS version used in the Atmosphere framework. + * + * @return a string with the version + */ + private native String getAtmosphereJSVersion() + /*-{ + if ($wnd.jQueryVaadin != undefined){ + return $wnd.jQueryVaadin.atmosphere.version; + } + else { + return null; + } + }-*/; + private native String getUIDL() /*-{ return this.getConfig("uidl"); @@ -461,6 +488,24 @@ public class ApplicationConfiguration implements EntryPoint { return getJsoConfiguration(id).getVaadinVersion(); } + /** + * Return Atmosphere version. + * + * @return Atmosphere version. + */ + public String getAtmosphereVersion() { + return getJsoConfiguration(id).getAtmosphereVersion(); + } + + /** + * Return Atmosphere JS version. + * + * @return Atmosphere JS version. + */ + public String getAtmosphereJSVersion() { + return getJsoConfiguration(id).getAtmosphereJSVersion(); + } + public Class getConnectorClassByEncodedTag( int tag) { Class type = classes.get(tag); diff --git a/client/src/com/vaadin/client/debug/internal/InfoSection.java b/client/src/com/vaadin/client/debug/internal/InfoSection.java index a7a84f5f8f..dfb31cdd18 100644 --- a/client/src/com/vaadin/client/debug/internal/InfoSection.java +++ b/client/src/com/vaadin/client/debug/internal/InfoSection.java @@ -193,6 +193,9 @@ public class InfoSection implements Section { ApplicationConfiguration applicationConfiguration) { String clientVersion = Version.getFullVersion(); String servletVersion = applicationConfiguration.getServletVersion(); + String atmosphereVersion = applicationConfiguration + .getAtmosphereVersion(); + String jsVersion = applicationConfiguration.getAtmosphereJSVersion(); String themeVersion; boolean themeOk; @@ -213,6 +216,11 @@ public class InfoSection implements Section { addRow("Server engine version", servletVersion, servletOk ? null : ERROR_STYLE); addRow("Theme version", themeVersion, themeOk ? null : ERROR_STYLE); + if (jsVersion != null) { + addRow("Push server version", atmosphereVersion); + addRow("Push client version", jsVersion + + " (note: does not need to match server version)"); + } } /** diff --git a/server/src/com/vaadin/server/BootstrapHandler.java b/server/src/com/vaadin/server/BootstrapHandler.java index f0666f63fc..c34e986fce 100644 --- a/server/src/com/vaadin/server/BootstrapHandler.java +++ b/server/src/com/vaadin/server/BootstrapHandler.java @@ -469,6 +469,8 @@ public abstract class BootstrapHandler extends SynchronizedRequestHandler { JsonObject versionInfo = Json.createObject(); versionInfo.put("vaadinVersion", Version.getFullVersion()); + versionInfo.put("atmosphereVersion", + org.atmosphere.util.Version.getRawVersion()); appConfig.put("versionInfo", versionInfo); appConfig.put("widgetset", context.getWidgetsetName()); diff --git a/uitest/src/com/vaadin/tests/debug/PushVersionInfo.java b/uitest/src/com/vaadin/tests/debug/PushVersionInfo.java new file mode 100644 index 0000000000..d8c23a390f --- /dev/null +++ b/uitest/src/com/vaadin/tests/debug/PushVersionInfo.java @@ -0,0 +1,51 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.tests.debug; + +import org.atmosphere.util.Version; + +import com.vaadin.server.VaadinRequest; +import com.vaadin.shared.communication.PushMode; +import com.vaadin.tests.components.AbstractTestUI; +import com.vaadin.ui.Label; + +/** + * Test UI for PUSH version string in debug window. + * + * @author Vaadin Ltd + */ +public class PushVersionInfo extends AbstractTestUI { + + @Override + protected void setup(VaadinRequest request) { + if (request.getParameter("enablePush") != null) { + getPushConfiguration().setPushMode(PushMode.AUTOMATIC); + Label label = new Label(Version.getRawVersion()); + label.addStyleName("atmosphere-version"); + addComponent(label); + } + } + + @Override + public String getDescription() { + return "Debug window shows Push version in info Tab."; + } + + @Override + protected Integer getTicketNumber() { + return 14904; + } +} diff --git a/uitest/src/com/vaadin/tests/debug/PushVersionInfoTest.java b/uitest/src/com/vaadin/tests/debug/PushVersionInfoTest.java new file mode 100644 index 0000000000..90ea645ab8 --- /dev/null +++ b/uitest/src/com/vaadin/tests/debug/PushVersionInfoTest.java @@ -0,0 +1,102 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.tests.debug; + +import java.util.List; + +import org.junit.Assert; +import org.junit.Test; +import org.openqa.selenium.By; +import org.openqa.selenium.Keys; +import org.openqa.selenium.WebElement; +import org.openqa.selenium.interactions.Actions; + +import com.vaadin.tests.annotations.TestCategory; +import com.vaadin.tests.tb3.MultiBrowserTest; + +/** + * Test for PUSH version string in debug window. + * + * @author Vaadin Ltd + */ +@TestCategory("push") +public class PushVersionInfoTest extends MultiBrowserTest { + + @Test + public void testDisabledPush() { + setDebug(true); + openTestURL(); + + selectInfoTab(); + Assert.assertNull("Found push info server string for disabled Push", + getPushRowValue("Push server version")); + Assert.assertNull("Found push info client string for disabled Push", + getPushRowValue("Push client version")); + } + + @Test + public void testEnabledPush() { + setDebug(true); + openTestURL("enablePush=true"); + + selectInfoTab(); + WebElement pushRow = getPushRowValue("Push server version"); + String atmVersion = findElement(By.className("atmosphere-version")) + .getText(); + Assert.assertTrue("Push row doesn't contain Atmosphere version", + pushRow.getText().contains(atmVersion)); + String jsString = getPushRowValue("Push client version").getText(); + Assert.assertTrue( + "Push client version doesn't contain 'vaadin' string", + jsString.contains("vaadin")); + Assert.assertTrue( + "Push client version doesn't contain 'jquery' string", + jsString.contains("jquery")); + } + + private void selectInfoTab() { + if (isElementPresent(By.className("v-ie8"))) { + + int size = findElements(By.className("v-debugwindow-tab")).size(); + for (int i = 0; i < size; i++) { + WebElement tab = findElement(By + .className("v-debugwindow-tab-selected")); + String title = tab.getAttribute("title"); + if (title != null && title.startsWith("General information")) { + break; + } + Actions actions = new Actions(getDriver()); + actions.sendKeys(Keys.TAB); + actions.sendKeys(Keys.SPACE); + actions.build().perform(); + } + } else { + findElements(By.className("v-debugwindow-tab")).get(0).click(); + findElements(By.className("v-debugwindow-tab")).get(1).click(); + } + } + + private WebElement getPushRowValue(String key) { + List rows = findElements(By.className("v-debugwindow-row")); + for (WebElement row : rows) { + WebElement caption = row.findElement(By.className("caption")); + if (caption.getText().startsWith(key)) { + return row.findElement(By.className("value")); + } + } + return null; + } +} -- cgit v1.2.3 From 654846837379db9a76823f5d0e73e5e6bfa8115d Mon Sep 17 00:00:00 2001 From: Denis Anisimov Date: Mon, 29 Sep 2014 20:40:36 +0300 Subject: Allow BeanFieldGroup.setItemDataSource() method accept null (#14731). Change-Id: I7a451f428f0aa3ea7fc322cac6b0e62d830d7987 --- .../com/vaadin/data/fieldgroup/BeanFieldGroup.java | 7 ++--- server/src/com/vaadin/data/util/BeanItem.java | 25 ++++++++++++++++- .../src/com/vaadin/data/util/MethodProperty.java | 10 ++++--- .../component/fieldgroup/BeanFieldGroupTest.java | 31 ++++++++++++++++++++++ 4 files changed, 66 insertions(+), 7 deletions(-) (limited to 'server/src') diff --git a/server/src/com/vaadin/data/fieldgroup/BeanFieldGroup.java b/server/src/com/vaadin/data/fieldgroup/BeanFieldGroup.java index e5d53b759d..1f3ee36d58 100644 --- a/server/src/com/vaadin/data/fieldgroup/BeanFieldGroup.java +++ b/server/src/com/vaadin/data/fieldgroup/BeanFieldGroup.java @@ -130,16 +130,17 @@ public class BeanFieldGroup extends FieldGroup { * The bean to use as data source. */ public void setItemDataSource(T bean) { - setItemDataSource(new BeanItem(bean)); + setItemDataSource(new BeanItem(bean, beanType)); } @Override public void setItemDataSource(Item item) { - if (!(item instanceof BeanItem)) { + if (item == null || (item instanceof BeanItem)) { + super.setItemDataSource(item); + } else { throw new RuntimeException(getClass().getSimpleName() + " only supports BeanItems as item data source"); } - super.setItemDataSource(item); } @Override diff --git a/server/src/com/vaadin/data/util/BeanItem.java b/server/src/com/vaadin/data/util/BeanItem.java index 12d9b23d0a..64f30261c2 100644 --- a/server/src/com/vaadin/data/util/BeanItem.java +++ b/server/src/com/vaadin/data/util/BeanItem.java @@ -62,7 +62,30 @@ public class BeanItem extends PropertysetItem { * */ public BeanItem(BT bean) { - this(bean, getPropertyDescriptors((Class) bean.getClass())); + this(bean, (Class) bean.getClass()); + } + + /** + *

+ * Creates a new instance of BeanItem and adds all properties + * of a Java Bean to it. The properties are identified by their respective + * bean names. + *

+ * + *

+ * Note : This version only supports introspectable bean properties and + * their getter and setter methods. Stand-alone is and + * are methods are not supported. + *

+ * + * @param bean + * the Java Bean to copy properties from. + * @param beanClass + * class of the {@code bean} + * + */ + public BeanItem(BT bean, Class beanClass) { + this(bean, getPropertyDescriptors(beanClass)); } /** diff --git a/server/src/com/vaadin/data/util/MethodProperty.java b/server/src/com/vaadin/data/util/MethodProperty.java index 5e6b731571..853f68b711 100644 --- a/server/src/com/vaadin/data/util/MethodProperty.java +++ b/server/src/com/vaadin/data/util/MethodProperty.java @@ -132,7 +132,7 @@ public class MethodProperty extends AbstractProperty { setArguments(getArgs, setArgs, setArgumentIndex); String name = (String) in.readObject(); Class[] paramTypes = SerializerHelper.readClassArray(in); - if (name != null) { + if (instance != null && name != null) { setMethod = instance.getClass().getMethod(name, paramTypes); } else { setMethod = null; @@ -140,7 +140,7 @@ public class MethodProperty extends AbstractProperty { name = (String) in.readObject(); paramTypes = SerializerHelper.readClassArray(in); - if (name != null) { + if (instance != null && name != null) { getMethod = instance.getClass().getMethod(name, paramTypes); } else { getMethod = null; @@ -589,7 +589,11 @@ public class MethodProperty extends AbstractProperty { @Override public T getValue() { try { - return (T) getMethod.invoke(instance, getArgs); + if (instance == null) { + return null; + } else { + return (T) getMethod.invoke(instance, getArgs); + } } catch (final Throwable e) { throw new MethodException(this, e); } diff --git a/server/tests/src/com/vaadin/tests/server/component/fieldgroup/BeanFieldGroupTest.java b/server/tests/src/com/vaadin/tests/server/component/fieldgroup/BeanFieldGroupTest.java index 112d36d884..965fb49479 100644 --- a/server/tests/src/com/vaadin/tests/server/component/fieldgroup/BeanFieldGroupTest.java +++ b/server/tests/src/com/vaadin/tests/server/component/fieldgroup/BeanFieldGroupTest.java @@ -2,12 +2,16 @@ package com.vaadin.tests.server.component.fieldgroup; import static org.junit.Assert.assertEquals; +import java.util.Collection; + import org.junit.Assert; import org.junit.Test; +import com.vaadin.data.Item; import com.vaadin.data.fieldgroup.BeanFieldGroup; import com.vaadin.data.fieldgroup.FieldGroup.CommitException; import com.vaadin.data.fieldgroup.PropertyId; +import com.vaadin.data.util.BeanItem; import com.vaadin.ui.Field; import com.vaadin.ui.TextField; @@ -133,4 +137,31 @@ public class BeanFieldGroupTest { assertEquals(bean.nestedBean.hello, helloField.getValue().toString()); } + @Test + public void setDataSource_nullBean_nullBeanIsSetInDataSource() { + BeanFieldGroup group = new BeanFieldGroup(MyBean.class); + + group.setItemDataSource((MyBean) null); + + BeanItem dataSource = group.getItemDataSource(); + Assert.assertNotNull("Data source is null for null bean", dataSource); + + Collection itemPropertyIds = dataSource.getItemPropertyIds(); + Assert.assertEquals("Unexpected number of properties", 3, + itemPropertyIds.size()); + for (Object id : itemPropertyIds) { + Assert.assertNull("Value for property " + id + " is not null", + dataSource.getItemProperty(id).getValue()); + } + } + + @Test + public void setDataSource_nullItem_nullDataSourceIsSet() { + BeanFieldGroup group = new BeanFieldGroup(MyBean.class); + + group.setItemDataSource((Item) null); + BeanItem dataSource = group.getItemDataSource(); + Assert.assertNull("Group returns not null data source", dataSource); + } + } -- cgit v1.2.3 From 3c59a1f08d6e2288c4bcd0ac74273ae14c4d4e0b Mon Sep 17 00:00:00 2001 From: Leif Åstrand Date: Fri, 14 Nov 2014 15:27:49 +0200 Subject: Escape dynamic and configured theme names in the same way. (#15309) Change-Id: Ib7fd42e6017d0b78e6d5e6bd7f531f0cd6c8c0ab --- server/src/com/vaadin/server/VaadinServlet.java | 6 +-- server/src/com/vaadin/ui/UI.java | 8 +++- .../tests/src/com/vaadin/ui/UIThemeEscaping.java | 43 ++++++++++++++++++++++ 3 files changed, 52 insertions(+), 5 deletions(-) create mode 100644 server/tests/src/com/vaadin/ui/UIThemeEscaping.java (limited to 'server/src') diff --git a/server/src/com/vaadin/server/VaadinServlet.java b/server/src/com/vaadin/server/VaadinServlet.java index 4fd1e97a40..d1242676da 100644 --- a/server/src/com/vaadin/server/VaadinServlet.java +++ b/server/src/com/vaadin/server/VaadinServlet.java @@ -573,8 +573,8 @@ public class VaadinServlet extends HttpServlet implements Constants { /** * A helper method to strip away characters that might somehow be used for - * XSS attacs. Leaves at least alphanumeric characters intact. Also removes - * eg. ( and ), so values should be safe in javascript too. + * XSS attacks. Leaves at least alphanumeric characters intact. Also removes + * e.g. '(' and ')', so values should be safe in javascript too. * * @param themeName * @return @@ -583,7 +583,7 @@ public class VaadinServlet extends HttpServlet implements Constants { * version */ @Deprecated - protected static String stripSpecialChars(String themeName) { + public static String stripSpecialChars(String themeName) { StringBuilder sb = new StringBuilder(); char[] charArray = themeName.toCharArray(); for (int i = 0; i < charArray.length; i++) { diff --git a/server/src/com/vaadin/ui/UI.java b/server/src/com/vaadin/ui/UI.java index 78cb5488e8..44948dfb6f 100644 --- a/server/src/com/vaadin/ui/UI.java +++ b/server/src/com/vaadin/ui/UI.java @@ -633,7 +633,11 @@ public abstract class UI extends AbstractSingleComponentContainer implements this.embedId = embedId; // Actual theme - used for finding CustomLayout templates - getState().theme = request.getParameter("theme"); + String unescapedThemeName = request.getParameter("theme"); + if (unescapedThemeName != null) { + // Set theme escapes the name + setTheme(unescapedThemeName); + } getPage().init(request); @@ -1164,7 +1168,7 @@ public abstract class UI extends AbstractSingleComponentContainer implements * The new theme name */ public void setTheme(String theme) { - getState().theme = theme; + getState().theme = VaadinServlet.stripSpecialChars(theme); } /** diff --git a/server/tests/src/com/vaadin/ui/UIThemeEscaping.java b/server/tests/src/com/vaadin/ui/UIThemeEscaping.java new file mode 100644 index 0000000000..ca6782952d --- /dev/null +++ b/server/tests/src/com/vaadin/ui/UIThemeEscaping.java @@ -0,0 +1,43 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.ui; + +import org.junit.Assert; +import org.junit.Test; + +import com.vaadin.server.VaadinRequest; + +public class UIThemeEscaping { + + @Test + public void testThemeEscaping() { + UI ui = new UI() { + @Override + protected void init(VaadinRequest request) { + // Nothing to do + } + }; + + ui.setTheme("a<å(_\"$"); + + String theme = ui.getTheme(); + + Assert.assertEquals( + "Dangerous characters should be removed from the theme name", + "aå_$", theme); + } + +} -- cgit v1.2.3 From 758300e27e0110f58794e42bafac6e806ffdfb24 Mon Sep 17 00:00:00 2001 From: Sauli Tähkäpää Date: Thu, 4 Dec 2014 14:36:11 +0200 Subject: Add null check to UI.setTheme. (#15326) Change-Id: I2ab2d24ec05bb618969f59ea15d3a971f88009ca --- server/src/com/vaadin/ui/UI.java | 12 ++-- .../tests/src/com/vaadin/ui/UIThemeEscaping.java | 64 +++++++++++++++++++--- 2 files changed, 61 insertions(+), 15 deletions(-) (limited to 'server/src') diff --git a/server/src/com/vaadin/ui/UI.java b/server/src/com/vaadin/ui/UI.java index 44948dfb6f..4bd4b67259 100644 --- a/server/src/com/vaadin/ui/UI.java +++ b/server/src/com/vaadin/ui/UI.java @@ -633,11 +633,7 @@ public abstract class UI extends AbstractSingleComponentContainer implements this.embedId = embedId; // Actual theme - used for finding CustomLayout templates - String unescapedThemeName = request.getParameter("theme"); - if (unescapedThemeName != null) { - // Set theme escapes the name - setTheme(unescapedThemeName); - } + setTheme(request.getParameter("theme")); getPage().init(request); @@ -1168,7 +1164,11 @@ public abstract class UI extends AbstractSingleComponentContainer implements * The new theme name */ public void setTheme(String theme) { - getState().theme = VaadinServlet.stripSpecialChars(theme); + if(theme == null) { + getState().theme = null; + } else { + getState().theme = VaadinServlet.stripSpecialChars(theme); + } } /** diff --git a/server/tests/src/com/vaadin/ui/UIThemeEscaping.java b/server/tests/src/com/vaadin/ui/UIThemeEscaping.java index ca6782952d..236f283823 100644 --- a/server/tests/src/com/vaadin/ui/UIThemeEscaping.java +++ b/server/tests/src/com/vaadin/ui/UIThemeEscaping.java @@ -15,29 +15,75 @@ */ package com.vaadin.ui; -import org.junit.Assert; +import com.vaadin.server.VaadinRequest; +import org.junit.Before; import org.junit.Test; -import com.vaadin.server.VaadinRequest; +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.CoreMatchers.nullValue; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; public class UIThemeEscaping { - @Test - public void testThemeEscaping() { - UI ui = new UI() { + private UI ui; + + private void initUiWithTheme(String theme) { + VaadinRequest request = getRequestWithTheme(theme); + + ui.doInit(request, 1234, "foobar"); + } + + private VaadinRequest getRequestWithTheme(String theme) { + VaadinRequest request = mock(VaadinRequest.class); + + when(request.getParameter("theme")).thenReturn(theme); + + return request; + } + + @Before + public void setup() { + ui = new UI() { @Override protected void init(VaadinRequest request) { // Nothing to do } }; + } + @Test + public void dangerousCharactersAreRemoved() { ui.setTheme("a<å(_\"$"); - String theme = ui.getTheme(); + assertThat(ui.getTheme(), is("aå_$")); + } + + @Test + public void nullThemeIsSet() { + ui.setTheme("foobar"); + + ui.setTheme(null); - Assert.assertEquals( - "Dangerous characters should be removed from the theme name", - "aå_$", theme); + assertThat(ui.getTheme(), is(nullValue())); } + @Test + public void themeIsSetOnInit() { + ui.setTheme("foobar"); + + initUiWithTheme("bar"); + + assertThat(ui.getTheme(), is("bar")); + } + + @Test + public void nullThemeIsSetOnInit() { + ui.setTheme("foobar"); + + initUiWithTheme(null); + + assertThat(ui.getTheme(), is(nullValue())); + } } -- cgit v1.2.3 From 66c3dd2bf87ac3b021365b7a7d89180fb4304d8c Mon Sep 17 00:00:00 2001 From: Ilya Ermakov Date: Fri, 28 Nov 2014 13:09:38 +0300 Subject: SQLContainer removeItem Error when isModified (#8802) This patch makes commit() work properly if an item was modified and later deleted. Change-Id: I5a00024112e7b6bb7ab3750c292a872937f03af9 --- .../data/util/sqlcontainer/SQLContainer.java | 26 ++++++++++++---------- .../sqlcontainer/SQLContainerTableQueryTest.java | 14 ++++++++++++ 2 files changed, 28 insertions(+), 12 deletions(-) (limited to 'server/src') diff --git a/server/src/com/vaadin/data/util/sqlcontainer/SQLContainer.java b/server/src/com/vaadin/data/util/sqlcontainer/SQLContainer.java index 683140d279..70b392ab80 100644 --- a/server/src/com/vaadin/data/util/sqlcontainer/SQLContainer.java +++ b/server/src/com/vaadin/data/util/sqlcontainer/SQLContainer.java @@ -1020,18 +1020,20 @@ public class SQLContainer implements Container, Container.Filterable, } /* Perform buffered modifications */ for (RowItem item : modifiedItems) { - if (queryDelegate.storeRow(item) > 0) { - /* - * Also reset the modified state in the item in case it is - * reused e.g. in a form. - */ - item.commit(); - } else { - queryDelegate.rollback(); - refresh(); - throw new ConcurrentModificationException( - "Item with the ID '" + item.getId() - + "' has been externally modified."); + if (!removedItems.containsKey(item.getId())) { + if (queryDelegate.storeRow(item) > 0) { + /* + * Also reset the modified state in the item in case it + * is reused e.g. in a form. + */ + item.commit(); + } else { + queryDelegate.rollback(); + refresh(); + throw new ConcurrentModificationException( + "Item with the ID '" + item.getId() + + "' has been externally modified."); + } } } /* Perform buffered additions */ diff --git a/server/tests/src/com/vaadin/data/util/sqlcontainer/SQLContainerTableQueryTest.java b/server/tests/src/com/vaadin/data/util/sqlcontainer/SQLContainerTableQueryTest.java index d907f12321..93a27352a5 100644 --- a/server/tests/src/com/vaadin/data/util/sqlcontainer/SQLContainerTableQueryTest.java +++ b/server/tests/src/com/vaadin/data/util/sqlcontainer/SQLContainerTableQueryTest.java @@ -1136,6 +1136,20 @@ public class SQLContainerTableQueryTest { .getValue()); } + @Test + public void commit_removeModifiedItem_shouldSucceed() throws SQLException { + TableQuery query = new TableQuery("people", connectionPool, + SQLTestsConstants.sqlGen); + SQLContainer container = new SQLContainer(query); + int size = container.size(); + Object key = container.firstItemId(); + Item row = container.getItem(key); + row.getItemProperty("NAME").setValue("Pekka"); + Assert.assertTrue(container.removeItem(key)); + container.commit(); + Assert.assertEquals(size - 1, container.size()); + } + @Test public void rollback_tableItemAdded_discardsAddedItem() throws SQLException { SQLContainer container = new SQLContainer(new TableQuery("people", -- cgit v1.2.3 From bf4e325ac6387cac0afc8096b3ca65b88bf9fdfd Mon Sep 17 00:00:00 2001 From: Fabian Lange Date: Mon, 24 Nov 2014 12:11:08 +0100 Subject: UIInitHandler emits Content-Length when writing json response (#15271) This prevents chunked-transfer mode and allows server infrastructure to decide correctly on things like compression which benefits from knowing a content length. Change-Id: I4e969e0874b506d0f61526662ee78418987937c4 --- .../vaadin/server/communication/UIInitHandler.java | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) (limited to 'server/src') diff --git a/server/src/com/vaadin/server/communication/UIInitHandler.java b/server/src/com/vaadin/server/communication/UIInitHandler.java index 8e61370d85..1216d2b689 100644 --- a/server/src/com/vaadin/server/communication/UIInitHandler.java +++ b/server/src/com/vaadin/server/communication/UIInitHandler.java @@ -17,7 +17,7 @@ package com.vaadin.server.communication; import java.io.IOException; -import java.io.OutputStreamWriter; +import java.io.OutputStream; import java.io.StringWriter; import java.util.List; import java.util.logging.Level; @@ -110,18 +110,13 @@ public abstract class UIInitHandler extends SynchronizedRequestHandler { // iOS 6 Safari requires this (#9732) response.setHeader("Cache-Control", "no-cache"); - // NOTE! GateIn requires, for some weird reason, getOutputStream - // to be used instead of getWriter() (it seems to interpret - // application/json as a binary content type) - OutputStreamWriter outputWriter = new OutputStreamWriter( - response.getOutputStream(), "UTF-8"); - try { - outputWriter.write(json); - // NOTE GateIn requires the buffers to be flushed to work - outputWriter.flush(); - } finally { - outputWriter.close(); - } + byte[] b = json.getBytes("UTF-8"); + response.setHeader("Content-Length", String.valueOf(b.length)); + + OutputStream outputStream = response.getOutputStream(); + outputStream.write(b); + // NOTE GateIn requires the buffers to be flushed to work + outputStream.flush(); return true; } -- cgit v1.2.3 From a28d6c2098e738dfd78e1df929ce689a2ceb6c2a Mon Sep 17 00:00:00 2001 From: Anna Miroshnik Date: Thu, 4 Dec 2014 15:52:27 +0300 Subject: Add new StringTo Converters (#14583) DefaultConverterFactory was updated, added missed types. Change-Id: I65cffc7f91df6f40e132b45e325e15f029f9848c --- .../converter/AbstractStringToNumberConverter.java | 1 + .../util/converter/DefaultConverterFactory.java | 7 ++++++ .../converter/StringToBigIntegerConverter.java | 11 ++++++--- .../data/util/converter/StringToByteConverter.java | 2 +- .../util/converter/StringToShortConverter.java | 2 +- .../converter/TestStringToBigIntegerConverter.java | 28 ++++++++++++---------- .../data/converter/TestStringToByteConverter.java | 16 ++++++++----- .../data/converter/TestStringToShortConverter.java | 15 ++++++++---- 8 files changed, 54 insertions(+), 28 deletions(-) (limited to 'server/src') diff --git a/server/src/com/vaadin/data/util/converter/AbstractStringToNumberConverter.java b/server/src/com/vaadin/data/util/converter/AbstractStringToNumberConverter.java index 9054f258c7..81f1a85f89 100644 --- a/server/src/com/vaadin/data/util/converter/AbstractStringToNumberConverter.java +++ b/server/src/com/vaadin/data/util/converter/AbstractStringToNumberConverter.java @@ -88,6 +88,7 @@ public abstract class AbstractStringToNumberConverter implements // Convert "" to null return null; } + return parsedValue; } diff --git a/server/src/com/vaadin/data/util/converter/DefaultConverterFactory.java b/server/src/com/vaadin/data/util/converter/DefaultConverterFactory.java index 26613c5d02..3a1f1a4252 100644 --- a/server/src/com/vaadin/data/util/converter/DefaultConverterFactory.java +++ b/server/src/com/vaadin/data/util/converter/DefaultConverterFactory.java @@ -17,6 +17,7 @@ package com.vaadin.data.util.converter; import java.math.BigDecimal; +import java.math.BigInteger; import java.util.Date; import java.util.logging.Logger; @@ -112,6 +113,12 @@ public class DefaultConverterFactory implements ConverterFactory { return new StringToDateConverter(); } else if (Enum.class.isAssignableFrom(sourceType)) { return new StringToEnumConverter(); + } else if (BigInteger.class.isAssignableFrom(sourceType)) { + return new StringToBigIntegerConverter(); + } else if (Short.class.isAssignableFrom(sourceType)) { + return new StringToShortConverter(); + } else if (Byte.class.isAssignableFrom(sourceType)) { + return new StringToByteConverter(); } else { return null; } diff --git a/server/src/com/vaadin/data/util/converter/StringToBigIntegerConverter.java b/server/src/com/vaadin/data/util/converter/StringToBigIntegerConverter.java index 1e830c1fd2..d176ac2e0d 100644 --- a/server/src/com/vaadin/data/util/converter/StringToBigIntegerConverter.java +++ b/server/src/com/vaadin/data/util/converter/StringToBigIntegerConverter.java @@ -15,6 +15,7 @@ */ package com.vaadin.data.util.converter; +import java.math.BigDecimal; import java.math.BigInteger; import java.text.DecimalFormat; import java.text.NumberFormat; @@ -32,7 +33,7 @@ import java.util.Locale; *

* * @author Vaadin Ltd - * @since 7.3.1 + * @since */ public class StringToBigIntegerConverter extends AbstractStringToNumberConverter { @@ -41,7 +42,7 @@ public class StringToBigIntegerConverter extends protected NumberFormat getFormat(Locale locale) { NumberFormat numberFormat = super.getFormat(locale); if (numberFormat instanceof DecimalFormat) { - ((DecimalFormat) numberFormat).setParseIntegerOnly(true); + ((DecimalFormat) numberFormat).setParseBigDecimal(true); } return numberFormat; @@ -51,7 +52,11 @@ public class StringToBigIntegerConverter extends public BigInteger convertToModel(String value, Class targetType, Locale locale) throws com.vaadin.data.util.converter.Converter.ConversionException { - return (BigInteger) convertToNumber(value, BigInteger.class, locale); + + BigDecimal bigDecimalValue = (BigDecimal) convertToNumber(value, + BigDecimal.class, locale); + + return (bigDecimalValue != null) ? bigDecimalValue.toBigInteger() : null; } @Override diff --git a/server/src/com/vaadin/data/util/converter/StringToByteConverter.java b/server/src/com/vaadin/data/util/converter/StringToByteConverter.java index b14182dc3f..26f52d108a 100644 --- a/server/src/com/vaadin/data/util/converter/StringToByteConverter.java +++ b/server/src/com/vaadin/data/util/converter/StringToByteConverter.java @@ -28,7 +28,7 @@ import java.util.Locale; *

* * @author Vaadin Ltd - * @since 7.3.1 + * @since */ public class StringToByteConverter extends AbstractStringToNumberConverter { diff --git a/server/src/com/vaadin/data/util/converter/StringToShortConverter.java b/server/src/com/vaadin/data/util/converter/StringToShortConverter.java index 3761d11227..4ee085286f 100644 --- a/server/src/com/vaadin/data/util/converter/StringToShortConverter.java +++ b/server/src/com/vaadin/data/util/converter/StringToShortConverter.java @@ -28,7 +28,7 @@ import java.util.Locale; *

* * @author Vaadin Ltd - * @since 7.3.1 + * @since */ public class StringToShortConverter extends AbstractStringToNumberConverter { diff --git a/server/tests/src/com/vaadin/tests/data/converter/TestStringToBigIntegerConverter.java b/server/tests/src/com/vaadin/tests/data/converter/TestStringToBigIntegerConverter.java index 641f18c865..8d493609fe 100644 --- a/server/tests/src/com/vaadin/tests/data/converter/TestStringToBigIntegerConverter.java +++ b/server/tests/src/com/vaadin/tests/data/converter/TestStringToBigIntegerConverter.java @@ -15,39 +15,43 @@ */ package com.vaadin.tests.data.converter; -import java.math.BigDecimal; +import java.math.BigInteger; import java.util.Locale; import junit.framework.TestCase; -import com.vaadin.data.util.converter.StringToBigDecimalConverter; +import com.vaadin.data.util.converter.StringToBigIntegerConverter; public class TestStringToBigIntegerConverter extends TestCase { - StringToBigDecimalConverter converter = new StringToBigDecimalConverter(); + StringToBigIntegerConverter converter = new StringToBigIntegerConverter(); public void testNullConversion() { - assertEquals(null, - converter.convertToModel(null, BigDecimal.class, null)); + assertEquals("Null value was converted incorrectly", null, + converter.convertToModel(null, BigInteger.class, null)); } public void testEmptyStringConversion() { - assertEquals(null, converter.convertToModel("", BigDecimal.class, null)); + assertEquals("Empty value was converted incorrectly", null, + converter.convertToModel("", BigInteger.class, null)); } public void testValueParsing() { - BigDecimal converted = converter.convertToModel("10", BigDecimal.class, - null); - BigDecimal expected = new BigDecimal(10); - assertEquals(expected, converted); + String bigInt = "1180591620717411303424"; // 2^70 > 2^63 - 1 + BigInteger converted = converter.convertToModel(bigInt, + BigInteger.class, null); + BigInteger expected = new BigInteger(bigInt); + assertEquals("Value bigger than max long was converted incorrectly", + expected, converted); } public void testValueFormatting() { - BigDecimal bd = new BigDecimal(1000); + BigInteger bd = new BigInteger("1000"); String expected = "1.000"; String converted = converter.convertToPresentation(bd, String.class, Locale.GERMAN); - assertEquals(expected, converted); + assertEquals("Value with specific locale was converted incorrectly", + expected, converted); } } diff --git a/server/tests/src/com/vaadin/tests/data/converter/TestStringToByteConverter.java b/server/tests/src/com/vaadin/tests/data/converter/TestStringToByteConverter.java index 440d056c06..19a68fbfdb 100644 --- a/server/tests/src/com/vaadin/tests/data/converter/TestStringToByteConverter.java +++ b/server/tests/src/com/vaadin/tests/data/converter/TestStringToByteConverter.java @@ -16,25 +16,28 @@ public class TestStringToByteConverter extends TestCase { converter); public void testNullConversion() { - assertEquals(null, converter.convertToModel(null, Byte.class, null)); + assertEquals("Null value was converted incorrectly", null, + converter.convertToModel(null, Byte.class, null)); } public void testReverseNullConversion() { - assertEquals(null, + assertEquals("Null value reversely was converted incorrectly", null, reverseConverter.convertToModel(null, String.class, null)); } public void testEmptyStringConversion() { - assertEquals(null, converter.convertToModel("", Byte.class, null)); + assertEquals("Empty value was converted incorrectly", null, + converter.convertToModel("", Byte.class, null)); } public void testValueConversion() { - assertEquals(Byte.valueOf((byte) 10), + assertEquals("Byte value was converted incorrectly", + Byte.valueOf((byte) 10), converter.convertToModel("10", Byte.class, null)); } public void testReverseValueConversion() { - assertEquals( + assertEquals("Byte value reversely was converted incorrectly", reverseConverter.convertToModel((byte) 10, String.class, null), "10"); } @@ -43,7 +46,8 @@ public class TestStringToByteConverter extends TestCase { byte b = converter.convertToModel("127", Byte.class, null); Assert.assertEquals(Byte.MAX_VALUE, b); b = converter.convertToModel("-128", Byte.class, null); - assertEquals(Byte.MIN_VALUE, b); + assertEquals("Min byte value was converted incorrectly", + Byte.MIN_VALUE, b); } public void testValueOutOfRange() { diff --git a/server/tests/src/com/vaadin/tests/data/converter/TestStringToShortConverter.java b/server/tests/src/com/vaadin/tests/data/converter/TestStringToShortConverter.java index 35547d2570..542c580025 100644 --- a/server/tests/src/com/vaadin/tests/data/converter/TestStringToShortConverter.java +++ b/server/tests/src/com/vaadin/tests/data/converter/TestStringToShortConverter.java @@ -16,25 +16,29 @@ public class TestStringToShortConverter extends TestCase { converter); public void testNullConversion() { - assertEquals(null, converter.convertToModel(null, Short.class, null)); + assertEquals("Null value was converted incorrectly", null, + converter.convertToModel(null, Short.class, null)); } public void testReverseNullConversion() { - assertEquals(null, + assertEquals("Null value reversely was converted incorrectly", null, reverseConverter.convertToModel(null, String.class, null)); } public void testEmptyStringConversion() { - assertEquals(null, converter.convertToModel("", Short.class, null)); + assertEquals("Empty value was converted incorrectly", null, + converter.convertToModel("", Short.class, null)); } public void testValueConversion() { - assertEquals(Short.valueOf((short) 10), + assertEquals("Short value was converted incorrectly", + Short.valueOf((short) 10), converter.convertToModel("10", Short.class, null)); } public void testReverseValueConversion() { assertEquals( + "Short value reversely was converted incorrectly", reverseConverter.convertToModel((short) 10, String.class, null), "10"); } @@ -43,7 +47,8 @@ public class TestStringToShortConverter extends TestCase { short b = converter.convertToModel("32767", Short.class, null); Assert.assertEquals(Short.MAX_VALUE, b); b = converter.convertToModel("-32768", Short.class, null); - assertEquals(Short.MIN_VALUE, b); + assertEquals("Min short value was converted incorrectly", + Short.MIN_VALUE, b); } public void testValueOutOfRange() { -- cgit v1.2.3 From 7e8b23a73a5dd1bef54b8fc5ddc4d3c431c298af Mon Sep 17 00:00:00 2001 From: Anna Miroshnik Date: Mon, 8 Dec 2014 17:25:00 +0300 Subject: Hierarchy change markAsDirty to AbstractComponentContainer (#14227) Change-Id: I7a05ad72dfa3d16d85aa4d0cdd235572ec01e31a --- server/src/com/vaadin/ui/AbsoluteLayout.java | 2 - .../com/vaadin/ui/AbstractComponentContainer.java | 2 + server/src/com/vaadin/ui/AbstractSplitPanel.java | 2 - server/src/com/vaadin/ui/CssLayout.java | 4 -- server/src/com/vaadin/ui/CustomLayout.java | 4 +- server/src/com/vaadin/ui/GridLayout.java | 3 -- server/src/com/vaadin/ui/TabSheet.java | 11 +++-- .../ComponentAttachDetachListenerTest.java | 50 ++++++++++++++++++++++ .../tests/minitutorials/v7a2/WidgetContainer.java | 2 - 9 files changed, 59 insertions(+), 21 deletions(-) (limited to 'server/src') diff --git a/server/src/com/vaadin/ui/AbsoluteLayout.java b/server/src/com/vaadin/ui/AbsoluteLayout.java index afc73f5ecc..af47981db6 100644 --- a/server/src/com/vaadin/ui/AbsoluteLayout.java +++ b/server/src/com/vaadin/ui/AbsoluteLayout.java @@ -153,7 +153,6 @@ public class AbsoluteLayout extends AbstractLayout implements internalRemoveComponent(c); throw e; } - markAsDirty(); } /** @@ -197,7 +196,6 @@ public class AbsoluteLayout extends AbstractLayout implements public void removeComponent(Component c) { internalRemoveComponent(c); super.removeComponent(c); - markAsDirty(); } /** diff --git a/server/src/com/vaadin/ui/AbstractComponentContainer.java b/server/src/com/vaadin/ui/AbstractComponentContainer.java index e70b0fa0ce..1095331602 100644 --- a/server/src/com/vaadin/ui/AbstractComponentContainer.java +++ b/server/src/com/vaadin/ui/AbstractComponentContainer.java @@ -209,6 +209,7 @@ public abstract class AbstractComponentContainer extends AbstractComponent c.setParent(this); fireComponentAttachEvent(c); + markAsDirty(); } /** @@ -223,6 +224,7 @@ public abstract class AbstractComponentContainer extends AbstractComponent if (equals(c.getParent())) { c.setParent(null); fireComponentDetachEvent(c); + markAsDirty(); } } diff --git a/server/src/com/vaadin/ui/AbstractSplitPanel.java b/server/src/com/vaadin/ui/AbstractSplitPanel.java index e9b37f8cff..a78f192fa2 100644 --- a/server/src/com/vaadin/ui/AbstractSplitPanel.java +++ b/server/src/com/vaadin/ui/AbstractSplitPanel.java @@ -214,7 +214,6 @@ public abstract class AbstractSplitPanel extends AbstractComponentContainer { } else if (c == getSecondComponent()) { getState().secondChild = null; } - markAsDirty(); } /* @@ -256,7 +255,6 @@ public abstract class AbstractSplitPanel extends AbstractComponentContainer { } else if (oldComponent == getSecondComponent()) { setSecondComponent(newComponent); } - markAsDirty(); } /** diff --git a/server/src/com/vaadin/ui/CssLayout.java b/server/src/com/vaadin/ui/CssLayout.java index e7b63cc87a..350423576f 100644 --- a/server/src/com/vaadin/ui/CssLayout.java +++ b/server/src/com/vaadin/ui/CssLayout.java @@ -118,7 +118,6 @@ public class CssLayout extends AbstractLayout implements LayoutClickNotifier { components.add(c); try { super.addComponent(c); - markAsDirty(); } catch (IllegalArgumentException e) { components.remove(c); throw e; @@ -141,7 +140,6 @@ public class CssLayout extends AbstractLayout implements LayoutClickNotifier { components.addFirst(c); try { super.addComponent(c); - markAsDirty(); } catch (IllegalArgumentException e) { components.remove(c); throw e; @@ -170,7 +168,6 @@ public class CssLayout extends AbstractLayout implements LayoutClickNotifier { components.add(index, c); try { super.addComponent(c); - markAsDirty(); } catch (IllegalArgumentException e) { components.remove(c); throw e; @@ -187,7 +184,6 @@ public class CssLayout extends AbstractLayout implements LayoutClickNotifier { public void removeComponent(Component c) { components.remove(c); super.removeComponent(c); - markAsDirty(); } /** diff --git a/server/src/com/vaadin/ui/CustomLayout.java b/server/src/com/vaadin/ui/CustomLayout.java index f4fe7fa66c..a9c266b0b9 100644 --- a/server/src/com/vaadin/ui/CustomLayout.java +++ b/server/src/com/vaadin/ui/CustomLayout.java @@ -144,8 +144,8 @@ public class CustomLayout extends AbstractLayout implements LegacyComponent { } slots.put(location, c); getState().childLocations.put(c, location); - c.setParent(this); - fireComponentAttachEvent(c); + + super.addComponent(c); } /** diff --git a/server/src/com/vaadin/ui/GridLayout.java b/server/src/com/vaadin/ui/GridLayout.java index 0dd16a03e7..96854c5b1b 100644 --- a/server/src/com/vaadin/ui/GridLayout.java +++ b/server/src/com/vaadin/ui/GridLayout.java @@ -255,8 +255,6 @@ public class GridLayout extends AbstractLayout implements cursorY = row1; } } - - markAsDirty(); } /** @@ -390,7 +388,6 @@ public class GridLayout extends AbstractLayout implements getState().childData.remove(component); components.remove(component); - super.removeComponent(component); } diff --git a/server/src/com/vaadin/ui/TabSheet.java b/server/src/com/vaadin/ui/TabSheet.java index d3410464a2..88002104b1 100644 --- a/server/src/com/vaadin/ui/TabSheet.java +++ b/server/src/com/vaadin/ui/TabSheet.java @@ -195,7 +195,6 @@ public class TabSheet extends AbstractComponentContainer implements Focusable, if (component != null && components.contains(component)) { int componentIndex = components.indexOf(component); - super.removeComponent(component); keyMapper.remove(component); components.remove(component); @@ -232,7 +231,6 @@ public class TabSheet extends AbstractComponentContainer implements Focusable, fireSelectedTabChange(); } } - markAsDirty(); } } @@ -394,8 +392,9 @@ public class TabSheet extends AbstractComponentContainer implements Focusable, setSelected(tabComponent); fireSelectedTabChange(); } + super.addComponent(tabComponent); - markAsDirty(); + return tab; } } @@ -967,16 +966,16 @@ public class TabSheet extends AbstractComponentContainer implements Focusable, /** * Gets the icon alt text for the tab. - * + * * @since 7.2 */ public String getIconAlternateText(); /** * Sets the icon alt text for the tab. - * + * * @since 7.2 - * + * * @param iconAltText * the icon to set */ diff --git a/server/tests/src/com/vaadin/tests/server/components/ComponentAttachDetachListenerTest.java b/server/tests/src/com/vaadin/tests/server/components/ComponentAttachDetachListenerTest.java index df515795eb..d8b366ffbc 100644 --- a/server/tests/src/com/vaadin/tests/server/components/ComponentAttachDetachListenerTest.java +++ b/server/tests/src/com/vaadin/tests/server/components/ComponentAttachDetachListenerTest.java @@ -9,6 +9,7 @@ import com.vaadin.ui.AbsoluteLayout.ComponentPosition; import com.vaadin.ui.AbstractOrderedLayout; import com.vaadin.ui.Component; import com.vaadin.ui.CssLayout; +import com.vaadin.ui.CustomLayout; import com.vaadin.ui.GridLayout; import com.vaadin.ui.GridLayout.Area; import com.vaadin.ui.HasComponents; @@ -25,6 +26,7 @@ public class ComponentAttachDetachListenerTest extends TestCase { private GridLayout gridlayout; private AbsoluteLayout absolutelayout; private CssLayout csslayout; + private CustomLayout customlayout; // General variables private int attachCounter = 0; @@ -143,6 +145,10 @@ public class ComponentAttachDetachListenerTest extends TestCase { csslayout = new CssLayout(); csslayout.addComponentAttachListener(new MyAttachListener()); csslayout.addComponentDetachListener(new MyDetachListener()); + + customlayout = new CustomLayout("
"); + customlayout.addComponentAttachListener(new MyAttachListener()); + customlayout.addComponentDetachListener(new MyDetachListener()); } public void testOrderedLayoutAttachListener() { @@ -342,4 +348,48 @@ public class ComponentAttachDetachListenerTest extends TestCase { // The detached component should not be found in the container assertFalse(foundInContainer); } + + public void testCustomLayoutAttachListener() { + // Reset state variables + resetVariables(); + + // Add component -> Should trigger attach listener + Component comp = new Label(); + customlayout.addComponent(comp, "loc"); + + assertEquals("Attach counter should get incremented", 1, attachCounter); + + assertSame("The attached component should be the label", comp, + attachedComponent); + + assertSame("The attached target should be the layout", customlayout, + attachTarget); + + assertTrue("The attached component should be found in the container", + foundInContainer); + } + + public void testCustomLayoutDetachListener() { + // Add a component to detach + Component comp = new Label(); + customlayout.addComponent(comp); + + // Reset state variables (since they are set by the attach listener) + resetVariables(); + + // Detach the component -> triggers the detach listener + customlayout.removeComponent(comp); + + assertEquals("Detach counter should get incremented", 1, detachCounter); + + assertSame("The detached component should be the label", comp, + detachedComponent); + + assertSame("The detached target should be the layout", customlayout, + detachedTarget); + + assertFalse( + "The detached component should not be found in the container", + foundInContainer); + } } diff --git a/uitest/src/com/vaadin/tests/minitutorials/v7a2/WidgetContainer.java b/uitest/src/com/vaadin/tests/minitutorials/v7a2/WidgetContainer.java index 8c14ba8bd7..850fa1044f 100644 --- a/uitest/src/com/vaadin/tests/minitutorials/v7a2/WidgetContainer.java +++ b/uitest/src/com/vaadin/tests/minitutorials/v7a2/WidgetContainer.java @@ -15,14 +15,12 @@ public class WidgetContainer extends AbstractComponentContainer { public void addComponent(Component c) { children.add(c); super.addComponent(c); - markAsDirty(); } @Override public void removeComponent(Component c) { children.remove(c); super.removeComponent(c); - markAsDirty(); } @Override -- cgit v1.2.3 From 206055708b0a8e1c17a8c63d482a5e202d3ebf6d Mon Sep 17 00:00:00 2001 From: Teemu Pöntelin Date: Mon, 8 Dec 2014 23:21:08 +0200 Subject: Fix issues when using java.sql.Date as DateField range (#15342) Change-Id: I656cc0600f929239605e17ab9cf71dc1ba96582f --- server/src/com/vaadin/ui/DateField.java | 14 +++--- .../components/datefield/DateRangeWithSqlDate.java | 54 ++++++++++++++++++++++ .../datefield/DateRangeWithSqlDateTest.java | 51 ++++++++++++++++++++ 3 files changed, 113 insertions(+), 6 deletions(-) create mode 100644 uitest/src/com/vaadin/tests/components/datefield/DateRangeWithSqlDate.java create mode 100644 uitest/src/com/vaadin/tests/components/datefield/DateRangeWithSqlDateTest.java (limited to 'server/src') diff --git a/server/src/com/vaadin/ui/DateField.java b/server/src/com/vaadin/ui/DateField.java index 030bd5f6c2..d5700c4b65 100644 --- a/server/src/com/vaadin/ui/DateField.java +++ b/server/src/com/vaadin/ui/DateField.java @@ -316,10 +316,10 @@ public class DateField extends AbstractField implements throw new IllegalStateException( "startDate cannot be later than endDate"); } - getState().rangeStart = startDate; - // rangeStart = startDate; - // This has to be done to correct for the resolution - // updateRangeState(); + + // Create a defensive copy against issues when using java.sql.Date (and + // also against mutable Date). + getState().rangeStart = new Date(startDate.getTime()); updateRangeValidator(); } @@ -436,8 +436,10 @@ public class DateField extends AbstractField implements throw new IllegalStateException( "endDate cannot be earlier than startDate"); } - // rangeEnd = endDate; - getState().rangeEnd = endDate; + + // Create a defensive copy against issues when using java.sql.Date (and + // also against mutable Date). + getState().rangeEnd = new Date(endDate.getTime()); updateRangeValidator(); } diff --git a/uitest/src/com/vaadin/tests/components/datefield/DateRangeWithSqlDate.java b/uitest/src/com/vaadin/tests/components/datefield/DateRangeWithSqlDate.java new file mode 100644 index 0000000000..74d3e85892 --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/datefield/DateRangeWithSqlDate.java @@ -0,0 +1,54 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.tests.components.datefield; + +import com.vaadin.server.VaadinRequest; +import com.vaadin.tests.components.AbstractTestUI; +import com.vaadin.ui.DateField; +import com.vaadin.ui.InlineDateField; + +public class DateRangeWithSqlDate extends AbstractTestUI { + + // 2014-12-01 + private static final java.sql.Date startDate = new java.sql.Date( + 1417467822699L); + + // 2014-12-02 + private static final java.sql.Date endDate = new java.sql.Date( + 1417554763317L); + + @Override + protected void setup(VaadinRequest request) { + DateField df = new InlineDateField(); + df.setRangeStart(startDate); + df.setRangeEnd(endDate); + + df.setValue(startDate); + + addComponent(df); + } + + @Override + protected String getTestDescription() { + return "Test that java.sql.Date can be given to specify date range start and end dates."; + } + + @Override + protected Integer getTicketNumber() { + return 15342; + } + +} diff --git a/uitest/src/com/vaadin/tests/components/datefield/DateRangeWithSqlDateTest.java b/uitest/src/com/vaadin/tests/components/datefield/DateRangeWithSqlDateTest.java new file mode 100644 index 0000000000..2352011585 --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/datefield/DateRangeWithSqlDateTest.java @@ -0,0 +1,51 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.tests.components.datefield; + +import static org.junit.Assert.assertEquals; + +import java.util.List; + +import org.junit.Test; +import org.openqa.selenium.By; +import org.openqa.selenium.WebElement; + +import com.vaadin.tests.tb3.MultiBrowserTest; + +public class DateRangeWithSqlDateTest extends MultiBrowserTest { + + @Test + public void testDateRange() { + openTestURL(); + + // Get all cells of the inline datefield. + List cells = driver.findElements(By + .className("v-inline-datefield-calendarpanel-day")); + + // Verify the range is rendered correctly. + assertCell(cells.get(0), "30", true); + assertCell(cells.get(1), "1", false); + assertCell(cells.get(2), "2", false); + assertCell(cells.get(3), "3", true); + } + + private void assertCell(WebElement cell, String text, boolean outsideRange) { + assertEquals(text, cell.getText()); + assertEquals(outsideRange, + cell.getAttribute("class").contains("outside-range")); + } + +} -- cgit v1.2.3 From 153129d52d0167a4d54d7c133155eeec7d407a19 Mon Sep 17 00:00:00 2001 From: Alexey Fansky Date: Wed, 3 Dec 2014 17:07:43 -0800 Subject: Returning all validation errors in the exception cause when submitting a field group (#14742) Following the similar logic as in AbstractField when multiple validation errors occur. Catching all InvalidValueExceptions and putting them together wrapped into the exception. Change-Id: Ied08fd2155412539b28ef94bc74e6c989c62f709 --- .../src/com/vaadin/data/fieldgroup/FieldGroup.java | 86 ++++++++++++++++------ uitest/ivy.xml | 2 + .../tests/fieldgroup/MultipleValidationErrors.java | 72 ++++++++++++++++++ .../fieldgroup/MultipleValidationErrorsTest.java | 37 ++++++++++ .../PersonBeanWithValidationAnnotations.java | 31 ++++++++ 5 files changed, 205 insertions(+), 23 deletions(-) create mode 100644 uitest/src/com/vaadin/tests/fieldgroup/MultipleValidationErrors.java create mode 100644 uitest/src/com/vaadin/tests/fieldgroup/MultipleValidationErrorsTest.java create mode 100644 uitest/src/com/vaadin/tests/fieldgroup/PersonBeanWithValidationAnnotations.java (limited to 'server/src') diff --git a/server/src/com/vaadin/data/fieldgroup/FieldGroup.java b/server/src/com/vaadin/data/fieldgroup/FieldGroup.java index 5a4e877554..bcfa8395df 100644 --- a/server/src/com/vaadin/data/fieldgroup/FieldGroup.java +++ b/server/src/com/vaadin/data/fieldgroup/FieldGroup.java @@ -26,6 +26,7 @@ import java.util.List; import com.vaadin.data.Item; import com.vaadin.data.Property; +import com.vaadin.data.Validator; import com.vaadin.data.Validator.InvalidValueException; import com.vaadin.data.util.TransactionalPropertyWrapper; import com.vaadin.ui.AbstractField; @@ -452,6 +453,54 @@ public class FieldGroup implements Serializable { // Not using buffered mode, nothing to do return; } + + startTransactions(); + + try { + firePreCommitEvent(); + + List invalidValueExceptions = commitFields(); + + if(invalidValueExceptions.isEmpty()) { + firePostCommitEvent(); + commitTransactions(); + } else { + throwInvalidValueException(invalidValueExceptions); + } + } catch (Exception e) { + rollbackTransactions(); + + throw new CommitException("Commit failed", e); + } + + } + + private List commitFields() { + List invalidValueExceptions = new ArrayList(); + + for (Field f : fieldToPropertyId.keySet()) { + try { + f.commit(); + } catch (InvalidValueException e) { + invalidValueExceptions.add(e); + } + } + + return invalidValueExceptions; + } + + private void throwInvalidValueException(List invalidValueExceptions) { + if(invalidValueExceptions.size() == 1) { + throw invalidValueExceptions.get(0); + } else { + InvalidValueException[] causes = invalidValueExceptions.toArray( + new InvalidValueException[invalidValueExceptions.size()]); + + throw new InvalidValueException(null, causes); + } + } + + private void startTransactions() throws CommitException { for (Field f : fieldToPropertyId.keySet()) { Property.Transactional property = (Property.Transactional) f .getPropertyDataSource(); @@ -462,33 +511,24 @@ public class FieldGroup implements Serializable { } property.startTransaction(); } - try { - firePreCommitEvent(); - // Commit the field values to the properties - for (Field f : fieldToPropertyId.keySet()) { - f.commit(); - } - firePostCommitEvent(); + } - // Commit the properties - for (Field f : fieldToPropertyId.keySet()) { - ((Property.Transactional) f.getPropertyDataSource()) - .commit(); - } + private void commitTransactions() { + for (Field f : fieldToPropertyId.keySet()) { + ((Property.Transactional) f.getPropertyDataSource()) + .commit(); + } + } - } catch (Exception e) { - for (Field f : fieldToPropertyId.keySet()) { - try { - ((Property.Transactional) f.getPropertyDataSource()) - .rollback(); - } catch (Exception rollbackException) { - // FIXME: What to do ? - } + private void rollbackTransactions() { + for (Field f : fieldToPropertyId.keySet()) { + try { + ((Property.Transactional) f.getPropertyDataSource()) + .rollback(); + } catch (Exception rollbackException) { + // FIXME: What to do ? } - - throw new CommitException("Commit failed", e); } - } /** diff --git a/uitest/ivy.xml b/uitest/ivy.xml index 14c8bc6ce3..78171f9a9c 100644 --- a/uitest/ivy.xml +++ b/uitest/ivy.xml @@ -27,6 +27,8 @@ + diff --git a/uitest/src/com/vaadin/tests/fieldgroup/MultipleValidationErrors.java b/uitest/src/com/vaadin/tests/fieldgroup/MultipleValidationErrors.java new file mode 100644 index 0000000000..5110bf6dcf --- /dev/null +++ b/uitest/src/com/vaadin/tests/fieldgroup/MultipleValidationErrors.java @@ -0,0 +1,72 @@ +package com.vaadin.tests.fieldgroup; + +import com.vaadin.data.Validator; +import com.vaadin.data.fieldgroup.FieldGroup; +import com.vaadin.data.util.BeanItem; +import com.vaadin.data.validator.BeanValidator; +import com.vaadin.server.AbstractErrorMessage; +import com.vaadin.server.VaadinRequest; +import com.vaadin.tests.components.AbstractTestUI; +import com.vaadin.ui.Button; +import com.vaadin.ui.Label; +import com.vaadin.ui.TextField; +import org.apache.commons.lang.StringEscapeUtils; + +public class MultipleValidationErrors extends AbstractTestUI { + + public static final String FIRST_NAME_NOT_NULL_VALIDATION_MESSAGE = "first name is null"; + public static final String LAST_NAME_NOT_NULL_VALIDATION_MESSAGE = "last name is null"; + public static final String FIRST_NAME_NOT_EMPTY_VALIDATION_MESSAGE = "first name is empty"; + public static final String LAST_NAME_NOT_EMPTY_VALIDATION_MESSAGE = "last name is empty"; + + @Override + protected void setup(VaadinRequest request) { + BeanItem item = new BeanItem( + new PersonBeanWithValidationAnnotations()); + final FieldGroup fieldGroup = new FieldGroup(item); + + bindTextField(item, fieldGroup, "First Name", "firstName"); + bindTextField(item, fieldGroup, "Last Name", "lastName"); + + final Label validationErrors = new Label(); + validationErrors.setId("validationErrors"); + addComponent(validationErrors); + + addButton("Submit", new Button.ClickListener() { + @Override + public void buttonClick(Button.ClickEvent event) { + validationErrors.setValue(""); + try { + fieldGroup.commit(); + } catch (FieldGroup.CommitException e) { + if (e.getCause() != null && e.getCause() instanceof Validator.InvalidValueException) { + validationErrors.setValue(StringEscapeUtils.unescapeHtml( + AbstractErrorMessage.getErrorMessageForException(e.getCause()).getFormattedHtmlMessage())); + } + } + + + } + }); + } + + private void bindTextField(BeanItem item, FieldGroup fieldGroup, + String caption, String propertyId) { + TextField textfield = new TextField(caption, item.getItemProperty(propertyId)); + textfield.addValidator(new BeanValidator(PersonBeanWithValidationAnnotations.class, propertyId)); + + fieldGroup.bind(textfield, propertyId); + + addComponent(textfield); + } + + @Override + protected Integer getTicketNumber() { + return 14742; + } + + @Override + protected String getTestDescription() { + return "All validation errors should be included when committing a field group."; + } +} diff --git a/uitest/src/com/vaadin/tests/fieldgroup/MultipleValidationErrorsTest.java b/uitest/src/com/vaadin/tests/fieldgroup/MultipleValidationErrorsTest.java new file mode 100644 index 0000000000..175b650be6 --- /dev/null +++ b/uitest/src/com/vaadin/tests/fieldgroup/MultipleValidationErrorsTest.java @@ -0,0 +1,37 @@ +package com.vaadin.tests.fieldgroup; + +import com.vaadin.testbench.elements.ButtonElement; +import com.vaadin.testbench.elements.LabelElement; +import com.vaadin.testbench.elements.TextFieldElement; +import com.vaadin.tests.tb3.MultiBrowserTest; +import org.junit.Test; + +import static org.hamcrest.CoreMatchers.containsString; +import static org.hamcrest.MatcherAssert.assertThat; + +public class MultipleValidationErrorsTest extends MultiBrowserTest { + + private void commitTextFields() { + $(ButtonElement.class).caption("Submit").first().click(); + } + + private void clearTextField(String caption) { + TextFieldElement textField = $(TextFieldElement.class).caption(caption).first(); + textField.clear(); + } + + @Test + public void validationErrorsIncludeBothErrors() { + openTestURL(); + + clearTextField("First Name"); + clearTextField("Last Name"); + + commitTextFields(); + + String validationErrors = $(LabelElement.class).id("validationErrors").getText(); + + assertThat(validationErrors, containsString(MultipleValidationErrors.FIRST_NAME_NOT_EMPTY_VALIDATION_MESSAGE)); + assertThat(validationErrors, containsString(MultipleValidationErrors.LAST_NAME_NOT_EMPTY_VALIDATION_MESSAGE)); + } +} diff --git a/uitest/src/com/vaadin/tests/fieldgroup/PersonBeanWithValidationAnnotations.java b/uitest/src/com/vaadin/tests/fieldgroup/PersonBeanWithValidationAnnotations.java new file mode 100644 index 0000000000..5f81ee248b --- /dev/null +++ b/uitest/src/com/vaadin/tests/fieldgroup/PersonBeanWithValidationAnnotations.java @@ -0,0 +1,31 @@ +package com.vaadin.tests.fieldgroup; + +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; +import java.io.Serializable; + +public class PersonBeanWithValidationAnnotations implements Serializable { + @NotNull(message = MultipleValidationErrors.FIRST_NAME_NOT_NULL_VALIDATION_MESSAGE) + @Size(min = 1, message = MultipleValidationErrors.FIRST_NAME_NOT_EMPTY_VALIDATION_MESSAGE) + private String firstName; + + @NotNull(message = MultipleValidationErrors.LAST_NAME_NOT_NULL_VALIDATION_MESSAGE) + @Size(min = 1, message = MultipleValidationErrors.LAST_NAME_NOT_EMPTY_VALIDATION_MESSAGE) + private String lastName; + + public String getFirstName() { + return firstName; + } + + public void setFirstName(String firstName) { + this.firstName = firstName; + } + + public String getLastName() { + return lastName; + } + + public void setLastName(String lastName) { + this.lastName = lastName; + } +} \ No newline at end of file -- cgit v1.2.3 From 52fb8cd941caad7d9c6277d7b154498abb6b99e6 Mon Sep 17 00:00:00 2001 From: Artur Signell Date: Tue, 9 Dec 2014 21:18:50 +0200 Subject: Make addNestedContainerBean work with existing bean item container items (#15355) Change-Id: I04a91349fce452aa26c304413061440ad74465cc --- .../vaadin/data/util/AbstractBeanContainer.java | 2 +- .../vaadin/data/util/BeanItemContainerTest.java | 42 ++++++++++++++++++++++ 2 files changed, 43 insertions(+), 1 deletion(-) (limited to 'server/src') diff --git a/server/src/com/vaadin/data/util/AbstractBeanContainer.java b/server/src/com/vaadin/data/util/AbstractBeanContainer.java index 7d7d71c423..fad0934e53 100644 --- a/server/src/com/vaadin/data/util/AbstractBeanContainer.java +++ b/server/src/com/vaadin/data/util/AbstractBeanContainer.java @@ -880,7 +880,7 @@ public abstract class AbstractBeanContainer extends model.put(qualifiedPropertyId, pd); model.remove(propertyId); for (BeanItem item : itemIdToItem.values()) { - item.addItemProperty(propertyId, + item.addItemProperty(qualifiedPropertyId, pd.createProperty(item.getBean())); item.removeItemProperty(propertyId); } diff --git a/server/tests/src/com/vaadin/data/util/BeanItemContainerTest.java b/server/tests/src/com/vaadin/data/util/BeanItemContainerTest.java index 01c282e294..514bf70416 100644 --- a/server/tests/src/com/vaadin/data/util/BeanItemContainerTest.java +++ b/server/tests/src/com/vaadin/data/util/BeanItemContainerTest.java @@ -12,6 +12,7 @@ import org.junit.Assert; import com.vaadin.data.Container; import com.vaadin.data.Item; +import com.vaadin.data.util.NestedMethodPropertyTest.Address; /** * Test basic functionality of BeanItemContainer. @@ -740,4 +741,45 @@ public class BeanItemContainerTest extends AbstractBeanContainerTest { assertNull(container.getContainerProperty(john, "address.street") .getValue()); } + + public void testAddNestedContainerBeanBeforeData() { + BeanItemContainer container = new BeanItemContainer( + NestedMethodPropertyTest.Person.class); + + container.addNestedContainerBean("address"); + + assertTrue(container.getContainerPropertyIds().contains( + "address.street")); + + NestedMethodPropertyTest.Person john = new NestedMethodPropertyTest.Person( + "John", new Address("streetname", 12345)); + container.addBean(john); + + assertTrue(container.getItem(john).getItemPropertyIds() + .contains("address.street")); + assertEquals("streetname", + container.getItem(john).getItemProperty("address.street") + .getValue()); + + } + + public void testAddNestedContainerBeanAfterData() { + BeanItemContainer container = new BeanItemContainer( + NestedMethodPropertyTest.Person.class); + + NestedMethodPropertyTest.Person john = new NestedMethodPropertyTest.Person( + "John", new Address("streetname", 12345)); + container.addBean(john); + + container.addNestedContainerBean("address"); + + assertTrue(container.getContainerPropertyIds().contains( + "address.street")); + assertTrue(container.getItem(john).getItemPropertyIds() + .contains("address.street")); + assertEquals("streetname", + container.getItem(john).getItemProperty("address.street") + .getValue()); + + } } -- cgit v1.2.3 From f1f089772749a0eb4b031f1876b95bb684565473 Mon Sep 17 00:00:00 2001 From: Artur Signell Date: Tue, 2 Dec 2014 21:19:06 +0200 Subject: Make TextField.clear() use empty string to be consistent with constructor (#14755) Change-Id: Ic50ff305277e54f50353fc948b31a89a6b3e083f --- server/src/com/vaadin/ui/TextField.java | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) (limited to 'server/src') diff --git a/server/src/com/vaadin/ui/TextField.java b/server/src/com/vaadin/ui/TextField.java index fb1e4284a2..1fc10c6ced 100644 --- a/server/src/com/vaadin/ui/TextField.java +++ b/server/src/com/vaadin/ui/TextField.java @@ -43,7 +43,7 @@ public class TextField extends AbstractTextField { * Constructs an empty TextField with no caption. */ public TextField() { - setValue(""); + clear(); } /** @@ -99,4 +99,14 @@ public class TextField extends AbstractTextField { setCaption(caption); } + /* + * (non-Javadoc) + * + * @see com.vaadin.ui.AbstractField#clear() + */ + @Override + public void clear() { + setValue(""); + } + } -- cgit v1.2.3 From e1b335022ec359061e696cf2711327663267e704 Mon Sep 17 00:00:00 2001 From: Sergey Budkin Date: Tue, 25 Nov 2014 19:35:13 +0200 Subject: Long events aren't displayed properly when using Container (#15242) Rewrote event selection. Change-Id: I8f0dd1c5ec736ea14037619b1656a79b7e3532be --- .../calendar/ContainerEventProvider.java | 74 ++++++---------------- .../calendar/BeanItemContainerLongEventTest.java | 55 ++++++++++++++++ .../calendar/BeanItemContainerTestUI.java | 8 +++ 3 files changed, 81 insertions(+), 56 deletions(-) create mode 100644 uitest/src/com/vaadin/tests/components/calendar/BeanItemContainerLongEventTest.java (limited to 'server/src') diff --git a/server/src/com/vaadin/ui/components/calendar/ContainerEventProvider.java b/server/src/com/vaadin/ui/components/calendar/ContainerEventProvider.java index fcaabcc079..2f51b21f7c 100644 --- a/server/src/com/vaadin/ui/components/calendar/ContainerEventProvider.java +++ b/server/src/com/vaadin/ui/components/calendar/ContainerEventProvider.java @@ -249,71 +249,33 @@ public class ContainerEventProvider implements CalendarEditableEventProvider, @Override public List getEvents(Date startDate, Date endDate) { eventCache.clear(); - - int[] rangeIndexes = getFirstAndLastEventIndex(startDate, endDate); - for (int i = rangeIndexes[0]; i <= rangeIndexes[1] - && i < container.size(); i++) { - eventCache.add(getEvent(i)); - } - return Collections.unmodifiableList(eventCache); - } - - /** - * Get the first event for a date - * - * @param date - * The date to search for, NUll returns first event in container - * @return Returns an array where the first item is the start index and the - * second item is the end item - */ - private int[] getFirstAndLastEventIndex(Date start, Date end) { - int startIndex = 0; int size = container.size(); assert size >= 0; - int endIndex = size - 1; - if (start != null) { - /* - * Iterating from the start of the container, if range is in the end - * of the container then this will be slow TODO This could be - * improved by using some sort of divide and conquer algorithm - */ - while (startIndex < size) { - Object id = container.getIdByIndex(startIndex); - Item item = container.getItem(id); - Date d = (Date) item.getItemProperty(startDateProperty) + for (int i = 0; i < size; i++) { + Object id = container.getIdByIndex(i); + Item item = container.getItem(id); + boolean add = true; + if (startDate != null) { + Date eventEnd = (Date) item.getItemProperty(endDateProperty) .getValue(); - if (d.compareTo(start) >= 0) { - break; + if (eventEnd.compareTo(startDate) < 0) { + add = false; } - startIndex++; } - } - - if (end != null) { - /* - * Iterate from the start index until range ends - */ - endIndex = startIndex; - while (endIndex < size - 1) { - Object id = container.getIdByIndex(endIndex); - Item item = container.getItem(id); - Date d = (Date) item.getItemProperty(endDateProperty) - .getValue(); - if (d == null) { - // No end date present, use start date - d = (Date) item.getItemProperty(startDateProperty) - .getValue(); + if (add && endDate != null) { + Date eventStart = (Date) item + .getItemProperty(startDateProperty).getValue(); + if (eventStart.compareTo(endDate) >= 0) { + break; // because container is sorted, all further events + // will be even later } - if (d.compareTo(end) >= 0) { - endIndex--; - break; - } - endIndex++; + } + if (add) { + eventCache.add(getEvent(i)); } } - - return new int[] { startIndex, endIndex }; + return Collections.unmodifiableList(eventCache); } /* diff --git a/uitest/src/com/vaadin/tests/components/calendar/BeanItemContainerLongEventTest.java b/uitest/src/com/vaadin/tests/components/calendar/BeanItemContainerLongEventTest.java new file mode 100644 index 0000000000..0ec196f266 --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/calendar/BeanItemContainerLongEventTest.java @@ -0,0 +1,55 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.tests.components.calendar; + +import org.junit.Assert; +import org.junit.Test; +import org.openqa.selenium.WebElement; + +import com.vaadin.testbench.By; +import com.vaadin.tests.tb3.MultiBrowserTest; + +/** + * Tests if long event which began before the view period is shown (#15242) + */ +public class BeanItemContainerLongEventTest extends MultiBrowserTest { + + @Override + protected String getDeploymentPath() { + return "/run/BeanItemContainerTestUI?restartApplication"; + } + + @Test + public void testEventDisplayedInWeekView() { + openTestURL(); + WebElement target = driver.findElements( + By.className("v-calendar-week-number")).get(1); + target.click(); + target = driver.findElement(By.className("v-calendar-event")); + Assert.assertEquals("Wrong event name", "Long event", target.getText()); + } + + @Test + public void testEventDisplayedInDayView() { + openTestURL(); + WebElement target = driver.findElements( + By.className("v-calendar-day-number")).get(5); + target.click(); + target = driver.findElement(By.className("v-calendar-event")); + Assert.assertEquals("Wrong event name", "Long event", target.getText()); + } + +} diff --git a/uitest/src/com/vaadin/tests/components/calendar/BeanItemContainerTestUI.java b/uitest/src/com/vaadin/tests/components/calendar/BeanItemContainerTestUI.java index 83fc4a03cb..bda3b34875 100644 --- a/uitest/src/com/vaadin/tests/components/calendar/BeanItemContainerTestUI.java +++ b/uitest/src/com/vaadin/tests/components/calendar/BeanItemContainerTestUI.java @@ -17,6 +17,7 @@ package com.vaadin.tests.components.calendar; import java.util.Arrays; import java.util.Date; +import java.util.GregorianCalendar; import com.vaadin.data.fieldgroup.FieldGroup; import com.vaadin.data.fieldgroup.FieldGroup.CommitException; @@ -69,6 +70,13 @@ public class BeanItemContainerTestUI extends UI { table.setVisibleColumns(new Object[] { "caption", "description", "start", "end" }); content.addComponent(table); + + BasicEvent longEvent = new BasicEvent(); + longEvent.setCaption("Long event"); + longEvent.setAllDay(true); + longEvent.setStart(new GregorianCalendar(2000, 1, 3).getTime()); + longEvent.setEnd(new GregorianCalendar(2000, 2, 5).getTime()); + events.addBean(longEvent); } /** -- cgit v1.2.3 From 22b20bc9fc4067a026cf08b5130bd20afa89d27e Mon Sep 17 00:00:00 2001 From: Artur Signell Date: Tue, 9 Dec 2014 16:58:01 +0200 Subject: Add public Field.isEmpty() and clear() (#15354) Change-Id: I6bda7ff2a66a9ad172c899d855ca868881600be4 --- server/src/com/vaadin/ui/AbstractField.java | 19 +----- server/src/com/vaadin/ui/AbstractSelect.java | 2 +- server/src/com/vaadin/ui/AbstractTextField.java | 2 +- server/src/com/vaadin/ui/Field.java | 22 +++++++ server/src/com/vaadin/ui/Form.java | 9 ++- server/src/com/vaadin/ui/RichTextArea.java | 2 +- .../src/com/vaadin/ui/AbstractSelectTest.java | 71 ++++++++++++++++++++++ .../tests/src/com/vaadin/ui/RichTextAreaTest.java | 47 ++++++++++++++ server/tests/src/com/vaadin/ui/TextAreaTest.java | 47 ++++++++++++++ 9 files changed, 200 insertions(+), 21 deletions(-) create mode 100644 server/tests/src/com/vaadin/ui/RichTextAreaTest.java create mode 100644 server/tests/src/com/vaadin/ui/TextAreaTest.java (limited to 'server/src') diff --git a/server/src/com/vaadin/ui/AbstractField.java b/server/src/com/vaadin/ui/AbstractField.java index 369ad1253c..df7bbb68a2 100644 --- a/server/src/com/vaadin/ui/AbstractField.java +++ b/server/src/com/vaadin/ui/AbstractField.java @@ -1502,25 +1502,12 @@ public abstract class AbstractField extends AbstractComponent implements markAsDirty(); } - /** - * Is the field empty? - * - * In general, "empty" state is same as null. As an exception, TextField - * also treats empty string as "empty". - */ - protected boolean isEmpty() { + @Override + public boolean isEmpty() { return (getFieldValue() == null); } - /** - * Clear the value of the field. - *

- * The field value is typically reset to the initial value of the field but - * this is not mandatory. Calling {@link #isEmpty()} on a cleared field must - * always returns true. - * - * @since - */ + @Override public void clear() { setValue(null); } diff --git a/server/src/com/vaadin/ui/AbstractSelect.java b/server/src/com/vaadin/ui/AbstractSelect.java index 2c4dd5be5d..70f08c95d8 100644 --- a/server/src/com/vaadin/ui/AbstractSelect.java +++ b/server/src/com/vaadin/ui/AbstractSelect.java @@ -1782,7 +1782,7 @@ public abstract class AbstractSelect extends AbstractField implements * @see AbstractField#isEmpty(). */ @Override - protected boolean isEmpty() { + public boolean isEmpty() { if (!multiSelect) { return super.isEmpty(); } else { diff --git a/server/src/com/vaadin/ui/AbstractTextField.java b/server/src/com/vaadin/ui/AbstractTextField.java index 9293d38119..ea0372bc8c 100644 --- a/server/src/com/vaadin/ui/AbstractTextField.java +++ b/server/src/com/vaadin/ui/AbstractTextField.java @@ -317,7 +317,7 @@ public abstract class AbstractTextField extends AbstractField implements } @Override - protected boolean isEmpty() { + public boolean isEmpty() { return super.isEmpty() || getValue().length() == 0; } diff --git a/server/src/com/vaadin/ui/Field.java b/server/src/com/vaadin/ui/Field.java index f191e1bdd7..6dee4de6cb 100644 --- a/server/src/com/vaadin/ui/Field.java +++ b/server/src/com/vaadin/ui/Field.java @@ -113,4 +113,26 @@ public interface Field extends Component, BufferedValidatable, Property, return (Property) getSource(); } } + + /** + * Is the field empty? + * + * In general, "empty" state is same as null. As an exception, TextField + * also treats empty string as "empty". + * + * @since + * @return true if the field is empty, false otherwise + */ + public boolean isEmpty(); + + /** + * Clears the value of the field. + *

+ * The field value is typically reset to the initial value of the field. + * Calling {@link #isEmpty()} on a cleared field must always returns true. + * + * @since + */ + public void clear(); + } diff --git a/server/src/com/vaadin/ui/Form.java b/server/src/com/vaadin/ui/Form.java index 48239b09e3..45532756e5 100644 --- a/server/src/com/vaadin/ui/Form.java +++ b/server/src/com/vaadin/ui/Form.java @@ -1186,9 +1186,14 @@ public class Form extends AbstractField implements Item.Editor, } } - /** Form is empty if all of its fields are empty. */ + /** + * {@inheritDoc} + *

+ * A Form is empty if all of its fields are empty. + * + */ @Override - protected boolean isEmpty() { + public boolean isEmpty() { for (Iterator> i = fields.values().iterator(); i.hasNext();) { Field f = i.next(); diff --git a/server/src/com/vaadin/ui/RichTextArea.java b/server/src/com/vaadin/ui/RichTextArea.java index 9d05181541..31327b3a6f 100644 --- a/server/src/com/vaadin/ui/RichTextArea.java +++ b/server/src/com/vaadin/ui/RichTextArea.java @@ -285,7 +285,7 @@ public class RichTextArea extends AbstractField implements } @Override - protected boolean isEmpty() { + public boolean isEmpty() { return super.isEmpty() || getValue().length() == 0; } diff --git a/server/tests/src/com/vaadin/ui/AbstractSelectTest.java b/server/tests/src/com/vaadin/ui/AbstractSelectTest.java index 83d66ee9d5..bd399f088c 100644 --- a/server/tests/src/com/vaadin/ui/AbstractSelectTest.java +++ b/server/tests/src/com/vaadin/ui/AbstractSelectTest.java @@ -16,10 +16,13 @@ package com.vaadin.ui; import java.util.ArrayList; +import java.util.HashSet; import org.junit.Assert; import org.junit.Test; +import com.vaadin.data.util.ObjectProperty; + public class AbstractSelectTest { @Test @@ -73,4 +76,72 @@ public class AbstractSelectTest { .toArray()); } + + @Test + public void singleSelectInitiallyEmpty() { + AbstractSelect s = new ListSelect(); + Assert.assertTrue(s.isEmpty()); + } + + @Test + public void singleSelectEmptyAfterClearUsingPDS() { + AbstractSelect s = new ListSelect(); + s.addItem("foo"); + s.addItem("bar"); + s.setPropertyDataSource(new ObjectProperty("foo")); + + Assert.assertFalse(s.isEmpty()); + s.clear(); + Assert.assertTrue(s.isEmpty()); + } + + @Test + public void singleSelectEmptyAfterClear() { + AbstractSelect s = new ListSelect(); + s.addItem("foo"); + s.addItem("bar"); + s.setValue("bar"); + + Assert.assertFalse(s.isEmpty()); + s.clear(); + Assert.assertTrue(s.isEmpty()); + } + + @Test + public void multiSelectInitiallyEmpty() { + AbstractSelect s = new ListSelect(); + s.setMultiSelect(true); + Assert.assertTrue(s.isEmpty()); + } + + @Test + public void multiSelectEmptyAfterClearUsingPDS() { + AbstractSelect s = new ListSelect(); + s.setMultiSelect(true); + s.addItem("foo"); + s.addItem("bar"); + HashSet sel = new HashSet(); + sel.add("foo"); + sel.add("bar"); + s.setPropertyDataSource(new ObjectProperty(sel)); + + Assert.assertFalse(s.isEmpty()); + s.clear(); + Assert.assertTrue(s.isEmpty()); + } + + @Test + public void multiSelectEmptyAfterClear() { + AbstractSelect s = new ListSelect(); + s.setMultiSelect(true); + s.addItem("foo"); + s.addItem("bar"); + s.select("foo"); + s.select("bar"); + + Assert.assertFalse(s.isEmpty()); + s.clear(); + Assert.assertTrue(s.isEmpty()); + } + } diff --git a/server/tests/src/com/vaadin/ui/RichTextAreaTest.java b/server/tests/src/com/vaadin/ui/RichTextAreaTest.java new file mode 100644 index 0000000000..ce0dfdc696 --- /dev/null +++ b/server/tests/src/com/vaadin/ui/RichTextAreaTest.java @@ -0,0 +1,47 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.ui; + +import org.junit.Assert; +import org.junit.Test; + +import com.vaadin.data.util.ObjectProperty; + +public class RichTextAreaTest { + @Test + public void initiallyEmpty() { + RichTextArea tf = new RichTextArea(); + Assert.assertTrue(tf.isEmpty()); + } + + @Test + public void emptyAfterClearUsingPDS() { + RichTextArea tf = new RichTextArea(new ObjectProperty("foo")); + Assert.assertFalse(tf.isEmpty()); + tf.clear(); + Assert.assertTrue(tf.isEmpty()); + } + + @Test + public void emptyAfterClear() { + RichTextArea tf = new RichTextArea(); + tf.setValue("foobar"); + Assert.assertFalse(tf.isEmpty()); + tf.clear(); + Assert.assertTrue(tf.isEmpty()); + } + +} diff --git a/server/tests/src/com/vaadin/ui/TextAreaTest.java b/server/tests/src/com/vaadin/ui/TextAreaTest.java new file mode 100644 index 0000000000..e7e99c19e9 --- /dev/null +++ b/server/tests/src/com/vaadin/ui/TextAreaTest.java @@ -0,0 +1,47 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.ui; + +import org.junit.Assert; +import org.junit.Test; + +import com.vaadin.data.util.ObjectProperty; + +public class TextAreaTest { + @Test + public void initiallyEmpty() { + TextArea tf = new TextArea(); + Assert.assertTrue(tf.isEmpty()); + } + + @Test + public void emptyAfterClearUsingPDS() { + TextArea tf = new TextArea(new ObjectProperty("foo")); + Assert.assertFalse(tf.isEmpty()); + tf.clear(); + Assert.assertTrue(tf.isEmpty()); + } + + @Test + public void emptyAfterClear() { + TextArea tf = new TextArea(); + tf.setValue("foobar"); + Assert.assertFalse(tf.isEmpty()); + tf.clear(); + Assert.assertTrue(tf.isEmpty()); + } + +} -- cgit v1.2.3 From b91063f884108bfc69a617846d91263339b062fe Mon Sep 17 00:00:00 2001 From: Artur Signell Date: Tue, 9 Dec 2014 19:43:06 +0200 Subject: Clear all bound fields when nulling the field group data source (#12371) Change-Id: I48eb0e7851187fa6bbb9024730b2611a74501ad0 --- .../com/vaadin/data/fieldgroup/BeanFieldGroup.java | 9 +- .../src/com/vaadin/data/fieldgroup/FieldGroup.java | 19 ++-- .../component/fieldgroup/BeanFieldGroupTest.java | 12 +-- .../src/com/vaadin/tests/fieldgroup/BasicCrud.java | 110 +++++++++++++++++++++ .../com/vaadin/tests/fieldgroup/BasicCrudTest.java | 68 +++++++++++++ 5 files changed, 198 insertions(+), 20 deletions(-) create mode 100644 uitest/src/com/vaadin/tests/fieldgroup/BasicCrud.java create mode 100644 uitest/src/com/vaadin/tests/fieldgroup/BasicCrudTest.java (limited to 'server/src') diff --git a/server/src/com/vaadin/data/fieldgroup/BeanFieldGroup.java b/server/src/com/vaadin/data/fieldgroup/BeanFieldGroup.java index 1f3ee36d58..257a958f3a 100644 --- a/server/src/com/vaadin/data/fieldgroup/BeanFieldGroup.java +++ b/server/src/com/vaadin/data/fieldgroup/BeanFieldGroup.java @@ -125,12 +125,19 @@ public class BeanFieldGroup extends FieldGroup { * Helper method for setting the data source directly using a bean. This * method wraps the bean in a {@link BeanItem} and calls * {@link #setItemDataSource(Item)}. + *

+ * For null values, a null item is passed to + * {@link #setItemDataSource(Item)} to be properly clear fields. * * @param bean * The bean to use as data source. */ public void setItemDataSource(T bean) { - setItemDataSource(new BeanItem(bean, beanType)); + if (bean == null) { + setItemDataSource((Item) null); + } else { + setItemDataSource(new BeanItem(bean, beanType)); + } } @Override diff --git a/server/src/com/vaadin/data/fieldgroup/FieldGroup.java b/server/src/com/vaadin/data/fieldgroup/FieldGroup.java index bcfa8395df..c89b94ace9 100644 --- a/server/src/com/vaadin/data/fieldgroup/FieldGroup.java +++ b/server/src/com/vaadin/data/fieldgroup/FieldGroup.java @@ -26,7 +26,6 @@ import java.util.List; import com.vaadin.data.Item; import com.vaadin.data.Property; -import com.vaadin.data.Validator; import com.vaadin.data.Validator.InvalidValueException; import com.vaadin.data.util.TransactionalPropertyWrapper; import com.vaadin.ui.AbstractField; @@ -256,6 +255,9 @@ public class FieldGroup implements Serializable { fieldToPropertyId.put(field, propertyId); propertyIdToField.put(propertyId, field); if (itemDataSource == null) { + // Clear any possible existing binding to clear the field + field.setPropertyDataSource(null); + field.clear(); // Will be bound when data source is set return; } @@ -461,7 +463,7 @@ public class FieldGroup implements Serializable { List invalidValueExceptions = commitFields(); - if(invalidValueExceptions.isEmpty()) { + if (invalidValueExceptions.isEmpty()) { firePostCommitEvent(); commitTransactions(); } else { @@ -489,12 +491,14 @@ public class FieldGroup implements Serializable { return invalidValueExceptions; } - private void throwInvalidValueException(List invalidValueExceptions) { - if(invalidValueExceptions.size() == 1) { + private void throwInvalidValueException( + List invalidValueExceptions) { + if (invalidValueExceptions.size() == 1) { throw invalidValueExceptions.get(0); } else { - InvalidValueException[] causes = invalidValueExceptions.toArray( - new InvalidValueException[invalidValueExceptions.size()]); + InvalidValueException[] causes = invalidValueExceptions + .toArray(new InvalidValueException[invalidValueExceptions + .size()]); throw new InvalidValueException(null, causes); } @@ -515,8 +519,7 @@ public class FieldGroup implements Serializable { private void commitTransactions() { for (Field f : fieldToPropertyId.keySet()) { - ((Property.Transactional) f.getPropertyDataSource()) - .commit(); + ((Property.Transactional) f.getPropertyDataSource()).commit(); } } diff --git a/server/tests/src/com/vaadin/tests/server/component/fieldgroup/BeanFieldGroupTest.java b/server/tests/src/com/vaadin/tests/server/component/fieldgroup/BeanFieldGroupTest.java index 965fb49479..9c37b91ef5 100644 --- a/server/tests/src/com/vaadin/tests/server/component/fieldgroup/BeanFieldGroupTest.java +++ b/server/tests/src/com/vaadin/tests/server/component/fieldgroup/BeanFieldGroupTest.java @@ -2,8 +2,6 @@ package com.vaadin.tests.server.component.fieldgroup; import static org.junit.Assert.assertEquals; -import java.util.Collection; - import org.junit.Assert; import org.junit.Test; @@ -144,15 +142,7 @@ public class BeanFieldGroupTest { group.setItemDataSource((MyBean) null); BeanItem dataSource = group.getItemDataSource(); - Assert.assertNotNull("Data source is null for null bean", dataSource); - - Collection itemPropertyIds = dataSource.getItemPropertyIds(); - Assert.assertEquals("Unexpected number of properties", 3, - itemPropertyIds.size()); - for (Object id : itemPropertyIds) { - Assert.assertNull("Value for property " + id + " is not null", - dataSource.getItemProperty(id).getValue()); - } + Assert.assertNull("Data source is null for null bean", dataSource); } @Test diff --git a/uitest/src/com/vaadin/tests/fieldgroup/BasicCrud.java b/uitest/src/com/vaadin/tests/fieldgroup/BasicCrud.java new file mode 100644 index 0000000000..be0368f4ae --- /dev/null +++ b/uitest/src/com/vaadin/tests/fieldgroup/BasicCrud.java @@ -0,0 +1,110 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.tests.fieldgroup; + +import com.vaadin.annotations.Theme; +import com.vaadin.data.Property.ValueChangeEvent; +import com.vaadin.data.Property.ValueChangeListener; +import com.vaadin.data.fieldgroup.BeanFieldGroup; +import com.vaadin.data.fieldgroup.PropertyId; +import com.vaadin.server.VaadinRequest; +import com.vaadin.tests.util.Person; +import com.vaadin.tests.util.PersonContainer; +import com.vaadin.ui.HorizontalLayout; +import com.vaadin.ui.Table; +import com.vaadin.ui.TextField; +import com.vaadin.ui.UI; +import com.vaadin.ui.VerticalLayout; + +@Theme("valo") +public class BasicCrud extends UI { + + private Form form; + + @Override + protected void init(VaadinRequest request) { + VerticalLayout main = new VerticalLayout(); + main.setMargin(true); + main.setSpacing(true); + final Table t = new Table(); + // t.setSelectionMode(SelectionMode.SINGLE); + t.setSelectable(true); + + PersonContainer c = PersonContainer.createWithTestData(); + + c.addBean(new Person("first", "Last", "email", "phone", "street", + 12332, "Turku")); + c.addBean(new Person("Foo", "Bar", "me@some.where", "123", + "homestreet 12", 10000, "Glasgow")); + t.setContainerDataSource(c); + // t.removeColumn("address"); + // t.setColumnOrder("firstName", "lastName", "email", "phoneNumber", + // "address.streetAddress", "address.postalCode", "address.city"); + t.setVisibleColumns("firstName", "lastName", "email", "phoneNumber", + "address.streetAddress", "address.postalCode", "address.city"); + + // t.addSelectionChangeListener(new SelectionChangeListener() { + // @Override + // public void selectionChange(SelectionChangeEvent event) { + // form.edit((Person) t.getSelectedRow()); + // } + // }); + t.addValueChangeListener(new ValueChangeListener() { + + @Override + public void valueChange(ValueChangeEvent event) { + form.edit((Person) t.getValue()); + } + }); + + form = new Form(); + + t.setSizeFull(); + + main.setSizeFull(); + main.addComponent(t); + main.addComponent(form); + main.setExpandRatio(t, 1); + setContent(main); + } + + public static class Form extends HorizontalLayout { + private TextField firstName = new TextField("First name"); + private TextField lastName = new TextField("Last name"); + private TextField email = new TextField("E-mail"); + @PropertyId("address.streetAddress") + private TextField streetAddress = new TextField("Street address"); + @PropertyId("address.postalCode") + private TextField postalCode = new TextField("Postal code"); + + BeanFieldGroup fieldGroup = new BeanFieldGroup( + Person.class); + + public Form() { + setSpacing(true); + setId("form"); + fieldGroup.bindMemberFields(this); + + // Stupid integer binding + postalCode.setNullRepresentation(""); + addComponents(firstName, lastName, email, streetAddress, postalCode); + } + + public void edit(Person p) { + fieldGroup.setItemDataSource(p); + } + } +} diff --git a/uitest/src/com/vaadin/tests/fieldgroup/BasicCrudTest.java b/uitest/src/com/vaadin/tests/fieldgroup/BasicCrudTest.java new file mode 100644 index 0000000000..a41725dbc9 --- /dev/null +++ b/uitest/src/com/vaadin/tests/fieldgroup/BasicCrudTest.java @@ -0,0 +1,68 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.tests.fieldgroup; + +import java.util.List; + +import org.junit.Assert; +import org.junit.Test; + +import com.vaadin.testbench.elements.AbstractOrderedLayoutElement; +import com.vaadin.testbench.elements.TableElement; +import com.vaadin.testbench.elements.TextFieldElement; +import com.vaadin.tests.tb3.SingleBrowserTest; + +public class BasicCrudTest extends SingleBrowserTest { + + @Test + public void fieldsInitiallyEmpty() { + openTestURL(); + AbstractOrderedLayoutElement fieldsLayout = $( + AbstractOrderedLayoutElement.class).id("form"); + List textFields = fieldsLayout.$( + TextFieldElement.class).all(); + + for (TextFieldElement e : textFields) { + Assert.assertEquals("TextField should be empty", "", e.getValue()); + } + } + + @Test + public void fieldsClearedOnDeselect() { + openTestURL(); + AbstractOrderedLayoutElement fieldsLayout = $( + AbstractOrderedLayoutElement.class).id("form"); + + // Select row + $(TableElement.class).first().getCell(2, 2).click(); + + List textFields = fieldsLayout.$( + TextFieldElement.class).all(); + + for (TextFieldElement e : textFields) { + Assert.assertNotEquals("TextField should not be empty", "", + e.getValue()); + } + + // Deselect row + $(TableElement.class).first().getCell(2, 2).click(); + + for (TextFieldElement e : textFields) { + Assert.assertEquals("TextField should be empty", "", e.getValue()); + } + + } +} -- cgit v1.2.3 From c4e4f449464f22c11e33b92f8aa578db959e92b2 Mon Sep 17 00:00:00 2001 From: Artur Signell Date: Tue, 9 Dec 2014 22:16:50 +0200 Subject: Convert empty string to null Enum value, only throw ConversionExceptions (#14756) Change-Id: I027a245975db12e3661740bd233edd98e73994e9 --- .../data/util/converter/StringToEnumConverter.java | 20 +++++++++++--------- .../data/converter/TestStringToEnumConverter.java | 14 ++++++++++++++ .../tests/components/textfield/EnumTextField.java | 1 + .../components/textfield/EnumTextFieldTest.java | 7 ++++--- 4 files changed, 30 insertions(+), 12 deletions(-) (limited to 'server/src') diff --git a/server/src/com/vaadin/data/util/converter/StringToEnumConverter.java b/server/src/com/vaadin/data/util/converter/StringToEnumConverter.java index a1328d831c..29bf8fc400 100644 --- a/server/src/com/vaadin/data/util/converter/StringToEnumConverter.java +++ b/server/src/com/vaadin/data/util/converter/StringToEnumConverter.java @@ -34,7 +34,7 @@ public class StringToEnumConverter implements Converter { @Override public Enum convertToModel(String value, Class targetType, Locale locale) throws ConversionException { - if (value == null) { + if (value == null || value.trim().equals("")) { return null; } if (locale == null) { @@ -46,19 +46,21 @@ public class StringToEnumConverter implements Converter { String result = value.replace(" ", "_").toUpperCase(locale); try { return Enum.valueOf(targetType, result); - } catch (IllegalArgumentException ee) { + } catch (Exception ee) { // There was no match. Try to compare the available values to see if // the constant is using something else than all upper case - - EnumSet set = EnumSet.allOf(targetType); - for (Enum e : set) { - if (e.name().toUpperCase(locale).equals(result)) { - return e; + try { + EnumSet set = EnumSet.allOf(targetType); + for (Enum e : set) { + if (e.name().toUpperCase(locale).equals(result)) { + return e; + } } + } catch (Exception e) { } - // Fallback did not work either, re-throw original exception so user - // knows what went wrong + // Fallback did not work either, re-throw original exception so + // user knows what went wrong throw new ConversionException(ee); } } diff --git a/server/tests/src/com/vaadin/tests/data/converter/TestStringToEnumConverter.java b/server/tests/src/com/vaadin/tests/data/converter/TestStringToEnumConverter.java index 2b19395c08..5dc24ca43a 100644 --- a/server/tests/src/com/vaadin/tests/data/converter/TestStringToEnumConverter.java +++ b/server/tests/src/com/vaadin/tests/data/converter/TestStringToEnumConverter.java @@ -3,6 +3,7 @@ package com.vaadin.tests.data.converter; import junit.framework.TestCase; import com.vaadin.data.util.converter.Converter; +import com.vaadin.data.util.converter.Converter.ConversionException; import com.vaadin.data.util.converter.ReverseConverter; import com.vaadin.data.util.converter.StringToEnumConverter; @@ -16,6 +17,19 @@ public class TestStringToEnumConverter extends TestCase { Converter reverseConverter = new ReverseConverter( converter); + public void testEmptyStringConversion() { + assertEquals(null, converter.convertToModel("", Enum.class, null)); + } + + public void testInvalidEnumClassConversion() { + try { + converter.convertToModel("Foo", Enum.class, null); + fail("No exception thrown"); + } catch (ConversionException e) { + // OK + } + } + public void testNullConversion() { assertEquals(null, converter.convertToModel(null, Enum.class, null)); } diff --git a/uitest/src/com/vaadin/tests/components/textfield/EnumTextField.java b/uitest/src/com/vaadin/tests/components/textfield/EnumTextField.java index 67b3b84688..99e08ae32d 100644 --- a/uitest/src/com/vaadin/tests/components/textfield/EnumTextField.java +++ b/uitest/src/com/vaadin/tests/components/textfield/EnumTextField.java @@ -31,6 +31,7 @@ public class EnumTextField extends AbstractTestUIWithLog { @Override protected void setup(VaadinRequest request) { final TextField tf = new TextField(); + tf.setNullRepresentation(""); tf.addValueChangeListener(new ValueChangeListener() { @Override diff --git a/uitest/src/com/vaadin/tests/components/textfield/EnumTextFieldTest.java b/uitest/src/com/vaadin/tests/components/textfield/EnumTextFieldTest.java index 113acee3a2..fe26fb7aad 100644 --- a/uitest/src/com/vaadin/tests/components/textfield/EnumTextFieldTest.java +++ b/uitest/src/com/vaadin/tests/components/textfield/EnumTextFieldTest.java @@ -27,8 +27,7 @@ public class EnumTextFieldTest extends SingleBrowserTest { public void validValues() { openTestURL(); $(TextFieldElement.class).first().clear(); - $(TextFieldElement.class).first().sendKeys("Value"); - $(TextFieldElement.class).first().sendKeys(Keys.TAB); + $(TextFieldElement.class).first().sendKeys("Value", Keys.TAB); Assert.assertEquals("3. Value (valid)", getLogRow(0)); $(TextFieldElement.class).first().clear(); @@ -41,13 +40,15 @@ public class EnumTextFieldTest extends SingleBrowserTest { $(TextFieldElement.class).first().sendKeys(Keys.TAB); Assert.assertEquals("7. The last value (valid)", getLogRow(0)); + $(TextFieldElement.class).first().clear(); + Assert.assertEquals("8. null (valid)", getLogRow(0)); + } @Test public void invalidValue() { openTestURL(); $(TextFieldElement.class).first().clear(); - Assert.assertEquals("2. (INVALID)", getLogRow(0)); $(TextFieldElement.class).first().sendKeys("bar"); $(TextFieldElement.class).first().sendKeys(Keys.TAB); -- cgit v1.2.3 From 4e477009c14231b5ecbd6bd0d289ac88eace2391 Mon Sep 17 00:00:00 2001 From: Artur Signell Date: Wed, 10 Dec 2014 23:41:45 +0200 Subject: Validate input to FileResource constructor (#14253) Change-Id: I7789f2de4cb179dfff936498f58dd6f2e491689b --- server/src/com/vaadin/server/FileResource.java | 3 ++ .../com/vaadin/tests/server/FileResourceTest.java | 36 ++++++++++++++++++++++ 2 files changed, 39 insertions(+) create mode 100644 server/tests/src/com/vaadin/tests/server/FileResourceTest.java (limited to 'server/src') diff --git a/server/src/com/vaadin/server/FileResource.java b/server/src/com/vaadin/server/FileResource.java index de14e2f0f2..b32905f972 100644 --- a/server/src/com/vaadin/server/FileResource.java +++ b/server/src/com/vaadin/server/FileResource.java @@ -57,6 +57,9 @@ public class FileResource implements ConnectorResource { * the file that should be served. */ public FileResource(File sourceFile) { + if (sourceFile == null) { + throw new IllegalArgumentException("File cannot be null"); + } setSourceFile(sourceFile); } diff --git a/server/tests/src/com/vaadin/tests/server/FileResourceTest.java b/server/tests/src/com/vaadin/tests/server/FileResourceTest.java new file mode 100644 index 0000000000..4798fb9f05 --- /dev/null +++ b/server/tests/src/com/vaadin/tests/server/FileResourceTest.java @@ -0,0 +1,36 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.tests.server; + +import java.io.File; + +import org.junit.Test; + +import com.vaadin.server.FileResource; + +public class FileResourceTest { + + @Test(expected = IllegalArgumentException.class) + public void nullFile() { + new FileResource(null); + } + + @Test(expected = RuntimeException.class) + public void nonExistingFile() { + new FileResource(new File("nonexisting")).getStream(); + } + +} -- cgit v1.2.3 From 3bc4ff53736ed2a0c3e9e362be3e7de481d1d00f Mon Sep 17 00:00:00 2001 From: Ilya Ermakov Date: Wed, 3 Dec 2014 13:43:15 +0300 Subject: Make SQLContainer.removeAllItems() work properly with paging (#12882) With this patch removeAllItems() works properly when items need to be fetched from database. Change-Id: Ic008ae7c67610cbdde7d71fa071494508678ac8f --- .../vaadin/data/util/sqlcontainer/SQLContainer.java | 1 - .../sqlcontainer/SQLContainerTableQueryTest.java | 20 ++++++++++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) (limited to 'server/src') diff --git a/server/src/com/vaadin/data/util/sqlcontainer/SQLContainer.java b/server/src/com/vaadin/data/util/sqlcontainer/SQLContainer.java index 70b392ab80..c0c660c084 100644 --- a/server/src/com/vaadin/data/util/sqlcontainer/SQLContainer.java +++ b/server/src/com/vaadin/data/util/sqlcontainer/SQLContainer.java @@ -652,7 +652,6 @@ public class SQLContainer implements Container, Container.Filterable, if (cachedItems.isEmpty()) { getPage(); } - int size = size(); // this protects against infinite looping int counter = 0; int oldIndex; diff --git a/server/tests/src/com/vaadin/data/util/sqlcontainer/SQLContainerTableQueryTest.java b/server/tests/src/com/vaadin/data/util/sqlcontainer/SQLContainerTableQueryTest.java index 93a27352a5..fbae0ee159 100644 --- a/server/tests/src/com/vaadin/data/util/sqlcontainer/SQLContainerTableQueryTest.java +++ b/server/tests/src/com/vaadin/data/util/sqlcontainer/SQLContainerTableQueryTest.java @@ -1071,6 +1071,26 @@ public class SQLContainerTableQueryTest { Assert.assertEquals(0, container.size()); } + // Set timeout to ensure there is no infinite looping (#12882) + @Test(timeout = 1000) + public void removeAllItems_manyItems_commit_shouldSucceed() + throws SQLException { + SQLContainer container = new SQLContainer(new TableQuery("people", + connectionPool, SQLTestsConstants.sqlGen)); + final int itemNumber = (SQLContainer.CACHE_RATIO + 1) + * SQLContainer.DEFAULT_PAGE_LENGTH + 1; + container.removeAllItems(); + Assert.assertEquals(container.size(), 0); + for (int i = 0; i < itemNumber; ++i) { + container.addItem(); + } + container.commit(); + Assert.assertEquals(container.size(), itemNumber); + Assert.assertTrue(container.removeAllItems()); + container.commit(); + Assert.assertEquals(container.size(), 0); + } + @Test public void commit_tableAddedItem_shouldBeWrittenToDB() throws SQLException { TableQuery query = new TableQuery("people", connectionPool, -- cgit v1.2.3 From dfaaae821ebea039dae6923c7433673b719dd42d Mon Sep 17 00:00:00 2001 From: Artur Signell Date: Thu, 25 Sep 2014 10:27:51 +0300 Subject: Use converter for Select/Tree/ComboBox when using item id for caption (#11433) Change-Id: I10c47986b98e132e874b2882fbb2323409d67a25 --- .../data/util/converter/StringToEnumConverter.java | 62 +++++++++++++++---- server/src/com/vaadin/ui/AbstractSelect.java | 17 +++++- .../notification/NotificationsWaiAriaTest.java | 7 ++- .../vaadin/tests/components/select/EnumSelect.java | 69 ++++++++++++++++++++++ .../tests/components/select/EnumSelectTest.java | 61 +++++++++++++++++++ 5 files changed, 201 insertions(+), 15 deletions(-) create mode 100644 uitest/src/com/vaadin/tests/components/select/EnumSelect.java create mode 100644 uitest/src/com/vaadin/tests/components/select/EnumSelectTest.java (limited to 'server/src') diff --git a/server/src/com/vaadin/data/util/converter/StringToEnumConverter.java b/server/src/com/vaadin/data/util/converter/StringToEnumConverter.java index 29bf8fc400..e91dd2a303 100644 --- a/server/src/com/vaadin/data/util/converter/StringToEnumConverter.java +++ b/server/src/com/vaadin/data/util/converter/StringToEnumConverter.java @@ -37,6 +37,28 @@ public class StringToEnumConverter implements Converter { if (value == null || value.trim().equals("")) { return null; } + + return stringToEnum(value, targetType, locale); + } + + /** + * Converts the given string to the given enum type using the given locale + *

+ * Compatible with {@link #enumToString(Enum, Locale)} + * + * @param value + * The string value to convert + * @param enumType + * The type of enum to create + * @param locale + * The locale to use for conversion. If null, the JVM default + * locale will be used + * @return The enum which matches the given string + * @throws ConversionException + * if the conversion fails + */ + public static > T stringToEnum(String value, + Class enumType, Locale locale) throws ConversionException { if (locale == null) { locale = Locale.getDefault(); } @@ -45,13 +67,13 @@ public class StringToEnumConverter implements Converter { // Foo bar -> FOO_BAR String result = value.replace(" ", "_").toUpperCase(locale); try { - return Enum.valueOf(targetType, result); + return Enum.valueOf(enumType, result); } catch (Exception ee) { // There was no match. Try to compare the available values to see if // the constant is using something else than all upper case try { - EnumSet set = EnumSet.allOf(targetType); - for (Enum e : set) { + EnumSet set = EnumSet.allOf(enumType); + for (T e : set) { if (e.name().toUpperCase(locale).equals(result)) { return e; } @@ -65,13 +87,21 @@ public class StringToEnumConverter implements Converter { } } - @Override - public String convertToPresentation(Enum value, - Class targetType, Locale locale) - throws ConversionException { - if (value == null) { - return null; - } + /** + * Converts the given enum to a human readable string using the given locale + *

+ * Compatible with {@link #stringToEnum(String, Class, Locale)} + * + * @param value + * The enum value to convert + * @param locale + * The locale to use for conversion. If null, the JVM default + * locale will be used + * @return A human readable string based on the enum + * @throws ConversionException + * if the conversion fails + */ + public static String enumToString(Enum value, Locale locale) { if (locale == null) { locale = Locale.getDefault(); } @@ -82,10 +112,20 @@ public class StringToEnumConverter implements Converter { // _FOO -> _foo String result = enumString.substring(0, 1).toUpperCase(locale); result += enumString.substring(1).toLowerCase(locale).replace('_', ' '); - return result; } + @Override + public String convertToPresentation(Enum value, + Class targetType, Locale locale) + throws ConversionException { + if (value == null) { + return null; + } + + return enumToString(value, locale); + } + @Override public Class getModelType() { return Enum.class; diff --git a/server/src/com/vaadin/ui/AbstractSelect.java b/server/src/com/vaadin/ui/AbstractSelect.java index 70f08c95d8..1a3eeb88a3 100644 --- a/server/src/com/vaadin/ui/AbstractSelect.java +++ b/server/src/com/vaadin/ui/AbstractSelect.java @@ -33,6 +33,8 @@ import com.vaadin.data.Container; import com.vaadin.data.Item; import com.vaadin.data.Property; import com.vaadin.data.util.IndexedContainer; +import com.vaadin.data.util.converter.Converter; +import com.vaadin.data.util.converter.ConverterUtil; import com.vaadin.event.DataBoundTransferable; import com.vaadin.event.Transferable; import com.vaadin.event.dd.DragAndDropEvent; @@ -1181,7 +1183,7 @@ public abstract class AbstractSelect extends AbstractField implements switch (getItemCaptionMode()) { case ID: - caption = itemId.toString(); + caption = idToCaption(itemId); break; case INDEX: @@ -1207,7 +1209,7 @@ public abstract class AbstractSelect extends AbstractField implements case EXPLICIT_DEFAULTS_ID: caption = itemCaptions.get(itemId); if (caption == null) { - caption = itemId.toString(); + caption = idToCaption(itemId); } break; @@ -1227,6 +1229,17 @@ public abstract class AbstractSelect extends AbstractField implements return caption != null ? caption : ""; } + private String idToCaption(Object itemId) { + try { + Converter c = (Converter) ConverterUtil + .getConverter(String.class, itemId.getClass(), getSession()); + return ConverterUtil.convertFromModel(itemId, String.class, c, + getLocale()); + } catch (Exception e) { + return itemId.toString(); + } + } + /** * Sets tqhe icon for an item. * diff --git a/uitest/src/com/vaadin/tests/components/notification/NotificationsWaiAriaTest.java b/uitest/src/com/vaadin/tests/components/notification/NotificationsWaiAriaTest.java index 6b517e9887..252efe2824 100644 --- a/uitest/src/com/vaadin/tests/components/notification/NotificationsWaiAriaTest.java +++ b/uitest/src/com/vaadin/tests/components/notification/NotificationsWaiAriaTest.java @@ -19,6 +19,7 @@ import org.junit.Assert; import org.junit.Test; import org.openqa.selenium.WebElement; +import com.vaadin.data.util.converter.StringToEnumConverter; import com.vaadin.shared.ui.ui.NotificationRole; import com.vaadin.testbench.By; import com.vaadin.testbench.elements.ButtonElement; @@ -57,7 +58,8 @@ public class NotificationsWaiAriaTest extends MultiBrowserTest { postfix.clear(); postfix.sendKeys("- press ESC to close"); - type.selectByText(NotificationRole.ALERT.toString()); + type.selectByText(StringToEnumConverter.enumToString( + NotificationRole.ALERT, null)); show.click(); waitForElementPresent(By.className("v-Notification")); @@ -83,7 +85,8 @@ public class NotificationsWaiAriaTest extends MultiBrowserTest { } catch (Exception e) { } - type.selectByText("STATUS"); + type.selectByText(StringToEnumConverter.enumToString( + NotificationRole.STATUS, null)); show.click(); waitForElementPresent(By.className("v-Notification")); diff --git a/uitest/src/com/vaadin/tests/components/select/EnumSelect.java b/uitest/src/com/vaadin/tests/components/select/EnumSelect.java new file mode 100644 index 0000000000..5976952f8c --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/select/EnumSelect.java @@ -0,0 +1,69 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.tests.components.select; + +import java.util.Locale; + +import com.vaadin.server.VaadinRequest; +import com.vaadin.shared.ui.combobox.FilteringMode; +import com.vaadin.tests.components.AbstractTestUIWithLog; +import com.vaadin.ui.ComboBox; +import com.vaadin.ui.NativeSelect; +import com.vaadin.ui.Tree; + +public class EnumSelect extends AbstractTestUIWithLog { + + public enum Constant { + SOME_VALUE, SOME_OTHER_VALUE, FOO, BAR; + } + + @Override + protected void setup(VaadinRequest request) { + + setLocale(new Locale("fi", "FI")); + ComboBox cb = new ComboBox(); + cb.setFilteringMode(FilteringMode.CONTAINS); + for (Constant c : Constant.values()) { + cb.addItem(c); + } + addComponent(cb); + + NativeSelect ns = new NativeSelect(); + for (Constant c : Constant.values()) { + ns.addItem(c); + } + addComponent(ns); + + Tree t = new Tree(); + t.addItem(Constant.SOME_OTHER_VALUE); + t.addItem(2500.12); + t.setParent(2500.12, Constant.SOME_OTHER_VALUE); + + addComponent(t); + + } + + @Override + protected String getTestDescription() { + return "Test formatting captions with enum converters in selection components"; + } + + @Override + protected Integer getTicketNumber() { + return 11433; + } + +} diff --git a/uitest/src/com/vaadin/tests/components/select/EnumSelectTest.java b/uitest/src/com/vaadin/tests/components/select/EnumSelectTest.java new file mode 100644 index 0000000000..c0429baa31 --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/select/EnumSelectTest.java @@ -0,0 +1,61 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.tests.components.select; + +import java.util.List; + +import org.junit.Assert; +import org.junit.Test; + +import com.vaadin.testbench.By; +import com.vaadin.testbench.TestBenchElement; +import com.vaadin.testbench.elements.ComboBoxElement; +import com.vaadin.testbench.elements.NativeSelectElement; +import com.vaadin.tests.tb3.SingleBrowserTest; + +public class EnumSelectTest extends SingleBrowserTest { + + @Test + public void enumInNativeSelect() { + openTestURL(); + NativeSelectElement ns = $(NativeSelectElement.class).first(); + List options = ns.getOptions(); + Assert.assertEquals("Some value", options.get(1).getText()); + Assert.assertEquals("Some other value", options.get(2).getText()); + } + + @Test + public void enumInComboBox() { + openTestURL(); + ComboBoxElement cb = $(ComboBoxElement.class).first(); + cb.openPopup(); + List options = cb.getPopupSuggestions(); + Assert.assertEquals("Some value", options.get(1)); + Assert.assertEquals("Some other value", options.get(2)); + } + + @Test + public void enumInComboBoxFiltering() { + openTestURL(); + ComboBoxElement cb = $(ComboBoxElement.class).first(); + cb.findElement(By.vaadin("#textbox")).sendKeys(" other "); + List options = cb.getPopupSuggestions(); + Assert.assertEquals("Only one item should match filter", 1, + options.size()); + Assert.assertEquals("Invalid option matched filter", + "Some other value", options.get(0)); + } +} -- cgit v1.2.3 From eaa5328054cf197e4c8192dd6c2e2fca37f1589d Mon Sep 17 00:00:00 2001 From: Leif Åstrand Date: Mon, 10 Nov 2014 20:26:02 +0200 Subject: Use ComboBox locale for filtering case tranform (#15193) Change-Id: Id462c3e76c8d761c04851227c949a3124ddf14b3 --- server/src/com/vaadin/ui/ComboBox.java | 4 +- .../combobox/FilteringTurkishLocale.java | 57 +++++++++++++++ .../combobox/FilteringTurkishLocaleTest.java | 80 ++++++++++++++++++++++ 3 files changed, 139 insertions(+), 2 deletions(-) create mode 100644 uitest/src/com/vaadin/tests/components/combobox/FilteringTurkishLocale.java create mode 100644 uitest/src/com/vaadin/tests/components/combobox/FilteringTurkishLocaleTest.java (limited to 'server/src') diff --git a/server/src/com/vaadin/ui/ComboBox.java b/server/src/com/vaadin/ui/ComboBox.java index c2b80fae35..4af93113f9 100644 --- a/server/src/com/vaadin/ui/ComboBox.java +++ b/server/src/com/vaadin/ui/ComboBox.java @@ -622,7 +622,7 @@ public class ComboBox extends AbstractSelect implements if (caption == null || caption.equals("")) { continue; } else { - caption = caption.toLowerCase(); + caption = caption.toLowerCase(getLocale()); } switch (filteringMode) { case CONTAINS: @@ -682,7 +682,7 @@ public class ComboBox extends AbstractSelect implements currentPage = ((Integer) variables.get("page")).intValue(); filterstring = newFilter; if (filterstring != null) { - filterstring = filterstring.toLowerCase(); + filterstring = filterstring.toLowerCase(getLocale()); } requestRepaint(); } else if (isNewItemsAllowed()) { diff --git a/uitest/src/com/vaadin/tests/components/combobox/FilteringTurkishLocale.java b/uitest/src/com/vaadin/tests/components/combobox/FilteringTurkishLocale.java new file mode 100644 index 0000000000..ff7faf1965 --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/combobox/FilteringTurkishLocale.java @@ -0,0 +1,57 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.tests.components.combobox; + +import java.util.Arrays; +import java.util.Locale; + +import com.vaadin.data.Property.ValueChangeEvent; +import com.vaadin.data.Property.ValueChangeListener; +import com.vaadin.server.VaadinRequest; +import com.vaadin.tests.components.AbstractTestUI; +import com.vaadin.ui.ComboBox; +import com.vaadin.ui.NativeSelect; + +public class FilteringTurkishLocale extends AbstractTestUI { + + @Override + protected void setup(VaadinRequest request) { + + final ComboBox comboBox = new ComboBox("Box", Arrays.asList( + "I without dot", "İ with dot")); + comboBox.setNullSelectionAllowed(false); + + NativeSelect localeSelect = new NativeSelect("Locale", Arrays.asList( + Locale.ENGLISH, new Locale("tr"))); + localeSelect.addValueChangeListener(new ValueChangeListener() { + @Override + public void valueChange(ValueChangeEvent event) { + comboBox.setLocale((Locale) event.getProperty().getValue()); + } + }); + localeSelect.setValue(Locale.ENGLISH); + + addComponents(localeSelect, comboBox); + } + + @Override + public String getDescription() { + return "When the Turkish locale is used," + + " filtering for 'i' should show the option with a dot" + + " while filtering for 'ı' should show the option witout a dot"; + } + +} diff --git a/uitest/src/com/vaadin/tests/components/combobox/FilteringTurkishLocaleTest.java b/uitest/src/com/vaadin/tests/components/combobox/FilteringTurkishLocaleTest.java new file mode 100644 index 0000000000..d7f8e233ec --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/combobox/FilteringTurkishLocaleTest.java @@ -0,0 +1,80 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.tests.components.combobox; + +import java.util.List; + +import org.junit.Assert; +import org.junit.Test; + +import com.vaadin.testbench.By; +import com.vaadin.testbench.elements.ComboBoxElement; +import com.vaadin.testbench.elements.NativeSelectElement; +import com.vaadin.tests.tb3.MultiBrowserTest; + +public class FilteringTurkishLocaleTest extends MultiBrowserTest { + + @Test + public void testEnglishLocale() { + openTestURL(); + + setLocale("en"); + + List suggestions = getFilterSuggestions("i"); + + Assert.assertEquals("Both suggestions should be present", 2, + suggestions.size()); + } + + @Test + public void testTurkishLocaleWithDot() { + openTestURL(); + + setLocale("tr"); + + List suggestions = getFilterSuggestions("i"); + + Assert.assertEquals("There should be only one suggestion", 1, + suggestions.size()); + Assert.assertEquals("İ with dot", suggestions.get(0)); + } + + @Test + public void testTurkishLocaleWithoutDot() { + openTestURL(); + + setLocale("tr"); + + List suggestions = getFilterSuggestions("ı"); + + Assert.assertEquals("There should be only one suggestion", 1, + suggestions.size()); + Assert.assertEquals("I without dot", suggestions.get(0)); + } + + private List getFilterSuggestions(String string) { + ComboBoxElement comboBox = $(ComboBoxElement.class).first(); + comboBox.findElement(By.vaadin("#textbox")).sendKeys(string); + + return comboBox.getPopupSuggestions(); + } + + private void setLocale(String locale) { + NativeSelectElement selector = $(NativeSelectElement.class).first(); + selector.selectByText(locale); + } + +} -- cgit v1.2.3 From e61ddefe447cc024f0c05144dae73c1cbd3a9b59 Mon Sep 17 00:00:00 2001 From: Sauli Tähkäpää Date: Sun, 14 Dec 2014 22:34:28 +0200 Subject: Throw IllegalArgumentException on non-existent version column. (#15290) Change-Id: I68fdea1144253feba906acd882b573d469f39a30 --- .../query/generator/DefaultSQLGenerator.java | 6 + .../sqlcontainer/SQLContainerTableQueryTest.java | 158 ++++++++++++--------- 2 files changed, 98 insertions(+), 66 deletions(-) (limited to 'server/src') diff --git a/server/src/com/vaadin/data/util/sqlcontainer/query/generator/DefaultSQLGenerator.java b/server/src/com/vaadin/data/util/sqlcontainer/query/generator/DefaultSQLGenerator.java index 84dfe9b865..21a486a017 100644 --- a/server/src/com/vaadin/data/util/sqlcontainer/query/generator/DefaultSQLGenerator.java +++ b/server/src/com/vaadin/data/util/sqlcontainer/query/generator/DefaultSQLGenerator.java @@ -262,6 +262,12 @@ public class DefaultSQLGenerator implements SQLGenerator { count++; } if (versionColumn != null) { + if(!item.getItemPropertyIds().contains(versionColumn)) { + throw new IllegalArgumentException(String.format( + "Table '%s' does not contain version column '%s'.", + tableName, versionColumn)); + } + query.append(String.format(" AND %s = ?", QueryBuilder.quote(versionColumn))); sh.addParameterValue( diff --git a/server/tests/src/com/vaadin/data/util/sqlcontainer/SQLContainerTableQueryTest.java b/server/tests/src/com/vaadin/data/util/sqlcontainer/SQLContainerTableQueryTest.java index fbae0ee159..f82ba49c3e 100644 --- a/server/tests/src/com/vaadin/data/util/sqlcontainer/SQLContainerTableQueryTest.java +++ b/server/tests/src/com/vaadin/data/util/sqlcontainer/SQLContainerTableQueryTest.java @@ -24,11 +24,15 @@ import com.vaadin.data.util.sqlcontainer.connection.SimpleJDBCConnectionPool; import com.vaadin.data.util.sqlcontainer.query.OrderBy; import com.vaadin.data.util.sqlcontainer.query.TableQuery; +import static org.junit.Assert.assertTrue; + public class SQLContainerTableQueryTest { private static final int offset = SQLTestsConstants.offset; private static final String createGarbage = SQLTestsConstants.createGarbage; private JDBCConnectionPool connectionPool; + private TableQuery peopleQuery; + private SQLContainer peopleContainer; @Before public void setUp() throws SQLException { @@ -43,6 +47,10 @@ public class SQLContainerTableQueryTest { } DataGenerator.addPeopleToDatabase(connectionPool); + + peopleQuery = new TableQuery("people", connectionPool, + SQLTestsConstants.sqlGen); + peopleContainer = new SQLContainer(peopleQuery); } @After @@ -52,6 +60,24 @@ public class SQLContainerTableQueryTest { } } + @Test + public void itemWithExistingVersionColumnIsRemoved() + throws SQLException { + peopleContainer.setAutoCommit(true); + peopleQuery.setVersionColumn("ID"); + + assertTrue(peopleContainer.removeItem(peopleContainer.lastItemId())); + } + + @Test(expected = IllegalArgumentException.class) + public void itemWithNonExistingVersionColumnCannotBeRemoved() throws SQLException { + peopleQuery.setVersionColumn("version"); + + peopleContainer.removeItem(peopleContainer.lastItemId()); + + peopleContainer.commit(); + } + @Test public void constructor_withTableQuery_shouldSucceed() throws SQLException { new SQLContainer(new TableQuery("people", connectionPool, @@ -63,8 +89,8 @@ public class SQLContainerTableQueryTest { throws SQLException { SQLContainer container = new SQLContainer(new TableQuery("people", connectionPool, SQLTestsConstants.sqlGen)); - Assert.assertTrue(container.containsId(new RowId( - new Object[] { 1 + offset }))); + assertTrue(container.containsId(new RowId( + new Object[]{1 + offset}))); } @Test @@ -410,11 +436,11 @@ public class SQLContainerTableQueryTest { SQLContainer container = new SQLContainer(new TableQuery("people", connectionPool, SQLTestsConstants.sqlGen)); if (SQLTestsConstants.db == DB.ORACLE) { - Assert.assertTrue(container.isFirstId(new RowId( - new Object[] { new BigDecimal(0 + offset) }))); + assertTrue(container.isFirstId(new RowId( + new Object[]{new BigDecimal(0 + offset)}))); } else { - Assert.assertTrue(container.isFirstId(new RowId( - new Object[] { 0 + offset }))); + assertTrue(container.isFirstId(new RowId( + new Object[]{0 + offset}))); } } @@ -449,11 +475,11 @@ public class SQLContainerTableQueryTest { SQLContainer container = new SQLContainer(new TableQuery("people", connectionPool, SQLTestsConstants.sqlGen)); if (SQLTestsConstants.db == DB.ORACLE) { - Assert.assertTrue(container.isLastId(new RowId( - new Object[] { new BigDecimal(3 + offset) }))); + assertTrue(container.isLastId(new RowId( + new Object[]{new BigDecimal(3 + offset)}))); } else { - Assert.assertTrue(container.isLastId(new RowId( - new Object[] { 3 + offset }))); + assertTrue(container.isLastId(new RowId( + new Object[]{3 + offset}))); } } @@ -463,11 +489,11 @@ public class SQLContainerTableQueryTest { SQLContainer container = new SQLContainer(new TableQuery("people", connectionPool, SQLTestsConstants.sqlGen)); if (SQLTestsConstants.db == DB.ORACLE) { - Assert.assertTrue(container.isLastId(new RowId( - new Object[] { new BigDecimal(4999 + offset) }))); + assertTrue(container.isLastId(new RowId( + new Object[]{new BigDecimal(4999 + offset)}))); } else { - Assert.assertTrue(container.isLastId(new RowId( - new Object[] { 4999 + offset }))); + assertTrue(container.isLastId(new RowId( + new Object[]{4999 + offset}))); } } @@ -478,7 +504,7 @@ public class SQLContainerTableQueryTest { SQLContainer container = new SQLContainer(new TableQuery("people", connectionPool, SQLTestsConstants.sqlGen)); for (int i = 0; i < 5000; i++) { - Assert.assertTrue(container.containsId(container.getIdByIndex(i))); + assertTrue(container.containsId(container.getIdByIndex(i))); } } @@ -490,7 +516,7 @@ public class SQLContainerTableQueryTest { connectionPool, SQLTestsConstants.sqlGen)); container.setAutoCommit(true); for (int i = 0; i < 5000; i++) { - Assert.assertTrue(container.containsId(container.getIdByIndex(i))); + assertTrue(container.containsId(container.getIdByIndex(i))); } } @@ -523,7 +549,7 @@ public class SQLContainerTableQueryTest { SQLContainer container = new SQLContainer(new TableQuery("people", connectionPool, SQLTestsConstants.sqlGen)); container.setAutoCommit(true); - Assert.assertTrue(container.isAutoCommit()); + assertTrue(container.isAutoCommit()); container.setAutoCommit(false); Assert.assertFalse(container.isAutoCommit()); } @@ -613,7 +639,7 @@ public class SQLContainerTableQueryTest { container.setAutoCommit(true); Object itemId = container.addItem(); Assert.assertNotNull(itemId); - Assert.assertTrue(itemId instanceof RowId); + assertTrue(itemId instanceof RowId); Assert.assertFalse(itemId instanceof TemporaryRowId); } @@ -696,7 +722,7 @@ public class SQLContainerTableQueryTest { SQLContainer container = new SQLContainer(new TableQuery("people", connectionPool, SQLTestsConstants.sqlGen)); Object id = container.addItem(); - Assert.assertTrue(container.getItemIds().contains(id)); + assertTrue(container.getItemIds().contains(id)); } @Test @@ -717,7 +743,7 @@ public class SQLContainerTableQueryTest { SQLContainer container = new SQLContainer(new TableQuery("people", connectionPool, SQLTestsConstants.sqlGen)); Object id = container.addItem(); - Assert.assertTrue(container.containsId(id)); + assertTrue(container.containsId(id)); } @Test @@ -747,7 +773,7 @@ public class SQLContainerTableQueryTest { SQLContainer container = new SQLContainer(new TableQuery("garbage", connectionPool, SQLTestsConstants.sqlGen)); Object id = container.addItem(); - Assert.assertTrue(container.isFirstId(id)); + assertTrue(container.isFirstId(id)); } @Test @@ -756,7 +782,7 @@ public class SQLContainerTableQueryTest { SQLContainer container = new SQLContainer(new TableQuery("people", connectionPool, SQLTestsConstants.sqlGen)); Object id = container.addItem(); - Assert.assertTrue(container.isLastId(id)); + assertTrue(container.isLastId(id)); } @Test @@ -766,7 +792,7 @@ public class SQLContainerTableQueryTest { connectionPool, SQLTestsConstants.sqlGen)); container.addItem(); Object id2 = container.addItem(); - Assert.assertTrue(container.isLastId(id2)); + assertTrue(container.isLastId(id2)); } @Test @@ -785,7 +811,7 @@ public class SQLContainerTableQueryTest { connectionPool, SQLTestsConstants.sqlGen)); int size = container.size(); Object id = container.firstItemId(); - Assert.assertTrue(container.removeItem(id)); + assertTrue(container.removeItem(id)); Assert.assertNotSame(id, container.firstItemId()); Assert.assertEquals(size - 1, container.size()); } @@ -795,7 +821,7 @@ public class SQLContainerTableQueryTest { SQLContainer container = new SQLContainer(new TableQuery("people", connectionPool, SQLTestsConstants.sqlGen)); Object id = container.firstItemId(); - Assert.assertTrue(container.removeItem(id)); + assertTrue(container.removeItem(id)); Assert.assertFalse(container.containsId(id)); } @@ -806,7 +832,7 @@ public class SQLContainerTableQueryTest { connectionPool, SQLTestsConstants.sqlGen)); Object id = container.addItem(); int size = container.size(); - Assert.assertTrue(container.removeItem(id)); + assertTrue(container.removeItem(id)); Assert.assertFalse(container.containsId(id)); Assert.assertEquals(size - 1, container.size()); } @@ -816,7 +842,7 @@ public class SQLContainerTableQueryTest { SQLContainer container = new SQLContainer(new TableQuery("people", connectionPool, SQLTestsConstants.sqlGen)); Object id = container.firstItemId(); - Assert.assertTrue(container.removeItem(id)); + assertTrue(container.removeItem(id)); Assert.assertNull(container.getItem(id)); } @@ -826,7 +852,7 @@ public class SQLContainerTableQueryTest { connectionPool, SQLTestsConstants.sqlGen)); Object id = container.addItem(); Assert.assertNotNull(container.getItem(id)); - Assert.assertTrue(container.removeItem(id)); + assertTrue(container.removeItem(id)); Assert.assertNull(container.getItem(id)); } @@ -836,8 +862,8 @@ public class SQLContainerTableQueryTest { SQLContainer container = new SQLContainer(new TableQuery("people", connectionPool, SQLTestsConstants.sqlGen)); Object id = container.firstItemId(); - Assert.assertTrue(container.getItemIds().contains(id)); - Assert.assertTrue(container.removeItem(id)); + assertTrue(container.getItemIds().contains(id)); + assertTrue(container.removeItem(id)); Assert.assertFalse(container.getItemIds().contains(id)); } @@ -847,8 +873,8 @@ public class SQLContainerTableQueryTest { SQLContainer container = new SQLContainer(new TableQuery("people", connectionPool, SQLTestsConstants.sqlGen)); Object id = container.addItem(); - Assert.assertTrue(container.getItemIds().contains(id)); - Assert.assertTrue(container.removeItem(id)); + assertTrue(container.getItemIds().contains(id)); + assertTrue(container.removeItem(id)); Assert.assertFalse(container.getItemIds().contains(id)); } @@ -857,8 +883,8 @@ public class SQLContainerTableQueryTest { SQLContainer container = new SQLContainer(new TableQuery("people", connectionPool, SQLTestsConstants.sqlGen)); Object id = container.firstItemId(); - Assert.assertTrue(container.containsId(id)); - Assert.assertTrue(container.removeItem(id)); + assertTrue(container.containsId(id)); + assertTrue(container.removeItem(id)); Assert.assertFalse(container.containsId(id)); } @@ -869,8 +895,8 @@ public class SQLContainerTableQueryTest { SQLTestsConstants.sqlGen); SQLContainer container = new SQLContainer(query); Object id = container.addItem(); - Assert.assertTrue(container.containsId(id)); - Assert.assertTrue(container.removeItem(id)); + assertTrue(container.containsId(id)); + assertTrue(container.removeItem(id)); Assert.assertFalse(container.containsId(id)); } @@ -882,7 +908,7 @@ public class SQLContainerTableQueryTest { Object first = container.getIdByIndex(0); Object second = container.getIdByIndex(1); Object third = container.getIdByIndex(2); - Assert.assertTrue(container.removeItem(second)); + assertTrue(container.removeItem(second)); Assert.assertEquals(third, container.nextItemId(first)); } @@ -894,7 +920,7 @@ public class SQLContainerTableQueryTest { Object first = container.lastItemId(); Object second = container.addItem(); Object third = container.addItem(); - Assert.assertTrue(container.removeItem(second)); + assertTrue(container.removeItem(second)); Assert.assertEquals(third, container.nextItemId(first)); } @@ -906,7 +932,7 @@ public class SQLContainerTableQueryTest { Object first = container.getIdByIndex(0); Object second = container.getIdByIndex(1); Object third = container.getIdByIndex(2); - Assert.assertTrue(container.removeItem(second)); + assertTrue(container.removeItem(second)); Assert.assertEquals(first, container.prevItemId(third)); } @@ -918,7 +944,7 @@ public class SQLContainerTableQueryTest { Object first = container.lastItemId(); Object second = container.addItem(); Object third = container.addItem(); - Assert.assertTrue(container.removeItem(second)); + assertTrue(container.removeItem(second)); Assert.assertEquals(first, container.prevItemId(third)); } @@ -928,7 +954,7 @@ public class SQLContainerTableQueryTest { SQLContainer container = new SQLContainer(new TableQuery("people", connectionPool, SQLTestsConstants.sqlGen)); Object first = container.firstItemId(); - Assert.assertTrue(container.removeItem(first)); + assertTrue(container.removeItem(first)); Assert.assertNotSame(first, container.firstItemId()); } @@ -941,7 +967,7 @@ public class SQLContainerTableQueryTest { Object first = container.addItem(); Object second = container.addItem(); Assert.assertSame(first, container.firstItemId()); - Assert.assertTrue(container.removeItem(first)); + assertTrue(container.removeItem(first)); Assert.assertSame(second, container.firstItemId()); } @@ -951,7 +977,7 @@ public class SQLContainerTableQueryTest { SQLContainer container = new SQLContainer(new TableQuery("people", connectionPool, SQLTestsConstants.sqlGen)); Object last = container.lastItemId(); - Assert.assertTrue(container.removeItem(last)); + assertTrue(container.removeItem(last)); Assert.assertNotSame(last, container.lastItemId()); } @@ -962,7 +988,7 @@ public class SQLContainerTableQueryTest { connectionPool, SQLTestsConstants.sqlGen)); Object last = container.addItem(); Assert.assertSame(last, container.lastItemId()); - Assert.assertTrue(container.removeItem(last)); + assertTrue(container.removeItem(last)); Assert.assertNotSame(last, container.lastItemId()); } @@ -972,7 +998,7 @@ public class SQLContainerTableQueryTest { SQLContainer container = new SQLContainer(new TableQuery("people", connectionPool, SQLTestsConstants.sqlGen)); Object first = container.firstItemId(); - Assert.assertTrue(container.removeItem(first)); + assertTrue(container.removeItem(first)); Assert.assertFalse(container.isFirstId(first)); } @@ -985,7 +1011,7 @@ public class SQLContainerTableQueryTest { Object first = container.addItem(); container.addItem(); Assert.assertSame(first, container.firstItemId()); - Assert.assertTrue(container.removeItem(first)); + assertTrue(container.removeItem(first)); Assert.assertFalse(container.isFirstId(first)); } @@ -995,7 +1021,7 @@ public class SQLContainerTableQueryTest { SQLContainer container = new SQLContainer(new TableQuery("people", connectionPool, SQLTestsConstants.sqlGen)); Object last = container.lastItemId(); - Assert.assertTrue(container.removeItem(last)); + assertTrue(container.removeItem(last)); Assert.assertFalse(container.isLastId(last)); } @@ -1006,7 +1032,7 @@ public class SQLContainerTableQueryTest { connectionPool, SQLTestsConstants.sqlGen)); Object last = container.addItem(); Assert.assertSame(last, container.lastItemId()); - Assert.assertTrue(container.removeItem(last)); + assertTrue(container.removeItem(last)); Assert.assertFalse(container.isLastId(last)); } @@ -1015,7 +1041,7 @@ public class SQLContainerTableQueryTest { SQLContainer container = new SQLContainer(new TableQuery("people", connectionPool, SQLTestsConstants.sqlGen)); Object id = container.getIdByIndex(2); - Assert.assertTrue(container.removeItem(id)); + assertTrue(container.removeItem(id)); Assert.assertEquals(-1, container.indexOfId(id)); } @@ -1025,8 +1051,8 @@ public class SQLContainerTableQueryTest { SQLContainer container = new SQLContainer(new TableQuery("people", connectionPool, SQLTestsConstants.sqlGen)); Object id = container.addItem(); - Assert.assertTrue(container.indexOfId(id) != -1); - Assert.assertTrue(container.removeItem(id)); + assertTrue(container.indexOfId(id) != -1); + assertTrue(container.removeItem(id)); Assert.assertEquals(-1, container.indexOfId(id)); } @@ -1036,7 +1062,7 @@ public class SQLContainerTableQueryTest { SQLContainer container = new SQLContainer(new TableQuery("people", connectionPool, SQLTestsConstants.sqlGen)); Object id = container.getIdByIndex(2); - Assert.assertTrue(container.removeItem(id)); + assertTrue(container.removeItem(id)); Assert.assertNotSame(id, container.getIdByIndex(2)); } @@ -1048,7 +1074,7 @@ public class SQLContainerTableQueryTest { Object id = container.addItem(); container.addItem(); int index = container.indexOfId(id); - Assert.assertTrue(container.removeItem(id)); + assertTrue(container.removeItem(id)); Assert.assertNotSame(id, container.getIdByIndex(index)); } @@ -1056,7 +1082,7 @@ public class SQLContainerTableQueryTest { public void removeAllItems_table_shouldSucceed() throws SQLException { SQLContainer container = new SQLContainer(new TableQuery("people", connectionPool, SQLTestsConstants.sqlGen)); - Assert.assertTrue(container.removeAllItems()); + assertTrue(container.removeAllItems()); Assert.assertEquals(0, container.size()); } @@ -1067,7 +1093,7 @@ public class SQLContainerTableQueryTest { connectionPool, SQLTestsConstants.sqlGen)); container.addItem(); container.addItem(); - Assert.assertTrue(container.removeAllItems()); + assertTrue(container.removeAllItems()); Assert.assertEquals(0, container.size()); } @@ -1086,7 +1112,7 @@ public class SQLContainerTableQueryTest { } container.commit(); Assert.assertEquals(container.size(), itemNumber); - Assert.assertTrue(container.removeAllItems()); + assertTrue(container.removeAllItems()); container.commit(); Assert.assertEquals(container.size(), 0); } @@ -1098,7 +1124,7 @@ public class SQLContainerTableQueryTest { SQLContainer container = new SQLContainer(query); Object id = container.addItem(); container.getContainerProperty(id, "NAME").setValue("New Name"); - Assert.assertTrue(id instanceof TemporaryRowId); + assertTrue(id instanceof TemporaryRowId); Assert.assertSame(id, container.lastItemId()); container.commit(); Assert.assertFalse(container.lastItemId() instanceof TemporaryRowId); @@ -1117,7 +1143,7 @@ public class SQLContainerTableQueryTest { Object id2 = container.addItem(); container.getContainerProperty(id, "NAME").setValue("Herbert"); container.getContainerProperty(id2, "NAME").setValue("Larry"); - Assert.assertTrue(id2 instanceof TemporaryRowId); + assertTrue(id2 instanceof TemporaryRowId); Assert.assertSame(id2, container.lastItemId()); container.commit(); Object nextToLast = container.getIdByIndex(container.size() - 2); @@ -1165,7 +1191,7 @@ public class SQLContainerTableQueryTest { Object key = container.firstItemId(); Item row = container.getItem(key); row.getItemProperty("NAME").setValue("Pekka"); - Assert.assertTrue(container.removeItem(key)); + assertTrue(container.removeItem(key)); container.commit(); Assert.assertEquals(size - 1, container.size()); } @@ -1217,7 +1243,7 @@ public class SQLContainerTableQueryTest { Assert.assertFalse(container.isModified()); RowItem last = (RowItem) container.getItem(container.lastItemId()); container.itemChangeNotification(last); - Assert.assertTrue(container.isModified()); + assertTrue(container.isModified()); } @Test @@ -1273,7 +1299,7 @@ public class SQLContainerTableQueryTest { connectionPool, SQLTestsConstants.sqlGen)); Assert.assertFalse(container.isModified()); container.removeItem(container.lastItemId()); - Assert.assertTrue(container.isModified()); + assertTrue(container.isModified()); } @Test @@ -1282,7 +1308,7 @@ public class SQLContainerTableQueryTest { connectionPool, SQLTestsConstants.sqlGen)); Assert.assertFalse(container.isModified()); container.addItem(); - Assert.assertTrue(container.isModified()); + assertTrue(container.isModified()); } @Test @@ -1292,7 +1318,7 @@ public class SQLContainerTableQueryTest { Assert.assertFalse(container.isModified()); container.getContainerProperty(container.lastItemId(), "NAME") .setValue("foo"); - Assert.assertTrue(container.isModified()); + assertTrue(container.isModified()); } @Test @@ -1301,9 +1327,9 @@ public class SQLContainerTableQueryTest { SQLContainer container = new SQLContainer(new TableQuery("people", connectionPool, SQLTestsConstants.sqlGen)); Collection sortableIds = container.getSortableContainerPropertyIds(); - Assert.assertTrue(sortableIds.contains("ID")); - Assert.assertTrue(sortableIds.contains("NAME")); - Assert.assertTrue(sortableIds.contains("AGE")); + assertTrue(sortableIds.contains("ID")); + assertTrue(sortableIds.contains("NAME")); + assertTrue(sortableIds.contains("AGE")); Assert.assertEquals(3, sortableIds.size()); if (SQLTestsConstants.db == DB.MSSQL || SQLTestsConstants.db == DB.ORACLE) { -- cgit v1.2.3 From 8c8ce29d6a6b3b1698cf28dd0e3a711d94f3bf25 Mon Sep 17 00:00:00 2001 From: Anna Miroshnik Date: Thu, 11 Dec 2014 18:22:42 +0300 Subject: Back button doesn't change URL if view blocks the navigation (#10901) Change-Id: Ib1211a7a2282753b329129615a544264e62d1ed5 --- server/src/com/vaadin/navigator/Navigator.java | 7 ++ .../NavigatorViewBlocksBackButtonAction.java | 128 +++++++++++++++++++++ .../NavigatorViewBlocksBackButtonActionTest.java | 95 +++++++++++++++ 3 files changed, 230 insertions(+) create mode 100644 uitest/src/com/vaadin/tests/navigator/NavigatorViewBlocksBackButtonAction.java create mode 100644 uitest/src/com/vaadin/tests/navigator/NavigatorViewBlocksBackButtonActionTest.java (limited to 'server/src') diff --git a/server/src/com/vaadin/navigator/Navigator.java b/server/src/com/vaadin/navigator/Navigator.java index 80dad2244e..591f73dc75 100644 --- a/server/src/com/vaadin/navigator/Navigator.java +++ b/server/src/com/vaadin/navigator/Navigator.java @@ -371,6 +371,7 @@ public class Navigator implements Serializable { private View currentView = null; private List listeners = new LinkedList(); private List providers = new LinkedList(); + private String currentNavigationState = null; private ViewProvider errorProvider; /** @@ -551,6 +552,11 @@ public class Navigator implements Serializable { ViewChangeEvent event = new ViewChangeEvent(this, currentView, view, viewName, parameters); if (!fireBeforeViewChange(event)) { + // #10901. Revert URL to previous state if back-button navigation + // was canceled + if (currentNavigationState != null) { + getStateManager().setState(currentNavigationState); + } return; } @@ -561,6 +567,7 @@ public class Navigator implements Serializable { } if (!navigationState.equals(getStateManager().getState())) { getStateManager().setState(navigationState); + currentNavigationState = navigationState; } } diff --git a/uitest/src/com/vaadin/tests/navigator/NavigatorViewBlocksBackButtonAction.java b/uitest/src/com/vaadin/tests/navigator/NavigatorViewBlocksBackButtonAction.java new file mode 100644 index 0000000000..5c78a3f42a --- /dev/null +++ b/uitest/src/com/vaadin/tests/navigator/NavigatorViewBlocksBackButtonAction.java @@ -0,0 +1,128 @@ +package com.vaadin.tests.navigator; + +import com.vaadin.navigator.Navigator; +import com.vaadin.navigator.View; +import com.vaadin.navigator.ViewChangeListener; +import com.vaadin.navigator.ViewChangeListener.ViewChangeEvent; +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.Button.ClickListener; +import com.vaadin.ui.Label; +import com.vaadin.ui.VerticalLayout; +import com.vaadin.ui.Window; + +public class NavigatorViewBlocksBackButtonAction extends AbstractTestUI { + + private Navigator navigator; + + protected static final String LABEL_MAINVIEW_ID = "LABEL_MAINVIEW_ID"; + protected static final String LABEL_PROMPTEDVIEW_ID = "LABEL_PROMPTEDVIEW_ID"; + + @Override + protected void setup(VaadinRequest request) { + navigator = new Navigator(this, this); + navigator.addView(MainView.NAME, new MainView()); + navigator.addView(ViewWithPromptedLeave.NAME, + new ViewWithPromptedLeave()); + navigator.navigateTo(MainView.NAME); + } + + class MainView extends VerticalLayout implements View { + + public static final String NAME = "mainview"; + + public MainView() { + Label label = new Label("MainView content"); + label.setId(LABEL_MAINVIEW_ID); + addComponent(label); + + Button buttonNavToAnotherView = new Button( + "Navigate to another view", new ClickListener() { + + @Override + public void buttonClick(ClickEvent event) { + navigator.navigateTo(ViewWithPromptedLeave.NAME); + } + }); + addComponent(buttonNavToAnotherView); + } + + @Override + public void enter(ViewChangeEvent event) { + } + + } + + class ViewWithPromptedLeave extends VerticalLayout implements View, + ViewChangeListener { + + public static final String NAME = "prompted"; + + protected boolean okToLeave; + + public ViewWithPromptedLeave() { + Label label = new Label("ViewWithPromptedLeave content"); + label.setId(LABEL_PROMPTEDVIEW_ID); + addComponent(label); + addComponent(new Label( + "Try to navigate back to first view with browser back button.")); + } + + @Override + public void enter(ViewChangeEvent event) { + event.getNavigator().addViewChangeListener(this); + } + + @Override + public boolean beforeViewChange(final ViewChangeEvent event) { + if (okToLeave) { + okToLeave = false; + return true; + } else { + final Window confirmationWindow = new Window("Confirm"); + confirmationWindow.setModal(true); + confirmationWindow.setClosable(true); + + VerticalLayout confirmationWindowLayout = new VerticalLayout(); + confirmationWindow.setContent(confirmationWindowLayout); + confirmationWindowLayout.setMargin(true); + confirmationWindowLayout.setSpacing(true); + confirmationWindowLayout.addComponent(new Label( + "Really exit this view?")); + confirmationWindowLayout.addComponent(new Button("Yeah, sure!", + new Button.ClickListener() { + + @Override + public void buttonClick(ClickEvent buttonEvent) { + okToLeave = true; + getUI().removeWindow(confirmationWindow); + event.getNavigator().navigateTo( + event.getViewName() + "/" + + event.getParameters()); + } + })); + getUI().addWindow(confirmationWindow); + return false; + } + } + + @Override + public void afterViewChange(ViewChangeEvent event) { + if (event.getNewView() != this) { + event.getNavigator().removeViewChangeListener(this); + } + } + } + + @Override + protected String getTestDescription() { + return "URL should not be changed when view blocks navigating away from view using the browser's Back-button"; + } + + @Override + protected Integer getTicketNumber() { + return 10901; + } +} \ No newline at end of file diff --git a/uitest/src/com/vaadin/tests/navigator/NavigatorViewBlocksBackButtonActionTest.java b/uitest/src/com/vaadin/tests/navigator/NavigatorViewBlocksBackButtonActionTest.java new file mode 100644 index 0000000000..84abdca24b --- /dev/null +++ b/uitest/src/com/vaadin/tests/navigator/NavigatorViewBlocksBackButtonActionTest.java @@ -0,0 +1,95 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.tests.navigator; + +import static org.junit.Assert.assertEquals; + +import org.junit.Test; +import org.openqa.selenium.By; +import org.openqa.selenium.WebElement; + +import com.vaadin.testbench.elements.ButtonElement; +import com.vaadin.tests.tb3.MultiBrowserTest; + +public class NavigatorViewBlocksBackButtonActionTest extends MultiBrowserTest { + + @Test + public void testIfConfirmBack() { + openTestURL(); + + // keep URL of main view + final String initialUrl = driver.getCurrentUrl(); + + // do it 2 times to verify that login is not broken after first time + for (int i = 0; i < 2; i++) { + // go to prompted view + WebElement button = $(ButtonElement.class).first(); + button.click(); + + // click back button + driver.navigate().back(); + + // confirm "go back by clicking confirm button + WebElement buttonConfirmView = $(ButtonElement.class).first(); + buttonConfirmView.click(); + + // verify we are in main view and url is correct + waitForElementPresent(By + .id(NavigatorViewBlocksBackButtonAction.LABEL_MAINVIEW_ID)); + String currentUrl = driver.getCurrentUrl(); + assertEquals( + "Current URL should be equal to initial main view URL", + initialUrl, currentUrl); + } + } + + @Test + public void testIfCancelBack() { + openTestURL(); + + // go to prompted view + WebElement button = $(ButtonElement.class).first(); + button.click(); + + // keep URL of prompted view + final String initialPromptedUrl = driver.getCurrentUrl(); + + // click back button + driver.navigate().back(); + + // verify url is correct (is not changed) + waitForElementPresent(By + .id(NavigatorViewBlocksBackButtonAction.LABEL_PROMPTEDVIEW_ID)); + String currentUrl = driver.getCurrentUrl(); + assertEquals( + "Current URL should be equal to initial prompted view URL", + initialPromptedUrl, currentUrl); + + WebElement cancelButton = driver.findElement(By + .className("v-window-closebox")); + + // click cancel button + cancelButton.click(); + + // verify we leave in prompted view and url is correct + waitForElementPresent(By + .id(NavigatorViewBlocksBackButtonAction.LABEL_PROMPTEDVIEW_ID)); + currentUrl = driver.getCurrentUrl(); + assertEquals( + "Current URL should be equal to initial prompted view URL", + initialPromptedUrl, currentUrl); + } +} -- cgit v1.2.3 From 4b58dccc09a6e0aa35dd3944ae5208644b6d4595 Mon Sep 17 00:00:00 2001 From: Leif Åstrand Date: Mon, 15 Dec 2014 13:40:07 +0200 Subject: Remove accidentally retained JavaDoc row The offending row was not removed when the proceeding "@throws JSONException" row was removed. Change-Id: I38d914284d92554540744e8c52eefa0db78bc55d --- server/src/com/vaadin/server/ClientConnector.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'server/src') diff --git a/server/src/com/vaadin/server/ClientConnector.java b/server/src/com/vaadin/server/ClientConnector.java index 50ce2754cb..b784aa5d35 100644 --- a/server/src/com/vaadin/server/ClientConnector.java +++ b/server/src/com/vaadin/server/ClientConnector.java @@ -26,6 +26,7 @@ import com.vaadin.shared.Connector; import com.vaadin.shared.communication.SharedState; import com.vaadin.ui.UI; import com.vaadin.util.ReflectTools; + import elemental.json.JsonObject; /** @@ -277,9 +278,8 @@ public interface ClientConnector extends Connector { * . * * @return a JSON object with the encoded connector state - * if the state can not be encoded */ - public JsonObject encodeState() ; + public JsonObject encodeState(); /** * Handle a request directed to this connector. This can be used by -- cgit v1.2.3 From 1b211745b02fbff5d4084f5ccada07cff8c09c85 Mon Sep 17 00:00:00 2001 From: Leif Åstrand Date: Sat, 13 Dec 2014 21:42:54 +0200 Subject: Release session memory at the end of each test Change-Id: I30dd917158091f1fe6f16d050ff7d6037493d3ef --- server/src/com/vaadin/server/VaadinService.java | 8 ++++---- uitest/src/com/vaadin/tests/tb3/AbstractTB3Test.java | 12 +++++++++--- 2 files changed, 13 insertions(+), 7 deletions(-) (limited to 'server/src') diff --git a/server/src/com/vaadin/server/VaadinService.java b/server/src/com/vaadin/server/VaadinService.java index fb93a44d37..36d6910a7a 100644 --- a/server/src/com/vaadin/server/VaadinService.java +++ b/server/src/com/vaadin/server/VaadinService.java @@ -703,12 +703,12 @@ public abstract class VaadinService implements Serializable { final boolean closeApplication = hasParameter(request, URL_PARAMETER_CLOSE_APPLICATION); - if (restartApplication) { - closeSession(session, request.getWrappedSession(false)); - return createAndRegisterSession(request); - } else if (closeApplication) { + if (closeApplication) { closeSession(session, request.getWrappedSession(false)); return null; + } else if (restartApplication) { + closeSession(session, request.getWrappedSession(false)); + return createAndRegisterSession(request); } else { return session; } diff --git a/uitest/src/com/vaadin/tests/tb3/AbstractTB3Test.java b/uitest/src/com/vaadin/tests/tb3/AbstractTB3Test.java index 76b851fd23..b5a345bd30 100644 --- a/uitest/src/com/vaadin/tests/tb3/AbstractTB3Test.java +++ b/uitest/src/com/vaadin/tests/tb3/AbstractTB3Test.java @@ -32,7 +32,6 @@ import java.util.Collections; import java.util.List; import java.util.NoSuchElementException; -import com.vaadin.testbench.elements.TableElement; import org.apache.commons.io.IOUtils; import org.apache.http.HttpHost; import org.apache.http.HttpResponse; @@ -69,6 +68,7 @@ import com.vaadin.testbench.TestBenchDriverProxy; import com.vaadin.testbench.TestBenchElement; import com.vaadin.testbench.TestBenchTestCase; import com.vaadin.testbench.elements.LabelElement; +import com.vaadin.testbench.elements.TableElement; import com.vaadin.testbench.elements.VerticalLayoutElement; import com.vaadin.tests.components.AbstractTestUIWithLog; import com.vaadin.tests.tb3.MultiBrowserTest.Browser; @@ -257,7 +257,7 @@ public abstract class AbstractTB3Test extends TestBenchTestCase { @Override public Object apply(WebDriver input) { try { - return table.getCell(row, 0) != null; + return table.getCell(row, 0) != null; } catch (NoSuchElementException e) { return false; } @@ -266,7 +266,8 @@ public abstract class AbstractTB3Test extends TestBenchTestCase { } protected void scrollTable(TableElement table, int rows, int rowToWait) { - testBenchElement(table.findElement(By.className("v-scrollable"))).scroll(rows * 30); + testBenchElement(table.findElement(By.className("v-scrollable"))) + .scroll(rows * 30); waitUntilRowIsVisible(table, rowToWait); } @@ -430,6 +431,11 @@ public abstract class AbstractTB3Test extends TestBenchTestCase { @After public void tearDown() throws Exception { if (driver != null) { + try { + openTestURL("&closeApplication"); + } catch (Exception e) { + e.printStackTrace(); + } driver.quit(); } driver = null; -- cgit v1.2.3 From 02d33ca7aea74f31319ce3920a7c67ac6f59571b Mon Sep 17 00:00:00 2001 From: Teemu Pöntelin Date: Mon, 15 Dec 2014 20:10:53 +0200 Subject: Fix NPE in DateField range handling (#15342) The NPE was introduced by 206055708b0a8e1c17a8c63d482a5e202d3ebf6d. Change-Id: I34401e108f7c02ee2f0aab581a78b9ab468b2b46 --- server/src/com/vaadin/ui/DateField.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'server/src') diff --git a/server/src/com/vaadin/ui/DateField.java b/server/src/com/vaadin/ui/DateField.java index d5700c4b65..3d683f4902 100644 --- a/server/src/com/vaadin/ui/DateField.java +++ b/server/src/com/vaadin/ui/DateField.java @@ -319,7 +319,8 @@ public class DateField extends AbstractField implements // Create a defensive copy against issues when using java.sql.Date (and // also against mutable Date). - getState().rangeStart = new Date(startDate.getTime()); + getState().rangeStart = startDate != null ? new Date( + startDate.getTime()) : null; updateRangeValidator(); } @@ -439,7 +440,8 @@ public class DateField extends AbstractField implements // Create a defensive copy against issues when using java.sql.Date (and // also against mutable Date). - getState().rangeEnd = new Date(endDate.getTime()); + getState().rangeEnd = endDate != null ? new Date(endDate.getTime()) + : null; updateRangeValidator(); } -- cgit v1.2.3 From a9f24b00e9ddcd5ca19ac2907e0bf2413f036af4 Mon Sep 17 00:00:00 2001 From: Denis Anisimov Date: Sun, 21 Sep 2014 21:04:31 +0300 Subject: Use introspection instead of reflection to get property type (#10672). Change-Id: I4eebad640c3c091bfff335bae8ef455e662ad4cb --- .../com/vaadin/data/fieldgroup/BeanFieldGroup.java | 51 ++---- server/src/com/vaadin/data/util/BeanItem.java | 107 +------------ server/src/com/vaadin/data/util/BeanUtil.java | 177 +++++++++++++++++++++ 3 files changed, 194 insertions(+), 141 deletions(-) create mode 100644 server/src/com/vaadin/data/util/BeanUtil.java (limited to 'server/src') diff --git a/server/src/com/vaadin/data/fieldgroup/BeanFieldGroup.java b/server/src/com/vaadin/data/fieldgroup/BeanFieldGroup.java index 257a958f3a..23a72ee1e5 100644 --- a/server/src/com/vaadin/data/fieldgroup/BeanFieldGroup.java +++ b/server/src/com/vaadin/data/fieldgroup/BeanFieldGroup.java @@ -15,18 +15,20 @@ */ package com.vaadin.data.fieldgroup; +import java.beans.IntrospectionException; import java.lang.reflect.Method; import java.util.HashMap; import java.util.Map; import com.vaadin.data.Item; import com.vaadin.data.util.BeanItem; +import com.vaadin.data.util.BeanUtil; import com.vaadin.data.validator.BeanValidator; import com.vaadin.ui.Field; public class BeanFieldGroup extends FieldGroup { - private Class beanType; + private final Class beanType; private static Boolean beanValidationImplementationAvailable = null; private final Map, BeanValidator> defaultValidators; @@ -47,17 +49,20 @@ public class BeanFieldGroup extends FieldGroup { * form "fieldName" or "fieldName.subField[.subField2]" but the * method declaration comes from parent. */ - java.lang.reflect.Field f; try { - f = getField(beanType, propertyId.toString()); - return f.getType(); - } catch (SecurityException e) { - throw new BindException("Cannot determine type of propertyId '" - + propertyId + "'.", e); - } catch (NoSuchFieldException e) { + Class type = BeanUtil.getPropertyType(beanType, + propertyId.toString()); + if (type == null) { + throw new BindException( + "Cannot determine type of propertyId '" + + propertyId + + "'. The propertyId was not found in " + + beanType.getName()); + } + return type; + } catch (IntrospectionException e) { throw new BindException("Cannot determine type of propertyId '" - + propertyId + "'. The propertyId was not found in " - + beanType.getName(), e); + + propertyId + "'. Unable to introspect " + beanType, e); } } } @@ -79,32 +84,6 @@ public class BeanFieldGroup extends FieldGroup { return null; } - private static java.lang.reflect.Field getField(Class cls, - String propertyId) throws SecurityException, NoSuchFieldException { - if (propertyId.contains(".")) { - String[] parts = propertyId.split("\\.", 2); - // Get the type of the field in the "cls" class - java.lang.reflect.Field field1 = getField(cls, parts[0]); - // Find the rest from the sub type - return getField(field1.getType(), parts[1]); - } else { - try { - // Try to find the field directly in the given class - java.lang.reflect.Field field1 = cls - .getDeclaredField(propertyId); - return field1; - } catch (NoSuchFieldException e) { - // Try super classes until we reach Object - Class superClass = cls.getSuperclass(); - if (superClass != null && superClass != Object.class) { - return getField(superClass, propertyId); - } else { - throw e; - } - } - } - } - private static String getFieldName(Class cls, String propertyId) throws SecurityException, NoSuchFieldException { for (java.lang.reflect.Field field1 : cls.getDeclaredFields()) { diff --git a/server/src/com/vaadin/data/util/BeanItem.java b/server/src/com/vaadin/data/util/BeanItem.java index 64f30261c2..1be8b70f47 100644 --- a/server/src/com/vaadin/data/util/BeanItem.java +++ b/server/src/com/vaadin/data/util/BeanItem.java @@ -16,12 +16,8 @@ package com.vaadin.data.util; -import java.beans.BeanInfo; -import java.beans.IntrospectionException; -import java.beans.Introspector; import java.beans.PropertyDescriptor; import java.lang.reflect.Method; -import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.HashSet; @@ -189,7 +185,8 @@ public class BeanItem extends PropertysetItem { // Try to introspect, if it fails, we just have an empty Item try { - List propertyDescriptors = getBeanPropertyDescriptor(beanClass); + List propertyDescriptors = BeanUtil + .getBeanPropertyDescriptor(beanClass); // Add all the bean properties as MethodProperties to this Item // later entries on the list overwrite earlier ones @@ -209,106 +206,6 @@ public class BeanItem extends PropertysetItem { return pdMap; } - /** - * Returns the property descriptors of a class or an interface. - * - * For an interface, superinterfaces are also iterated as Introspector does - * not take them into account (Oracle Java bug 4275879), but in that case, - * both the setter and the getter for a property must be in the same - * interface and should not be overridden in subinterfaces for the discovery - * to work correctly. - * - * For interfaces, the iteration is depth first and the properties of - * superinterfaces are returned before those of their subinterfaces. - * - * @param beanClass - * @return - * @throws IntrospectionException - */ - private static List getBeanPropertyDescriptor( - final Class beanClass) throws IntrospectionException { - // Oracle bug 4275879: Introspector does not consider superinterfaces of - // an interface - if (beanClass.isInterface()) { - List propertyDescriptors = new ArrayList(); - - for (Class cls : beanClass.getInterfaces()) { - propertyDescriptors.addAll(getBeanPropertyDescriptor(cls)); - } - - BeanInfo info = Introspector.getBeanInfo(beanClass); - propertyDescriptors.addAll(getPropertyDescriptors(info)); - - return propertyDescriptors; - } else { - BeanInfo info = Introspector.getBeanInfo(beanClass); - return getPropertyDescriptors(info); - } - } - - // Workaround for Java6 bug JDK-6788525. Do nothing for JDK7+. - private static List getPropertyDescriptors( - BeanInfo beanInfo) { - PropertyDescriptor[] descriptors = beanInfo.getPropertyDescriptors(); - List result = new ArrayList( - descriptors.length); - for (PropertyDescriptor descriptor : descriptors) { - try { - Method readMethod = getMethodFromBridge(descriptor - .getReadMethod()); - if (readMethod != null) { - Method writeMethod = getMethodFromBridge( - descriptor.getWriteMethod(), - readMethod.getReturnType()); - if (writeMethod == null) { - writeMethod = descriptor.getWriteMethod(); - } - PropertyDescriptor descr = new PropertyDescriptor( - descriptor.getName(), readMethod, writeMethod); - result.add(descr); - } else { - result.add(descriptor); - } - } catch (SecurityException ignore) { - // handle next descriptor - } catch (IntrospectionException e) { - result.add(descriptor); - } - } - return result; - } - - /** - * Return not bridged method for bridge {@code bridgeMethod} method. If - * method {@code bridgeMethod} is not bridge method then return null. - */ - private static Method getMethodFromBridge(Method bridgeMethod) - throws SecurityException { - if (bridgeMethod == null) { - return null; - } - return getMethodFromBridge(bridgeMethod, - bridgeMethod.getParameterTypes()); - } - - /** - * Return not bridged method for bridge {@code bridgeMethod} method and - * declared {@code paramTypes}. If method {@code bridgeMethod} is not bridge - * method then return null. - */ - private static Method getMethodFromBridge(Method bridgeMethod, - Class... paramTypes) throws SecurityException { - if (bridgeMethod == null || !bridgeMethod.isBridge()) { - return null; - } - try { - return bridgeMethod.getDeclaringClass().getMethod( - bridgeMethod.getName(), paramTypes); - } catch (NoSuchMethodException e) { - return null; - } - } - /** * Expands nested bean properties by replacing a top-level property with * some or all of its sub-properties. The expansion is not recursive. diff --git a/server/src/com/vaadin/data/util/BeanUtil.java b/server/src/com/vaadin/data/util/BeanUtil.java new file mode 100644 index 0000000000..e2f85a765c --- /dev/null +++ b/server/src/com/vaadin/data/util/BeanUtil.java @@ -0,0 +1,177 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.data.util; + +import java.beans.BeanInfo; +import java.beans.IntrospectionException; +import java.beans.Introspector; +import java.beans.PropertyDescriptor; +import java.io.Serializable; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.List; + +/** + * Utility class for Java Beans information access. + * + * @author Vaadin Ltd + */ +public final class BeanUtil implements Serializable { + // Prevent instantiation of util class + private BeanUtil() { + } + + /** + * Returns the property descriptors of a class or an interface. + * + * For an interface, superinterfaces are also iterated as Introspector does + * not take them into account (Oracle Java bug 4275879), but in that case, + * both the setter and the getter for a property must be in the same + * interface and should not be overridden in subinterfaces for the discovery + * to work correctly. + * + * NOTE : This utility method relies on introspection (and returns + * PropertyDescriptor) which is a part of java.beans package. The latter + * package could require bigger JDK in the future (with Java 9+). So it may + * be changed in the future. + * + * For interfaces, the iteration is depth first and the properties of + * superinterfaces are returned before those of their subinterfaces. + * + * @param beanClass + * @return + * @throws IntrospectionException + */ + public static List getBeanPropertyDescriptor( + final Class beanClass) throws IntrospectionException { + // Oracle bug 4275879: Introspector does not consider superinterfaces of + // an interface + if (beanClass.isInterface()) { + List propertyDescriptors = new ArrayList(); + + for (Class cls : beanClass.getInterfaces()) { + propertyDescriptors.addAll(getBeanPropertyDescriptor(cls)); + } + + BeanInfo info = Introspector.getBeanInfo(beanClass); + propertyDescriptors.addAll(getPropertyDescriptors(info)); + + return propertyDescriptors; + } else { + BeanInfo info = Introspector.getBeanInfo(beanClass); + return getPropertyDescriptors(info); + } + } + + /** + * Returns {@code propertyId} class for property declared in {@code clazz}. + * Property could be of form "property.subProperty[.subProperty2]" i.e. + * refer to some nested property. + * + * @param clazz + * class where property is declared + * @param propertyId + * property of form "property" or + * "property.subProperty[.subProperty2]" + * @return class of the property + * @throws IntrospectionException + */ + public static Class getPropertyType(Class clazz, String propertyId) + throws IntrospectionException { + if (propertyId.contains(".")) { + String[] parts = propertyId.split("\\.", 2); + // Get the type of the field in the "cls" class + Class propertyBean = getPropertyType(clazz, parts[0]); + // Find the rest from the sub type + return getPropertyType(propertyBean, parts[1]); + } else { + List descriptors = getBeanPropertyDescriptor(clazz); + + for (PropertyDescriptor descriptor : descriptors) { + final Method getMethod = descriptor.getReadMethod(); + if (descriptor.getName().equals(propertyId) + && getMethod != null + && getMethod.getDeclaringClass() != Object.class) { + return descriptor.getPropertyType(); + } + } + return null; + } + } + + // Workaround for Java6 bug JDK-6788525. Do nothing for JDK7+. + private static List getPropertyDescriptors( + BeanInfo beanInfo) { + PropertyDescriptor[] descriptors = beanInfo.getPropertyDescriptors(); + List result = new ArrayList( + descriptors.length); + for (PropertyDescriptor descriptor : descriptors) { + try { + Method readMethod = getMethodFromBridge(descriptor + .getReadMethod()); + if (readMethod != null) { + Method writeMethod = getMethodFromBridge( + descriptor.getWriteMethod(), + readMethod.getReturnType()); + if (writeMethod == null) { + writeMethod = descriptor.getWriteMethod(); + } + PropertyDescriptor descr = new PropertyDescriptor( + descriptor.getName(), readMethod, writeMethod); + result.add(descr); + } else { + result.add(descriptor); + } + } catch (SecurityException ignore) { + // handle next descriptor + } catch (IntrospectionException e) { + result.add(descriptor); + } + } + return result; + } + + /** + * Return declared method for which {@code bridgeMethod} is generated. If + * {@code bridgeMethod} is not a bridge method then return null. + */ + private static Method getMethodFromBridge(Method bridgeMethod) + throws SecurityException { + if (bridgeMethod == null) { + return null; + } + return getMethodFromBridge(bridgeMethod, + bridgeMethod.getParameterTypes()); + } + + /** + * Return declared method for which {@code bridgeMethod} is generated using + * its {@code paramTypes}. If {@code bridgeMethod} is not a bridge method + * then return null. + */ + private static Method getMethodFromBridge(Method bridgeMethod, + Class... paramTypes) throws SecurityException { + if (bridgeMethod == null || !bridgeMethod.isBridge()) { + return null; + } + try { + return bridgeMethod.getDeclaringClass().getMethod( + bridgeMethod.getName(), paramTypes); + } catch (NoSuchMethodException e) { + return null; + } + } +} -- cgit v1.2.3