1   /**
2    * Copyright (c) 2000-2010 Liferay, Inc. All rights reserved.
3    *
4    * This library is free software; you can redistribute it and/or modify it under
5    * the terms of the GNU Lesser General Public License as published by the Free
6    * Software Foundation; either version 2.1 of the License, or (at your option)
7    * any later version.
8    *
9    * This library is distributed in the hope that it will be useful, but WITHOUT
10   * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11   * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
12   * details.
13   */
14  
15  package com.liferay.portal.model;
16  
17  import com.liferay.portal.kernel.log.Log;
18  import com.liferay.portal.kernel.log.LogFactoryUtil;
19  import com.liferay.portal.kernel.util.GetterUtil;
20  import com.liferay.portal.kernel.util.ListUtil;
21  import com.liferay.portal.kernel.util.PropsKeys;
22  import com.liferay.portal.kernel.util.StringUtil;
23  import com.liferay.portal.kernel.util.Tuple;
24  import com.liferay.portal.kernel.xml.Document;
25  import com.liferay.portal.kernel.xml.Element;
26  import com.liferay.portal.kernel.xml.SAXReader;
27  import com.liferay.portal.service.ClassNameLocalServiceUtil;
28  import com.liferay.portal.util.PropsUtil;
29  
30  import java.io.InputStream;
31  
32  import java.util.ArrayList;
33  import java.util.Collections;
34  import java.util.HashMap;
35  import java.util.Iterator;
36  import java.util.LinkedHashMap;
37  import java.util.List;
38  import java.util.Map;
39  import java.util.Set;
40  import java.util.TreeSet;
41  
42  /**
43   * <a href="ModelHintsImpl.java.html"><b><i>View Source</i></b></a>
44   *
45   * @author Brian Wing Shun Chan
46   */
47  public class ModelHintsImpl implements ModelHints {
48  
49      public void afterPropertiesSet() {
50          _hintCollections = new HashMap<String, Map<String, String>>();
51          _defaultHints = new HashMap<String, Map<String, String>>();
52          _modelFields = new HashMap<String, Object>();
53          _models = new TreeSet<String>();
54  
55          try {
56              ClassLoader classLoader = getClass().getClassLoader();
57  
58              String[] configs = StringUtil.split(
59                  PropsUtil.get(PropsKeys.MODEL_HINTS_CONFIGS));
60  
61              for (int i = 0; i < configs.length; i++) {
62                  read(classLoader, configs[i]);
63              }
64          }
65          catch (Exception e) {
66              _log.error(e, e);
67          }
68      }
69  
70      public Map<String, String> getDefaultHints(String model) {
71          return _defaultHints.get(model);
72      }
73  
74      public com.liferay.portal.kernel.xml.Element getFieldsEl(
75          String model, String field) {
76  
77          Map<String, Object> fields =
78              (Map<String, Object>)_modelFields.get(model);
79  
80          if (fields == null) {
81              return null;
82          }
83          else {
84              Element fieldsEl = (Element)fields.get(field + _ELEMENTS_SUFFIX);
85  
86              if (fieldsEl == null) {
87                  return null;
88              }
89              else {
90                  return fieldsEl;
91              }
92          }
93      }
94  
95      public Map<String, String> getHints(String model, String field) {
96          Map<String, Object> fields =
97              (Map<String, Object>)_modelFields.get(model);
98  
99          if (fields == null) {
100             return null;
101         }
102         else {
103             return (Map<String, String>)fields.get(field + _HINTS_SUFFIX);
104         }
105     }
106 
107     public List<String> getModels() {
108         return ListUtil.fromCollection(_models);
109     }
110 
111     public Tuple getSanitizeTuple(String model, String field) {
112         Map<String, Object> fields = (Map<String, Object>)_modelFields.get(
113             model);
114 
115         if (fields == null) {
116             return null;
117         }
118         else {
119             return (Tuple)fields.get(field + _SANITIZE_SUFFIX);
120         }
121     }
122 
123     public List<Tuple> getSanitizeTuples(String model) {
124         Map<String, Object> fields = (Map<String, Object>)_modelFields.get(
125             model);
126 
127         if (fields == null) {
128             return Collections.EMPTY_LIST;
129         }
130         else {
131             List<Tuple> sanitizeTuples = new ArrayList<Tuple>();
132 
133             for (String key : fields.keySet()) {
134                 if (key.endsWith(_SANITIZE_SUFFIX)) {
135                     Tuple sanitizeTuple = (Tuple)fields.get(key);
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             return (Boolean)fields.get(field + _LOCALIZATION_SUFFIX);
166         }
167     }
168 
169     public void read(ClassLoader classLoader, String source) throws Exception {
170         InputStream is = classLoader.getResourceAsStream(source);
171 
172         if (is == null) {
173             if (_log.isWarnEnabled()) {
174                 _log.warn("Cannot load " + source);
175             }
176             return;
177         }
178         else {
179             if (_log.isDebugEnabled()) {
180                 _log.debug("Loading " + source);
181             }
182         }
183 
184         Document doc = _saxReader.read(is);
185 
186         Element root = doc.getRootElement();
187 
188         Iterator<Element> itr1 = root.elements("hint-collection").iterator();
189 
190         while (itr1.hasNext()) {
191             Element hintCollection = itr1.next();
192 
193             String name = hintCollection.attributeValue("name");
194 
195             Map<String, String> hints = _hintCollections.get(name);
196 
197             if (hints == null) {
198                 hints = new HashMap<String, String>();
199 
200                 _hintCollections.put(name, hints);
201             }
202 
203             Iterator<Element> itr2 = hintCollection.elements("hint").iterator();
204 
205             while (itr2.hasNext()) {
206                 Element hint = itr2.next();
207 
208                 String hintName = hint.attributeValue("name");
209                 String hintValue = hint.getText();
210 
211                 hints.put(hintName, hintValue);
212             }
213         }
214 
215         itr1 = root.elements("model").iterator();
216 
217         while (itr1.hasNext()) {
218             Element model = itr1.next();
219 
220             String name = model.attributeValue("name");
221 
222             if (classLoader != ModelHintsImpl.class.getClassLoader()) {
223                 ClassNameLocalServiceUtil.getClassName(name);
224             }
225 
226             Map<String, String> defaultHints = new HashMap<String, String>();
227 
228             _defaultHints.put(name, defaultHints);
229 
230             Element defaultHintsEl = model.element("default-hints");
231 
232             if (defaultHintsEl != null) {
233                 Iterator<Element> itr2 = defaultHintsEl.elements(
234                     "hint").iterator();
235 
236                 while (itr2.hasNext()) {
237                     Element hint = itr2.next();
238 
239                     String hintName = hint.attributeValue("name");
240                     String hintValue = hint.getText();
241 
242                     defaultHints.put(hintName, hintValue);
243                 }
244             }
245 
246             Map<String, Object> fields =
247                 (Map<String, Object>)_modelFields.get(name);
248 
249             if (fields == null) {
250                 fields = new LinkedHashMap<String, Object>();
251 
252                 _modelFields.put(name, fields);
253             }
254 
255             _models.add(name);
256 
257             Iterator<Element> itr2 = model.elements("field").iterator();
258 
259             while (itr2.hasNext()) {
260                 Element field = itr2.next();
261 
262                 String fieldName = field.attributeValue("name");
263                 String fieldType = field.attributeValue("type");
264                 boolean fieldLocalized = GetterUtil.getBoolean(
265                     field.attributeValue("localized"));
266 
267                 Map<String, String> fieldHints = new HashMap<String, String>();
268 
269                 fieldHints.putAll(defaultHints);
270 
271                 Iterator<Element> itr3 = field.elements(
272                     "hint-collection").iterator();
273 
274                 while (itr3.hasNext()) {
275                     Element hintCollection = itr3.next();
276 
277                     Map<String, String> hints = _hintCollections.get(
278                         hintCollection.attributeValue("name"));
279 
280                     fieldHints.putAll(hints);
281                 }
282 
283                 itr3 = field.elements("hint").iterator();
284 
285                 while (itr3.hasNext()) {
286                     Element hint = itr3.next();
287 
288                     String hintName = hint.attributeValue("name");
289                     String hintValue = hint.getText();
290 
291                     fieldHints.put(hintName, hintValue);
292                 }
293 
294                 Tuple fieldSanitize = null;
295 
296                 Element sanitize = field.element("sanitize");
297 
298                 if (sanitize != null) {
299                     String contentType = sanitize.attributeValue(
300                         "content-type");
301                     String modes = sanitize.attributeValue("modes");
302 
303                     fieldSanitize = new Tuple(fieldName, contentType, modes);
304                 }
305 
306                 fields.put(fieldName + _ELEMENTS_SUFFIX, field);
307                 fields.put(fieldName + _TYPE_SUFFIX, fieldType);
308                 fields.put(fieldName + _LOCALIZATION_SUFFIX, fieldLocalized);
309                 fields.put(fieldName + _HINTS_SUFFIX, fieldHints);
310 
311                 if (fieldSanitize != null) {
312                     fields.put(fieldName + _SANITIZE_SUFFIX, fieldSanitize);
313                 }
314             }
315         }
316     }
317 
318     public void setSAXReader(SAXReader saxReader) {
319         _saxReader = saxReader;
320     }
321 
322     public String trimString(String model, String field, String value) {
323         if (value == null) {
324             return value;
325         }
326 
327         Map<String, String> hints = getHints(model, field);
328 
329         if (hints == null) {
330             return value;
331         }
332 
333         int maxLength = GetterUtil.getInteger(
334             ModelHintsConstants.TEXT_MAX_LENGTH);
335 
336         maxLength = GetterUtil.getInteger(hints.get("max-length"), maxLength);
337 
338         if (value.length() > maxLength) {
339             return value.substring(0, maxLength);
340         }
341         else {
342             return value;
343         }
344     }
345 
346     private static final String _ELEMENTS_SUFFIX = "_ELEMENTS";
347 
348     private static final String _HINTS_SUFFIX = "_HINTS";
349 
350     private static final String _LOCALIZATION_SUFFIX = "_LOCALIZATION";
351 
352     private static final String _SANITIZE_SUFFIX = "_SANITIZE_SUFFIX";
353 
354     private static final String _TYPE_SUFFIX = "_TYPE";
355 
356     private static Log _log = LogFactoryUtil.getLog(ModelHintsImpl.class);
357 
358     private Map<String, Map<String, String>> _defaultHints;
359     private Map<String, Map<String, String>> _hintCollections;
360     private Map<String, Object> _modelFields;
361     private Set<String> _models;
362     private SAXReader _saxReader;
363 
364 }