001package io.jstach.opt.spring.webmvc;
002
003import java.util.ArrayList;
004import java.util.List;
005
006import org.eclipse.jdt.annotation.Nullable;
007import org.springframework.context.ApplicationContext;
008import org.springframework.web.servlet.HandlerInterceptor;
009import org.springframework.web.servlet.ModelAndView;
010import org.springframework.web.servlet.View;
011import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
012import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
013
014import jakarta.servlet.http.HttpServletRequest;
015import jakarta.servlet.http.HttpServletResponse;
016
017/**
018 * A {@link HandlerInterceptor} that automatically applies all
019 * {@link JStachioModelViewConfigurer} instances to views before rendering. Also
020 * implements {@link WebMvcConfigurer} so that it registers itself when the servlet
021 * context starts.
022 *
023 * @author dsyer
024 */
025@SuppressWarnings("exports")
026public class ViewSetupHandlerInterceptor implements HandlerInterceptor, WebMvcConfigurer {
027
028        private final List<JStachioModelViewConfigurer> configurers = new ArrayList<>();
029
030        private final ApplicationContext context;
031
032        /**
033         * Injected context will be searched for {@link JStachioModelViewConfigurer}
034         * @param context autowired.
035         */
036        public ViewSetupHandlerInterceptor(ApplicationContext context) {
037                for (String name : context.getBeanNamesForType(JStachioModelViewConfigurer.class)) {
038                        this.configurers.add((JStachioModelViewConfigurer) context.getBean(name));
039                }
040                this.context = context;
041        }
042
043        /**
044         * {@inheritDoc} If the modelAndView is a {@link JStachioModelView} then it will be
045         * configured with all of the found {@link JStachioModelViewConfigurer} in the
046         * application context.
047         */
048        @Override
049        public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
050                        ModelAndView modelAndView) throws Exception {
051                @Nullable
052                JStachioModelView view = findView(modelAndView);
053                if (view != null) {
054                        Object page = view.model();
055                        for (JStachioModelViewConfigurer configurer : configurers) {
056                                configurer.configure(page, modelAndView.getModel(), request);
057                        }
058                }
059        }
060
061        private @Nullable JStachioModelView findView(ModelAndView modelAndView) {
062                if (modelAndView != null) {
063                        if (modelAndView.getView() instanceof JStachioModelView) {
064                                return (JStachioModelView) modelAndView.getView();
065                        }
066                        if (modelAndView.getView() instanceof View) {
067                                return null;
068                        }
069                        if (this.context.containsBean(modelAndView.getViewName())
070                                        && this.context.getBean(modelAndView.getViewName()) instanceof JStachioModelView view) {
071                                return view;
072                        }
073                }
074                return null;
075        }
076
077        @Override
078        public void addInterceptors(InterceptorRegistry registry) {
079                registry.addInterceptor(this);
080        }
081
082}