diff options
author | Teemu Suo-Anttila <teemusa@vaadin.com> | 2014-10-16 13:48:15 +0300 |
---|---|---|
committer | Teemu Suo-Anttila <teemusa@vaadin.com> | 2014-10-16 13:48:47 +0300 |
commit | 9e769462bd09483c1ccfde452bc679ea54a5d85e (patch) | |
tree | ddca2585fefccf6ab7382503465ca5aa2bcfa48f /server | |
parent | 6290daf788d6a96afaae4d6db058762b713af291 (diff) | |
parent | e157228948d4583951cad358b77e8ab27990e5e5 (diff) | |
download | vaadin-framework-9e769462bd09483c1ccfde452bc679ea54a5d85e.tar.gz vaadin-framework-9e769462bd09483c1ccfde452bc679ea54a5d85e.zip |
Merge remote-tracking branch 'origin/master' into grid
Change-Id: I7462e5a6a902eb0c4396bc14216a6f323dd33b76
Diffstat (limited to 'server')
51 files changed, 1909 insertions, 176 deletions
diff --git a/server/src/com/vaadin/data/fieldgroup/DefaultFieldGroupFieldFactory.java b/server/src/com/vaadin/data/fieldgroup/DefaultFieldGroupFieldFactory.java index b1bf58199a..9c2e4b2f83 100644 --- a/server/src/com/vaadin/data/fieldgroup/DefaultFieldGroupFieldFactory.java +++ b/server/src/com/vaadin/data/fieldgroup/DefaultFieldGroupFieldFactory.java @@ -36,10 +36,26 @@ import com.vaadin.ui.RichTextArea; import com.vaadin.ui.Table; import com.vaadin.ui.TextField; +/** + * This class contains a basic implementation for {@link FieldGroupFieldFactory} + * .The class is singleton, use {@link #get()} method to get reference to the + * instance. + * + * @author Vaadin Ltd + */ public class DefaultFieldGroupFieldFactory implements FieldGroupFieldFactory { + private static final DefaultFieldGroupFieldFactory INSTANCE = new DefaultFieldGroupFieldFactory(); + public static final Object CAPTION_PROPERTY_ID = "Caption"; + protected DefaultFieldGroupFieldFactory() { + } + + public static DefaultFieldGroupFieldFactory get() { + return INSTANCE; + } + @Override public <T extends Field> T createField(Class<?> type, Class<T> fieldType) { if (Enum.class.isAssignableFrom(type)) { diff --git a/server/src/com/vaadin/data/fieldgroup/FieldGroup.java b/server/src/com/vaadin/data/fieldgroup/FieldGroup.java index e647bdbf6d..c5aab5a053 100644 --- a/server/src/com/vaadin/data/fieldgroup/FieldGroup.java +++ b/server/src/com/vaadin/data/fieldgroup/FieldGroup.java @@ -28,6 +28,7 @@ import com.vaadin.data.Item; import com.vaadin.data.Property; import com.vaadin.data.Validator.InvalidValueException; import com.vaadin.data.util.TransactionalPropertyWrapper; +import com.vaadin.ui.AbstractField; import com.vaadin.ui.DefaultFieldFactory; import com.vaadin.ui.Field; import com.vaadin.ui.Form; @@ -67,7 +68,8 @@ public class FieldGroup implements Serializable { /** * The field factory used by builder methods. */ - private FieldGroupFieldFactory fieldFactory = new DefaultFieldGroupFieldFactory(); + private FieldGroupFieldFactory fieldFactory = DefaultFieldGroupFieldFactory + .get(); /** * Constructs a field binder. Use {@link #setItemDataSource(Item)} to set a @@ -435,8 +437,14 @@ public class FieldGroup implements Serializable { return; } for (Field<?> f : fieldToPropertyId.keySet()) { - ((Property.Transactional<?>) f.getPropertyDataSource()) - .startTransaction(); + Property.Transactional<?> property = (Property.Transactional<?>) f + .getPropertyDataSource(); + if (property == null) { + throw new CommitException("Property \"" + + fieldToPropertyId.get(f) + + "\" not bound to datasource."); + } + property.startTransaction(); } try { firePreCommitEvent(); @@ -1095,4 +1103,18 @@ public class FieldGroup implements Serializable { } return memberFieldInOrder; } + + /** + * Clears the value of all fields. + * + * @since + */ + public void clear() { + for (Field<?> f : getFields()) { + if (f instanceof AbstractField) { + ((AbstractField) f).clear(); + } + } + + } } diff --git a/server/src/com/vaadin/data/util/BeanItem.java b/server/src/com/vaadin/data/util/BeanItem.java index ac3ef86434..12d9b23d0a 100644 --- a/server/src/com/vaadin/data/util/BeanItem.java +++ b/server/src/com/vaadin/data/util/BeanItem.java @@ -214,13 +214,75 @@ public class BeanItem<BT> extends PropertysetItem { } BeanInfo info = Introspector.getBeanInfo(beanClass); - propertyDescriptors.addAll(Arrays.asList(info - .getPropertyDescriptors())); + propertyDescriptors.addAll(getPropertyDescriptors(info)); return propertyDescriptors; } else { BeanInfo info = Introspector.getBeanInfo(beanClass); - return Arrays.asList(info.getPropertyDescriptors()); + return getPropertyDescriptors(info); + } + } + + // Workaround for Java6 bug JDK-6788525. Do nothing for JDK7+. + private static List<PropertyDescriptor> getPropertyDescriptors( + BeanInfo beanInfo) { + PropertyDescriptor[] descriptors = beanInfo.getPropertyDescriptors(); + List<PropertyDescriptor> result = new ArrayList<PropertyDescriptor>( + 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; } } diff --git a/server/src/com/vaadin/data/util/converter/DefaultConverterFactory.java b/server/src/com/vaadin/data/util/converter/DefaultConverterFactory.java index fdf858a528..26613c5d02 100644 --- a/server/src/com/vaadin/data/util/converter/DefaultConverterFactory.java +++ b/server/src/com/vaadin/data/util/converter/DefaultConverterFactory.java @@ -110,6 +110,8 @@ public class DefaultConverterFactory implements ConverterFactory { return new StringToBooleanConverter(); } else if (Date.class.isAssignableFrom(sourceType)) { return new StringToDateConverter(); + } else if (Enum.class.isAssignableFrom(sourceType)) { + return new StringToEnumConverter(); } else { return null; } diff --git a/server/src/com/vaadin/data/util/converter/StringToEnumConverter.java b/server/src/com/vaadin/data/util/converter/StringToEnumConverter.java new file mode 100644 index 0000000000..a1328d831c --- /dev/null +++ b/server/src/com/vaadin/data/util/converter/StringToEnumConverter.java @@ -0,0 +1,97 @@ +/* + * 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.converter; + +import java.util.EnumSet; +import java.util.Locale; + +/** + * A converter that converts from {@link String} to an {@link Enum} and back. + * <p> + * Designed to provide nice human readable strings for {@link Enum} classes + * where the constants are named SOME_UPPERCASE_WORDS. Will not necessarily work + * correctly for other cases. + * </p> + * + * @author Vaadin Ltd + * @since + */ +public class StringToEnumConverter implements Converter<String, Enum> { + + @Override + public Enum convertToModel(String value, Class<? extends Enum> targetType, + Locale locale) throws ConversionException { + if (value == null) { + return null; + } + if (locale == null) { + locale = Locale.getDefault(); + } + + // Foo -> FOO + // Foo bar -> FOO_BAR + String result = value.replace(" ", "_").toUpperCase(locale); + try { + return Enum.valueOf(targetType, result); + } catch (IllegalArgumentException 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; + } + } + + // Fallback did not work either, re-throw original exception so user + // knows what went wrong + throw new ConversionException(ee); + } + } + + @Override + public String convertToPresentation(Enum value, + Class<? extends String> targetType, Locale locale) + throws ConversionException { + if (value == null) { + return null; + } + if (locale == null) { + locale = Locale.getDefault(); + } + + String enumString = value.toString(); + // FOO -> Foo + // FOO_BAR -> Foo bar + // _FOO -> _foo + String result = enumString.substring(0, 1).toUpperCase(locale); + result += enumString.substring(1).toLowerCase(locale).replace('_', ' '); + + return result; + } + + @Override + public Class<Enum> getModelType() { + return Enum.class; + } + + @Override + public Class<String> getPresentationType() { + return String.class; + } + +} diff --git a/server/src/com/vaadin/server/AbstractDeploymentConfiguration.java b/server/src/com/vaadin/server/AbstractDeploymentConfiguration.java new file mode 100644 index 0000000000..43d4570d90 --- /dev/null +++ b/server/src/com/vaadin/server/AbstractDeploymentConfiguration.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.server; + +/** + * An abstract base class for DeploymentConfiguration implementations. This + * class provides default implementation for common config properties. + * + * @author Vaadin Ltd + */ +public abstract class AbstractDeploymentConfiguration implements + DeploymentConfiguration { + + @Override + public String getUIClassName() { + return getApplicationOrSystemProperty(VaadinSession.UI_PARAMETER, null); + } + + @Override + public String getUIProviderClassName() { + return getApplicationOrSystemProperty( + Constants.SERVLET_PARAMETER_UI_PROVIDER, null); + } + + @Override + public String getWidgetset(String defaultValue) { + return getApplicationOrSystemProperty(Constants.PARAMETER_WIDGETSET, + defaultValue); + } + + @Override + public String getResourcesPath() { + return getApplicationOrSystemProperty( + Constants.PARAMETER_VAADIN_RESOURCES, null); + } + + @Override + public String getClassLoaderName() { + return getApplicationOrSystemProperty("ClassLoader", null); + } +} diff --git a/server/src/com/vaadin/server/BootstrapHandler.java b/server/src/com/vaadin/server/BootstrapHandler.java index 0605d6a2b8..f0666f63fc 100644 --- a/server/src/com/vaadin/server/BootstrapHandler.java +++ b/server/src/com/vaadin/server/BootstrapHandler.java @@ -350,7 +350,6 @@ public abstract class BootstrapHandler extends SynchronizedRequestHandler { /*- Add classnames; * .v-app * .v-app-loading - * .v-app-<simpleName for app class> *- Additionally added from javascript: * <themeName, remove non-alphanum> */ @@ -362,6 +361,8 @@ public abstract class BootstrapHandler extends SynchronizedRequestHandler { mainDiv.attr("id", context.getAppId()); mainDiv.addClass("v-app"); mainDiv.addClass(context.getThemeName()); + mainDiv.addClass(context.getUIClass().getSimpleName() + .toLowerCase(Locale.ENGLISH)); if (style != null && style.length() != 0) { mainDiv.attr("style", style); } @@ -401,7 +402,7 @@ public abstract class BootstrapHandler extends SynchronizedRequestHandler { builder.append("//<![CDATA[\n"); builder.append("if (!window.vaadin) alert(" + JsonUtil.quote("Failed to load the bootstrap javascript: " - + bootstrapLocation) + ");\n"); + + bootstrapLocation) + ");\n"); appendMainScriptTagContents(context, builder); @@ -501,7 +502,8 @@ public abstract class BootstrapHandler extends SynchronizedRequestHandler { if (systemMessages.getAuthenticationErrorURL() == null) { authErrMsg.put("url", Json.createNull()); } else { - authErrMsg.put("url", systemMessages.getAuthenticationErrorURL()); + authErrMsg.put("url", + systemMessages.getAuthenticationErrorURL()); } appConfig.put("authErrMsg", authErrMsg); diff --git a/server/src/com/vaadin/server/BrowserWindowOpener.java b/server/src/com/vaadin/server/BrowserWindowOpener.java index 44679fbfbb..8cc1faa728 100644 --- a/server/src/com/vaadin/server/BrowserWindowOpener.java +++ b/server/src/com/vaadin/server/BrowserWindowOpener.java @@ -126,6 +126,55 @@ public class BrowserWindowOpener extends AbstractExtension { } /** + * Sets the provided URL {@code url} for this instance. The {@code url} will + * be opened in a new browser window/tab when the extended component is + * clicked. + * + * @param url + * URL to open + */ + public void setUrl(String url) { + setResource(new ExternalResource(url)); + } + + /** + * Sets the provided {@code resource} for this instance. The + * {@code resource} will be opened in a new browser window/tab when the + * extended component is clicked. + * + * @param resource + * resource to open + */ + public void setResource(Resource resource) { + setResource(BrowserWindowOpenerState.locationResource, resource); + } + + /** + * Returns the resource for this instance. + * + * @return resource to open browser window + */ + public Resource getResource() { + return getResource(BrowserWindowOpenerState.locationResource); + } + + /** + * Returns the URL for this BrowserWindowOpener instance. Returns + * {@code null} if this instance is not URL resource based (a non URL based + * resource has been set for it). + * + * @return URL to open in the new browser window/tab when the extended + * component is clicked + */ + public String getUrl() { + Resource resource = getResource(); + if (resource instanceof ExternalResource) { + return ((ExternalResource) resource).getURL(); + } + return null; + } + + /** * Sets the target window name that will be used. If a window has already * been opened with the same name, the contents of that window will be * replaced instead of opening a new window. If the name is diff --git a/server/src/com/vaadin/server/Constants.java b/server/src/com/vaadin/server/Constants.java index 2b868c12a6..fc0bf7381a 100644 --- a/server/src/com/vaadin/server/Constants.java +++ b/server/src/com/vaadin/server/Constants.java @@ -162,4 +162,6 @@ public interface Constants { static final String PORTAL_PARAMETER_VAADIN_WIDGETSET = "vaadin.widgetset"; static final String PORTAL_PARAMETER_VAADIN_RESOURCE_PATH = "vaadin.resources.path"; static final String PORTAL_PARAMETER_VAADIN_THEME = "vaadin.theme"; + + static final String PORTLET_CONTEXT = "PORTLET_CONTEXT"; } diff --git a/server/src/com/vaadin/server/DefaultDeploymentConfiguration.java b/server/src/com/vaadin/server/DefaultDeploymentConfiguration.java index fd14c3cd3f..22d5210eaa 100644 --- a/server/src/com/vaadin/server/DefaultDeploymentConfiguration.java +++ b/server/src/com/vaadin/server/DefaultDeploymentConfiguration.java @@ -29,7 +29,8 @@ import com.vaadin.shared.communication.PushMode; * @author Vaadin Ltd * @since 7.0.0 */ -public class DefaultDeploymentConfiguration implements DeploymentConfiguration { +public class DefaultDeploymentConfiguration extends + AbstractDeploymentConfiguration { /** * Default value for {@link #getResourceCacheTime()} = {@value} . */ diff --git a/server/src/com/vaadin/server/DefaultUIProvider.java b/server/src/com/vaadin/server/DefaultUIProvider.java index 2a1a59dbe6..38525fc020 100644 --- a/server/src/com/vaadin/server/DefaultUIProvider.java +++ b/server/src/com/vaadin/server/DefaultUIProvider.java @@ -24,15 +24,9 @@ public class DefaultUIProvider extends UIProvider { public Class<? extends UI> getUIClass(UIClassSelectionEvent event) { VaadinRequest request = event.getRequest(); - Object uiClassNameObj = request - .getService() - .getDeploymentConfiguration() - .getApplicationOrSystemProperty(VaadinSession.UI_PARAMETER, - null); - - if (uiClassNameObj instanceof String) { - String uiClassName = uiClassNameObj.toString(); - + String uiClassName = request.getService().getDeploymentConfiguration() + .getUIClassName(); + if (uiClassName != null) { ClassLoader classLoader = request.getService().getClassLoader(); try { Class<? extends UI> uiClass = Class.forName(uiClassName, true, diff --git a/server/src/com/vaadin/server/DeploymentConfiguration.java b/server/src/com/vaadin/server/DeploymentConfiguration.java index fcfeecc31f..3124729773 100644 --- a/server/src/com/vaadin/server/DeploymentConfiguration.java +++ b/server/src/com/vaadin/server/DeploymentConfiguration.java @@ -163,6 +163,38 @@ public interface DeploymentConfiguration extends Serializable { String defaultValue); /** + * Gets UI class configuration option value. + * + * @return UI class name + */ + public String getUIClassName(); + + /** + * Gets UI provider class configuration option value. + * + * @return UI class name + */ + public String getUIProviderClassName(); + + /** + * Gets Widgetset configuration option value. {@code defaultValue} is + * returned if widgetset parameter is not configured. + * + * @return UI class name + */ + public String getWidgetset(String defaultValue); + + /** + * Gets resources path configuration option value. + */ + public String getResourcesPath(); + + /** + * Gets class loader configuration option value. + */ + public String getClassLoaderName(); + + /** * Returns to legacy Property.toString() mode used. See * {@link AbstractProperty#isLegacyToStringEnabled()} for more information. * diff --git a/server/src/com/vaadin/server/DragAndDropService.java b/server/src/com/vaadin/server/DragAndDropService.java index c21f27de97..c0c3eebca3 100644 --- a/server/src/com/vaadin/server/DragAndDropService.java +++ b/server/src/com/vaadin/server/DragAndDropService.java @@ -38,6 +38,7 @@ import com.vaadin.shared.communication.SharedState; import com.vaadin.shared.ui.dd.DragEventType; import com.vaadin.ui.Component; import com.vaadin.ui.UI; + import elemental.json.JsonObject; public class DragAndDropService implements VariableOwner, ClientConnector { @@ -64,7 +65,7 @@ public class DragAndDropService implements VariableOwner, ClientConnector { final Component sourceComponent = (Component) variables .get("component"); - if (sourceComponent != null && !sourceComponent.isEnabled()) { + if (sourceComponent != null && !sourceComponent.isConnectorEnabled()) { // source component not supposed to be enabled getLogger().warning( "Client dropped from " + sourceComponent @@ -83,7 +84,7 @@ public class DragAndDropService implements VariableOwner, ClientConnector { DropTarget dropTarget = (DropTarget) owner; - if (!dropTarget.isEnabled()) { + if (!dropTarget.isConnectorEnabled()) { getLogger() .warning( "Client dropped on " + owner diff --git a/server/src/com/vaadin/server/Page.java b/server/src/com/vaadin/server/Page.java index 3acea97c0f..3ddf4862b2 100644 --- a/server/src/com/vaadin/server/Page.java +++ b/server/src/com/vaadin/server/Page.java @@ -485,14 +485,14 @@ public class Page implements Serializable { } private void addListener(Class<?> eventType, Object target, Method method) { - if (eventRouter == null) { + if (!hasEventRouter()) { eventRouter = new EventRouter(); } eventRouter.addListener(eventType, target, method); } private void removeListener(Class<?> eventType, Object target, Method method) { - if (eventRouter != null) { + if (hasEventRouter()) { eventRouter.removeListener(eventType, target, method); } } @@ -599,7 +599,7 @@ public class Page implements Serializable { } private void fireEvent(EventObject event) { - if (eventRouter != null) { + if (hasEventRouter()) { eventRouter.fireEvent(event); } } @@ -776,8 +776,8 @@ public class Page implements Serializable { BrowserWindowResizeListener resizeListener) { removeListener(BrowserWindowResizeEvent.class, resizeListener, BROWSER_RESIZE_METHOD); - getState(true).hasResizeListeners = eventRouter - .hasListeners(BrowserWindowResizeEvent.class); + getState(true).hasResizeListeners = hasEventRouter() + && eventRouter.hasListeners(BrowserWindowResizeEvent.class); } /** @@ -1242,4 +1242,7 @@ public class Page implements Serializable { return state; } + private boolean hasEventRouter() { + return eventRouter != null; + } } diff --git a/server/src/com/vaadin/server/ServletPortletHelper.java b/server/src/com/vaadin/server/ServletPortletHelper.java index 2ec747ba3a..197d9fe416 100644 --- a/server/src/com/vaadin/server/ServletPortletHelper.java +++ b/server/src/com/vaadin/server/ServletPortletHelper.java @@ -130,8 +130,7 @@ public class ServletPortletHelper implements Serializable { public static void initDefaultUIProvider(VaadinSession session, VaadinService vaadinService) throws ServiceException { String uiProperty = vaadinService.getDeploymentConfiguration() - .getApplicationOrSystemProperty(VaadinSession.UI_PARAMETER, - null); + .getUIClassName(); // Add provider for UI parameter first to give it lower priority // (providers are FILO) @@ -141,8 +140,7 @@ public class ServletPortletHelper implements Serializable { } String uiProviderProperty = vaadinService.getDeploymentConfiguration() - .getApplicationOrSystemProperty( - Constants.SERVLET_PARAMETER_UI_PROVIDER, null); + .getUIProviderClassName(); // Then add custom UI provider if defined if (uiProviderProperty != null) { UIProvider uiProvider = getUIProvider(uiProviderProperty, diff --git a/server/src/com/vaadin/server/VaadinPortletService.java b/server/src/com/vaadin/server/VaadinPortletService.java index 2b290b4cc4..cff024672c 100644 --- a/server/src/com/vaadin/server/VaadinPortletService.java +++ b/server/src/com/vaadin/server/VaadinPortletService.java @@ -124,9 +124,7 @@ public class VaadinPortletService extends VaadinService { @Override public String getConfiguredWidgetset(VaadinRequest request) { - String widgetset = getDeploymentConfiguration() - .getApplicationOrSystemProperty( - VaadinPortlet.PARAMETER_WIDGETSET, null); + String widgetset = getDeploymentConfiguration().getWidgetset(null); if (widgetset == null) { widgetset = getParameter(request, @@ -162,7 +160,11 @@ public class VaadinPortletService extends VaadinService { String staticFileLocation = getParameter(request, Constants.PORTAL_PARAMETER_VAADIN_RESOURCE_PATH, "/html"); - return trimTrailingSlashes(staticFileLocation); + if (Constants.PORTLET_CONTEXT.equals(staticFileLocation)) { + return request.getContextPath(); + } else{ + return trimTrailingSlashes(staticFileLocation); + } } private PortletContext getPortletContext() { diff --git a/server/src/com/vaadin/server/VaadinService.java b/server/src/com/vaadin/server/VaadinService.java index 8fd6da8dee..4d8e7e9bc9 100644 --- a/server/src/com/vaadin/server/VaadinService.java +++ b/server/src/com/vaadin/server/VaadinService.java @@ -155,7 +155,7 @@ public abstract class VaadinService implements Serializable { this.deploymentConfiguration = deploymentConfiguration; final String classLoaderName = getDeploymentConfiguration() - .getApplicationOrSystemProperty("ClassLoader", null); + .getClassLoaderName(); if (classLoaderName != null) { try { final Class<?> classLoaderClass = getClass().getClassLoader() @@ -448,7 +448,7 @@ public abstract class VaadinService implements Serializable { */ public void fireSessionDestroy(VaadinSession vaadinSession) { final VaadinSession session = vaadinSession; - session.accessSynchronously(new Runnable() { + session.access(new Runnable() { @Override public void run() { if (session.getState() == State.CLOSED) { diff --git a/server/src/com/vaadin/server/VaadinServletService.java b/server/src/com/vaadin/server/VaadinServletService.java index a4ff3943c9..8946ac4fae 100644 --- a/server/src/com/vaadin/server/VaadinServletService.java +++ b/server/src/com/vaadin/server/VaadinServletService.java @@ -118,9 +118,7 @@ public class VaadinServletService extends VaadinService { VaadinServletRequest servletRequest = (VaadinServletRequest) request; String staticFileLocation; // if property is defined in configurations, use that - staticFileLocation = getDeploymentConfiguration() - .getApplicationOrSystemProperty( - VaadinServlet.PARAMETER_VAADIN_RESOURCES, null); + staticFileLocation = getDeploymentConfiguration().getResourcesPath(); if (staticFileLocation != null) { return staticFileLocation; } @@ -159,8 +157,7 @@ public class VaadinServletService extends VaadinService { @Override public String getConfiguredWidgetset(VaadinRequest request) { - return getDeploymentConfiguration().getApplicationOrSystemProperty( - VaadinServlet.PARAMETER_WIDGETSET, + return getDeploymentConfiguration().getWidgetset( VaadinServlet.DEFAULT_WIDGETSET); } diff --git a/server/src/com/vaadin/server/VaadinSession.java b/server/src/com/vaadin/server/VaadinSession.java index f93cb8e070..e5d63a6961 100644 --- a/server/src/com/vaadin/server/VaadinSession.java +++ b/server/src/com/vaadin/server/VaadinSession.java @@ -721,6 +721,9 @@ public class VaadinSession implements HttpSessionBindingListener, Serializable { * {@link InheritableThreadLocal}). In other cases, (e.g. from background * threads started in some other way), the current session is not * automatically defined. + * <p> + * The session is stored using a weak reference to avoid leaking memory in + * case it is not explicitly cleared. * * @return the current session instance if available, otherwise * <code>null</code> @@ -741,9 +744,12 @@ public class VaadinSession implements HttpSessionBindingListener, Serializable { * The application developer can also use this method to define the current * session outside the normal request handling and treads started from * request handling threads, e.g. when initiating custom background threads. - * </p> + * <p> + * The session is stored using a weak reference to avoid leaking memory in + * case it is not explicitly cleared. * * @param session + * the session to set as current * * @see #getCurrent() * @see ThreadLocal diff --git a/server/src/com/vaadin/server/WebBrowser.java b/server/src/com/vaadin/server/WebBrowser.java index 5ec4e6b19c..cb5979d612 100644 --- a/server/src/com/vaadin/server/WebBrowser.java +++ b/server/src/com/vaadin/server/WebBrowser.java @@ -264,6 +264,7 @@ public class WebBrowser implements Serializable { * @return true if the user is using Windows Phone, false if the user is not * using Windows Phone or if no information on the browser is * present + * @since 7.3.2 */ public boolean isWindowsPhone() { return browserDetails.isWindowsPhone(); @@ -290,6 +291,26 @@ public class WebBrowser implements Serializable { } /** + * Tests if the browser is run on IPhone. + * + * @return true if run on IPhone false if the user is not using IPhone or if + * no information on the browser is present + */ + public boolean isIPhone() { + return browserDetails.isIPhone(); + } + + /** + * Tests if the browser is run on IPad. + * + * @return true if run on IPad false if the user is not using IPad or if no + * information on the browser is present + */ + public boolean isIPad() { + return browserDetails.isIPad(); + } + + /** * Returns the browser-reported TimeZone offset in milliseconds from GMT. * This includes possible daylight saving adjustments, to figure out which * TimeZone the user actually might be in, see diff --git a/server/src/com/vaadin/server/communication/AtmospherePushConnection.java b/server/src/com/vaadin/server/communication/AtmospherePushConnection.java index f8ef360eda..a274fbbb9b 100644 --- a/server/src/com/vaadin/server/communication/AtmospherePushConnection.java +++ b/server/src/com/vaadin/server/communication/AtmospherePushConnection.java @@ -269,6 +269,7 @@ public class AtmospherePushConnection implements PushConnection { // the resource is already resumed; this is a bit hacky and should // be implemented in a better way in 7.2. resource = null; + state = State.DISCONNECTED; return; } diff --git a/server/src/com/vaadin/ui/AbstractField.java b/server/src/com/vaadin/ui/AbstractField.java index 47ac953319..369ad1253c 100644 --- a/server/src/com/vaadin/ui/AbstractField.java +++ b/server/src/com/vaadin/ui/AbstractField.java @@ -1402,7 +1402,8 @@ public abstract class AbstractField<T> extends AbstractComponent implements valueLocale); T newinternalValue = convertFromModel(convertedValue); if (!SharedUtil.equals(getInternalValue(), newinternalValue)) { - setConvertedValue(convertedValue); + setInternalValue(newinternalValue); + fireValueChange(false); } } } @@ -1512,6 +1513,19 @@ public abstract class AbstractField<T> extends AbstractComponent implements } /** + * 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 + */ + public void clear() { + setValue(null); + } + + /** * Is automatic, visible validation enabled? * * If automatic validation is enabled, any validators connected to this diff --git a/server/src/com/vaadin/ui/Button.java b/server/src/com/vaadin/ui/Button.java index 76b82aa034..e58ad7bee5 100644 --- a/server/src/com/vaadin/ui/Button.java +++ b/server/src/com/vaadin/ui/Button.java @@ -359,7 +359,7 @@ public class Button extends AbstractComponent implements * No action is taken is the button is disabled. */ public void click() { - if (isEnabled() && !isReadOnly()) { + if (isConnectorEnabled() && !isReadOnly()) { fireClick(); } } diff --git a/server/src/com/vaadin/ui/Calendar.java b/server/src/com/vaadin/ui/Calendar.java index 59dfceec9b..63ac9fe35c 100644 --- a/server/src/com/vaadin/ui/Calendar.java +++ b/server/src/com/vaadin/ui/Calendar.java @@ -890,17 +890,21 @@ public class Calendar extends AbstractComponent implements * @see #isEventClickAllowed() */ protected boolean isClientChangeAllowed() { - return !isReadOnly() && isEnabled(); + return !isReadOnly(); } /** - * Is the user allowed to trigger click events + * Is the user allowed to trigger click events. Returns {@code true} by + * default. Subclass can override this method to disallow firing event + * clicks got from the client side. * * @return true if the client is allowed to click events * @see #isClientChangeAllowed() + * @deprecated Override {@link #fireEventClick(Integer)} instead. */ + @Deprecated protected boolean isEventClickAllowed() { - return isEnabled(); + return true; } /** diff --git a/server/src/com/vaadin/ui/CustomLayout.java b/server/src/com/vaadin/ui/CustomLayout.java index 7f1aa1ce46..f4fe7fa66c 100644 --- a/server/src/com/vaadin/ui/CustomLayout.java +++ b/server/src/com/vaadin/ui/CustomLayout.java @@ -16,6 +16,7 @@ package com.vaadin.ui; +import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; @@ -101,22 +102,20 @@ public class CustomLayout extends AbstractLayout implements LegacyComponent { protected void initTemplateContentsFromInputStream( InputStream templateStream) throws IOException { - InputStreamReader reader = new InputStreamReader(templateStream, - "UTF-8"); - StringBuilder b = new StringBuilder(BUFFER_SIZE); - - char[] cbuf = new char[BUFFER_SIZE]; - int offset = 0; - - while (true) { - int nrRead = reader.read(cbuf, offset, BUFFER_SIZE); - b.append(cbuf, 0, nrRead); - if (nrRead < BUFFER_SIZE) { - break; + BufferedReader reader = new BufferedReader(new InputStreamReader( + templateStream, "UTF-8")); + StringBuilder builder = new StringBuilder(BUFFER_SIZE); + try { + char[] cbuf = new char[BUFFER_SIZE]; + int nRead; + while ((nRead = reader.read(cbuf, 0, BUFFER_SIZE)) > 0) { + builder.append(cbuf, 0, nRead); } + } finally { + reader.close(); } - setTemplateContents(b.toString()); + setTemplateContents(builder.toString()); } @Override diff --git a/server/src/com/vaadin/ui/DateField.java b/server/src/com/vaadin/ui/DateField.java index e88d767bc9..030bd5f6c2 100644 --- a/server/src/com/vaadin/ui/DateField.java +++ b/server/src/com/vaadin/ui/DateField.java @@ -815,17 +815,15 @@ public class DateField extends AbstractField<Date> implements // Clone the instance final Calendar newCal = (Calendar) calendar.clone(); - // Assigns the current time tom calendar. - final Date currentDate = getValue(); - if (currentDate != null) { - newCal.setTime(currentDate); - } - final TimeZone currentTimeZone = getTimeZone(); if (currentTimeZone != null) { newCal.setTimeZone(currentTimeZone); } + final Date currentDate = getValue(); + if (currentDate != null) { + newCal.setTime(currentDate); + } return newCal; } diff --git a/server/src/com/vaadin/ui/Form.java b/server/src/com/vaadin/ui/Form.java index 391ee45536..48239b09e3 100644 --- a/server/src/com/vaadin/ui/Form.java +++ b/server/src/com/vaadin/ui/Form.java @@ -1064,7 +1064,7 @@ public class Form extends AbstractField<Object> implements Item.Editor, for (Object id : itemPropertyIds) { if (id != null) { Field<?> field = getField(id); - if (field.isEnabled() && !field.isReadOnly()) { + if (field.isConnectorEnabled() && !field.isReadOnly()) { return field; } } @@ -1202,6 +1202,21 @@ public class Form extends AbstractField<Object> implements Item.Editor, return true; } + /* + * (non-Javadoc) + * + * @see com.vaadin.ui.AbstractField#clear() + */ + @Override + public void clear() { + for (Iterator<Field<?>> i = fields.values().iterator(); i.hasNext();) { + Field<?> f = i.next(); + if (f instanceof AbstractField) { + ((AbstractField<?>) f).clear(); + } + } + } + /** * Adding validators directly to form is not supported. * diff --git a/server/src/com/vaadin/ui/Table.java b/server/src/com/vaadin/ui/Table.java index 3a1ab82be5..34d48a9b18 100644 --- a/server/src/com/vaadin/ui/Table.java +++ b/server/src/com/vaadin/ui/Table.java @@ -422,61 +422,11 @@ public class Table extends AbstractSelect implements Action.Container, private Object currentPageFirstItemId = null; /* - * This class stores the hashcode and scroll position of the previous - * container so that the scroll position can be restored if the same - * container is removed and then re-added. This resolves #14581. + * If all rows get removed then scroll position of the previous container + * can be restored after re-adding/replacing rows via addAll(). This + * resolves #14581. */ - protected static class ScrollPositionRepairOnReAddAllRowsData implements - Serializable { - - private static final long serialVersionUID = 1L; - // current page first item index (to repair scroll position) - private int itemIndex; - /* - * hashCode() of container before it was cleared via - * container.removeAllItems(); - */ - private int containerHashCode; - - public ScrollPositionRepairOnReAddAllRowsData() { - itemIndex = -1; - containerHashCode = -1; - } - - public int getItemId() { - return itemIndex; - } - - public void setItemId(int itemId) { - itemIndex = itemId; - } - - public void resetItemId() { - itemIndex = -1; - } - - public void setContainerData(Container container) { - if (container != null) { - containerHashCode = container.hashCode(); - } else { - containerHashCode = -1; - } - } - - public boolean needRepairScrollPosition(Container newContainer) { - return (itemIndex != -1) && isTheSameContainer(newContainer); - } - - private boolean isTheSameContainer(Container newContainer) { - boolean theSame = false; - if (newContainer != null) { - theSame = (newContainer.hashCode() == containerHashCode); - } - return theSame; - } - } - - private final ScrollPositionRepairOnReAddAllRowsData scrollRepairOnReAdding = new ScrollPositionRepairOnReAddAllRowsData(); + private int repairOnReAddAllRowsDataScrollPositionItemIndex = -1; /** * Index of the first item on the current page. @@ -2734,10 +2684,6 @@ public class Table extends AbstractSelect implements Action.Container, newDataSource = new IndexedContainer(); } - if (scrollRepairOnReAdding != null) { - // this is important if container is set for table after filling - scrollRepairOnReAdding.setContainerData(newDataSource); - } Collection<Object> generated; if (columnGenerators != null) { generated = columnGenerators.keySet(); @@ -4571,14 +4517,22 @@ public class Table extends AbstractSelect implements Action.Container, int currentFirstItemIndex = getCurrentPageFirstItemIndex(); if (event.getContainer().size() == 0) { - scrollRepairOnReAdding.setItemId(getCurrentPageFirstItemIndex()); + repairOnReAddAllRowsDataScrollPositionItemIndex = getCurrentPageFirstItemIndex(); } else { - if (scrollRepairOnReAdding.needRepairScrollPosition(event - .getContainer())) { - currentFirstItemIndex = scrollRepairOnReAdding.getItemId(); + if (repairOnReAddAllRowsDataScrollPositionItemIndex != -1) { + currentFirstItemIndex = repairOnReAddAllRowsDataScrollPositionItemIndex; + /* + * Reset repairOnReAddAllRowsDataScrollPositionItemIndex. + * + * Next string should be commented (removed) if we want to have + * possibility to restore scroll position during adding items to + * container one by one via add() but not only addAll(). The + * problem in this case: we cannot track what happened between + * add() and add()... So it is ambiguous where to stop restore + * scroll position. + */ + repairOnReAddAllRowsDataScrollPositionItemIndex = -1; } - scrollRepairOnReAdding.resetItemId(); - scrollRepairOnReAdding.setContainerData(event.getContainer()); } // ensure that page still has first item in page, ignore buffer refresh diff --git a/server/src/com/vaadin/ui/UI.java b/server/src/com/vaadin/ui/UI.java index d67e08828a..438b086ec2 100644 --- a/server/src/com/vaadin/ui/UI.java +++ b/server/src/com/vaadin/ui/UI.java @@ -719,9 +719,11 @@ public abstract class UI extends AbstractSingleComponentContainer implements * The application developer can also use this method to define the current * UI outside the normal request handling, e.g. when initiating custom * background threads. - * </p> + * <p> + * The UI is stored using a weak reference to avoid leaking memory in case + * it is not explicitly cleared. * - * @param uI + * @param ui * the UI to register as the current UI * * @see #getCurrent() @@ -735,6 +737,9 @@ public abstract class UI extends AbstractSingleComponentContainer implements * Gets the currently used UI. The current UI is automatically defined when * processing requests to the server. In other cases, (e.g. from background * threads), the current UI is not automatically defined. + * <p> + * The UI is stored using a weak reference to avoid leaking memory in case + * it is not explicitly cleared. * * @return the current UI instance if available, otherwise <code>null</code> * diff --git a/server/src/com/vaadin/ui/Upload.java b/server/src/com/vaadin/ui/Upload.java index 1c953779e4..693bd74dbf 100644 --- a/server/src/com/vaadin/ui/Upload.java +++ b/server/src/com/vaadin/ui/Upload.java @@ -1150,23 +1150,25 @@ public class Upload extends AbstractComponent implements Component.Focusable, fireUploadSuccess(event.getFileName(), event.getMimeType(), event.getContentLength()); endUpload(); - markAsDirty(); } @Override public void streamingFailed(StreamingErrorEvent event) { - Exception exception = event.getException(); - if (exception instanceof NoInputStreamException) { - fireNoInputStream(event.getFileName(), - event.getMimeType(), 0); - } else if (exception instanceof NoOutputStreamException) { - fireNoOutputStream(event.getFileName(), - event.getMimeType(), 0); - } else { - fireUploadInterrupted(event.getFileName(), - event.getMimeType(), 0, exception); + try { + Exception exception = event.getException(); + if (exception instanceof NoInputStreamException) { + fireNoInputStream(event.getFileName(), + event.getMimeType(), 0); + } else if (exception instanceof NoOutputStreamException) { + fireNoOutputStream(event.getFileName(), + event.getMimeType(), 0); + } else { + fireUploadInterrupted(event.getFileName(), + event.getMimeType(), 0, exception); + } + } finally { + endUpload(); } - endUpload(); } }; } diff --git a/server/tests/src/com/vaadin/data/DefaultFieldGroupFieldFactoryTest.java b/server/tests/src/com/vaadin/data/DefaultFieldGroupFieldFactoryTest.java index a5fee5175e..bbf74bfb21 100644 --- a/server/tests/src/com/vaadin/data/DefaultFieldGroupFieldFactoryTest.java +++ b/server/tests/src/com/vaadin/data/DefaultFieldGroupFieldFactoryTest.java @@ -15,6 +15,7 @@ */ package com.vaadin.data; +import java.lang.reflect.Constructor; import java.util.Date; import org.junit.Assert; @@ -34,7 +35,30 @@ public class DefaultFieldGroupFieldFactoryTest { @Before public void setupFieldFactory() { - fieldFactory = new DefaultFieldGroupFieldFactory(); + fieldFactory = DefaultFieldGroupFieldFactory.get(); + } + + @Test + public void noPublicConstructor() { + Class<DefaultFieldGroupFieldFactory> clazz = DefaultFieldGroupFieldFactory.class; + Constructor<?>[] constructors = clazz.getConstructors(); + Assert.assertEquals( + "DefaultFieldGroupFieldFactory contains public constructors", + 0, constructors.length); + } + + @Test + public void testSameInstance() { + DefaultFieldGroupFieldFactory factory1 = DefaultFieldGroupFieldFactory + .get(); + DefaultFieldGroupFieldFactory factory2 = DefaultFieldGroupFieldFactory + .get(); + Assert.assertTrue( + "DefaultFieldGroupFieldFactory.get() method returns different instances", + factory1 == factory2); + Assert.assertNotNull( + "DefaultFieldGroupFieldFactory.get() method returns null", + factory1); } @Test diff --git a/server/tests/src/com/vaadin/data/fieldgroup/FieldGroupDate.java b/server/tests/src/com/vaadin/data/fieldgroup/FieldGroupDate.java index 07e36b93f9..fd5d47b32f 100644 --- a/server/tests/src/com/vaadin/data/fieldgroup/FieldGroupDate.java +++ b/server/tests/src/com/vaadin/data/fieldgroup/FieldGroupDate.java @@ -78,4 +78,20 @@ public class FieldGroupDate { Assert.assertEquals(PopupDateField.class, f.getClass()); } + @Test + public void clearFields() { + PopupDateField sqlDate = new PopupDateField(); + PopupDateField javaDate = new PopupDateField(); + fieldGroup.bind(sqlDate, "sqlDate"); + fieldGroup.bind(javaDate, "javaDate"); + + Assert.assertEquals(new Date(2010, 5, 7), javaDate.getValue()); + Assert.assertEquals(new Date(2011, 6, 8), sqlDate.getValue()); + + fieldGroup.clear(); + Assert.assertEquals(null, javaDate.getValue()); + Assert.assertEquals(null, sqlDate.getValue()); + + } + } diff --git a/server/tests/src/com/vaadin/data/fieldgroup/FieldGroupExceptionTest.java b/server/tests/src/com/vaadin/data/fieldgroup/FieldGroupExceptionTest.java new file mode 100644 index 0000000000..636162de54 --- /dev/null +++ b/server/tests/src/com/vaadin/data/fieldgroup/FieldGroupExceptionTest.java @@ -0,0 +1,33 @@ +/* + * 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.fieldgroup; + +import org.junit.Test; + +import com.vaadin.data.fieldgroup.FieldGroup.CommitException; +import com.vaadin.ui.PopupDateField; + +public class FieldGroupExceptionTest { + + @Test(expected = CommitException.class) + public void testUnboundCommitException() throws CommitException { + FieldGroup fieldGroup = new FieldGroup(); + PopupDateField dateField = new PopupDateField(); + fieldGroup.bind(dateField, "date"); + fieldGroup.commit(); + } + +} diff --git a/server/tests/src/com/vaadin/data/util/BeanItemContainerGenerator.java b/server/tests/src/com/vaadin/data/util/BeanItemContainerGenerator.java new file mode 100644 index 0000000000..7400f0efcf --- /dev/null +++ b/server/tests/src/com/vaadin/data/util/BeanItemContainerGenerator.java @@ -0,0 +1,153 @@ +package com.vaadin.data.util; + +import java.util.Date; +import java.util.concurrent.atomic.AtomicLong; + +import org.junit.Ignore; + +@Ignore +public class BeanItemContainerGenerator { + + public static class PortableRandom { + private final static long multiplier = 0x5DEECE66DL; + private final static long addend = 0xBL; + private final static long mask = (1L << 48) - 1; + private AtomicLong seed; + + public PortableRandom(long seed) { + this.seed = new AtomicLong(0L); + setSeed(seed); + } + + synchronized public void setSeed(long seed) { + seed = (seed ^ multiplier) & mask; + this.seed.set(seed); + } + + public int nextInt(int n) { + if (n <= 0) { + throw new IllegalArgumentException("n must be positive"); + } + + if ((n & -n) == n) { + return (int) ((n * (long) next(31)) >> 31); + } + + int bits, val; + do { + bits = next(31); + val = bits % n; + } while (bits - val + (n - 1) < 0); + return val; + } + + protected int next(int bits) { + long oldseed, nextseed; + AtomicLong seed = this.seed; + do { + oldseed = seed.get(); + nextseed = (oldseed * multiplier + addend) & mask; + } while (!seed.compareAndSet(oldseed, nextseed)); + return (int) (nextseed >>> (48 - bits)); + } + + public boolean nextBoolean() { + return next(1) != 0; + } + + } + + public static BeanItemContainer<TestBean> createContainer(int size) { + return createContainer(size, new Date().getTime()); + } + + public static BeanItemContainer<TestBean> createContainer(int size, + long seed) { + + BeanItemContainer<TestBean> container = new BeanItemContainer<TestBean>( + TestBean.class); + PortableRandom r = new PortableRandom(seed); + for (int i = 0; i < size; i++) { + container.addBean(new TestBean(r)); + } + + return container; + + } + + public static class TestBean { + private String name, address, city, country; + private int age, shoesize; + + public int getAge() { + return age; + } + + public void setAge(int age) { + this.age = age; + } + + public int getShoesize() { + return shoesize; + } + + public void setShoesize(int shoesize) { + this.shoesize = shoesize; + } + + public TestBean(PortableRandom r) { + age = r.nextInt(100) + 5; + shoesize = r.nextInt(10) + 35; + name = createRandomString(r, r.nextInt(5) + 5); + address = createRandomString(r, r.nextInt(15) + 5) + " " + + r.nextInt(100) + 1; + city = createRandomString(r, r.nextInt(7) + 3); + if (r.nextBoolean()) { + country = createRandomString(r, r.nextInt(4) + 4); + } + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getAddress() { + return address; + } + + public void setAddress(String address) { + this.address = address; + } + + public String getCity() { + return city; + } + + public void setCity(String city) { + this.city = city; + } + + public String getCountry() { + return country; + } + + public void setCountry(String country) { + this.country = country; + } + + } + + public static String createRandomString(PortableRandom r, int len) { + StringBuilder b = new StringBuilder(); + for (int i = 0; i < len; i++) { + b.append((char) (r.nextInt('z' - 'a') + 'a')); + } + + return b.toString(); + } + +} diff --git a/server/tests/src/com/vaadin/data/util/BeanItemTest.java b/server/tests/src/com/vaadin/data/util/BeanItemTest.java index b458856826..89c56b1779 100644 --- a/server/tests/src/com/vaadin/data/util/BeanItemTest.java +++ b/server/tests/src/com/vaadin/data/util/BeanItemTest.java @@ -13,6 +13,8 @@ import junit.framework.TestCase; import org.junit.Assert; +import com.vaadin.data.Property; + /** * Test BeanItem specific features. * @@ -122,6 +124,31 @@ public class BeanItemTest extends TestCase { public int getSuper2(); } + protected static class Generic<T> { + + public T getProperty() { + return null; + } + + public void setProperty(T t) { + throw new UnsupportedOperationException(); + } + } + + protected static class SubClass extends Generic<String> { + + @Override + // Has a bridged method + public String getProperty() { + return ""; + } + + @Override + // Has a bridged method + public void setProperty(String t) { + } + } + protected static interface MySubInterface extends MySuperInterface, MySuperInterface2 { public int getSub(); @@ -331,4 +358,18 @@ public class BeanItemTest extends TestCase { Assert.assertEquals(6, item.getItemPropertyIds().size()); Assert.assertEquals(null, item.getItemProperty("myname")); } + + public void testOverridenGenericMethods() { + BeanItem<SubClass> item = new BeanItem<SubClass>(new SubClass()); + + Property<?> property = item.getItemProperty("property"); + Assert.assertEquals("Unexpected class for property type", String.class, + property.getType()); + + Assert.assertEquals("Unexpected property value", "", + property.getValue()); + + // Should not be exception + property.setValue(null); + } } diff --git a/server/tests/src/com/vaadin/server/AbstractDeploymentConfigurationTest.java b/server/tests/src/com/vaadin/server/AbstractDeploymentConfigurationTest.java new file mode 100644 index 0000000000..7370bd3fac --- /dev/null +++ b/server/tests/src/com/vaadin/server/AbstractDeploymentConfigurationTest.java @@ -0,0 +1,157 @@ +/* + * 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.server; + +import java.util.Properties; +import java.util.UUID; + +import org.junit.Assert; +import org.junit.Test; + +import com.vaadin.shared.communication.PushMode; + +/** + * Test for {@link AbstractDeploymentConfiguration} + * + * @author Vaadin Ltd + */ +public class AbstractDeploymentConfigurationTest { + + @Test + public void getUIClass_returnsUIParameterPropertyValue() { + String ui = UUID.randomUUID().toString(); + DeploymentConfiguration config = getConfig(VaadinSession.UI_PARAMETER, + ui); + Assert.assertEquals("Unexpected UI class configuration option value", + ui, config.getUIClassName()); + } + + @Test + public void getUIProviderClass_returnsUIProviderPropertyValue() { + String uiProvider = UUID.randomUUID().toString(); + DeploymentConfiguration config = getConfig( + Constants.SERVLET_PARAMETER_UI_PROVIDER, uiProvider); + Assert.assertEquals( + "Unexpected UI providerclass configuration option value", + uiProvider, config.getUIProviderClassName()); + } + + @Test + public void getWidgetset_returnsWidgetsetProviderPropertyValue() { + String widgetset = UUID.randomUUID().toString(); + DeploymentConfiguration config = getConfig( + Constants.PARAMETER_WIDGETSET, widgetset); + Assert.assertEquals("Unexpected widgetset configuration option value", + widgetset, config.getWidgetset(null)); + } + + @Test + public void getWidgetset_noWidgetsetPropertyValue_returnsProvidedDefaultValue() { + DeploymentConfiguration config = getConfig(null, null); + String widgetset = UUID.randomUUID().toString(); + Assert.assertEquals("Unexpected widgetset configuration option value", + widgetset, config.getWidgetset(widgetset)); + } + + @Test + public void getResourcesPath_returnsResourcesPathPropertyValue() { + String resources = UUID.randomUUID().toString(); + DeploymentConfiguration config = getConfig( + Constants.PARAMETER_VAADIN_RESOURCES, resources); + Assert.assertEquals( + "Unexpected resources path configuration option value", + resources, config.getResourcesPath()); + } + + @Test + public void getClassLoader_returnsClassloaderPropertyValue() { + String classLoader = UUID.randomUUID().toString(); + DeploymentConfiguration config = getConfig("ClassLoader", classLoader); + Assert.assertEquals( + "Unexpected classLoader configuration option value", + classLoader, config.getClassLoaderName()); + } + + private DeploymentConfiguration getConfig(String property, String value) { + Properties props = new Properties(); + if (property != null) { + props.put(property, value); + } + return new DeploymentConfigImpl(props); + } + + private static class DeploymentConfigImpl extends + AbstractDeploymentConfiguration { + + private Properties properties; + + DeploymentConfigImpl(Properties props) { + properties = props; + } + + @Override + public boolean isProductionMode() { + return false; + } + + @Override + public boolean isXsrfProtectionEnabled() { + return false; + } + + @Override + public boolean isSyncIdCheckEnabled() { + return false; + } + + @Override + public int getResourceCacheTime() { + return 0; + } + + @Override + public int getHeartbeatInterval() { + return 0; + } + + @Override + public boolean isCloseIdleSessions() { + return false; + } + + @Override + public PushMode getPushMode() { + return null; + } + + @Override + public Properties getInitParameters() { + return null; + } + + @Override + public String getApplicationOrSystemProperty(String propertyName, + String defaultValue) { + return properties.getProperty(propertyName, defaultValue); + } + + @Override + public LegacyProperyToStringMode getLegacyPropertyToStringMode() { + return null; + } + + } +} diff --git a/server/tests/src/com/vaadin/server/BrowserWindowOpenerTest.java b/server/tests/src/com/vaadin/server/BrowserWindowOpenerTest.java new file mode 100644 index 0000000000..7c76f7d421 --- /dev/null +++ b/server/tests/src/com/vaadin/server/BrowserWindowOpenerTest.java @@ -0,0 +1,79 @@ +/* + * 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.server; + +import static org.junit.Assert.assertEquals; + +import org.easymock.EasyMock; +import org.junit.Assert; +import org.junit.Test; + +import com.vaadin.shared.communication.URLReference; +import com.vaadin.shared.ui.BrowserWindowOpenerState; + +/** + * + * @author Vaadin Ltd + */ +public class BrowserWindowOpenerTest { + + @Test + public void setResource_urlBasedOpener_resourceIsSetAndUrlIsNull() { + BrowserWindowOpener opener = new BrowserWindowOpener("url"); + + StreamResource resource = EasyMock.createMock(StreamResource.class); + opener.setResource(resource); + + assertEquals("Unexpected resource is got on getResource() method", + resource, opener.getResource()); + Assert.assertNull("Unexpected resource is got on getUrl() method", + opener.getUrl()); + + URLReference ref = opener.getState(false).resources + .get(BrowserWindowOpenerState.locationResource); + Assert.assertTrue( + "Url reference in the state is not ResourceReference", + ref instanceof ResourceReference); + Assert.assertEquals("Unexpected resource saved in state", resource, + ((ResourceReference) ref).getResource()); + } + + @Test + public void setUrl_urlBasedOpener_urlIsSet() { + BrowserWindowOpener opener = new BrowserWindowOpener("url"); + + String url = "newUrl"; + opener.setUrl(url); + + assertEquals("Unexpected URL is got on getURL() method", url, + opener.getUrl()); + Assert.assertNotNull( + "Unexpected resource is got on getResource() method", + opener.getResource()); + + URLReference ref = opener.getState(false).resources + .get(BrowserWindowOpenerState.locationResource); + Assert.assertTrue( + "Url reference in the state is not ResourceReference", + ref instanceof ResourceReference); + Resource resource = ((ResourceReference) ref).getResource(); + Assert.assertTrue("Resource reference is not ExternalResource", + resource instanceof ExternalResource); + Assert.assertEquals("Unexpected URL in resource saved in state", url, + ((ExternalResource) resource).getURL()); + } + +} diff --git a/server/tests/src/com/vaadin/server/DragAndDropServiceTest.java b/server/tests/src/com/vaadin/server/DragAndDropServiceTest.java new file mode 100644 index 0000000000..d0cb0ca5a6 --- /dev/null +++ b/server/tests/src/com/vaadin/server/DragAndDropServiceTest.java @@ -0,0 +1,125 @@ +/* + * 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.server; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.logging.Level; +import java.util.logging.LogRecord; +import java.util.logging.Logger; +import java.util.logging.StreamHandler; + +import org.easymock.EasyMock; +import org.junit.Assert; +import org.junit.Test; + +import com.vaadin.event.dd.DropHandler; +import com.vaadin.event.dd.TargetDetails; +import com.vaadin.ui.AbstractComponent; + +/** + * Tests for {@link DragAndDropService}. + * + * @author Vaadin Ltd + */ +public class DragAndDropServiceTest { + + @Test + public void changeVariables_isSourceConnectorEnabledCalled() { + final List<Level> levels = new ArrayList<Level>(); + Logger.getLogger(DragAndDropService.class.getName()).addHandler( + new StreamHandler() { + @Override + public synchronized void publish(LogRecord record) { + levels.add(record.getLevel()); + } + }); + Map<String, Object> variables = new HashMap<String, Object>(); + final boolean[] isConnectorEnabledCalled = new boolean[1]; + AbstractComponent component = new AbstractComponent() { + @Override + public boolean isConnectorEnabled() { + isConnectorEnabledCalled[0] = true; + return false; + } + }; + variables.put("component", component); + + DragAndDropService service = new DragAndDropService( + EasyMock.createMock(VaadinSession.class)); + service.changeVariables(null, variables); + + Assert.assertTrue("isConnectorEnabled() method is not called", + isConnectorEnabledCalled[0]); + Assert.assertTrue("No warning on drop from disabled source", + levels.contains(Level.WARNING)); + + } + + @Test + public void changeVariables_isTargetConnectorEnabledCalled() { + final List<Level> levels = new ArrayList<Level>(); + Logger.getLogger(DragAndDropService.class.getName()).addHandler( + new StreamHandler() { + @Override + public void publish(LogRecord record) { + levels.add(record.getLevel()); + } + }); + Map<String, Object> variables = new HashMap<String, Object>(); + TestDropTarget target = new TestDropTarget(); + variables.put("dhowner", target); + + DragAndDropService service = new DragAndDropService( + EasyMock.createMock(VaadinSession.class)); + service.changeVariables(null, variables); + + Assert.assertTrue("isConnectorEnabled() method is not called", + target.isConnectorEnabledCalled()); + Assert.assertTrue("No warning on drop to disabled target", + levels.contains(Level.WARNING)); + + } + + private static class TestDropTarget extends AbstractComponent implements + com.vaadin.event.dd.DropTarget { + @Override + public boolean isConnectorEnabled() { + isConnectorEnabledCalled = true; + return false; + } + + @Override + public DropHandler getDropHandler() { + return null; + } + + @Override + public TargetDetails translateDropTargetDetails( + Map<String, Object> clientVariables) { + return null; + } + + boolean isConnectorEnabledCalled() { + return isConnectorEnabledCalled; + } + + private boolean isConnectorEnabledCalled; + + } +} diff --git a/server/tests/src/com/vaadin/server/PageTest.java b/server/tests/src/com/vaadin/server/PageTest.java new file mode 100644 index 0000000000..b782b1f67d --- /dev/null +++ b/server/tests/src/com/vaadin/server/PageTest.java @@ -0,0 +1,92 @@ +/* + * 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.server; + +import org.easymock.EasyMock; +import org.junit.Assert; +import org.junit.Test; + +import com.vaadin.server.Page.BrowserWindowResizeEvent; +import com.vaadin.server.Page.BrowserWindowResizeListener; +import com.vaadin.shared.ui.ui.PageState; +import com.vaadin.ui.UI; + +/** + * + * Tests for {@link Page} + * + * @author Vaadin Ltd + */ +public class PageTest { + + @Test + public void removeBrowserWindowResizeListener_listenerIsAttached_listenerRemoved() { + Page page = new Page(EasyMock.createMock(UI.class), + EasyMock.createMock(PageState.class)); + + TestBrowserWindowResizeListener listener = new TestBrowserWindowResizeListener(); + page.addBrowserWindowResizeListener(listener); + page.removeBrowserWindowResizeListener(listener); + + page.updateBrowserWindowSize(0, 0, true); + + Assert.assertFalse("Listener is called after removal", + listener.isCalled()); + } + + @Test + public void removeBrowserWindowResizeListener_listenerIsNotAttached_stateIsUpdated() { + TestPage page = new TestPage(EasyMock.createMock(UI.class), + EasyMock.createMock(PageState.class)); + + BrowserWindowResizeListener listener = EasyMock + .createMock(BrowserWindowResizeListener.class); + page.removeBrowserWindowResizeListener(listener); + + Assert.assertFalse( + "Page state 'hasResizeListeners' property has wrong value", + page.getState(false).hasResizeListeners); + } + + private static class TestPage extends Page { + + public TestPage(UI uI, PageState state) { + super(uI, state); + } + + @Override + protected PageState getState(boolean markAsDirty) { + return super.getState(markAsDirty); + } + + } + + private static class TestBrowserWindowResizeListener implements + BrowserWindowResizeListener { + + @Override + public void browserWindowResized(BrowserWindowResizeEvent event) { + isCalled = true; + } + + public boolean isCalled() { + return isCalled; + } + + private boolean isCalled; + + } +} diff --git a/server/tests/src/com/vaadin/server/VaadinPortletServiceTests.java b/server/tests/src/com/vaadin/server/VaadinPortletServiceTests.java index f7a69c2edb..0e094bfabb 100644 --- a/server/tests/src/com/vaadin/server/VaadinPortletServiceTests.java +++ b/server/tests/src/com/vaadin/server/VaadinPortletServiceTests.java @@ -86,10 +86,7 @@ public class VaadinPortletServiceTests { } private void mockWidgetsetConfiguration(String widgetset) { - when( - conf.getApplicationOrSystemProperty( - Constants.PARAMETER_WIDGETSET, null)).thenReturn( - widgetset); + when(conf.getWidgetset(null)).thenReturn(widgetset); } @Test diff --git a/server/tests/src/com/vaadin/server/VaadinSessionTest.java b/server/tests/src/com/vaadin/server/VaadinSessionTest.java index b710ee483f..fa7e892066 100644 --- a/server/tests/src/com/vaadin/server/VaadinSessionTest.java +++ b/server/tests/src/com/vaadin/server/VaadinSessionTest.java @@ -15,7 +15,9 @@ */ package com.vaadin.server; +import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; import javax.servlet.ServletConfig; @@ -30,6 +32,7 @@ import org.junit.Test; import com.vaadin.server.ClientConnector.DetachEvent; import com.vaadin.server.ClientConnector.DetachListener; +import com.vaadin.server.communication.UIInitHandler; import com.vaadin.ui.UI; import com.vaadin.util.CurrentInstance; @@ -43,9 +46,11 @@ public class VaadinSessionTest { private WrappedSession mockWrappedSession; private VaadinServletRequest vaadinRequest; private UI ui; + private Lock httpSessionLock; @Before public void setup() throws Exception { + httpSessionLock = new ReentrantLock(); mockServletConfig = new MockServletConfig(); mockServlet = new VaadinServlet(); mockServlet.init(mockServletConfig); @@ -60,11 +65,30 @@ public class VaadinSessionTest { @Override public Object getAttribute(String name) { - String lockAttribute = mockService.getServiceName() + ".lock"; - if (lockAttribute.equals(name)) { - return lock; + Object res; + try { + Thread.sleep(100); // for deadlock testing + org.junit.Assert.assertTrue("Deadlock detected", + httpSessionLock.tryLock(5, TimeUnit.SECONDS)); // simulates + // servlet + // container's + // session + // locking + String lockAttribute = mockService.getServiceName() + + ".lock"; + if (lockAttribute.equals(name)) { + res = lock; + } else if ("com.vaadin.server.VaadinSession.Mock Servlet" + .equals(name)) { + res = session; + } else { + res = super.getAttribute(name); + } + httpSessionLock.unlock(); + } catch (InterruptedException e) { + throw new RuntimeException(e); } - return super.getAttribute(name); + return res; } }; @@ -91,12 +115,26 @@ public class VaadinSessionTest { EasyMock.createMock(HttpServletRequest.class), mockService) { @Override public String getParameter(String name) { - if ("theme".equals(name)) { + if ("theme".equals(name) || "restartApplication".equals(name) + || "ignoreRestart".equals(name) + || "closeApplication".equals(name)) { return null; + } else if (UIInitHandler.BROWSER_DETAILS_PARAMETER.equals(name)) { + return "1"; } - return super.getParameter(name); } + + @Override + public String getMethod() { + return "POST"; + } + + @Override + public WrappedSession getWrappedSession(boolean allowSessionCreation) { + return mockWrappedSession; + } + }; ui.doInit(vaadinRequest, session.getNextUIid(), null); @@ -106,8 +144,43 @@ public class VaadinSessionTest { } + /** + * This reproduces #14452 situation with deadlock - see diagram + */ + @Test + public void testInvalidationDeadlock() { + + // this simulates servlet container's session invalidation from another + // thread + new Thread(new Runnable() { + @Override + public void run() { + try { + Thread.sleep(150); // delay selected so that VaadinSession + // will be already locked by the main + // thread + // when we get here + httpSessionLock.lock();// simulating servlet container's + // session lock + mockService.fireSessionDestroy(session); + httpSessionLock.unlock(); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + } + }).start(); + + try { + mockService.findVaadinSession(vaadinRequest); + } catch (Exception e) { + throw new RuntimeException(e); + } + + } + @Test - public void threadLocalsAfterUnderlyingSessionTimeout() { + public void threadLocalsAfterUnderlyingSessionTimeout() + throws InterruptedException { final AtomicBoolean detachCalled = new AtomicBoolean(false); ui.addDetachListener(new DetachListener() { @@ -123,11 +196,17 @@ public class VaadinSessionTest { }); session.valueUnbound(EasyMock.createMock(HttpSessionBindingEvent.class)); + mockService.runPendingAccessTasks(session); // as soon as we changed + // session.accessSynchronously + // to session.access in + // VaadinService.fireSessionDestroy, + // we need to run the + // pending task ourselves Assert.assertTrue(detachCalled.get()); } @Test - public void threadLocalsAfterSessionDestroy() { + public void threadLocalsAfterSessionDestroy() throws InterruptedException { final AtomicBoolean detachCalled = new AtomicBoolean(false); ui.addDetachListener(new DetachListener() { @Override @@ -143,6 +222,12 @@ public class VaadinSessionTest { CurrentInstance.clearAll(); session.close(); mockService.cleanupSession(session); + mockService.runPendingAccessTasks(session); // as soon as we changed + // session.accessSynchronously + // to session.access in + // VaadinService.fireSessionDestroy, + // we need to run the + // pending task ourselves Assert.assertTrue(detachCalled.get()); } diff --git a/server/tests/src/com/vaadin/tests/data/converter/TestStringToEnumConverter.java b/server/tests/src/com/vaadin/tests/data/converter/TestStringToEnumConverter.java new file mode 100644 index 0000000000..2b19395c08 --- /dev/null +++ b/server/tests/src/com/vaadin/tests/data/converter/TestStringToEnumConverter.java @@ -0,0 +1,59 @@ +package com.vaadin.tests.data.converter; + +import junit.framework.TestCase; + +import com.vaadin.data.util.converter.Converter; +import com.vaadin.data.util.converter.ReverseConverter; +import com.vaadin.data.util.converter.StringToEnumConverter; + +public class TestStringToEnumConverter extends TestCase { + + public static enum FooEnum { + VALUE1, SOME_VALUE, FOO_BAR_BAZ, Bar, nonStandardCase, _HUGH; + } + + StringToEnumConverter converter = new StringToEnumConverter(); + Converter<Enum, String> reverseConverter = new ReverseConverter<Enum, String>( + converter); + + public void testNullConversion() { + assertEquals(null, converter.convertToModel(null, Enum.class, null)); + } + + public void testReverseNullConversion() { + assertEquals(null, + reverseConverter.convertToModel(null, String.class, null)); + } + + public void testValueConversion() { + assertEquals(FooEnum.VALUE1, + converter.convertToModel("Value1", FooEnum.class, null)); + assertEquals(FooEnum.SOME_VALUE, + converter.convertToModel("Some value", FooEnum.class, null)); + assertEquals(FooEnum.FOO_BAR_BAZ, + converter.convertToModel("Foo bar baz", FooEnum.class, null)); + assertEquals(FooEnum.Bar, + converter.convertToModel("Bar", FooEnum.class, null)); + assertEquals(FooEnum.nonStandardCase, converter.convertToModel( + "Nonstandardcase", FooEnum.class, null)); + assertEquals(FooEnum._HUGH, + converter.convertToModel("_hugh", FooEnum.class, null)); + } + + public void testReverseValueConversion() { + assertEquals("Value1", reverseConverter.convertToModel(FooEnum.VALUE1, + String.class, null)); + assertEquals("Some value", reverseConverter.convertToModel( + FooEnum.SOME_VALUE, String.class, null)); + assertEquals("Foo bar baz", reverseConverter.convertToModel( + FooEnum.FOO_BAR_BAZ, String.class, null)); + assertEquals("Bar", reverseConverter.convertToModel(FooEnum.Bar, + String.class, null)); + assertEquals("Nonstandardcase", reverseConverter.convertToModel( + FooEnum.nonStandardCase, String.class, null)); + assertEquals("_hugh", reverseConverter.convertToModel(FooEnum._HUGH, + String.class, null)); + + } + +} diff --git a/server/tests/src/com/vaadin/tests/server/TestClassesSerializable.java b/server/tests/src/com/vaadin/tests/server/TestClassesSerializable.java index 63f79504ff..1220209479 100644 --- a/server/tests/src/com/vaadin/tests/server/TestClassesSerializable.java +++ b/server/tests/src/com/vaadin/tests/server/TestClassesSerializable.java @@ -16,6 +16,7 @@ import java.util.jar.JarFile; import junit.framework.TestCase; +import org.junit.Ignore; import org.junit.Test; public class TestClassesSerializable extends TestCase { @@ -95,15 +96,8 @@ public class TestClassesSerializable extends TestCase { if (cls.isAnnotation() || cls.isSynthetic()) { continue; } - // Don't add classes that have a @Test annotation on any methods - boolean testPresent = false; - for (Method method : cls.getMethods()) { - if (method.isAnnotationPresent(Test.class)) { - testPresent = true; - break; - } - } - if (testPresent) { + // Don't add classes that have a @Ignore annotation on the class + if (isTestClass(cls)) { continue; } @@ -152,6 +146,27 @@ public class TestClassesSerializable extends TestCase { } } + private boolean isTestClass(Class<?> cls) { + // @Ignore is used on test util classes + if (cls.isAnnotationPresent(Ignore.class)) { + return true; + } + + if (cls.getEnclosingClass() != null + && isTestClass(cls.getEnclosingClass())) { + return true; + } + + // Test classes with a @Test annotation on some method + for (Method method : cls.getMethods()) { + if (method.isAnnotationPresent(Test.class)) { + return true; + } + } + + return false; + } + /** * Lists all class path entries by splitting the class path string. * diff --git a/server/tests/src/com/vaadin/tests/server/component/button/ButtonClick.java b/server/tests/src/com/vaadin/tests/server/component/button/ButtonClick.java index f82bbfe907..b41e93900f 100644 --- a/server/tests/src/com/vaadin/tests/server/component/button/ButtonClick.java +++ b/server/tests/src/com/vaadin/tests/server/component/button/ButtonClick.java @@ -1,11 +1,12 @@ package com.vaadin.tests.server.component.button; -import static org.junit.Assert.assertEquals; - +import org.junit.Assert; import org.junit.Test; +import com.vaadin.server.VaadinRequest; import com.vaadin.ui.Button; import com.vaadin.ui.Button.ClickEvent; +import com.vaadin.ui.UI; /** * Tests the public click() method. @@ -16,7 +17,7 @@ public class ButtonClick { @Test public void testClick() { getButton().click(); - assertEquals(clicked, true); + Assert.assertTrue("Button doesn't fire clicks", clicked); } @Test @@ -24,7 +25,7 @@ public class ButtonClick { Button b = getButton(); b.setEnabled(false); b.click(); - assertEquals(clicked, false); + Assert.assertFalse("Disabled button fires click events", clicked); } @Test @@ -32,17 +33,50 @@ public class ButtonClick { Button b = getButton(); b.setReadOnly(true); b.click(); - assertEquals(clicked, false); + Assert.assertFalse("Read only button fires click events", clicked); + } + + @Test + public void testClickConnectorDisabled() { + Button b = new Button() { + @Override + public boolean isConnectorEnabled() { + return false; + } + }; + UI ui = createUI(); + b.setParent(ui); + addClickListener(b); + b.click(); + Assert.assertFalse("Button with disabled connector fires click events", + clicked); } private Button getButton() { Button b = new Button(); - b.addListener(new Button.ClickListener() { + UI ui = createUI(); + b.setParent(ui); + addClickListener(b); + return b; + } + + private UI createUI() { + UI ui = new UI() { + + @Override + protected void init(VaadinRequest request) { + } + }; + return ui; + } + + private void addClickListener(Button b) { + clicked = false; + b.addClickListener(new Button.ClickListener() { @Override public void buttonClick(ClickEvent ev) { clicked = true; } }); - return b; } } diff --git a/server/tests/src/com/vaadin/tests/server/component/calendar/CalendarBasics.java b/server/tests/src/com/vaadin/tests/server/component/calendar/CalendarBasics.java index ab2bc7c8c0..773631642a 100644 --- a/server/tests/src/com/vaadin/tests/server/component/calendar/CalendarBasics.java +++ b/server/tests/src/com/vaadin/tests/server/component/calendar/CalendarBasics.java @@ -24,6 +24,7 @@ import java.util.GregorianCalendar; import java.util.Locale; import java.util.TimeZone; +import org.junit.Assert; import org.junit.Test; import com.vaadin.ui.Calendar; @@ -207,4 +208,29 @@ public class CalendarBasics { assertEquals(23, calendar.getLastVisibleHourOfDay()); } + @Test + public void isClientChangeAllowed_connectorEnabled() { + TestCalendar calendar = new TestCalendar(true); + Assert.assertTrue( + "Calendar with enabled connector doesn't allow client change", + calendar.isClientChangeAllowed()); + } + + private static class TestCalendar extends Calendar { + TestCalendar(boolean connectorEnabled) { + isConnectorEnabled = connectorEnabled; + } + + @Override + public boolean isConnectorEnabled() { + return isConnectorEnabled; + } + + @Override + public boolean isClientChangeAllowed() { + return super.isClientChangeAllowed(); + } + + private final boolean isConnectorEnabled; + } } diff --git a/server/tests/src/com/vaadin/tests/server/component/customlayout/CustomLayoutTest.java b/server/tests/src/com/vaadin/tests/server/component/customlayout/CustomLayoutTest.java new file mode 100644 index 0000000000..4d327e70a6 --- /dev/null +++ b/server/tests/src/com/vaadin/tests/server/component/customlayout/CustomLayoutTest.java @@ -0,0 +1,148 @@ +/* + * 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.component.customlayout; + +import java.io.ByteArrayInputStream; +import java.io.FilterInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import java.nio.charset.Charset; +import java.util.ArrayList; +import java.util.List; +import java.util.Locale; + +import org.junit.Assert; +import org.junit.Test; + +import com.vaadin.ui.CustomLayout; + +/** + * + * Tests for {@link CustomLayout} + * + * @author Vaadin Ltd + */ +public class CustomLayoutTest { + + @Test + public void ctor_inputStreamProvided_inputStreamIsRead() + throws IOException, IllegalArgumentException, + IllegalAccessException { + Integer buffer = getBufferSize(); + StringBuilder builder = new StringBuilder(); + for (int i = 0; i < buffer; i++) { + builder.append('a'); + } + byte[] bytes = builder.toString().getBytes(Charset.forName("UTF-8")); + ByteArrayInputStream inputStream = new ByteArrayInputStream(bytes); + InputStreamImpl stream = new InputStreamImpl(inputStream, buffer / 2); + new CustomLayout(stream); + + Assert.assertTrue("Stream is not closed in CustomLayout CTOR ", + stream.isClosed()); + Assert.assertEquals("Number of read bytes is incorrect", bytes.length, + stream.getCount()); + } + + private Integer getBufferSize() throws IllegalAccessException { + Field[] fields = CustomLayout.class.getDeclaredFields(); + List<Field> list = new ArrayList<Field>(fields.length); + for (Field field : fields) { + if ((field.getModifiers() & Modifier.STATIC) > 0) { + list.add(field); + } + } + Field field = null; + if (list.size() == 1) { + field = list.get(0); + } else { + for (Field fld : list) { + if (fld.getName().toLowerCase(Locale.ENGLISH) + .startsWith("buffer")) { + field = fld; + break; + } + } + } + Assert.assertNotNull( + "Unable to find default buffer size in CustomLayout class", + field); + field.setAccessible(true); + Integer buffer = (Integer) field.get(null); + return buffer; + } + + private static class InputStreamImpl extends FilterInputStream { + + InputStreamImpl(InputStream inputStream, int maxArrayLength) { + super(inputStream); + this.maxArrayLength = maxArrayLength; + } + + @Override + public int read() throws IOException { + int read = super.read(); + if (read != -1) { + readCount++; + } + return read; + } + + @Override + public int read(byte[] b) throws IOException { + if (b.length > maxArrayLength) { + return read(b, 0, maxArrayLength); + } + int count = super.read(b); + if (count != -1) { + readCount += count; + } + return count; + } + + @Override + public int read(byte[] b, int off, int len) throws IOException { + if (len > maxArrayLength) { + return read(b, off, maxArrayLength); + } + int count = super.read(b, off, len); + if (count != -1) { + readCount += count; + } + return count; + } + + @Override + public void close() throws IOException { + isClosed = true; + super.close(); + } + + int getCount() { + return readCount; + } + + boolean isClosed() { + return isClosed; + } + + private int readCount; + private boolean isClosed; + private int maxArrayLength; + } +} diff --git a/server/tests/src/com/vaadin/tests/server/component/form/FormTest.java b/server/tests/src/com/vaadin/tests/server/component/form/FormTest.java new file mode 100644 index 0000000000..2075f7b115 --- /dev/null +++ b/server/tests/src/com/vaadin/tests/server/component/form/FormTest.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.server.component.form; + +import org.junit.Assert; +import org.junit.Test; + +import com.vaadin.ui.Form; +import com.vaadin.ui.TextField; + +/** + * Test for {@link Form}. + * + * @author Vaadin Ltd + */ +public class FormTest { + + @Test + public void testFocus() { + Form form = new Form(); + final boolean firstFieldIsFocused[] = new boolean[1]; + TextField field1 = new TextField() { + @Override + public boolean isConnectorEnabled() { + return false; + } + + @Override + public void focus() { + firstFieldIsFocused[0] = true; + } + }; + + final boolean secondFieldIsFocused[] = new boolean[1]; + TextField field2 = new TextField() { + @Override + public boolean isConnectorEnabled() { + return true; + } + + @Override + public void focus() { + secondFieldIsFocused[0] = true; + } + }; + form.addField("a", field1); + form.addField("b", field2); + form.focus(); + + Assert.assertTrue("Field with enabled connector is not focused", + secondFieldIsFocused[0]); + Assert.assertFalse("Field with disabled connector is focused", + firstFieldIsFocused[0]); + } +} diff --git a/server/tests/src/com/vaadin/tests/server/component/upload/UploadTest.java b/server/tests/src/com/vaadin/tests/server/component/upload/UploadTest.java new file mode 100644 index 0000000000..2132829c0a --- /dev/null +++ b/server/tests/src/com/vaadin/tests/server/component/upload/UploadTest.java @@ -0,0 +1,101 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.tests.server.component.upload; + +import org.junit.Assert; +import org.junit.Test; + +import com.vaadin.server.StreamVariable; +import com.vaadin.server.StreamVariable.StreamingErrorEvent; +import com.vaadin.ui.Upload; + +/** + * + * @author Vaadin Ltd + */ +public class UploadTest { + + @Test + public void getStreamVariable_streamingFailed_endUploadIsCalled() { + TestUpload upload = new TestUpload(); + upload.startUpload(); + StreamVariable variable = upload.getStreamVariable(); + try { + variable.streamingFailed(new TestStreamingErrorEvent()); + } catch (Exception e) { + } + Assert.assertFalse(upload.isUploading()); + } + + private static class TestStreamingErrorEvent implements StreamingErrorEvent { + + @Override + public String getFileName() { + return null; + } + + @Override + public String getMimeType() { + return null; + } + + @Override + public long getContentLength() { + return 0; + } + + @Override + public long getBytesReceived() { + return 0; + } + + @Override + public Exception getException() { + return new Exception(); + } + + } + + private static class TestUpload extends Upload { + + @Override + public StreamVariable getStreamVariable() { + return super.getStreamVariable(); + } + + @Override + protected void fireNoInputStream(String filename, String MIMEType, + long length) { + fireEvent(); + } + + @Override + protected void fireNoOutputStream(String filename, String MIMEType, + long length) { + fireEvent(); + } + + @Override + protected void fireUploadInterrupted(String filename, String MIMEType, + long length, Exception e) { + fireEvent(); + } + + private void fireEvent() { + throw new NullPointerException(); + } + } +} diff --git a/server/tests/src/com/vaadin/tests/util/MockDeploymentConfiguration.java b/server/tests/src/com/vaadin/tests/util/MockDeploymentConfiguration.java index fe7f9ba03e..8eceaea53f 100644 --- a/server/tests/src/com/vaadin/tests/util/MockDeploymentConfiguration.java +++ b/server/tests/src/com/vaadin/tests/util/MockDeploymentConfiguration.java @@ -4,10 +4,11 @@ import java.util.HashMap; import java.util.Map; import java.util.Properties; -import com.vaadin.server.DeploymentConfiguration; +import com.vaadin.server.AbstractDeploymentConfiguration; import com.vaadin.shared.communication.PushMode; -public class MockDeploymentConfiguration implements DeploymentConfiguration { +public class MockDeploymentConfiguration extends + AbstractDeploymentConfiguration { private boolean productionMode = false; private boolean xsrfProtectionEnabled = true; diff --git a/server/tests/src/com/vaadin/ui/TableTest.java b/server/tests/src/com/vaadin/ui/TableTest.java new file mode 100644 index 0000000000..86237abbe0 --- /dev/null +++ b/server/tests/src/com/vaadin/ui/TableTest.java @@ -0,0 +1,78 @@ +/* + * 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 java.util.Collection; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +import com.vaadin.data.util.BeanItemContainerGenerator; + +public class TableTest { + + Table table; + + @Before + public void init() { + table = new Table(); + } + + @Test + public void initiallyEmpty() { + Assert.assertTrue(table.isEmpty()); + } + + @Test + public void emptyAfterClearSingleSelect() { + table.setContainerDataSource(BeanItemContainerGenerator + .createContainer(100)); + Assert.assertTrue(table.isEmpty()); + Object first = table.getContainerDataSource().getItemIds().iterator() + .next(); + table.setValue(first); + Assert.assertEquals(first, table.getValue()); + Assert.assertFalse(table.isEmpty()); + table.clear(); + Assert.assertEquals(null, table.getValue()); + Assert.assertTrue(table.isEmpty()); + } + + @Test + public void emptyAfterClearMultiSelect() { + table.setMultiSelect(true); + table.setContainerDataSource(BeanItemContainerGenerator + .createContainer(100)); + + Assert.assertTrue(table.isEmpty()); + Assert.assertArrayEquals(new Object[] {}, + ((Collection) table.getValue()).toArray()); + + Object first = table.getContainerDataSource().getItemIds().iterator() + .next(); + table.select(first); + Assert.assertArrayEquals(new Object[] { first }, + ((Collection) table.getValue()).toArray()); + Assert.assertFalse(table.isEmpty()); + + table.clear(); + Assert.assertArrayEquals(new Object[] {}, + ((Collection) table.getValue()).toArray()); + Assert.assertTrue(table.isEmpty()); + } + +} diff --git a/server/tests/src/com/vaadin/ui/TextFieldTest.java b/server/tests/src/com/vaadin/ui/TextFieldTest.java new file mode 100644 index 0000000000..bfd452bd3b --- /dev/null +++ b/server/tests/src/com/vaadin/ui/TextFieldTest.java @@ -0,0 +1,48 @@ +/* + * 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 TextFieldTest { + + @Test + public void initiallyEmpty() { + TextField tf = new TextField(); + Assert.assertTrue(tf.isEmpty()); + } + + @Test + public void emptyAfterClearUsingPDS() { + TextField tf = new TextField(new ObjectProperty<String>("foo")); + Assert.assertFalse(tf.isEmpty()); + tf.clear(); + Assert.assertTrue(tf.isEmpty()); + } + + @Test + public void emptyAfterClear() { + TextField tf = new TextField(); + tf.setValue("foobar"); + Assert.assertFalse(tf.isEmpty()); + tf.clear(); + Assert.assertTrue(tf.isEmpty()); + } + +} |