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 @Override
281 public void prepareLocalizedFieldsForImport(Locale defaultImportLocale)
282 throws LocaleException {
283
284 super.prepareLocalizedFieldsForImport(defaultImportLocale);
285
286 Locale ddmStructureDefaultLocale = LocaleUtil.fromLanguageId(
287 getDefaultLanguageId());
288
289 try {
290 setXsd(
291 DDMXMLUtil.updateXMLDefaultLocale(
292 getXsd(), ddmStructureDefaultLocale, defaultImportLocale));
293 }
294 catch (Exception e) {
295 throw new LocaleException(e);
296 }
297 }
298
299 @Override
300 public void setDocument(Document document) {
301 _document = document;
302 }
303
304 @Override
305 public void setLocalizedFieldsMap(
306 Map<String, Map<String, Map<String, String>>> localizedFieldsMap) {
307
308 _localizedFieldsMap = localizedFieldsMap;
309 }
310
311 @Override
312 public void setLocalizedTransientFieldsMap(
313 Map<String, Map<String, Map<String, String>>>
314 localizedTransientFieldsMap) {
315
316 _localizedTransientFieldsMap = localizedTransientFieldsMap;
317 }
318
319 @Override
320 public void setXsd(String xsd) {
321 super.setXsd(xsd);
322
323 _document = null;
324 _localizedFieldsMap.clear();
325 _localizedTransientFieldsMap.clear();
326 }
327
328 private Map<String, String> _getField(Element element, String locale) {
329 Map<String, String> field = new HashMap<String, String>();
330
331 List<String> availableLocales = getAvailableLanguageIds();
332
333 if ((locale != null) && !availableLocales.contains(locale)) {
334 locale = getDefaultLanguageId();
335 }
336
337 locale = HtmlUtil.escapeXPathAttribute(locale);
338
339 String xPathExpression =
340 "meta-data[@locale=".concat(locale).concat("]");
341
342 XPath xPathSelector = SAXReaderUtil.createXPath(xPathExpression);
343
344 Node node = xPathSelector.selectSingleNode(element);
345
346 Element metaDataElement = (Element)node.asXPathResult(node.getParent());
347
348 if (metaDataElement != null) {
349 List<Element> childMetaDataElements = metaDataElement.elements();
350
351 for (Element childMetaDataElement : childMetaDataElements) {
352 String name = childMetaDataElement.attributeValue("name");
353 String value = childMetaDataElement.getText();
354
355 field.put(name, value);
356 }
357 }
358
359 for (Attribute attribute : element.attributes()) {
360 field.put(attribute.getName(), attribute.getValue());
361 }
362
363 Element parentElement = element.getParent();
364
365 if (parentElement != null) {
366 String parentName = parentElement.attributeValue("name");
367
368 if (Validator.isNotNull(parentName)) {
369 field.put(_getPrivateAttributeKey("parentName"), parentName);
370 }
371 }
372
373 return field;
374 }
375
376 private String _getPrivateAttributeKey(String attributeName) {
377 return StringPool.UNDERLINE.concat(attributeName).concat(
378 StringPool.UNDERLINE);
379 }
380
381 private void _indexFieldsMap(String locale)
382 throws PortalException, SystemException {
383
384 Map<String, Map<String, String>> fieldsMap = _localizedFieldsMap.get(
385 locale);
386 Map<String, Map<String, String>> transientFieldsMap =
387 _localizedTransientFieldsMap.get(locale);
388
389 if (fieldsMap != null) {
390 return;
391 }
392
393 if (getParentStructureId() > 0) {
394 DDMStructure parentStructure =
395 DDMStructureLocalServiceUtil.getStructure(
396 getParentStructureId());
397
398 fieldsMap = parentStructure.getFieldsMap(locale);
399 transientFieldsMap = parentStructure.getTransientFieldsMap(locale);
400 }
401 else {
402 fieldsMap = new LinkedHashMap<String, Map<String, String>>();
403 transientFieldsMap =
404 new LinkedHashMap<String, Map<String, String>>();
405 }
406
407 XPath xPathSelector = SAXReaderUtil.createXPath("
408
409 List<Node> nodes = xPathSelector.selectNodes(getDocument());
410
411 for (Node node : nodes) {
412 Element element = (Element)node;
413
414 String name = element.attributeValue("name");
415
416 if (Validator.isNotNull(element.attributeValue("dataType"))) {
417 fieldsMap.put(name, _getField(element, locale));
418 }
419 else {
420 transientFieldsMap.put(name, _getField(element, locale));
421 }
422 }
423
424 _localizedFieldsMap.put(locale, fieldsMap);
425 _localizedTransientFieldsMap.put(locale, transientFieldsMap);
426 }
427
428 private String _mergeXsds(String xsd1, String xsd2) throws SystemException {
429 try {
430 Document document1 = SAXReaderUtil.read(xsd1);
431 Document document2 = SAXReaderUtil.read(xsd2);
432
433 Element rootElement1 = document1.getRootElement();
434 Element rootElement2 = document2.getRootElement();
435
436 for (Element element : rootElement1.elements()) {
437 rootElement1.remove(element);
438
439 rootElement2.add(element);
440 }
441
442 return rootElement2.formattedString();
443 }
444 catch (Exception e) {
445 throw new SystemException(e);
446 }
447 }
448
449 private static Log _log = LogFactoryUtil.getLog(DDMStructureImpl.class);
450
451 @CacheField
452 private Document _document;
453
454 @CacheField
455 private Map<String, Map<String, Map<String, String>>> _localizedFieldsMap =
456 new ConcurrentHashMap<String, Map<String, Map<String, String>>>();
457
458 @CacheField
459 private Map<String, Map<String, Map<String, String>>>
460 _localizedTransientFieldsMap =
461 new ConcurrentHashMap<String, Map<String, Map<String, String>>>();
462
463 }