Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Continue ControllersAutoConfiguration Migration #13866

Merged
merged 3 commits into from
Nov 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,22 +1,30 @@
package org.grails.plugins.web.controllers;

import grails.config.Settings;
import grails.core.GrailsApplication;
import jakarta.servlet.DispatcherType;
import jakarta.servlet.Filter;
import jakarta.servlet.MultipartConfigElement;
import org.grails.web.config.http.GrailsFilters;
import org.grails.web.filters.HiddenHttpMethodFilter;
import org.grails.web.servlet.mvc.GrailsDispatcherServlet;
import org.grails.web.servlet.mvc.GrailsWebRequestFilter;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.boot.autoconfigure.web.servlet.DispatcherServletRegistrationBean;
import org.springframework.boot.autoconfigure.web.servlet.HttpEncodingAutoConfiguration;
import org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.boot.web.servlet.filter.OrderedCharacterEncodingFilter;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.util.ClassUtils;
import org.springframework.web.filter.CharacterEncodingFilter;
import org.springframework.web.servlet.DispatcherServlet;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import java.util.EnumSet;

Expand All @@ -30,6 +38,30 @@ public class ControllersAutoConfiguration {
@Value("${" + Settings.FILTER_FORCE_ENCODING + ":false}")
private boolean filtersForceEncoding;

@Value("${" + Settings.RESOURCES_CACHE_PERIOD + ":0}")
private int resourcesCachePeriod;

@Value("${" + Settings.RESOURCES_ENABLED + ":true}")
private boolean resourcesEnabled;

@Value("${" + Settings.RESOURCES_PATTERN + ":" + Settings.DEFAULT_RESOURCE_PATTERN + "}")
private String resourcesPattern;

@Value("${" + Settings.CONTROLLERS_UPLOAD_LOCATION + ":#{null}}")
private String uploadTmpDir;

@Value("${" + Settings.CONTROLLERS_UPLOAD_MAX_FILE_SIZE + ":128000}")
private long maxFileSize;

@Value("${" + Settings.CONTROLLERS_UPLOAD_MAX_REQUEST_SIZE + ":128000}")
private long maxRequestSize;

@Value("${" + Settings.CONTROLLERS_UPLOAD_FILE_SIZE_THRESHOLD + ":0}")
private int fileSizeThreshold;

@Value("${" + Settings.WEB_SERVLET_PATH + ":#{null}}")
String grailsServletPath;

@Bean
@ConditionalOnMissingBean(CharacterEncodingFilter.class)
public CharacterEncodingFilter characterEncodingFilter() {
Expand Down Expand Up @@ -67,4 +99,84 @@ public FilterRegistrationBean<Filter> grailsWebRequestFilter(ApplicationContext
registrationBean.setOrder(GrailsFilters.GRAILS_WEB_REQUEST_FILTER.getOrder());
return registrationBean;
}

@Bean
public MultipartConfigElement multipartConfigElement() {
if (uploadTmpDir == null) {
uploadTmpDir = System.getProperty("java.io.tmpdir");
}
return new MultipartConfigElement(uploadTmpDir, maxFileSize, maxRequestSize, fileSizeThreshold);
}

@Bean
public DispatcherServlet dispatcherServlet() {
return new GrailsDispatcherServlet();
}

@Bean
public DispatcherServletRegistrationBean dispatcherServletRegistration(GrailsApplication application, DispatcherServlet dispatcherServlet, MultipartConfigElement multipartConfigElement) {
if (grailsServletPath == null) {
boolean isTomcat = ClassUtils.isPresent("org.apache.catalina.startup.Tomcat", application.getClassLoader());
grailsServletPath = isTomcat ? Settings.DEFAULT_TOMCAT_SERVLET_PATH : Settings.DEFAULT_WEB_SERVLET_PATH;
}
DispatcherServletRegistrationBean dispatcherServletRegistration = new DispatcherServletRegistrationBean(dispatcherServlet, grailsServletPath);
dispatcherServletRegistration.setLoadOnStartup(2);
dispatcherServletRegistration.setAsyncSupported(true);
dispatcherServletRegistration.setMultipartConfig(multipartConfigElement);
return dispatcherServletRegistration;
}

@Bean
public GrailsWebMvcConfigurer webMvcConfig() {
return new GrailsWebMvcConfigurer(resourcesCachePeriod, resourcesEnabled, resourcesPattern);
}

static class GrailsWebMvcConfigurer implements WebMvcConfigurer {

private static final String[] SERVLET_RESOURCE_LOCATIONS = new String[] { "/" };

private static final String[] CLASSPATH_RESOURCE_LOCATIONS = new String[] {
"classpath:/META-INF/resources/", "classpath:/resources/",
"classpath:/static/", "classpath:/public/"
};

private static final String[] RESOURCE_LOCATIONS;

static {
RESOURCE_LOCATIONS = new String[CLASSPATH_RESOURCE_LOCATIONS.length
+ SERVLET_RESOURCE_LOCATIONS.length];
System.arraycopy(SERVLET_RESOURCE_LOCATIONS, 0, RESOURCE_LOCATIONS, 0,
SERVLET_RESOURCE_LOCATIONS.length);
System.arraycopy(CLASSPATH_RESOURCE_LOCATIONS, 0, RESOURCE_LOCATIONS,
SERVLET_RESOURCE_LOCATIONS.length, CLASSPATH_RESOURCE_LOCATIONS.length);
}

boolean addMappings;
Integer cachePeriod;
String resourcesPattern;

GrailsWebMvcConfigurer(Integer cachePeriod, Boolean addMappings, String resourcesPattern) {
this.addMappings = addMappings;
this.cachePeriod = cachePeriod;
this.resourcesPattern = resourcesPattern;
}

@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
if (!addMappings) {
return;
}

if (!registry.hasMappingForPattern("/webjars/**")) {
registry.addResourceHandler("/webjars/**")
.addResourceLocations("classpath:/META-INF/resources/webjars/")
.setCachePeriod(cachePeriod);
}
if (!registry.hasMappingForPattern(resourcesPattern)) {
registry.addResourceHandler(resourcesPattern)
.addResourceLocations(RESOURCE_LOCATIONS)
.setCachePeriod(cachePeriod);
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,24 +19,16 @@ import grails.config.Settings
import grails.core.GrailsControllerClass
import grails.plugins.Plugin
import grails.util.GrailsUtil
import groovy.transform.CompileStatic
import groovy.util.logging.Slf4j
import org.grails.core.artefact.ControllerArtefactHandler
import org.grails.plugins.web.servlet.context.BootStrapClassRunner
import org.grails.web.errors.GrailsExceptionResolver
import org.grails.web.servlet.mvc.GrailsDispatcherServlet
import org.grails.web.servlet.mvc.TokenResponseActionResultTransformer
import org.grails.web.servlet.view.CompositeViewResolver
import org.springframework.beans.factory.support.AbstractBeanDefinition
import org.springframework.boot.autoconfigure.web.servlet.DispatcherServletRegistrationBean
import org.springframework.context.ApplicationContext
import org.springframework.util.ClassUtils
import org.springframework.web.multipart.support.StandardServletMultipartResolver
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping
import jakarta.servlet.MultipartConfigElement

/**
* Handles the configuration of controllers for Grails.
Expand All @@ -61,15 +53,6 @@ class ControllersGrailsPlugin extends Plugin {
def config = application.config

boolean useJsessionId = config.getProperty(Settings.GRAILS_VIEWS_ENABLE_JSESSIONID, Boolean, false)
String uploadTmpDir = config.getProperty(Settings.CONTROLLERS_UPLOAD_LOCATION, System.getProperty("java.io.tmpdir"))
long maxFileSize = config.getProperty(Settings.CONTROLLERS_UPLOAD_MAX_FILE_SIZE, Long, 128000L)
long maxRequestSize = config.getProperty(Settings.CONTROLLERS_UPLOAD_MAX_REQUEST_SIZE, Long, 128000L)
int fileSizeThreashold = config.getProperty(Settings.CONTROLLERS_UPLOAD_FILE_SIZE_THRESHOLD, Integer, 0)
boolean isTomcat = ClassUtils.isPresent("org.apache.catalina.startup.Tomcat", application.classLoader)
String grailsServletPath = config.getProperty(Settings.WEB_SERVLET_PATH, isTomcat ? Settings.DEFAULT_TOMCAT_SERVLET_PATH : Settings.DEFAULT_WEB_SERVLET_PATH)
int resourcesCachePeriod = config.getProperty(Settings.RESOURCES_CACHE_PERIOD, Integer, 0)
boolean resourcesEnabled = config.getProperty(Settings.RESOURCES_ENABLED, Boolean, true)
String resourcesPattern = config.getProperty(Settings.RESOURCES_PATTERN, String, Settings.DEFAULT_RESOURCE_PATTERN)

if (!Boolean.parseBoolean(System.getProperty(Settings.SETTING_SKIP_BOOTSTRAP))) {
bootStrapClassRunner(BootStrapClassRunner)
Expand All @@ -83,8 +66,6 @@ class ControllersGrailsPlugin extends Plugin {

"${CompositeViewResolver.BEAN_NAME}"(CompositeViewResolver)

multipartConfigElement(MultipartConfigElement, uploadTmpDir, maxFileSize, maxRequestSize, fileSizeThreashold)

def handlerInterceptors = springConfig.containsBean("localeChangeInterceptor") ? [ref("localeChangeInterceptor")] : []
def interceptorsClosure = {
interceptors = handlerInterceptors
Expand All @@ -93,17 +74,6 @@ class ControllersGrailsPlugin extends Plugin {
annotationHandlerMapping(RequestMappingHandlerMapping, interceptorsClosure)
annotationHandlerAdapter(RequestMappingHandlerAdapter)

// add Grails webmvc config
webMvcConfig(GrailsWebMvcConfigurer, resourcesCachePeriod, resourcesEnabled, resourcesPattern)

// add the dispatcher servlet
dispatcherServlet(GrailsDispatcherServlet)
dispatcherServletRegistration(DispatcherServletRegistrationBean, ref("dispatcherServlet"), grailsServletPath) {
loadOnStartup = 2
asyncSupported = true
multipartConfig = multipartConfigElement
}

for (controller in application.getArtefacts(ControllerArtefactHandler.TYPE)) {
log.debug "Configuring controller $controller.fullName"
if (controller.available) {
Expand All @@ -128,55 +98,6 @@ class ControllersGrailsPlugin extends Plugin {
}
} }


@CompileStatic
static class GrailsWebMvcConfigurer implements WebMvcConfigurer {

private static final String[] SERVLET_RESOURCE_LOCATIONS = [ "/" ]

private static final String[] CLASSPATH_RESOURCE_LOCATIONS = [
"classpath:/META-INF/resources/", "classpath:/resources/",
"classpath:/static/", "classpath:/public/" ]

private static final String[] RESOURCE_LOCATIONS
static {
RESOURCE_LOCATIONS = new String[CLASSPATH_RESOURCE_LOCATIONS.length
+ SERVLET_RESOURCE_LOCATIONS.length]
System.arraycopy(SERVLET_RESOURCE_LOCATIONS, 0, RESOURCE_LOCATIONS, 0,
SERVLET_RESOURCE_LOCATIONS.length)
System.arraycopy(CLASSPATH_RESOURCE_LOCATIONS, 0, RESOURCE_LOCATIONS,
SERVLET_RESOURCE_LOCATIONS.length, CLASSPATH_RESOURCE_LOCATIONS.length);
}

boolean addMappings = true
Integer cachePeriod
String resourcesPattern

GrailsWebMvcConfigurer(Integer cachePeriod, boolean addMappings = true, String resourcesPattern = '/static/**') {
this.addMappings = addMappings
this.cachePeriod = cachePeriod
this.resourcesPattern = resourcesPattern
}

@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
if (!addMappings) {
return
}

if (!registry.hasMappingForPattern("/webjars/**")) {
registry.addResourceHandler("/webjars/**")
.addResourceLocations("classpath:/META-INF/resources/webjars/")
.setCachePeriod(cachePeriod)
}
if (!registry.hasMappingForPattern(resourcesPattern)) {
registry.addResourceHandler(resourcesPattern)
.addResourceLocations(RESOURCE_LOCATIONS)
.setCachePeriod(cachePeriod)
}
}
}

@Override
void onChange( Map<String, Object> event) {
if (!(event.source instanceof Class)) {
Expand Down Expand Up @@ -205,5 +126,4 @@ class ControllersGrailsPlugin extends Plugin {
}
}
}

}
Loading