aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--server/src/com/vaadin/server/AbstractCommunicationManager.java71
-rw-r--r--server/src/com/vaadin/ui/ConnectorTracker.java115
-rw-r--r--server/tests/src/com/vaadin/tests/server/TestStreamVariableMapping.java12
-rw-r--r--uitest/src/com/vaadin/tests/components/ui/MultipleUIUploadTest.java118
4 files changed, 251 insertions, 65 deletions
diff --git a/server/src/com/vaadin/server/AbstractCommunicationManager.java b/server/src/com/vaadin/server/AbstractCommunicationManager.java
index 0a3dff8120..af9118547f 100644
--- a/server/src/com/vaadin/server/AbstractCommunicationManager.java
+++ b/server/src/com/vaadin/server/AbstractCommunicationManager.java
@@ -165,10 +165,6 @@ public abstract class AbstractCommunicationManager implements Serializable {
private Map<String, Class<?>> publishedFileContexts = new HashMap<String, Class<?>>();
- private Map<String, Map<String, StreamVariable>> pidToNameToStreamVariable;
-
- private Map<StreamVariable, String> streamVariableToSeckey;
-
/**
* TODO New constructor - document me!
*
@@ -644,23 +640,6 @@ public abstract class AbstractCommunicationManager implements Serializable {
// Remove connectors that have been detached from the session during
// handling of the request
uI.getConnectorTracker().cleanConnectorMap();
-
- if (pidToNameToStreamVariable != null) {
- Iterator<String> iterator = pidToNameToStreamVariable.keySet()
- .iterator();
- while (iterator.hasNext()) {
- String connectorId = iterator.next();
- if (uI.getConnectorTracker().getConnector(connectorId) == null) {
- // Owner is no longer attached to the session
- Map<String, StreamVariable> removed = pidToNameToStreamVariable
- .get(connectorId);
- for (String key : removed.keySet()) {
- streamVariableToSeckey.remove(removed.get(key));
- }
- iterator.remove();
- }
- }
- }
}
protected void highlightConnector(ClientConnector highlightedConnector) {
@@ -2269,28 +2248,13 @@ public abstract class AbstractCommunicationManager implements Serializable {
* handling post
*/
String paintableId = owner.getConnectorId();
- int uiId = owner.getUI().getUIId();
+ UI ui = owner.getUI();
+ int uiId = ui.getUIId();
String key = uiId + "/" + paintableId + "/" + name;
- if (pidToNameToStreamVariable == null) {
- pidToNameToStreamVariable = new HashMap<String, Map<String, StreamVariable>>();
- }
- Map<String, StreamVariable> nameToStreamVariable = pidToNameToStreamVariable
- .get(paintableId);
- if (nameToStreamVariable == null) {
- nameToStreamVariable = new HashMap<String, StreamVariable>();
- pidToNameToStreamVariable.put(paintableId, nameToStreamVariable);
- }
- nameToStreamVariable.put(name, value);
-
- if (streamVariableToSeckey == null) {
- streamVariableToSeckey = new HashMap<StreamVariable, String>();
- }
- String seckey = streamVariableToSeckey.get(value);
- if (seckey == null) {
- seckey = UUID.randomUUID().toString();
- streamVariableToSeckey.put(value, seckey);
- }
+ ConnectorTracker connectorTracker = ui.getConnectorTracker();
+ connectorTracker.addStreamVariable(paintableId, name, value);
+ String seckey = connectorTracker.getSeckey(value);
return ApplicationConstants.APP_PROTOCOL_PREFIX
+ ServletPortletHelper.UPLOAD_URL_PREFIX + key + "/" + seckey;
@@ -2298,12 +2262,8 @@ public abstract class AbstractCommunicationManager implements Serializable {
}
public void cleanStreamVariable(ClientConnector owner, String name) {
- Map<String, StreamVariable> nameToStreamVar = pidToNameToStreamVariable
- .get(owner.getConnectorId());
- nameToStreamVar.remove(name);
- if (nameToStreamVar.isEmpty()) {
- pidToNameToStreamVariable.remove(owner.getConnectorId());
- }
+ owner.getUI().getConnectorTracker()
+ .cleanStreamVariable(owner.getConnectorId(), name);
}
/**
@@ -2683,9 +2643,9 @@ public abstract class AbstractCommunicationManager implements Serializable {
UI uI = session.getUIById(Integer.parseInt(uiId));
UI.setCurrent(uI);
- StreamVariable streamVariable = getStreamVariable(connectorId,
- variableName);
- String secKey = streamVariableToSeckey.get(streamVariable);
+ StreamVariable streamVariable = uI.getConnectorTracker()
+ .getStreamVariable(connectorId, variableName);
+ String secKey = uI.getConnectorTracker().getSeckey(streamVariable);
if (secKey.equals(parts[3])) {
ClientConnector source = getConnector(uI, connectorId);
@@ -2741,17 +2701,6 @@ public abstract class AbstractCommunicationManager implements Serializable {
}
}
- public StreamVariable getStreamVariable(String connectorId,
- String variableName) {
- Map<String, StreamVariable> map = pidToNameToStreamVariable
- .get(connectorId);
- if (map == null) {
- return null;
- }
- StreamVariable streamVariable = map.get(variableName);
- return streamVariable;
- }
-
/**
* Stream that extracts content from another stream until the boundary
* string is encountered.
diff --git a/server/src/com/vaadin/ui/ConnectorTracker.java b/server/src/com/vaadin/ui/ConnectorTracker.java
index 8b1a940c4b..91f9ac451c 100644
--- a/server/src/com/vaadin/ui/ConnectorTracker.java
+++ b/server/src/com/vaadin/ui/ConnectorTracker.java
@@ -23,6 +23,7 @@ import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
+import java.util.UUID;
import java.util.logging.Level;
import java.util.logging.Logger;
@@ -33,6 +34,7 @@ import com.vaadin.server.AbstractClientConnector;
import com.vaadin.server.AbstractCommunicationManager;
import com.vaadin.server.ClientConnector;
import com.vaadin.server.GlobalResourceHandler;
+import com.vaadin.server.StreamVariable;
/**
* A class which takes care of book keeping of {@link ClientConnector}s for a
@@ -65,6 +67,11 @@ public class ConnectorTracker implements Serializable {
private UI uI;
private transient Map<ClientConnector, JSONObject> diffStates = new HashMap<ClientConnector, JSONObject>();
+ /** Maps connectorIds to a map of named StreamVariables */
+ private Map<String, Map<String, StreamVariable>> pidToNameToStreamVariable;
+
+ private Map<StreamVariable, String> streamVariableToSeckey;
+
/**
* Gets a logger for this class
*
@@ -259,6 +266,7 @@ public class ConnectorTracker implements Serializable {
}
}
+ cleanStreamVariables();
}
/**
@@ -497,4 +505,111 @@ public class ConnectorTracker implements Serializable {
}
}
+
+ /**
+ * Checks if the indicated connector has a StreamVariable of the given name
+ * and returns the variable if one is found.
+ *
+ * @param connectorId
+ * @param variableName
+ * @return variable if a matching one exists, otherwise null
+ */
+ public StreamVariable getStreamVariable(String connectorId,
+ String variableName) {
+ if (pidToNameToStreamVariable == null) {
+ return null;
+ }
+ Map<String, StreamVariable> map = pidToNameToStreamVariable
+ .get(connectorId);
+ if (map == null) {
+ return null;
+ }
+ StreamVariable streamVariable = map.get(variableName);
+ return streamVariable;
+ }
+
+ /**
+ * Adds a StreamVariable of the given name to the indicated connector.
+ *
+ * @param connectorId
+ * @param variableName
+ * @param variable
+ */
+ public void addStreamVariable(String connectorId, String variableName,
+ StreamVariable variable) {
+ if (pidToNameToStreamVariable == null) {
+ pidToNameToStreamVariable = new HashMap<String, Map<String, StreamVariable>>();
+ }
+ Map<String, StreamVariable> nameToStreamVariable = pidToNameToStreamVariable
+ .get(connectorId);
+ if (nameToStreamVariable == null) {
+ nameToStreamVariable = new HashMap<String, StreamVariable>();
+ pidToNameToStreamVariable.put(connectorId, nameToStreamVariable);
+ }
+ nameToStreamVariable.put(variableName, variable);
+
+ if (streamVariableToSeckey == null) {
+ streamVariableToSeckey = new HashMap<StreamVariable, String>();
+ }
+ String seckey = streamVariableToSeckey.get(variable);
+ if (seckey == null) {
+ seckey = UUID.randomUUID().toString();
+ streamVariableToSeckey.put(variable, seckey);
+ }
+ }
+
+ /**
+ * Removes StreamVariables that belong to connectors that are no longer
+ * attached to the session.
+ */
+ private void cleanStreamVariables() {
+ if (pidToNameToStreamVariable != null) {
+ Iterator<String> iterator = pidToNameToStreamVariable.keySet()
+ .iterator();
+ while (iterator.hasNext()) {
+ String connectorId = iterator.next();
+ if (uI.getConnectorTracker().getConnector(connectorId) == null) {
+ // Owner is no longer attached to the session
+ Map<String, StreamVariable> removed = pidToNameToStreamVariable
+ .get(connectorId);
+ for (String key : removed.keySet()) {
+ streamVariableToSeckey.remove(removed.get(key));
+ }
+ iterator.remove();
+ }
+ }
+ }
+ }
+
+ /**
+ * Removes any StreamVariable of the given name from the indicated
+ * connector.
+ *
+ * @param connectorId
+ * @param variableName
+ */
+ public void cleanStreamVariable(String connectorId, String variableName) {
+ if (pidToNameToStreamVariable == null) {
+ return;
+ }
+ Map<String, StreamVariable> nameToStreamVar = pidToNameToStreamVariable
+ .get(connectorId);
+ nameToStreamVar.remove(variableName);
+ if (nameToStreamVar.isEmpty()) {
+ pidToNameToStreamVariable.remove(connectorId);
+ }
+ }
+
+ /**
+ * Returns the security key associated with the given StreamVariable.
+ *
+ * @param variable
+ * @return matching security key if one exists, null otherwise
+ */
+ public String getSeckey(StreamVariable variable) {
+ if (streamVariableToSeckey == null) {
+ return null;
+ }
+ return streamVariableToSeckey.get(variable);
+ }
}
diff --git a/server/tests/src/com/vaadin/tests/server/TestStreamVariableMapping.java b/server/tests/src/com/vaadin/tests/server/TestStreamVariableMapping.java
index f8dceca363..f24638e6a7 100644
--- a/server/tests/src/com/vaadin/tests/server/TestStreamVariableMapping.java
+++ b/server/tests/src/com/vaadin/tests/server/TestStreamVariableMapping.java
@@ -8,6 +8,7 @@ import com.vaadin.server.CommunicationManager;
import com.vaadin.server.StreamVariable;
import com.vaadin.server.VaadinRequest;
import com.vaadin.server.VaadinSession;
+import com.vaadin.ui.ConnectorTracker;
import com.vaadin.ui.UI;
import com.vaadin.ui.Upload;
@@ -51,18 +52,21 @@ public class TestStreamVariableMapping extends TestCase {
streamVariable);
assertTrue(targetUrl.startsWith("app://APP/UPLOAD/-1/1/myName/"));
- StreamVariable streamVariable2 = cm.getStreamVariable(
+ ConnectorTracker tracker = UI.getCurrent().getConnectorTracker();
+ StreamVariable streamVariable2 = tracker.getStreamVariable(
owner.getConnectorId(), variableName);
assertSame(streamVariable, streamVariable2);
}
public void testRemoverVariable() {
+ ConnectorTracker tracker = UI.getCurrent().getConnectorTracker();
cm.getStreamVariableTargetUrl(owner, variableName, streamVariable);
- assertNotNull(cm
- .getStreamVariable(owner.getConnectorId(), variableName));
+ assertNotNull(tracker.getStreamVariable(owner.getConnectorId(),
+ variableName));
cm.cleanStreamVariable(owner, variableName);
- assertNull(cm.getStreamVariable(owner.getConnectorId(), variableName));
+ assertNull(tracker.getStreamVariable(owner.getConnectorId(),
+ variableName));
}
private CommunicationManager createCommunicationManager() {
diff --git a/uitest/src/com/vaadin/tests/components/ui/MultipleUIUploadTest.java b/uitest/src/com/vaadin/tests/components/ui/MultipleUIUploadTest.java
new file mode 100644
index 0000000000..f92e22d06b
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/ui/MultipleUIUploadTest.java
@@ -0,0 +1,118 @@
+package com.vaadin.tests.components.ui;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import com.vaadin.server.StreamResource;
+import com.vaadin.server.VaadinRequest;
+import com.vaadin.tests.components.AbstractTestUI;
+import com.vaadin.ui.Button;
+import com.vaadin.ui.Button.ClickEvent;
+import com.vaadin.ui.Button.ClickListener;
+import com.vaadin.ui.Notification;
+import com.vaadin.ui.Upload;
+import com.vaadin.ui.VerticalLayout;
+
+public class MultipleUIUploadTest extends AbstractTestUI {
+
+ private MemoryBuffer buffer = new MemoryBuffer();
+ private Upload upload;
+
+ @Override
+ protected String getTestDescription() {
+ return "Using Upload with multiple UIs causes NPE."
+ + " Open test in first browser window and open the file selection window."
+ + " Then open test in second browser window (without ?restartApplication) and click the notification button."
+ + " Then go back to the first window, select a file, and click Upload."
+ + " Click notification button to ensure the upload was received successfully.";
+ }
+
+ @Override
+ protected Integer getTicketNumber() {
+ return 10112;
+ }
+
+ @Override
+ protected void setup(VaadinRequest request) {
+ final VerticalLayout layout = new VerticalLayout();
+ layout.setMargin(true);
+ layout.setSpacing(true);
+ setContent(layout);
+
+ upload = new Upload(null, buffer);
+ upload.setId("upload");
+ layout.addComponent(upload);
+
+ Button button = new Button("show notification");
+ button.setId("notify");
+ button.addClickListener(new ClickListener() {
+
+ @Override
+ public void buttonClick(ClickEvent event) {
+ Notification.show("uploaded: " + buffer.getFileName());
+ }
+ });
+ layout.addComponent(button);
+
+ }
+
+ public class MemoryBuffer implements StreamResource.StreamSource,
+ Upload.Receiver {
+ ByteArrayOutputStream outputBuffer = null;
+
+ String mimeType;
+
+ String fileName;
+
+ public MemoryBuffer() {
+
+ }
+
+ @Override
+ public InputStream getStream() {
+ if (outputBuffer == null) {
+ return null;
+ }
+ return new ByteArrayInputStream(outputBuffer.toByteArray());
+ }
+
+ /**
+ * @see com.vaadin.ui.Upload.Receiver#receiveUpload(String, String)
+ */
+ @Override
+ public OutputStream receiveUpload(String filename, String MIMEType) {
+ fileName = filename;
+ mimeType = MIMEType;
+ outputBuffer = new ByteArrayOutputStream() {
+ @Override
+ public synchronized void write(byte[] b, int off, int len) {
+ super.write(b, off, len);
+ }
+
+ };
+ return outputBuffer;
+ }
+
+ /**
+ * Returns the fileName.
+ *
+ * @return String
+ */
+ public String getFileName() {
+ return fileName;
+ }
+
+ /**
+ * Returns the mimeType.
+ *
+ * @return String
+ */
+ public String getMimeType() {
+ return mimeType;
+ }
+
+ }
+
+}