001/*
002 * (C) Copyright 2010 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 *     Anahide Tchertchian
018 */
019package org.nuxeo.ecm.platform.forms.layout.demo.jsf;
020
021import java.io.Serializable;
022import java.util.ArrayList;
023import java.util.HashMap;
024import java.util.List;
025import java.util.Map;
026
027import javax.faces.application.FacesMessage;
028import javax.faces.component.UIComponent;
029import javax.faces.context.FacesContext;
030import javax.faces.validator.ValidatorException;
031
032import org.apache.commons.lang.StringUtils;
033import org.nuxeo.ecm.platform.forms.layout.api.FieldDefinition;
034import org.nuxeo.ecm.platform.forms.layout.api.WidgetDefinition;
035import org.nuxeo.ecm.platform.forms.layout.api.impl.FieldDefinitionImpl;
036
037/**
038 * Collects information to generate a layout definition from user information.
039 *
040 * @author Anahide Tchertchian
041 * @since 5.4
042 */
043public class PreviewLayoutDefinition implements Serializable {
044
045    private static final long serialVersionUID = 1L;
046
047    protected final String widgetType;
048
049    protected final List<String> fields;
050
051    protected String label;
052
053    protected String helpLabel;
054
055    protected Boolean translated;
056
057    protected Boolean handlingLabels;
058
059    protected Map<String, Serializable> defaultProperties;
060
061    protected Map<String, Serializable> properties;
062
063    protected List<Map<String, Serializable>> customProperties;
064
065    protected List<WidgetDefinition> subWidgets;
066
067    public PreviewLayoutDefinition(String widgetType, List<String> fields, Map<String, Serializable> defaultProperties) {
068        super();
069        this.widgetType = widgetType;
070        this.fields = fields;
071        this.defaultProperties = defaultProperties;
072    }
073
074    public String getWidgetType() {
075        return widgetType;
076    }
077
078    public List<String> getFields() {
079        return fields;
080    }
081
082    public List<FieldDefinition> getFieldDefinitions() {
083        if (fields != null) {
084            List<FieldDefinition> res = new ArrayList<FieldDefinition>();
085            for (String field : fields) {
086                res.add(new FieldDefinitionImpl(null, field));
087            }
088            return res;
089        }
090        return null;
091    }
092
093    public String getLabel() {
094        return label;
095    }
096
097    public void setLabel(String label) {
098        this.label = label;
099    }
100
101    public String getHelpLabel() {
102        return helpLabel;
103    }
104
105    public void setHelpLabel(String helpLabel) {
106        this.helpLabel = helpLabel;
107    }
108
109    public Boolean getTranslated() {
110        return translated;
111    }
112
113    public void setTranslated(Boolean translated) {
114        this.translated = translated;
115    }
116
117    public Boolean getHandlingLabels() {
118        return handlingLabels;
119    }
120
121    public void setHandlingLabels(Boolean handlingLabels) {
122        this.handlingLabels = handlingLabels;
123    }
124
125    public List<WidgetDefinition> getSubWidgets() {
126        return subWidgets;
127    }
128
129    public void setSubWidgets(List<WidgetDefinition> subWidgets) {
130        this.subWidgets = subWidgets;
131    }
132
133    public Map<String, Serializable> getProperties() {
134        if (properties == null) {
135            properties = new HashMap<String, Serializable>();
136            // fill with default properties
137            if (defaultProperties != null) {
138                properties.putAll(defaultProperties);
139            }
140        }
141        return properties;
142    }
143
144    public void setProperties(Map<String, Serializable> properties) {
145        this.properties = properties;
146    }
147
148    public List<Map<String, Serializable>> getCustomProperties() {
149        if (customProperties == null) {
150            customProperties = new ArrayList<Map<String, Serializable>>();
151        }
152        return customProperties;
153    }
154
155    public void setCustomProperties(List<Map<String, Serializable>> customProperties) {
156        this.customProperties = customProperties;
157    }
158
159    public Map<String, Serializable> getWidgetProperties() {
160        Map<String, Serializable> widgetProps = new HashMap<String, Serializable>();
161        Map<String, Serializable> props = getProperties();
162        if (props != null) {
163            widgetProps.putAll(props);
164        }
165        List<Map<String, Serializable>> customProps = getCustomProperties();
166        if (customProps != null) {
167            widgetProps.putAll(convertCustomProperties(customProps, true));
168        }
169        return cleanUpProperties(widgetProps);
170    }
171
172    /**
173     * Removes empty properties as the JSF component may not accept empty values for some properties like "converter" or
174     * "validator".
175     */
176    protected Map<String, Serializable> cleanUpProperties(Map<String, Serializable> props) {
177        Map<String, Serializable> res = new HashMap<String, Serializable>();
178        if (props != null) {
179            for (Map.Entry<String, Serializable> prop : props.entrySet()) {
180                Serializable value = prop.getValue();
181                if (value == null || (value instanceof String && StringUtils.isEmpty((String) value))) {
182                    continue;
183                }
184                res.put(prop.getKey(), value);
185            }
186        }
187        return res;
188    }
189
190    public Map<String, Serializable> getNewCustomProperty() {
191        Map<String, Serializable> prop = new HashMap<String, Serializable>();
192        prop.put("key", null);
193        prop.put("value", null);
194        return prop;
195    }
196
197    protected Map<String, Serializable> convertCustomProperties(List<Map<String, Serializable>> listProps,
198            boolean ignoreErrors) throws ValidatorException {
199        Map<String, Serializable> values = new HashMap<String, Serializable>();
200        if (listProps != null) {
201            for (Map<String, Serializable> entry : listProps) {
202                String key = (String) entry.get("key");
203                Serializable value = entry.get("value");
204                if (key == null || key.trim().length() == 0) {
205                    if (ignoreErrors) {
206                        continue;
207                    }
208                    FacesMessage message = new FacesMessage(FacesMessage.SEVERITY_ERROR, "Invalid empty key", null);
209                    throw new ValidatorException(message);
210                }
211                if (values.containsKey(key)) {
212                    if (ignoreErrors) {
213                        continue;
214                    }
215                    FacesMessage message = new FacesMessage(FacesMessage.SEVERITY_ERROR, String.format(
216                            "Duplicate key '%s'", key), null);
217                    throw new ValidatorException(message);
218                }
219                values.put(key, value);
220            }
221        }
222        return values;
223    }
224
225    @SuppressWarnings({ "unchecked", "rawtypes" })
226    public void validateCustomProperties(FacesContext context, UIComponent component, Object value) {
227        if (value != null && !(value instanceof List)) {
228            FacesMessage message = new FacesMessage(FacesMessage.SEVERITY_ERROR, "Invalid value: " + value, null);
229            // also add global message
230            context.addMessage(null, message);
231            throw new ValidatorException(message);
232        }
233        List<Map<String, Serializable>> listValue = (List) value;
234        // will throw an error
235        convertCustomProperties(listValue, false);
236    }
237
238}