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