/*
* Copyright 2009-2015 the original author or authors.
*
* 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.jdal.vaadin;
import java.io.Serializable;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jdal.annotation.SerializableProxy;
import org.jdal.vaadin.annotation.UiMapping;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.PathMatcher;
import com.vaadin.server.VaadinRequest;
import com.vaadin.ui.UI;
/**
* {@link UiRequestMapping} implementation that look for {@link UI UIs} by bean name.
* Parse {@link UiMapping} annotations in spring context UI types and match urls using
* an {@link AntPathMatcher}.
*
* @author Jose Luis Martin
* @since 2.1
*/
@SerializableProxy
public class UrlBeanNameUiMapping implements UiRequestMapping, Serializable {
private static final Log log = LogFactory.getLog(UrlBeanNameUiMapping.class);
/** translate paths to bean names */
private Map<String, String> urlMap = new ConcurrentHashMap<String, String>();;
/** Used to match url paths */
private transient PathMatcher pathMatcher = new AntPathMatcher();
@Override
public UI getUi(VaadinRequest request) {
ApplicationContext ctx = VaadinUtils.getApplicationContext();
String beanName = getBeanNameFromRequest(request);
if (beanName != null && ctx.containsBean(beanName))
return VaadinUtils.getApplicationContext().getBean(beanName, UI.class);
return null;
}
/**
* Try to match a ant url pattern in url mapping and return the UI bean name
* @param request vaadin request
* @return the bean name for request, null if none.
*/
protected String getBeanNameFromRequest(VaadinRequest request) {
String beanName = null;
String pathInfo = request.getPathInfo();
if (this.pathMatcher == null)
this.pathMatcher = new AntPathMatcher();
for (String pattern : this.urlMap.keySet()) {
if (log.isDebugEnabled())
log.debug("Matching pattern [" + pattern + "] over path info [" + pathInfo + "]");
if (this.pathMatcher.match(pattern, request.getPathInfo())) {
beanName = this.urlMap.get(pattern);
if (log.isDebugEnabled())
log.debug("Matching success. Using bean name [" + beanName + "]");
break;
}
}
if (beanName == null)
beanName = request.getPathInfo();
return beanName;
}
/**
* Init th url map parsing {@link UiMapping} annotations
* @param ctx ApplicationContext
*/
@Autowired
public void init(ApplicationContext ctx) {
Map<String, Object> uis = ctx.getBeansWithAnnotation(UiMapping.class);
for (String name : uis.keySet()) {
Object ui = uis.get(name);
if (ui instanceof UI) {
UiMapping ann = AnnotationUtils.findAnnotation(ui.getClass(), UiMapping.class);
if (ann != null) {
if (log.isDebugEnabled())
log.debug("Mapping UI [" + ui.getClass().getName() + "] to request path [" + ann.value() + "]");
this.urlMap.put(ann.value(), name);
}
}
}
}
/**
* Lookup UI class from application context.
* @param request request
*/
@Override
@SuppressWarnings("unchecked")
public Class<?extends UI> getUiClass(VaadinRequest request) {
ApplicationContext ctx = VaadinUtils.getApplicationContext();
String beanName = getBeanNameFromRequest(request);
if (beanName != null && ctx.containsBean(beanName))
return (Class<? extends UI>) ctx.getType(beanName);
return null;
}
}