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