protected WebApplicationContext createWebApplicationContext(WebApplicationContext parent) throws BeansException { WebApplicationContext wac = WebApplicationContextUtils.getWebApplicationContext(getServletContext()); WebApplicationContext webContext; // construct the SpringConfig for the container managed application Assert.notNull( parent, "Grails requires a parent ApplicationContext, is the /WEB-INF/applicationContext.xml file missing?"); this.application = (GrailsApplication) parent.getBean(GrailsApplication.APPLICATION_ID, GrailsApplication.class); if (wac instanceof GrailsApplicationContext) { webContext = wac; } else { webContext = GrailsConfigUtils.configureWebApplicationContext(getServletContext(), parent); try { GrailsConfigUtils.executeGrailsBootstraps(application, webContext, getServletContext()); } catch (Exception e) { GrailsUtil.deepSanitize(e); if (e instanceof BeansException) throw (BeansException) e; else { throw new BootstrapException("Error executing bootstraps", e); } } } initMainController(webContext); this.interceptors = establishInterceptors(webContext); return webContext; }
public void rebuild() { initialised = false; loadedClasses.clear(); initArtefactHandlers(); if (GrailsUtil.isDevelopmentEnv()) { initialise(); } else { throw new IllegalStateException( "Cannot rebuild GrailsApplication when not in development mode!"); } }
/** * Get the default Compass connection (ie, Lucene index dir) * * @param grailsApplication the GrailsApplication - may be null * @return {user.home}/.grails/projects/{project-name}/searchable-index/{grails.env} */ public static String getDefaultConnection(GrailsApplication grailsApplication) { String appName = SearchableUtils.getAppName(grailsApplication); return new StringBuffer(System.getProperty("user.home")) .append(File.separator) .append(".grails") .append(File.separator) .append("projects") .append(File.separator) .append(appName) .append(File.separator) .append("searchable-index") .append(File.separator) .append(GrailsUtil.getEnvironment()) .toString(); }
/* (non-Javadoc) * @see org.codehaus.groovy.grails.plugins.AbstractGrailsPlugin#refresh() */ @Override public void refresh() { // do nothing Resource descriptor = getDescriptor(); if (application != null && descriptor != null) { ClassLoader parent = application.getClassLoader(); GroovyClassLoader gcl = new GroovyClassLoader(parent); try { Class pluginClass = gcl.parseClass(descriptor.getFile()); initialisePlugin(pluginClass); } catch (Exception e) { GrailsUtil.deepSanitize(e); LOG.error("Error refreshing plugin: " + e.getMessage(), e); } } }
/** * Creates a GroovyPageMetaInfo instance from the given Parse object, and initialises it with the * the specified last modifed date and InputStream * * @param parse The Parse object * @param lastModified The last modified date * @param in The InputStream instance * @return A GroovyPageMetaInfo instance */ private GroovyPageMetaInfo createPageMetaInfo( GroovyPageParser parse, long lastModified, InputStream in) { GroovyPageMetaInfo pageMeta = new GroovyPageMetaInfo(); pageMeta.setJspTagLibraryResolver(jspTagLibraryResolver); pageMeta.setTagLibraryLookup(tagLibraryLookup); pageMeta.setContentType(parse.getContentType()); pageMeta.setLineNumbers(parse.getLineNumberMatrix()); pageMeta.setLastModified(lastModified); pageMeta.setJspTags(parse.getJspTags()); pageMeta.setCodecName(parse.getDefaultCodecDirectiveValue()); pageMeta.initCodec(); // just return groovy and don't compile if asked if (isReloadEnabled() || GrailsUtil.isDevelopmentEnv()) { pageMeta.setGroovySource(in); } return pageMeta; }
@Override protected View loadView(String viewName, Locale locale) throws Exception { Assert.notNull(templateEngine, "Property [templateEngine] cannot be null"); if (GrailsUtil.isDevelopmentEnv()) { return createGrailsView(viewName); } View view = VIEW_CACHE.get(viewName); if (view == null || (templateEngine.isReloadEnabled() && view instanceof GroovyPageView && ((GroovyPageView) view).isExpired())) { view = createGrailsView(viewName); } VIEW_CACHE.put(viewName, view); return view; }
@Override protected View loadView(String viewName, Locale locale) throws Exception { final View resolvedView = super.loadView(viewName, locale); if (templateGenerator == null || resolvedView instanceof GroovyPageView) { return resolvedView; } GrailsWebRequest webRequest = WebUtils.retrieveGrailsWebRequest(); List<String> controllerActions = scaffoldedActionMap.get(webRequest.getControllerName()); if (controllerActions != null && controllerActions.contains(webRequest.getActionName())) { GrailsDomainClass domainClass = scaffoldedDomains.get(webRequest.getControllerName()); if (domainClass != null) { String viewFileName; final int i = viewName.lastIndexOf('/'); if (i > -1) { viewFileName = viewName.substring(i, viewName.length()); } else { viewFileName = viewName; } final ViewKey viewKey = new ViewKey(webRequest.getControllerName(), viewFileName); View v = scaffoldedViews.get(viewKey); if (v == null) { String viewCode = null; try { viewCode = generateViewSource(webRequest, domainClass); } catch (Exception e) { GrailsUtil.deepSanitize(e); LOG.error("Error generating scaffolded view [" + viewName + "]: " + e.getMessage(), e); return resolvedView; } v = createScaffoldedView(viewName, viewCode); scaffoldedViews.put(viewKey, v); } if (v != null) { return v; } } } return resolvedView; }
/** Default constructor. */ public ReloadAwareAutowireCapableBeanFactory() { reloadEnabled = GrailsUtil.isDevelopmentEnv() || Environment.getCurrent().isReloadEnabled(); if (reloadEnabled) { // Implementation note: The default Spring InstantiationStrategy caches constructors. // This is no good at development time because if the class reloads then Spring // continues to use the old class. We deal with this here by disabling the caching // for development time only setInstantiationStrategy( new CglibSubclassingInstantiationStrategy() { @Override public Object instantiate( RootBeanDefinition beanDefinition, String beanName, BeanFactory owner) { // Don't override the class with CGLIB if no overrides. if (beanDefinition.getMethodOverrides().isEmpty()) { Constructor<?> constructorToUse; Class<?> clazz = beanDefinition.getBeanClass(); if (clazz.isInterface()) { throw new BeanInstantiationException(clazz, "Specified class is an interface"); } try { constructorToUse = clazz.getDeclaredConstructor((Class[]) null); } catch (Exception ex) { throw new BeanInstantiationException(clazz, "No default constructor found", ex); } return BeanUtils.instantiateClass(constructorToUse); } // Must generate CGLIB subclass. return instantiateWithMethodInjection(beanDefinition, beanName, owner); } }); } setParameterNameDiscoverer(new LocalVariableTableParameterNameDiscoverer()); setAutowireCandidateResolver(new QualifierAnnotationAutowireCandidateResolver()); ignoreDependencyType(Closure.class); }
/** * Trigger afterCompletion callbacks on the mapped HandlerInterceptors. Will just invoke * afterCompletion for all interceptors whose preHandle invocation has successfully completed and * returned true. * * @param mappedHandler the mapped HandlerExecutionChain * @param interceptorIndex index of last interceptor that successfully completed * @param ex Exception thrown on handler execution, or <code>null</code> if none * @see HandlerInterceptor#afterCompletion */ protected void triggerAfterCompletion( HandlerExecutionChain mappedHandler, int interceptorIndex, HttpServletRequest request, HttpServletResponse response, Exception ex) throws Exception { // Apply afterCompletion methods of registered interceptors. if (mappedHandler != null) { if (mappedHandler.getInterceptors() != null) { for (int i = interceptorIndex; i >= 0; i--) { HandlerInterceptor interceptor = mappedHandler.getInterceptors()[i]; try { interceptor.afterCompletion(request, response, mappedHandler.getHandler(), ex); } catch (Throwable ex2) { GrailsUtil.deepSanitize(ex2); logger.error("HandlerInterceptor.afterCompletion threw exception", ex2); } } } } }
/** * Overrides the default behaviour to establish the handler from the GrailsApplication instance * * @param request The request * @param cache Whether to cache the Handler in the request * @return The HandlerExecutionChain * @throws Exception */ protected HandlerExecutionChain getHandler(HttpServletRequest request, boolean cache) throws Exception { String uri = urlHelper.getPathWithinApplication(request); if (logger.isDebugEnabled()) { logger.debug("Looking up Grails controller for URI [" + uri + "]"); } GrailsControllerClass controllerClass = (GrailsControllerClass) application.getArtefactForFeature(ControllerArtefactHandler.TYPE, uri); final String actionName = (String) request.getAttribute(GrailsApplicationAttributes.ACTION_NAME_ATTRIBUTE); if (controllerClass != null) { HandlerInterceptor[] interceptors; // if we're in a development environment we want to re-establish interceptors just in case // they // have changed at runtime if (GrailsUtil.isDevelopmentEnv()) { interceptors = establishInterceptors(getWebApplicationContext()); } else { interceptors = this.interceptors; } if (controllerClass.isFlowAction(actionName)) { FlowHandler flowHandler = new AbstractFlowHandler() { public String getFlowId() { return actionName; } }; return new HandlerExecutionChain(flowHandler, interceptors); } else { return new HandlerExecutionChain(mainController, interceptors); } } return null; }
@SuppressWarnings("unchecked") private void evaluateOnChangeListener() { if (pluginBean.isReadableProperty(ON_SHUTDOWN)) { onShutdownListener = (Closure) GrailsClassUtils.getPropertyOrStaticPropertyOrFieldValue(plugin, ON_SHUTDOWN); } if (pluginBean.isReadableProperty(ON_CONFIG_CHANGE)) { onConfigChangeListener = (Closure) GrailsClassUtils.getPropertyOrStaticPropertyOrFieldValue(plugin, ON_CONFIG_CHANGE); } if (pluginBean.isReadableProperty(ON_CHANGE)) { onChangeListener = (Closure) GrailsClassUtils.getPropertyOrStaticPropertyOrFieldValue(plugin, ON_CHANGE); } final boolean warDeployed = Metadata.getCurrent().isWarDeployed(); final boolean reloadEnabled = Environment.getCurrent().isReloadEnabled(); if (!((reloadEnabled || !warDeployed) && onChangeListener != null)) { return; } Object referencedResources = GrailsClassUtils.getPropertyOrStaticPropertyOrFieldValue(plugin, WATCHED_RESOURCES); try { List resourceList = null; if (referencedResources instanceof String) { if (LOG.isDebugEnabled()) { LOG.debug( "Configuring plugin " + this + " to watch resources with pattern: " + referencedResources); } resourceList = new ArrayList(); resourceList.add(referencedResources.toString()); } else if (referencedResources instanceof List) { resourceList = (List) referencedResources; } if (resourceList != null) { List<String> resourceListTmp = new ArrayList<String>(); PluginBuildSettings pluginBuildSettings = GrailsPluginUtils.getPluginBuildSettings(); if (pluginBuildSettings != null) { final Resource[] pluginDirs = pluginBuildSettings.getPluginDirectories(); final Environment env = Environment.getCurrent(); final String baseLocation = env.getReloadLocation(); for (Object ref : resourceList) { String stringRef = ref.toString(); if (!warDeployed) { for (Resource pluginDir : pluginDirs) { if (pluginDir != null) { String pluginResources = getResourcePatternForBaseLocation( pluginDir.getFile().getCanonicalPath(), stringRef); resourceListTmp.add(pluginResources); } } addBaseLocationPattern(resourceListTmp, baseLocation, stringRef); } else { addBaseLocationPattern(resourceListTmp, baseLocation, stringRef); } } watchedResourcePatternReferences = new String[resourceListTmp.size()]; for (int i = 0; i < watchedResourcePatternReferences.length; i++) { String resRef = resourceListTmp.get(i); watchedResourcePatternReferences[i] = resRef; } watchedResourcePatterns = new WatchPatternParser() .getWatchPatterns(Arrays.asList(watchedResourcePatternReferences)); } } } catch (IllegalArgumentException e) { if (GrailsUtil.isDevelopmentEnv()) { LOG.debug( "Cannot load plug-in resource watch list from [" + ArrayUtils.toString(watchedResourcePatternReferences) + "]. This means that the plugin " + this + ", will not be able to auto-reload changes effectively. Try runnng grails upgrade.: " + e.getMessage()); } } catch (IOException e) { if (GrailsUtil.isDevelopmentEnv()) { LOG.debug( "Cannot load plug-in resource watch list from [" + ArrayUtils.toString(watchedResourcePatternReferences) + "]. This means that the plugin " + this + ", will not be able to auto-reload changes effectively. Try runnng grails upgrade.: " + e.getMessage()); } } }
/* (non-Javadoc) * @see org.springframework.web.servlet.DispatcherServlet#doDispatch(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse) */ protected void doDispatch(final HttpServletRequest request, HttpServletResponse response) throws Exception { HttpServletRequest processedRequest = request; HandlerExecutionChain mappedHandler = null; int interceptorIndex = -1; final LocaleResolver localeResolver = (LocaleResolver) request.getAttribute(LOCALE_RESOLVER_ATTRIBUTE); // Expose current LocaleResolver and request as LocaleContext. LocaleContext previousLocaleContext = LocaleContextHolder.getLocaleContext(); LocaleContextHolder.setLocaleContext( new LocaleContext() { public Locale getLocale() { return localeResolver.resolveLocale(request); } }); // If the request is an include we need to try to use the original wrapped sitemesh // response, otherwise layouts won't work properly if (WebUtils.isIncludeRequest(request)) { response = useWrappedOrOriginalResponse(response); } GrailsWebRequest requestAttributes = null; GrailsWebRequest previousRequestAttributes = null; Exception handlerException = null; try { ModelAndView mv = null; try { Object exceptionAttribute = request.getAttribute(EXCEPTION_ATTRIBUTE); // only process multipart requests if an exception hasn't occured if (exceptionAttribute == null) processedRequest = checkMultipart(request); // Expose current RequestAttributes to current thread. previousRequestAttributes = (GrailsWebRequest) RequestContextHolder.currentRequestAttributes(); requestAttributes = new GrailsWebRequest(processedRequest, response, getServletContext()); copyParamsFromPreviousRequest(previousRequestAttributes, requestAttributes); // Update the current web request. WebUtils.storeGrailsWebRequest(requestAttributes); if (logger.isDebugEnabled()) { logger.debug("Bound request context to thread: " + request); logger.debug("Using response object: " + response.getClass()); } // Determine handler for the current request. mappedHandler = getHandler(processedRequest, false); if (mappedHandler == null || mappedHandler.getHandler() == null) { noHandlerFound(processedRequest, response); return; } // Apply preHandle methods of registered interceptors. if (mappedHandler.getInterceptors() != null) { for (int i = 0; i < mappedHandler.getInterceptors().length; i++) { HandlerInterceptor interceptor = mappedHandler.getInterceptors()[i]; if (!interceptor.preHandle(processedRequest, response, mappedHandler.getHandler())) { triggerAfterCompletion( mappedHandler, interceptorIndex, processedRequest, response, null); return; } interceptorIndex = i; } } // Actually invoke the handler. HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler()); mv = ha.handle(processedRequest, response, mappedHandler.getHandler()); // Apply postHandle methods of registered interceptors. if (mappedHandler.getInterceptors() != null) { for (int i = mappedHandler.getInterceptors().length - 1; i >= 0; i--) { HandlerInterceptor interceptor = mappedHandler.getInterceptors()[i]; interceptor.postHandle(processedRequest, response, mappedHandler.getHandler(), mv); } } } catch (ModelAndViewDefiningException ex) { GrailsUtil.deepSanitize(ex); handlerException = ex; if (logger.isDebugEnabled()) logger.debug("ModelAndViewDefiningException encountered", ex); mv = ex.getModelAndView(); } catch (Exception ex) { GrailsUtil.deepSanitize(ex); handlerException = ex; Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null); mv = processHandlerException(request, response, handler, ex); } // Did the handler return a view to render? if (mv != null && !mv.wasCleared()) { // If an exception occurs in here, like a bad closing tag, // we have nothing to render. try { render(mv, processedRequest, response); } catch (Exception e) { mv = super.processHandlerException(processedRequest, response, mappedHandler, e); handlerException = e; render(mv, processedRequest, response); } } else { if (logger.isDebugEnabled()) { logger.debug( "Null ModelAndView returned to DispatcherServlet with name '" + getServletName() + "': assuming HandlerAdapter completed request handling"); } } // Trigger after-completion for successful outcome. triggerAfterCompletion( mappedHandler, interceptorIndex, processedRequest, response, handlerException); } catch (Exception ex) { // Trigger after-completion for thrown exception. triggerAfterCompletion(mappedHandler, interceptorIndex, processedRequest, response, ex); throw ex; } catch (Error err) { ServletException ex = new NestedServletException("Handler processing failed", err); // Trigger after-completion for thrown exception. triggerAfterCompletion(mappedHandler, interceptorIndex, processedRequest, response, ex); throw ex; } finally { // Clean up any resources used by a multipart request. if (processedRequest instanceof MultipartHttpServletRequest && processedRequest != request) { if (multipartResolver != null) this.multipartResolver.cleanupMultipart((MultipartHttpServletRequest) processedRequest); } request.removeAttribute(MultipartHttpServletRequest.class.getName()); // Reset thread-bound holders if (requestAttributes != null) { requestAttributes.requestCompleted(); WebUtils.storeGrailsWebRequest(previousRequestAttributes); } LocaleContextHolder.setLocaleContext(previousLocaleContext); if (logger.isDebugEnabled()) { logger.debug("Cleared thread-bound request context: " + request); } } }
@SuppressWarnings("unchecked") @Override protected Object createNode(Object name, Map attributes) { // we do this so that missing property exception is throw if it doesn't exist try { String property = (String) name; ConstrainedProperty cp; if (constrainedProperties.containsKey(property)) { cp = constrainedProperties.get(property); } else { cp = new ConstrainedProperty( targetClass, property, classPropertyFetcher.getPropertyType(property)); cp.setOrder(order++); constrainedProperties.put(property, cp); } if (cp.getPropertyType() == null) { GrailsUtil.warn( "Property [" + cp.getPropertyName() + "] not found in domain class " + targetClass.getName() + "; cannot apply constraints: " + attributes); return cp; } for (Object o : attributes.keySet()) { String constraintName = (String) o; final Object value = attributes.get(constraintName); if (SHARED_CONSTRAINT.equals(constraintName)) { if (value != null) { sharedConstraints.put(property, value.toString()); } continue; } if (cp.supportsContraint(constraintName)) { cp.applyConstraint(constraintName, value); } else { if (ConstrainedProperty.hasRegisteredConstraint(constraintName)) { // constraint is registered but doesn't support this property's type GrailsUtil.warn( "Property [" + cp.getPropertyName() + "] of domain class " + targetClass.getName() + " has type [" + cp.getPropertyType().getName() + "] and doesn't support constraint [" + constraintName + "]. This constraint will not be checked during validation."); } else { // in the case where the constraint is not supported we still retain meta data // about the constraint in case its needed for other things cp.addMetaConstraint(constraintName, value); } } } return cp; } catch (InvalidPropertyException ipe) { throw new MissingMethodException((String) name, targetClass, new Object[] {attributes}); } }
/** * Evaluates the existance of a view for different extensions choosing which one to delegate to. * * @author Graeme Rocher * @since 0.1 */ public class GroovyPageViewResolver extends InternalResourceViewResolver implements GrailsViewResolver { private static final Log LOG = LogFactory.getLog(GroovyPageViewResolver.class); public static final String GSP_SUFFIX = ".gsp"; public static final String JSP_SUFFIX = ".jsp"; protected GroovyPagesTemplateEngine templateEngine; protected GrailsConventionGroovyPageLocator groovyPageLocator; private ConcurrentMap<String, CacheEntry<View>> viewCache = new ConcurrentHashMap<String, CacheEntry<View>>(); private boolean allowGrailsViewCaching = !GrailsUtil.isDevelopmentEnv(); private long cacheTimeout = -1; /** Constructor. */ public GroovyPageViewResolver() { setCache(false); setOrder(Ordered.LOWEST_PRECEDENCE - 20); } public GroovyPageViewResolver( GroovyPagesTemplateEngine templateEngine, GrailsConventionGroovyPageLocator groovyPageLocator) { this(); this.templateEngine = templateEngine; this.groovyPageLocator = groovyPageLocator; } public void setGroovyPageLocator(GrailsConventionGroovyPageLocator groovyPageLocator) { this.groovyPageLocator = groovyPageLocator; } @Override public View resolveViewName(String viewName, Locale locale) throws Exception { return super.resolveViewName(WebUtils.addViewPrefix(viewName), locale); } @Override protected View loadView(String viewName, Locale locale) throws Exception { Assert.notNull(templateEngine, "Property [templateEngine] cannot be null"); if (viewName.endsWith(GSP_SUFFIX)) { viewName = viewName.substring(0, viewName.length() - GSP_SUFFIX.length()); } if (!allowGrailsViewCaching) { return createGrailsView(viewName); } String viewCacheKey = groovyPageLocator.resolveViewFormat(viewName); String currentControllerKeyPrefix = resolveCurrentControllerKeyPrefixes(); if (currentControllerKeyPrefix != null) { viewCacheKey = currentControllerKeyPrefix + ':' + viewCacheKey; } CacheEntry<View> entry = viewCache.get(viewCacheKey); final String lookupViewName = viewName; Callable<View> updater = new Callable<View>() { public View call() throws Exception { try { return createGrailsView(lookupViewName); } catch (Exception e) { throw new WrappedInitializationException(e); } } }; View view = null; if (entry == null) { try { return CacheEntry.getValue(viewCache, viewCacheKey, cacheTimeout, updater); } catch (CacheEntry.UpdateException e) { e.rethrowCause(); // make compiler happy return null; } } try { view = entry.getValue(cacheTimeout, updater, true, null); } catch (WrappedInitializationException e) { e.rethrowCause(); } return view; } /** * @return prefix for cache key that contains current controller's context (currently plugin and * namespace) */ protected String resolveCurrentControllerKeyPrefixes() { String pluginContextPath = null; String namespace = null; GrailsWebRequest webRequest = GrailsWebRequest.lookup(); if (webRequest != null) { namespace = webRequest.getControllerNamespace(); pluginContextPath = (webRequest.getAttributes() != null && webRequest.getCurrentRequest() != null) ? webRequest.getAttributes().getPluginContextPath(webRequest.getCurrentRequest()) : null; return (pluginContextPath != null ? pluginContextPath : "-") + "," + (namespace != null ? namespace : "-"); } else { return null; } } private static class WrappedInitializationException extends RuntimeException { private static final long serialVersionUID = 1L; public WrappedInitializationException(Throwable cause) { super(cause); } public void rethrowCause() throws Exception { if (getCause() instanceof Exception) { throw (Exception) getCause(); } throw this; } } protected View createGrailsView(String viewName) throws Exception { // try GSP if res is null GroovyObject controller = null; GrailsWebRequest webRequest = GrailsWebRequest.lookup(); if (webRequest != null) { HttpServletRequest request = webRequest.getCurrentRequest(); controller = webRequest.getAttributes().getController(request); } GroovyPageScriptSource scriptSource; if (controller == null) { scriptSource = groovyPageLocator.findViewByPath(viewName); } else { scriptSource = groovyPageLocator.findView(controller, viewName); } if (scriptSource != null) { return createGroovyPageView(scriptSource.getURI(), scriptSource); } return createFallbackView(viewName); } private View createGroovyPageView(String gspView, ScriptSource scriptSource) { if (LOG.isDebugEnabled()) { LOG.debug("Resolved GSP view at URI [" + gspView + "]"); } GroovyPageView gspSpringView = new GroovyPageView(); gspSpringView.setServletContext(getServletContext()); gspSpringView.setUrl(gspView); gspSpringView.setApplicationContext(getApplicationContext()); gspSpringView.setTemplateEngine(templateEngine); gspSpringView.setScriptSource(scriptSource); try { gspSpringView.afterPropertiesSet(); } catch (Exception e) { throw new RuntimeException("Error initializing GroovyPageView", e); } return gspSpringView; } protected View createFallbackView(String viewName) throws Exception { return createJstlView(viewName); } protected View createJstlView(String viewName) throws Exception { AbstractUrlBasedView view = buildView(viewName); view.setApplicationContext(getApplicationContext()); view.afterPropertiesSet(); return view; } @Autowired(required = true) @Qualifier(GroovyPagesTemplateEngine.BEAN_ID) public void setTemplateEngine(GroovyPagesTemplateEngine templateEngine) { this.templateEngine = templateEngine; } public long getCacheTimeout() { return cacheTimeout; } public void setCacheTimeout(long cacheTimeout) { this.cacheTimeout = cacheTimeout; } @Override public void clearCache() { super.clearCache(); viewCache.clear(); } public boolean isAllowGrailsViewCaching() { return allowGrailsViewCaching; } public void setAllowGrailsViewCaching(boolean allowGrailsViewCaching) { this.allowGrailsViewCaching = allowGrailsViewCaching; } }