@Override
@SuppressWarnings("unchecked")
public int doEndTag() throws JspException {
try {
if (!name.startsWith("/")) {
throw new StripesJspException("The name= attribute of the layout-render tag must be " +
"an absolute path, starting with a forward slash (/). Please modify the " +
"layout-render tag with the name '" + name + "' accordingly.");
}
HttpServletRequest request = (HttpServletRequest) getPageContext().getRequest();
// Put the components into the request, for the definition tag to use.. using a stack
// to allow for the same layout to be nested inside itself :o
String attributeName = LayoutDefinitionTag.PREFIX + this.name;
Stack<LayoutContext> stack =
(Stack<LayoutContext>) request.getAttribute(attributeName);
if (stack == null) {
stack = new Stack<LayoutContext>();
request.setAttribute(attributeName, stack);
}
stack.push(this.context);
// Now wrap the JSPWriter, and include the target JSP
BodyContent content = getPageContext().pushBody();
getPageContext().include(this.name, false);
getPageContext().popBody();
getPageContext().getOut().write(content.getString());
// Check that the layout actually got rendered as some containers will
// just quietly ignore includes of non-existent pages!
if (!this.context.isRendered()) {
throw new StripesJspException(
"Attempt made to render a layout that does not exist. The layout name " +
"provided was '" + this.name + "'. Please check that a JSP/view exists at " +
"that location within your web application."
);
}
stack.pop();
popPageContextAttributes(); // remove any dynattrs from page scope
// Clean up in case the tag gets pooled
this.context = new LayoutContext();
}
catch (StripesJspException sje) { throw sje; }
catch (Exception e) {
throw new StripesJspException(
"An exception was raised while invoking a layout. The layout used was " +
"'" + this.name + "'. The following information was supplied to the render " +
"tag: " + this.context.toString(), e);
}