001    /**
002     * Copyright (c) 2000-2012 Liferay, Inc. All rights reserved.
003     *
004     * The contents of this file are subject to the terms of the Liferay Enterprise
005     * Subscription License ("License"). You may not use this file except in
006     * compliance with the License. You can obtain a copy of the License by
007     * contacting Liferay, Inc. See the License for the specific language governing
008     * permissions and limitations under the License, including but not limited to
009     * distribution rights of the Software.
010     *
011     *
012     *
013     */
014    
015    package com.liferay.portlet.dynamicdatamapping.model.impl;
016    
017    import com.liferay.portal.LocaleException;
018    import com.liferay.portal.kernel.exception.SystemException;
019    import com.liferay.portal.kernel.log.Log;
020    import com.liferay.portal.kernel.log.LogFactoryUtil;
021    import com.liferay.portal.kernel.util.GetterUtil;
022    import com.liferay.portal.kernel.util.HtmlUtil;
023    import com.liferay.portal.kernel.util.ListUtil;
024    import com.liferay.portal.kernel.util.LocaleUtil;
025    import com.liferay.portal.kernel.util.StringBundler;
026    import com.liferay.portal.kernel.util.StringUtil;
027    import com.liferay.portal.kernel.xml.Attribute;
028    import com.liferay.portal.kernel.xml.Document;
029    import com.liferay.portal.kernel.xml.Element;
030    import com.liferay.portal.kernel.xml.Node;
031    import com.liferay.portal.kernel.xml.SAXReaderUtil;
032    import com.liferay.portal.kernel.xml.XPath;
033    import com.liferay.portal.model.CacheField;
034    import com.liferay.portlet.dynamicdatamapping.StructureFieldException;
035    import com.liferay.portlet.dynamicdatamapping.model.DDMTemplate;
036    import com.liferay.portlet.dynamicdatamapping.service.DDMTemplateLocalServiceUtil;
037    import com.liferay.portlet.dynamicdatamapping.util.DDMXMLUtil;
038    
039    import java.util.HashMap;
040    import java.util.Iterator;
041    import java.util.LinkedHashMap;
042    import java.util.List;
043    import java.util.Locale;
044    import java.util.Map;
045    import java.util.Set;
046    import java.util.concurrent.ConcurrentHashMap;
047    
048    /**
049     * @author Brian Wing Shun Chan
050     */
051    public class DDMStructureImpl extends DDMStructureBaseImpl {
052    
053            public DDMStructureImpl() {
054            }
055    
056            public List<String> getAvailableLocales() {
057                    Document document = getDocument();
058    
059                    Element rootElement = document.getRootElement();
060    
061                    String availableLocales = rootElement.attributeValue(
062                            "available-locales");
063    
064                    return ListUtil.fromArray(StringUtil.split(availableLocales));
065            }
066    
067            public String getDefaultLocale() {
068                    Document document = getDocument();
069    
070                    if (document == null) {
071                            Locale locale = LocaleUtil.getDefault();
072    
073                            return locale.toString();
074                    }
075    
076                    Element rootElement = document.getRootElement();
077    
078                    return rootElement.attributeValue("default-locale");
079            }
080    
081            @Override
082            public Document getDocument() {
083                    if (_document == null) {
084                            try {
085                                    _document = SAXReaderUtil.read(getXsd());
086                            }
087                            catch (Exception e) {
088                                    StackTraceElement[] stackTraceElements = e.getStackTrace();
089    
090                                    for (StackTraceElement stackTraceElement : stackTraceElements) {
091                                            String className = stackTraceElement.getClassName();
092    
093                                            if (className.endsWith("DDMStructurePersistenceTest")) {
094                                                    return null;
095                                            }
096                                    }
097    
098                                    _log.error(e, e);
099                            }
100                    }
101    
102                    return _document;
103            }
104    
105            public String getFieldDataType(String fieldName)
106                    throws StructureFieldException {
107    
108                    return getFieldProperty(fieldName, "dataType");
109            }
110    
111            public String getFieldLabel(String fieldName, Locale locale)
112                    throws StructureFieldException {
113    
114                    return getFieldLabel(fieldName, LocaleUtil.toLanguageId(locale));
115            }
116    
117            public String getFieldLabel(String fieldName, String locale)
118                    throws StructureFieldException {
119    
120                    return GetterUtil.getString(
121                            getFieldProperty(fieldName, "label", locale), fieldName);
122            }
123    
124            public Set<String> getFieldNames() {
125                    Map<String, Map<String, String>> fieldsMap = getFieldsMap();
126    
127                    return fieldsMap.keySet();
128            }
129    
130            public String getFieldProperty(String fieldName, String property)
131                    throws StructureFieldException {
132    
133                    return getFieldProperty(fieldName, property, getDefaultLocale());
134            }
135    
136            public String getFieldProperty(
137                            String fieldName, String property, String locale)
138                    throws StructureFieldException {
139    
140                    if (!hasField(fieldName)) {
141                            throw new StructureFieldException();
142                    }
143    
144                    Map<String, Map<String, String>> fieldsMap = _getFieldsMap(locale);
145    
146                    Map<String, String> field = fieldsMap.get(fieldName);
147    
148                    return field.get(property);
149            }
150    
151            public boolean getFieldRequired(String fieldName)
152                    throws StructureFieldException {
153    
154                    return GetterUtil.getBoolean(getFieldProperty(fieldName, "required"));
155            }
156    
157            public Map<String, String> getFields(
158                    String fieldName, String attributeName, String attributeValue) {
159    
160                    return getFields(
161                            fieldName, attributeName, attributeValue, getDefaultLocale());
162            }
163    
164            public Map<String, String> getFields(
165                    String fieldName, String attributeName, String attributeValue,
166                    String locale) {
167    
168                    try {
169                            StringBundler sb = new StringBundler(7);
170    
171                            sb.append("//dynamic-element[@name=");
172                            sb.append(HtmlUtil.escapeXPathAttribute(fieldName));
173                            sb.append("] //dynamic-element[@");
174                            sb.append(HtmlUtil.escapeXPath(attributeName));
175                            sb.append("=");
176                            sb.append(HtmlUtil.escapeXPathAttribute(attributeValue));
177                            sb.append("]");
178    
179                            XPath xPathSelector = SAXReaderUtil.createXPath(sb.toString());
180    
181                            Node node = xPathSelector.selectSingleNode(getDocument());
182    
183                            if (node != null) {
184                                    return _getField(
185                                            (Element)node.asXPathResult(node.getParent()), locale);
186                            }
187                    }
188                    catch (Exception e) {
189                            _log.error(e, e);
190                    }
191    
192                    return null;
193            }
194    
195            public Map<String, Map<String, String>> getFieldsMap() {
196                    return _getFieldsMap(getDefaultLocale());
197            }
198    
199            public Map<String, Map<String, String>> getFieldsMap(String locale) {
200                    return _getFieldsMap(locale);
201            }
202    
203            public String getFieldType(String fieldName)
204                    throws StructureFieldException {
205    
206                    return getFieldProperty(fieldName, "type");
207            }
208    
209            public List<DDMTemplate> getTemplates() throws SystemException {
210                    return DDMTemplateLocalServiceUtil.getTemplates(getStructureId());
211            }
212    
213            public boolean hasField(String fieldName) {
214                    Map<String, Map<String, String>> fieldsMap = getFieldsMap();
215    
216                    return fieldsMap.containsKey(fieldName);
217            }
218    
219            @Override
220            public void prepareLocalizedFieldsForImport(Locale defaultImportLocale)
221                    throws LocaleException {
222    
223                    super.prepareLocalizedFieldsForImport(defaultImportLocale);
224    
225                    Locale ddmStructureDefaultLocale = LocaleUtil.fromLanguageId(
226                            getDefaultLocale());
227    
228                    try {
229                            setXsd(
230                                    DDMXMLUtil.updateXMLDefaultLocale(
231                                            getXsd(), ddmStructureDefaultLocale, defaultImportLocale));
232                    }
233                    catch (Exception e) {
234                            throw new LocaleException(e);
235                    }
236            }
237    
238            @Override
239            public void setDocument(Document document) {
240                    _document = document;
241            }
242    
243            public void setLocalizedFieldsMap(
244                    Map<String, Map<String, Map<String, String>>> localizedFieldsMap) {
245    
246                    _localizedFieldsMap = localizedFieldsMap;
247            }
248    
249            @Override
250            public void setXsd(String xsd) {
251                    super.setXsd(xsd);
252    
253                    _document = null;
254                    _localizedFieldsMap.clear();
255            }
256    
257            private Map<String, String> _getField(Element element, String locale) {
258                    Map<String, String> field = new HashMap<String, String>();
259    
260                    List<String> availableLocales = getAvailableLocales();
261    
262                    if ((locale != null) && !availableLocales.contains(locale)) {
263                            locale = getDefaultLocale();
264                    }
265    
266                    String xPathExpression =
267                            "meta-data[@locale=\"".concat(locale).concat("\"]");
268    
269                    XPath xPathSelector = SAXReaderUtil.createXPath(xPathExpression);
270    
271                    Node node = xPathSelector.selectSingleNode(element);
272    
273                    Element metaDataElement = (Element)node.asXPathResult(node.getParent());
274    
275                    if (metaDataElement != null) {
276                            List<Element> childMetaDataElements = metaDataElement.elements();
277    
278                            for (Element childMetaDataElement : childMetaDataElements) {
279                                    String name = childMetaDataElement.attributeValue("name");
280                                    String value = childMetaDataElement.getText();
281    
282                                    field.put(name, value);
283                            }
284                    }
285    
286                    for (Attribute attribute : element.attributes()) {
287                            field.put(attribute.getName(), attribute.getValue());
288                    }
289    
290                    return field;
291            }
292    
293            private Map<String, Map<String, String>> _getFieldsMap(String locale) {
294                    Map<String, Map<String, String>> fieldsMap = _localizedFieldsMap.get(
295                            locale);
296    
297                    if (fieldsMap == null) {
298                            fieldsMap = new LinkedHashMap<String, Map<String, String>>();
299    
300                            XPath xPathSelector = SAXReaderUtil.createXPath(
301                                    "//dynamic-element[@dataType]");
302    
303                            List<Node> nodes = xPathSelector.selectNodes(getDocument());
304    
305                            Iterator<Node> itr = nodes.iterator();
306    
307                            while (itr.hasNext()) {
308                                    Element element = (Element)itr.next();
309    
310                                    String name = element.attributeValue("name");
311    
312                                    fieldsMap.put(name, _getField(element, locale));
313                            }
314    
315                            _localizedFieldsMap.put(locale, fieldsMap);
316                    }
317    
318                    return fieldsMap;
319            }
320    
321            private static Log _log = LogFactoryUtil.getLog(DDMStructureImpl.class);
322    
323            @CacheField
324            private Document _document;
325    
326            private Map<String, Map<String, Map<String, String>>> _localizedFieldsMap =
327                    new ConcurrentHashMap<String, Map<String, Map<String, String>>>();
328    
329    }