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