001/*
002 * (C) Copyright 2006-2007 Nuxeo SAS <http://nuxeo.com> and others
003 *
004 * All rights reserved. This program and the accompanying materials
005 * are made available under the terms of the Eclipse Public License v1.0
006 * which accompanies this distribution, and is available at
007 * http://www.eclipse.org/legal/epl-v10.html
008 *
009 * Contributors:
010 *     Jean-Marc Orliaguet, Chalmers
011 *
012 * $Id$
013 */
014
015package org.nuxeo.theme.elements;
016
017import java.io.StringWriter;
018import java.net.URL;
019
020import org.apache.commons.logging.Log;
021import org.apache.commons.logging.LogFactory;
022import org.nuxeo.theme.Manager;
023import org.nuxeo.theme.engines.EngineType;
024import org.nuxeo.theme.formats.Format;
025import org.nuxeo.theme.formats.FormatFilter;
026import org.nuxeo.theme.formats.FormatType;
027import org.nuxeo.theme.fragments.Fragment;
028import org.nuxeo.theme.models.InfoPool;
029import org.nuxeo.theme.models.ModelException;
030import org.nuxeo.theme.nodes.Node;
031import org.nuxeo.theme.rendering.Filter;
032import org.nuxeo.theme.rendering.FilterType;
033import org.nuxeo.theme.rendering.FilterTypeFamily;
034import org.nuxeo.theme.rendering.RendererType;
035import org.nuxeo.theme.rendering.RenderingInfo;
036import org.nuxeo.theme.types.TypeFamily;
037import org.nuxeo.theme.types.TypeRegistry;
038
039public final class ElementRenderer {
040
041    private static final Log log = LogFactory.getLog(ElementRenderer.class);
042
043    private ElementRenderer() {
044        // This class is not supposed to be instantiated.
045    }
046
047    public static RenderingInfo render(final RenderingInfo info) {
048        return render(info, true);
049    }
050
051    public static RenderingInfo render(RenderingInfo info, final boolean cache) {
052        InfoPool.register(info);
053
054        final StringWriter rendered = new StringWriter();
055        final URL themeUrl = info.getThemeUrl();
056        if (themeUrl == null) {
057            log.warn("Theme URL not set for the element: " + info.getElement());
058        }
059
060        final EngineType engine = info.getEngine();
061        final Element element = info.getElement();
062
063        String markup = "";
064        if (element.isLeaf()) {
065            if (!(element instanceof Fragment)) {
066                log.error(String.format("Leaf nodes must be fragments, ignoring element: %s",
067                        element.getElementType().getTypeName()));
068                return info;
069            }
070            final Fragment fragment = (Fragment) element;
071            try {
072                info.setModel(fragment.getModel());
073            } catch (ModelException e) {
074                if (info.isDirty()) {
075                    final String fragmentName = fragment.getFragmentType().getTypeName();
076                    log.error("Rendering of fragment '" + fragmentName + "' failed.", e);
077                    return info;
078                }
079            }
080            if (fragment.isDynamic()) {
081                info.setDirty(true);
082            }
083        } else {
084            for (Node child : element.getChildrenInContext(themeUrl)) {
085                final RenderingInfo childInfo = new RenderingInfo((Element) child, themeUrl);
086                final RenderingInfo renderedChild = render(childInfo);
087                if (renderedChild == null) {
088                    continue;
089                }
090                rendered.append(renderedChild.getMarkup());
091            }
092            markup = rendered.toString();
093        }
094
095        info.setMarkup(markup);
096
097        final RendererType renderer = engine.getRenderers().get(element.getElementType().getTypeName());
098
099        if (renderer == null) {
100            return info;
101        }
102
103        final String templateEngineName = info.getTemplateEngine().getName();
104        final String engineName = info.getEngine().getName();
105        final String viewMode = info.getViewMode();
106        for (final String filterName : renderer.getFilters()) {
107
108            // Look for a filter for the current engine
109            FilterType filterType = getFilterFor(engineName, filterName, templateEngineName, viewMode);
110
111            // Fall back to no specific engine
112            if (filterType == null) {
113                filterType = getFilterFor("*", filterName, templateEngineName, viewMode);
114            }
115
116            if (filterType == null) {
117                log.warn("Filter type '" + filterName + "' not found.");
118                continue;
119            }
120
121            final Filter filter = filterType.getFilter();
122            if (filter == null) {
123                log.warn("Filter instantiation failed: " + filterName);
124                continue;
125            }
126
127            final FilterTypeFamily filterTypeFamily = filterType.getFilterTypeFamily();
128
129            if (filterTypeFamily == FilterTypeFamily.FORMAT) {
130                final FormatType formatType = ((FormatFilter) filter).getFormatType();
131                final Format format = ElementFormatter.getFormatByType(element, formatType);
132                if (format == null) {
133                    log.debug("Could not find '" + formatType.getTypeName() + "' format for: "
134                            + element.getElementType().getTypeName());
135                    continue;
136                }
137                info.setFormat(format);
138            } else if (filterTypeFamily == FilterTypeFamily.STANDALONE) {
139                // Do nothing
140            } else {
141                log.warn("Unsupported filter type: " + filterName);
142            }
143
144            info = filter.process(info, cache);
145
146            // Abort the rendering if the filter returns null
147            if (info == null) {
148                break;
149            }
150        }
151        return info;
152    }
153
154    private static FilterType getFilterFor(final String engineName, final String filterName,
155            final String templateEngineName, final String viewMode) {
156
157        TypeRegistry typeRegistry = Manager.getTypeRegistry();
158
159        // get the filter for this specified template engine and view mode
160        FilterType filterType = (FilterType) typeRegistry.lookup(TypeFamily.FILTER,
161                String.format("%s/%s/%s/%s", engineName, templateEngineName, viewMode, filterName));
162
163        // fall back to unspecified view mode
164        if (filterType == null) {
165            filterType = (FilterType) typeRegistry.lookup(TypeFamily.FILTER,
166                    String.format("%s/%s/*/%s", engineName, templateEngineName, filterName));
167        }
168
169        // fall back to unspecified template engine and view mode
170        if (filterType == null) {
171            filterType = (FilterType) typeRegistry.lookup(TypeFamily.FILTER,
172                    String.format("%s/*/*/%s", engineName, filterName));
173        }
174        return filterType;
175    }
176}