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: SubWidgetTagHandler.java 30553 2008-02-24 15:51:31Z atchertchian $
020 */
021
022package org.nuxeo.ecm.platform.forms.layout.facelets;
023
024import java.io.IOException;
025import java.io.Serializable;
026import java.util.ArrayList;
027import java.util.HashMap;
028import java.util.List;
029import java.util.Map;
030
031import javax.el.ELException;
032import javax.el.ExpressionFactory;
033import javax.el.ValueExpression;
034import javax.faces.FacesException;
035import javax.faces.component.UIComponent;
036import javax.faces.view.facelets.FaceletContext;
037import javax.faces.view.facelets.FaceletHandler;
038import javax.faces.view.facelets.TagAttribute;
039import javax.faces.view.facelets.TagConfig;
040import javax.faces.view.facelets.TagHandler;
041
042import org.apache.commons.logging.Log;
043import org.apache.commons.logging.LogFactory;
044import org.nuxeo.ecm.platform.forms.layout.api.Widget;
045
046/**
047 * SubWidget tag handler.
048 * <p>
049 * Iterates over a widget subwidgets and apply next handlers as many times as needed.
050 * <p>
051 * Only works when used inside a tag using the {@link WidgetTagHandler}.
052 *
053 * @author <a href="mailto:at@nuxeo.com">Anahide Tchertchian</a>
054 */
055public class SubWidgetTagHandler extends TagHandler {
056
057    private static final Log log = LogFactory.getLog(SubWidgetTagHandler.class);
058
059    protected final TagConfig config;
060
061    /**
062     * @since 7.2
063     */
064    protected final TagAttribute recomputeIds;
065
066    public SubWidgetTagHandler(TagConfig config) {
067        super(config);
068        this.config = config;
069        recomputeIds = getAttribute("recomputeIds");
070    }
071
072    /**
073     * For each subwidget in current widget, exposes widget variables and applies next handler.
074     * <p>
075     * Needs widget to be exposed in context, so works in conjunction with {@link WidgetTagHandler}.
076     * <p>
077     * Widget variables exposed: {@link RenderVariables.widgetVariables#widget} , same variable suffixed with "_n" where
078     * n is the widget level, and {@link RenderVariables.widgetVariables#widgetIndex}.
079     */
080    public void apply(FaceletContext ctx, UIComponent parent) throws IOException, FacesException, ELException {
081        // resolve subwidgets from widget in context
082        Widget widget = null;
083        String widgetVariableName = RenderVariables.widgetVariables.widget.name();
084        FaceletHandlerHelper helper = new FaceletHandlerHelper(config);
085        TagAttribute widgetAttribute = helper.createAttribute(widgetVariableName, "#{" + widgetVariableName + "}");
086        if (widgetAttribute != null) {
087            widget = (Widget) widgetAttribute.getObject(ctx, Widget.class);
088        }
089        if (widget == null) {
090            log.error("Could not resolve widget " + widgetAttribute);
091            return;
092        }
093
094        Widget[] subWidgets = widget.getSubWidgets();
095        if (subWidgets == null || subWidgets.length == 0) {
096            return;
097        }
098
099        boolean recomputeIdsBool = false;
100        if (recomputeIds != null) {
101            recomputeIdsBool = recomputeIds.getBoolean(ctx);
102        }
103
104        int subWidgetCounter = 0;
105        for (Widget subWidget : subWidgets) {
106            // set unique id on widget before exposing it to the context, but assumes iteration could be done several
107            // times => do not generate id again if already set, unless specified by attribute "recomputeIds"
108            if (subWidget != null && (subWidget.getId() == null || recomputeIdsBool)) {
109                WidgetTagHandler.generateWidgetId(ctx, helper, subWidget, false);
110            }
111
112            // expose widget variables
113            Map<String, ValueExpression> variables = new HashMap<String, ValueExpression>();
114            ExpressionFactory eFactory = ctx.getExpressionFactory();
115            ValueExpression subWidgetVe = eFactory.createValueExpression(subWidget, Widget.class);
116            Integer level = null;
117            String tagConfigId = null;
118            if (subWidget != null) {
119                level = Integer.valueOf(subWidget.getLevel());
120                tagConfigId = subWidget.getTagConfigId();
121            }
122
123            variables.put(RenderVariables.widgetVariables.widget.name(), subWidgetVe);
124            // variables.put(String.format("%s_%s",
125            // RenderVariables.widgetVariables.widget.name(), level),
126            // subWidgetVe);
127            ValueExpression subWidgetIndexVe = eFactory.createValueExpression(Integer.valueOf(subWidgetCounter),
128                    Integer.class);
129            variables.put(RenderVariables.widgetVariables.widgetIndex.name(), subWidgetIndexVe);
130            variables.put(RenderVariables.widgetVariables.widgetIndex.name() + "_" + level, subWidgetIndexVe);
131
132            // XXX: expose widget controls too, need to figure out
133            // why controls cannot be references to widget.controls like
134            // properties are in TemplateWidgetTypeHandler
135            if (subWidget != null) {
136                for (Map.Entry<String, Serializable> ctrl : subWidget.getControls().entrySet()) {
137                    String key = ctrl.getKey();
138                    String name = RenderVariables.widgetVariables.widgetControl.name() + "_" + key;
139                    Serializable value = ctrl.getValue();
140                    variables.put(name, eFactory.createValueExpression(value, Object.class));
141                }
142            }
143
144            List<String> blockedPatterns = new ArrayList<String>();
145            blockedPatterns.add(RenderVariables.widgetVariables.widget.name());
146            blockedPatterns.add(RenderVariables.widgetVariables.widgetIndex.name() + "*");
147            blockedPatterns.add(RenderVariables.widgetVariables.widgetControl.name() + "_*");
148
149            FaceletHandler handlerWithVars = helper.getAliasFaceletHandler(tagConfigId, variables, blockedPatterns,
150                    nextHandler);
151
152            // apply
153            handlerWithVars.apply(ctx, parent);
154            subWidgetCounter++;
155        }
156    }
157}