/* Licensed 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.riotfamily.common.web.mvc.mapping;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import org.riotfamily.common.beans.property.MapPropertyAccessor;
import org.riotfamily.common.util.Generics;
import org.springframework.beans.BeanWrapperImpl;
import org.springframework.beans.PropertyAccessor;
import org.springframework.context.ApplicationContext;
import org.springframework.util.ClassUtils;
import org.springframework.util.CollectionUtils;
import org.springframework.web.servlet.HandlerMapping;
import org.springframework.web.servlet.handler.AbstractUrlHandlerMapping;
public class ReverseUrlHanderMappingAdapter implements ReverseHandlerMappingAdapter {
private String servletPrefix = "";
public void setServletPrefix(String servletPrefix) {
this.servletPrefix = servletPrefix;
}
public boolean supports(HandlerMapping mapping) {
return mapping instanceof AbstractUrlHandlerMapping;
}
public ReverseHandlerMapping adapt(HandlerMapping mapping) {
return new ReverseUrlHandlerMapping((AbstractUrlHandlerMapping) mapping);
}
private class ReverseUrlHandlerMapping implements ReverseHandlerMapping {
private Map<String, List<HandlerUrl>> urlsForName = Generics.newHashMap();
private Map<Class<?>, List<HandlerUrl>> urlsForClass = Generics.newHashMap();
private ApplicationContext context;
public ReverseUrlHandlerMapping(AbstractUrlHandlerMapping mapping) {
context = mapping.getApplicationContext();
Map<String, ?> handlers = mapping.getHandlerMap();
for (Map.Entry<String,?> entry : handlers.entrySet()) {
String url = entry.getKey();
Object handler = entry.getValue();
if (!(handler instanceof String)) {
Class<?> handlerClass = handler.getClass();
register(handlerClass, url, urlsForClass);
}
String handlerName = getHandlerName(handler);
register(handlerName, url, urlsForName);
}
}
private <T> void register(T key, String url, Map<T, List<HandlerUrl>> map) {
List<HandlerUrl> urls = map.get(key);
if (urls == null) {
urls = Generics.newLinkedList();
map.put(key, urls);
}
urls.add(new HandlerUrl(url));
Collections.sort(urls);
}
private String getHandlerName(Object handler) {
if (handler instanceof String) {
return (String) handler;
}
Map<String, ?> beans = context.getBeansOfType(
handler.getClass(), false, false);
for (Map.Entry<String, ?> entry : beans.entrySet()) {
if (entry.getValue().equals(handler)) {
return entry.getKey();
}
}
return null;
}
public String getUrlForHandler(Class<?> handlerClass, Object... vars) {
return fillIn(urlsForClass.get(handlerClass), vars);
}
public String getUrlForHandler(String name, Object... vars) {
return fillIn(urlsForName.get(name), vars);
}
private String fillIn(List<HandlerUrl> urls, Object... vars) {
if (urls != null) {
if (vars != null && vars.length == 1) {
Object var = vars[0];
if (var instanceof Map<?, ?>) {
return getUrl(urls, new MapPropertyAccessor((Map<?, ?>) var));
}
if (var instanceof Collection<?>) {
return getUrl(urls, (Collection<?>) var);
}
if (var.getClass().isArray()) {
return getUrl(urls, CollectionUtils.arrayToList(var));
}
if (var instanceof String
|| ClassUtils.isPrimitiveOrWrapper(var.getClass())) {
return getUrl(urls, Collections.singletonList(var));
}
return getUrl(urls, new BeanWrapperImpl(var));
}
return getUrl(urls, CollectionUtils.arrayToList(vars));
}
return null;
}
private String getUrl(List<HandlerUrl> urls, PropertyAccessor pa) {
for (HandlerUrl uri : urls) {
if (uri.canFillIn(pa)) {
return servletPrefix + uri.fillIn(pa);
}
}
return null;
}
private String getUrl(List<HandlerUrl> urls, Collection<?> values) {
for (HandlerUrl uri : urls) {
if (uri.canFillIn(values)) {
return servletPrefix + uri.fillIn(values);
}
}
return null;
}
}
}