Skip to content

Commit

Permalink
Auto-Configure GroovyPagesGrailsPlugin
Browse files Browse the repository at this point in the history
  • Loading branch information
rainboyan committed May 17, 2023
1 parent ad98158 commit c921b03
Show file tree
Hide file tree
Showing 2 changed files with 140 additions and 85 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -15,20 +15,37 @@
*/
package org.grails.plugins.web;

import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import org.springframework.beans.factory.ObjectProvider;
import org.springframework.beans.factory.config.PropertiesFactoryBean;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.AutoConfigureOrder;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.core.Ordered;
import org.springframework.core.io.DefaultResourceLoader;
import org.springframework.core.io.FileUrlResource;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.util.StringUtils;

import grails.config.Config;
import grails.config.Settings;
import grails.core.GrailsApplication;
import grails.util.BuildSettings;
import grails.util.Environment;

import org.grails.core.io.ResourceLocator;
import org.grails.gsp.GroovyPageResourceLoader;
import org.grails.gsp.io.CachingGroovyPageStaticResourceLocator;
import org.grails.web.errors.ErrorsViewStackTracePrinter;
import org.grails.web.gsp.io.CachingGrailsConventionGroovyPageLocator;
import org.grails.web.pages.FilteringCodecsByContentTypeSettings;
import org.grails.web.pages.GroovyPagesServlet;

Expand All @@ -39,16 +56,123 @@
* @since 2022.2.3
*/
@AutoConfiguration
@AutoConfigureOrder(Ordered.LOWEST_PRECEDENCE - 1000)
@AutoConfigureOrder
public class GroovyPagesAutoConfiguration {

private static final String GSP_RELOAD_INTERVAL = "grails.gsp.reload.interval";
private static final String GSP_VIEWS_DIR = "grails.gsp.view.dir";
private static final String SITEMESH_DEFAULT_LAYOUT = "grails.sitemesh.default.layout";
private static final String SITEMESH_ENABLE_NONGSP = "grails.sitemesh.enable.nongsp";

@Bean
@ConditionalOnMissingBean
public GroovyPageResourceLoader groovyPageResourceLoader(ObjectProvider<GrailsApplication> grailsApplication) throws Exception {
Config config = grailsApplication.getIfAvailable().getConfig();
String viewsDir = config.getProperty(GSP_VIEWS_DIR, "");
Environment env = Environment.getCurrent();
boolean developmentMode = Environment.isDevelopmentEnvironmentAvailable();
boolean gspEnableReload = config.getProperty(Settings.GSP_ENABLE_RELOAD, Boolean.class, false);
boolean enableReload = env.isReloadEnabled() || gspEnableReload || (developmentMode && env == Environment.DEVELOPMENT);
boolean warDeployed = Environment.isWarDeployed();
boolean warDeployedWithReload = warDeployed && enableReload;

GroovyPageResourceLoader groovyPageResourceLoader = new GroovyPageResourceLoader();
Resource baseResource;
if (StringUtils.hasText(viewsDir)) {
baseResource = new FileUrlResource(viewsDir);
}
else if (warDeployedWithReload && env.hasReloadLocation()) {
baseResource = new FileUrlResource(transformToValidLocation(env.getReloadLocation()));
}
else {
baseResource = new FileUrlResource(transformToValidLocation(BuildSettings.BASE_DIR.getAbsolutePath()));
}
groovyPageResourceLoader.setBaseResource(baseResource);

return groovyPageResourceLoader;
}

@Bean
@ConditionalOnMissingBean
public CachingGrailsConventionGroovyPageLocator groovyPageLocator(ObjectProvider<GrailsApplication> grailsApplication,
GroovyPageResourceLoader groovyPageResourceLoader) {

Config config = grailsApplication.getIfAvailable().getConfig();
Environment env = Environment.getCurrent();
boolean developmentMode = Environment.isDevelopmentEnvironmentAvailable();
boolean gspEnableReload = config.getProperty(Settings.GSP_ENABLE_RELOAD, Boolean.class, false);
boolean enableReload = env.isReloadEnabled() || gspEnableReload || (developmentMode && env == Environment.DEVELOPMENT);
long gspCacheTimeout = config.getProperty(GSP_RELOAD_INTERVAL, Long.class, (developmentMode && env == Environment.DEVELOPMENT) ? 0L : 5000L);

ResourceLoader resourceLoader = new DefaultResourceLoader();

CachingGrailsConventionGroovyPageLocator groovyPageLocator = new CachingGrailsConventionGroovyPageLocator();
groovyPageLocator.setResourceLoader(groovyPageResourceLoader);

if (!developmentMode) {
Resource defaultViews = resourceLoader.getResource("gsp/views.properties");
if (!defaultViews.exists()) {
defaultViews = resourceLoader.getResource("classpath:gsp/views.properties");
}
if (defaultViews.exists()) {
PropertiesFactoryBean pfb = new PropertiesFactoryBean();
pfb.setIgnoreResourceNotFound(true);
pfb.setLocation(defaultViews);
try {
Map<String, String> precompiledGspMap = pfb.getObject().entrySet().stream().collect(
Collectors.toMap(
e -> String.valueOf(e.getKey()),
e -> String.valueOf(e.getValue()),
(prev, next) -> next, HashMap::new
));
groovyPageLocator.setPrecompiledGspMap(precompiledGspMap);
}
catch (IOException ignored) {
}
}
}
if (enableReload) {
groovyPageLocator.setCacheTimeout(gspCacheTimeout);
}
groovyPageLocator.setReloadEnabled(enableReload);

return groovyPageLocator;
}

@Bean
@ConditionalOnMissingBean
public ResourceLocator grailsResourceLocator(ObjectProvider<GrailsApplication> grailsApplication) {
Config config = grailsApplication.getIfAvailable().getConfig();
Environment env = Environment.getCurrent();
boolean developmentMode = Environment.isDevelopmentEnvironmentAvailable();
boolean gspEnableReload = config.getProperty(Settings.GSP_ENABLE_RELOAD, Boolean.class, false);
boolean enableReload = env.isReloadEnabled() || gspEnableReload || (developmentMode && env == Environment.DEVELOPMENT);
long gspCacheTimeout = config.getProperty(GSP_RELOAD_INTERVAL, Long.class, (developmentMode && env == Environment.DEVELOPMENT) ? 0L : 5000L);

CachingGroovyPageStaticResourceLocator groovyPageStaticResourceLocator = new CachingGroovyPageStaticResourceLocator();

if (enableReload) {
groovyPageStaticResourceLocator.setCacheTimeout(gspCacheTimeout);
}

return groovyPageStaticResourceLocator;
}

@Bean
@ConditionalOnMissingBean
public ErrorsViewStackTracePrinter errorsViewStackTracePrinter(ResourceLocator grailsResourceLocator) {
return new ErrorsViewStackTracePrinter(grailsResourceLocator);
}

@Bean
@ConditionalOnMissingBean
public FilteringCodecsByContentTypeSettings filteringCodecsByContentTypeSettings(ObjectProvider<GrailsApplication> grailsApplication) {

return new FilteringCodecsByContentTypeSettings(grailsApplication.getIfAvailable());
}

@Bean
@ConditionalOnMissingBean
public DefaultGrailsTagDateHelper grailsTagDateHelper() {
return new DefaultGrailsTagDateHelper();
}
Expand All @@ -65,4 +189,14 @@ public ServletRegistrationBean<GroovyPagesServlet> groovyPagesServlet() {
return servletRegistration;
}

private static String transformToValidLocation(String location) {
if (location.equals(".")) {
return location;
}
if (!location.endsWith(java.io.File.separator)) {
return location + java.io.File.separator;
}
return location;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -17,26 +17,21 @@ package org.grails.plugins.web

import groovy.transform.CompileStatic
import groovy.util.logging.Slf4j
import org.springframework.beans.factory.config.PropertiesFactoryBean
import org.springframework.core.Ordered
import org.springframework.core.io.Resource
import org.springframework.util.ClassUtils
import org.springframework.web.servlet.view.InternalResourceViewResolver

import grails.config.Config
import grails.core.gsp.GrailsTagLibClass
import grails.gsp.PageRenderer
import grails.plugins.Plugin
import grails.util.BuildSettings
import grails.util.Environment
import grails.util.GrailsUtil
import grails.util.Metadata
import grails.web.pages.GroovyPagesUriService

import org.grails.core.artefact.gsp.TagLibArtefactHandler
import org.grails.gsp.GroovyPageResourceLoader
import org.grails.gsp.GroovyPagesTemplateEngine
import org.grails.gsp.io.CachingGroovyPageStaticResourceLocator
import org.grails.gsp.jsp.TagLibraryResolverImpl
import org.grails.plugins.web.taglib.ApplicationTagLib
import org.grails.plugins.web.taglib.CountryTagLib
Expand All @@ -51,9 +46,7 @@ import org.grails.plugins.web.taglib.ValidationTagLib
import org.grails.spring.RuntimeSpringConfiguration
import org.grails.taglib.TagLibraryLookup
import org.grails.taglib.TagLibraryMetaUtils
import org.grails.web.errors.ErrorsViewStackTracePrinter
import org.grails.web.gsp.GroovyPagesTemplateRenderer
import org.grails.web.gsp.io.CachingGrailsConventionGroovyPageLocator
import org.grails.web.pages.DefaultGroovyPagesUriService
import org.grails.web.pages.FilteringCodecsByContentTypeSettings
import org.grails.web.servlet.view.GroovyPageViewResolver
Expand All @@ -71,7 +64,6 @@ import org.grails.web.util.GrailsApplicationAttributes
class GroovyPagesGrailsPlugin extends Plugin implements Ordered {

public static final String GSP_RELOAD_INTERVAL = "grails.gsp.reload.interval"
public static final String GSP_VIEWS_DIR = 'grails.gsp.view.dir'
public static final String GSP_VIEW_LAYOUT_RESOLVER_ENABLED = 'grails.gsp.view.layoutViewResolver'
public static final String SITEMESH_DEFAULT_LAYOUT = 'grails.sitemesh.default.layout'
public static final String SITEMESH_ENABLE_NONGSP = 'grails.sitemesh.enable.nongsp'
Expand Down Expand Up @@ -123,12 +115,8 @@ class GroovyPagesGrailsPlugin extends Plugin implements Ordered {
config.getProperty(GroovyPagesTemplateEngine.CONFIG_PROPERTY_GSP_ENABLE_RELOAD, Boolean, false) ||
(developmentMode && env == Environment.DEVELOPMENT)

boolean warDeployed = application.warDeployed
boolean warDeployedWithReload = warDeployed && enableReload

long gspCacheTimeout = config.getProperty(GSP_RELOAD_INTERVAL, Long, (developmentMode && env == Environment.DEVELOPMENT) ? 0L : 5000L)
boolean enableCacheResources = !config.getProperty(GroovyPagesTemplateEngine.CONFIG_PROPERTY_DISABLE_CACHING_RESOURCES, Boolean, false)
String viewsDir = config.getProperty(GSP_VIEWS_DIR, '')
def disableLayoutViewResolver = config.getProperty(GSP_VIEW_LAYOUT_RESOLVER_ENABLED, Boolean, true)
String defaultDecoratorNameSetting = config.getProperty(SITEMESH_DEFAULT_LAYOUT, '')
def sitemeshEnableNonGspViews = config.getProperty(SITEMESH_ENABLE_NONGSP, Boolean, false)
Expand All @@ -143,75 +131,9 @@ class GroovyPagesGrailsPlugin extends Plugin implements Ordered {
// resolves GSP tag libraries
gspTagLibraryLookup(TagLibraryLookup)

boolean customResourceLoader = false
// If the development environment is used we need to load GSP files relative to the base directory
// as oppose to in WAR deployment where views are loaded from /WEB-INF

if (viewsDir) {
log.info "Configuring GSP views directory as '${viewsDir}'"
customResourceLoader = true
groovyPageResourceLoader(GroovyPageResourceLoader) {
baseResource = "file:${viewsDir}"
}
}
else {
if (developmentMode) {
customResourceLoader = true
groovyPageResourceLoader(GroovyPageResourceLoader) { bean ->
bean.lazyInit = true
def location = GroovyPagesGrailsPlugin.transformToValidLocation(BuildSettings.BASE_DIR.absolutePath)
baseResource = "file:$location"
}
}
else {
if (warDeployedWithReload && env.hasReloadLocation()) {
customResourceLoader = true
groovyPageResourceLoader(GroovyPageResourceLoader) {
def location = GroovyPagesGrailsPlugin.transformToValidLocation(env.reloadLocation)
baseResource = "file:${location}"
}
}
}
}

def deployed = !Metadata.getCurrent().isDevelopmentEnvironmentAvailable()
groovyPageLocator(CachingGrailsConventionGroovyPageLocator) { bean ->
bean.lazyInit = true
if (customResourceLoader) {
resourceLoader = groovyPageResourceLoader
}
if (deployed) {
Resource defaultViews = applicationContext?.getResource('gsp/views.properties')

if (defaultViews != null) {
if (!defaultViews.exists()) {
defaultViews = applicationContext?.getResource('classpath:gsp/views.properties')
}
}

if (defaultViews?.exists()) {
precompiledGspMap = { PropertiesFactoryBean pfb ->
ignoreResourceNotFound = true
locations = [defaultViews] as Resource[]
}
}
}
if (enableReload) {
cacheTimeout = gspCacheTimeout
}
reloadEnabled = enableReload
}

grailsResourceLocator(CachingGroovyPageStaticResourceLocator) { bean ->
bean.parent = "abstractGrailsResourceLocator"
if (enableReload) {
cacheTimeout = gspCacheTimeout
}
}

// Setup the main templateEngine used to render GSPs
groovyPagesTemplateEngine(GroovyPagesTemplateEngine) { bean ->
groovyPageLocator = groovyPageLocator
groovyPageLocator = ref('groovyPageLocator')
if (enableReload) {
reloadEnabled = enableReload
}
Expand All @@ -224,7 +146,7 @@ class GroovyPagesGrailsPlugin extends Plugin implements Ordered {

groovyPageRenderer(PageRenderer, ref("groovyPagesTemplateEngine")) { bean ->
bean.lazyInit = true
groovyPageLocator = groovyPageLocator
groovyPageLocator = ref('groovyPageLocator')
}

groovyPagesTemplateRenderer(GroovyPagesTemplateRenderer) { bean ->
Expand All @@ -249,7 +171,7 @@ class GroovyPagesGrailsPlugin extends Plugin implements Ordered {
prefix = GrailsApplicationAttributes.PATH_TO_VIEWS
suffix = jstlPresent ? GroovyPageViewResolver.JSP_SUFFIX : GroovyPageViewResolver.GSP_SUFFIX
templateEngine = groovyPagesTemplateEngine
groovyPageLocator = groovyPageLocator
groovyPageLocator = ref('groovyPageLocator')
if (enableReload) {
cacheTimeout = gspCacheTimeout
}
Expand Down Expand Up @@ -281,7 +203,6 @@ class GroovyPagesGrailsPlugin extends Plugin implements Ordered {
}
}

errorsViewStackTracePrinter(ErrorsViewStackTracePrinter, ref('grailsResourceLocator'))
}
}

Expand Down

0 comments on commit c921b03

Please sign in to comment.