package at.gv.egiz.eaaf.core.impl.gui.utils;
import java.util.Locale;
import javax.annotation.Nullable;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.http.HttpStatus;
import org.springframework.util.Assert;
import org.springframework.web.servlet.LocaleResolver;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.View;
import org.springframework.web.servlet.ViewResolver;
import at.gv.egiz.eaaf.core.api.gui.IGuiBuilderConfiguration;
import lombok.NonNull;
import lombok.extern.slf4j.Slf4j;
/**
* Utils GUI generation by using Spring MVC.
* @author tlenz
*
*/
@Slf4j
public class MvcGuiRenderUtils {
private static final String REQ_ATTR_MODEL_HOLDER = "GUI_MODEL_ASYNCH_RENDERING";
/**
* Build Spring MVC model from GUI configuration.
*
* @param config GUI configuration
* @return MVC model
*/
@NonNull
public static ModelAndView prepareSpringGuiModel(@NonNull final IGuiBuilderConfiguration config) {
final ModelAndView mav = new ModelAndView(config.getViewName());
if (config.getViewParameters() != null) {
mav.addAllObjects(config.getViewParameters());
}
return mav;
}
/**
* Inject GUI-builder configuration into http request to render it asynchronous in Spring intercepter.
*
* @param request Current HttpServletRequest
* @param config Configuration for GUI rendering
*/
public static void setMvcForAsynchRendering(@NonNull final HttpServletRequest request,
@NonNull final IGuiBuilderConfiguration config) {
request.setAttribute(REQ_ATTR_MODEL_HOLDER, prepareSpringGuiModel(config));
}
/**
* Get GUI model for asynchronous rendering.
*
* @param request Current HttpServletRequest
* @return GUI model, or null
of model was set
*/
@Nullable
public static ModelAndView getMvcForAsynchRendering(@NonNull final HttpServletRequest request) {
return (ModelAndView) request.getAttribute(REQ_ATTR_MODEL_HOLDER);
}
/**
* Analyze GUI template and HTTP request to evaluate ContentType of HTTP response generated by this builder.
*
* @param httpReq Current HttpServletRequest
* @param config GUI configuration
* @param viewResolvers Spring based view-resolvers
* @param localeResolver Spring based locale-resolvers
* @return Response content-type, or null
if evaluation has no result
* @throws Exception In case of a GUI rendering error
*/
@Nullable
public static String evaluateResponseContentType(HttpServletRequest httpReq,
IGuiBuilderConfiguration config, @Nullable final ViewResolver[] viewResolvers,
@Nullable final LocaleResolver localeResolver) throws Exception {
return buildViewFromModel(viewResolvers,
getLocaleByRequest(localeResolver, httpReq),
prepareSpringGuiModel(config)).getContentType();
}
/**
* Get i18n information from HTTP request.
*
* @param localeResolver Resolver for localization
* @param request HTTP request
* @return Current locale
*/
public static Locale getLocaleByRequest(LocaleResolver localeResolver, @NonNull HttpServletRequest request) {
return localeResolver != null ? localeResolver.resolveLocale(request) : request.getLocale();
}
/**
* Render a GUI by using Spring based ModelAndView (MVC) components.
*
* @param mv GUI model
* @param request Current HttpServletRequest
* @param response Current HttpServletResponse
* @param viewResolvers Spring based view-resolvers
* @param localeResolver Spring based locale-resolvers
* @throws Exception In case of a GUI rendering error
*/
public static void render(@NonNull final ModelAndView mv, @NonNull final HttpServletRequest request,
@NonNull final HttpServletResponse response, @Nullable final ViewResolver[] viewResolvers,
@Nullable final LocaleResolver localeResolver) throws Exception {
Assert.notNull(request, "http request object");
Assert.notNull(response, "http response object");
Assert.notNull(mv, "Model and view");
// Determine locale for request and apply it to the response.
final Locale locale = getLocaleByRequest(localeResolver, request);
response.setLocale(locale);
// Determine view for response
View view = buildViewFromModel(viewResolvers, locale, mv);
final HttpStatus modelStatus = mv.getStatus();
if (modelStatus != null) {
response.setStatus(modelStatus.value());
} else {
log.trace("HttpStatus is 'null' Set {} as default", HttpServletResponse.SC_OK);
response.setStatus(HttpServletResponse.SC_OK);
}
// Delegate to the View object for rendering.
if (log.isTraceEnabled()) {
log.trace("Rendering view [{}] ", view);
}
try {
view.render(mv.getModelMap(), request, response);
} catch (final Exception ex) {
if (log.isDebugEnabled()) {
log.debug("Error rendering view [{}]", view, null, ex);
}
throw ex;
}
}
private static View buildViewFromModel(ViewResolver[] viewResolvers, Locale locale,
@NonNull ModelAndView mv) throws Exception {
final String viewName = mv.getViewName();
View view;
if (viewName != null) {
// We need to resolve the view name.
view = resolveViewName(viewResolvers, viewName, locale);
if (view == null) {
throw new ServletException("Could not resolve view with name '" + mv.getViewName() + "' ");
}
} else {
// No need to lookup: the ModelAndView object contains the actual View object.
view = mv.getView();
if (view == null) {
throw new ServletException(
"ModelAndView [" + mv + "] neither contains a view name nor a " + "View object ");
}
}
return view;
}
private static View resolveViewName(@Nullable final ViewResolver[] viewResolvers,
final String viewName, final Locale locale) throws Exception {
if (viewResolvers != null) {
for (final ViewResolver viewResolver : viewResolvers) {
final View view = viewResolver.resolveViewName(viewName, locale);
if (view != null) {
return view;
}
}
}
return null;
}
private MvcGuiRenderUtils() {
// private constructor for class with only static methods
}
}