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 else {
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
132 @Override
133 public Map<String, String> getHints(String model, String field) {
134 Map<String, Object> fields = (Map<String, Object>)_modelFields.get(
135 model);
136
137 if (fields == null) {
138 return null;
139 }
140 else {
141 return (Map<String, String>)fields.get(field + _HINTS_SUFFIX);
142 }
143 }
144
145 @Override
146 public int getMaxLength(String model, String field) {
147 Map<String, String> hints = getHints(model, field);
148
149 if (hints == null) {
150 return Integer.MAX_VALUE;
151 }
152
153 int maxLength = GetterUtil.getInteger(
154 ModelHintsConstants.TEXT_MAX_LENGTH);
155
156 maxLength = GetterUtil.getInteger(hints.get("max-length"), maxLength);
157
158 return maxLength;
159 }
160
161 @Override
162 public List<String> getModels() {
163 return ListUtil.fromCollection(_models);
164 }
165
166 @Override
167 public Tuple getSanitizeTuple(String model, String field) {
168 Map<String, Object> fields = (Map<String, Object>)_modelFields.get(
169 model);
170
171 if (fields == null) {
172 return null;
173 }
174 else {
175 return (Tuple)fields.get(field + _SANITIZE_SUFFIX);
176 }
177 }
178
179 @Override
180 public List<Tuple> getSanitizeTuples(String model) {
181 Map<String, Object> fields = (Map<String, Object>)_modelFields.get(
182 model);
183
184 if (fields == null) {
185 return Collections.emptyList();
186 }
187 else {
188 List<Tuple> sanitizeTuples = new ArrayList<Tuple>();
189
190 for (Map.Entry<String, Object> entry : fields.entrySet()) {
191 String key = entry.getKey();
192
193 if (key.endsWith(_SANITIZE_SUFFIX)) {
194 Tuple sanitizeTuple = (Tuple)entry.getValue();
195
196 sanitizeTuples.add(sanitizeTuple);
197 }
198 }
199
200 return sanitizeTuples;
201 }
202 }
203
204 @Override
205 public String getType(String model, String field) {
206 Map<String, Object> fields = (Map<String, Object>)_modelFields.get(
207 model);
208
209 if (fields == null) {
210 return null;
211 }
212 else {
213 return (String)fields.get(field + _TYPE_SUFFIX);
214 }
215 }
216
217 @Override
218 public List<Tuple> getValidators(String model, String field) {
219 Map<String, Object> fields = (Map<String, Object>)_modelFields.get(
220 model);
221
222 if ((fields == null) ||
223 (fields.get(field + _VALIDATORS_SUFFIX) == null)) {
224
225 return null;
226 }
227 else {
228 return (List<Tuple>)fields.get(field + _VALIDATORS_SUFFIX);
229 }
230 }
231
232 @Override
233 public String getValue(
234 String model, String field, String name, String defaultValue) {
235
236 Map<String, String> hints = getHints(model, field);
237
238 if (hints == null) {
239 return defaultValue;
240 }
241
242 return GetterUtil.getString(hints.get(name), defaultValue);
243 }
244
245 @Override
246 public boolean hasField(String model, String field) {
247 Map<String, Object> fields = (Map<String, Object>)_modelFields.get(
248 model);
249
250 if (fields == null) {
251 return false;
252 }
253
254 return fields.containsKey(field + _ELEMENTS_SUFFIX);
255 }
256
257 @Override
258 public boolean isCustomValidator(String validatorName) {
259 if (validatorName.equals("custom")) {
260 return true;
261 }
262
263 return false;
264 }
265
266 @Override
267 public boolean isLocalized(String model, String field) {
268 Map<String, Object> fields = (Map<String, Object>)_modelFields.get(
269 model);
270
271 if (fields == null) {
272 return false;
273 }
274 else {
275 Boolean localized = (Boolean)fields.get(
276 field + _LOCALIZATION_SUFFIX);
277
278 if (localized != null) {
279 return localized;
280 }
281 else {
282 return false;
283 }
284 }
285 }
286
287 @Override
288 public void read(ClassLoader classLoader, String source) throws Exception {
289 read(classLoader, source, classLoader.getResourceAsStream(source));
290 }
291
292 public void read(
293 ClassLoader classLoader, String source, InputStream inputStream)
294 throws Exception {
295
296 if (inputStream == null) {
297 if (_log.isWarnEnabled()) {
298 _log.warn("Cannot load " + source);
299 }
300
301 return;
302 }
303 else {
304 if (_log.isDebugEnabled()) {
305 _log.debug("Loading " + source);
306 }
307 }
308
309 Document document = _saxReader.read(inputStream);
310
311 Element rootElement = document.getRootElement();
312
313 List<Element> rootElements = rootElement.elements("hint-collection");
314
315 for (Element hintCollectionElement : rootElements) {
316 String name = hintCollectionElement.attributeValue("name");
317
318 Map<String, String> hints = _hintCollections.get(name);
319
320 if (hints == null) {
321 hints = new HashMap<String, String>();
322
323 _hintCollections.put(name, hints);
324 }
325
326 List<Element> hintElements = hintCollectionElement.elements("hint");
327
328 for (Element hintElement : hintElements) {
329 String hintName = hintElement.attributeValue("name");
330 String hintValue = hintElement.getText();
331
332 hints.put(hintName, hintValue);
333 }
334 }
335
336 rootElements = rootElement.elements("model");
337
338 for (Element modelElement : rootElements) {
339 String name = modelElement.attributeValue("name");
340
341 if (classLoader != ModelHintsImpl.class.getClassLoader()) {
342 ClassNameLocalServiceUtil.getClassName(name);
343 }
344
345 Map<String, String> defaultHints = new HashMap<String, String>();
346
347 _defaultHints.put(name, defaultHints);
348
349 Element defaultHintsElement = modelElement.element("default-hints");
350
351 if (defaultHintsElement != null) {
352 List<Element> hintElements = defaultHintsElement.elements(
353 "hint");
354
355 for (Element hintElement : hintElements) {
356 String hintName = hintElement.attributeValue("name");
357 String hintValue = hintElement.getText();
358
359 defaultHints.put(hintName, hintValue);
360 }
361 }
362
363 Map<String, Object> fields = (Map<String, Object>)_modelFields.get(
364 name);
365
366 if (fields == null) {
367 fields = new LinkedHashMap<String, Object>();
368
369 _modelFields.put(name, fields);
370 }
371
372 _models.add(name);
373
374 List<Element> modelElements = modelElement.elements("field");
375
376 for (Element fieldElement : modelElements) {
377 String fieldName = fieldElement.attributeValue("name");
378 String fieldType = fieldElement.attributeValue("type");
379 boolean fieldLocalized = GetterUtil.getBoolean(
380 fieldElement.attributeValue("localized"));
381
382 Map<String, String> fieldHints = new HashMap<String, String>();
383
384 fieldHints.putAll(defaultHints);
385
386 List<Element> fieldElements = fieldElement.elements(
387 "hint-collection");
388
389 for (Element hintCollectionElement : fieldElements) {
390 Map<String, String> hints = _hintCollections.get(
391 hintCollectionElement.attributeValue("name"));
392
393 fieldHints.putAll(hints);
394 }
395
396 fieldElements = fieldElement.elements("hint");
397
398 for (Element hintElement : fieldElements) {
399 String hintName = hintElement.attributeValue("name");
400 String hintValue = hintElement.getText();
401
402 fieldHints.put(hintName, hintValue);
403 }
404
405 Tuple fieldSanitize = null;
406
407 Element sanitizeElement = fieldElement.element("sanitize");
408
409 if (sanitizeElement != null) {
410 String contentType = sanitizeElement.attributeValue(
411 "content-type");
412 String modes = sanitizeElement.attributeValue("modes");
413
414 fieldSanitize = new Tuple(fieldName, contentType, modes);
415 }
416
417 Map<String, Tuple> fieldValidators =
418 new TreeMap<String, Tuple>();
419
420 fieldElements = fieldElement.elements("validator");
421
422 for (Element validatorElement : fieldElements) {
423 String validatorName = validatorElement.attributeValue(
424 "name");
425
426 if (Validator.isNull(validatorName)) {
427 continue;
428 }
429
430 String validatorErrorMessage = GetterUtil.getString(
431 validatorElement.attributeValue("error-message"));
432 String validatorValue = GetterUtil.getString(
433 validatorElement.getText());
434 boolean customValidator = isCustomValidator(validatorName);
435
436 if (customValidator) {
437 validatorName = buildCustomValidatorName(validatorName);
438 }
439
440 Tuple fieldValidator = new Tuple(
441 fieldName, validatorName, validatorErrorMessage,
442 validatorValue, customValidator);
443
444 fieldValidators.put(validatorName, fieldValidator);
445 }
446
447 fields.put(fieldName + _ELEMENTS_SUFFIX, fieldElement);
448 fields.put(fieldName + _TYPE_SUFFIX, fieldType);
449 fields.put(fieldName + _LOCALIZATION_SUFFIX, fieldLocalized);
450 fields.put(fieldName + _HINTS_SUFFIX, fieldHints);
451
452 if (fieldSanitize != null) {
453 fields.put(fieldName + _SANITIZE_SUFFIX, fieldSanitize);
454 }
455
456 if (!fieldValidators.isEmpty()) {
457 fields.put(
458 fieldName + _VALIDATORS_SUFFIX,
459 ListUtil.fromMapValues(fieldValidators));
460 }
461 }
462 }
463 }
464
465 public void setSAXReader(SAXReader saxReader) {
466 _saxReader = saxReader;
467 }
468
469 @Override
470 public String trimString(String model, String field, String value) {
471 if (value == null) {
472 return value;
473 }
474
475 int maxLength = getMaxLength(model, field);
476
477 if (value.length() > maxLength) {
478 return value.substring(0, maxLength);
479 }
480 else {
481 return value;
482 }
483 }
484
485 private static final String _ELEMENTS_SUFFIX = "_ELEMENTS";
486
487 private static final String _HINTS_SUFFIX = "_HINTS";
488
489 private static final String _LOCALIZATION_SUFFIX = "_LOCALIZATION";
490
491 private static final String _SANITIZE_SUFFIX = "_SANITIZE_SUFFIX";
492
493 private static final String _TYPE_SUFFIX = "_TYPE";
494
495 private static final String _VALIDATORS_SUFFIX = "_VALIDATORS";
496
497 private static Log _log = LogFactoryUtil.getLog(ModelHintsImpl.class);
498
499 private Map<String, Map<String, String>> _defaultHints;
500 private Map<String, Map<String, String>> _hintCollections;
501 private Map<String, Object> _modelFields;
502 private Set<String> _models;
503 private SAXReader _saxReader;
504
505 }