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