public static Object captureTagOutput( TagLibraryLookup gspTagLibraryLookup, String namespace, String tagName, Map attrs, Object body, GrailsWebRequest webRequest) { if (!(attrs instanceof GroovyPageAttributes)) { attrs = new GroovyPageAttributes(attrs); } GroovyObject tagLib = lookupCachedTagLib(webRequest, gspTagLibraryLookup, namespace, tagName); boolean preferSubChunkWhenWritingToOtherBuffer = resolvePreferSubChunk(namespace, tagName); Closure actualBody = createOutputCapturingClosure( tagLib, body, webRequest, preferSubChunkWhenWritingToOtherBuffer); final GroovyPageTagWriter out = new GroovyPageTagWriter(preferSubChunkWhenWritingToOtherBuffer); try { GroovyPageOutputStack.currentStack().push(out); Object tagLibProp = tagLib.getProperty(tagName); // retrieve tag lib and create wrapper writer if (tagLibProp instanceof Closure) { Closure tag = (Closure) ((Closure) tagLibProp).clone(); Object bodyResult = null; if (tag.getParameterTypes().length == 1) { bodyResult = tag.call(new Object[] {attrs}); if (actualBody != null && actualBody != EMPTY_BODY_CLOSURE) { Object bodyResult2 = actualBody.call(); if (bodyResult2 != null) { out.print(bodyResult2); } } } else if (tag.getParameterTypes().length == 2) { bodyResult = tag.call(new Object[] {attrs, actualBody}); } else { throw new GrailsTagException( "Tag [" + tagName + "] does not specify expected number of params in tag library [" + tagLib.getClass().getName() + "]"); } boolean returnsObject = gspTagLibraryLookup.doesTagReturnObject(namespace, tagName); if (returnsObject && bodyResult != null && !(bodyResult instanceof Writer)) { return bodyResult; } // add some method to always return string, configurable? return out.getBuffer(); } else { throw new GrailsTagException( "Tag [" + tagName + "] does not exist in tag library [" + tagLib.getClass().getName() + "]"); } } finally { GroovyPageOutputStack.currentStack().pop(); } }
public void invokeTag( String tagName, String tagNamespace, int lineNumber, Map attrs, Closure body) { // TODO custom namespace stuff needs to be generalized and pluggable if (tagNamespace.equals(TEMPLATE_NAMESPACE)) { final String tmpTagName = tagName; final Map tmpAttrs = attrs; tagName = "render"; tagNamespace = DEFAULT_NAMESPACE; attrs = new HashMap() { { put("model", tmpAttrs); put("template", tmpTagName); } }; } else if (tagNamespace.equals(LINK_NAMESPACE)) { final String tmpTagName = tagName; final Map tmpAttrs = attrs; tagName = "link"; tagNamespace = DEFAULT_NAMESPACE; attrs = new HashMap() { { if (tmpAttrs.size() > 0) { put("params", tmpAttrs); } put("mapping", tmpTagName); } }; } try { GroovyObject tagLib = getTagLib(tagNamespace, tagName); if (tagLib != null || gspTagLibraryLookup.hasNamespace(tagNamespace)) { if (tagLib != null) { boolean returnsObject = gspTagLibraryLookup.doesTagReturnObject(tagNamespace, tagName); Object tagLibProp = tagLib.getProperty(tagName); if (tagLibProp instanceof Closure) { Closure tag = (Closure) ((Closure) tagLibProp).clone(); Object tagresult = null; // GSP<->Sitemesh integration requires that the body or head subchunk isn't written to // output boolean preferSubChunkWhenWritingToOtherBuffer = resolvePreferSubChunk(tagNamespace, tagName); if (body instanceof GroovyPageTagBody && preferSubChunkWhenWritingToOtherBuffer) { ((GroovyPageTagBody) body).setPreferSubChunkWhenWritingToOtherBuffer(true); } switch (tag.getParameterTypes().length) { case 1: tagresult = tag.call(new Object[] {attrs}); if (returnsObject && tagresult != null && !(tagresult instanceof Writer)) { out.print(tagresult); } if (body != null && body != EMPTY_BODY_CLOSURE) { body.call(); } break; case 2: if (tag.getParameterTypes().length == 2) { tagresult = tag.call(new Object[] {attrs, (body != null) ? body : EMPTY_BODY_CLOSURE}); if (returnsObject && tagresult != null && !(tagresult instanceof Writer)) { out.print(tagresult); } } break; } } else { throw new GrailsTagException( "Tag [" + tagName + "] does not exist in tag library [" + tagLib.getClass().getName() + "]", getGroovyPageFileName(), lineNumber); } } else { throw new GrailsTagException( "Tag [" + tagName + "] does not exist. No tag library found for namespace: " + tagNamespace, getGroovyPageFileName(), lineNumber); } } else { out.append('<').append(tagNamespace).append(':').append(tagName); for (Object o : attrs.entrySet()) { Map.Entry entry = (Map.Entry) o; out.append(' '); out.append(entry.getKey()).append('='); String value = String.valueOf(entry.getValue()); // handle attribute value quotes & possible escaping " -> " boolean containsQuotes = (value.indexOf('"') > -1); boolean containsSingleQuote = (value.indexOf('\'') > -1); if (containsQuotes && !containsSingleQuote) { out.append('\'').append(value).append('\''); } else if (containsQuotes & containsSingleQuote) { out.append('\"').append(value.replaceAll("\"", """)).append('\"'); } else { out.append('\"').append(value).append('\"'); } } out.append('>'); if (body != null) { Object bodyOutput = body.call(); if (bodyOutput != null) out.print(bodyOutput); } out.append("</").append(tagNamespace).append(':').append(tagName).append('>'); } } catch (Throwable e) { if (LOG.isTraceEnabled()) { LOG.trace("Full exception for problem at " + getGroovyPageFileName() + ":" + lineNumber, e); } // The capture* tags are internal tags and not to be displayed to the user // hence we don't wrap the exception and simple rethrow it if (tagName.matches("capture(Body|Head|Meta|Title|Component)")) { RuntimeException rte = GrailsExceptionResolver.getFirstRuntimeException(e); if (rte == null) { throwRootCause(tagName, tagNamespace, lineNumber, e); } else { throw rte; } } else { throwRootCause(tagName, tagNamespace, lineNumber, e); } } }