From e3639ef805f1e525415c43cbda80ed71cc43a70c Mon Sep 17 00:00:00 2001
From: Thomas <>
Date: Sun, 9 Jan 2022 15:01:28 +0100
Subject: feature(core): add synch. and asynch. GUI builder implementation that
use Spring MVC architecture
---
.../impl/gui/builder/AsynchGuiFormBuilderImpl.java | 72 ++++++++
.../gui/builder/SpringMvcGuiFormBuilderImpl.java | 57 ++++++
.../AsynchSpringMvcGuiBuilderIntercepter.java | 63 +++++++
.../core/impl/gui/utils/MvcGuiRenderUtils.java | 199 +++++++++++++++++++++
4 files changed, 391 insertions(+)
create mode 100644 eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/gui/builder/AsynchGuiFormBuilderImpl.java
create mode 100644 eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/gui/builder/SpringMvcGuiFormBuilderImpl.java
create mode 100644 eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/gui/interceptor/AsynchSpringMvcGuiBuilderIntercepter.java
create mode 100644 eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/gui/utils/MvcGuiRenderUtils.java
(limited to 'eaaf_core/src/main/java/at/gv/egiz/eaaf/core')
diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/gui/builder/AsynchGuiFormBuilderImpl.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/gui/builder/AsynchGuiFormBuilderImpl.java
new file mode 100644
index 00000000..6ed50955
--- /dev/null
+++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/gui/builder/AsynchGuiFormBuilderImpl.java
@@ -0,0 +1,72 @@
+package at.gv.egiz.eaaf.core.impl.gui.builder;
+
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.servlet.LocaleResolver;
+import org.springframework.web.servlet.ViewResolver;
+
+import at.gv.egiz.eaaf.core.api.gui.IGuiBuilderConfiguration;
+import at.gv.egiz.eaaf.core.api.gui.ISpringMvcGuiFormBuilder;
+import at.gv.egiz.eaaf.core.exceptions.GuiBuildException;
+import at.gv.egiz.eaaf.core.impl.gui.utils.MvcGuiRenderUtils;
+import lombok.extern.slf4j.Slf4j;
+
+@Slf4j
+public class AsynchGuiFormBuilderImpl implements ISpringMvcGuiFormBuilder {
+
+ private @Autowired(required = false) ViewResolver[] viewResolvers;
+ private @Autowired(required = false) LocaleResolver localeResolver;
+
+ @Override
+ public void build(final HttpServletRequest httpReq, final HttpServletResponse httpResp,
+ final IGuiBuilderConfiguration config, final String loggerName) throws GuiBuildException {
+ build(httpReq, httpResp, config, null, loggerName);
+
+ }
+
+ @Override
+ public void build(final HttpServletRequest httpReq, final HttpServletResponse httpResp,
+ final IGuiBuilderConfiguration config, final String contentType, final String loggerName)
+ throws GuiBuildException {
+ if (config.isWriteAsynch()) {
+ log.debug("{} injects GUI model: {} for asynch. rendering", loggerName, config.getViewName());
+ MvcGuiRenderUtils.setMvcForAsynchRendering(httpReq, config);
+
+ } else {
+ renderGuiDirectly(httpReq, httpResp, config, loggerName);
+
+ }
+
+ }
+
+ @Override
+ public String evaluateResponseContentType(HttpServletRequest httpReq, IGuiBuilderConfiguration config,
+ String loggerName) throws GuiBuildException {
+ try {
+ return MvcGuiRenderUtils.evaluateResponseContentType(httpReq, config, viewResolvers, localeResolver);
+
+ } catch (final Exception e) {
+ log.info("Can NOT evaluate contentType for response GUI: {}", loggerName, e);
+ throw new GuiBuildException(e.getMessage(), e);
+
+ }
+ }
+
+ private void renderGuiDirectly(final HttpServletRequest httpReq, final HttpServletResponse httpResp,
+ final IGuiBuilderConfiguration config, final String loggerName) throws GuiBuildException {
+ try {
+ MvcGuiRenderUtils.render(MvcGuiRenderUtils.prepareSpringGuiModel(config),
+ httpReq, httpResp, viewResolvers, localeResolver);
+
+ } catch (final Exception e) {
+ log.info("Can NOT generate GUI for: {}", loggerName, e);
+ throw new GuiBuildException(e.getMessage(), e);
+
+ }
+
+ }
+
+}
diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/gui/builder/SpringMvcGuiFormBuilderImpl.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/gui/builder/SpringMvcGuiFormBuilderImpl.java
new file mode 100644
index 00000000..9fae07e2
--- /dev/null
+++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/gui/builder/SpringMvcGuiFormBuilderImpl.java
@@ -0,0 +1,57 @@
+package at.gv.egiz.eaaf.core.impl.gui.builder;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.servlet.LocaleResolver;
+import org.springframework.web.servlet.ViewResolver;
+
+import at.gv.egiz.eaaf.core.api.gui.IGuiBuilderConfiguration;
+import at.gv.egiz.eaaf.core.api.gui.ISpringMvcGuiFormBuilder;
+import at.gv.egiz.eaaf.core.exceptions.GuiBuildException;
+import at.gv.egiz.eaaf.core.impl.gui.utils.MvcGuiRenderUtils;
+import lombok.extern.slf4j.Slf4j;
+
+@Slf4j
+public class SpringMvcGuiFormBuilderImpl implements ISpringMvcGuiFormBuilder {
+
+ private @Autowired(required = false) ViewResolver[] viewResolvers;
+ private @Autowired(required = false) LocaleResolver localeResolver;
+
+ @Override
+ public void build(final HttpServletRequest httpReq, final HttpServletResponse httpResp,
+ final IGuiBuilderConfiguration config, final String loggerName) throws GuiBuildException {
+ build(httpReq, httpResp, config, null, loggerName);
+
+ }
+
+ @Override
+ public void build(final HttpServletRequest httpReq, final HttpServletResponse httpResp,
+ final IGuiBuilderConfiguration config, final String contentType, final String loggerName)
+ throws GuiBuildException {
+ try {
+ MvcGuiRenderUtils.render(MvcGuiRenderUtils.prepareSpringGuiModel(config),
+ httpReq, httpResp, viewResolvers, localeResolver);
+
+ } catch (final Exception e) {
+ log.info("Can NOT generate GUI for: {}", loggerName, e);
+ throw new GuiBuildException(e.getMessage(), e);
+
+ }
+ }
+
+ @Override
+ public String evaluateResponseContentType(HttpServletRequest httpReq, IGuiBuilderConfiguration config,
+ String loggerName) throws GuiBuildException {
+ try {
+ return MvcGuiRenderUtils.evaluateResponseContentType(httpReq, config, viewResolvers, localeResolver);
+
+ } catch (final Exception e) {
+ log.info("Can NOT evaluate contentType for response GUI: {}", loggerName, e);
+ throw new GuiBuildException(e.getMessage(), e);
+
+ }
+ }
+
+}
diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/gui/interceptor/AsynchSpringMvcGuiBuilderIntercepter.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/gui/interceptor/AsynchSpringMvcGuiBuilderIntercepter.java
new file mode 100644
index 00000000..708e3b84
--- /dev/null
+++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/gui/interceptor/AsynchSpringMvcGuiBuilderIntercepter.java
@@ -0,0 +1,63 @@
+package at.gv.egiz.eaaf.core.impl.gui.interceptor;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.servlet.HandlerInterceptor;
+import org.springframework.web.servlet.LocaleResolver;
+import org.springframework.web.servlet.ModelAndView;
+import org.springframework.web.servlet.ViewResolver;
+
+import at.gv.egiz.eaaf.core.exceptions.GuiBuildException;
+import at.gv.egiz.eaaf.core.impl.gui.utils.MvcGuiRenderUtils;
+import lombok.extern.slf4j.Slf4j;
+
+/**
+ * Intercepter to render GUI in response processing.
+ *
+ * @author tlenz
+ *
+ */
+@Slf4j
+public class AsynchSpringMvcGuiBuilderIntercepter implements HandlerInterceptor {
+
+ private @Autowired(required = false) ViewResolver[] viewResolvers;
+ private @Autowired(required = false) LocaleResolver localeResolver;
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * org.springframework.web.servlet.HandlerInterceptor#postHandle(javax.servlet.
+ * http. HttpServletRequest, javax.servlet.http.HttpServletResponse,
+ * java.lang.Object, org.springframework.web.servlet.ModelAndView)
+ */
+ @Override
+ public void postHandle(final HttpServletRequest httpReq, final HttpServletResponse httpResp,
+ final Object handler, final ModelAndView modelAndView) throws Exception {
+
+ final ModelAndView model = MvcGuiRenderUtils.getMvcForAsynchRendering(httpReq);
+ if (model != null) {
+ log.debug("Find GUI model: {} Starting model rendering ... ", model.getViewName());
+ renderGui(model, httpReq, httpResp);
+
+ } else {
+ log.trace("No GUI model skipping asynch model rendering");
+
+ }
+
+ }
+
+ private void renderGui(final ModelAndView mav,
+ final HttpServletRequest httpReq, final HttpServletResponse httpResp) throws GuiBuildException {
+ try {
+ MvcGuiRenderUtils.render(mav, httpReq, httpResp, viewResolvers, localeResolver);
+
+ } catch (final Exception e) {
+ log.info("Can NOT generate GUI for illustration", e);
+ throw new GuiBuildException(e.getMessage(), e);
+
+ }
+ }
+}
diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/gui/utils/MvcGuiRenderUtils.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/gui/utils/MvcGuiRenderUtils.java
new file mode 100644
index 00000000..5a3f14cb
--- /dev/null
+++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/gui/utils/MvcGuiRenderUtils.java
@@ -0,0 +1,199 @@
+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();
+
+ }
+
+ /**
+ * 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 Locale getLocaleByRequest(LocaleResolver localeResolver, @NonNull HttpServletRequest request) {
+ return localeResolver != null ? localeResolver.resolveLocale(request) : request.getLocale();
+
+ }
+
+ 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
+ }
+
+}
--
cgit v1.2.3