001    /**
002     * Copyright (c) 2000-2010 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.StringUtil;
023    import com.liferay.portal.kernel.util.Tuple;
024    import com.liferay.portal.kernel.xml.Document;
025    import com.liferay.portal.kernel.xml.Element;
026    import com.liferay.portal.kernel.xml.SAXReader;
027    import com.liferay.portal.service.ClassNameLocalServiceUtil;
028    import com.liferay.portal.util.PropsUtil;
029    
030    import java.io.InputStream;
031    
032    import java.util.ArrayList;
033    import java.util.Collections;
034    import java.util.HashMap;
035    import java.util.Iterator;
036    import java.util.LinkedHashMap;
037    import java.util.List;
038    import java.util.Map;
039    import java.util.Set;
040    import java.util.TreeSet;
041    
042    /**
043     * @author Brian Wing Shun Chan
044     */
045    public class ModelHintsImpl implements ModelHints {
046    
047            public void afterPropertiesSet() {
048                    _hintCollections = new HashMap<String, Map<String, String>>();
049                    _defaultHints = new HashMap<String, Map<String, String>>();
050                    _modelFields = new HashMap<String, Object>();
051                    _models = new TreeSet<String>();
052    
053                    try {
054                            ClassLoader classLoader = getClass().getClassLoader();
055    
056                            String[] configs = StringUtil.split(
057                                    PropsUtil.get(PropsKeys.MODEL_HINTS_CONFIGS));
058    
059                            for (int i = 0; i < configs.length; i++) {
060                                    read(classLoader, configs[i]);
061                            }
062                    }
063                    catch (Exception e) {
064                            _log.error(e, e);
065                    }
066            }
067    
068            public Map<String, String> getDefaultHints(String model) {
069                    return _defaultHints.get(model);
070            }
071    
072            public com.liferay.portal.kernel.xml.Element getFieldsEl(
073                    String model, String field) {
074    
075                    Map<String, Object> fields =
076                            (Map<String, Object>)_modelFields.get(model);
077    
078                    if (fields == null) {
079                            return null;
080                    }
081                    else {
082                            Element fieldsEl = (Element)fields.get(field + _ELEMENTS_SUFFIX);
083    
084                            if (fieldsEl == null) {
085                                    return null;
086                            }
087                            else {
088                                    return fieldsEl;
089                            }
090                    }
091            }
092    
093            public Map<String, String> getHints(String model, String field) {
094                    Map<String, Object> fields =
095                            (Map<String, Object>)_modelFields.get(model);
096    
097                    if (fields == null) {
098                            return null;
099                    }
100                    else {
101                            return (Map<String, String>)fields.get(field + _HINTS_SUFFIX);
102                    }
103            }
104    
105            public List<String> getModels() {
106                    return ListUtil.fromCollection(_models);
107            }
108    
109            public Tuple getSanitizeTuple(String model, String field) {
110                    Map<String, Object> fields = (Map<String, Object>)_modelFields.get(
111                            model);
112    
113                    if (fields == null) {
114                            return null;
115                    }
116                    else {
117                            return (Tuple)fields.get(field + _SANITIZE_SUFFIX);
118                    }
119            }
120    
121            public List<Tuple> getSanitizeTuples(String model) {
122                    Map<String, Object> fields = (Map<String, Object>)_modelFields.get(
123                            model);
124    
125                    if (fields == null) {
126                            return Collections.EMPTY_LIST;
127                    }
128                    else {
129                            List<Tuple> sanitizeTuples = new ArrayList<Tuple>();
130    
131                            for (Map.Entry<String, Object> entry : fields.entrySet()) {
132                                    String key = entry.getKey();
133    
134                                    if (key.endsWith(_SANITIZE_SUFFIX)) {
135                                            Tuple sanitizeTuple = (Tuple)entry.getValue();
136    
137                                            sanitizeTuples.add(sanitizeTuple);
138                                    }
139                            }
140    
141                            return sanitizeTuples;
142                    }
143            }
144    
145            public String getType(String model, String field) {
146                    Map<String, Object> fields =
147                            (Map<String, Object>)_modelFields.get(model);
148    
149                    if (fields == null) {
150                            return null;
151                    }
152                    else {
153                            return (String)fields.get(field + _TYPE_SUFFIX);
154                    }
155            }
156    
157            public boolean isLocalized(String model, String field) {
158                    Map<String, Object> fields = (Map<String, Object>)_modelFields.get(
159                            model);
160    
161                    if (fields == null) {
162                            return false;
163                    }
164                    else {
165                            Boolean localized = (Boolean)fields.get(
166                                    field + _LOCALIZATION_SUFFIX);
167    
168                            if (localized != null) {
169                                    return localized;
170                            }
171                            else {
172                                    return false;
173                            }
174                    }
175            }
176    
177            public void read(ClassLoader classLoader, String source) throws Exception {
178                    InputStream is = classLoader.getResourceAsStream(source);
179    
180                    if (is == null) {
181                            if (_log.isWarnEnabled()) {
182                                    _log.warn("Cannot load " + source);
183                            }
184                            return;
185                    }
186                    else {
187                            if (_log.isDebugEnabled()) {
188                                    _log.debug("Loading " + source);
189                            }
190                    }
191    
192                    Document doc = _saxReader.read(is);
193    
194                    Element root = doc.getRootElement();
195    
196                    Iterator<Element> itr1 = root.elements("hint-collection").iterator();
197    
198                    while (itr1.hasNext()) {
199                            Element hintCollection = itr1.next();
200    
201                            String name = hintCollection.attributeValue("name");
202    
203                            Map<String, String> hints = _hintCollections.get(name);
204    
205                            if (hints == null) {
206                                    hints = new HashMap<String, String>();
207    
208                                    _hintCollections.put(name, hints);
209                            }
210    
211                            Iterator<Element> itr2 = hintCollection.elements("hint").iterator();
212    
213                            while (itr2.hasNext()) {
214                                    Element hint = itr2.next();
215    
216                                    String hintName = hint.attributeValue("name");
217                                    String hintValue = hint.getText();
218    
219                                    hints.put(hintName, hintValue);
220                            }
221                    }
222    
223                    itr1 = root.elements("model").iterator();
224    
225                    while (itr1.hasNext()) {
226                            Element model = itr1.next();
227    
228                            String name = model.attributeValue("name");
229    
230                            if (classLoader != ModelHintsImpl.class.getClassLoader()) {
231                                    ClassNameLocalServiceUtil.getClassName(name);
232                            }
233    
234                            Map<String, String> defaultHints = new HashMap<String, String>();
235    
236                            _defaultHints.put(name, defaultHints);
237    
238                            Element defaultHintsEl = model.element("default-hints");
239    
240                            if (defaultHintsEl != null) {
241                                    Iterator<Element> itr2 = defaultHintsEl.elements(
242                                            "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                                            defaultHints.put(hintName, hintValue);
251                                    }
252                            }
253    
254                            Map<String, Object> fields =
255                                    (Map<String, Object>)_modelFields.get(name);
256    
257                            if (fields == null) {
258                                    fields = new LinkedHashMap<String, Object>();
259    
260                                    _modelFields.put(name, fields);
261                            }
262    
263                            _models.add(name);
264    
265                            Iterator<Element> itr2 = model.elements("field").iterator();
266    
267                            while (itr2.hasNext()) {
268                                    Element field = itr2.next();
269    
270                                    String fieldName = field.attributeValue("name");
271                                    String fieldType = field.attributeValue("type");
272                                    boolean fieldLocalized = GetterUtil.getBoolean(
273                                            field.attributeValue("localized"));
274    
275                                    Map<String, String> fieldHints = new HashMap<String, String>();
276    
277                                    fieldHints.putAll(defaultHints);
278    
279                                    Iterator<Element> itr3 = field.elements(
280                                            "hint-collection").iterator();
281    
282                                    while (itr3.hasNext()) {
283                                            Element hintCollection = itr3.next();
284    
285                                            Map<String, String> hints = _hintCollections.get(
286                                                    hintCollection.attributeValue("name"));
287    
288                                            fieldHints.putAll(hints);
289                                    }
290    
291                                    itr3 = field.elements("hint").iterator();
292    
293                                    while (itr3.hasNext()) {
294                                            Element hint = itr3.next();
295    
296                                            String hintName = hint.attributeValue("name");
297                                            String hintValue = hint.getText();
298    
299                                            fieldHints.put(hintName, hintValue);
300                                    }
301    
302                                    Tuple fieldSanitize = null;
303    
304                                    Element sanitize = field.element("sanitize");
305    
306                                    if (sanitize != null) {
307                                            String contentType = sanitize.attributeValue(
308                                                    "content-type");
309                                            String modes = sanitize.attributeValue("modes");
310    
311                                            fieldSanitize = new Tuple(fieldName, contentType, modes);
312                                    }
313    
314                                    fields.put(fieldName + _ELEMENTS_SUFFIX, field);
315                                    fields.put(fieldName + _TYPE_SUFFIX, fieldType);
316                                    fields.put(fieldName + _LOCALIZATION_SUFFIX, fieldLocalized);
317                                    fields.put(fieldName + _HINTS_SUFFIX, fieldHints);
318    
319                                    if (fieldSanitize != null) {
320                                            fields.put(fieldName + _SANITIZE_SUFFIX, fieldSanitize);
321                                    }
322                            }
323                    }
324            }
325    
326            public void setSAXReader(SAXReader saxReader) {
327                    _saxReader = saxReader;
328            }
329    
330            public String trimString(String model, String field, String value) {
331                    if (value == null) {
332                            return value;
333                    }
334    
335                    Map<String, String> hints = getHints(model, field);
336    
337                    if (hints == null) {
338                            return value;
339                    }
340    
341                    int maxLength = GetterUtil.getInteger(
342                            ModelHintsConstants.TEXT_MAX_LENGTH);
343    
344                    maxLength = GetterUtil.getInteger(hints.get("max-length"), maxLength);
345    
346                    if (value.length() > maxLength) {
347                            return value.substring(0, maxLength);
348                    }
349                    else {
350                            return value;
351                    }
352            }
353    
354            private static final String _ELEMENTS_SUFFIX = "_ELEMENTS";
355    
356            private static final String _HINTS_SUFFIX = "_HINTS";
357    
358            private static final String _LOCALIZATION_SUFFIX = "_LOCALIZATION";
359    
360            private static final String _SANITIZE_SUFFIX = "_SANITIZE_SUFFIX";
361    
362            private static final String _TYPE_SUFFIX = "_TYPE";
363    
364            private static Log _log = LogFactoryUtil.getLog(ModelHintsImpl.class);
365    
366            private Map<String, Map<String, String>> _defaultHints;
367            private Map<String, Map<String, String>> _hintCollections;
368            private Map<String, Object> _modelFields;
369            private Set<String> _models;
370            private SAXReader _saxReader;
371    
372    }