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.formats;
023
024import java.net.URL;
025
026import org.apache.commons.logging.Log;
027import org.apache.commons.logging.LogFactory;
028import org.nuxeo.theme.Manager;
029import org.nuxeo.theme.elements.Element;
030import org.nuxeo.theme.elements.ElementType;
031import org.nuxeo.theme.engines.EngineType;
032import org.nuxeo.theme.fragments.Fragment;
033import org.nuxeo.theme.models.Model;
034import org.nuxeo.theme.models.ModelType;
035import org.nuxeo.theme.rendering.AbstractFilter;
036import org.nuxeo.theme.rendering.FilterTypeFamily;
037import org.nuxeo.theme.rendering.RenderingInfo;
038import org.nuxeo.theme.resources.ResourceManager;
039import org.nuxeo.theme.templates.TemplateEngineType;
040import org.nuxeo.theme.types.TypeFamily;
041import org.nuxeo.theme.types.TypeRegistry;
042import org.nuxeo.theme.views.View;
043import org.nuxeo.theme.views.ViewType;
044
045public class FormatFilter extends AbstractFilter {
046
047    private static final Log log = LogFactory.getLog(FormatFilter.class);
048
049    private FormatType formatType;
050
051    public FormatFilter() {
052    }
053
054    public FilterTypeFamily getFilterTypeFamily() {
055        return FilterTypeFamily.FORMAT;
056    }
057
058    public FormatType getFormatType() {
059        return formatType;
060    }
061
062    public void setFormatType(final FormatType formatType) {
063        this.formatType = formatType;
064    }
065
066    @Override
067    public RenderingInfo process(final RenderingInfo info, final boolean cache) {
068        final EngineType engine = info.getEngine();
069        final TemplateEngineType templateEngineType = info.getTemplateEngine();
070        final String viewMode = info.getViewMode();
071        final Element element = info.getElement();
072        final ElementType elementType = element.getElementType();
073
074        final Model model = info.getModel();
075        final ModelType modelType = model == null ? null : model.getModelType();
076
077        final Format format = info.getFormat();
078
079        // look for a view by model type and by view name
080        final View view = getView(format.getName(), engine, viewMode, elementType, modelType, formatType,
081                templateEngineType);
082
083        if (view == null) {
084            // Sanity check
085            if (model == null) {
086                if (element instanceof Fragment) {
087                    Fragment fragment = (Fragment) element;
088                    ModelType expectedModelType = fragment.getFragmentType().getModelType();
089                    if (expectedModelType != null) {
090                        log.warn(String.format("Fragment %s should have returned a model of type: %s",
091                                fragment.computeXPath(), expectedModelType.getTypeName()));
092                    }
093                }
094            } else {
095                log.warn(String.format("No %s view named '%s' found for element %s (theme URL is: %s)",
096                        formatType.getTypeName(), format.getName(), element.computeXPath(),
097                        info.getThemeUrl().toString()));
098            }
099        } else {
100
101            final String markup = view.render(info);
102            info.setMarkup(markup);
103
104            // Add resources used by the view (.css, .js, ...)
105            final URL themeUrl = info.getThemeUrl();
106            final ResourceManager resourceManager = Manager.getResourceManager();
107            for (String resource : view.getViewType().getResources()) {
108                resourceManager.addResource(resource, themeUrl);
109            }
110        }
111        return info;
112    }
113
114    private View getView(final String viewName, final EngineType engine, final String viewMode,
115            final ElementType elementType, final ModelType modelType, final FormatType formatType,
116            final TemplateEngineType templateEngineType) {
117
118        // allow to fall back on no specific view name
119        final String effectiveViewName = (viewName == null || viewName.equals("")) ? "*" : viewName;
120        final String effectiveViewMode = viewMode == null ? "*" : viewMode;
121        final String engineName = engine == null ? "default" : engine.getName();
122        final String templateEngineName = templateEngineType == null ? null : templateEngineType.getName();
123
124        final String elementTypeName = elementType == null ? "*" : elementType.getTypeName();
125        final String modelTypeName = modelType == null ? "*" : modelType.getTypeName();
126        final String formatTypeName = formatType == null ? "*" : formatType.getTypeName();
127
128        View view = getViewFor(formatTypeName, elementTypeName, effectiveViewName, modelTypeName, engineName,
129                effectiveViewMode, templateEngineName);
130
131        // fall back to unspecified element type
132        if (view == null && !"*".equals(elementTypeName)) {
133            view = getViewFor(formatTypeName, "*", effectiveViewName, modelTypeName, engineName, effectiveViewMode,
134                    templateEngineName);
135        }
136
137        // fall back to unspecified model type
138        if (view == null && !"*".equals(modelTypeName)) {
139            view = getViewFor(formatTypeName, elementTypeName, effectiveViewName, "*", engineName, effectiveViewMode,
140                    templateEngineName);
141        }
142
143        // fall back to unspecified element and model type
144        if (view == null && !"*".equals(elementTypeName) && !"*".equals(modelTypeName)) {
145            view = getViewFor(formatTypeName, "*", effectiveViewName, "*", engineName, effectiveViewMode,
146                    templateEngineName);
147        }
148
149        // fall back to unspecified view name and unspecified model type
150        if (view == null && !"*".equals(effectiveViewName)) {
151            view = getViewFor(formatTypeName, elementTypeName, "*", "*", engineName, effectiveViewMode,
152                    templateEngineName);
153        }
154        return view;
155    }
156
157    private View getViewFor(final String formatTypeName, final String elementTypeName, final String viewName,
158            final String modelTypeName, final String engineName, final String viewMode, final String templateEngineName) {
159
160        TypeRegistry typeRegistry = Manager.getTypeRegistry();
161
162        ViewType viewType = (ViewType) typeRegistry.lookup(TypeFamily.VIEW, ViewType.computeName(formatTypeName,
163                elementTypeName, viewName, modelTypeName, engineName, viewMode, templateEngineName));
164
165        // Any view mode
166        if (viewType == null && !"*".equals(viewMode)) {
167            viewType = (ViewType) typeRegistry.lookup(TypeFamily.VIEW, ViewType.computeName(formatTypeName,
168                    elementTypeName, viewName, modelTypeName, engineName, "*", templateEngineName));
169        }
170
171        // Any view mode, default engine
172        if (viewType == null && !"default".equals(engineName)) {
173            viewType = (ViewType) typeRegistry.lookup(TypeFamily.VIEW, ViewType.computeName(formatTypeName,
174                    elementTypeName, viewName, modelTypeName, "default", "*", templateEngineName));
175        }
176
177        return viewType == null ? null : viewType.getView();
178    }
179}