summaryrefslogtreecommitdiffstats
path: root/server
diff options
context:
space:
mode:
Diffstat (limited to 'server')
-rw-r--r--server/src/com/vaadin/data/RpcDataProviderExtension.java18
-rw-r--r--server/src/com/vaadin/data/util/converter/StringToCollectionConverter.java4
-rw-r--r--server/src/com/vaadin/server/AbstractClientConnector.java10
-rw-r--r--server/src/com/vaadin/server/CustomizedSystemMessages.java44
-rw-r--r--server/src/com/vaadin/server/SystemMessages.java11
-rw-r--r--server/src/com/vaadin/ui/ConnectorTracker.java52
-rw-r--r--server/src/com/vaadin/ui/Grid.java5
-rw-r--r--server/tests/src/com/vaadin/tests/data/converter/StringToCollectionConverterTest.java10
8 files changed, 66 insertions, 88 deletions
diff --git a/server/src/com/vaadin/data/RpcDataProviderExtension.java b/server/src/com/vaadin/data/RpcDataProviderExtension.java
index 71b597ff1d..55947c98d1 100644
--- a/server/src/com/vaadin/data/RpcDataProviderExtension.java
+++ b/server/src/com/vaadin/data/RpcDataProviderExtension.java
@@ -947,6 +947,14 @@ public class RpcDataProviderExtension extends AbstractExtension {
listener.removeListener();
}
+ // Wipe clean all details.
+ HashSet<Object> detailItemIds = new HashSet<Object>(
+ detailComponentManager.visibleDetailsComponents
+ .keySet());
+ for (Object itemId : detailItemIds) {
+ detailComponentManager.destroyDetails(itemId);
+ }
+
listeners.clear();
activeRowHandler.activeRange = Range.withLength(0, 0);
@@ -1387,4 +1395,14 @@ public class RpcDataProviderExtension extends AbstractExtension {
public DetailComponentManager getDetailComponentManager() {
return detailComponentManager;
}
+
+ @Override
+ public void detach() {
+ for (Object itemId : ImmutableSet
+ .copyOf(detailComponentManager.visibleDetails)) {
+ detailComponentManager.destroyDetails(itemId);
+ }
+
+ super.detach();
+ }
}
diff --git a/server/src/com/vaadin/data/util/converter/StringToCollectionConverter.java b/server/src/com/vaadin/data/util/converter/StringToCollectionConverter.java
index 495bed74f8..b86fec5558 100644
--- a/server/src/com/vaadin/data/util/converter/StringToCollectionConverter.java
+++ b/server/src/com/vaadin/data/util/converter/StringToCollectionConverter.java
@@ -155,9 +155,7 @@ public class StringToCollectionConverter implements
previous = index + delimiter.length();
index = value.indexOf(delimiter, previous);
}
- if (result.size() > 0) {
- collectToken(value.substring(previous), result, converter, locale);
- }
+ collectToken(value.substring(previous), result, converter, locale);
return result;
}
diff --git a/server/src/com/vaadin/server/AbstractClientConnector.java b/server/src/com/vaadin/server/AbstractClientConnector.java
index 0655b482ed..b6bcebd167 100644
--- a/server/src/com/vaadin/server/AbstractClientConnector.java
+++ b/server/src/com/vaadin/server/AbstractClientConnector.java
@@ -30,6 +30,7 @@ import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
+import java.util.concurrent.ConcurrentHashMap;
import java.util.logging.Logger;
import com.vaadin.event.EventRouter;
@@ -91,6 +92,8 @@ public abstract class AbstractClientConnector implements ClientConnector,
private ErrorHandler errorHandler = null;
+ private static final ConcurrentHashMap<Class<? extends AbstractClientConnector>, Class<? extends SharedState>> stateTypeCache = new ConcurrentHashMap<Class<? extends AbstractClientConnector>, Class<? extends SharedState>>();
+
@Override
public void addAttachListener(AttachListener listener) {
addListener(AttachEvent.ATTACH_EVENT_IDENTIFIER, AttachEvent.class,
@@ -296,7 +299,12 @@ public abstract class AbstractClientConnector implements ClientConnector,
// Lazy load because finding type can be expensive because of the
// exceptions flying around
if (stateType == null) {
- stateType = findStateType();
+ // Cache because we don't need to do this once per instance
+ stateType = stateTypeCache.get(this.getClass());
+ if (stateType == null) {
+ stateType = findStateType();
+ stateTypeCache.put(this.getClass(), stateType);
+ }
}
return stateType;
diff --git a/server/src/com/vaadin/server/CustomizedSystemMessages.java b/server/src/com/vaadin/server/CustomizedSystemMessages.java
index f7049e3688..9aef4f5cf3 100644
--- a/server/src/com/vaadin/server/CustomizedSystemMessages.java
+++ b/server/src/com/vaadin/server/CustomizedSystemMessages.java
@@ -240,50 +240,6 @@ public class CustomizedSystemMessages extends SystemMessages implements
}
/**
- * Sets the URL to go to when the client is out-of-sync.
- *
- * @param outOfSyncURL
- * the URL to go to, or null to reload current
- */
- public void setOutOfSyncURL(String outOfSyncURL) {
- this.outOfSyncURL = outOfSyncURL;
- }
-
- /**
- * Enables or disables the notification. If disabled, the set URL (or
- * current) is loaded directly.
- *
- * @param outOfSyncNotificationEnabled
- * true = enabled, false = disabled
- */
- public void setOutOfSyncNotificationEnabled(
- boolean outOfSyncNotificationEnabled) {
- this.outOfSyncNotificationEnabled = outOfSyncNotificationEnabled;
- }
-
- /**
- * Sets the caption of the notification. Set to null for no caption. If both
- * caption and message is null, the notification is disabled;
- *
- * @param outOfSyncCaption
- * the caption
- */
- public void setOutOfSyncCaption(String outOfSyncCaption) {
- this.outOfSyncCaption = outOfSyncCaption;
- }
-
- /**
- * Sets the message of the notification. Set to null for no message. If both
- * caption and message is null, the notification is disabled;
- *
- * @param outOfSyncMessage
- * the message
- */
- public void setOutOfSyncMessage(String outOfSyncMessage) {
- this.outOfSyncMessage = outOfSyncMessage;
- }
-
- /**
* Sets the URL to redirect to when the browser has cookies disabled.
*
* @param cookiesDisabledURL
diff --git a/server/src/com/vaadin/server/SystemMessages.java b/server/src/com/vaadin/server/SystemMessages.java
index 51cc7d497d..3bcf0a90fa 100644
--- a/server/src/com/vaadin/server/SystemMessages.java
+++ b/server/src/com/vaadin/server/SystemMessages.java
@@ -43,12 +43,6 @@ import java.io.Serializable;
* <li><b>internalErrorCaption</b> = "Internal error"</li>
* <li><b>internalErrorMessage</b> = "Please notify the administrator.<br/>
* Take note of any unsaved data, and <u>click here</u> to continue."</li>
- * <li><b>outOfSyncURL</b> = null</li>
- * <li><b>outOfSyncNotificationEnabled</b> = true</li>
- * <li><b>outOfSyncCaption</b> = "Out of sync"</li>
- * <li><b>outOfSyncMessage</b> = "Something has caused us to be out of sync with
- * the server.<br/>
- * Take note of any unsaved data, and <u>click here</u> to re-sync."</li>
* <li><b>cookiesDisabledURL</b> = null</li>
* <li><b>cookiesDisabledNotificationEnabled</b> = true</li>
* <li><b>cookiesDisabledCaption</b> = "Cookies disabled"</li>
@@ -80,11 +74,6 @@ public class SystemMessages implements Serializable {
protected String internalErrorCaption = "Internal error";
protected String internalErrorMessage = "Please notify the administrator.<br/>Take note of any unsaved data, and <u>click here</u> or press ESC to continue.";
- protected String outOfSyncURL = null;
- protected boolean outOfSyncNotificationEnabled = true;
- protected String outOfSyncCaption = "Out of sync";
- protected String outOfSyncMessage = "Something has caused us to be out of sync with the server.<br/>Take note of any unsaved data, and <u>click here</u> or press ESC to re-sync.";
-
protected String cookiesDisabledURL = null;
protected boolean cookiesDisabledNotificationEnabled = true;
protected String cookiesDisabledCaption = "Cookies disabled";
diff --git a/server/src/com/vaadin/ui/ConnectorTracker.java b/server/src/com/vaadin/ui/ConnectorTracker.java
index 95a80b7be0..eba248fb00 100644
--- a/server/src/com/vaadin/ui/ConnectorTracker.java
+++ b/server/src/com/vaadin/ui/ConnectorTracker.java
@@ -24,6 +24,7 @@ import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Map;
+import java.util.NavigableMap;
import java.util.Set;
import java.util.TreeMap;
import java.util.UUID;
@@ -591,8 +592,8 @@ public class ConnectorTracker implements Serializable {
* <p>
* This method has a side-effect of incrementing the sync id by one (see
* {@link #getCurrentSyncId()}), if {@link #isWritingResponse()} returns
- * <code>false</code> and <code>writingResponse</code> is set to
- * <code>true</code>.
+ * <code>true</code> and <code>writingResponse</code> is set to
+ * <code>false</code>.
*
* @param writingResponse
* the new response status.
@@ -616,7 +617,9 @@ public class ConnectorTracker implements Serializable {
* the right hand side of the && is unnecessary here because of the
* if-clause above, but rigorous coding is always rigorous coding.
*/
- if (writingResponse && !this.writingResponse) {
+ if (!writingResponse && this.writingResponse) {
+ // Bump sync id when done writing - the client is not expected to
+ // know about anything happening after this moment.
currentSyncId++;
}
this.writingResponse = writingResponse;
@@ -784,34 +787,25 @@ public class ConnectorTracker implements Serializable {
*/
public boolean connectorWasPresentAsRequestWasSent(String connectorId,
long lastSyncIdSeenByClient) {
-
assert getConnector(connectorId) == null : "Connector " + connectorId
+ " is still attached";
- boolean clientRequestIsTooOld = lastSyncIdSeenByClient < currentSyncId
- && lastSyncIdSeenByClient != -1;
- if (clientRequestIsTooOld) {
- /*
- * The headMap call is present here because we're only interested in
- * connectors removed "in the past" (i.e. the server has removed
- * them before the client ever knew about that), since those are the
- * ones that we choose to handle as a special case.
- */
- /*-
- * Server Client
- * [#1 add table] ---------.
- * \
- * [push: #2 remove table]-. `--> [adding table, storing #1]
- * \ .- [table from request #1 needs more data]
- * \/
- * /`-> [removing table, storing #2]
- * [#1 < #2 - ignoring] <---ยด
- */
- for (Set<String> unregisteredConnectors : syncIdToUnregisteredConnectorIds
- .headMap(currentSyncId).values()) {
- if (unregisteredConnectors.contains(connectorId)) {
- return true;
- }
+ if (lastSyncIdSeenByClient == -1) {
+ // Ignore potential problems
+ return true;
+ }
+
+ /*
+ * Use non-inclusive tail map to find all connectors that were removed
+ * after the reported sync id was sent to the client.
+ */
+ NavigableMap<Integer, Set<String>> unregisteredAfter = syncIdToUnregisteredConnectorIds
+ .tailMap(Integer.valueOf((int) lastSyncIdSeenByClient), false);
+ for (Set<String> unregisteredIds : unregisteredAfter.values()) {
+ if (unregisteredIds.contains(connectorId)) {
+ // Removed with a higher sync id, so it was most likely present
+ // when this sync id was sent.
+ return true;
}
}
@@ -877,7 +871,7 @@ public class ConnectorTracker implements Serializable {
* conflicts. In any case, it's better to clean up too little than too
* much, especially as the data will hardly grow into the kilobytes.
*/
- syncIdToUnregisteredConnectorIds.headMap(lastSyncIdSeenByClient)
+ syncIdToUnregisteredConnectorIds.headMap(lastSyncIdSeenByClient, true)
.clear();
}
}
diff --git a/server/src/com/vaadin/ui/Grid.java b/server/src/com/vaadin/ui/Grid.java
index af89064411..251ec0f678 100644
--- a/server/src/com/vaadin/ui/Grid.java
+++ b/server/src/com/vaadin/ui/Grid.java
@@ -6084,10 +6084,15 @@ public class Grid extends AbstractFocusable implements SelectionNotifier,
editorActive = false;
editorFieldGroup.discard();
editorFieldGroup.setItemDataSource(null);
+
if (datasource instanceof ItemSetChangeNotifier) {
((ItemSetChangeNotifier) datasource)
.removeItemSetChangeListener(editorClosingItemSetListener);
}
+
+ // Mark Grid as dirty so the client side gets to know that the editors
+ // are no longer attached
+ markAsDirty();
}
void resetEditor() {
diff --git a/server/tests/src/com/vaadin/tests/data/converter/StringToCollectionConverterTest.java b/server/tests/src/com/vaadin/tests/data/converter/StringToCollectionConverterTest.java
index 977985c6cb..bcd0dc15bd 100644
--- a/server/tests/src/com/vaadin/tests/data/converter/StringToCollectionConverterTest.java
+++ b/server/tests/src/com/vaadin/tests/data/converter/StringToCollectionConverterTest.java
@@ -141,6 +141,16 @@ public class StringToCollectionConverterTest {
Assert.assertEquals("Z,Y", presentation);
}
+ @Test
+ public void convertToModel_singleItem() {
+ StringToCollectionConverter converter = new StringToCollectionConverter();
+ Collection<?> model = converter.convertToModel("a", List.class, null);
+ Iterator<?> iterator = model.iterator();
+ Assert.assertEquals("Incorrect fist token", "a", iterator.next());
+ Assert.assertFalse("More than one item detected after conversation",
+ iterator.hasNext());
+ }
+
public enum TestEnum {
X, Y, Z;
}