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.GetterUtil;
024 import com.liferay.portal.kernel.util.HtmlUtil;
025 import com.liferay.portal.kernel.util.ListUtil;
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 public List<String> getAvailableLanguageIds() {
066 Document document = getDocument();
067
068 Element rootElement = document.getRootElement();
069
070 String availableLocales = rootElement.attributeValue(
071 "available-locales");
072
073 return ListUtil.fromArray(StringUtil.split(availableLocales));
074 }
075
076 public List<String> getChildrenFieldNames(String fieldName)
077 throws PortalException, SystemException {
078
079 List<String> fieldNames = new ArrayList<String>();
080
081 Map<String, Map<String, String>> fieldsMap = getFieldsMap();
082
083 for (Map<String, String> field : fieldsMap.values()) {
084 String parentNameKey = _getPrivateAttributeKey("parentName");
085
086 String parentName = field.get(parentNameKey);
087
088 if (fieldName.equals(parentName)) {
089 fieldNames.add(field.get("name"));
090 }
091 }
092
093 return fieldNames;
094 }
095
096 public String getCompleteXsd() throws PortalException, SystemException {
097 if (getParentStructureId() == 0) {
098 return getXsd();
099 }
100
101 DDMStructure parentStructure =
102 DDMStructureLocalServiceUtil.getStructure(getParentStructureId());
103
104 return _mergeXsds(getXsd(), parentStructure.getCompleteXsd());
105 }
106
107 public String getDefaultLanguageId() {
108 Document document = getDocument();
109
110 if (document == null) {
111 Locale locale = LocaleUtil.getDefault();
112
113 return locale.toString();
114 }
115
116 Element rootElement = document.getRootElement();
117
118 return rootElement.attributeValue("default-locale");
119 }
120
121 @Override
122 public Document getDocument() {
123 if (_document == null) {
124 try {
125 _document = SAXReaderUtil.read(getXsd());
126 }
127 catch (Exception e) {
128 StackTraceElement[] stackTraceElements = e.getStackTrace();
129
130 for (StackTraceElement stackTraceElement : stackTraceElements) {
131 String className = stackTraceElement.getClassName();
132
133 if (className.endsWith("DDMStructurePersistenceTest")) {
134 return null;
135 }
136 }
137
138 _log.error(e, e);
139 }
140 }
141
142 return _document;
143 }
144
145 public String getFieldDataType(String fieldName)
146 throws PortalException, SystemException {
147
148 return getFieldProperty(fieldName, "dataType");
149 }
150
151 public String getFieldLabel(String fieldName, Locale locale)
152 throws PortalException, SystemException {
153
154 return getFieldLabel(fieldName, LocaleUtil.toLanguageId(locale));
155 }
156
157 public String getFieldLabel(String fieldName, String locale)
158 throws PortalException, SystemException {
159
160 return GetterUtil.getString(
161 getFieldProperty(fieldName, "label", locale), fieldName);
162 }
163
164 public Set<String> getFieldNames() throws PortalException, SystemException {
165 Map<String, Map<String, String>> fieldsMap = getFieldsMap();
166
167 return fieldsMap.keySet();
168 }
169
170 public String getFieldProperty(String fieldName, String property)
171 throws PortalException, SystemException {
172
173 return getFieldProperty(fieldName, property, getDefaultLanguageId());
174 }
175
176 public String getFieldProperty(
177 String fieldName, String property, String locale)
178 throws PortalException, SystemException {
179
180 if (!hasField(fieldName)) {
181 throw new StructureFieldException();
182 }
183
184 Map<String, Map<String, String>> fieldsMap = getFieldsMap(locale);
185
186 Map<String, String> field = fieldsMap.get(fieldName);
187
188 return field.get(property);
189 }
190
191 public boolean getFieldRepeatable(String fieldName)
192 throws PortalException, SystemException {
193
194 return GetterUtil.getBoolean(getFieldProperty(fieldName, "repeatable"));
195 }
196
197 public boolean getFieldRequired(String fieldName)
198 throws PortalException, SystemException {
199
200 return GetterUtil.getBoolean(getFieldProperty(fieldName, "required"));
201 }
202
203 public Map<String, String> getFields(
204 String fieldName, String attributeName, String attributeValue) {
205
206 return getFields(
207 fieldName, attributeName, attributeValue, getDefaultLanguageId());
208 }
209
210 public Map<String, String> getFields(
211 String fieldName, String attributeName, String attributeValue,
212 String locale) {
213
214 try {
215 if ((attributeName == null) || (attributeValue == null)) {
216 return null;
217 }
218
219 Map<String, Map<String, String>> fieldsMap = getTransientFieldsMap(
220 locale);
221
222 for (Map<String, String> fields : fieldsMap.values()) {
223 String parentName = fields.get(
224 _getPrivateAttributeKey("parentName"));
225
226 if (!fieldName.equals(parentName)) {
227 continue;
228 }
229
230 if (attributeValue.equals(fields.get(attributeName))) {
231 return fields;
232 }
233 }
234 }
235 catch (Exception e) {
236 _log.error(e, e);
237 }
238
239 return null;
240 }
241
242 public Map<String, Map<String, String>> getFieldsMap()
243 throws PortalException, SystemException {
244
245 return getFieldsMap(getDefaultLanguageId());
246 }
247
248 public Map<String, Map<String, String>> getFieldsMap(String locale)
249 throws PortalException, SystemException {
250
251 _indexFieldsMap(locale);
252
253 Map<String, Map<String, String>> fieldsMap = _localizedFieldsMap.get(
254 locale);
255
256 return fieldsMap;
257 }
258
259 public String getFieldTip(String fieldName, Locale locale)
260 throws PortalException, SystemException {
261
262 return getFieldTip(fieldName, LocaleUtil.toLanguageId(locale));
263 }
264
265 public String getFieldTip(String fieldName, String locale)
266 throws PortalException, SystemException {
267
268 return GetterUtil.getString(
269 getFieldProperty(fieldName, "tip", locale), fieldName);
270 }
271
272 public String getFieldType(String fieldName)
273 throws PortalException, SystemException {
274
275 return getFieldProperty(fieldName, "type");
276 }
277
278 @Override
279 public Map<String, Map<String, Map<String, String>>>
280 getLocalizedFieldsMap() {
281
282 return _localizedFieldsMap;
283 }
284
285 @Override
286 public Map<String, Map<String, Map<String, String>>>
287 getLocalizedTransientFieldsMap() {
288
289 return _localizedTransientFieldsMap;
290 }
291
292 public List<String> getRootFieldNames()
293 throws PortalException, SystemException {
294
295 List<String> fieldNames = new ArrayList<String>();
296
297 Map<String, Map<String, String>> fieldsMap = getFieldsMap();
298
299 for (Map.Entry<String, Map<String, String>> entry :
300 fieldsMap.entrySet()) {
301
302 Map<String, String> field = entry.getValue();
303
304 String parentNameKey = _getPrivateAttributeKey("parentName");
305
306 if (!field.containsKey(parentNameKey)) {
307 fieldNames.add(entry.getKey());
308 }
309 }
310
311 return fieldNames;
312 }
313
314 public List<DDMTemplate> getTemplates() throws SystemException {
315 return DDMTemplateLocalServiceUtil.getTemplates(getStructureId());
316 }
317
318 public Map<String, Map<String, String>> getTransientFieldsMap(String locale)
319 throws PortalException, SystemException {
320
321 _indexFieldsMap(locale);
322
323 Map<String, Map<String, String>> fieldsMap =
324 _localizedTransientFieldsMap.get(locale);
325
326 return fieldsMap;
327 }
328
329
338 public String getWebDavURL(ThemeDisplay themeDisplay, String webDAVToken) {
339 StringBundler sb = new StringBundler(11);
340
341 boolean secure = false;
342
343 if (themeDisplay.isSecure() ||
344 PropsValues.WEBDAV_SERVLET_HTTPS_REQUIRED) {
345
346 secure = true;
347 }
348
349 String portalURL = PortalUtil.getPortalURL(
350 themeDisplay.getServerName(), themeDisplay.getServerPort(), secure);
351
352 sb.append(portalURL);
353
354 sb.append(themeDisplay.getPathContext());
355 sb.append(StringPool.SLASH);
356 sb.append("webdav");
357
358 Group group = themeDisplay.getScopeGroup();
359
360 sb.append(group.getFriendlyURL());
361
362 sb.append(StringPool.SLASH);
363 sb.append(webDAVToken);
364 sb.append(StringPool.SLASH);
365 sb.append("Structures");
366 sb.append(StringPool.SLASH);
367 sb.append(getStructureId());
368
369 return sb.toString();
370 }
371
372 public boolean hasField(String fieldName)
373 throws PortalException, SystemException {
374
375 Map<String, Map<String, String>> fieldsMap = getFieldsMap();
376
377 boolean hasField = fieldsMap.containsKey(fieldName);
378
379 while (!hasField && (getParentStructureId() > 0)) {
380 DDMStructure parentStructure =
381 DDMStructureLocalServiceUtil.getStructure(
382 getParentStructureId());
383
384 hasField = parentStructure.hasField(fieldName);
385 }
386
387 return hasField;
388 }
389
390 public boolean isFieldPrivate(String fieldName)
391 throws PortalException, SystemException {
392
393 return GetterUtil.getBoolean(getFieldProperty(fieldName, "private"));
394 }
395
396 public boolean isFieldRepeatable(String fieldName)
397 throws PortalException, SystemException {
398
399 return GetterUtil.getBoolean(getFieldProperty(fieldName, "repeatable"));
400 }
401
402 @Override
403 public void prepareLocalizedFieldsForImport(Locale defaultImportLocale)
404 throws LocaleException {
405
406 super.prepareLocalizedFieldsForImport(defaultImportLocale);
407
408 Locale ddmStructureDefaultLocale = LocaleUtil.fromLanguageId(
409 getDefaultLanguageId());
410
411 try {
412 setXsd(
413 DDMXMLUtil.updateXMLDefaultLocale(
414 getXsd(), ddmStructureDefaultLocale, defaultImportLocale));
415 }
416 catch (Exception e) {
417 throw new LocaleException(e);
418 }
419 }
420
421 @Override
422 public void setDocument(Document document) {
423 _document = document;
424 }
425
426 @Override
427 public void setLocalizedFieldsMap(
428 Map<String, Map<String, Map<String, String>>> localizedFieldsMap) {
429
430 _localizedFieldsMap = localizedFieldsMap;
431 }
432
433 @Override
434 public void setLocalizedTransientFieldsMap(
435 Map<String, Map<String, Map<String, String>>>
436 localizedTransientFieldsMap) {
437
438 _localizedTransientFieldsMap = localizedTransientFieldsMap;
439 }
440
441 @Override
442 public void setXsd(String xsd) {
443 super.setXsd(xsd);
444
445 _document = null;
446 _localizedFieldsMap.clear();
447 _localizedTransientFieldsMap.clear();
448 }
449
450 private Map<String, String> _getField(Element element, String locale) {
451 Map<String, String> field = new HashMap<String, String>();
452
453 List<String> availableLocales = getAvailableLanguageIds();
454
455 if ((locale != null) && !availableLocales.contains(locale)) {
456 locale = getDefaultLanguageId();
457 }
458
459 locale = HtmlUtil.escapeXPathAttribute(locale);
460
461 String xPathExpression =
462 "meta-data[@locale=".concat(locale).concat("]");
463
464 XPath xPathSelector = SAXReaderUtil.createXPath(xPathExpression);
465
466 Node node = xPathSelector.selectSingleNode(element);
467
468 Element metaDataElement = (Element)node.asXPathResult(node.getParent());
469
470 if (metaDataElement != null) {
471 List<Element> childMetaDataElements = metaDataElement.elements();
472
473 for (Element childMetaDataElement : childMetaDataElements) {
474 String name = childMetaDataElement.attributeValue("name");
475 String value = childMetaDataElement.getText();
476
477 field.put(name, value);
478 }
479 }
480
481 for (Attribute attribute : element.attributes()) {
482 field.put(attribute.getName(), attribute.getValue());
483 }
484
485 Element parentElement = element.getParent();
486
487 if (parentElement != null) {
488 String parentName = parentElement.attributeValue("name");
489
490 if (Validator.isNotNull(parentName)) {
491 field.put(_getPrivateAttributeKey("parentName"), parentName);
492 }
493 }
494
495 return field;
496 }
497
498 private String _getPrivateAttributeKey(String attributeName) {
499 return StringPool.UNDERLINE.concat(attributeName).concat(
500 StringPool.UNDERLINE);
501 }
502
503 private Map<String, String> _getPrivateField(String privateFieldName) {
504 Map<String, String> privateField = new HashMap<String, String>();
505
506 String dataType = PropsUtil.get(
507 PropsKeys.DYNAMIC_DATA_MAPPING_STRUCTURE_PRIVATE_FIELD_DATATYPE,
508 new Filter(privateFieldName));
509
510 privateField.put("dataType", dataType);
511
512 privateField.put("private", Boolean.TRUE.toString());
513
514 String repeatable = PropsUtil.get(
515 PropsKeys.DYNAMIC_DATA_MAPPING_STRUCTURE_PRIVATE_FIELD_REPEATABLE,
516 new Filter(privateFieldName));
517
518 privateField.put("repeatable", repeatable);
519
520 return privateField;
521 }
522
523 private void _indexFieldsMap(String locale)
524 throws PortalException, SystemException {
525
526 Map<String, Map<String, String>> fieldsMap = _localizedFieldsMap.get(
527 locale);
528 Map<String, Map<String, String>> transientFieldsMap =
529 _localizedTransientFieldsMap.get(locale);
530
531 if (fieldsMap != null) {
532 return;
533 }
534
535 if (getParentStructureId() > 0) {
536 DDMStructure parentStructure =
537 DDMStructureLocalServiceUtil.getStructure(
538 getParentStructureId());
539
540 fieldsMap = parentStructure.getFieldsMap(locale);
541 transientFieldsMap = parentStructure.getTransientFieldsMap(locale);
542 }
543 else {
544 fieldsMap = new LinkedHashMap<String, Map<String, String>>();
545 transientFieldsMap =
546 new LinkedHashMap<String, Map<String, String>>();
547 }
548
549 XPath xPathSelector = SAXReaderUtil.createXPath("
550
551 List<Node> nodes = xPathSelector.selectNodes(getDocument());
552
553 for (Node node : nodes) {
554 Element element = (Element)node;
555
556 String name = element.attributeValue("name");
557
558 if (Validator.isNotNull(element.attributeValue("dataType"))) {
559 fieldsMap.put(name, _getField(element, locale));
560 }
561 else {
562 transientFieldsMap.put(name, _getField(element, locale));
563 }
564 }
565
566 String[] privateFieldNames =
567 PropsValues.DYNAMIC_DATA_MAPPING_STRUCTURE_PRIVATE_FIELD_NAMES;
568
569 for (String privateFieldName : privateFieldNames) {
570 Map<String, String> privateField = _getPrivateField(
571 privateFieldName);
572
573 fieldsMap.put(privateFieldName, privateField);
574 }
575
576 _localizedFieldsMap.put(locale, fieldsMap);
577 _localizedTransientFieldsMap.put(locale, transientFieldsMap);
578 }
579
580 private String _mergeXsds(String xsd1, String xsd2) throws SystemException {
581 try {
582 Document document1 = SAXReaderUtil.read(xsd1);
583 Document document2 = SAXReaderUtil.read(xsd2);
584
585 Element rootElement1 = document1.getRootElement();
586 Element rootElement2 = document2.getRootElement();
587
588 for (Element element : rootElement1.elements()) {
589 rootElement1.remove(element);
590
591 rootElement2.add(element);
592 }
593
594 return rootElement2.formattedString();
595 }
596 catch (Exception e) {
597 throw new SystemException(e);
598 }
599 }
600
601 private static Log _log = LogFactoryUtil.getLog(DDMStructureImpl.class);
602
603 @CacheField
604 private Document _document;
605
606 @CacheField
607 private Map<String, Map<String, Map<String, String>>> _localizedFieldsMap =
608 new ConcurrentHashMap<String, Map<String, Map<String, String>>>();
609
610 @CacheField
611 private Map<String, Map<String, Map<String, String>>>
612 _localizedTransientFieldsMap =
613 new ConcurrentHashMap<String, Map<String, Map<String, String>>>();
614
615 }