View Javadoc
1   /*
2    * Copyright (C) 2003-2008 eXo Platform SAS.
3    *
4    * This program is free software; you can redistribute it and/or
5    * modify it under the terms of the GNU Affero General Public License
6    * as published by the Free Software Foundation; either version 3
7    * of the License, or (at your option) any later version.
8    *
9    * This program is distributed in the hope that it will be useful,
10   * but WITHOUT ANY WARRANTY; without even the implied warranty of
11   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12   * GNU General Public License for more details.
13   *
14   * You should have received a copy of the GNU General Public License
15   * along with this program; if not, see<http://www.gnu.org/licenses/>.
16   */
17  package org.exoplatform.ecm.webui.utils;
18  
19  import java.io.InputStream;
20  import java.net.URLDecoder;
21  import java.util.ArrayList;
22  import java.util.HashMap;
23  import java.util.HashSet;
24  import java.util.Iterator;
25  import java.util.List;
26  import java.util.Map;
27  import java.util.Set;
28  import java.util.TreeMap;
29  
30  import javax.jcr.Node;
31  import javax.jcr.PathNotFoundException;
32  import javax.jcr.Property;
33  import javax.jcr.PropertyType;
34  
35  import org.apache.commons.lang.StringEscapeUtils;
36  
37  import org.exoplatform.commons.utils.HTMLSanitizer;
38  import org.exoplatform.commons.utils.IOUtil;
39  import org.exoplatform.ecm.utils.text.Text;
40  import org.exoplatform.ecm.webui.form.UIDialogForm;
41  import org.exoplatform.ecm.webui.form.UIFormUploadInputNoUploadButton;
42  import org.exoplatform.ecm.webui.form.validator.CategoryValidator;
43  import org.exoplatform.ecm.webui.form.validator.CronExpressionValidator;
44  import org.exoplatform.ecm.webui.form.validator.DateValidator;
45  import org.exoplatform.ecm.webui.form.validator.ECMNameValidator;
46  import org.exoplatform.ecm.webui.form.validator.PhoneFormatValidator;
47  import org.exoplatform.ecm.webui.form.validator.RepeatCountValidator;
48  import org.exoplatform.ecm.webui.form.validator.RepeatIntervalValidator;
49  import org.exoplatform.ecm.webui.form.validator.XSSValidator;
50  import org.exoplatform.services.cms.JcrInputProperty;
51  import org.exoplatform.upload.UploadResource;
52  import org.exoplatform.wcm.webui.Utils;
53  import org.exoplatform.webui.core.UIComponent;
54  import org.exoplatform.webui.form.UIFormDateTimeInput;
55  import org.exoplatform.webui.form.UIFormInputBase;
56  import org.exoplatform.webui.form.UIFormMultiValueInputSet;
57  import org.exoplatform.webui.form.UIFormSelectBox;
58  import org.exoplatform.webui.form.input.UICheckBoxInput;
59  import org.exoplatform.webui.form.input.UIUploadInput;
60  import org.exoplatform.webui.form.validator.DateTimeValidator;
61  import org.exoplatform.webui.form.validator.DoubleFormatValidator;
62  import org.exoplatform.webui.form.validator.EmailAddressValidator;
63  import org.exoplatform.webui.form.validator.MandatoryValidator;
64  import org.exoplatform.webui.form.validator.NullFieldValidator;
65  import org.exoplatform.webui.form.validator.NumberFormatValidator;
66  import org.exoplatform.webui.form.validator.StringLengthValidator;
67  
68  /*
69   * Created by The eXo Platform SAS
70   * @author : Hoa.Pham
71   *          hoa.pham@exoplatform.com
72   * Jun 23, 2008
73   */
74  /**
75   * The Class DialogFormUtil.
76   */
77  public class DialogFormUtil {
78  
79    public static String VALIDATOR_PARAM_BEGIN     = "(";
80  
81    public static String VALIDATOR_PARAM_END       = ")";
82  
83    public static String VALIDATOR_PARAM_SEPERATOR = ";";
84  
85    public static String SANITIZATION_FLAG         = "noSanitization";
86  
87    /**
88     * Type of parameters which were passed for the validator TODO: Please add all
89     * the possible type here and parser it in side the function
90     * parserValidatorParam. If any question, ask for VinhNT from Content's team.
91     */
92    public static String TYPE_FLOAT                = "Float";
93  
94    public static String TYPE_DOUBLE               = "Double";
95  
96    public static String TYPE_INTEGER              = "Int";
97  
98    public static String TYPE_STRING               = "String";
99  
100   /**
101    * Prepare map.
102    *
103    * @param inputs the inputs
104    * @param properties the properties
105    * @return the map of string and jcr input property
106    * @throws Exception the exception
107    */
108   public static Map<String, JcrInputProperty> prepareMap(List inputs, Map properties) throws Exception {
109     return prepareMap(inputs, properties, null);
110   }
111 
112   @SuppressWarnings("unchecked")
113   public static Map<String, JcrInputProperty> prepareMap(List inputs, Map properties, Map options) throws Exception {
114     Map<String, String> changeInJcrPathParamMap = new HashMap<String, String>();
115     Map<String, JcrInputProperty> rawinputs = new HashMap<String, JcrInputProperty>();
116     HashMap<String, JcrInputProperty> hasMap = new HashMap<String, JcrInputProperty>();
117     String inputName = null;
118     String mimeTypeJcrPath = null;
119     InputStream inputStream = null;
120     Map<String, JcrInputProperty> mimeTypes = new HashMap<String, JcrInputProperty>();
121     for (int i = 0; i < inputs.size(); i++) {
122       JcrInputProperty property = null;
123       String option = null;
124       if (inputs.get(i) instanceof UIFormMultiValueInputSet) {
125         UIFormMultiValueInputSet inputI = (UIFormMultiValueInputSet) inputs.get(i);
126         inputName = (inputI).getName();
127         if (!hasMap.containsKey(inputName)) {
128           List<UIComponent> inputChild = inputI.getChildren();
129           property = (JcrInputProperty) properties.get(inputName);
130           if (inputChild != null && inputChild.size() > 0 && inputChild.get(0) instanceof UIUploadInput) {
131             Map<String, List> uploadDataMap = new TreeMap<String, List>();
132             for (UIComponent child : inputChild) {
133               UIUploadInput uploadInput = (UIUploadInput) child;
134               String uploadId = uploadInput.getUploadIds()[0];
135               String uploadDataName = null;
136               String uploadMimeType = null;
137               byte[] uploadData = null;
138               if (uploadInput instanceof UIFormUploadInputNoUploadButton) {
139                 uploadDataName = ((UIFormUploadInputNoUploadButton) uploadInput).getFileName();
140                 uploadMimeType = ((UIFormUploadInputNoUploadButton) uploadInput).getMimeType();
141                 uploadData = ((UIFormUploadInputNoUploadButton) uploadInput).getByteValue();
142               } else {
143                 UploadResource uploadResource = (uploadInput).getUploadResource(uploadId);
144                 if (uploadResource != null) {
145                   String location = uploadResource.getStoreLocation();
146                   uploadDataName = uploadResource.getFileName();
147                   uploadData = IOUtil.getFileContentAsBytes(location);
148                   uploadMimeType = uploadResource.getMimeType();
149                 }
150               }
151               if (uploadDataName != null && uploadData != null) {
152                 List<Object> data = new ArrayList<Object>();
153                 data.add(uploadMimeType);
154                 data.add(uploadData);
155                 if (!uploadDataMap.containsKey(uploadDataName)) {
156                   uploadDataMap.put(uploadDataName, data);
157                 } else {
158                   int count = 1;
159                   while (uploadDataMap.containsKey(uploadDataName + count)) {
160                     count++;
161                   }
162                   uploadDataMap.put(uploadDataName + count, data);
163                 }
164               }
165             }
166             property.setValue(uploadDataMap);
167           } else {
168             List<String> values = (List<String>) (inputI).getValue();
169             if (property != null) {
170               property.setValue(values.toArray(new String[values.size()]));
171             }
172           }
173         }
174         hasMap.put(inputName, property);
175       } else {
176         UIFormInputBase input = (UIFormInputBase) inputs.get(i);
177         property = (JcrInputProperty) properties.get(input.getName());
178         if (options != null && options.get(input.getName()) != null)
179           option = (String) options.get(input.getName());
180         if (property != null) {
181           if (input instanceof UIUploadInput) {
182             String uploadId = ((UIUploadInput) input).getUploadIds()[0];
183             UploadResource uploadResource = ((UIUploadInput) input).getUploadResource(uploadId);
184             if (uploadResource == null) {
185               if (property.getChangeInJcrPathParam() != null)
186                 changeInJcrPathParamMap.put(property.getChangeInJcrPathParam(), "");
187               continue;
188             }
189             String location = uploadResource.getStoreLocation();
190             byte[] uploadData = IOUtil.getFileContentAsBytes(location);
191             property.setValue(uploadData);
192             // change param in jcr path
193             if (property.getChangeInJcrPathParam() != null)
194               changeInJcrPathParamMap.put(property.getChangeInJcrPathParam(),
195                                           Text.escapeIllegalJcrChars(uploadResource.getFileName()));
196 
197             mimeTypeJcrPath = property.getJcrPath().replace("jcr:data", "jcr:mimeType");
198             JcrInputProperty mimeTypeInputPropertyTmp = new JcrInputProperty();
199             mimeTypeInputPropertyTmp.setJcrPath(mimeTypeJcrPath);
200             mimeTypeInputPropertyTmp.setValue(((UIUploadInput) input).getUploadResource(uploadId).getMimeType());
201             mimeTypes.put(mimeTypeJcrPath, mimeTypeInputPropertyTmp);
202           } else if (input instanceof UIFormDateTimeInput) {
203             property.setValue(((UIFormDateTimeInput) input).getCalendar());
204           } else if (input instanceof UIFormSelectBox) {
205             UIFormSelectBox uiSelectBox = (UIFormSelectBox) input;
206             if (!uiSelectBox.isMultiple()) {
207               property.setValue(uiSelectBox.getValue());
208             } else {
209               property.setValue(uiSelectBox.getSelectedValues());
210             }
211           } else if (input instanceof UICheckBoxInput) {
212             property.setValue(((UICheckBoxInput) input).isChecked());
213           } else {
214             if (input.getValue() != null) {
215               String inputValue = input.getValue().toString().trim();
216               boolean isEmpty = Utils.isEmptyContent(inputValue);
217               if (isEmpty)
218                 inputValue = "";
219               else if (option == null || option.indexOf(SANITIZATION_FLAG) < 0) {
220                 inputValue = HTMLSanitizer.sanitize(inputValue);
221                 inputValue = StringEscapeUtils.unescapeHtml(inputValue);
222               }
223               if (input.getName().equals("name") && input.getAncestorOfType(UIDialogForm.class).isAddNew()) {
224                 JcrInputProperty titleInputProperty = (JcrInputProperty) properties.get("title");
225                 if(titleInputProperty == null) {
226                   JcrInputProperty jcrExoTitle = new JcrInputProperty();
227                   jcrExoTitle.setJcrPath("/node/exo:title");
228                   jcrExoTitle.setValue(inputValue);
229                   properties.put("/node/exo:title", jcrExoTitle);
230                 } else if(titleInputProperty.getValue() == null){
231                     JcrInputProperty jcrExoTitle = new JcrInputProperty();
232                     jcrExoTitle.setJcrPath(titleInputProperty.getJcrPath());
233                     jcrExoTitle.setValue(inputValue);
234                     properties.put("title", jcrExoTitle);
235                 }
236                 property.setValue(Text.escapeIllegalJcrChars(inputValue));
237               } else {
238                 property.setValue(inputValue);
239               }
240             } else {
241               // The is already setted in the previous block, thus it needs to be skipped here.
242               if (input.getName() == "title")
243                 continue;
244               property.setValue(input.getValue());
245             }
246           }
247         }
248       }
249     }
250     Iterator iter = properties.values().iterator();
251     JcrInputProperty property;
252     while (iter.hasNext()) {
253       property = (JcrInputProperty) iter.next();
254       rawinputs.put(property.getJcrPath(), property);
255     }
256     for (String jcrPath : mimeTypes.keySet()) {
257       if (!rawinputs.containsKey(jcrPath)) {
258         rawinputs.put(jcrPath, mimeTypes.get(jcrPath));
259       }
260     }
261     List<UIUploadInput> formUploadList = new ArrayList<UIUploadInput>();
262     for (Object input : inputs) {
263       if (input instanceof UIFormMultiValueInputSet) {
264         UIFormMultiValueInputSet uiSet = (UIFormMultiValueInputSet) input;
265         if (uiSet.getId() != null && uiSet.getUIFormInputBase().equals(UIUploadInput.class)
266             && uiSet.getId().equals("attachment__")) {
267           List<UIComponent> list = uiSet.getChildren();
268           for (UIComponent component : list) {
269             if (!formUploadList.contains(component))
270               formUploadList.add((UIUploadInput) component);
271           }
272         }
273       } else if (input instanceof UIUploadInput) {
274         if (!formUploadList.contains(input))
275           formUploadList.add((UIUploadInput) input);
276       }
277     }
278     if (formUploadList.size() > 0) {
279       List<String> keyListToRemove = new ArrayList<String>();
280       Map<String, JcrInputProperty> jcrPropertiesToAdd = new HashMap<String, JcrInputProperty>();
281       for (Object inputJCRKeyTmp : rawinputs.keySet()) {
282         String inputJCRKey = (String) inputJCRKeyTmp;
283         if (inputJCRKey.contains("attachment__")) {
284           JcrInputProperty jcrInputProperty = rawinputs.get(inputJCRKey);
285           for (UIUploadInput uploadInput : formUploadList) {
286             String uploadId = uploadInput.getUploadIds()[0];
287             JcrInputProperty newJcrInputProperty = clone(jcrInputProperty);
288             if (uploadInput == null || uploadInput.getUploadResource(uploadId) == null
289                 || uploadInput.getUploadResource(uploadId).getFileName() == null)
290               continue;
291             String fileName = uploadInput.getUploadResource(uploadId).getFileName();
292             String newJCRPath = inputJCRKey.replace("attachment__", fileName);
293             newJcrInputProperty.setJcrPath(newJCRPath);
294             if (inputJCRKey.endsWith("attachment__")) {
295               newJcrInputProperty.setValue(fileName);
296               JcrInputProperty mimeTypeInputPropertyTmp = new JcrInputProperty();
297               mimeTypeInputPropertyTmp.setJcrPath(newJCRPath + "/jcr:content/jcr:mimeType");
298               mimeTypeInputPropertyTmp.setValue(uploadInput.getUploadResource(uploadId).getMimeType());
299               jcrPropertiesToAdd.put(mimeTypeInputPropertyTmp.getJcrPath(), mimeTypeInputPropertyTmp);
300             }
301             if (inputJCRKey.endsWith("jcr:data")) {
302               inputStream = uploadInput.getUploadDataAsStream(uploadId);
303               newJcrInputProperty.setValue(inputStream);
304             }
305             jcrPropertiesToAdd.put(newJCRPath, newJcrInputProperty);
306           }
307           keyListToRemove.add(inputJCRKey);
308           keyListToRemove.add(inputJCRKey.replace("jcr:data", "jcr:mimeType"));
309         }
310       }
311       for (String keyToRemove : keyListToRemove) {
312         rawinputs.remove(keyToRemove);
313       }
314       rawinputs.putAll(jcrPropertiesToAdd);
315     }
316 
317     if (changeInJcrPathParamMap.isEmpty()) {
318       return rawinputs;
319     }
320 
321     Map<String, JcrInputProperty> ret = new HashMap<String, JcrInputProperty>();
322     Set<String> removedKeys = new HashSet<String>();
323     for (Map.Entry<String, String> changeEntry : changeInJcrPathParamMap.entrySet()) {
324       for (Map.Entry<String, JcrInputProperty> entry : rawinputs.entrySet()) {
325         if (entry.getKey().contains(changeEntry.getKey())) {
326           removedKeys.add(entry.getKey());
327           JcrInputProperty value = entry.getValue();
328           if (value.getJcrPath() != null) {
329             value.setJcrPath(value.getJcrPath().replace(changeEntry.getKey(), changeEntry.getValue()));
330           }
331           if (value.getValue() != null && value.getValue() instanceof String) {
332             value.setValue(((String) value.getValue()).replace(changeEntry.getKey(), changeEntry.getValue()));
333           }
334           if (value != null && !"".equals(value) && changeEntry.getValue() != null && !"".equals(changeEntry.getValue())) {
335             ret.put(entry.getKey().replace(changeEntry.getKey(), changeEntry.getValue()), value);
336           }
337         }
338       }
339     }
340     for (Map.Entry<String, JcrInputProperty> entry : rawinputs.entrySet()) {
341       if (!removedKeys.contains(entry.getKey())) {
342         ret.put(entry.getKey(), entry.getValue());
343       }
344     }
345 
346     return ret;
347   }
348 
349   private static JcrInputProperty clone(JcrInputProperty fileNodeInputProperty) {
350     JcrInputProperty jcrInputProperty = new JcrInputProperty();
351     jcrInputProperty.setJcrPath(fileNodeInputProperty.getJcrPath());
352     jcrInputProperty.setMixintype(fileNodeInputProperty.getMixintype());
353     jcrInputProperty.setNodetype(fileNodeInputProperty.getNodetype());
354     jcrInputProperty.setType(fileNodeInputProperty.getType());
355     jcrInputProperty.setValue(fileNodeInputProperty.getValue());
356     jcrInputProperty.setValueType(fileNodeInputProperty.getValueType());
357     return jcrInputProperty;
358   }
359 
360   /**
361    * Creates the form input.
362    *
363    * @param type the type
364    * @param name the name
365    * @param label the label
366    * @param validateType the validate type
367    * @param valueType the value type
368    * @return the t
369    * @throws Exception the exception
370    */
371   public static <T extends UIFormInputBase> T createFormInput(Class<T> type,
372                                                               String name,
373                                                               String label,
374                                                               String validateType,
375                                                               Class valueType) throws Exception {
376     Object[] args = { name, null, valueType };
377     UIFormInputBase formInput = type.getConstructor().newInstance(args);
378     addValidators(formInput, validateType);
379     if (label != null && label.length() != 0) {
380       formInput.setLabel(label);
381     }
382     return type.cast(formInput);
383   }
384 
385   /**
386    * Gets the property value as string.
387    *
388    * @param node the node
389    * @param propertyName the property name
390    * @return the property value as string
391    * @throws Exception the exception
392    */
393   public static String getPropertyValueAsString(Node node, String propertyName) throws Exception {
394     Property property = null;
395     try {
396       property = node.getProperty(propertyName);
397     } catch (PathNotFoundException e) {
398       return "";
399     }
400     int valueType = property.getType();
401     switch (valueType) {
402     case PropertyType.STRING: // String
403       return property.getString();
404     case PropertyType.LONG: // Long
405       return Long.toString(property.getLong());
406     case PropertyType.DOUBLE: // Double
407       return Double.toString(property.getDouble());
408     case PropertyType.DATE: // Date
409       return property.getDate().getTime().toString();
410     case PropertyType.BOOLEAN: // Boolean
411       return Boolean.toString(property.getBoolean());
412     case PropertyType.NAME: // Name
413       return property.getName();
414     case 8: // Path
415     case 9: // References
416     case 0: // Undifine
417     }
418     return "";
419   }
420 
421   public static Class getValidator(String validatorType) throws ClassNotFoundException {
422     if (validatorType.equals("name")) {
423       return ECMNameValidator.class;
424     } else if (validatorType.equals("email")) {
425       return EmailAddressValidator.class;
426     } else if (validatorType.equals("number")) {
427       return NumberFormatValidator.class;
428     } else if (validatorType.equals("double")) {
429       return DoubleFormatValidator.class;
430     } else if (validatorType.equals("empty")) {
431       return MandatoryValidator.class;
432     } else if (validatorType.equals("null")) {
433       return NullFieldValidator.class;
434     } else if (validatorType.equals("datetime")) {
435       return DateTimeValidator.class;
436     } else if (validatorType.equals("date")) {
437       return DateValidator.class;
438     } else if (validatorType.equals("cronExpressionValidator")) {
439       return CronExpressionValidator.class;
440     } else if (validatorType.equals("repeatCountValidator")) {
441       return RepeatCountValidator.class;
442     } else if (validatorType.equals("repeatIntervalValidator")) {
443       return RepeatIntervalValidator.class;
444     } else if (validatorType.equals("length")) {
445       return StringLengthValidator.class;
446     } else if (validatorType.equals("category")) {
447       return CategoryValidator.class;
448     } else if (validatorType.equals("XSSValidator")) {
449       return XSSValidator.class;
450     } else if (validatorType.equals("phone")) {
451       return PhoneFormatValidator.class;
452     } else {
453       ClassLoader cl = Thread.currentThread().getContextClassLoader();
454       return cl.loadClass(validatorType);
455     }
456   }
457 
458   @SuppressWarnings("unchecked")
459   public static void addValidators(UIFormInputBase uiInput, String validators) throws Exception {
460     String[] validatorList = null;
461     if (validators.indexOf(',') > -1)
462       validatorList = validators.split(",");
463     else
464       validatorList = new String[] { validators };
465     for (String validator : validatorList) {
466       Object[] params;
467       String s_param = null;
468       int p_begin, p_end;
469       p_begin = validator.indexOf(VALIDATOR_PARAM_BEGIN);
470       p_end = validator.indexOf(VALIDATOR_PARAM_END);
471       if (p_begin > 0 && p_end > p_begin) {
472         String v_name;
473         s_param = validator.substring(p_begin + 1, p_end);
474         params = s_param.split(VALIDATOR_PARAM_SEPERATOR);
475         params = parserValidatorParam(params, params.length - 1, params[params.length - 1].toString());
476         v_name = validator.substring(0, p_begin);
477         uiInput.addValidator(getValidator(v_name.trim()), params);
478       } else {
479         uiInput.addValidator(getValidator(validator.trim()));
480       }
481     }
482   }
483 
484   /**
485    * @param params
486    * @param length
487    * @param type
488    * @return the conversion of the input parameters with the new type.
489    * @throws Exception
490    */
491   public static Object[] parserValidatorParam(Object[] params, int length, String type) throws Exception {
492     int i;
493     Object[] newParams;
494     if (length < 1)
495       return params;
496     newParams = new Object[length];
497     if (type.equalsIgnoreCase(TYPE_INTEGER)) {
498       for (i = 0; i < length; i++)
499         newParams[i] = Integer.parseInt(params[i].toString());
500     } else if (type.equalsIgnoreCase(TYPE_FLOAT)) {
501       for (i = 0; i < length; i++)
502         newParams[i] = Float.parseFloat(params[i].toString());
503     } else if (type.equalsIgnoreCase(TYPE_DOUBLE)) {
504       for (i = 0; i < length; i++)
505         newParams[i] = Double.parseDouble(params[i].toString());
506     } else
507       return params;// Do not convert, let those parameters are the Objec type
508     return newParams;
509   }
510 }