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