diff options
author | Artur Signell <artur@vaadin.com> | 2014-12-12 10:32:29 +0200 |
---|---|---|
committer | Artur Signell <artur@vaadin.com> | 2014-12-12 10:32:29 +0200 |
commit | 6fdc3320fec5801a73f51d3e3a3584d23d942c6c (patch) | |
tree | bca21a044acc56530bb403eb1cd3652c01c71928 /server | |
parent | b3e6edc9634f444ccece00e200cb51eee7994d75 (diff) | |
parent | 10fa4e4236ed049ef6eac337d23701bc381763ce (diff) | |
download | vaadin-framework-6fdc3320fec5801a73f51d3e3a3584d23d942c6c.tar.gz vaadin-framework-6fdc3320fec5801a73f51d3e3a3584d23d942c6c.zip |
Merge remote-tracking branch 'origin/master' into grid
Conflicts:
server/tests/src/com/vaadin/data/util/BeanItemContainerTest.java
Change-Id: I04938bd8c5b4f01c3ca801c9f7adbb20d279523c
Diffstat (limited to 'server')
48 files changed, 913 insertions, 218 deletions
diff --git a/server/src/com/vaadin/data/fieldgroup/BeanFieldGroup.java b/server/src/com/vaadin/data/fieldgroup/BeanFieldGroup.java index e5d53b759d..257a958f3a 100644 --- a/server/src/com/vaadin/data/fieldgroup/BeanFieldGroup.java +++ b/server/src/com/vaadin/data/fieldgroup/BeanFieldGroup.java @@ -125,21 +125,29 @@ public class BeanFieldGroup<T> 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)}. + * <p> + * 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)); + if (bean == null) { + setItemDataSource((Item) null); + } else { + setItemDataSource(new BeanItem<T>(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/fieldgroup/FieldGroup.java b/server/src/com/vaadin/data/fieldgroup/FieldGroup.java index 5a4e877554..c89b94ace9 100644 --- a/server/src/com/vaadin/data/fieldgroup/FieldGroup.java +++ b/server/src/com/vaadin/data/fieldgroup/FieldGroup.java @@ -255,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; } @@ -452,6 +455,56 @@ public class FieldGroup implements Serializable { // Not using buffered mode, nothing to do return; } + + startTransactions(); + + try { + firePreCommitEvent(); + + List<InvalidValueException> invalidValueExceptions = commitFields(); + + if (invalidValueExceptions.isEmpty()) { + firePostCommitEvent(); + commitTransactions(); + } else { + throwInvalidValueException(invalidValueExceptions); + } + } catch (Exception e) { + rollbackTransactions(); + + throw new CommitException("Commit failed", e); + } + + } + + private List<InvalidValueException> commitFields() { + List<InvalidValueException> invalidValueExceptions = new ArrayList<InvalidValueException>(); + + for (Field<?> f : fieldToPropertyId.keySet()) { + try { + f.commit(); + } catch (InvalidValueException e) { + invalidValueExceptions.add(e); + } + } + + return invalidValueExceptions; + } + + private void throwInvalidValueException( + List<InvalidValueException> 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 +515,23 @@ 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/server/src/com/vaadin/data/util/AbstractBeanContainer.java b/server/src/com/vaadin/data/util/AbstractBeanContainer.java index 0559585e14..6dcfbb2b84 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<IDTYPE, BEANTYPE> 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<String, VaadinPropertyDescriptor<BEANTYPE>> model; + private final LinkedHashMap<String, VaadinPropertyDescriptor<BEANTYPE>> model; /** * Constructs a {@code AbstractBeanContainer} for beans of the given type. @@ -178,7 +178,11 @@ public abstract class AbstractBeanContainer<IDTYPE, BEANTYPE> extends */ @Override public Class<?> getType(Object propertyId) { - return model.get(propertyId).getPropertyType(); + VaadinPropertyDescriptor<BEANTYPE> descriptor = model.get(propertyId); + if (descriptor == null) { + return null; + } + return descriptor.getPropertyType(); } /** @@ -888,7 +892,7 @@ public abstract class AbstractBeanContainer<IDTYPE, BEANTYPE> extends model.put(qualifiedPropertyId, pd); model.remove(propertyId); for (BeanItem<BEANTYPE> item : itemIdToItem.values()) { - item.addItemProperty(propertyId, + item.addItemProperty(qualifiedPropertyId, pd.createProperty(item.getBean())); item.removeItemProperty(propertyId); } 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<BT> extends PropertysetItem { * */ public BeanItem(BT bean) { - this(bean, getPropertyDescriptors((Class<BT>) bean.getClass())); + this(bean, (Class<BT>) bean.getClass()); + } + + /** + * <p> + * Creates a new instance of <code>BeanItem</code> and adds all properties + * of a Java Bean to it. The properties are identified by their respective + * bean names. + * </p> + * + * <p> + * Note : This version only supports introspectable bean properties and + * their getter and setter methods. Stand-alone <code>is</code> and + * <code>are</code> methods are not supported. + * </p> + * + * @param bean + * the Java Bean to copy properties from. + * @param beanClass + * class of the {@code bean} + * + */ + public BeanItem(BT bean, Class<BT> 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<T> extends AbstractProperty<T> { 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<T> extends AbstractProperty<T> { 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<T> extends AbstractProperty<T> { @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/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<T> 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; * </p> * * @author Vaadin Ltd - * @since 7.3.1 + * @since */ public class StringToBigIntegerConverter extends AbstractStringToNumberConverter<BigInteger> { @@ -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<? extends BigInteger> 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; * </p> * * @author Vaadin Ltd - * @since 7.3.1 + * @since */ public class StringToByteConverter extends AbstractStringToNumberConverter<Byte> { 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<String, Enum> { @Override public Enum convertToModel(String value, Class<? extends Enum> 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, Enum> { 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/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; * </p> * * @author Vaadin Ltd - * @since 7.3.1 + * @since */ public class StringToShortConverter extends AbstractStringToNumberConverter<Short> { diff --git a/server/src/com/vaadin/data/util/sqlcontainer/SQLContainer.java b/server/src/com/vaadin/data/util/sqlcontainer/SQLContainer.java index 683140d279..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; @@ -1020,18 +1019,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/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/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/src/com/vaadin/server/VaadinServlet.java b/server/src/com/vaadin/server/VaadinServlet.java index 4656f9a672..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++) { @@ -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); } 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; } 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/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<T> 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. - * <p> - * 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<Object> 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/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/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<String> implements } @Override - protected boolean isEmpty() { + public boolean isEmpty() { return super.isEmpty() || getValue().length() == 0; } 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/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<Date> 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<Date> 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/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<T> extends Component, BufferedValidatable, Property<T>, 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. + * <p> + * 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<Object> implements Item.Editor, } } - /** Form is empty if all of its fields are empty. */ + /** + * {@inheritDoc} + * <p> + * A Form is empty if all of its fields are empty. + * + */ @Override - protected boolean isEmpty() { + public boolean isEmpty() { for (Iterator<Field<?>> i = fields.values().iterator(); i.hasNext();) { Field<?> f = i.next(); 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/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<String> implements } @Override - protected boolean isEmpty() { + public boolean isEmpty() { return super.isEmpty() || getValue().length() == 0; } 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/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 <code>TextField</code> 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(""); + } + } diff --git a/server/src/com/vaadin/ui/UI.java b/server/src/com/vaadin/ui/UI.java index 78cb5488e8..4bd4b67259 100644 --- a/server/src/com/vaadin/ui/UI.java +++ b/server/src/com/vaadin/ui/UI.java @@ -633,7 +633,7 @@ public abstract class UI extends AbstractSingleComponentContainer implements this.embedId = embedId; // Actual theme - used for finding CustomLayout templates - getState().theme = request.getParameter("theme"); + setTheme(request.getParameter("theme")); getPage().init(request); @@ -1164,7 +1164,11 @@ public abstract class UI extends AbstractSingleComponentContainer implements * The new theme name */ public void setTheme(String theme) { - getState().theme = theme; + if(theme == null) { + getState().theme = null; + } else { + getState().theme = VaadinServlet.stripSpecialChars(theme); + } } /** 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<CalendarEvent> 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/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<String, ClassName> container = getContainer(); + Assert.assertEquals( + "Unexpected type is returned for property 'simpleName'", + String.class, container.getType("simpleName")); + } + + public void testGetType_notExistingProperty_nullReturned() { + BeanContainer<String, ClassName> 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 463f0c92c1..2cf64bbc7c 100644 --- a/server/tests/src/com/vaadin/data/util/BeanItemContainerTest.java +++ b/server/tests/src/com/vaadin/data/util/BeanItemContainerTest.java @@ -8,16 +8,16 @@ import java.util.LinkedHashMap; import java.util.List; import java.util.Map; -import org.junit.Assert; - import org.easymock.Capture; import org.easymock.EasyMock; +import org.junit.Assert; import com.vaadin.data.Container; import com.vaadin.data.Container.Indexed.ItemAddEvent; import com.vaadin.data.Container.Indexed.ItemRemoveEvent; import com.vaadin.data.Container.ItemSetChangeListener; import com.vaadin.data.Item; +import com.vaadin.data.util.NestedMethodPropertyTest.Address; import com.vaadin.data.util.filter.Compare; /** @@ -78,6 +78,19 @@ public class BeanItemContainerTest extends AbstractBeanContainerTest { return false; } + public void testGetType_existingProperty_typeReturned() { + BeanItemContainer<ClassName> container = getContainer(); + Assert.assertEquals( + "Unexpected type is returned for property 'simpleName'", + String.class, container.getType("simpleName")); + } + + public void testGetType_notExistingProperty_nullReturned() { + BeanItemContainer<ClassName> container = getContainer(); + Assert.assertNull("Not null type is returned for property ''", + container.getType("")); + } + public void testBasicOperations() { testBasicContainerOperations(getContainer()); } @@ -912,4 +925,45 @@ public class BeanItemContainerTest extends AbstractBeanContainerTest { container.addItemSetChangeListener(listener); return listener; } + + public void testAddNestedContainerBeanBeforeData() { + BeanItemContainer<NestedMethodPropertyTest.Person> container = new BeanItemContainer<NestedMethodPropertyTest.Person>( + 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<NestedMethodPropertyTest.Person> container = new BeanItemContainer<NestedMethodPropertyTest.Person>( + 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()); + + } } 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..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, @@ -1137,6 +1157,20 @@ public class SQLContainerTableQueryTest { } @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", connectionPool, SQLTestsConstants.sqlGen)); diff --git a/server/tests/src/com/vaadin/tests/data/converter/TestDefaultConverterFactory.java b/server/tests/src/com/vaadin/tests/data/converter/TestDefaultConverterFactory.java new file mode 100644 index 0000000000..e1becf43e1 --- /dev/null +++ b/server/tests/src/com/vaadin/tests/data/converter/TestDefaultConverterFactory.java @@ -0,0 +1,128 @@ +/* + * 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.data.converter; + +import java.math.BigDecimal; +import java.math.BigInteger; +import java.util.Date; +import java.util.Locale; + +import org.junit.Assert; +import org.junit.Test; + +import com.vaadin.data.util.converter.DefaultConverterFactory; + +public class TestDefaultConverterFactory { + + private DefaultConverterFactory factory = new DefaultConverterFactory(); + + @Test + public void stringToBigDecimal() { + assertConverter("14", new BigDecimal("14")); + } + + @Test + public void stringToBigInteger() { + assertConverter("14", new BigInteger("14")); + } + + @Test + public void stringToDouble() { + assertConverter("14", new Double("14")); + } + + @Test + public void stringToFloat() { + assertConverter("14", new Float("14")); + } + + @Test + public void stringToInteger() { + assertConverter("14", new Integer("14")); + } + + @Test + public void stringToLong() { + assertConverter("14", new Long("14")); + } + + @SuppressWarnings("deprecation") + @Test + public void stringToDate() { + assertConverter("Oct 12, 2014 12:00:00 AM", new Date(2014 - 1900, + 10 - 1, 12)); + } + + @Test + public void sqlDateToDate() { + long l = 1413071210000L; + assertConverter(new java.sql.Date(l), new java.util.Date(l)); + } + + @SuppressWarnings("deprecation") + @Test + public void longToDate() { + assertConverter(1413061200000L, new Date(2014 - 1900, 10 - 1, 12)); + } + + public enum Foo { + BAR, BAZ; + } + + @Test + public void stringToEnum() { + assertConverter("Bar", Foo.BAR); + } + + @Test + public void stringToShort() { + assertConverter("14", new Short("14")); + } + + @Test + public void stringToByte() { + assertConverter("14", new Byte("14")); + } + + private <T, U> void assertConverter(T t, U u) { + Class<T> tClass = (Class<T>) t.getClass(); + Class<U> uClass = (Class<U>) u.getClass(); + + U tConvertedToU = factory.createConverter(tClass, uClass) + .convertToModel(t, uClass, Locale.ENGLISH); + Assert.assertEquals( + "Incorrect type of value converted from " + + tClass.getSimpleName() + " to " + + uClass.getSimpleName(), uClass, + tConvertedToU.getClass()); + Assert.assertEquals( + "Incorrect conversion of " + t + " to " + + uClass.getSimpleName(), u, tConvertedToU); + + T uConvertedToT = factory.createConverter(uClass, tClass) + .convertToModel(u, tClass, Locale.ENGLISH); + Assert.assertEquals( + "Incorrect type of value converted from " + + uClass.getSimpleName() + " to " + + tClass.getSimpleName(), tClass, + uConvertedToT.getClass()); + Assert.assertEquals( + "Incorrect conversion of " + u + " to " + + tClass.getSimpleName(), t, uConvertedToT); + + } + +} 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/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<Enum, String> reverseConverter = new ReverseConverter<Enum, String>( 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/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() { 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(); + } + +} 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..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 @@ -5,9 +5,11 @@ import static org.junit.Assert.assertEquals; 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 +135,23 @@ public class BeanFieldGroupTest { assertEquals(bean.nestedBean.hello, helloField.getValue().toString()); } + @Test + public void setDataSource_nullBean_nullBeanIsSetInDataSource() { + BeanFieldGroup<MyBean> group = new BeanFieldGroup<MyBean>(MyBean.class); + + group.setItemDataSource((MyBean) null); + + BeanItem<MyBean> dataSource = group.getItemDataSource(); + Assert.assertNull("Data source is null for null bean", dataSource); + } + + @Test + public void setDataSource_nullItem_nullDataSourceIsSet() { + BeanFieldGroup<MyBean> group = new BeanFieldGroup<MyBean>(MyBean.class); + + group.setItemDataSource((Item) null); + BeanItem<MyBean> dataSource = group.getItemDataSource(); + Assert.assertNull("Group returns not null data source", dataSource); + } + } 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("<div location='loc'/>"); + 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/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<String>("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<String> sel = new HashSet<String>(); + sel.add("foo"); + sel.add("bar"); + s.setPropertyDataSource(new ObjectProperty<HashSet>(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<String>("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<String>("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()); + } + +} 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..236f283823 --- /dev/null +++ b/server/tests/src/com/vaadin/ui/UIThemeEscaping.java @@ -0,0 +1,89 @@ +/* + * 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 com.vaadin.server.VaadinRequest; +import org.junit.Before; +import org.junit.Test; + +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 { + + 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<å(_\"$"); + + assertThat(ui.getTheme(), is("aå_$")); + } + + @Test + public void nullThemeIsSet() { + ui.setTheme("foobar"); + + ui.setTheme(null); + + 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())); + } +} |