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