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