EXTCDI-311 support external handling of navigation-cases

git-svn-id: https://svn.apache.org/repos/asf/myfaces/extensions/cdi/trunk@1551515 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/jee-modules/jsf20-module/impl/src/main/java/org/apache/myfaces/extensions/cdi/jsf2/impl/navigation/CodiNavigationHandler.java b/jee-modules/jsf20-module/impl/src/main/java/org/apache/myfaces/extensions/cdi/jsf2/impl/navigation/CodiNavigationHandler.java
index f8fea1d..67cdc38 100644
--- a/jee-modules/jsf20-module/impl/src/main/java/org/apache/myfaces/extensions/cdi/jsf2/impl/navigation/CodiNavigationHandler.java
+++ b/jee-modules/jsf20-module/impl/src/main/java/org/apache/myfaces/extensions/cdi/jsf2/impl/navigation/CodiNavigationHandler.java
@@ -197,7 +197,7 @@
             return result;

         }

 

-        return new NavigationCaseMapWrapper(result);

+        return new NavigationCaseMapWrapper(result, this.wrapped);

     }

 

     /**

diff --git a/jee-modules/jsf20-module/impl/src/main/java/org/apache/myfaces/extensions/cdi/jsf2/impl/navigation/NavigationCaseMapWrapper.java b/jee-modules/jsf20-module/impl/src/main/java/org/apache/myfaces/extensions/cdi/jsf2/impl/navigation/NavigationCaseMapWrapper.java
index d95e87c..64c808e 100644
--- a/jee-modules/jsf20-module/impl/src/main/java/org/apache/myfaces/extensions/cdi/jsf2/impl/navigation/NavigationCaseMapWrapper.java
+++ b/jee-modules/jsf20-module/impl/src/main/java/org/apache/myfaces/extensions/cdi/jsf2/impl/navigation/NavigationCaseMapWrapper.java
@@ -25,7 +25,9 @@
 import org.apache.myfaces.extensions.cdi.jsf.impl.util.JsfUtils;

 import org.apache.myfaces.extensions.cdi.jsf.impl.util.RequestParameter;

 

+import javax.faces.application.ConfigurableNavigationHandler;

 import javax.faces.application.NavigationCase;

+import javax.faces.application.NavigationHandler;

 import javax.faces.context.ExternalContext;

 import javax.faces.context.FacesContext;

 import java.util.List;

@@ -34,6 +36,7 @@
 import java.util.HashSet;

 import java.util.HashMap;

 import java.util.Collection;

+import java.util.logging.Logger;

 

 /**

  * Destructive operations aren't supported (compared to the SubKeyMap used in MyFaces).

@@ -41,22 +44,39 @@
  */

 class NavigationCaseMapWrapper implements Map<String, Set<NavigationCase>>

 {

+    private static final Logger LOG = Logger.getLogger(NavigationCaseMapWrapper.class.getName());

+

     private Map<String, Set<NavigationCase>> wrappedNavigationCaseMap;

+    private NavigationHandler wrapped;

     private final Map<String, Set<NavigationCase>> viewConfigBasedNavigationCaseCache;

 

     /**

      * Constructor for wrapping the given navigation-cases

      * @param navigationCases current navigation-cases

+     * @param wrapped

      */

-    public NavigationCaseMapWrapper(Map<String, Set<NavigationCase>> navigationCases)

+    public NavigationCaseMapWrapper(Map<String, Set<NavigationCase>> navigationCases, NavigationHandler wrapped)

     {

         this.wrappedNavigationCaseMap = navigationCases;

+        this.wrapped = wrapped;

         this.viewConfigBasedNavigationCaseCache = createViewConfigBasedNavigationCases(false);

     }

 

     private Map<String, Set<NavigationCase>> createViewConfigBasedNavigationCases(boolean allowParameters)

     {

-        Map<String, Set<NavigationCase>> result = new HashMap<String, Set<NavigationCase>>();

+        Map<String, Set<NavigationCase>> result;

+

+        if (this.wrapped instanceof ConfigurableNavigationHandler)

+        {

+            result = new DelegatingMap((ConfigurableNavigationHandler)this.wrapped);

+        }

+        else

+        {

+            LOG.warning("the wrapped navigation-handler doesn't extend " +

+                ConfigurableNavigationHandler.class.getName() +

+                    ". therefore std. navigation-rules might not work correctly with mojarra");

+            result = new HashMap<String, Set<NavigationCase>>();

+        }

 

         Collection<ViewConfigDescriptor> viewConfigDescriptors = ViewConfigCache.getViewConfigDescriptors();

 

@@ -233,4 +253,70 @@
         result.addAll(createViewConfigBasedNavigationCases(true).entrySet());

         return result;

     }

+

+    //currently not a complete handling, but enough to fix the issues with mojarra

+    private class DelegatingMap extends HashMap<String, Set<NavigationCase>>

+    {

+        private static final long serialVersionUID = -955468874397821639L;

+        private final ConfigurableNavigationHandler wrapped;

+

+        private DelegatingMap(ConfigurableNavigationHandler wrapped)

+        {

+            this.wrapped = wrapped;

+        }

+

+        @Override

+        public Set<NavigationCase> put(String key, Set<NavigationCase> value)

+        {

+            //delegate to the wrapped instance -> the innermost handler needs to receive it

+            //(because mojarra uses ConfigurableNavigationHandler#getNavigationCases

+            // to add cases for std. nav.rules from the outside)

+            return this.wrapped.getNavigationCases().put(key, value);

+        }

+

+        @Override

+        public Set<NavigationCase> get(Object key)

+        {

+            Set<NavigationCase> navigationCases = super.get(key);

+            if (navigationCases == null)

+            {

+                navigationCases = new HashSet<NavigationCase>();

+                put((String)key, navigationCases);

+            }

+

+            return new DelegatingSet(navigationCases, this.wrapped, (String)key);

+        }

+    }

+

+    //currently not a complete handling, but enough to fix the issues with mojarra

+    private class DelegatingSet extends HashSet<NavigationCase>

+    {

+        private static final long serialVersionUID = -7040572530963900394L;

+

+        private final ConfigurableNavigationHandler wrapped;

+        private String navigationCaseKey;

+

+        private DelegatingSet(Collection<? extends NavigationCase> c,

+                              ConfigurableNavigationHandler wrapped,

+                              String navigationCaseKey)

+        {

+            super(c);

+            this.wrapped = wrapped;

+            this.navigationCaseKey = navigationCaseKey;

+        }

+

+        @Override

+        public boolean add(NavigationCase navigationCase)

+        {

+            Set<NavigationCase> navigationCases = this.wrapped.getNavigationCases().get(this.navigationCaseKey);

+

+            if (navigationCases == null)

+            {

+                navigationCases = new HashSet<NavigationCase>();

+                this.wrapped.getNavigationCases().put(this.navigationCaseKey, navigationCases);

+            }

+

+            return navigationCases.add(navigationCase);

+        }

+    }

 }