package org.sothis.mvc;
import java.io.IOException;
import java.lang.reflect.Modifier;
import java.util.HashMap;
import java.util.Map;
import org.sothis.core.beans.BeanFactory;
import org.sothis.core.beans.BeanInstantiationException;
import org.sothis.core.util.ClassUtils;
import org.sothis.core.util.StringUtils;
public class DefaultApplicationContext implements ApplicationContext {
private final Map<Object, Action> actions = new HashMap<Object, Action>();
private final BeanFactory beanFactory;
private final Configuration configuration;
private final String contextPath;
private final Object nativeContext;
public DefaultApplicationContext(BeanFactory beanFactory, Configuration configuration, Object nativeContext)
throws BeanInstantiationException, ClassNotFoundException, IOException, ConfigurationException {
this("", beanFactory, configuration, nativeContext);
}
public DefaultApplicationContext(String contextPath, BeanFactory beanFactory, Configuration configuration,
Object nativeContext) throws BeanInstantiationException, ClassNotFoundException, IOException, ConfigurationException {
if (null == contextPath) {
throw new IllegalArgumentException("context path can not be null.");
}
this.contextPath = contextPath;
this.beanFactory = beanFactory;
this.configuration = configuration;
this.nativeContext = nativeContext;
regBeans();
initActions();
}
private void regBean(Class<?> c) {
this.beanFactory.registerBean(c.getName(), c);
}
private void regBeans() {
regBean(this.configuration.getActionMapper());
regBean(this.configuration.getModelAndViewResolver());
regBean(this.configuration.getExceptionHandler());
Map<String, Class<? extends View>> views = this.configuration.getViews();
for (Map.Entry<String, Class<? extends View>> entry : views.entrySet()) {
regBean(entry.getValue());
}
Map<String, Class<Interceptor>> interceptors = this.configuration.getInterceptors();
for (Map.Entry<String, Class<Interceptor>> entry : interceptors.entrySet()) {
regBean(entry.getValue());
}
}
private void initActions() throws BeanInstantiationException, ClassNotFoundException, IOException, ConfigurationException {
final String[] packageNames = configuration.getControllerPackages();
ActionMapper actionMapper = beanFactory.getBean(configuration.getActionMapper());
for (String packageName : packageNames) {
if (StringUtils.isEmpty(packageName)) {
continue;
}
final Class<?>[] classes = ClassUtils.getClasses(packageName);
for (Class<?> c : classes) {
if (c.isLocalClass() || c.isMemberClass() || c.isAnonymousClass() || c.isAnnotationPresent(Ignore.class)
|| c.getPackage().isAnnotationPresent(Ignore.class) || Modifier.isAbstract(c.getModifiers())
|| Modifier.isInterface(c.getModifiers()) || !Modifier.isPublic(c.getModifiers())) {
continue;
}
final String className = c.getName().substring(packageName.length() + 1);
String subPackageName;
int dotIndex = className.lastIndexOf('.');
if (dotIndex > 0) {
subPackageName = className.substring(0, dotIndex).replaceAll("\\.", "/");
} else {
subPackageName = "";
}
final String simpleName = c.getSimpleName();
dotIndex = simpleName.indexOf(Controller.CONTROLLER_SUFFIX);
String name;
if (dotIndex > 0) {
name = StringUtils.uncapitalize(simpleName.substring(0, dotIndex));
} else if (dotIndex == 0) {
name = "";
} else {
continue;
}
Controller controller = new DefaultController(this.configuration, subPackageName, name, c);
beanFactory.registerBean(c.getName(), c);
Map<String, Action> controllerActions = controller.getActions();
for (String actionName : controllerActions.keySet()) {
Action action = controllerActions.get(actionName);
Object actionKey = actionMapper.map(this, action);
if (actions.containsKey(actionKey)) {
throw new ConfigurationException("duplicated action key:" + actionKey + ", which already registered as "
+ actions.get(actionKey));
}
actions.put(actionKey, action);
}
if (configuration.isInitializeControllerOnStartup()) {
this.beanFactory.getBean(c);
}
}
}
}
@Override
public boolean containsAction(Object key) {
return this.actions.containsKey(key);
}
@Override
public Action getAction(Object key) {
return this.actions.get(key);
}
@Override
public Configuration getConfiguration() {
return configuration;
}
@Override
public BeanFactory getBeanFactory() {
return beanFactory;
}
@Override
public Map<Object, Action> getActions() {
return this.actions;
}
public String getContextPath() {
return contextPath;
}
public Object getNativeContext() {
return nativeContext;
}
}