001/*
002 * (C) Copyright 2006-2014 Nuxeo SAS (http://nuxeo.com/) and contributors.
003 *
004 * All rights reserved. This program and the accompanying materials
005 * are made available under the terms of the GNU Lesser General Public License
006 * (LGPL) version 2.1 which accompanies this distribution, and is available at
007 * http://www.gnu.org/licenses/lgpl-2.1.html
008 *
009 * This library is distributed in the hope that it will be useful,
010 * but WITHOUT ANY WARRANTY; without even the implied warranty of
011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
012 * Lesser General Public License for more details.
013 *
014 * Contributors:
015 *     <a href="mailto:at@nuxeo.com">Anahide Tchertchian</a>
016 *
017 * $Id: AbstractWidgetTypeHandler.java 28491 2008-01-04 19:04:30Z sfermigier $
018 */
019
020package org.nuxeo.ecm.platform.forms.layout.facelets.plugins;
021
022import java.util.ArrayList;
023import java.util.List;
024import java.util.Map;
025
026import javax.faces.view.facelets.CompositeFaceletHandler;
027import javax.faces.view.facelets.FaceletContext;
028import javax.faces.view.facelets.FaceletHandler;
029import javax.faces.view.facelets.TagAttribute;
030import javax.faces.view.facelets.TagAttributes;
031import javax.faces.view.facelets.TagConfig;
032import javax.faces.view.facelets.ValidatorHandler;
033
034import org.apache.commons.lang.StringUtils;
035import org.nuxeo.ecm.platform.forms.layout.api.BuiltinWidgetModes;
036import org.nuxeo.ecm.platform.forms.layout.api.Widget;
037import org.nuxeo.ecm.platform.forms.layout.api.exceptions.WidgetException;
038import org.nuxeo.ecm.platform.forms.layout.facelets.FaceletHandlerHelper;
039import org.nuxeo.ecm.platform.forms.layout.facelets.RenderVariables;
040import org.nuxeo.ecm.platform.forms.layout.facelets.WidgetTypeHandler;
041import org.nuxeo.ecm.platform.forms.layout.facelets.dev.WidgetTypeDevTagHandler;
042import org.nuxeo.ecm.platform.ui.web.tag.handler.LeafFaceletHandler;
043import org.nuxeo.ecm.platform.ui.web.tag.handler.TagConfigFactory;
044import org.nuxeo.ecm.platform.ui.web.validator.DocumentConstraintValidator;
045
046import com.sun.faces.facelets.tag.ui.InsertHandler;
047
048/**
049 * Abstract widget type handler.
050 *
051 * @author <a href="mailto:at@nuxeo.com">Anahide Tchertchian</a>
052 */
053public abstract class AbstractWidgetTypeHandler implements WidgetTypeHandler {
054
055    private static final long serialVersionUID = -2933485416045771633L;
056
057    /**
058     * @since 6.0
059     */
060    public static final String DEV_TEMPLATE_PROPERTY_NAME = "dev_template";
061
062    /**
063     * @since 6.0
064     */
065    public static final String DISABLE_DEV_PROPERTY_NAME = "disable_dev";
066
067    protected Map<String, String> properties;
068
069    public abstract FaceletHandler getFaceletHandler(FaceletContext ctx, TagConfig tagConfig, Widget widget,
070            FaceletHandler[] subHandlers) throws WidgetException;
071
072    public FaceletHandler getDevFaceletHandler(FaceletContext ctx, TagConfig tagConfig, Widget widget)
073            throws WidgetException {
074        if (Boolean.parseBoolean(getProperty(DISABLE_DEV_PROPERTY_NAME))
075                || Boolean.parseBoolean((String) widget.getProperty(DISABLE_DEV_PROPERTY_NAME))) {
076            return null;
077        }
078        // lookup in the widget type configuration
079        String template = (String) widget.getProperty(DEV_TEMPLATE_PROPERTY_NAME);
080        if (StringUtils.isBlank(template)) {
081            template = getProperty(DEV_TEMPLATE_PROPERTY_NAME);
082        }
083        FaceletHandlerHelper helper = new FaceletHandlerHelper(ctx, tagConfig);
084        TagAttribute widgetAttr = helper.createAttribute("widget",
085                String.format("#{%s}", RenderVariables.widgetVariables.widget.name()));
086        TagAttributes devWidgetAttributes;
087        if (StringUtils.isBlank(template)) {
088            devWidgetAttributes = FaceletHandlerHelper.getTagAttributes(widgetAttr);
089        } else {
090            devWidgetAttributes = FaceletHandlerHelper.getTagAttributes(widgetAttr,
091                    helper.createAttribute("template", template));
092        }
093        TagConfig devWidgetConfig = TagConfigFactory.createTagConfig(tagConfig, widget.getTagConfigId(),
094                devWidgetAttributes, new LeafFaceletHandler());
095        return new WidgetTypeDevTagHandler(devWidgetConfig);
096    }
097
098    public String getProperty(String name) {
099        if (properties != null) {
100            return properties.get(name);
101        }
102        return null;
103    }
104
105    /**
106     * Helper method, throws an exception if property value is null.
107     */
108    public String getRequiredProperty(String name) throws WidgetException {
109        String value = getProperty(name);
110        if (value == null) {
111            throw new WidgetException(String.format(
112                    "Required property %s is missing " + "on widget type configuration", name));
113        }
114        return value;
115    }
116
117    public void setProperties(Map<String, String> properties) {
118        this.properties = properties;
119    }
120
121    /**
122     * Returns sub handlers as computed from tag information.
123     * <p>
124     * Adds an sub insert handler slot named {@link RenderVariables.widgetTemplatingZones#inside_input_widget} when
125     * widget is in edit mode.
126     * <p>
127     * Adds an sub document constraint validator handler named {@link DocumentConstraintValidator#VALIDATOR_ID} when
128     * widget is in edit mode.
129     * <p>
130     *
131     * @since 6.0
132     */
133    protected FaceletHandler getNextHandler(FaceletContext ctx, TagConfig tagConfig, Widget widget,
134            FaceletHandler[] subHandlers, FaceletHandlerHelper helper) {
135        boolean isEdit = BuiltinWidgetModes.EDIT.equals(widget.getMode());
136        return getNextHandler(ctx, tagConfig, widget, subHandlers, helper, isEdit, isEdit);
137    }
138
139    /**
140     * Returns sub handlers as computed from tag information.
141     * <p>
142     * Adds an input slot if corresponding boolean parameter is true.
143     *
144     * @since 6.0
145     * @deprecated since 7.2, use
146     *             {@link #getNextHandler(FaceletContext, TagConfig, Widget, FaceletHandler[], FaceletHandlerHelper, boolean, boolean)}
147     *             instead
148     */
149    protected FaceletHandler getNextHandler(FaceletContext ctx, TagConfig tagConfig, Widget widget,
150            FaceletHandler[] subHandlers, FaceletHandlerHelper helper, boolean addInputSlot) {
151        return getNextHandler(ctx, tagConfig, widget, subHandlers, helper, addInputSlot, false);
152    }
153
154    /**
155     * Returns sub handlers as computed from tag information.
156     * <p>
157     * Adds an input slot if corresponding boolean parameter is true.
158     * <p>
159     * Adds an document constraint validator if corresponding boolean parameter is true.
160     *
161     * @since 7.2
162     */
163    protected FaceletHandler getNextHandler(FaceletContext ctx, TagConfig tagConfig, Widget widget,
164            FaceletHandler[] subHandlers, FaceletHandlerHelper helper, boolean addInputSlot,
165            boolean addDocumentConstraintValidator) {
166        FaceletHandler leaf;
167        List<FaceletHandler> handlers = new ArrayList<>();
168        if (subHandlers != null && subHandlers.length > 0) {
169            for (FaceletHandler fh : subHandlers) {
170                if (fh != null && !(fh instanceof LeafFaceletHandler)) {
171                    handlers.add(fh);
172                }
173            }
174        }
175        if (addInputSlot) {
176            FaceletHandler slot = getInputSlotHandler(ctx, tagConfig, widget, subHandlers, helper);
177            if (slot != null) {
178                handlers.add(slot);
179            }
180        }
181        if (addDocumentConstraintValidator) {
182            FaceletHandler v = getDocumentConstraintValidatorHandler(ctx, tagConfig, widget, subHandlers, helper);
183            if (v != null) {
184                handlers.add(v);
185            }
186        }
187        if (handlers.size() == 0) {
188            leaf = new LeafFaceletHandler();
189        } else {
190            leaf = new CompositeFaceletHandler(handlers.toArray(new FaceletHandler[] {}));
191        }
192        return leaf;
193    }
194
195    protected FaceletHandler getInputSlotHandler(FaceletContext ctx, TagConfig tagConfig, Widget widget,
196            FaceletHandler[] subHandlers, FaceletHandlerHelper helper) {
197        TagConfig config = TagConfigFactory.createTagConfig(tagConfig, tagConfig.getTagId(),
198                FaceletHandlerHelper.getTagAttributes(helper.createAttribute("name",
199                        RenderVariables.widgetTemplatingZones.inside_input_widget.name())), new LeafFaceletHandler());
200        return new InsertHandler(config);
201    }
202
203    protected FaceletHandler getDocumentConstraintValidatorHandler(FaceletContext ctx, TagConfig tagConfig,
204            Widget widget, FaceletHandler[] subHandlers, FaceletHandlerHelper helper) {
205        // XXX maybe take into account control on widget to handle sub properties validation (or not)
206        ValidatorHandler validator = helper.getValidateHandler(tagConfig.getTagId(),
207                FaceletHandlerHelper.getTagAttributes(), new LeafFaceletHandler(),
208                DocumentConstraintValidator.VALIDATOR_ID);
209        return validator;
210    }
211
212}