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