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, String source) throws Exception {
285 read(classLoader, source, classLoader.getResourceAsStream(source));
286 }
287
288 public void read(
289 ClassLoader classLoader, String source, InputStream inputStream)
290 throws Exception {
291
292 if (inputStream == null) {
293 if (_log.isWarnEnabled()) {
294 _log.warn("Cannot load " + source);
295 }
296
297 return;
298 }
299 else {
300 if (_log.isDebugEnabled()) {
301 _log.debug("Loading " + source);
302 }
303 }
304
305 Document document = _saxReader.read(inputStream);
306
307 Element rootElement = document.getRootElement();
308
309 List<Element> rootElements = rootElement.elements("hint-collection");
310
311 for (Element hintCollectionElement : rootElements) {
312 String name = hintCollectionElement.attributeValue("name");
313
314 Map<String, String> hints = _hintCollections.get(name);
315
316 if (hints == null) {
317 hints = new HashMap<String, String>();
318
319 _hintCollections.put(name, hints);
320 }
321
322 List<Element> hintElements = hintCollectionElement.elements("hint");
323
324 for (Element hintElement : hintElements) {
325 String hintName = hintElement.attributeValue("name");
326 String hintValue = hintElement.getText();
327
328 hints.put(hintName, hintValue);
329 }
330 }
331
332 rootElements = rootElement.elements("model");
333
334 for (Element modelElement : rootElements) {
335 String name = modelElement.attributeValue("name");
336
337 if (classLoader != ModelHintsImpl.class.getClassLoader()) {
338 ClassNameLocalServiceUtil.getClassName(name);
339 }
340
341 Map<String, String> defaultHints = new HashMap<String, String>();
342
343 _defaultHints.put(name, defaultHints);
344
345 Element defaultHintsElement = modelElement.element("default-hints");
346
347 if (defaultHintsElement != null) {
348 List<Element> hintElements = defaultHintsElement.elements(
349 "hint");
350
351 for (Element hintElement : hintElements) {
352 String hintName = hintElement.attributeValue("name");
353 String hintValue = hintElement.getText();
354
355 defaultHints.put(hintName, hintValue);
356 }
357 }
358
359 Map<String, Object> fields = (Map<String, Object>)_modelFields.get(
360 name);
361
362 if (fields == null) {
363 fields = new LinkedHashMap<String, Object>();
364
365 _modelFields.put(name, fields);
366 }
367
368 _models.add(name);
369
370 List<Element> modelElements = modelElement.elements("field");
371
372 for (Element fieldElement : modelElements) {
373 String fieldName = fieldElement.attributeValue("name");
374 String fieldType = fieldElement.attributeValue("type");
375 boolean fieldLocalized = GetterUtil.getBoolean(
376 fieldElement.attributeValue("localized"));
377
378 Map<String, String> fieldHints = new HashMap<String, String>();
379
380 fieldHints.putAll(defaultHints);
381
382 List<Element> fieldElements = fieldElement.elements(
383 "hint-collection");
384
385 for (Element hintCollectionElement : fieldElements) {
386 Map<String, String> hints = _hintCollections.get(
387 hintCollectionElement.attributeValue("name"));
388
389 fieldHints.putAll(hints);
390 }
391
392 fieldElements = fieldElement.elements("hint");
393
394 for (Element hintElement : fieldElements) {
395 String hintName = hintElement.attributeValue("name");
396 String hintValue = hintElement.getText();
397
398 fieldHints.put(hintName, hintValue);
399 }
400
401 Tuple fieldSanitize = null;
402
403 Element sanitizeElement = fieldElement.element("sanitize");
404
405 if (sanitizeElement != null) {
406 String contentType = sanitizeElement.attributeValue(
407 "content-type");
408 String modes = sanitizeElement.attributeValue("modes");
409
410 fieldSanitize = new Tuple(fieldName, contentType, modes);
411 }
412
413 Map<String, Tuple> fieldValidators =
414 new TreeMap<String, Tuple>();
415
416 fieldElements = fieldElement.elements("validator");
417
418 for (Element validatorElement : fieldElements) {
419 String validatorName = validatorElement.attributeValue(
420 "name");
421
422 if (Validator.isNull(validatorName)) {
423 continue;
424 }
425
426 String validatorErrorMessage = GetterUtil.getString(
427 validatorElement.attributeValue("error-message"));
428 String validatorValue = GetterUtil.getString(
429 validatorElement.getText());
430 boolean customValidator = isCustomValidator(validatorName);
431
432 if (customValidator) {
433 validatorName = buildCustomValidatorName(validatorName);
434 }
435
436 Tuple fieldValidator = new Tuple(
437 fieldName, validatorName, validatorErrorMessage,
438 validatorValue, customValidator);
439
440 fieldValidators.put(validatorName, fieldValidator);
441 }
442
443 fields.put(fieldName + _ELEMENTS_SUFFIX, fieldElement);
444 fields.put(fieldName + _TYPE_SUFFIX, fieldType);
445 fields.put(fieldName + _LOCALIZATION_SUFFIX, fieldLocalized);
446 fields.put(fieldName + _HINTS_SUFFIX, fieldHints);
447
448 if (fieldSanitize != null) {
449 fields.put(fieldName + _SANITIZE_SUFFIX, fieldSanitize);
450 }
451
452 if (!fieldValidators.isEmpty()) {
453 fields.put(
454 fieldName + _VALIDATORS_SUFFIX,
455 ListUtil.fromMapValues(fieldValidators));
456 }
457 }
458 }
459 }
460
461 public void setSAXReader(SAXReader saxReader) {
462 _saxReader = saxReader;
463 }
464
465 @Override
466 public String trimString(String model, String field, String value) {
467 if (value == null) {
468 return value;
469 }
470
471 int maxLength = getMaxLength(model, field);
472
473 if (value.length() > maxLength) {
474 return value.substring(0, maxLength);
475 }
476 else {
477 return value;
478 }
479 }
480
481 private static final String _ELEMENTS_SUFFIX = "_ELEMENTS";
482
483 private static final String _HINTS_SUFFIX = "_HINTS";
484
485 private static final String _LOCALIZATION_SUFFIX = "_LOCALIZATION";
486
487 private static final String _SANITIZE_SUFFIX = "_SANITIZE_SUFFIX";
488
489 private static final String _TYPE_SUFFIX = "_TYPE";
490
491 private static final String _VALIDATORS_SUFFIX = "_VALIDATORS";
492
493 private static Log _log = LogFactoryUtil.getLog(ModelHintsImpl.class);
494
495 private Map<String, Map<String, String>> _defaultHints;
496 private Map<String, Map<String, String>> _hintCollections;
497 private Map<String, Object> _modelFields;
498 private Set<String> _models;
499 private SAXReader _saxReader;
500
501 }