001/**
002 * Copyright 2005-2018 The Kuali Foundation
003 *
004 * Licensed under the Educational Community License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.opensource.org/licenses/ecl2.php
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016package org.kuali.rice.krad.uif.freemarker;
017
018import java.util.Collections;
019
020import org.apache.log4j.Logger;
021import org.kuali.rice.krad.uif.component.Component;
022import org.kuali.rice.krad.uif.lifecycle.ViewLifecycle;
023import org.kuali.rice.krad.uif.lifecycle.ViewLifecyclePhase;
024import org.kuali.rice.krad.uif.lifecycle.ViewLifecycleTaskBase;
025
026import freemarker.core.Environment;
027import freemarker.core.Macro;
028import freemarker.template.TemplateModel;
029
030/**
031 * Perform actual rendering on a component during the lifecycle.
032 * 
033 * @author Kuali Rice Team (rice.collab@kuali.org)
034 */
035public class RenderComponentTask extends ViewLifecycleTaskBase<Component> {
036
037    private static final Logger LOG = Logger.getLogger(RenderComponentTask.class);
038
039    /**
040     * Constructor.
041     * 
042     * @param phase The render phase for the component.
043     */
044    public RenderComponentTask() {
045        super(Component.class);
046    }
047
048    /**
049     * {@inheritDoc}
050     */
051    @Override
052    protected void performLifecycleTask() {
053        Component component = (Component) getElementState().getElement();
054        if (!component.isRender() || component.getTemplate() == null) {
055            return;
056        }
057        
058        LifecycleRenderingContext renderingContext = ViewLifecycle.getRenderingContext();
059        renderingContext.clearRenderingBuffer();
060
061        renderingContext.importTemplate(component.getTemplate());
062
063        for (String additionalTemplate : component.getAdditionalTemplates()) {
064            renderingContext.importTemplate(additionalTemplate);
065        }
066
067        try {
068            Environment env = renderingContext.getEnvironment();
069
070            // Check for a single-arg macro, with the parameter name "component"
071            // defer for parent rendering if not found
072            Macro fmMacro = (Macro) env.getMainNamespace().get(component.getTemplateName());
073
074            if (fmMacro == null) {
075                return;
076            }
077
078            String[] args = fmMacro.getArgumentNames();
079            if (args == null || args.length != 1 || !component.getComponentTypeName().equals(args[0])) {
080                return;
081            }
082
083            FreeMarkerInlineRenderUtils.renderTemplate(env, component,
084                    null, false, false, Collections.<String, TemplateModel> emptyMap());
085
086            component.setRenderedHtmlOutput(renderingContext.getRenderedOutput());
087            component.setSelfRendered(true);
088        } catch (Throwable e) {
089            if (ViewLifecycle.isStrict()) {
090                LOG.warn("Error rendering component during lifecycle phase " + getElementState()
091                        + " falling back to higher level rendering", e);
092            } else if (ViewLifecycle.isTrace() && LOG.isDebugEnabled()) {
093                LOG.debug("component rendering failed during lifecycle phase " + getElementState()
094                        + " falling back to higher level rendering", e);
095            }
096        }
097
098    }
099}