001    /**
002     * Copyright (c) 2000-2012 Liferay, Inc. All rights reserved.
003     *
004     * This library is free software; you can redistribute it and/or modify it under
005     * the terms of the GNU Lesser General Public License as published by the Free
006     * Software Foundation; either version 2.1 of the License, or (at your option)
007     * any later version.
008     *
009     * This library is distributed in the hope that it will be useful, but WITHOUT
010     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
011     * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
012     * details.
013     */
014    
015    package com.liferay.portal.model;
016    
017    import com.liferay.portal.kernel.log.Log;
018    import com.liferay.portal.kernel.log.LogFactoryUtil;
019    import com.liferay.portal.kernel.util.GetterUtil;
020    import com.liferay.portal.kernel.util.ListUtil;
021    import com.liferay.portal.kernel.util.PropsKeys;
022    import com.liferay.portal.kernel.util.StringPool;
023    import com.liferay.portal.kernel.util.StringUtil;
024    import com.liferay.portal.kernel.util.Tuple;
025    import com.liferay.portal.kernel.util.Validator;
026    import com.liferay.portal.kernel.xml.Document;
027    import com.liferay.portal.kernel.xml.Element;
028    import com.liferay.portal.kernel.xml.SAXReader;
029    import com.liferay.portal.service.ClassNameLocalServiceUtil;
030    import com.liferay.portal.util.PropsUtil;
031    import com.liferay.util.PwdGenerator;
032    
033    import java.io.InputStream;
034    
035    import java.util.ArrayList;
036    import java.util.Collections;
037    import java.util.HashMap;
038    import java.util.Iterator;
039    import java.util.LinkedHashMap;
040    import java.util.List;
041    import java.util.Map;
042    import java.util.Set;
043    import java.util.TreeMap;
044    import java.util.TreeSet;
045    
046    /**
047     * @author Brian Wing Shun Chan
048     */
049    public class ModelHintsImpl implements ModelHints {
050    
051            public void afterPropertiesSet() {
052                    _hintCollections = new HashMap<String, Map<String, String>>();
053                    _defaultHints = new HashMap<String, Map<String, String>>();
054                    _modelFields = new HashMap<String, Object>();
055                    _models = new TreeSet<String>();
056    
057                    try {
058                            ClassLoader classLoader = getClass().getClassLoader();
059    
060                            String[] configs = StringUtil.split(
061                                    PropsUtil.get(PropsKeys.MODEL_HINTS_CONFIGS));
062    
063                            for (int i = 0; i < configs.length; i++) {
064                                    read(classLoader, configs[i]);
065                            }
066                    }
067                    catch (Exception e) {
068                            _log.error(e, e);
069                    }
070            }
071    
072            public String buildCustomValidatorName(String validatorName) {
073                    return validatorName.concat(StringPool.UNDERLINE).concat(
074                            PwdGenerator.getPassword(PwdGenerator.KEY3, 4));
075            }
076    
077            public Map<String, String> getDefaultHints(String model) {
078                    return _defaultHints.get(model);
079            }
080    
081            public com.liferay.portal.kernel.xml.Element getFieldsEl(
082                    String model, String field) {
083    
084                    Map<String, Object> fields = (Map<String, Object>)_modelFields.get(
085                            model);
086    
087                    if (fields == null) {
088                            return null;
089                    }
090                    else {
091                            Element fieldsEl = (Element)fields.get(field + _ELEMENTS_SUFFIX);
092    
093                            if (fieldsEl == null) {
094                                    return null;
095                            }
096                            else {
097                                    return fieldsEl;
098                            }
099                    }
100            }
101    
102            public Map<String, String> getHints(String model, String field) {
103                    Map<String, Object> fields =
104                            (Map<String, Object>)_modelFields.get(model);
105    
106                    if (fields == null) {
107                            return null;
108                    }
109                    else {
110                            return (Map<String, String>)fields.get(field + _HINTS_SUFFIX);
111                    }
112            }
113    
114            public List<String> getModels() {
115                    return ListUtil.fromCollection(_models);
116            }
117    
118            public Tuple getSanitizeTuple(String model, String field) {
119                    Map<String, Object> fields = (Map<String, Object>)_modelFields.get(
120                            model);
121    
122                    if (fields == null) {
123                            return null;
124                    }
125                    else {
126                            return (Tuple)fields.get(field + _SANITIZE_SUFFIX);
127                    }
128            }
129    
130            public List<Tuple> getSanitizeTuples(String model) {
131                    Map<String, Object> fields = (Map<String, Object>)_modelFields.get(
132                            model);
133    
134                    if (fields == null) {
135                            return Collections.emptyList();
136                    }
137                    else {
138                            List<Tuple> sanitizeTuples = new ArrayList<Tuple>();
139    
140                            for (Map.Entry<String, Object> entry : fields.entrySet()) {
141                                    String key = entry.getKey();
142    
143                                    if (key.endsWith(_SANITIZE_SUFFIX)) {
144                                            Tuple sanitizeTuple = (Tuple)entry.getValue();
145    
146                                            sanitizeTuples.add(sanitizeTuple);
147                                    }
148                            }
149    
150                            return sanitizeTuples;
151                    }
152            }
153    
154            public String getType(String model, String field) {
155                    Map<String, Object> fields = (Map<String, Object>)_modelFields.get(
156                            model);
157    
158                    if (fields == null) {
159                            return null;
160                    }
161                    else {
162                            return (String)fields.get(field + _TYPE_SUFFIX);
163                    }
164            }
165    
166            public List<Tuple> getValidators(String model, String field) {
167                    Map<String, Object> fields = (Map<String, Object>)_modelFields.get(
168                            model);
169    
170                    if ((fields == null) ||
171                            (fields.get(field + _VALIDATORS_SUFFIX) == null)) {
172    
173                            return null;
174                    }
175                    else {
176                            return (List<Tuple>)fields.get(field + _VALIDATORS_SUFFIX);
177                    }
178            }
179    
180            public boolean isCustomValidator(String validatorName) {
181                    if (validatorName.equals("custom")) {
182                            return true;
183                    }
184    
185                    return false;
186            }
187    
188            public boolean isLocalized(String model, String field) {
189                    Map<String, Object> fields = (Map<String, Object>)_modelFields.get(
190                            model);
191    
192                    if (fields == null) {
193                            return false;
194                    }
195                    else {
196                            Boolean localized = (Boolean)fields.get(
197                                    field + _LOCALIZATION_SUFFIX);
198    
199                            if (localized != null) {
200                                    return localized;
201                            }
202                            else {
203                                    return false;
204                            }
205                    }
206            }
207    
208            public void read(ClassLoader classLoader, String source) throws Exception {
209                    InputStream is = classLoader.getResourceAsStream(source);
210    
211                    if (is == null) {
212                            if (_log.isWarnEnabled()) {
213                                    _log.warn("Cannot load " + source);
214                            }
215                            return;
216                    }
217                    else {
218                            if (_log.isDebugEnabled()) {
219                                    _log.debug("Loading " + source);
220                            }
221                    }
222    
223                    Document doc = _saxReader.read(is);
224    
225                    Element root = doc.getRootElement();
226    
227                    Iterator<Element> itr1 = root.elements("hint-collection").iterator();
228    
229                    while (itr1.hasNext()) {
230                            Element hintCollection = itr1.next();
231    
232                            String name = hintCollection.attributeValue("name");
233    
234                            Map<String, String> hints = _hintCollections.get(name);
235    
236                            if (hints == null) {
237                                    hints = new HashMap<String, String>();
238    
239                                    _hintCollections.put(name, hints);
240                            }
241    
242                            Iterator<Element> itr2 = hintCollection.elements("hint").iterator();
243    
244                            while (itr2.hasNext()) {
245                                    Element hint = itr2.next();
246    
247                                    String hintName = hint.attributeValue("name");
248                                    String hintValue = hint.getText();
249    
250                                    hints.put(hintName, hintValue);
251                            }
252                    }
253    
254                    itr1 = root.elements("model").iterator();
255    
256                    while (itr1.hasNext()) {
257                            Element model = itr1.next();
258    
259                            String name = model.attributeValue("name");
260    
261                            if (classLoader != ModelHintsImpl.class.getClassLoader()) {
262                                    ClassNameLocalServiceUtil.getClassName(name);
263                            }
264    
265                            Map<String, String> defaultHints = new HashMap<String, String>();
266    
267                            _defaultHints.put(name, defaultHints);
268    
269                            Element defaultHintsEl = model.element("default-hints");
270    
271                            if (defaultHintsEl != null) {
272                                    Iterator<Element> itr2 = defaultHintsEl.elements(
273                                            "hint").iterator();
274    
275                                    while (itr2.hasNext()) {
276                                            Element hint = itr2.next();
277    
278                                            String hintName = hint.attributeValue("name");
279                                            String hintValue = hint.getText();
280    
281                                            defaultHints.put(hintName, hintValue);
282                                    }
283                            }
284    
285                            Map<String, Object> fields = (Map<String, Object>)_modelFields.get(
286                                    name);
287    
288                            if (fields == null) {
289                                    fields = new LinkedHashMap<String, Object>();
290    
291                                    _modelFields.put(name, fields);
292                            }
293    
294                            _models.add(name);
295    
296                            Iterator<Element> itr2 = model.elements("field").iterator();
297    
298                            while (itr2.hasNext()) {
299                                    Element field = itr2.next();
300    
301                                    String fieldName = field.attributeValue("name");
302                                    String fieldType = field.attributeValue("type");
303                                    boolean fieldLocalized = GetterUtil.getBoolean(
304                                            field.attributeValue("localized"));
305    
306                                    Map<String, String> fieldHints = new HashMap<String, String>();
307    
308                                    fieldHints.putAll(defaultHints);
309    
310                                    Iterator<Element> itr3 = field.elements(
311                                            "hint-collection").iterator();
312    
313                                    while (itr3.hasNext()) {
314                                            Element hintCollection = itr3.next();
315    
316                                            Map<String, String> hints = _hintCollections.get(
317                                                    hintCollection.attributeValue("name"));
318    
319                                            fieldHints.putAll(hints);
320                                    }
321    
322                                    itr3 = field.elements("hint").iterator();
323    
324                                    while (itr3.hasNext()) {
325                                            Element hint = itr3.next();
326    
327                                            String hintName = hint.attributeValue("name");
328                                            String hintValue = hint.getText();
329    
330                                            fieldHints.put(hintName, hintValue);
331                                    }
332    
333                                    Tuple fieldSanitize = null;
334    
335                                    Element sanitize = field.element("sanitize");
336    
337                                    if (sanitize != null) {
338                                            String contentType = sanitize.attributeValue(
339                                                    "content-type");
340                                            String modes = sanitize.attributeValue("modes");
341    
342                                            fieldSanitize = new Tuple(fieldName, contentType, modes);
343                                    }
344    
345                                    Map<String, Tuple> fieldValidators =
346                                            new TreeMap<String, Tuple>();
347    
348                                    itr3 = field.elements("validator").iterator();
349    
350                                    while (itr3.hasNext()) {
351                                            Element validator = itr3.next();
352    
353                                            String validatorName = validator.attributeValue("name");
354    
355                                            if (Validator.isNull(validatorName)) {
356                                                    continue;
357                                            }
358    
359                                            String validatorErrorMessage = GetterUtil.getString(
360                                                    validator.attributeValue("error-message"));
361                                            String validatorValue = GetterUtil.getString(
362                                                    validator.getText());
363                                            boolean customValidator = isCustomValidator(validatorName);
364    
365                                            if (customValidator) {
366                                                    validatorName = buildCustomValidatorName(validatorName);
367                                            }
368    
369                                            Tuple fieldValidator = new Tuple(
370                                                    fieldName, validatorName, validatorErrorMessage,
371                                                    validatorValue, customValidator);
372    
373                                            fieldValidators.put(validatorName, fieldValidator);
374                                    }
375    
376                                    fields.put(fieldName + _ELEMENTS_SUFFIX, field);
377                                    fields.put(fieldName + _TYPE_SUFFIX, fieldType);
378                                    fields.put(fieldName + _LOCALIZATION_SUFFIX, fieldLocalized);
379                                    fields.put(fieldName + _HINTS_SUFFIX, fieldHints);
380    
381                                    if (fieldSanitize != null) {
382                                            fields.put(fieldName + _SANITIZE_SUFFIX, fieldSanitize);
383                                    }
384    
385                                    if (!fieldValidators.isEmpty()) {
386                                            fields.put(
387                                                    fieldName + _VALIDATORS_SUFFIX,
388                                                    ListUtil.fromMapValues(fieldValidators));
389                                    }
390                            }
391                    }
392            }
393    
394            public void setSAXReader(SAXReader saxReader) {
395                    _saxReader = saxReader;
396            }
397    
398            public String trimString(String model, String field, String value) {
399                    if (value == null) {
400                            return value;
401                    }
402    
403                    Map<String, String> hints = getHints(model, field);
404    
405                    if (hints == null) {
406                            return value;
407                    }
408    
409                    int maxLength = GetterUtil.getInteger(
410                            ModelHintsConstants.TEXT_MAX_LENGTH);
411    
412                    maxLength = GetterUtil.getInteger(hints.get("max-length"), maxLength);
413    
414                    if (value.length() > maxLength) {
415                            return value.substring(0, maxLength);
416                    }
417                    else {
418                            return value;
419                    }
420            }
421    
422            private static final String _ELEMENTS_SUFFIX = "_ELEMENTS";
423    
424            private static final String _HINTS_SUFFIX = "_HINTS";
425    
426            private static final String _LOCALIZATION_SUFFIX = "_LOCALIZATION";
427    
428            private static final String _SANITIZE_SUFFIX = "_SANITIZE_SUFFIX";
429    
430            private static final String _TYPE_SUFFIX = "_TYPE";
431    
432            private static final String _VALIDATORS_SUFFIX = "_VALIDATORS";
433    
434            private static Log _log = LogFactoryUtil.getLog(ModelHintsImpl.class);
435    
436            private Map<String, Map<String, String>> _defaultHints;
437            private Map<String, Map<String, String>> _hintCollections;
438            private Map<String, Object> _modelFields;
439            private Set<String> _models;
440            private SAXReader _saxReader;
441    
442    }