| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| */ |
| package org.apache.deltaspike.jsf.impl.config.view.navigation; |
| |
| import org.apache.deltaspike.core.api.config.view.metadata.ViewConfigDescriptor; |
| import org.apache.deltaspike.core.api.config.view.metadata.ViewConfigResolver; |
| import org.apache.deltaspike.core.api.provider.BeanProvider; |
| import org.apache.deltaspike.jsf.api.config.view.View; |
| import org.apache.deltaspike.jsf.impl.util.JsfUtils; |
| import org.apache.deltaspike.jsf.impl.util.RequestParameter; |
| |
| import javax.faces.application.ConfigurableNavigationHandler; |
| import javax.faces.application.NavigationCase; |
| import javax.faces.application.NavigationHandler; |
| import java.util.List; |
| import java.util.Set; |
| import java.util.Map; |
| 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). |
| * Reason: It isn't allowed to remove navigation cases |
| * (which are based on {@link org.apache.deltaspike.core.api.config.view.ViewConfig}) |
| */ |
| public class NavigationCaseMapWrapper implements Map<String, Set<NavigationCase>> |
| { |
| private static final Logger LOG = Logger.getLogger(NavigationCaseMapWrapper.class.getName()); |
| |
| private Map<String, Set<NavigationCase>> wrappedNavigationCaseMap; |
| private final NavigationHandler wrapped; |
| private final Map<String, Set<NavigationCase>> viewConfigBasedNavigationCaseCache; |
| |
| /** |
| * Constructor for wrapping the given navigation-cases |
| * |
| * @param navigationCases current navigation-cases |
| * @param wrapped wrapped navigation-handler |
| */ |
| 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; |
| |
| 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 = |
| BeanProvider.getContextualReference(ViewConfigResolver.class).getViewConfigDescriptors(); |
| |
| if (!viewConfigDescriptors.isEmpty()) |
| { |
| Set<NavigationCase> navigationCase = new HashSet<NavigationCase>(); |
| |
| Map<String, List<String>> parameters = null; |
| |
| if (allowParameters) |
| { |
| parameters = resolveParameters(); |
| } |
| |
| boolean includeParameters; |
| |
| for (ViewConfigDescriptor entry : viewConfigDescriptors) |
| { |
| View viewMetaData = entry.getMetaData(View.class).iterator().next(); |
| includeParameters = View.ViewParameterMode.INCLUDE |
| .equals(viewMetaData.viewParams()); |
| |
| navigationCase.add(new NavigationCase("*", |
| null, |
| null, |
| null, |
| entry.getViewId(), |
| includeParameters ? parameters : null, |
| View.NavigationMode.REDIRECT.equals(viewMetaData.navigation()), |
| includeParameters)); |
| |
| result.put(entry.getViewId(), navigationCase); |
| } |
| } |
| return result; |
| } |
| |
| private Map<String, List<String>> resolveParameters() |
| { |
| Map<String, List<String>> parameters = new HashMap<String, List<String>>(); |
| |
| for (RequestParameter parameter : JsfUtils.getViewConfigPageParameters()) |
| { |
| parameters.put(parameter.getKey(), parameter.getValueList()); |
| } |
| |
| return parameters; |
| } |
| |
| /** |
| * @return the final size (might be a combination of the configured navigation cases (via XML) and the |
| * {@link org.apache.deltaspike.core.api.config.view.ViewConfig}s |
| */ |
| @Override |
| public int size() |
| { |
| return this.wrappedNavigationCaseMap.size() + this.viewConfigBasedNavigationCaseCache.size(); |
| } |
| |
| @Override |
| public boolean isEmpty() |
| { |
| return this.wrappedNavigationCaseMap.isEmpty() && |
| this.viewConfigBasedNavigationCaseCache.isEmpty(); |
| } |
| |
| @Override |
| public boolean containsKey(Object key) |
| { |
| return this.wrappedNavigationCaseMap.containsKey(key) || |
| this.viewConfigBasedNavigationCaseCache.containsKey(key); |
| } |
| |
| @Override |
| public boolean containsValue(Object value) |
| { |
| return this.wrappedNavigationCaseMap.containsValue(value) || |
| this.viewConfigBasedNavigationCaseCache.containsValue(value); |
| } |
| |
| /** |
| * XML configuration overrules {@link org.apache.deltaspike.core.api.config.view.ViewConfig}s |
| */ |
| @Override |
| public Set<NavigationCase> get(Object key) |
| { |
| Set<NavigationCase> result = this.wrappedNavigationCaseMap.get(key); |
| |
| if (result == null) |
| { |
| return createViewConfigBasedNavigationCases(true).get(key); |
| } |
| return result; |
| } |
| |
| @Override |
| public Set<NavigationCase> put(String key, Set<NavigationCase> value) |
| { |
| return this.wrappedNavigationCaseMap.put(key, value); |
| } |
| |
| @Override |
| public Set<NavigationCase> remove(Object key) |
| { |
| return this.wrappedNavigationCaseMap.remove(key); |
| } |
| |
| @Override |
| public void putAll(Map<? extends String, ? extends Set<NavigationCase>> m) |
| { |
| this.wrappedNavigationCaseMap.putAll(m); |
| } |
| |
| @Override |
| public void clear() |
| { |
| this.wrappedNavigationCaseMap.clear(); |
| } |
| |
| /** |
| * @return a combination of navigation-cases configured via XML and |
| * {@link org.apache.deltaspike.core.api.config.view.ViewConfig}s |
| */ |
| @Override |
| public Set<String> keySet() |
| { |
| Set<String> result = new HashSet<String>(); |
| result.addAll(this.wrappedNavigationCaseMap.keySet()); |
| result.addAll(this.viewConfigBasedNavigationCaseCache.keySet()); |
| return result; |
| } |
| |
| /** |
| * @return a combination of navigation-cases configured via XML and |
| * {@link org.apache.deltaspike.core.api.config.view.ViewConfig}s |
| */ |
| @Override |
| public Collection<Set<NavigationCase>> values() |
| { |
| Collection<Set<NavigationCase>> result = new HashSet<Set<NavigationCase>>(); |
| |
| result.addAll(this.wrappedNavigationCaseMap.values()); |
| result.addAll(createViewConfigBasedNavigationCases(true).values()); |
| return result; |
| } |
| |
| /** |
| * @return a combination of navigation-cases configured via XML and |
| * {@link org.apache.deltaspike.core.api.config.view.ViewConfig}s |
| */ |
| @Override |
| public Set<Entry<String, Set<NavigationCase>>> entrySet() |
| { |
| Set<Entry<String, Set<NavigationCase>>> result = new HashSet<Entry<String, Set<NavigationCase>>>(); |
| |
| result.addAll(this.wrappedNavigationCaseMap.entrySet()); |
| 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) |
| { |
| if (value == null) |
| { |
| return null; |
| } |
| |
| Set<NavigationCase> result = new HashSet<NavigationCase>(); |
| |
| //filter entries created by createViewConfigBasedNavigationCases |
| for (NavigationCase navigationCase : value) |
| { |
| if (!(navigationCase.getFromOutcome() == null && navigationCase.getFromAction() == null)) |
| { |
| result.add(navigationCase); |
| } |
| } |
| |
| //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, result); |
| } |
| |
| @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); |
| } |
| } |
| } |