package org.gwtoolbox.springrpc;
import com.google.gwt.user.client.rpc.RemoteService;
import com.google.gwt.user.client.rpc.RemoteServiceRelativePath;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.tools.ant.util.ClasspathUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.FatalBeanException;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.beans.factory.config.*;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.GenericBeanDefinition;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.util.ClassUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.handler.SimpleUrlHandlerMapping;
/**
* @author Uri Boness
*/
public class GwtServiceBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
private final static Log logger = LogFactory.getLog(GwtServiceBeanFactoryPostProcessor.class);
private String pathPrefix;
private String unexpectedExceptionMappingsBeanName;
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
String[] names = beanFactory.getBeanNamesForType(RemoteService.class);
StringBuilder sb = new StringBuilder();
for (String name : names) {
BeanDefinition beanDeifnition = beanFactory.getBeanDefinition(name);
String className = beanDeifnition.getBeanClassName();
String[] paths = resolvePaths(className);
for (String path : paths) {
if (path.startsWith("/")) {
path = path.substring(1);
}
String fullPath = pathPrefix + path;
String controllerName = name + "Controller";
sb.append(fullPath).append("=").append(controllerName).append("\n");
}
}
GenericBeanDefinition mapperDef = new GenericBeanDefinition();
mapperDef.setBeanClass(SimpleUrlHandlerMapping.class);
MutablePropertyValues propertyValues = new MutablePropertyValues();
propertyValues.addPropertyValue("mappings", new TypedStringValue(sb.toString()));
mapperDef.setPropertyValues(propertyValues);
((BeanDefinitionRegistry) beanFactory).registerBeanDefinition("__urlMapper", mapperDef);
for (String name : names) {
GenericBeanDefinition definition = new GenericBeanDefinition();
definition.setBeanClass(GwtRpcController.class);
propertyValues = new MutablePropertyValues();
propertyValues.addPropertyValue("remoteService", new RuntimeBeanReference(name));
if (unexpectedExceptionMappingsBeanName != null) {
if (logger.isDebugEnabled()) {
logger.debug("Registering unexpected exception mappings on controler: " + name + "Controller");
}
propertyValues.addPropertyValue("unexpectedExceptionMappings", new RuntimeBeanReference(unexpectedExceptionMappingsBeanName));
}
definition.setPropertyValues(propertyValues);
if (logger.isDebugEnabled()) {
logger.debug("Registering controller: " + name + "Controller");
}
((BeanDefinitionRegistry) beanFactory).registerBeanDefinition(name + "Controller", definition);
}
}
//============================================ Setter/Getter Methods ===============================================
public void setPathPrefix(String pathPrefix) {
if (!pathPrefix.endsWith("/")) {
pathPrefix += "/";
}
this.pathPrefix = pathPrefix;
}
public void setUnexpectedExceptionMappingsBeanName(String unexpectedExceptionMappingsBeanName) {
this.unexpectedExceptionMappingsBeanName = unexpectedExceptionMappingsBeanName;
}
//================================================ Helper Methods ==================================================
protected String[] resolvePaths(String className) {
Class clazz = loadClass(className);
RequestMapping path = AnnotationUtils.findAnnotation(clazz, RequestMapping.class);
if (path == null) {
String value = resolvePathFromServiceInterface(clazz);
if (value == null) {
throw new FatalBeanException("Could not resolve GWT remote service path - either define a @RemoteServiceRelativePath annotation on the" +
"remote service interface or define a @RequestMapping annotation on the service '" +
clazz.getName() + "' class hierarchy");
}
return new String[] { value };
}
return path.value();
}
protected String resolvePathFromServiceInterface(Class serviceImplClass) {
for (Class clazz : serviceImplClass.getInterfaces()) {
if (clazz.isAnnotationPresent(RemoteServiceRelativePath.class)) {
RemoteServiceRelativePath path = (RemoteServiceRelativePath) clazz.getAnnotation(RemoteServiceRelativePath.class);
return path.value();
}
}
return null;
}
protected Class loadClass(String className) {
try {
return ClassUtils.forName(className, ClassUtils.getDefaultClassLoader());
} catch (ClassNotFoundException cnfe){
throw new FatalBeanException("Cannot load class '" + className + "'", cnfe);
}
}
}