]> source.dussan.org Git - vaadin-framework.git/commitdiff
Add getStateParameterMap to Navigator to get parameters as a map (#9517)
authorPeter Lehto <peter@vaadin.com>
Tue, 13 Jun 2017 09:41:36 +0000 (12:41 +0300)
committerArtur <artur@vaadin.com>
Tue, 13 Jun 2017 09:41:36 +0000 (12:41 +0300)
server/src/main/java/com/vaadin/navigator/Navigator.java
server/src/test/java/com/vaadin/tests/server/navigator/NavigatorTest.java

index 23414798324aae556468320144fc603b84409506..8b9e39b3542569c57efce331eb3601c34dfa4683 100644 (file)
@@ -17,9 +17,13 @@ package com.vaadin.navigator;
 
 import java.io.Serializable;
 import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
 import java.util.Iterator;
 import java.util.LinkedList;
 import java.util.List;
+import java.util.Map;
+import java.util.Objects;
 
 import com.vaadin.navigator.ViewChangeListener.ViewChangeEvent;
 import com.vaadin.server.Page;
@@ -53,6 +57,11 @@ public class Navigator implements Serializable {
 
     // TODO investigate relationship with TouchKit navigation support
 
+    private static final String DEFAULT_VIEW_SEPARATOR = "/";
+
+    private static final String DEFAULT_STATE_PARAMETER_SEPARATOR = "&";
+    private static final String DEFAULT_STATE_PARAMETER_KEY_VALUE_SEPARATOR = "=";
+
     /**
      * Empty view component.
      */
@@ -340,23 +349,17 @@ public class Navigator implements Serializable {
 
     /**
      * The {@link UI} bound with the Navigator.
-     *
-     * @since 8.0.3
      */
     protected UI ui;
 
     /**
      * The {@link NavigationStateManager} that is used to get, listen to and
      * manipulate the navigation state used by the Navigator.
-     *
-     * @since 8.0.3
      */
     protected NavigationStateManager stateManager;
 
     /**
      * The {@link ViewDisplay} used by the Navigator.
-     *
-     * @since 8.0.3
      */
     protected ViewDisplay display;
 
@@ -741,6 +744,76 @@ public class Navigator implements Serializable {
         return getStateManager().getState();
     }
 
+    /**
+     * Returns the current navigation state reported by this Navigator's
+     * {@link NavigationStateManager} as Map<String, String> where each key
+     * represents a parameter in the state.
+     *
+     * Uses {@literal &} as parameter separator. If the state contains
+     * {@literal #!view/foo&bar=baz} then this method will return a map
+     * containing {@literal foo => ""} and {@literal bar => baz}.
+     *
+     * @return The parameters from the navigation state as a map
+     * @see #getStateParameterMap(String)
+     */
+    public Map<String, String> getStateParameterMap() {
+        return getStateParameterMap(DEFAULT_STATE_PARAMETER_SEPARATOR);
+    }
+
+    /**
+     * Returns the current navigation state reported by this Navigator's
+     * {@link NavigationStateManager} as Map<String, String> where each key
+     * represents a parameter in the state. The state parameter separator
+     * character needs to be specified with the separator.
+     *
+     * @param separator
+     *            the string (typically one character) used to separate values
+     *            from each other
+     * @return The parameters from the navigation state as a map
+     * @see #getStateParameterMap()
+     */
+    public Map<String, String> getStateParameterMap(String separator) {
+        return parseStateParameterMap(Objects.requireNonNull(separator));
+    }
+
+    /**
+     * Parses the state parameter map using given separator String.
+     *
+     * @param separator
+     *            the string (typically one character) used to separate values
+     *            from each other
+     * @return The navigation state as Map<String, String>.
+     */
+    protected Map<String, String> parseStateParameterMap(String separator) {
+        Map<String, String> parameterMap = new HashMap<>();
+        if (getState() == null || getState().isEmpty()) {
+            return Collections.emptyMap();
+        }
+
+        String state = getState();
+        int viewSeparatorLocation = state.indexOf(DEFAULT_VIEW_SEPARATOR);
+
+        String parameterString;
+        if (viewSeparatorLocation == -1) {
+            parameterString = "";
+        } else {
+            parameterString = state.substring(viewSeparatorLocation + 1,
+                    state.length());
+        }
+        if (parameterString.isEmpty()) {
+            return Collections.emptyMap();
+        }
+        String[] parameters = parameterString.split(separator);
+        for (int i = 0; i < parameters.length; i++) {
+            String[] keyAndValue = parameters[i]
+                    .split(DEFAULT_STATE_PARAMETER_KEY_VALUE_SEPARATOR);
+            parameterMap.put(keyAndValue[0],
+                    keyAndValue.length > 1 ? keyAndValue[1] : "");
+        }
+
+        return parameterMap;
+    }
+
     /**
      * Return the {@link ViewDisplay} used by the navigator.
      *
@@ -993,8 +1066,6 @@ public class Navigator implements Serializable {
      * @param state
      *            state string
      * @return suitable provider
-     *
-     * @since 8.0.3
      */
     protected ViewProvider getViewProvider(String state) {
         String longestViewName = null;
index 6991fd1b9ea8f1c54342d5ac42ded880325b7467..022b388840bbf790a2f84bd7c80a42dac68f06c6 100644 (file)
@@ -23,6 +23,8 @@ import static org.junit.Assert.assertSame;
 import static org.junit.Assert.fail;
 
 import java.util.LinkedList;
+import java.util.Map;
+import java.util.Map.Entry;
 
 import org.easymock.EasyMock;
 import org.easymock.IArgumentMatcher;
@@ -51,6 +53,25 @@ import com.vaadin.ui.VerticalLayout;
 
 public class NavigatorTest {
 
+    private final class TestNavigationStateManager
+            implements NavigationStateManager {
+        private String state;
+
+        @Override
+        public void setState(String state) {
+            this.state = state;
+        }
+
+        @Override
+        public void setNavigator(Navigator navigator) {
+        }
+
+        @Override
+        public String getState() {
+            return state;
+        }
+    }
+
     // TODO test internal parameters (and absence of them)
     // TODO test listeners blocking navigation, multiple listeners
 
@@ -854,24 +875,7 @@ public class NavigatorTest {
 
     @Test
     public void testNavigateTo_navigateSameUriTwice_secondNavigationDoesNothing() {
-        NavigationStateManager manager = new NavigationStateManager() {
-
-            private String state;
-
-            @Override
-            public void setState(String state) {
-                this.state = state;
-            }
-
-            @Override
-            public void setNavigator(Navigator navigator) {
-            }
-
-            @Override
-            public String getState() {
-                return state;
-            }
-        };
+        NavigationStateManager manager = new TestNavigationStateManager();
 
         final String viewName = "view";
 
@@ -969,4 +973,91 @@ public class NavigatorTest {
                 ((Label) ((HorizontalLayout) ui.getContent()).getComponent(0))
                         .getValue());
     }
+
+    @Test
+    public void parameterMap_noViewSeparator() {
+        Navigator navigator = createNavigatorWithState("fooview");
+        Assert.assertTrue(navigator.getStateParameterMap().isEmpty());
+        Assert.assertTrue(navigator.getStateParameterMap("foo").isEmpty());
+    }
+
+    @Test
+    public void parameterMap_noParameters() {
+        Navigator navigator = createNavigatorWithState("fooview/");
+        Assert.assertTrue(navigator.getStateParameterMap().isEmpty());
+    }
+
+    @Test
+    public void parameterMap_oneParameterNoValue() {
+        Navigator navigator = createNavigatorWithState("fooview/bar");
+        assertMap(navigator.getStateParameterMap(), entry("bar", ""));
+    }
+
+    @Test
+    public void parameterMap_oneParameterNoValueButEquals() {
+        Navigator navigator = createNavigatorWithState("fooview/bar=");
+        assertMap(navigator.getStateParameterMap(), entry("bar", ""));
+    }
+
+    @Test
+    public void parameterMap_oneParameterWithValue() {
+        Navigator navigator = createNavigatorWithState("fooview/bar=baz");
+        assertMap(navigator.getStateParameterMap(), entry("bar", "baz"));
+    }
+
+    @Test
+    public void parameterMap_twoParameters() {
+        Navigator navigator = createNavigatorWithState("fooview/foo=bar&baz");
+        assertMap(navigator.getStateParameterMap(), entry("foo", "bar"),
+                entry("baz", ""));
+    }
+
+    @Test
+    public void parameterMap_customSeparator() {
+        Navigator navigator = createNavigatorWithState("fooview/foo=bar&baz");
+        assertMap(navigator.getStateParameterMap("a"), entry("foo", "b"),
+                entry("r&b", ""), entry("z", ""));
+    }
+
+    @SafeVarargs
+    private final void assertMap(Map<String, String> map,
+            Entry<String, String>... entries) {
+        Assert.assertEquals(entries.length, map.size());
+        for (Entry<String, String> entry : entries) {
+            Assert.assertTrue(
+                    "Map should contain a key called '" + entry.getKey() + "'",
+                    map.containsKey(entry.getKey()));
+            Assert.assertEquals(entry.getValue(), map.get(entry.getKey()));
+        }
+
+    }
+
+    private Entry<String, String> entry(String key, String value) {
+        return new Entry<String, String>() {
+
+            @Override
+            public String getKey() {
+                return key;
+            }
+
+            @Override
+            public String getValue() {
+                return value;
+            }
+
+            @Override
+            public String setValue(String value) {
+                throw new UnsupportedOperationException();
+            }
+
+        };
+    }
+
+    private Navigator createNavigatorWithState(String state) {
+        TestNavigationStateManager manager = new TestNavigationStateManager();
+        Navigator navigator = new Navigator(createMockUI(), manager,
+                EasyMock.createMock(ViewDisplay.class));
+        manager.setState(state);
+        return navigator;
+    }
 }