001
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.security.pacl.DoPrivileged;
020 import com.liferay.portal.kernel.util.GetterUtil;
021 import com.liferay.portal.kernel.util.ListUtil;
022 import com.liferay.portal.kernel.util.PropsKeys;
023 import com.liferay.portal.kernel.util.StringPool;
024 import com.liferay.portal.kernel.util.StringUtil;
025 import com.liferay.portal.kernel.util.Tuple;
026 import com.liferay.portal.kernel.util.Validator;
027 import com.liferay.portal.kernel.xml.Document;
028 import com.liferay.portal.kernel.xml.Element;
029 import com.liferay.portal.kernel.xml.SAXReader;
030 import com.liferay.portal.service.ClassNameLocalServiceUtil;
031 import com.liferay.portal.util.PropsUtil;
032
033 import java.io.InputStream;
034
035 import java.net.URL;
036
037 import java.util.ArrayList;
038 import java.util.Collections;
039 import java.util.Enumeration;
040 import java.util.HashMap;
041 import java.util.LinkedHashMap;
042 import java.util.List;
043 import java.util.Map;
044 import java.util.Set;
045 import java.util.TreeMap;
046 import java.util.TreeSet;
047
048
052 @DoPrivileged
053 public class ModelHintsImpl implements ModelHints {
054
055 public void afterPropertiesSet() {
056 _hintCollections = new HashMap<String, Map<String, String>>();
057 _defaultHints = new HashMap<String, Map<String, String>>();
058 _modelFields = new HashMap<String, Object>();
059 _models = new TreeSet<String>();
060
061 try {
062 ClassLoader classLoader = getClass().getClassLoader();
063
064 String[] configs = StringUtil.split(
065 PropsUtil.get(PropsKeys.MODEL_HINTS_CONFIGS));
066
067 for (String config : configs) {
068 if (config.startsWith("classpath*:")) {
069 String name = config.substring("classpath*:".length());
070
071 Enumeration<URL> enu = classLoader.getResources(name);
072
073 if (_log.isDebugEnabled() && !enu.hasMoreElements()) {
074 _log.debug("No resources found for " + name);
075 }
076
077 while (enu.hasMoreElements()) {
078 URL url = enu.nextElement();
079
080 if (_log.isDebugEnabled()) {
081 _log.debug("Loading " + name + " from " + url);
082 }
083
084 InputStream inputStream = url.openStream();
085
086 read(classLoader, url.toString(), inputStream);
087 }
088 }
089 else {
090 read(classLoader, config);
091 }
092 }
093 }
094 catch (Exception e) {
095 _log.error(e, e);
096 }
097 }
098
099 @Override
100 public String buildCustomValidatorName(String validatorName) {
101 return validatorName.concat(StringPool.UNDERLINE).concat(
102 StringUtil.randomId());
103 }
104
105 @Override
106 public Map<String, String> getDefaultHints(String model) {
107 return _defaultHints.get(model);
108 }
109
110 @Override
111 public com.liferay.portal.kernel.xml.Element getFieldsEl(
112 String model, String field) {
113
114 Map<String, Object> fields = (Map<String, Object>)_modelFields.get(
115 model);
116
117 if (fields == null) {
118 return null;
119 }
120
121 Element fieldsEl = (Element)fields.get(field + _ELEMENTS_SUFFIX);
122
123 if (fieldsEl == null) {
124 return null;
125 }
126 else {
127 return fieldsEl;
128 }
129 }
130
131 @Override
132 public Map<String, String> getHints(String model, String field) {
133 Map<String, Object> fields = (Map<String, Object>)_modelFields.get(
134 model);
135
136 if (fields == null) {
137 return null;
138 }
139 else {
140 return (Map<String, String>)fields.get(field + _HINTS_SUFFIX);
141 }
142 }
143
144 @Override
145 public int getMaxLength(String model, String field) {
146 Map<String, String> hints = getHints(model, field);
147
148 if (hints == null) {
149 return Integer.MAX_VALUE;
150 }
151
152 int maxLength = GetterUtil.getInteger(
153 ModelHintsConstants.TEXT_MAX_LENGTH);
154
155 maxLength = GetterUtil.getInteger(hints.get("max-length"), maxLength);
156
157 return maxLength;
158 }
159
160 @Override
161 public List<String> getModels() {
162 return ListUtil.fromCollection(_models);
163 }
164
165 @Override
166 public Tuple getSanitizeTuple(String model, String field) {
167 Map<String, Object> fields = (Map<String, Object>)_modelFields.get(
168 model);
169
170 if (fields == null) {
171 return null;
172 }
173 else {
174 return (Tuple)fields.get(field + _SANITIZE_SUFFIX);
175 }
176 }
177
178 @Override
179 public List<Tuple> getSanitizeTuples(String model) {
180 Map<String, Object> fields = (Map<String, Object>)_modelFields.get(
181 model);
182
183 if (fields == null) {
184 return Collections.emptyList();
185 }
186
187 List<Tuple> sanitizeTuples = new ArrayList<Tuple>();
188
189 for (Map.Entry<String, Object> entry : fields.entrySet()) {
190 String key = entry.getKey();
191
192 if (key.endsWith(_SANITIZE_SUFFIX)) {
193 Tuple sanitizeTuple = (Tuple)entry.getValue();
194
195 sanitizeTuples.add(sanitizeTuple);
196 }
197 }
198
199 return sanitizeTuples;
200 }
201
202 @Override
203 public String getType(String model, String field) {
204 Map<String, Object> fields = (Map<String, Object>)_modelFields.get(
205 model);
206
207 if (fields == null) {
208 return null;
209 }
210 else {
211 return (String)fields.get(field + _TYPE_SUFFIX);
212 }
213 }
214
215 @Override
216 public List<Tuple> getValidators(String model, String field) {
217 Map<String, Object> fields = (Map<String, Object>)_modelFields.get(
218 model);
219
220 if ((fields == null) ||
221 (fields.get(field + _VALIDATORS_SUFFIX) == null)) {
222
223 return null;
224 }
225 else {
226 return (List<Tuple>)fields.get(field + _VALIDATORS_SUFFIX);
227 }
228 }
229
230 @Override
231 public String getValue(
232 String model, String field, String name, String defaultValue) {
233
234 Map<String, String> hints = getHints(model, field);
235
236 if (hints == null) {
237 return defaultValue;
238 }
239
240 return GetterUtil.getString(hints.get(name), defaultValue);
241 }
242
243 @Override
244 public boolean hasField(String model, String field) {
245 Map<String, Object> fields = (Map<String, Object>)_modelFields.get(
246 model);
247
248 if (fields == null) {
249 return false;
250 }
251
252 return fields.containsKey(field + _ELEMENTS_SUFFIX);
253 }
254
255 @Override
256 public boolean isCustomValidator(String validatorName) {
257 if (validatorName.equals("custom")) {
258 return true;
259 }
260
261 return false;
262 }
263
264 @Override
265 public boolean isLocalized(String model, String field) {
266 Map<String, Object> fields = (Map<String, Object>)_modelFields.get(
267 model);
268
269 if (fields == null) {
270 return false;
271 }
272
273 Boolean localized = (Boolean)fields.get(field + _LOCALIZATION_SUFFIX);
274
275 if (localized != null) {
276 return localized;
277 }
278 else {
279 return false;
280 }
281 }
282
283 @Override
284 public void read(ClassLoader classLoader, InputStream inputStream)
285 throws Exception {
286
287 read(classLoader, null, inputStream);
288 }
289
290 @Override
291 public void read(ClassLoader classLoader, String source) throws Exception {
292 read(classLoader, source, classLoader.getResourceAsStream(source));
293 }
294
295 public void read(
296 ClassLoader classLoader, String source, InputStream inputStream)
297 throws Exception {
298
299 if (inputStream == null) {
300 if (_log.isWarnEnabled()) {
301 _log.warn("Cannot load " + source);
302 }
303
304 return;
305 }
306 else {
307 if (_log.isDebugEnabled()) {
308 _log.debug("Loading " + source);
309 }
310 }
311
312 Document document = _saxReader.read(inputStream);
313
314 Element rootElement = document.getRootElement();
315
316 List<Element> rootElements = rootElement.elements("hint-collection");
317
318 for (Element hintCollectionElement : rootElements) {
319 String name = hintCollectionElement.attributeValue("name");
320
321 Map<String, String> hints = _hintCollections.get(name);
322
323 if (hints == null) {
324 hints = new HashMap<String, String>();
325
326 _hintCollections.put(name, hints);
327 }
328
329 List<Element> hintElements = hintCollectionElement.elements("hint");
330
331 for (Element hintElement : hintElements) {
332 String hintName = hintElement.attributeValue("name");
333 String hintValue = hintElement.getText();
334
335 hints.put(hintName, hintValue);
336 }
337 }
338
339 rootElements = rootElement.elements("model");
340
341 for (Element modelElement : rootElements) {
342 String name = modelElement.attributeValue("name");
343
344 if (classLoader != ModelHintsImpl.class.getClassLoader()) {
345 ClassNameLocalServiceUtil.getClassName(name);
346 }
347
348 Map<String, String> defaultHints = new HashMap<String, String>();
349
350 _defaultHints.put(name, defaultHints);
351
352 Element defaultHintsElement = modelElement.element("default-hints");
353
354 if (defaultHintsElement != null) {
355 List<Element> hintElements = defaultHintsElement.elements(
356 "hint");
357
358 for (Element hintElement : hintElements) {
359 String hintName = hintElement.attributeValue("name");
360 String hintValue = hintElement.getText();
361
362 defaultHints.put(hintName, hintValue);
363 }
364 }
365
366 Map<String, Object> fields = (Map<String, Object>)_modelFields.get(
367 name);
368
369 if (fields == null) {
370 fields = new LinkedHashMap<String, Object>();
371
372 _modelFields.put(name, fields);
373 }
374
375 _models.add(name);
376
377 List<Element> modelElements = modelElement.elements("field");
378
379 for (Element fieldElement : modelElements) {
380 String fieldName = fieldElement.attributeValue("name");
381 String fieldType = fieldElement.attributeValue("type");
382 boolean fieldLocalized = GetterUtil.getBoolean(
383 fieldElement.attributeValue("localized"));
384
385 Map<String, String> fieldHints = new HashMap<String, String>();
386
387 fieldHints.putAll(defaultHints);
388
389 List<Element> fieldElements = fieldElement.elements(
390 "hint-collection");
391
392 for (Element hintCollectionElement : fieldElements) {
393 Map<String, String> hints = _hintCollections.get(
394 hintCollectionElement.attributeValue("name"));
395
396 fieldHints.putAll(hints);
397 }
398
399 fieldElements = fieldElement.elements("hint");
400
401 for (Element hintElement : fieldElements) {
402 String hintName = hintElement.attributeValue("name");
403 String hintValue = hintElement.getText();
404
405 fieldHints.put(hintName, hintValue);
406 }
407
408 Tuple fieldSanitize = null;
409
410 Element sanitizeElement = fieldElement.element("sanitize");
411
412 if (sanitizeElement != null) {
413 String contentType = sanitizeElement.attributeValue(
414 "content-type");
415 String modes = sanitizeElement.attributeValue("modes");
416
417 fieldSanitize = new Tuple(fieldName, contentType, modes);
418 }
419
420 Map<String, Tuple> fieldValidators =
421 new TreeMap<String, Tuple>();
422
423 fieldElements = fieldElement.elements("validator");
424
425 for (Element validatorElement : fieldElements) {
426 String validatorName = validatorElement.attributeValue(
427 "name");
428
429 if (Validator.isNull(validatorName)) {
430 continue;
431 }
432
433 String validatorErrorMessage = GetterUtil.getString(
434 validatorElement.attributeValue("error-message"));
435 String validatorValue = GetterUtil.getString(
436 validatorElement.getText());
437 boolean customValidator = isCustomValidator(validatorName);
438
439 if (customValidator) {
440 validatorName = buildCustomValidatorName(validatorName);
441 }
442
443 Tuple fieldValidator = new Tuple(
444 fieldName, validatorName, validatorErrorMessage,
445 validatorValue, customValidator);
446
447 fieldValidators.put(validatorName, fieldValidator);
448 }
449
450 fields.put(fieldName + _ELEMENTS_SUFFIX, fieldElement);
451 fields.put(fieldName + _TYPE_SUFFIX, fieldType);
452 fields.put(fieldName + _LOCALIZATION_SUFFIX, fieldLocalized);
453 fields.put(fieldName + _HINTS_SUFFIX, fieldHints);
454
455 if (fieldSanitize != null) {
456 fields.put(fieldName + _SANITIZE_SUFFIX, fieldSanitize);
457 }
458
459 if (!fieldValidators.isEmpty()) {
460 fields.put(
461 fieldName + _VALIDATORS_SUFFIX,
462 ListUtil.fromMapValues(fieldValidators));
463 }
464 }
465 }
466 }
467
468 public void setSAXReader(SAXReader saxReader) {
469 _saxReader = saxReader;
470 }
471
472 @Override
473 public String trimString(String model, String field, String value) {
474 if (value == null) {
475 return value;
476 }
477
478 int maxLength = getMaxLength(model, field);
479
480 if (value.length() > maxLength) {
481 return value.substring(0, maxLength);
482 }
483 else {
484 return value;
485 }
486 }
487
488 private static final String _ELEMENTS_SUFFIX = "_ELEMENTS";
489
490 private static final String _HINTS_SUFFIX = "_HINTS";
491
492 private static final String _LOCALIZATION_SUFFIX = "_LOCALIZATION";
493
494 private static final String _SANITIZE_SUFFIX = "_SANITIZE_SUFFIX";
495
496 private static final String _TYPE_SUFFIX = "_TYPE";
497
498 private static final String _VALIDATORS_SUFFIX = "_VALIDATORS";
499
500 private static final Log _log = LogFactoryUtil.getLog(ModelHintsImpl.class);
501
502 private Map<String, Map<String, String>> _defaultHints;
503 private Map<String, Map<String, String>> _hintCollections;
504 private Map<String, Object> _modelFields;
505 private Set<String> _models;
506 private SAXReader _saxReader;
507
508 }