001
014
015 package com.liferay.portlet.dynamicdatamapping.model.impl;
016
017 import com.liferay.portal.LocaleException;
018 import com.liferay.portal.kernel.configuration.Filter;
019 import com.liferay.portal.kernel.exception.PortalException;
020 import com.liferay.portal.kernel.exception.SystemException;
021 import com.liferay.portal.kernel.log.Log;
022 import com.liferay.portal.kernel.log.LogFactoryUtil;
023 import com.liferay.portal.kernel.util.ArrayUtil;
024 import com.liferay.portal.kernel.util.GetterUtil;
025 import com.liferay.portal.kernel.util.HtmlUtil;
026 import com.liferay.portal.kernel.util.LocaleUtil;
027 import com.liferay.portal.kernel.util.PropsKeys;
028 import com.liferay.portal.kernel.util.PropsUtil;
029 import com.liferay.portal.kernel.util.StringBundler;
030 import com.liferay.portal.kernel.util.StringPool;
031 import com.liferay.portal.kernel.util.StringUtil;
032 import com.liferay.portal.kernel.util.Validator;
033 import com.liferay.portal.kernel.xml.Attribute;
034 import com.liferay.portal.kernel.xml.Document;
035 import com.liferay.portal.kernel.xml.Element;
036 import com.liferay.portal.kernel.xml.Node;
037 import com.liferay.portal.kernel.xml.SAXReaderUtil;
038 import com.liferay.portal.kernel.xml.XPath;
039 import com.liferay.portal.model.CacheField;
040 import com.liferay.portal.model.Group;
041 import com.liferay.portal.theme.ThemeDisplay;
042 import com.liferay.portal.util.PortalUtil;
043 import com.liferay.portal.util.PropsValues;
044 import com.liferay.portlet.dynamicdatamapping.StructureFieldException;
045 import com.liferay.portlet.dynamicdatamapping.model.DDMStructure;
046 import com.liferay.portlet.dynamicdatamapping.model.DDMTemplate;
047 import com.liferay.portlet.dynamicdatamapping.service.DDMStructureLocalServiceUtil;
048 import com.liferay.portlet.dynamicdatamapping.service.DDMTemplateLocalServiceUtil;
049 import com.liferay.portlet.dynamicdatamapping.util.DDMXMLUtil;
050
051 import java.util.ArrayList;
052 import java.util.HashMap;
053 import java.util.LinkedHashMap;
054 import java.util.List;
055 import java.util.Locale;
056 import java.util.Map;
057 import java.util.Set;
058 import java.util.concurrent.ConcurrentHashMap;
059
060
063 public class DDMStructureImpl extends DDMStructureBaseImpl {
064
065 @Override
066 public String[] getAvailableLanguageIds() {
067 Document document = getDocument();
068
069 Element rootElement = document.getRootElement();
070
071 String availableLocales = rootElement.attributeValue(
072 "available-locales");
073
074 return StringUtil.split(availableLocales);
075 }
076
077 @Override
078 public List<String> getChildrenFieldNames(String fieldName)
079 throws PortalException, SystemException {
080
081 List<String> fieldNames = new ArrayList<String>();
082
083 Map<String, Map<String, String>> fieldsMap = getFieldsMap(true);
084
085 for (Map<String, String> field : fieldsMap.values()) {
086 String parentNameKey = _getPrivateAttributeKey("parentName");
087
088 String parentName = field.get(parentNameKey);
089
090 if (fieldName.equals(parentName)) {
091 fieldNames.add(field.get("name"));
092 }
093 }
094
095 return fieldNames;
096 }
097
098 @Override
099 public String getCompleteXsd() throws PortalException, SystemException {
100 if (getParentStructureId() == 0) {
101 return getXsd();
102 }
103
104 DDMStructure parentStructure =
105 DDMStructureLocalServiceUtil.getStructure(getParentStructureId());
106
107 return _mergeXsds(getXsd(), parentStructure.getCompleteXsd());
108 }
109
110 @Override
111 public String getDefaultLanguageId() {
112 Document document = getDocument();
113
114 if (document == null) {
115 Locale locale = LocaleUtil.getSiteDefault();
116
117 return locale.toString();
118 }
119
120 Element rootElement = document.getRootElement();
121
122 return rootElement.attributeValue("default-locale");
123 }
124
125 @Override
126 public Document getDocument() {
127 if (_document == null) {
128 try {
129 _document = SAXReaderUtil.read(getXsd());
130 }
131 catch (Exception e) {
132 StackTraceElement[] stackTraceElements = e.getStackTrace();
133
134 for (StackTraceElement stackTraceElement : stackTraceElements) {
135 String className = stackTraceElement.getClassName();
136
137 if (className.endsWith("DDMStructurePersistenceTest")) {
138 return null;
139 }
140 }
141
142 _log.error(e, e);
143 }
144 }
145
146 return _document;
147 }
148
149 @Override
150 public String getFieldDataType(String fieldName)
151 throws PortalException, SystemException {
152
153 return getFieldProperty(fieldName, "dataType");
154 }
155
156 @Override
157 public String getFieldLabel(String fieldName, Locale locale)
158 throws PortalException, SystemException {
159
160 return getFieldLabel(fieldName, LocaleUtil.toLanguageId(locale));
161 }
162
163 @Override
164 public String getFieldLabel(String fieldName, String locale)
165 throws PortalException, SystemException {
166
167 return GetterUtil.getString(
168 getFieldProperty(fieldName, "label", locale), fieldName);
169 }
170
171 @Override
172 public Set<String> getFieldNames() throws PortalException, SystemException {
173 Map<String, Map<String, String>> fieldsMap = getFieldsMap();
174
175 return fieldsMap.keySet();
176 }
177
178 @Override
179 public String getFieldProperty(String fieldName, String property)
180 throws PortalException, SystemException {
181
182 return getFieldProperty(fieldName, property, getDefaultLanguageId());
183 }
184
185 @Override
186 public String getFieldProperty(
187 String fieldName, String property, String locale)
188 throws PortalException, SystemException {
189
190 if (!hasField(fieldName)) {
191 throw new StructureFieldException();
192 }
193
194 Map<String, Map<String, String>> fieldsMap = getFieldsMap(locale, true);
195
196 Map<String, String> field = fieldsMap.get(fieldName);
197
198 return field.get(property);
199 }
200
201 @Override
202 public boolean getFieldRepeatable(String fieldName)
203 throws PortalException, SystemException {
204
205 return GetterUtil.getBoolean(getFieldProperty(fieldName, "repeatable"));
206 }
207
208 @Override
209 public boolean getFieldRequired(String fieldName)
210 throws PortalException, SystemException {
211
212 return GetterUtil.getBoolean(getFieldProperty(fieldName, "required"));
213 }
214
215 @Override
216 public Map<String, String> getFields(
217 String fieldName, String attributeName, String attributeValue) {
218
219 return getFields(
220 fieldName, attributeName, attributeValue, getDefaultLanguageId());
221 }
222
223 @Override
224 public Map<String, String> getFields(
225 String fieldName, String attributeName, String attributeValue,
226 String locale) {
227
228 try {
229 if ((attributeName == null) || (attributeValue == null)) {
230 return null;
231 }
232
233 Map<String, Map<String, String>> fieldsMap = getTransientFieldsMap(
234 locale);
235
236 for (Map<String, String> fields : fieldsMap.values()) {
237 String parentName = fields.get(
238 _getPrivateAttributeKey("parentName"));
239
240 if (!fieldName.equals(parentName)) {
241 continue;
242 }
243
244 if (attributeValue.equals(fields.get(attributeName))) {
245 return fields;
246 }
247 }
248 }
249 catch (Exception e) {
250 _log.error(e, e);
251 }
252
253 return null;
254 }
255
256 @Override
257 public Map<String, Map<String, String>> getFieldsMap()
258 throws PortalException, SystemException {
259
260 return getFieldsMap(getDefaultLanguageId());
261 }
262
263 @Override
264 public Map<String, Map<String, String>> getFieldsMap(
265 boolean includeTransientFields)
266 throws PortalException, SystemException {
267
268 return getFieldsMap(getDefaultLanguageId(), includeTransientFields);
269 }
270
271 @Override
272 public Map<String, Map<String, String>> getFieldsMap(String locale)
273 throws PortalException, SystemException {
274
275 return getFieldsMap(locale, false);
276 }
277
278 @Override
279 public Map<String, Map<String, String>> getFieldsMap(
280 String locale, boolean includeTransientFields)
281 throws PortalException, SystemException {
282
283 _indexFieldsMap(locale);
284
285 Map<String, Map<String, Map<String, String>>> fieldsMap = null;
286
287 if (includeTransientFields) {
288 fieldsMap = getLocalizedFieldsMap();
289 }
290 else {
291 fieldsMap = getLocalizedPersistentFieldsMap();
292 }
293
294 return fieldsMap.get(locale);
295 }
296
297 @Override
298 public String getFieldTip(String fieldName, Locale locale)
299 throws PortalException, SystemException {
300
301 return getFieldTip(fieldName, LocaleUtil.toLanguageId(locale));
302 }
303
304 @Override
305 public String getFieldTip(String fieldName, String locale)
306 throws PortalException, SystemException {
307
308 return GetterUtil.getString(
309 getFieldProperty(fieldName, "tip", locale), fieldName);
310 }
311
312 @Override
313 public String getFieldType(String fieldName)
314 throws PortalException, SystemException {
315
316 return getFieldProperty(fieldName, "type");
317 }
318
319 @Override
320 public Map<String, Map<String, Map<String, String>>>
321 getLocalizedFieldsMap() {
322
323 if (_localizedFieldsMap == null) {
324 _localizedFieldsMap =
325 new ConcurrentHashMap
326 <String, Map<String, Map<String, String>>>();
327 }
328
329 return _localizedFieldsMap;
330 }
331
332 @Override
333 public Map<String, Map<String, Map<String, String>>>
334 getLocalizedPersistentFieldsMap() {
335
336 if (_localizedPersistentFieldsMap == null) {
337 _localizedPersistentFieldsMap =
338 new ConcurrentHashMap
339 <String, Map<String, Map<String, String>>>();
340 }
341
342 return _localizedPersistentFieldsMap;
343 }
344
345 @Override
346 public Map<String, Map<String, Map<String, String>>>
347 getLocalizedTransientFieldsMap() {
348
349 if (_localizedTransientFieldsMap == null) {
350 _localizedTransientFieldsMap =
351 new ConcurrentHashMap
352 <String, Map<String, Map<String, String>>>();
353 }
354
355 return _localizedTransientFieldsMap;
356 }
357
358 @Override
359 public Map<String, Map<String, String>> getPersistentFieldsMap(
360 String locale)
361 throws PortalException, SystemException {
362
363 _indexFieldsMap(locale);
364
365 Map<String, Map<String, Map<String, String>>>
366 localizedPersistentFieldsMap = getLocalizedPersistentFieldsMap();
367
368 Map<String, Map<String, String>> fieldsMap =
369 localizedPersistentFieldsMap.get(locale);
370
371 return fieldsMap;
372 }
373
374 @Override
375 public List<String> getRootFieldNames()
376 throws PortalException, SystemException {
377
378 List<String> fieldNames = new ArrayList<String>();
379
380 Map<String, Map<String, String>> fieldsMap = getFieldsMap(true);
381
382 for (Map.Entry<String, Map<String, String>> entry :
383 fieldsMap.entrySet()) {
384
385 Map<String, String> field = entry.getValue();
386
387 String parentNameKey = _getPrivateAttributeKey("parentName");
388
389 if (!field.containsKey(parentNameKey)) {
390 fieldNames.add(entry.getKey());
391 }
392 }
393
394 return fieldNames;
395 }
396
397 @Override
398 public List<DDMTemplate> getTemplates() throws SystemException {
399 return DDMTemplateLocalServiceUtil.getTemplates(getStructureId());
400 }
401
402 @Override
403 public Map<String, Map<String, String>> getTransientFieldsMap(String locale)
404 throws PortalException, SystemException {
405
406 _indexFieldsMap(locale);
407
408 Map<String, Map<String, Map<String, String>>>
409 localizedTransientFieldsMap = getLocalizedTransientFieldsMap();
410
411 Map<String, Map<String, String>> fieldsMap =
412 localizedTransientFieldsMap.get(locale);
413
414 return fieldsMap;
415 }
416
417
426 @Override
427 public String getWebDavURL(ThemeDisplay themeDisplay, String webDAVToken) {
428 StringBundler sb = new StringBundler(11);
429
430 boolean secure = false;
431
432 if (themeDisplay.isSecure() ||
433 PropsValues.WEBDAV_SERVLET_HTTPS_REQUIRED) {
434
435 secure = true;
436 }
437
438 String portalURL = PortalUtil.getPortalURL(
439 themeDisplay.getServerName(), themeDisplay.getServerPort(), secure);
440
441 sb.append(portalURL);
442
443 sb.append(themeDisplay.getPathContext());
444 sb.append(StringPool.SLASH);
445 sb.append("webdav");
446
447 Group group = themeDisplay.getScopeGroup();
448
449 sb.append(group.getFriendlyURL());
450
451 sb.append(StringPool.SLASH);
452 sb.append(webDAVToken);
453 sb.append(StringPool.SLASH);
454 sb.append("Structures");
455 sb.append(StringPool.SLASH);
456 sb.append(getStructureId());
457
458 return sb.toString();
459 }
460
461 @Override
462 public boolean hasField(String fieldName)
463 throws PortalException, SystemException {
464
465 Map<String, Map<String, String>> fieldsMap = getFieldsMap(true);
466
467 boolean hasField = fieldsMap.containsKey(fieldName);
468
469 while (!hasField && (getParentStructureId() > 0)) {
470 DDMStructure parentStructure =
471 DDMStructureLocalServiceUtil.getStructure(
472 getParentStructureId());
473
474 hasField = parentStructure.hasField(fieldName);
475 }
476
477 return hasField;
478 }
479
480 @Override
481 public boolean isFieldPrivate(String fieldName)
482 throws PortalException, SystemException {
483
484 return GetterUtil.getBoolean(getFieldProperty(fieldName, "private"));
485 }
486
487 @Override
488 public boolean isFieldRepeatable(String fieldName)
489 throws PortalException, SystemException {
490
491 return GetterUtil.getBoolean(getFieldProperty(fieldName, "repeatable"));
492 }
493
494 @Override
495 public boolean isFieldTransient(String fieldName)
496 throws PortalException, SystemException {
497
498 if (!hasField(fieldName)) {
499 throw new StructureFieldException();
500 }
501
502 Map<String, Map<String, String>> transientFieldsMap =
503 getTransientFieldsMap(getDefaultLanguageId());
504
505 return transientFieldsMap.containsKey(fieldName);
506 }
507
508 @Override
509 public void prepareLocalizedFieldsForImport(Locale defaultImportLocale)
510 throws LocaleException {
511
512 super.prepareLocalizedFieldsForImport(defaultImportLocale);
513
514 Locale ddmStructureDefaultLocale = LocaleUtil.fromLanguageId(
515 getDefaultLanguageId());
516
517 try {
518 setXsd(
519 DDMXMLUtil.updateXMLDefaultLocale(
520 getXsd(), ddmStructureDefaultLocale, defaultImportLocale));
521 }
522 catch (Exception e) {
523 throw new LocaleException(LocaleException.TYPE_EXPORT_IMPORT, e);
524 }
525 }
526
527 @Override
528 public void setDocument(Document document) {
529 _document = document;
530 }
531
532 @Override
533 public void setLocalizedFieldsMap(
534 Map<String, Map<String, Map<String, String>>> localizedFieldsMap) {
535
536 _localizedFieldsMap = localizedFieldsMap;
537 }
538
539 @Override
540 public void setLocalizedPersistentFieldsMap(
541 Map<String, Map<String, Map<String, String>>>
542 localizedPersistentFieldsMap) {
543
544 _localizedPersistentFieldsMap = localizedPersistentFieldsMap;
545 }
546
547 @Override
548 public void setLocalizedTransientFieldsMap(
549 Map<String, Map<String, Map<String, String>>>
550 localizedTransientFieldsMap) {
551
552 _localizedTransientFieldsMap = localizedTransientFieldsMap;
553 }
554
555 @Override
556 public void setXsd(String xsd) {
557 super.setXsd(xsd);
558
559 _document = null;
560 _localizedFieldsMap = null;
561 _localizedPersistentFieldsMap = null;
562 _localizedTransientFieldsMap = null;
563 }
564
565 private Map<String, String> _getField(Element element, String locale) {
566 Map<String, String> field = new HashMap<String, String>();
567
568 String[] availableLanguageIds = getAvailableLanguageIds();
569
570 if ((locale != null) &&
571 !ArrayUtil.contains(availableLanguageIds, locale)) {
572
573 locale = getDefaultLanguageId();
574 }
575
576 locale = HtmlUtil.escapeXPathAttribute(locale);
577
578 String xPathExpression =
579 "meta-data[@locale=".concat(locale).concat("]");
580
581 XPath xPathSelector = SAXReaderUtil.createXPath(xPathExpression);
582
583 Node node = xPathSelector.selectSingleNode(element);
584
585 Element metaDataElement = (Element)node.asXPathResult(node.getParent());
586
587 if (metaDataElement != null) {
588 List<Element> childMetaDataElements = metaDataElement.elements();
589
590 for (Element childMetaDataElement : childMetaDataElements) {
591 String name = childMetaDataElement.attributeValue("name");
592 String value = childMetaDataElement.getText();
593
594 field.put(name, value);
595 }
596 }
597
598 for (Attribute attribute : element.attributes()) {
599 field.put(attribute.getName(), attribute.getValue());
600 }
601
602 Element parentElement = element.getParent();
603
604 if (parentElement != null) {
605 String parentName = parentElement.attributeValue("name");
606
607 if (Validator.isNotNull(parentName)) {
608 field.put(_getPrivateAttributeKey("parentName"), parentName);
609 }
610 }
611
612 return field;
613 }
614
615 private String _getPrivateAttributeKey(String attributeName) {
616 return StringPool.UNDERLINE.concat(attributeName).concat(
617 StringPool.UNDERLINE);
618 }
619
620 private Map<String, String> _getPrivateField(String privateFieldName) {
621 Map<String, String> privateField = new HashMap<String, String>();
622
623 String dataType = PropsUtil.get(
624 PropsKeys.DYNAMIC_DATA_MAPPING_STRUCTURE_PRIVATE_FIELD_DATATYPE,
625 new Filter(privateFieldName));
626
627 privateField.put("dataType", dataType);
628
629 privateField.put("name", privateFieldName);
630 privateField.put("private", Boolean.TRUE.toString());
631
632 String repeatable = PropsUtil.get(
633 PropsKeys.DYNAMIC_DATA_MAPPING_STRUCTURE_PRIVATE_FIELD_REPEATABLE,
634 new Filter(privateFieldName));
635
636 privateField.put("repeatable", repeatable);
637
638 return privateField;
639 }
640
641 private void _indexFieldsMap(String locale)
642 throws PortalException, SystemException {
643
644 Map<String, Map<String, Map<String, String>>> localizedFieldsMap =
645 getLocalizedFieldsMap();
646
647 Map<String, Map<String, String>> fieldsMap = localizedFieldsMap.get(
648 locale);
649
650 Map<String, Map<String, Map<String, String>>>
651 localizedPersistentFieldsMap = getLocalizedPersistentFieldsMap();
652
653 Map<String, Map<String, String>> persistentFieldsMap =
654 localizedPersistentFieldsMap.get(locale);
655
656 Map<String, Map<String, Map<String, String>>>
657 localizedTransientFieldsMap = getLocalizedTransientFieldsMap();
658
659 Map<String, Map<String, String>> transientFieldsMap =
660 localizedTransientFieldsMap.get(locale);
661
662 if (fieldsMap != null) {
663 return;
664 }
665
666 fieldsMap = new LinkedHashMap<String, Map<String, String>>();
667 persistentFieldsMap = new LinkedHashMap<String, Map<String, String>>();
668 transientFieldsMap = new LinkedHashMap<String, Map<String, String>>();
669
670 if (getParentStructureId() > 0) {
671 DDMStructure parentStructure =
672 DDMStructureLocalServiceUtil.getStructure(
673 getParentStructureId());
674
675 fieldsMap.putAll(parentStructure.getFieldsMap(locale, true));
676 persistentFieldsMap.putAll(
677 parentStructure.getPersistentFieldsMap(locale));
678 transientFieldsMap.putAll(
679 parentStructure.getTransientFieldsMap(locale));
680 }
681
682 XPath xPathSelector = SAXReaderUtil.createXPath("
683
684 List<Node> nodes = xPathSelector.selectNodes(getDocument());
685
686 for (Node node : nodes) {
687 Element element = (Element)node;
688
689 String name = element.attributeValue("name");
690
691 fieldsMap.put(name, _getField(element, locale));
692
693 if (Validator.isNotNull(element.attributeValue("dataType"))) {
694 persistentFieldsMap.put(name, _getField(element, locale));
695 }
696 else {
697 transientFieldsMap.put(name, _getField(element, locale));
698 }
699 }
700
701 String[] privateFieldNames =
702 PropsValues.DYNAMIC_DATA_MAPPING_STRUCTURE_PRIVATE_FIELD_NAMES;
703
704 for (String privateFieldName : privateFieldNames) {
705 Map<String, String> privateField = _getPrivateField(
706 privateFieldName);
707
708 fieldsMap.put(privateFieldName, privateField);
709 persistentFieldsMap.put(privateFieldName, privateField);
710 }
711
712 localizedFieldsMap.put(locale, fieldsMap);
713 localizedPersistentFieldsMap.put(locale, persistentFieldsMap);
714 localizedTransientFieldsMap.put(locale, transientFieldsMap);
715 }
716
717 private String _mergeXsds(String xsd1, String xsd2) throws SystemException {
718 try {
719 Document document1 = SAXReaderUtil.read(xsd1);
720 Document document2 = SAXReaderUtil.read(xsd2);
721
722 Element rootElement1 = document1.getRootElement();
723 Element rootElement2 = document2.getRootElement();
724
725 for (Element element : rootElement1.elements()) {
726 rootElement1.remove(element);
727
728 rootElement2.add(element);
729 }
730
731 return rootElement2.formattedString();
732 }
733 catch (Exception e) {
734 throw new SystemException(e);
735 }
736 }
737
738 private static Log _log = LogFactoryUtil.getLog(DDMStructureImpl.class);
739
740 @CacheField
741 private Document _document;
742
743 @CacheField
744 private Map<String, Map<String, Map<String, String>>> _localizedFieldsMap;
745
746 @CacheField
747 private Map<String, Map<String, Map<String, String>>>
748 _localizedPersistentFieldsMap;
749
750 @CacheField
751 private Map<String, Map<String, Map<String, String>>>
752 _localizedTransientFieldsMap;
753
754 }