From 6e03178a8e8819e016d7c8dd0b19a914a69bf2f6 Mon Sep 17 00:00:00 2001 From: Lari Hotari Date: Fri, 2 Jan 2015 19:04:45 +0200 Subject: [PATCH] GRAILS-11837 Make GSP template engine independent of Servlet API --- grails-gsp/build.gradle | 6 +- .../groovy/org/grails/gsp/GroovyPage.java | 50 ++---- .../org/grails/gsp/GroovyPageBinding.java | 2 +- .../org/grails/gsp/GroovyPageMetaInfo.java | 2 +- .../org/grails/gsp/GroovyPageTemplate.java | 13 +- .../org/grails/gsp/GroovyPageWritable.java | 146 ++++++++---------- .../grails/gsp/GroovyPagesMetaUtils.groovy | 5 +- .../grails/gsp/GroovyPagesTemplateEngine.java | 78 +--------- .../gsp}/ResourceAwareTemplateEngine.java | 18 +-- .../gsp/io/DefaultGroovyPageLocator.java | 15 +- .../org/grails/gsp/io/GroovyPageLocator.java | 2 +- .../io/GroovyPageStaticResourceLocator.java | 17 +- .../controller/support/RenderHelper.groovy | 2 +- .../web/GroovyPagesGrailsPlugin.groovy | 10 +- .../web/taglib/UrlMappingTagLib.groovy | 9 +- .../web/taglib/ValidationTagLib.groovy | 11 +- .../util/AbstractLinkingRenderer.groovy | 2 +- .../render/DefaultRendererRegistry.groovy | 2 +- .../render/json/DefaultJsonRenderer.groovy | 2 +- .../rest/render/xml/DefaultXmlRenderer.groovy | 2 +- .../mixin/support/LazyTagLibraryLookup.java | 21 ++- .../mixin/web/GroovyPageUnitTestMixin.groovy | 13 +- .../test/runtime/ControllerTestPlugin.groovy | 4 +- .../AbstractTemplateVariableBinding.java | 13 +- .../grails}/taglib/GroovyPageAttributes.java | 6 +- .../grails}/taglib/GroovyPageTagWriter.java | 2 +- .../taglib/NamespacedTagDispatcher.groovy | 3 +- .../org/grails}/taglib/TagBodyClosure.java | 28 ++-- .../org/grails}/taglib/TagLibraryLookup.java | 2 +- .../grails/taglib}/TagLibraryMetaUtils.groovy | 19 +-- .../groovy/org/grails}/taglib/TagOutput.java | 19 ++- .../TemplateNamespacedTagDispatcher.groovy | 10 +- .../taglib/TemplateVariableBinding.java | 39 ++--- .../encoder/DefaultOutputContextLookup.java | 128 +++++++++++++++ .../grails/taglib/encoder/OutputContext.java | 45 ++++++ .../taglib/encoder/OutputContextLookup.java | 24 +++ .../encoder/OutputContextLookupHelper.java | 33 ++++ .../encoder/OutputEncodingSettings.groovy | 8 +- .../taglib/encoder/OutputEncodingStack.java | 67 ++++---- .../OutputEncodingStackAttributes.java | 21 ++- .../main/resources/META-INF/grails.factories | 1 + .../taglib/GroovyPageAttributesTests.groovy | 4 +- .../taglib/GroovyPageTagWriterSpec.groovy | 3 +- .../web/taglib/AbstractGrailsTagTests.groovy | 32 ++-- .../GrailsLayoutDecoratorMapperTests.java | 26 ++-- .../groovy/grails/gsp/PageRendererSpec.groovy | 4 +- .../web/pages/GroovyPageServletSpec.groovy | 2 +- grails-web-common/build.gradle | 4 +- .../errors/GrailsWrappedRuntimeException.java | 2 +- .../DefaultGrailsApplicationAttributes.java | 33 ++-- .../web/util/GrailsApplicationAttributes.java | 15 +- .../plugins/web/taglib/RenderTagLib.groovy | 13 +- .../plugins/web/taglib/SitemeshTagLib.groovy | 2 +- .../web/pages/StandaloneTagLibraryLookup.java | 2 +- grails-web-gsp/build.gradle | 2 +- .../groovy/grails/gsp/PageRenderer.groovy | 2 +- .../web}/gsp/GroovyPagesTemplateRenderer.java | 12 +- ...hingGrailsConventionGroovyPageLocator.java | 7 +- .../io/GrailsConventionGroovyPageLocator.java | 6 +- .../grails/web/pages/GroovyPagesServlet.java | 10 +- .../servlet/view/GroovyPageViewResolver.java | 2 +- ...ailsConventionGroovyPageLocatorSpec.groovy | 6 +- .../view/GroovyPageViewResolverSpec.groovy | 2 +- .../groovy/grails/artefact/TagLibrary.groovy | 8 +- .../artefact/gsp/TagLibraryInvoker.groovy | 8 +- .../web/taglib/TagLibraryTransformer.java | 13 +- .../WebRequestTemplateVariableBinding.java | 27 +++- .../encoder/WebOutputContextLookup.java | 121 +++++++++++++++ .../encoder/WebRequestOutputContext.java | 34 ++++ .../main/resources/META-INF/grails.factories | 1 + .../web/taglib/TagLibraryLookupSpec.groovy | 2 + 71 files changed, 798 insertions(+), 507 deletions(-) rename {grails-web-common/src/main/groovy/org/grails/web/support => grails-gsp/src/main/groovy/org/grails/gsp}/ResourceAwareTemplateEngine.java (93%) rename {grails-web-taglib/src/main/groovy/org/grails/web => grails-taglib/src/main/groovy/org/grails}/taglib/AbstractTemplateVariableBinding.java (95%) rename {grails-web-taglib/src/main/groovy/org/grails/web => grails-taglib/src/main/groovy/org/grails}/taglib/GroovyPageAttributes.java (95%) rename {grails-web-taglib/src/main/groovy/org/grails/web => grails-taglib/src/main/groovy/org/grails}/taglib/GroovyPageTagWriter.java (97%) rename {grails-web-taglib/src/main/groovy/org/grails/web => grails-taglib/src/main/groovy/org/grails}/taglib/NamespacedTagDispatcher.groovy (96%) rename {grails-web-taglib/src/main/groovy/org/grails/web => grails-taglib/src/main/groovy/org/grails}/taglib/TagBodyClosure.java (89%) rename {grails-web-taglib/src/main/groovy/org/grails/web => grails-taglib/src/main/groovy/org/grails}/taglib/TagLibraryLookup.java (99%) rename {grails-web-taglib/src/main/groovy/org/grails/web/taglib/util => grails-taglib/src/main/groovy/org/grails/taglib}/TagLibraryMetaUtils.groovy (93%) rename {grails-web-taglib/src/main/groovy/org/grails/web => grails-taglib/src/main/groovy/org/grails}/taglib/TagOutput.java (91%) rename {grails-web-taglib/src/main/groovy/org/grails/web => grails-taglib/src/main/groovy/org/grails}/taglib/TemplateNamespacedTagDispatcher.groovy (94%) rename {grails-web-taglib/src/main/groovy/org/grails/web => grails-taglib/src/main/groovy/org/grails}/taglib/TemplateVariableBinding.java (79%) create mode 100644 grails-taglib/src/main/groovy/org/grails/taglib/encoder/DefaultOutputContextLookup.java create mode 100644 grails-taglib/src/main/groovy/org/grails/taglib/encoder/OutputContext.java create mode 100644 grails-taglib/src/main/groovy/org/grails/taglib/encoder/OutputContextLookup.java create mode 100644 grails-taglib/src/main/groovy/org/grails/taglib/encoder/OutputContextLookupHelper.java create mode 100644 grails-taglib/src/main/resources/META-INF/grails.factories rename {grails-test-suite-web/src/test/groovy/org/grails/web => grails-taglib/src/test/groovy/org/grails}/taglib/GroovyPageAttributesTests.groovy (97%) rename {grails-web-taglib/src/test/groovy/org/grails/web => grails-taglib/src/test/groovy/org/grails}/taglib/GroovyPageTagWriterSpec.groovy (85%) rename {grails-gsp/src/main/groovy/org/grails => grails-web-gsp/src/main/groovy/org/grails/web}/gsp/GroovyPagesTemplateRenderer.java (97%) rename {grails-gsp/src/main/groovy/org/grails => grails-web-gsp/src/main/groovy/org/grails/web}/gsp/io/CachingGrailsConventionGroovyPageLocator.java (97%) rename {grails-gsp/src/main/groovy/org/grails => grails-web-gsp/src/main/groovy/org/grails/web}/gsp/io/GrailsConventionGroovyPageLocator.java (98%) rename {grails-gsp/src/test/groovy/org/grails => grails-web-gsp/src/test/groovy/org/grails/web}/gsp/io/GrailsConventionGroovyPageLocatorSpec.groovy (98%) create mode 100644 grails-web-taglib/src/main/groovy/org/grails/web/taglib/encoder/WebOutputContextLookup.java create mode 100644 grails-web-taglib/src/main/groovy/org/grails/web/taglib/encoder/WebRequestOutputContext.java diff --git a/grails-gsp/build.gradle b/grails-gsp/build.gradle index 6ad28cc6707..ed86f9be87d 100644 --- a/grails-gsp/build.gradle +++ b/grails-gsp/build.gradle @@ -1,3 +1,7 @@ dependencies { - compile( project(":grails-web-taglib") ) + compile project(":grails-core"), { + exclude group:'org.grails', module:'grails-spring' + } + compile project(":grails-taglib") + compile "org.codehaus.groovy:groovy-templates:$groovyVersion" } diff --git a/grails-gsp/src/main/groovy/org/grails/gsp/GroovyPage.java b/grails-gsp/src/main/groovy/org/grails/gsp/GroovyPage.java index f3fcabc4ed7..f63c784f6c6 100644 --- a/grails-gsp/src/main/groovy/org/grails/gsp/GroovyPage.java +++ b/grails-gsp/src/main/groovy/org/grails/gsp/GroovyPage.java @@ -30,14 +30,12 @@ import org.grails.gsp.jsp.JspTag; import org.grails.gsp.jsp.JspTagLib; import org.grails.gsp.jsp.TagLibraryResolver; +import org.grails.taglib.*; +import org.grails.taglib.encoder.OutputContext; import org.grails.taglib.encoder.OutputEncodingStack; import org.grails.taglib.encoder.OutputEncodingStackAttributes; import org.grails.taglib.encoder.WithCodecHelper; -import org.grails.web.servlet.mvc.GrailsWebRequest; -import org.grails.web.taglib.*; -import org.grails.taglib.GrailsTagException; -import javax.servlet.http.HttpServletRequest; import java.io.Writer; import java.util.*; @@ -58,42 +56,22 @@ public abstract class GroovyPage extends Script { private static final Log LOG = LogFactory.getLog(GroovyPage.class); - public static final String REQUEST = "request"; - public static final String SERVLET_CONTEXT = "application"; - public static final String RESPONSE = "response"; public static final String OUT = "out"; public static final String EXPRESSION_OUT = "expressionOut"; public static final String EXPRESSION_OUT_STATEMENT = EXPRESSION_OUT; // "getCodecOut()"; public static final String OUT_STATEMENT = OUT; // "getOut()"; public static final String CODEC_VARNAME = "Codec"; - public static final String ATTRIBUTES = "attributes"; - public static final String APPLICATION_CONTEXT = "applicationContext"; - public static final String SESSION = "session"; - public static final String PARAMS = "params"; - public static final String FLASH = "flash"; public static final String PLUGIN_CONTEXT_PATH = "pluginContextPath"; public static final String EXTENSION = ".gsp"; - public static final String WEB_REQUEST = "webRequest"; public static final String DEFAULT_NAMESPACE = "g"; public static final String LINK_NAMESPACE = "link"; public static final String TEMPLATE_NAMESPACE = "tmpl"; public static final String PAGE_SCOPE = "pageScope"; - public static final String CONTROLLER_NAME = "controllerName"; - public static final String SUFFIX = ".gsp"; - public static final String ACTION_NAME = "actionName"; public static final Collection RESERVED_NAMES = CollectionUtils.newSet( - REQUEST, - SERVLET_CONTEXT, - RESPONSE, OUT, EXPRESSION_OUT, CODEC_VARNAME, - ATTRIBUTES, - APPLICATION_CONTEXT, - SESSION, - PARAMS, - FLASH, PLUGIN_CONTEXT_PATH, PAGE_SCOPE); @@ -109,9 +87,8 @@ public abstract class GroovyPage extends Script { private GrailsPrintWriter staticOut; private GrailsPrintWriter expressionOut; private OutputEncodingStack outputStack; - private GrailsWebRequest webRequest; + private OutputContext outputContext; private String pluginContextPath; - private HttpServletRequest request; private Encoder rawEncoder; private final List> bodyClosures = new ArrayList>(15); @@ -136,7 +113,7 @@ public void setOut(Writer newWriter) { throw new IllegalStateException("Setting out in page isn't allowed."); } - public void initRun(Writer target, GrailsWebRequest grailsWebRequest, GroovyPageMetaInfo metaInfo) { + public void initRun(Writer target, OutputContext outputContext, GroovyPageMetaInfo metaInfo) { OutputEncodingStackAttributes.Builder attributesBuilder = new OutputEncodingStackAttributes.Builder(); if (metaInfo != null) { setJspTags(metaInfo.getJspTags()); @@ -150,7 +127,7 @@ public void initRun(Writer target, GrailsWebRequest grailsWebRequest, GroovyPage attributesBuilder.defaultTaglibEncoder(metaInfo.getTaglibEncoder()); } attributesBuilder.allowCreate(true).topWriter(target).autoSync(false).pushTop(true); - attributesBuilder.webRequest(grailsWebRequest); + attributesBuilder.outputContext(outputContext); attributesBuilder.inheritPreviousEncoders(false); outputStack = OutputEncodingStack.currentStack(attributesBuilder.build()); @@ -158,11 +135,10 @@ public void initRun(Writer target, GrailsWebRequest grailsWebRequest, GroovyPage staticOut = outputStack.getStaticWriter(); expressionOut = outputStack.getExpressionWriter(); - this.webRequest = grailsWebRequest; - if (grailsWebRequest != null) { - grailsWebRequest.setOut(out); - request = grailsWebRequest.getCurrentRequest(); - GrailsApplication grailsApplication = grailsWebRequest.getAttributes().getGrailsApplication(); + this.outputContext = outputContext; + if (outputContext != null) { + outputContext.setCurrentWriter(out); + GrailsApplication grailsApplication = outputContext.getGrailsApplication(); if (grailsApplication != null) { rawEncoder = WithCodecHelper.lookupEncoder(grailsApplication, "Raw"); } @@ -427,7 +403,7 @@ private void invokeTagLibClosure(String tagName, String tagNamespace, Closure try { Map codecSettings = TagOutput.createCodecSettings(tagNamespace, tagName, attrs, defaultEncodeAs); if (codecSettings != null) { - outputStack.push(WithCodecHelper.createOutputStackAttributesBuilder(codecSettings, webRequest.getAttributes().getGrailsApplication()).build()); + outputStack.push(WithCodecHelper.createOutputStackAttributesBuilder(codecSettings, outputContext.getGrailsApplication()).build()); encodeAsPushedToStack=true; } Object tagresult = null; @@ -522,8 +498,8 @@ public final OutputEncodingStack getOutputStack() { return outputStack; } - public final HttpServletRequest getRequest() { - return request; + public OutputContext getOutputContext() { + return outputContext; } public final void registerSitemeshPreprocessMode() { @@ -542,7 +518,7 @@ public final void registerSitemeshPreprocessMode() { } public final void createTagBody(int bodyClosureIndex, Closure bodyClosure) { - TagBodyClosure tagBody = new TagBodyClosure(this, webRequest, bodyClosure, true); + TagBodyClosure tagBody = new TagBodyClosure(this, outputContext, bodyClosure, true); setBodyClosure(bodyClosureIndex, tagBody); } diff --git a/grails-gsp/src/main/groovy/org/grails/gsp/GroovyPageBinding.java b/grails-gsp/src/main/groovy/org/grails/gsp/GroovyPageBinding.java index cea6f3577ef..9f9c9337b7a 100644 --- a/grails-gsp/src/main/groovy/org/grails/gsp/GroovyPageBinding.java +++ b/grails-gsp/src/main/groovy/org/grails/gsp/GroovyPageBinding.java @@ -19,7 +19,7 @@ import groovy.lang.Binding; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import org.grails.web.taglib.TemplateVariableBinding; +import org.grails.taglib.TemplateVariableBinding; import java.util.Map; diff --git a/grails-gsp/src/main/groovy/org/grails/gsp/GroovyPageMetaInfo.java b/grails-gsp/src/main/groovy/org/grails/gsp/GroovyPageMetaInfo.java index f22313670ea..30f8a2e3353 100644 --- a/grails-gsp/src/main/groovy/org/grails/gsp/GroovyPageMetaInfo.java +++ b/grails-gsp/src/main/groovy/org/grails/gsp/GroovyPageMetaInfo.java @@ -27,8 +27,8 @@ import org.grails.encoder.Encoder; import org.grails.gsp.compiler.GroovyPageParser; import org.grails.gsp.jsp.TagLibraryResolver; +import org.grails.taglib.TagLibraryLookup; import org.grails.taglib.encoder.WithCodecHelper; -import org.grails.web.taglib.TagLibraryLookup; import org.springframework.context.ApplicationContext; import org.springframework.core.io.FileSystemResource; import org.springframework.core.io.Resource; diff --git a/grails-gsp/src/main/groovy/org/grails/gsp/GroovyPageTemplate.java b/grails-gsp/src/main/groovy/org/grails/gsp/GroovyPageTemplate.java index befa322c0c1..c6c5a34b46f 100644 --- a/grails-gsp/src/main/groovy/org/grails/gsp/GroovyPageTemplate.java +++ b/grails-gsp/src/main/groovy/org/grails/gsp/GroovyPageTemplate.java @@ -17,6 +17,8 @@ import groovy.lang.Writable; import groovy.text.Template; +import org.grails.taglib.encoder.OutputContextLookup; +import org.grails.taglib.encoder.OutputContextLookupHelper; import java.util.Map; @@ -27,21 +29,26 @@ * @since 0.5 */ public class GroovyPageTemplate implements Template, Cloneable { - + private final OutputContextLookup outputContextLookup; private GroovyPageMetaInfo metaInfo; private boolean allowSettingContentType = false; public GroovyPageTemplate(GroovyPageMetaInfo metaInfo) { + this(metaInfo, OutputContextLookupHelper.getOutputContextLookup()); + } + + public GroovyPageTemplate(GroovyPageMetaInfo metaInfo, OutputContextLookup outputContextLookup) { this.metaInfo = metaInfo; + this.outputContextLookup = outputContextLookup; } public Writable make() { - return new GroovyPageWritable(metaInfo, allowSettingContentType); + return new GroovyPageWritable(metaInfo, outputContextLookup, allowSettingContentType); } @SuppressWarnings("rawtypes") public Writable make(Map binding) { - GroovyPageWritable gptw = new GroovyPageWritable(metaInfo, allowSettingContentType); + GroovyPageWritable gptw = new GroovyPageWritable(metaInfo, outputContextLookup, allowSettingContentType); gptw.setBinding(binding); return gptw; } diff --git a/grails-gsp/src/main/groovy/org/grails/gsp/GroovyPageWritable.java b/grails-gsp/src/main/groovy/org/grails/gsp/GroovyPageWritable.java index 0d7229341b9..edb189bd552 100644 --- a/grails-gsp/src/main/groovy/org/grails/gsp/GroovyPageWritable.java +++ b/grails-gsp/src/main/groovy/org/grails/gsp/GroovyPageWritable.java @@ -20,21 +20,16 @@ import groovy.lang.Writable; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import org.grails.web.servlet.WrappedResponseHolder; -import org.grails.web.servlet.mvc.GrailsWebRequest; -import org.grails.web.taglib.TemplateVariableBinding; -import org.grails.web.taglib.WebRequestTemplateVariableBinding; -import org.grails.web.util.GrailsApplicationAttributes; -import org.springframework.web.context.request.RequestContextHolder; - -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; +import org.grails.taglib.AbstractTemplateVariableBinding; +import org.grails.taglib.TemplateVariableBinding; +import org.grails.taglib.encoder.OutputContext; +import org.grails.taglib.encoder.OutputContextLookup; + import java.io.*; import java.text.DateFormat; import java.util.Date; -import java.util.HashMap; +import java.util.LinkedHashMap; import java.util.Map; -import java.util.concurrent.atomic.AtomicInteger; /** * Writes itself to the specified writer, typically the response writer. @@ -45,31 +40,30 @@ */ class GroovyPageWritable implements Writable { private static final Log LOG = LogFactory.getLog(GroovyPageWritable.class); - private static final String ATTRIBUTE_NAME_DEBUG_TEMPLATES_ID_COUNTER = "org.codehaus.groovy.grails.web.pages.DEBUG_TEMPLATES_COUNTER"; private static final String GSP_NONE_CODEC_NAME = "none"; - private HttpServletResponse response; - private HttpServletRequest request; private GroovyPageMetaInfo metaInfo; - private boolean showSource; - private boolean debugTemplates; - private AtomicInteger debugTemplatesIdCounter; - private GrailsWebRequest webRequest; + private OutputContextLookup outputContextLookup; private boolean allowSettingContentType; - @SuppressWarnings("rawtypes") - private Map additionalBinding = new HashMap(); - private static final String GROOVY_SOURCE_CONTENT_TYPE = "text/plain"; + private Map additionalBinding = new LinkedHashMap(); + private boolean showSource; - public GroovyPageWritable(GroovyPageMetaInfo metaInfo, boolean allowSettingContentType) { + private static final String GROOVY_SOURCE_CONTENT_TYPE = "text/plain"; + public GroovyPageWritable(GroovyPageMetaInfo metaInfo, OutputContextLookup outputContextLookup, boolean allowSettingContentType) { this.metaInfo = metaInfo; + this.outputContextLookup = outputContextLookup; this.allowSettingContentType = allowSettingContentType; - webRequest = (GrailsWebRequest) RequestContextHolder.getRequestAttributes(); - if (webRequest != null) { - request = webRequest.getCurrentRequest(); - HttpServletResponse wrapped = WrappedResponseHolder.getWrappedResponse(); - response = wrapped != null ? wrapped : webRequest.getCurrentResponse(); - } - showSource = shouldShowGroovySource(); + } + + + /* + private static final String ATTRIBUTE_NAME_DEBUG_TEMPLATES_ID_COUNTER = "org.codehaus.groovy.grails.web.pages.DEBUG_TEMPLATES_COUNTER"; + + TODO: implement debugging GSPs at development time + + private boolean debugTemplates; + private AtomicInteger debugTemplatesIdCounter; + debugTemplates = shouldDebugTemplates(); if (debugTemplates) { debugTemplatesIdCounter=(AtomicInteger)request.getAttribute(ATTRIBUTE_NAME_DEBUG_TEMPLATES_ID_COUNTER); @@ -78,7 +72,6 @@ public GroovyPageWritable(GroovyPageMetaInfo metaInfo, boolean allowSettingConte request.setAttribute(ATTRIBUTE_NAME_DEBUG_TEMPLATES_ID_COUNTER, debugTemplatesIdCounter); } } - } private boolean shouldDebugTemplates() { return request != null && request.getParameter("debugTemplates") != null && Environment.getCurrent() == Environment.DEVELOPMENT; @@ -89,6 +82,7 @@ private boolean shouldShowGroovySource() { (Environment.getCurrent() == Environment.DEVELOPMENT) && metaInfo.getGroovySource() != null; } + */ /** * This sets any additional variables that need to be placed in the Binding of the GSP page. @@ -102,14 +96,6 @@ public void setBinding(Map binding) { } } - /** - * Set to true if the generated source should be output instead - * @param showSource True if source output should be output - */ - public void setShowSource(boolean showSource) { - this.showSource = showSource; - } - /** * Writes the template to the specified Writer * @@ -118,69 +104,63 @@ public void setShowSource(boolean showSource) { * @throws IOException */ public Writer writeTo(Writer out) throws IOException { + OutputContext outputContext = outputContextLookup.lookupOutputContext(); try { - return doWriteTo(out); + return doWriteTo(outputContext, out); } finally { - doCleanUp(out); + doCleanUp(outputContext, out); } } - protected void doCleanUp(Writer out) { + protected void doCleanUp(OutputContext outputContext, Writer out) { metaInfo.writeToFinished(out); } - protected Writer doWriteTo(Writer out) throws IOException { - if (showSource) { + protected Writer doWriteTo(OutputContext outputContext, Writer out) throws IOException { + if (shouldShowGroovySource(outputContext)) { // Set it to TEXT - response.setContentType(GROOVY_SOURCE_CONTENT_TYPE); // must come before response.getOutputStream() + outputContext.setContentType(GROOVY_SOURCE_CONTENT_TYPE); // must come before response.getOutputStream() writeGroovySourceToResponse(metaInfo, out); } else { + boolean debugTemplates = shouldDebugTemplates(outputContext); + // Set it to HTML by default if (metaInfo.getCompilationException()!=null) { throw metaInfo.getCompilationException(); } // Set up the script context - TemplateVariableBinding parentBinding = null; - boolean hasRequest = request != null; + AbstractTemplateVariableBinding parentBinding = null; + boolean hasRequest = outputContext != null; boolean newParentCreated = false; if (hasRequest) { - parentBinding = (TemplateVariableBinding) request.getAttribute(GrailsApplicationAttributes.PAGE_SCOPE); + parentBinding = outputContext.getBinding(); if (parentBinding == null) { - if (webRequest != null) { - parentBinding = new TemplateVariableBinding(new WebRequestTemplateVariableBinding(webRequest)); - parentBinding.setRoot(true); + if (outputContext != null) { + parentBinding = outputContext.createAndRegisterRootBinding(); newParentCreated = true; } } } - if (allowSettingContentType && response != null) { + if (allowSettingContentType && hasRequest) { // only try to set content type when evaluating top level GSP - boolean contentTypeAlreadySet = response.isCommitted() || response.getContentType() != null; + boolean contentTypeAlreadySet = outputContext.isContentTypeAlreadySet(); if (!contentTypeAlreadySet) { if (LOG.isDebugEnabled()) { - LOG.debug("Writing response to ["+response.getClass()+"] with content type: " + metaInfo.getContentType()); + LOG.debug("Writing output with content type: " + metaInfo.getContentType()); } - response.setContentType(metaInfo.getContentType()); // must come before response.getWriter() + outputContext.setContentType(metaInfo.getContentType()); // must come before response.getWriter() } } GroovyPageBinding binding = createBinding(parentBinding); - String previousGspCode = GSP_NONE_CODEC_NAME; if (hasRequest) { - request.setAttribute(GrailsApplicationAttributes.PAGE_SCOPE, binding); - previousGspCode = (String)request.getAttribute(GrailsApplicationAttributes.GSP_CODEC); + outputContext.setBinding(binding); } - makeLegacyCodecVariablesAvailable(hasRequest, binding); - - binding.setVariableDirectly(GroovyPage.RESPONSE, response); - binding.setVariableDirectly(GroovyPage.REQUEST, request); - // support development mode's evaluate (so that doesn't search for missing variable in parent bindings) - GroovyPage page = null; try { page = (GroovyPage)metaInfo.getPageClass().newInstance(); @@ -190,12 +170,12 @@ protected Writer doWriteTo(Writer out) throws IOException { page.setBinding(binding); binding.setOwner(page); - page.initRun(out, webRequest, metaInfo); + page.initRun(out, outputContext, metaInfo); int debugId = 0; long debugStartTimeMs = 0; if (debugTemplates) { - debugId = debugTemplatesIdCounter.incrementAndGet(); + debugId = incrementAndGetDebugTemplatesIdCounter(outputContext); out.write("