001    /**
002     * Copyright (c) 2000-present Liferay, Inc. All rights reserved.
003     *
004     * This library is free software; you can redistribute it and/or modify it under
005     * the terms of the GNU Lesser General Public License as published by the Free
006     * Software Foundation; either version 2.1 of the License, or (at your option)
007     * any later version.
008     *
009     * This library is distributed in the hope that it will be useful, but WITHOUT
010     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
011     * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
012     * details.
013     */
014    
015    package com.liferay.portlet.dynamicdatamapping.util;
016    
017    import com.liferay.portal.kernel.exception.PortalException;
018    import com.liferay.portal.kernel.exception.SystemException;
019    import com.liferay.portal.kernel.io.unsync.UnsyncStringWriter;
020    import com.liferay.portal.kernel.json.JSONArray;
021    import com.liferay.portal.kernel.json.JSONFactoryUtil;
022    import com.liferay.portal.kernel.json.JSONObject;
023    import com.liferay.portal.kernel.language.LanguageUtil;
024    import com.liferay.portal.kernel.security.pacl.DoPrivileged;
025    import com.liferay.portal.kernel.servlet.JSPSupportServlet;
026    import com.liferay.portal.kernel.template.Template;
027    import com.liferay.portal.kernel.template.TemplateConstants;
028    import com.liferay.portal.kernel.template.TemplateManagerUtil;
029    import com.liferay.portal.kernel.template.TemplateResource;
030    import com.liferay.portal.kernel.template.URLTemplateResource;
031    import com.liferay.portal.kernel.util.ArrayUtil;
032    import com.liferay.portal.kernel.util.CharPool;
033    import com.liferay.portal.kernel.util.GetterUtil;
034    import com.liferay.portal.kernel.util.HtmlUtil;
035    import com.liferay.portal.kernel.util.LocaleUtil;
036    import com.liferay.portal.kernel.util.LocalizationUtil;
037    import com.liferay.portal.kernel.util.ParamUtil;
038    import com.liferay.portal.kernel.util.StringBundler;
039    import com.liferay.portal.kernel.util.StringPool;
040    import com.liferay.portal.kernel.util.StringUtil;
041    import com.liferay.portal.kernel.util.Validator;
042    import com.liferay.portal.kernel.xml.Attribute;
043    import com.liferay.portal.kernel.xml.Document;
044    import com.liferay.portal.kernel.xml.DocumentException;
045    import com.liferay.portal.kernel.xml.Element;
046    import com.liferay.portal.kernel.xml.Node;
047    import com.liferay.portal.kernel.xml.SAXReaderUtil;
048    import com.liferay.portal.kernel.xml.XPath;
049    import com.liferay.portal.util.PortalUtil;
050    import com.liferay.portlet.dynamicdatamapping.io.DDMFormJSONDeserializerUtil;
051    import com.liferay.portlet.dynamicdatamapping.io.DDMFormXSDSerializerUtil;
052    import com.liferay.portlet.dynamicdatamapping.model.DDMForm;
053    import com.liferay.portlet.dynamicdatamapping.model.DDMStructure;
054    import com.liferay.portlet.dynamicdatamapping.model.DDMTemplate;
055    import com.liferay.portlet.dynamicdatamapping.model.DDMTemplateConstants;
056    import com.liferay.portlet.dynamicdatamapping.service.DDMStorageLinkLocalServiceUtil;
057    import com.liferay.portlet.dynamicdatamapping.service.DDMStructureLocalServiceUtil;
058    import com.liferay.portlet.dynamicdatamapping.service.DDMTemplateLocalServiceUtil;
059    import com.liferay.portlet.dynamicdatamapping.storage.Field;
060    import com.liferay.portlet.dynamicdatamapping.storage.Fields;
061    import com.liferay.util.freemarker.FreeMarkerTaglibFactoryUtil;
062    
063    import freemarker.ext.servlet.HttpRequestHashModel;
064    import freemarker.ext.servlet.ServletContextHashModel;
065    
066    import freemarker.template.ObjectWrapper;
067    import freemarker.template.TemplateHashModel;
068    
069    import java.io.Writer;
070    
071    import java.net.URL;
072    
073    import java.util.ArrayList;
074    import java.util.HashMap;
075    import java.util.List;
076    import java.util.Locale;
077    import java.util.Map;
078    
079    import javax.servlet.GenericServlet;
080    import javax.servlet.http.HttpServletRequest;
081    import javax.servlet.http.HttpServletResponse;
082    
083    /**
084     * @author Bruno Basto
085     * @author Eduardo Lundgren
086     * @author Brian Wing Shun Chan
087     * @author Marcellus Tavares
088     */
089    @DoPrivileged
090    public class DDMXSDImpl implements DDMXSD {
091    
092            public DDMXSDImpl() {
093                    String defaultTemplateId = _TPL_PATH + "alloy/text.ftl";
094    
095                    URL defaultTemplateURL = getResource(defaultTemplateId);
096    
097                    _defaultTemplateResource = new URLTemplateResource(
098                            defaultTemplateId, defaultTemplateURL);
099    
100                    String defaultReadOnlyTemplateId = _TPL_PATH + "readonly/default.ftl";
101    
102                    URL defaultReadOnlyTemplateURL = getResource(defaultReadOnlyTemplateId);
103    
104                    _defaultReadOnlyTemplateResource = new URLTemplateResource(
105                            defaultReadOnlyTemplateId, defaultReadOnlyTemplateURL);
106            }
107    
108            @Override
109            public String getFieldHTML(
110                            HttpServletRequest request, HttpServletResponse response,
111                            Element element, Fields fields, String portletNamespace,
112                            String namespace, String mode, boolean readOnly, Locale locale)
113                    throws Exception {
114    
115                    Map<String, Object> freeMarkerContext = getFreeMarkerContext(
116                            request, response, portletNamespace, namespace, element, locale);
117    
118                    if (fields != null) {
119                            freeMarkerContext.put("fields", fields);
120                    }
121    
122                    Map<String, Object> fieldStructure =
123                            (Map<String, Object>)freeMarkerContext.get("fieldStructure");
124    
125                    int fieldRepetition = 1;
126                    int offset = 0;
127    
128                    DDMFieldsCounter ddmFieldsCounter = getFieldsCounter(
129                            request, response, fields, portletNamespace, namespace);
130    
131                    String name = element.attributeValue("name");
132    
133                    String fieldDisplayValue = getFieldsDisplayValue(
134                            request, response, fields);
135    
136                    String[] fieldsDisplayValues = getFieldsDisplayValues(
137                            fieldDisplayValue);
138    
139                    boolean fieldDisplayable = ArrayUtil.contains(
140                            fieldsDisplayValues, name);
141    
142                    if (fieldDisplayable) {
143                            Map<String, Object> parentFieldStructure =
144                                    (Map<String, Object>)freeMarkerContext.get(
145                                            "parentFieldStructure");
146    
147                            String parentFieldName = (String)parentFieldStructure.get("name");
148    
149                            offset = getFieldOffset(
150                                    fieldsDisplayValues, name, ddmFieldsCounter.get(name));
151    
152                            if (offset == fieldsDisplayValues.length) {
153                                    return StringPool.BLANK;
154                            }
155    
156                            fieldRepetition = countFieldRepetition(
157                                    fieldsDisplayValues, parentFieldName, offset);
158                    }
159    
160                    StringBundler sb = new StringBundler(fieldRepetition);
161    
162                    while (fieldRepetition > 0) {
163                            offset = getFieldOffset(
164                                    fieldsDisplayValues, name, ddmFieldsCounter.get(name));
165    
166                            String fieldNamespace = StringUtil.randomId();
167    
168                            if (fieldDisplayable) {
169                                    fieldNamespace = getFieldNamespace(
170                                            fieldDisplayValue, ddmFieldsCounter, offset);
171                            }
172    
173                            fieldStructure.put("fieldNamespace", fieldNamespace);
174    
175                            fieldStructure.put("valueIndex", ddmFieldsCounter.get(name));
176    
177                            if (fieldDisplayable) {
178                                    ddmFieldsCounter.incrementKey(name);
179                            }
180    
181                            String childrenHTML = getHTML(
182                                    request, response, element, fields, portletNamespace, namespace,
183                                    mode, readOnly, locale);
184    
185                            fieldStructure.put("children", childrenHTML);
186    
187                            boolean disabled = GetterUtil.getBoolean(
188                                    fieldStructure.get("disabled"), false);
189    
190                            if (disabled) {
191                                    readOnly = true;
192                            }
193    
194                            sb.append(
195                                    processFTL(
196                                            request, response, element, mode, readOnly,
197                                            freeMarkerContext));
198    
199                            fieldRepetition--;
200                    }
201    
202                    return sb.toString();
203            }
204    
205            @Override
206            public String getFieldHTMLByName(
207                            HttpServletRequest request, HttpServletResponse response,
208                            long classNameId, long classPK, String fieldName, Fields fields,
209                            String portletNamespace, String namespace, String mode,
210                            boolean readOnly, Locale locale)
211                    throws Exception {
212    
213                    String xsd = getXSD(classNameId, classPK);
214    
215                    Document document = SAXReaderUtil.read(xsd);
216    
217                    String xPathExpression = "//dynamic-element[@name=".concat(
218                            HtmlUtil.escapeXPathAttribute(fieldName)).concat("]");
219    
220                    XPath xPathSelector = SAXReaderUtil.createXPath(xPathExpression);
221    
222                    Node node = xPathSelector.selectSingleNode(document.getRootElement());
223    
224                    Element element = (Element)node.asXPathResult(node.getParent());
225    
226                    return getFieldHTML(
227                            request, response, element, fields, portletNamespace, namespace,
228                            mode, readOnly, locale);
229            }
230    
231            @Override
232            public String getHTML(
233                            HttpServletRequest request, HttpServletResponse response,
234                            DDMStructure ddmStructure, Fields fields, String portletNamespace,
235                            String namespace, boolean readOnly, Locale locale)
236                    throws Exception {
237    
238                    return getHTML(
239                            request, response, ddmStructure.getDefinition(), fields,
240                            portletNamespace, namespace, readOnly, locale);
241            }
242    
243            @Override
244            public String getHTML(
245                            HttpServletRequest request, HttpServletResponse response,
246                            DDMTemplate ddmTemplate, Fields fields, String portletNamespace,
247                            String namespace, boolean readOnly, Locale locale)
248                    throws Exception {
249    
250                    return getHTML(
251                            request, response, ddmTemplate.getScript(), fields,
252                            portletNamespace, namespace, ddmTemplate.getMode(), readOnly,
253                            locale);
254            }
255    
256            public String getHTML(
257                            HttpServletRequest request, HttpServletResponse response,
258                            Element element, Fields fields, String portletNamespace,
259                            Locale locale)
260                    throws Exception {
261    
262                    return getHTML(
263                            request, response, element, fields, portletNamespace,
264                            StringPool.BLANK, null, false, locale);
265            }
266    
267            public String getHTML(
268                            HttpServletRequest request, HttpServletResponse response,
269                            Element element, Fields fields, String portletNamespace,
270                            String namespace, String mode, boolean readOnly, Locale locale)
271                    throws Exception {
272    
273                    List<Element> dynamicElementElements = element.elements(
274                            "dynamic-element");
275    
276                    StringBundler sb = new StringBundler(dynamicElementElements.size());
277    
278                    for (Element dynamicElementElement : dynamicElementElements) {
279                            sb.append(
280                                    getFieldHTML(
281                                            request, response, dynamicElementElement, fields,
282                                            portletNamespace, namespace, mode, readOnly, locale));
283                    }
284    
285                    return sb.toString();
286            }
287    
288            public String getHTML(
289                            HttpServletRequest request, HttpServletResponse response,
290                            Element element, String portletNamespace, Locale locale)
291                    throws Exception {
292    
293                    return getHTML(
294                            request, response, element, null, portletNamespace, locale);
295            }
296    
297            @Override
298            public String getHTML(
299                            HttpServletRequest request, HttpServletResponse response,
300                            String xml, Fields fields, String portletNamespace, Locale locale)
301                    throws Exception {
302    
303                    return getHTML(
304                            request, response, xml, fields, portletNamespace, StringPool.BLANK,
305                            locale);
306            }
307    
308            @Override
309            public String getHTML(
310                            HttpServletRequest request, HttpServletResponse response,
311                            String xml, Fields fields, String portletNamespace,
312                            String namespace, boolean readOnly, Locale locale)
313                    throws Exception {
314    
315                    return getHTML(
316                            request, response, xml, fields, portletNamespace, namespace, null,
317                            readOnly, locale);
318            }
319    
320            @Override
321            public String getHTML(
322                            HttpServletRequest request, HttpServletResponse response,
323                            String xml, Fields fields, String portletNamespace,
324                            String namespace, Locale locale)
325                    throws Exception {
326    
327                    return getHTML(
328                            request, response, xml, fields, portletNamespace, namespace, false,
329                            locale);
330            }
331    
332            @Override
333            public String getHTML(
334                            HttpServletRequest request, HttpServletResponse response,
335                            String xml, Fields fields, String portletNamespace,
336                            String namespace, String mode, boolean readOnly, Locale locale)
337                    throws Exception {
338    
339                    Document document = SAXReaderUtil.read(xml);
340    
341                    return getHTML(
342                            request, response, document.getRootElement(), fields,
343                            portletNamespace, namespace, mode, readOnly, locale);
344            }
345    
346            @Override
347            public String getHTML(
348                            HttpServletRequest request, HttpServletResponse response,
349                            String xml, String portletNamespace, Locale locale)
350                    throws Exception {
351    
352                    return getHTML(request, response, xml, null, locale);
353            }
354    
355            @Override
356            public JSONArray getJSONArray(DDMStructure structure, String xsd)
357                    throws PortalException {
358    
359                    JSONArray jsonArray = null;
360    
361                    if (Validator.isNull(xsd)) {
362                            jsonArray = getJSONArray(structure.getDefinition());
363                    }
364                    else {
365                            jsonArray = getJSONArray(xsd);
366                    }
367    
368                    addStructureFieldAttributes(structure, jsonArray);
369    
370                    return jsonArray;
371            }
372    
373            @Override
374            public JSONArray getJSONArray(Document document) throws PortalException {
375                    return getJSONArray(document.getRootElement());
376            }
377    
378            @Override
379            public JSONArray getJSONArray(Element element) throws PortalException {
380                    JSONArray jsonArray = JSONFactoryUtil.createJSONArray();
381    
382                    Document document = element.getDocument();
383    
384                    String defaultLanguageId = LocalizationUtil.getDefaultLanguageId(
385                            document.asXML());
386    
387                    List<Element> dynamicElementElements = element.elements(
388                            "dynamic-element");
389    
390                    for (Element dynamicElementElement : dynamicElementElements) {
391                            JSONObject jsonObject = JSONFactoryUtil.createJSONObject();
392                            JSONObject localizationMapJSONObject =
393                                    JSONFactoryUtil.createJSONObject();
394    
395                            for (Attribute attribute : dynamicElementElement.attributes()) {
396                                    jsonObject.put(attribute.getName(), attribute.getValue());
397                            }
398    
399                            jsonObject.put("autoGeneratedName", false);
400                            jsonObject.put("id", dynamicElementElement.attributeValue("name"));
401    
402                            String type = jsonObject.getString("type");
403    
404                            List<Element> metadataElements = dynamicElementElement.elements(
405                                    "meta-data");
406    
407                            for (Element metadataElement : metadataElements) {
408                                    if (metadataElement == null) {
409                                            continue;
410                                    }
411    
412                                    String locale = metadataElement.attributeValue("locale");
413    
414                                    JSONObject localeMap = JSONFactoryUtil.createJSONObject();
415    
416                                    for (Element metadataEntryElement :
417                                                    metadataElement.elements()) {
418    
419                                            String attributeName = metadataEntryElement.attributeValue(
420                                                    "name");
421                                            String attributeValue = metadataEntryElement.getTextTrim();
422    
423                                            putMetadataValue(
424                                                    localeMap, attributeName, attributeValue, type);
425    
426                                            if (defaultLanguageId.equals(locale)) {
427                                                    putMetadataValue(
428                                                            jsonObject, attributeName, attributeValue, type);
429                                            }
430                                    }
431    
432                                    localizationMapJSONObject.put(locale, localeMap);
433                            }
434    
435                            jsonObject.put("localizationMap", localizationMapJSONObject);
436    
437                            JSONArray hiddenAttributesJSONArray =
438                                    JSONFactoryUtil.createJSONArray();
439    
440                            if (type.equals(DDMImpl.TYPE_CHECKBOX)) {
441                                    hiddenAttributesJSONArray.put("required");
442                            }
443    
444                            hiddenAttributesJSONArray.put("readOnly");
445    
446                            jsonObject.put("hiddenAttributes", hiddenAttributesJSONArray);
447    
448                            String key = "fields";
449    
450                            if (type.equals(DDMImpl.TYPE_RADIO) ||
451                                    type.equals(DDMImpl.TYPE_SELECT)) {
452    
453                                    key = "options";
454                            }
455    
456                            jsonObject.put(key, getJSONArray(dynamicElementElement));
457    
458                            jsonArray.put(jsonObject);
459                    }
460    
461                    return jsonArray;
462            }
463    
464            @Override
465            public JSONArray getJSONArray(String xml) throws PortalException {
466                    try {
467                            return getJSONArray(SAXReaderUtil.read(xml));
468                    }
469                    catch (DocumentException de) {
470                            throw new SystemException();
471                    }
472            }
473    
474            @Override
475            public String getSimpleFieldHTML(
476                            HttpServletRequest request, HttpServletResponse response,
477                            Element element, Field field, String portletNamespace,
478                            String namespace, String mode, boolean readOnly, Locale locale)
479                    throws Exception {
480    
481                    Map<String, Object> freeMarkerContext = getFreeMarkerContext(
482                            request, response, portletNamespace, namespace, element, locale);
483    
484                    freeMarkerContext.put("ignoreRepeatable", Boolean.TRUE);
485    
486                    Map<String, Object> fieldStructure =
487                            (Map<String, Object>)freeMarkerContext.get("fieldStructure");
488    
489                    DDMFieldsCounter ddmFieldsCounter = getFieldsCounter(
490                            request, response, null, portletNamespace, namespace);
491    
492                    String name = element.attributeValue("name");
493    
494                    if ((field != null) && Validator.isNotNull(field.getValue())) {
495                            Fields fields = new Fields();
496    
497                            fields.put(field);
498    
499                            freeMarkerContext.put("fields", fields);
500                    }
501    
502                    fieldStructure.put("fieldNamespace", StringUtil.randomId());
503                    fieldStructure.put("valueIndex", ddmFieldsCounter.get(name));
504    
505                    List<Element> dynamicElementElements = element.elements(
506                            "dynamic-element");
507    
508                    StringBundler sb = new StringBundler(dynamicElementElements.size());
509    
510                    for (Element dynamicElementElement : dynamicElementElements) {
511                            String type = dynamicElementElement.attributeValue("type");
512    
513                            if (!type.equals("option")) {
514                                    sb.append(StringPool.BLANK);
515                            }
516                            else {
517                                    sb.append(
518                                            getSimpleFieldHTML(
519                                                    request, response, dynamicElementElement, field,
520                                                    portletNamespace, namespace, mode, readOnly, locale));
521                            }
522                    }
523    
524                    fieldStructure.put("children", sb.toString());
525    
526                    return processFTL(
527                            request, response, element, mode, readOnly, freeMarkerContext);
528            }
529    
530            @Override
531            public String getSimpleFieldHTMLByName(
532                            HttpServletRequest request, HttpServletResponse response,
533                            long classNameId, long classPK, Field field,
534                            String portletNamespace, String namespace, String mode,
535                            boolean readOnly, Locale locale)
536                    throws Exception {
537    
538                    String xsd = getXSD(classNameId, classPK);
539    
540                    Document document = SAXReaderUtil.read(xsd);
541    
542                    String xPathExpression = "//dynamic-element[@name=".concat(
543                            HtmlUtil.escapeXPathAttribute(field.getName())).concat("]");
544    
545                    XPath xPathSelector = SAXReaderUtil.createXPath(xPathExpression);
546    
547                    Node node = xPathSelector.selectSingleNode(document.getRootElement());
548    
549                    Element element = (Element)node.asXPathResult(node.getParent());
550    
551                    return getSimpleFieldHTML(
552                            request, response, element, field, portletNamespace, namespace,
553                            mode, readOnly, locale);
554            }
555    
556            @Override
557            public String getXSD(long classNameId, long classPK)
558                    throws PortalException {
559    
560                    if ((classNameId <= 0) || (classPK <= 0)) {
561                            return null;
562                    }
563    
564                    long ddmStructureClassNameId = PortalUtil.getClassNameId(
565                            DDMStructure.class);
566    
567                    long ddmTemplateClassNameId = PortalUtil.getClassNameId(
568                            DDMTemplate.class);
569    
570                    if (classNameId == ddmStructureClassNameId) {
571                            DDMStructure structure = DDMStructureLocalServiceUtil.getStructure(
572                                    classPK);
573    
574                            DDMForm ddmForm = structure.getFullHierarchyDDMForm();
575    
576                            return DDMFormXSDSerializerUtil.serialize(ddmForm);
577                    }
578                    else if (classNameId == ddmTemplateClassNameId) {
579                            DDMTemplate template = DDMTemplateLocalServiceUtil.getTemplate(
580                                    classPK);
581    
582                            return template.getScript();
583                    }
584    
585                    return null;
586            }
587    
588            @Override
589            public String getXSD(String json) throws PortalException {
590                    DDMForm ddmForm = DDMFormJSONDeserializerUtil.deserialize(json);
591    
592                    return DDMFormXSDSerializerUtil.serialize(ddmForm);
593            }
594    
595            protected JSONArray addStructureFieldAttributes(
596                    DDMStructure structure, JSONArray jsonArray) {
597    
598                    for (int i = 0; i < jsonArray.length(); i++) {
599                            JSONObject jsonObject = jsonArray.getJSONObject(i);
600    
601                            String fieldName = jsonObject.getString("name");
602    
603                            jsonObject.put(
604                                    "readOnlyAttributes",
605                                    getStructureFieldReadOnlyAttributes(structure, fieldName));
606                    }
607    
608                    return jsonArray;
609            }
610    
611            protected int countFieldRepetition(
612                    String[] fieldsDisplayValues, String parentFieldName, int offset) {
613    
614                    int total = 0;
615    
616                    String fieldName = fieldsDisplayValues[offset];
617    
618                    for (; offset < fieldsDisplayValues.length; offset++) {
619                            String fieldNameValue = fieldsDisplayValues[offset];
620    
621                            if (fieldNameValue.equals(fieldName)) {
622                                    total++;
623                            }
624    
625                            if (fieldNameValue.equals(parentFieldName)) {
626                                    break;
627                            }
628                    }
629    
630                    return total;
631            }
632    
633            protected Map<String, Object> getFieldContext(
634                    HttpServletRequest request, HttpServletResponse response,
635                    String portletNamespace, String namespace,
636                    Element dynamicElementElement, Locale locale) {
637    
638                    Map<String, Map<String, Object>> fieldsContext = getFieldsContext(
639                            request, response, portletNamespace, namespace);
640    
641                    String name = dynamicElementElement.attributeValue("name");
642    
643                    Map<String, Object> fieldContext = fieldsContext.get(name);
644    
645                    if (fieldContext != null) {
646                            return fieldContext;
647                    }
648    
649                    Document document = dynamicElementElement.getDocument();
650    
651                    String[] availableLanguageIds =
652                            LocalizationUtil.getAvailableLanguageIds(document);
653    
654                    String defaultLanguageId = LocalizationUtil.getDefaultLanguageId(
655                            document);
656    
657                    String editingLanguageId = LocaleUtil.toLanguageId(locale);
658    
659                    String structureLanguageId = editingLanguageId;
660    
661                    if (!ArrayUtil.contains(availableLanguageIds, editingLanguageId)) {
662                            structureLanguageId = defaultLanguageId;
663                    }
664    
665                    Element metadataElement =
666                            (Element)dynamicElementElement.selectSingleNode(
667                                    "meta-data[@locale='" + structureLanguageId + "']");
668    
669                    fieldContext = new HashMap<String, Object>();
670    
671                    if (metadataElement != null) {
672                            for (Element metadataEntry : metadataElement.elements()) {
673                                    fieldContext.put(
674                                            metadataEntry.attributeValue("name"),
675                                            metadataEntry.getText());
676                            }
677                    }
678    
679                    for (Attribute attribute : dynamicElementElement.attributes()) {
680                            fieldContext.put(attribute.getName(), attribute.getValue());
681                    }
682    
683                    boolean localizable = GetterUtil.getBoolean(
684                            dynamicElementElement.attributeValue("localizable"), true);
685    
686                    if (!localizable && !editingLanguageId.equals(defaultLanguageId)) {
687                            fieldContext.put("disabled", Boolean.TRUE.toString());
688                    }
689    
690                    fieldContext.put("fieldNamespace", StringUtil.randomId());
691    
692                    boolean checkRequired = GetterUtil.getBoolean(
693                            request.getAttribute("checkRequired"), true);
694    
695                    if (!checkRequired) {
696                            fieldContext.put("required", Boolean.FALSE.toString());
697                    }
698    
699                    fieldsContext.put(name, fieldContext);
700    
701                    return fieldContext;
702            }
703    
704            protected String getFieldNamespace(
705                    String fieldDisplayValue, DDMFieldsCounter ddmFieldsCounter,
706                    int offset) {
707    
708                    String[] fieldsDisplayValues = StringUtil.split(fieldDisplayValue);
709    
710                    String fieldsDisplayValue = fieldsDisplayValues[offset];
711    
712                    return StringUtil.extractLast(
713                            fieldsDisplayValue, DDMImpl.INSTANCE_SEPARATOR);
714            }
715    
716            protected int getFieldOffset(
717                    String[] fieldsDisplayValues, String name, int index) {
718    
719                    int offset = 0;
720    
721                    for (; offset < fieldsDisplayValues.length; offset++) {
722                            if (name.equals(fieldsDisplayValues[offset])) {
723                                    index--;
724    
725                                    if (index < 0) {
726                                            break;
727                                    }
728                            }
729                    }
730    
731                    return offset;
732            }
733    
734            protected Map<String, Map<String, Object>> getFieldsContext(
735                    HttpServletRequest request, HttpServletResponse response,
736                    String portletNamespace, String namespace) {
737    
738                    String fieldsContextKey =
739                            portletNamespace + namespace + "fieldsContext";
740    
741                    Map<String, Map<String, Object>> fieldsContext =
742                            (Map<String, Map<String, Object>>)request.getAttribute(
743                                    fieldsContextKey);
744    
745                    if (fieldsContext == null) {
746                            fieldsContext = new HashMap<String, Map<String, Object>>();
747    
748                            request.setAttribute(fieldsContextKey, fieldsContext);
749                    }
750    
751                    return fieldsContext;
752            }
753    
754            protected DDMFieldsCounter getFieldsCounter(
755                    HttpServletRequest request, HttpServletResponse response, Fields fields,
756                    String portletNamespace, String namespace) {
757    
758                    String fieldsCounterKey = portletNamespace + namespace + "fieldsCount";
759    
760                    DDMFieldsCounter ddmFieldsCounter =
761                            (DDMFieldsCounter)request.getAttribute(fieldsCounterKey);
762    
763                    if (ddmFieldsCounter == null) {
764                            ddmFieldsCounter = new DDMFieldsCounter();
765    
766                            request.setAttribute(fieldsCounterKey, ddmFieldsCounter);
767                    }
768    
769                    return ddmFieldsCounter;
770            }
771    
772            protected String getFieldsDisplayValue(
773                    HttpServletRequest request, HttpServletResponse response,
774                    Fields fields) {
775    
776                    String defaultFieldsDisplayValue = null;
777    
778                    if (fields != null) {
779                            Field fieldsDisplayField = fields.get(DDMImpl.FIELDS_DISPLAY_NAME);
780    
781                            if (fieldsDisplayField != null) {
782                                    defaultFieldsDisplayValue =
783                                            (String)fieldsDisplayField.getValue();
784                            }
785                    }
786    
787                    return ParamUtil.getString(
788                            request, DDMImpl.FIELDS_DISPLAY_NAME, defaultFieldsDisplayValue);
789            }
790    
791            protected String[] getFieldsDisplayValues(String fieldDisplayValue) {
792                    List<String> fieldsDisplayValues = new ArrayList<String>();
793    
794                    for (String value : StringUtil.split(fieldDisplayValue)) {
795                            String fieldName = StringUtil.extractFirst(
796                                    value, DDMImpl.INSTANCE_SEPARATOR);
797    
798                            fieldsDisplayValues.add(fieldName);
799                    }
800    
801                    return fieldsDisplayValues.toArray(
802                            new String[fieldsDisplayValues.size()]);
803            }
804    
805            protected Map<String, Object> getFreeMarkerContext(
806                    HttpServletRequest request, HttpServletResponse response,
807                    String portletNamespace, String namespace,
808                    Element dynamicElementElement, Locale locale) {
809    
810                    Map<String, Object> freeMarkerContext = new HashMap<String, Object>();
811    
812                    Map<String, Object> fieldContext = getFieldContext(
813                            request, response, portletNamespace, namespace,
814                            dynamicElementElement, locale);
815    
816                    Map<String, Object> parentFieldContext = new HashMap<String, Object>();
817    
818                    Element parentElement = dynamicElementElement.getParent();
819    
820                    if (parentElement != null) {
821                            parentFieldContext = getFieldContext(
822                                    request, response, portletNamespace, namespace, parentElement,
823                                    locale);
824                    }
825    
826                    freeMarkerContext.put("fieldStructure", fieldContext);
827                    freeMarkerContext.put("namespace", namespace);
828                    freeMarkerContext.put("parentFieldStructure", parentFieldContext);
829                    freeMarkerContext.put("portletNamespace", portletNamespace);
830                    freeMarkerContext.put(
831                            "requestedLanguageDir", LanguageUtil.get(locale, "lang.dir"));
832                    freeMarkerContext.put("requestedLocale", locale);
833    
834                    return freeMarkerContext;
835            }
836    
837            protected URL getResource(String name) {
838                    Class<?> clazz = getClass();
839    
840                    ClassLoader classLoader = clazz.getClassLoader();
841    
842                    return classLoader.getResource(name);
843            }
844    
845            protected JSONArray getStructureFieldReadOnlyAttributes(
846                    DDMStructure structure, String fieldName) {
847    
848                    JSONArray jsonArray = JSONFactoryUtil.createJSONArray();
849    
850                    try {
851                            if (DDMStorageLinkLocalServiceUtil.getStructureStorageLinksCount(
852                                            structure.getStructureId()) > 0) {
853    
854                                    jsonArray.put("name");
855                            }
856                    }
857                    catch (Exception e) {
858                    }
859    
860                    return jsonArray;
861            }
862    
863            protected String processFTL(
864                            HttpServletRequest request, HttpServletResponse response,
865                            Element element, String mode, boolean readOnly,
866                            Map<String, Object> freeMarkerContext)
867                    throws Exception {
868    
869                    String fieldNamespace = element.attributeValue(
870                            "fieldNamespace", _DEFAULT_NAMESPACE);
871    
872                    TemplateResource templateResource = _defaultTemplateResource;
873    
874                    Map<String, Object> fieldStructure =
875                            (Map<String, Object>)freeMarkerContext.get("fieldStructure");
876    
877                    boolean fieldReadOnly = GetterUtil.getBoolean(
878                            fieldStructure.get("readOnly"));
879    
880                    if ((fieldReadOnly && Validator.isNotNull(mode) &&
881                             StringUtil.equalsIgnoreCase(
882                                    mode, DDMTemplateConstants.TEMPLATE_MODE_EDIT)) ||
883                            readOnly) {
884    
885                            fieldNamespace = _DEFAULT_READ_ONLY_NAMESPACE;
886    
887                            templateResource = _defaultReadOnlyTemplateResource;
888                    }
889    
890                    String type = element.attributeValue("type");
891    
892                    String templateName = StringUtil.replaceFirst(
893                            type, fieldNamespace.concat(StringPool.DASH), StringPool.BLANK);
894    
895                    StringBundler resourcePath = new StringBundler(5);
896    
897                    resourcePath.append(_TPL_PATH);
898                    resourcePath.append(StringUtil.toLowerCase(fieldNamespace));
899                    resourcePath.append(CharPool.SLASH);
900                    resourcePath.append(templateName);
901                    resourcePath.append(_TPL_EXT);
902    
903                    String resource = resourcePath.toString();
904    
905                    URL url = getResource(resource);
906    
907                    if (url != null) {
908                            templateResource = new URLTemplateResource(resource, url);
909                    }
910    
911                    if (templateResource == null) {
912                            throw new Exception("Unable to load template resource " + resource);
913                    }
914    
915                    Template template = TemplateManagerUtil.getTemplate(
916                            TemplateConstants.LANG_TYPE_FTL, templateResource, false);
917    
918                    for (Map.Entry<String, Object> entry : freeMarkerContext.entrySet()) {
919                            template.put(entry.getKey(), entry.getValue());
920                    }
921    
922                    return processFTL(request, response, template);
923            }
924    
925            /**
926             * @see com.liferay.taglib.util.ThemeUtil#includeFTL
927             */
928            protected String processFTL(
929                            HttpServletRequest request, HttpServletResponse response,
930                            Template template)
931                    throws Exception {
932    
933                    // FreeMarker variables
934    
935                    template.prepare(request);
936    
937                    // Tag libraries
938    
939                    Writer writer = new UnsyncStringWriter();
940    
941                    // Portal JSP tag library factory
942    
943                    TemplateHashModel portalTaglib =
944                            FreeMarkerTaglibFactoryUtil.createTaglibFactory(
945                                    request.getServletContext());
946    
947                    template.put("PortalJspTagLibs", portalTaglib);
948    
949                    // FreeMarker JSP tag library support
950    
951                    GenericServlet genericServlet = new JSPSupportServlet(
952                            request.getServletContext());
953    
954                    ServletContextHashModel servletContextHashModel =
955                            new ServletContextHashModel(
956                                    genericServlet, ObjectWrapper.DEFAULT_WRAPPER);
957    
958                    template.put("Application", servletContextHashModel);
959    
960                    HttpRequestHashModel httpRequestHashModel = new HttpRequestHashModel(
961                            request, response, ObjectWrapper.DEFAULT_WRAPPER);
962    
963                    template.put("Request", httpRequestHashModel);
964    
965                    // Merge templates
966    
967                    template.processTemplate(writer);
968    
969                    return writer.toString();
970            }
971    
972            protected void putMetadataValue(
973                    JSONObject jsonObject, String attributeName, String attributeValue,
974                    String type) {
975    
976                    if (type.equals(DDMImpl.TYPE_RADIO) ||
977                            type.equals(DDMImpl.TYPE_SELECT)) {
978    
979                            if (attributeName.equals("predefinedValue")) {
980                                    try {
981                                            jsonObject.put(
982                                                    attributeName,
983                                                    JSONFactoryUtil.createJSONArray(attributeValue));
984                                    }
985                                    catch (Exception e) {
986                                    }
987    
988                                    return;
989                            }
990                    }
991    
992                    jsonObject.put(attributeName, attributeValue);
993            }
994    
995            private static final String _DEFAULT_NAMESPACE = "alloy";
996    
997            private static final String _DEFAULT_READ_ONLY_NAMESPACE = "readonly";
998    
999            private static final String _TPL_EXT = ".ftl";
1000    
1001            private static final String _TPL_PATH =
1002                    "com/liferay/portlet/dynamicdatamapping/dependencies/";
1003    
1004            private TemplateResource _defaultReadOnlyTemplateResource;
1005            private TemplateResource _defaultTemplateResource;
1006    
1007    }