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