From 3e8f9af86029b796de957ad79ea175fea808de5b Mon Sep 17 00:00:00 2001 From: graemerocher Date: Mon, 9 Mar 2015 10:22:05 +0100 Subject: [PATCH] Ensure custom 404 pages work --- .../mapping/UrlMappingsGrailsPlugin.groovy | 2 + .../mapping/UrlMappingsHolderFactoryBean.java | 49 ++++++---------- .../UrlMappingsErrorPageCustomizer.groovy | 58 +++++++++++++++++++ 3 files changed, 78 insertions(+), 31 deletions(-) create mode 100644 grails-web-url-mappings/src/main/groovy/org/grails/web/mapping/servlet/UrlMappingsErrorPageCustomizer.groovy diff --git a/grails-plugin-url-mappings/src/main/groovy/org/grails/plugins/web/mapping/UrlMappingsGrailsPlugin.groovy b/grails-plugin-url-mappings/src/main/groovy/org/grails/plugins/web/mapping/UrlMappingsGrailsPlugin.groovy index 6ea247f082a..132686eaf8d 100644 --- a/grails-plugin-url-mappings/src/main/groovy/org/grails/plugins/web/mapping/UrlMappingsGrailsPlugin.groovy +++ b/grails-plugin-url-mappings/src/main/groovy/org/grails/plugins/web/mapping/UrlMappingsGrailsPlugin.groovy @@ -35,6 +35,7 @@ import grails.web.mapping.UrlMappingsHolder import org.grails.web.mapping.UrlMappingsHolderFactoryBean import org.grails.web.mapping.mvc.UrlMappingsHandlerMapping import org.grails.web.mapping.mvc.UrlMappingsInfoHandlerAdapter +import org.grails.web.mapping.servlet.UrlMappingsErrorPageCustomizer import org.springframework.aop.framework.ProxyFactoryBean import org.springframework.aop.target.HotSwappableTargetSource import org.springframework.context.ApplicationContext @@ -69,6 +70,7 @@ class UrlMappingsGrailsPlugin extends Plugin { urlMappingsHandlerMapping(UrlMappingsHandlerMapping, ref("grailsUrlMappingsHolder")) urlMappingsInfoHandlerAdapter(UrlMappingsInfoHandlerAdapter) + urlMappingsErrorPageCustomizer(UrlMappingsErrorPageCustomizer) grailsLinkGenerator(cacheUrls ? CachingLinkGenerator : DefaultLinkGenerator, serverURL) if (Environment.isDevelopmentMode() || Environment.current.isReloadEnabled()) { diff --git a/grails-web-url-mappings/src/main/groovy/org/grails/web/mapping/UrlMappingsHolderFactoryBean.java b/grails-web-url-mappings/src/main/groovy/org/grails/web/mapping/UrlMappingsHolderFactoryBean.java index 36d739899d6..81f39c9aa44 100644 --- a/grails-web-url-mappings/src/main/groovy/org/grails/web/mapping/UrlMappingsHolderFactoryBean.java +++ b/grails-web-url-mappings/src/main/groovy/org/grails/web/mapping/UrlMappingsHolderFactoryBean.java @@ -15,31 +15,30 @@ */ package org.grails.web.mapping; +import grails.config.Config; import grails.core.GrailsApplication; import grails.core.GrailsClass; import grails.core.GrailsControllerClass; import grails.core.GrailsUrlMappingsClass; -import grails.web.mapping.UrlMappings; -import groovy.lang.Script; - -import java.util.ArrayList; -import java.util.List; -import java.util.Map; - -import javax.servlet.ServletContext; - import grails.core.events.ArtefactAdditionEvent; +import grails.core.support.GrailsApplicationAware; import grails.plugins.GrailsPluginManager; import grails.plugins.PluginManagerAware; -import grails.core.support.GrailsApplicationAware; +import grails.web.mapping.UrlMappings; +import groovy.lang.Script; import org.grails.core.artefact.UrlMappingsArtefactHandler; import org.grails.web.mapping.mvc.GrailsControllerUrlMappings; import org.springframework.beans.BeansException; import org.springframework.beans.factory.FactoryBean; import org.springframework.beans.factory.InitializingBean; -import org.springframework.context.*; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; +import org.springframework.context.ApplicationListener; +import org.springframework.context.ConfigurableApplicationContext; import org.springframework.util.Assert; -import org.springframework.web.context.WebApplicationContext; + +import java.util.ArrayList; +import java.util.List; /** * Constructs the UrlMappingsHolder from the registered UrlMappings class within a GrailsApplication. @@ -103,12 +102,12 @@ public void afterPropertiesSet() throws Exception { DefaultUrlMappingsHolder defaultUrlMappingsHolder = new DefaultUrlMappingsHolder(urlMappings, excludePatterns, true); - Map flatConfig = grailsApplication.getFlatConfig(); - Integer cacheSize = mapGetInteger(flatConfig, URL_MAPPING_CACHE_MAX_SIZE); + Config config = grailsApplication.getConfig(); + Integer cacheSize = config.getProperty(URL_MAPPING_CACHE_MAX_SIZE, Integer.class, null); if (cacheSize != null) { defaultUrlMappingsHolder.setMaxWeightedCacheCapacity(cacheSize); } - Integer urlCreatorCacheSize = mapGetInteger(flatConfig, URL_CREATOR_CACHE_MAX_SIZE); + Integer urlCreatorCacheSize = config.getProperty(URL_CREATOR_CACHE_MAX_SIZE, Integer.class, null); if (urlCreatorCacheSize != null) { defaultUrlMappingsHolder.setUrlCreatorMaxWeightedCacheCapacity(urlCreatorCacheSize); } @@ -127,25 +126,11 @@ public void onApplicationEvent(ArtefactAdditionEvent event) { urlMappingsHolder= grailsControllerUrlMappings; } - // this should possibly be somewhere in utility classes , MapUtils.getInteger doesn't handle GStrings/CharSequence - private static Integer mapGetInteger(Map map, String key) { - Object value = map.get(key); - if (value == null) { - return null; - } - if (value instanceof Integer) { - return (Integer)value; - } - return value instanceof Number ? ((Number)value).intValue() : Integer.valueOf(String.valueOf(value)); - } public void setGrailsApplication(GrailsApplication grailsApplication) { this.grailsApplication = grailsApplication; } - public void setServletContext(ServletContext servletContext) { - // not used - } public void setPluginManager(GrailsPluginManager pluginManager) { this.pluginManager = pluginManager; @@ -169,8 +154,10 @@ public void setPluginManager(GrailsPluginManager pluginManager) { */ public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { this.applicationContext = applicationContext; - setGrailsApplication(applicationContext.getBean( GrailsApplication.APPLICATION_ID, GrailsApplication.class) ); - setServletContext(applicationContext instanceof WebApplicationContext ? ((WebApplicationContext) applicationContext).getServletContext() : null); + setGrailsApplication(applicationContext.getBean(GrailsApplication.APPLICATION_ID, GrailsApplication.class)); setPluginManager( applicationContext.containsBean(GrailsPluginManager.BEAN_NAME) ? applicationContext.getBean(GrailsPluginManager.BEAN_NAME, GrailsPluginManager.class) : null); } + + + } diff --git a/grails-web-url-mappings/src/main/groovy/org/grails/web/mapping/servlet/UrlMappingsErrorPageCustomizer.groovy b/grails-web-url-mappings/src/main/groovy/org/grails/web/mapping/servlet/UrlMappingsErrorPageCustomizer.groovy new file mode 100644 index 00000000000..b961ec1016d --- /dev/null +++ b/grails-web-url-mappings/src/main/groovy/org/grails/web/mapping/servlet/UrlMappingsErrorPageCustomizer.groovy @@ -0,0 +1,58 @@ +/* + * Copyright 2015 original authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.grails.web.mapping.servlet + +import grails.web.mapping.UrlMapping +import grails.web.mapping.UrlMappings +import groovy.transform.CompileStatic +import org.grails.web.mapping.ResponseCodeMappingData +import org.grails.web.mapping.ResponseCodeUrlMapping +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.boot.context.embedded.ConfigurableEmbeddedServletContainer +import org.springframework.boot.context.embedded.EmbeddedServletContainerCustomizer +import org.springframework.boot.context.embedded.ErrorPage +import org.springframework.http.HttpStatus + + +/** + * Customizes the error pages based on UrlMappings + * + * @author Graeme Rocher + * @since 3.0 + */ +@CompileStatic +class UrlMappingsErrorPageCustomizer implements EmbeddedServletContainerCustomizer{ + + @Autowired + UrlMappings urlMappings + + @Override + void customize(ConfigurableEmbeddedServletContainer container) { + final UrlMapping[] allMappings = urlMappings.getUrlMappings() + + List errorPages = [] + for (UrlMapping urlMapping : allMappings) { + if(urlMapping instanceof ResponseCodeUrlMapping) { + ResponseCodeUrlMapping responseCodeUrlMapping = (ResponseCodeUrlMapping) urlMapping; + ResponseCodeMappingData data = (ResponseCodeMappingData) responseCodeUrlMapping.urlData + final int code = data.responseCode + errorPages << new ErrorPage(HttpStatus.valueOf(code), "/error") + + } + } + container.addErrorPages(errorPages as ErrorPage[]) + } +}