Skip to main content

RenderComponentPresentation Tag for Java Mediator

In order to write the first complete Page Template for the Java Mediator for SDL Tridion Templating, I needed a Java tag similar to the @@RenderComponentPresentation@@ from Dreamweaver Templating.

The logic to write such a tag is pretty simple. However, I wanted to have a versatile tag that would not only accept a Component and a Component Template, but also the possibility to specify some 'wildcards' or, more exactly, some Regular Expressions to allow the rendering of several Component Presentations based on different criterias.

The criterias I implemented are:
  • Component title: in the current Page, matches each Component Presentation Component title on this Regular Expression and if a match is found, the CP is displayed;
  • Component Template title: same as above, but matching is done on the Component Presentation's Component Template title;
  • Schema title: same as above, only matches the Schema title of the Component in the Component Presentation;
Additionally, I wanted to have the choice of sharing the Package object a Page Template would interact with, in the Component Template. Therefore, by using an 'inherit' boolean attribute on the tag, I can specify whether the Package from the Page Template would be 'inherited' into the Component Templates.

Examples

A 'Real' Page Template

The JSP TBB below iterates over each Component Presentation in the current Page in the Package and triggers its rendering:

<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@taglib prefix="t" uri="http://www.mitza.net/java/mediator/tag"%>
<html>
<head>
    <title>${Page.Title}</title>
</head>
<body>
    <c:forEach var="cp" items="${Page.ComponentPresentationsList}">
        <t:renderComponentPresentation cp="${cp}" />
    </c:forEach>
</body>
</html>

Specify Component and Component Template

The code below outputs each Component Presentation in the Page:

<c:forEach var="cp" items="${Page.ComponentPresentationsList}">
    <t:renderComponentPresentation component="${cp.Component}"
        componentTemplate="${cp.ComponentTemplate}" />
</c:forEach>

Attributes component and componentTemplate can in this case Strings representing TcmUri values, or actual TcmUri objects.

Specify Schema

Display all Component Presentations with Component based on the Schema with TcmUri tcm:1-2-8:

<t:renderComponentPresentation schema="tcm:1-2-8" />

Note the tag above should not be placed inside a for loop -- it will display all Component Presentations that match the specified Schema.

Combine Schema and Component Template

Combinations of attributes are possible. The more attributes are specified, the more restrictive the matching Component Presentations will become (i.e. the operator between several attributes is AND):

<t:renderComponentPresentation schema="tcm:1-2-8" componentTemplate="tcm:1-3-32" />

Inherit Page Template Package into Component Templates

Specifying attribute inherit="true" (default, false), the Package object used during the rendering of the Page Template will be re-used (inherited) into the Component Template rendering. This means that potentially, several Component Templates can share the same Package.

This will of course work also with other, non Java, mediators. For example, adding a C# TBB, the Package available to it could contain items inserted by previous TBBs. This way it is no longer needed to use the ContextVariables to pass values and objects from Page Template to Component Templates.

<c:forEach var="cp" items="${Page.ComponentPresentationsList}">
    <t:renderComponentPresentation cp="${cp}" inherit="true" />
</c:forEach>

Specifying with Regular Expressions

All three attributes -- component, componentTemplate and schema, allow Regular Expressions. They will be matched on their corresponding values of the Component Presentation Component title, Component Template title and Component's Schema title. The operator between the attributes is AND. The tag renders all Component Presentations matched; no need placing it inside a loop.

<t:renderComponentPresentation schema="Article" /> - displays all CPs where the Component's Schema title contains word "Article"

<t:renderComponentPresentation componentTemplate="^Summary News$" /> - displays all CPs where the Component Template's title matches exactly "Summary News"

<t:renderComponentPresentation component="^Quarterly Report.*2012" componentTemplate="tcm:1-3-32" /> - displays all CPs where the Component's title starts with "Qarterly Report" and contains the string "2012" and are using Component Template tcm:1-3-32

Code

public class RenderComponentPresentationTag extends SimpleTagSupport {

    private TcmUri component;
    private Pattern componentPattern;
    private TcmUri componentTemplate;
    private Pattern componentTemplatePattern;
    private TcmUri schema;
    private Pattern schemaPattern;
    private boolean inherit;

    private Log log = Log.getInstance();

    @Override
    public void doTag() throws JspException, IOException {
        log.debug("RenderComponentPresentationTag.ByTcmUri: component=%s, componentTemplate=%s", component,
                componentTemplate);

        if (component != null && componentTemplate != null) {
            renderComponentPresentation(component, componentTemplate);
        } else {
            FakePageContext pageContext = getJspContext();
            Engine engine = pageContext.getEngine();
            Package _package = pageContext.getPackage();

            Item pageItem = _package.GetByName("Page");
            if (pageItem == null) {
                throw new MediatorException("Cannot find item Page in the Package. Are you in Page Template context?");
            }

            Page page = (Page) engine.GetObject(pageItem);
            renderComponentPresentations(page);
        }
    }

    @Override
    protected FakePageContext getJspContext() {
        return (FakePageContext) super.getJspContext();
    }

    public void setComponent(Object component) {
        if (component instanceof TcmUri) {
            this.component = (TcmUri) component;
        } else if (component instanceof Component) {
            this.component = ((Component) component).getId();
        } else {
            String value = component.toString();
            if (TcmUri.IsValid(value)) {
                this.component = new TcmUri(value);
            } else {
                componentPattern = Pattern.compile(value);
            }
        }
    }

    public void setComponentTemplate(Object componentTemplate) {
        if (componentTemplate instanceof TcmUri) {
            this.componentTemplate = (TcmUri) componentTemplate;
        } else if (componentTemplate instanceof ComponentTemplate) {
            this.componentTemplate = ((ComponentTemplate) componentTemplate).getId();
        } else {
            String value = componentTemplate.toString();
            if (TcmUri.IsValid(value)) {
                this.componentTemplate = new TcmUri(value);
            } else {
                componentTemplatePattern = Pattern.compile(value);
            }
        }
    }

    public void setCp(ComponentPresentation cp) {
        this.component = cp.getComponent().getId();
        this.componentTemplate = cp.getComponentTemplate().getId();
    }

    public void setSchema(Object schema) {
        if (schema instanceof TcmUri) {
            this.schema = (TcmUri) schema;
        } else if (schema instanceof Schema) {
            this.schema = ((Schema) schema).getId();
        } else {
            String value = schema.toString();
            if (TcmUri.IsValid(value)) {
                this.schema = new TcmUri(value);
            } else {
                schemaPattern = Pattern.compile(value);
            }
        }
    }

    public void setInherit(boolean inherit) {
        this.inherit = inherit;
    }

    private void renderComponentPresentations(Page page) throws IOException {
        for (ComponentPresentation cp : page.getComponentPresentationsList()) {
            boolean isRender = true;

            Component cpComponent = cp.getComponent();
            ComponentTemplate cpComponentTemplate = cp.getComponentTemplate();
            Schema cpSchema = cpComponent.getSchema();

            TcmUri cpComponentUri = cpComponent.getId();
            TcmUri cpComponentTemplateUri = cpComponentTemplate.getId();

            if (component != null) {
                isRender = component.equals(cpComponentUri);
            }

            if (isRender && componentPattern != null) {
                isRender = componentPattern.matcher(cpComponent.getTitle()).find();
            }

            if (isRender && componentTemplate != null) {
                isRender = componentTemplate.equals(cpComponentTemplateUri);
            }

            if (isRender && componentTemplatePattern != null) {
                isRender = componentTemplatePattern.matcher(cpComponentTemplate.getTitle()).find();
            }

            if (isRender && schema != null) {
                isRender = schema.equals(cpSchema.getId());
            }

            if (isRender && schemaPattern != null) {
                isRender = schemaPattern.matcher(cpSchema.getTitle()).find();
            }

            if (isRender) {
                renderComponentPresentation(cpComponentUri, cpComponentTemplateUri);
            }
        }
    }

    private void renderComponentPresentation(TcmUri component, TcmUri componentTemplate) throws IOException {
        log.debug(
                "RenderComponentPresentationTag.renderComponentPresentation: component=%s, componentTemplate=%s, inherit=%b",
                component, componentTemplate, inherit);
        String cpContent;
        FakePageContext pageContext = getJspContext();
        Engine engine = pageContext.getEngine();
        JspWriter out = pageContext.getOut();

        if (inherit) {
            MediatorEngine mediatorEngine = MediatorEngine.Wrap(engine);
            cpContent = mediatorEngine.RenderComponentPresentation(component, componentTemplate);
        } else {
            cpContent = engine.RenderComponentPresentation(component, componentTemplate);
        }

        out.print(cpContent);
    }
}


Comments

Popular posts from this blog

Running sp_updatestats on AWS RDS database

Part of the maintenance tasks that I perform on a MSSQL Content Manager database is to run stored procedure sp_updatestats . exec sp_updatestats However, that is not supported on an AWS RDS instance. The error message below indicates that only the sa  account can perform this: Msg 15247 , Level 16 , State 1 , Procedure sp_updatestats, Line 15 [Batch Start Line 0 ] User does not have permission to perform this action. Instead there are several posts that suggest using UPDATE STATISTICS instead: https://dba.stackexchange.com/questions/145982/sp-updatestats-vs-update-statistics I stumbled upon the following post from 2008 (!!!), https://social.msdn.microsoft.com/Forums/sqlserver/en-US/186e3db0-fe37-4c31-b017-8e7c24d19697/spupdatestats-fails-to-run-with-permission-error-under-dbopriveleged-user , which describes a way to wrap the call to sp_updatestats and execute it under a different user: create procedure dbo.sp_updstats with execute as 'dbo' as...

I Have Gone Dark

Maybe it's the Holidays, but my mood has gone pretty dark. That is, regarding the look and feel of my computer and Tridion CME, of course. What I did was to dim the lights on the operating system, so I installed Placebo themes for Windows 7 . I went for the Ashtray look -- great name :) My VM looks now like this: But, once you change the theme on Windows, you should 'match' the theme of your applications. Some skin easily, some not. The Office suite has an in-built scheme, which can be set to Black , but it doesn't actually dim the ribbon tool bars -- it looks quite weird. Yahoo Messenger is skinnable, but you can't change the big white panels where you actually 'chat'. Skype is not skinnable at all. For Chrome, there are plenty of grey themes. Now i'm using Pro Grey . But then I got into changing the theme of websites. While very few offer skinnable interfaces (as GMail does), I had to find a way to darken the websites... Enter Stylish -- a pl...

REL Standard Tag Library

The RSTL is a library of REL tags providing standard functionality such as iterating collections, conditionals, imports, assignments, XML XSLT transformations, formatting dates, etc. RSTL distributable is available on my Google Code page under  REL Standard Tag Library . Always use the latest JAR . This post describes each RSTL tag in the library explaining its functionality, attributes and providing examples. For understanding the way expressions are evaluated, please read my post about the  Expression Language used by REL Standard Tag Library . <c:choose> / <c:when> / <c:otherwise> Syntax:     <c:choose>         <c:when test="expr1">             Do something         </c:when>         <c:when test="expr2">             Do something else         </c:when...