in grails-controllers/src/main/groovy/grails/artefact/controller/support/ResponseRenderer.groovy [223:440]
void render(Map argMap) {
GrailsWebRequest webRequest = (GrailsWebRequest)RequestContextHolder.currentRequestAttributes()
HttpServletResponse response = webRequest.currentResponse
String layoutArg = argMap[ARGUMENT_LAYOUT]?.toString() ?: null
boolean statusSet = handleStatusArgument(argMap, webRequest, response)
def applicationAttributes = webRequest.attributes
if (argMap.containsKey(ARGUMENT_TEXT)) {
def textArg = argMap[ARGUMENT_TEXT]
applyContentType response, argMap, textArg
if (textArg instanceof Writable) {
renderWritable((Writable)textArg, response)
webRequest.renderView = false
} else {
CharSequence text = (textArg instanceof CharSequence) ? ((CharSequence)textArg) : textArg.toString()
render text
}
setLayout webRequest.currentRequest, layoutArg
}
else if (argMap.containsKey(ARGUMENT_VIEW)) {
String viewName = argMap[ARGUMENT_VIEW].toString()
String viewUri = applicationAttributes.getNoSuffixViewURI((GroovyObject)this, viewName)
String contextPath = getContextPath(webRequest, argMap)
if(contextPath) {
viewUri = contextPath + viewUri
}
Object modelObject = argMap[ARGUMENT_MODEL]
if (modelObject) {
Collection<ActionResultTransformer> resultTransformers = actionResultTransformers
for (ActionResultTransformer resultTransformer : resultTransformers) {
modelObject = resultTransformer.transformActionResult webRequest,viewUri, modelObject
}
}
applyContentType webRequest.currentResponse, argMap, null, false
Map model
if (modelObject instanceof Map) {
model = (Map) modelObject
}
else {
model = [:]
}
((GroovyObject)this).setProperty "modelAndView", new ModelAndView(viewUri, model)
setLayout webRequest.currentRequest, layoutArg
}
else if (argMap.containsKey(ARGUMENT_TEMPLATE)) {
applyContentType response, argMap, null, false
webRequest.renderView = false
boolean hasModel = argMap.containsKey(ARGUMENT_MODEL)
def modelObject
if(hasModel) {
modelObject = argMap[ARGUMENT_MODEL]
}
String templateName = argMap[ARGUMENT_TEMPLATE].toString()
String var
if (argMap.containsKey(ARGUMENT_VAR)) {
var = String.valueOf( argMap[ARGUMENT_VAR] )
}
// get the template uri
String templateUri = applicationAttributes.getTemplateURI((GroovyObject)this, templateName, false)
// retrieve view resolver
def applicationContext = applicationAttributes.getApplicationContext()
def viewResolver = applicationContext.getBean(CompositeViewResolver.BEAN_NAME, CompositeViewResolver)
try {
View view = viewResolver.resolveView(templateUri, webRequest.locale)
if(view instanceof GroovyPageView) {
((GroovyPageTemplate)((GroovyPageView)view).template).allowSettingContentType = true
}
if (view == null) {
throw new ControllerExecutionException("Unable to load template for uri [$templateUri]. Template not found.")
}
boolean renderWithLayout = (layoutArg || webRequest.getCurrentRequest().getAttribute(WebUtils.LAYOUT_ATTRIBUTE))
// if automatic decoration occurred unwrap, since this is a partial
if (renderWithLayout) {
setLayout webRequest.currentRequest, layoutArg
}
Map binding = [:]
if (argMap.containsKey(ARGUMENT_BEAN)) {
Object bean = argMap[ARGUMENT_BEAN]
if (hasModel) {
if (modelObject instanceof Map) {
setTemplateModel webRequest, binding, (Map) modelObject
}
}
if (GrailsStringUtils.isBlank(var)) {
binding.put DEFAULT_ARGUMENT, bean
}
else {
binding.put var, bean
}
renderViewForTemplate webRequest, view, binding
}
else if (argMap.containsKey(ARGUMENT_COLLECTION)) {
Object colObject = argMap[ARGUMENT_COLLECTION]
if (hasModel) {
if (modelObject instanceof Map) {
setTemplateModel webRequest, binding, (Map)modelObject
}
}
renderTemplateForCollection webRequest, view, binding, colObject, var
}
else if (hasModel) {
if (modelObject instanceof Map) {
setTemplateModel webRequest, binding, (Map)modelObject
}
renderViewForTemplate webRequest, view, binding
}
else {
renderViewForTemplate webRequest, view, binding
}
}
catch (GroovyRuntimeException gre) {
throw new ControllerExecutionException("Error rendering template [$templateName]: ${gre.message}", gre)
}
catch (IOException ioex) {
throw new ControllerExecutionException("I/O error executing render method for arguments [$argMap]: ${ioex.message}" , ioex)
}
}
else if (argMap.containsKey(ARGUMENT_FILE)) {
webRequest.renderView = false
def o = argMap[ARGUMENT_FILE]
def fnO = argMap[ARGUMENT_FILE_NAME]
String fileName = fnO ? fnO.toString() : ((o instanceof File) ? ((File)o).name : null )
if (o) {
boolean hasContentType = applyContentType(response, argMap, null, false)
if (fileName) {
if(!hasContentType) {
hasContentType = detectContentTypeFromFileName(webRequest, response, argMap, fileName)
}
if (fnO) {
response.setHeader HttpHeaders.CONTENT_DISPOSITION, "$DISPOSITION_HEADER_PREFIX\"$fileName\""
}
}
if (!hasContentType) {
throw new ControllerExecutionException(
"Argument [file] of render method specified without valid [contentType] argument")
}
InputStream input
try {
if (o instanceof File) {
input = IOUtils.openStream(o)
}
else if (o instanceof InputStream) {
input = (InputStream)o
}
else if (o instanceof byte[]) {
input = new ByteArrayInputStream((byte[])o)
}
else {
input = IOUtils.openStream(new File(o.toString()))
}
SpringIOUtils.copy input, response.getOutputStream()
} catch (IOException e) {
throw new ControllerExecutionException(
"I/O error copying file to response: ${e.message}", e)
}
finally {
if (input) {
try {
((InputStream)input).close()
} catch (IOException e) {
// ignore
}
}
}
}
}
else if( !statusSet ) {
webRequest.renderView = false
if(argMap instanceof JSONElement) {
response.contentType = GrailsWebUtil.getContentType(MimeType.JSON.name, DEFAULT_ENCODING)
renderWritable( (JSONElement)argMap, response )
}
else {
applyContentType response, argMap, argMap
try {
response.writer.write argMap.inspect()
}
catch (IOException e) {
throw new ControllerExecutionException("I/O error obtaining response writer: ${e.message}", e)
}
}
}
else {
// reached here so only the status was set, just send it back
String message = argMap?.message?.toString()
int statusCode = response.status
if( message ) {
response.sendError(statusCode, message )
}
else {
// if the status code is an error trigger the container
// forwarding logic
if(statusCode >= 300) {
response.sendError(statusCode)
}
else {
// otherwise just ensure the status is propagated to the client
response.setStatus(statusCode)
response.flushBuffer()
}
}
}
}