package ddth.dasp.hetty.mvc;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import org.osgi.framework.BundleContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.osgi.context.BundleContextAware;
import ddth.dasp.common.utils.OsgiUtils;
import ddth.dasp.framework.osgi.IServiceAutoRegister;
import ddth.dasp.hetty.IRequestActionHandler;
import ddth.dasp.hetty.IUrlCreator;
import ddth.dasp.hetty.message.IRequest;
import ddth.dasp.hetty.message.IRequestParser;
import ddth.dasp.hetty.mvc.view.IView;
import ddth.dasp.hetty.mvc.view.IViewResolver;
import ddth.dasp.hetty.mvc.view.RedirectView;
import ddth.dasp.hetty.qnt.ITopicPublisher;
/**
* This action handler implements the following workflow:
* <ul>
* <li>
* {@link #internalHandleRequest(IRequest, ITopicPublisher)} is called to handle
* the request. If a view object is returned:
* <ul>
* <li>
* {@link #resolveVew(IRequest, String)} is called to resolve the view.</li>
* <li>If the view is resolved, {@link #buildViewModel()} is called to build the
* view model</li>
* <li>If the view is resolved, method
* {@link IView#render(IRequest, Object, ITopicPublisher)} is call to render
* view.</li></li>
* </ul>
*
* @author Thanh Ba Nguyen <btnguyen2k@gmail.com>
*/
public abstract class AbstractActionHandler implements IRequestActionHandler, IServiceAutoRegister,
ApplicationContextAware, BundleContextAware {
private final static Logger LOGGER = LoggerFactory.getLogger(AbstractActionHandler.class);
private ApplicationContext appContext;
private BundleContext bundleContext;
private Properties properties;
private IViewResolver viewResolver;
private IRequestParser requestParser;
private IUrlCreator urlCreator;
private String viewName;
public String getViewName() {
return viewName;
}
public void setViewName(String viewName) {
this.viewName = viewName;
}
public void setViewResolver(IViewResolver viewResolver) {
this.viewResolver = viewResolver;
}
protected IViewResolver getViewResolver() {
if (viewResolver == null) {
try {
viewResolver = appContext.getBean(IViewResolver.class);
} catch (Exception e) {
LOGGER.error(e.getMessage(), e);
}
}
return viewResolver;
}
public void setRequestParser(IRequestParser requestParser) {
this.requestParser = requestParser;
}
protected IRequestParser getRequestParser() {
if (requestParser == null) {
try {
requestParser = appContext.getBean(IRequestParser.class);
} catch (Exception e) {
LOGGER.error(e.getMessage(), e);
}
}
return requestParser;
}
public void setUrlCreator(IUrlCreator urlCreator) {
this.urlCreator = urlCreator;
}
protected IUrlCreator getUrlCreator() {
if (urlCreator == null) {
try {
urlCreator = appContext.getBean(IUrlCreator.class);
} catch (Exception e) {
LOGGER.error(e.getMessage(), e);
}
}
return urlCreator;
}
/**
* {@inheritDoc}
*/
@Override
public String getClassName() {
return IRequestActionHandler.class.getName();
}
/**
* {@inheritDoc}
*/
@Override
public Properties getProperties() {
return properties;
}
public void setProperties(Properties properties) {
this.properties = properties;
}
/**
* {@inheritDoc}
*/
@Override
public void handleRequest(IRequest request, ITopicPublisher topicPublisher, String topicName)
throws Exception {
if (!preHandleRequest(request, topicPublisher)) {
return;
}
Object view = internalHandleRequest(request, topicPublisher, topicName);
if (view == null) {
postHandleRequest(request, null, null);
return;
}
Object oldView = view;
if (!(view instanceof IView)) {
String viewName = view.toString();
view = resolveVew(request, viewName);
}
if (view instanceof IView) {
Map<String, Object> model = view instanceof RedirectView ? null
: buildViewModel(request);
postHandleRequest(request, model, (IView) view);
((IView) view).render(request, model, topicPublisher, topicName);
} else {
postHandleRequest(request, null, null);
String msg = "Can not resolve view for [" + oldView + "]!";
throw new Exception(msg);
}
}
/**
* This method simply returns an empty {@link Map}. Sub-class overrides this
* method to build its own model.
*
* @param request
* @return
*/
protected Map<String, Object> buildViewModel(IRequest request) {
Map<String, Object> model = new HashMap<String, Object>();
return model;
}
/**
* {@link #handleRequest(IRequest, ITopicPublisher)} calls this method
* before handling the request.
*
* @param request
* @param topicPublisher
* @return <code>true</code> to indicates that request should be handled
* normally, <code>false</code> to indicate that request has already
* been completely handled by this method and should not be handled
* any further
*/
protected boolean preHandleRequest(IRequest request, ITopicPublisher topicPublisher) {
return true;
}
/**
* Sub-class to implement this method to implement its own business. This
* method is called by {@link #handleRequest(IRequest, ITopicPublisher)}.
*
* @param request
* @param topicPublisher
* @param topicName
* @return
*/
protected abstract Object internalHandleRequest(IRequest request,
ITopicPublisher topicPublisher, String topicName) throws Exception;
/**
* {@link #handleRequest(IRequest, ITopicPublisher)} calls this method after
* request has been handled, and before rendering view.
*
* @param request
* @param model
* @param view
*/
protected void postHandleRequest(IRequest request, Map<String, Object> model, IView view) {
// EMPTY
}
/**
* Resolves a view name to {@link IView} object.
*
* @param request
* @param viewName
* @return
*/
protected IView resolveVew(IRequest request, String viewName) {
Map<String, String> replacements = new HashMap<String, String>();
IViewResolver viewResolver = getViewResolver();
return viewResolver.resolveView(viewName, replacements);
}
/**
* Gets a Spring bean by class.
*
* @param clazz
* @return
*/
protected <T> T getSpringBean(Class<T> clazz) {
try {
return appContext.getBean(clazz);
} catch (NoSuchBeanDefinitionException e) {
return null;
}
}
/**
* Gets a Spring bean by name.
*
* @param name
* @return
*/
protected Object getSpringBean(String name) {
try {
return appContext.getBean(name);
} catch (NoSuchBeanDefinitionException e) {
return null;
}
}
/**
* Gets a Spring bean by name and class.
*
* @param name
* @param clazz
* @return
*/
protected <T> T getSpringBean(String name, Class<T> clazz) {
try {
return appContext.getBean(name, clazz);
} catch (NoSuchBeanDefinitionException e) {
return null;
}
}
/**
* {@inheritDoc}
*/
@Override
public void setApplicationContext(ApplicationContext appContext) {
this.appContext = appContext;
}
protected ApplicationContext getApplicationContext() {
return appContext;
}
/**
* Gets an OSGi service by class.
*
* @param clazz
* @return
*/
protected <T> T getService(Class<T> clazz) {
return OsgiUtils.getService(bundleContext, clazz);
}
/**
* Gets an OSGi service by class and filter.
*
* @param clazz
* @param filter
* @return
*/
protected <T> T getService(Class<T> clazz, Map<String, String> filter) {
return OsgiUtils.getService(bundleContext, clazz, filter);
}
/**
* Gets an OSGi service by class and filter.
*
* @param clazz
* @param filterQuery
* @return
*/
protected <T> T getService(Class<T> clazz, String filterQuery) {
return OsgiUtils.getService(bundleContext, clazz, filterQuery);
}
@Override
public void setBundleContext(BundleContext bundleContext) {
this.bundleContext = bundleContext;
}
protected BundleContext getBundleContext() {
return bundleContext;
}
}