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