]> source.dussan.org Git - vaadin-framework.git/commitdiff
Moved StreamVariable handling from AbstractCommunicationManager to 55/455/2
authorAnna Koskinen <anna@vaadin.com>
Fri, 7 Dec 2012 12:14:31 +0000 (14:14 +0200)
committerAnna Koskinen <anna@vaadin.com>
Fri, 7 Dec 2012 12:14:31 +0000 (14:14 +0200)
ConnectorTracker to prevent untimely unregistrations through other UIs
within the same session (#10112)

Change-Id: Id04c97970325be65b0b3c63756a2f2e731dd60d2

server/src/com/vaadin/server/AbstractCommunicationManager.java
server/src/com/vaadin/ui/ConnectorTracker.java
server/tests/src/com/vaadin/tests/server/TestStreamVariableMapping.java
uitest/src/com/vaadin/tests/components/ui/MultipleUIUploadTest.java [new file with mode: 0644]

index 0a3dff812015cdd6e3caaa865360dd7cbb420069..af9118547f2120f3374951cb9010b743ff5dfc0d 100644 (file)
@@ -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.
index 8b1a940c4bc163f429187dd7270eda3b590a314e..91f9ac451cba018bfb8236032873a03c3abfee1f 100644 (file)
@@ -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);
+    }
 }
index f8dceca363e0a25c0a1b503bdf8abdf597274794..f24638e6a7f4ca771d11f25b43910e9f2e001739 100644 (file)
@@ -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 (file)
index 0000000..f92e22d
--- /dev/null
@@ -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;
+        }
+
+    }
+
+}