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