diff options
author | Leif Åstrand <leif@vaadin.com> | 2013-09-03 10:07:22 +0300 |
---|---|---|
committer | Leif Åstrand <leif@vaadin.com> | 2013-09-03 10:07:22 +0300 |
commit | ce110b8b060d7c215f69a7e03c24ca80d88da037 (patch) | |
tree | b4209253abf876db9d2233abdba945ae96ae28a8 /server/src | |
parent | 261a3ba76a523d7e8d6b717f6f9d67eaef8c901f (diff) | |
parent | 11cdf93fedc9e693468d25092afba8172ce8ebf0 (diff) | |
download | vaadin-framework-ce110b8b060d7c215f69a7e03c24ca80d88da037.tar.gz vaadin-framework-ce110b8b060d7c215f69a7e03c24ca80d88da037.zip |
Merge changes from origin/7.1
d8b0b50 Always unlock the same session instance that was locked (#12481)
e6af0f0 Avoid leaking memory from inherited ThreadLocales. Fixes #12401
f7ee8fb Updated _trackMessageSize based on latest upstream version (#12468)
a24d391 Table ignores Container updates while painting (#12258)
7068d78 The colon in the calendar event caption is now also hideable. Fixes #12460
61dd8f7 Corrected typo in version variable (#12440)
476e0b8 Changed 'feature release' text to maintenance release (#12486)
faa2569 Updated browser versions
831747a Fix regression where empty RTA returns <br> (#12490)
cb8df75 Add deprecation message to unused constant
4c5bb0e Sets the locale in the test case. #12460
11cdf93 Excludes WeakValueMap from the serializable test #12401
Change-Id: Id7eeba06d14518c254ceb01e38e2441967932755
Diffstat (limited to 'server/src')
-rw-r--r-- | server/src/com/vaadin/server/AbstractClientConnector.java | 5 | ||||
-rw-r--r-- | server/src/com/vaadin/server/Constants.java | 5 | ||||
-rw-r--r-- | server/src/com/vaadin/server/FileDownloader.java | 6 | ||||
-rw-r--r-- | server/src/com/vaadin/ui/AbstractMedia.java | 6 | ||||
-rw-r--r-- | server/src/com/vaadin/ui/Table.java | 19 | ||||
-rw-r--r-- | server/src/com/vaadin/util/CurrentInstance.java | 2 | ||||
-rw-r--r-- | server/src/com/vaadin/util/WeakValueMap.java | 230 |
7 files changed, 266 insertions, 7 deletions
diff --git a/server/src/com/vaadin/server/AbstractClientConnector.java b/server/src/com/vaadin/server/AbstractClientConnector.java index 91a9e41522..a73ca3d985 100644 --- a/server/src/com/vaadin/server/AbstractClientConnector.java +++ b/server/src/com/vaadin/server/AbstractClientConnector.java @@ -625,7 +625,8 @@ public abstract class AbstractClientConnector implements ClientConnector, String[] parts = path.split("/", 2); String key = parts[0]; - getSession().lock(); + VaadinSession session = getSession(); + session.lock(); try { ConnectorResource resource = (ConnectorResource) getResource(key); if (resource == null) { @@ -633,7 +634,7 @@ public abstract class AbstractClientConnector implements ClientConnector, } stream = resource.getStream(); } finally { - getSession().unlock(); + session.unlock(); } stream.writeResponse(request, response); return true; diff --git a/server/src/com/vaadin/server/Constants.java b/server/src/com/vaadin/server/Constants.java index ab91ee021c..8c379abe06 100644 --- a/server/src/com/vaadin/server/Constants.java +++ b/server/src/com/vaadin/server/Constants.java @@ -146,6 +146,11 @@ public interface Constants { // Widget set parameter name static final String PARAMETER_WIDGETSET = "widgetset"; + /** + * @deprecated As of 7.1, this message is no longer used and might be + * removed from the code. + */ + @Deprecated static final String ERROR_NO_UI_FOUND = "No UIProvider returned a UI for the request."; static final String DEFAULT_THEME_NAME = "reindeer"; diff --git a/server/src/com/vaadin/server/FileDownloader.java b/server/src/com/vaadin/server/FileDownloader.java index 9b49ad8edd..bd7d9caafd 100644 --- a/server/src/com/vaadin/server/FileDownloader.java +++ b/server/src/com/vaadin/server/FileDownloader.java @@ -129,7 +129,9 @@ public class FileDownloader extends AbstractExtension { // Ignore if it isn't for us return false; } - getSession().lock(); + VaadinSession session = getSession(); + + session.lock(); DownloadStream stream; try { @@ -151,7 +153,7 @@ public class FileDownloader extends AbstractExtension { stream.setContentType("application/octet-stream;charset=UTF-8"); } } finally { - getSession().unlock(); + session.unlock(); } stream.writeResponse(request, response); return true; diff --git a/server/src/com/vaadin/ui/AbstractMedia.java b/server/src/com/vaadin/ui/AbstractMedia.java index 97947b568d..d7d593c29e 100644 --- a/server/src/com/vaadin/ui/AbstractMedia.java +++ b/server/src/com/vaadin/ui/AbstractMedia.java @@ -30,6 +30,7 @@ import com.vaadin.server.Resource; import com.vaadin.server.ResourceReference; import com.vaadin.server.VaadinRequest; import com.vaadin.server.VaadinResponse; +import com.vaadin.server.VaadinSession; import com.vaadin.shared.communication.URLReference; import com.vaadin.shared.ui.AbstractMediaState; import com.vaadin.shared.ui.MediaControl; @@ -90,7 +91,8 @@ public abstract class AbstractMedia extends AbstractComponent { DownloadStream stream; - getSession().lock(); + VaadinSession session = getSession(); + session.lock(); try { List<URLReference> sources = getState().sources; @@ -108,7 +110,7 @@ public abstract class AbstractMedia extends AbstractComponent { .getResource(reference); stream = resource.getStream(); } finally { - getSession().unlock(); + session.unlock(); } stream.writeResponse(request, response); diff --git a/server/src/com/vaadin/ui/Table.java b/server/src/com/vaadin/ui/Table.java index 3507e6b0a5..bd2b7828de 100644 --- a/server/src/com/vaadin/ui/Table.java +++ b/server/src/com/vaadin/ui/Table.java @@ -564,6 +564,8 @@ public class Table extends AbstractSelect implements Action.Container, private List<Throwable> exceptionsDuringCachePopulation = new ArrayList<Throwable>(); + private boolean isBeingPainted; + /* Table constructors */ /** @@ -3166,6 +3168,15 @@ public class Table extends AbstractSelect implements Action.Container, @Override public void paintContent(PaintTarget target) throws PaintException { + isBeingPainted = true; + try { + doPaintContent(target); + } finally { + isBeingPainted = false; + } + } + + private void doPaintContent(PaintTarget target) throws PaintException { /* * Body actions - Actions which has the target null and can be invoked * by right clicking on the table body. @@ -4394,6 +4405,10 @@ public class Table extends AbstractSelect implements Action.Container, @Override public void containerItemSetChange(Container.ItemSetChangeEvent event) { + if (isBeingPainted) { + return; + } + super.containerItemSetChange(event); // super method clears the key map, must inform client about this to @@ -4416,6 +4431,10 @@ public class Table extends AbstractSelect implements Action.Container, @Override public void containerPropertySetChange( Container.PropertySetChangeEvent event) { + if (isBeingPainted) { + return; + } + disableContentRefreshing(); super.containerPropertySetChange(event); diff --git a/server/src/com/vaadin/util/CurrentInstance.java b/server/src/com/vaadin/util/CurrentInstance.java index b97bab3d8a..a1c543117d 100644 --- a/server/src/com/vaadin/util/CurrentInstance.java +++ b/server/src/com/vaadin/util/CurrentInstance.java @@ -60,7 +60,7 @@ public class CurrentInstance implements Serializable { return null; } - Map<Class<?>, CurrentInstance> value = new HashMap<Class<?>, CurrentInstance>(); + Map<Class<?>, CurrentInstance> value = new WeakValueMap<Class<?>, CurrentInstance>(); // Copy all inheritable values to child map for (Entry<Class<?>, CurrentInstance> e : parentValue.entrySet()) { diff --git a/server/src/com/vaadin/util/WeakValueMap.java b/server/src/com/vaadin/util/WeakValueMap.java new file mode 100644 index 0000000000..1134594cba --- /dev/null +++ b/server/src/com/vaadin/util/WeakValueMap.java @@ -0,0 +1,230 @@ +/* + * Copyright 2000-2013 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ + +package com.vaadin.util; + +import java.lang.ref.Reference; +import java.lang.ref.ReferenceQueue; +import java.lang.ref.WeakReference; +import java.util.AbstractMap; +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +/** + * A Map holding weak references to its values. It is internally backed by a + * normal HashMap and all values are stored as WeakReferences. Garbage collected + * entries are removed when touched. + * <p> + * <em>Note</em> this class is not serializable. + * + * @author Vaadin Ltd + * @since 7.1.4 + */ +public class WeakValueMap<K, V> implements Map<K, V> { + + /** + * This class holds a weak reference to the value and a strong reference to + * the key for efficient removal of stale values. + */ + private static class WeakValueReference<K, V> extends WeakReference<V> { + private final K key; + + WeakValueReference(K key, V value, ReferenceQueue<V> refQueue) { + super(value, refQueue); + this.key = key; + } + + K getKey() { + return key; + } + } + + private final HashMap<K, WeakValueReference<K, V>> backingMap; + private final ReferenceQueue<V> refQueue; + + /** + * Constructs a new WeakValueMap, where all values are stored as weak + * references. + */ + public WeakValueMap() { + backingMap = new HashMap<K, WeakValueReference<K, V>>(); + refQueue = new ReferenceQueue<V>(); + } + + /** + * {@inheritDoc} + */ + @Override + public V put(K key, V value) { + if (key == null) { + throw new NullPointerException("key cannot be null"); + } + if (value == null) { + throw new NullPointerException("value cannot be null"); + } + removeStaleEntries(); + backingMap.put(key, new WeakValueReference<K, V>(key, value, refQueue)); + return value; + } + + /** + * {@inheritDoc} + */ + @Override + public V remove(Object o) { + removeStaleEntries(); + WeakReference<V> value = backingMap.remove(o); + return value == null ? null : value.get(); + } + + /** + * {@inheritDoc} + */ + @Override + public void putAll(Map<? extends K, ? extends V> map) { + if (map != null) { + for (Map.Entry<? extends K, ? extends V> entry : map.entrySet()) { + put(entry.getKey(), entry.getValue()); + } + } + } + + /** + * {@inheritDoc} + */ + @Override + public void clear() { + backingMap.clear(); + } + + /** + * {@inheritDoc} + */ + @Override + public Set<K> keySet() { + removeStaleEntries(); + return backingMap.keySet(); + } + + /** + * {@inheritDoc} + */ + @Override + public V get(Object o) { + removeStaleEntries(); + WeakReference<V> weakValue = backingMap.get(o); + if (weakValue != null) { + return weakValue.get(); + } + return null; + } + + /** + * {@inheritDoc} + */ + @Override + public int size() { + removeStaleEntries(); + return backingMap.size(); + } + + /** + * {@inheritDoc} + */ + @Override + public boolean isEmpty() { + removeStaleEntries(); + return backingMap.isEmpty(); + } + + /** + * {@inheritDoc} + */ + @Override + public boolean containsKey(Object o) { + removeStaleEntries(); + return backingMap.containsKey(o); + } + + /** + * {@inheritDoc} + */ + @Override + public boolean containsValue(Object o) { + removeStaleEntries(); + for (V value : values()) { + if (o.equals(value)) { + return true; + } + } + return false; + } + + /** + * {@inheritDoc} + */ + @Override + public Collection<V> values() { + removeStaleEntries(); + Collection<V> values = new HashSet<V>(); + for (WeakReference<V> weakValue : backingMap.values()) { + V value = weakValue.get(); + if (value != null) { + // null values have been GC'd, which may happen long before + // anything is enqueued in the ReferenceQueue. + values.add(value); + } + } + return values; + } + + /** + * {@inheritDoc} + */ + @Override + public Set<Entry<K, V>> entrySet() { + removeStaleEntries(); + Set<Entry<K, V>> entrySet = new HashSet<Entry<K, V>>(); + for (Entry<K, WeakValueReference<K, V>> entry : backingMap.entrySet()) { + V value = entry.getValue().get(); + if (value != null) { + // null values have been GC'd, which may happen long before + // anything is enqueued in the ReferenceQueue. + entrySet.add(new AbstractMap.SimpleEntry<K, V>(entry.getKey(), + value)); + } + } + return entrySet; + } + + /** + * Cleans up stale entries by polling the ReferenceQueue. + * <p> + * Depending on the GC implementation and strategy, the ReferenceQueue is + * not necessarily notified immediately when a reference is garbage + * collected, but it will eventually be. + */ + private void removeStaleEntries() { + Reference<? extends V> ref; + while ((ref = refQueue.poll()) != null) { + Object key = ((WeakValueReference<?, ?>) ref).getKey(); + backingMap.remove(key); + } + } +} |