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}