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 *     <a href="mailto:at@nuxeo.com">Anahide Tchertchian</a>
018 *
019 * $Id: DocumentLayoutTagHandler.java 26053 2007-10-16 01:45:43Z atchertchian $
020 */
021
022package org.nuxeo.ecm.platform.forms.layout.facelets;
023
024import java.io.IOException;
025import java.util.ArrayList;
026import java.util.Arrays;
027import java.util.List;
028
029import javax.el.ELException;
030import javax.faces.FacesException;
031import javax.faces.component.UIComponent;
032import javax.faces.view.facelets.CompositeFaceletHandler;
033import javax.faces.view.facelets.FaceletContext;
034import javax.faces.view.facelets.FaceletHandler;
035import javax.faces.view.facelets.TagAttribute;
036import javax.faces.view.facelets.TagAttributes;
037import javax.faces.view.facelets.TagConfig;
038import javax.faces.view.facelets.TagHandler;
039
040import org.apache.commons.lang3.StringUtils;
041import org.apache.commons.logging.Log;
042import org.apache.commons.logging.LogFactory;
043import org.nuxeo.ecm.core.api.DocumentModel;
044import org.nuxeo.ecm.platform.forms.layout.api.BuiltinModes;
045import org.nuxeo.ecm.platform.types.adapter.TypeInfo;
046import org.nuxeo.ecm.platform.ui.web.tag.handler.TagConfigFactory;
047
048/**
049 * Document layout tag handler.
050 * <p>
051 * Computes layouts in given facelet context, for given mode and document attributes.
052 * <p>
053 * Document must be resolved at the component tree construction so it cannot be bound to an iteration value.
054 *
055 * @author <a href="mailto:at@nuxeo.com">Anahide Tchertchian</a>
056 */
057public class DocumentLayoutTagHandler extends TagHandler {
058
059    @SuppressWarnings("unused")
060    private static final Log log = LogFactory.getLog(DocumentLayoutTagHandler.class);
061
062    protected final TagConfig config;
063
064    protected final TagAttribute mode;
065
066    protected final TagAttribute documentMode;
067
068    protected final TagAttribute documentModeFallback;
069
070    protected final TagAttribute value;
071
072    protected final TagAttribute template;
073
074    /**
075     * @since 5.4.2
076     */
077    protected final TagAttribute defaultLayout;
078
079    /**
080     * @since 5.4.2
081     */
082    protected final TagAttribute includeAnyMode;
083
084    protected final TagAttribute[] vars;
085
086    protected final String[] reservedVarsArray = { "id", "name", "mode", "documentMode", "value", "template",
087            "defaultLayout", "includeAnyMode" };
088
089    public DocumentLayoutTagHandler(TagConfig config) {
090        super(config);
091        this.config = config;
092        mode = getRequiredAttribute("mode");
093        documentMode = getAttribute("documentMode");
094        documentModeFallback = getAttribute("documentModeFallback");
095        value = getRequiredAttribute("value");
096        template = getAttribute("template");
097        defaultLayout = getAttribute("defaultLayout");
098        includeAnyMode = getAttribute("includeAnyMode");
099        vars = tag.getAttributes().getAll();
100    }
101
102    /**
103     * If resolved document has layouts, apply each of them.
104     */
105    public void apply(FaceletContext ctx, UIComponent parent) throws IOException, FacesException, ELException {
106        Object document = value.getObject(ctx, DocumentModel.class);
107        if (!(document instanceof DocumentModel)) {
108            return;
109        }
110
111        TypeInfo typeInfo = ((DocumentModel) document).getAdapter(TypeInfo.class);
112        if (typeInfo == null) {
113            return;
114        }
115        String modeValue = mode.getValue(ctx);
116        String documentModeValue = null;
117        if (documentMode != null) {
118            documentModeValue = documentMode.getValue(ctx);
119        }
120        String documentModeFallbackValue = null;
121        if (documentModeFallback != null) {
122            documentModeFallbackValue = documentModeFallback.getValue(ctx);
123        }
124        boolean useAnyMode = true;
125        if (includeAnyMode != null) {
126            useAnyMode = includeAnyMode.getBoolean(ctx);
127        }
128        String defaultMode = documentModeFallbackValue;
129        if (StringUtils.isBlank(defaultMode) && useAnyMode) {
130            defaultMode = BuiltinModes.ANY;
131        }
132        String[] layoutNames = typeInfo.getLayouts(documentModeValue == null ? modeValue : documentModeValue,
133                defaultMode);
134        if (layoutNames == null || layoutNames.length == 0) {
135            // fallback on default layout
136            if (defaultLayout != null) {
137                layoutNames = new String[] { defaultLayout.getValue() };
138            } else {
139                // no layout => do nothing
140                return;
141            }
142        }
143
144        FaceletHandlerHelper helper = new FaceletHandlerHelper(config);
145        TagAttribute modeAttr = helper.createAttribute("mode", modeValue);
146        List<FaceletHandler> handlers = new ArrayList<FaceletHandler>();
147        FaceletHandler leaf = nextHandler;
148        for (String layoutName : layoutNames) {
149            TagAttributes attributes = FaceletHandlerHelper.getTagAttributes(
150                    helper.createAttribute("name", layoutName), modeAttr, value);
151            if (template != null) {
152                attributes = FaceletHandlerHelper.addTagAttribute(attributes, template);
153            }
154            // add other variables put on original tag
155            List<String> reservedVars = Arrays.asList(reservedVarsArray);
156            for (TagAttribute var : vars) {
157                String localName = var.getLocalName();
158                if (!reservedVars.contains(localName)) {
159                    attributes = FaceletHandlerHelper.addTagAttribute(attributes, var);
160                }
161            }
162            TagConfig tagConfig = TagConfigFactory.createTagConfig(config, null, attributes, leaf);
163            handlers.add(new LayoutTagHandler(tagConfig));
164        }
165        CompositeFaceletHandler composite = new CompositeFaceletHandler(handlers.toArray(new FaceletHandler[0]));
166        composite.apply(ctx, parent);
167    }
168}