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.DDMStructureServiceUtil;
053    import com.liferay.portlet.dynamicdatamapping.service.DDMTemplateServiceUtil;
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 = DDMStructureServiceUtil.getStructure(
543                                    classPK);
544    
545                            return structure.getCompleteXsd();
546                    }
547                    else if (classNameId == ddmTemplateClassNameId) {
548                            DDMTemplate template = DDMTemplateServiceUtil.getTemplate(classPK);
549    
550                            return template.getScript();
551                    }
552    
553                    return null;
554            }
555    
556            protected JSONArray addStructureFieldAttributes(
557                    DDMStructure structure, JSONArray jsonArray) {
558    
559                    for (int i = 0; i < jsonArray.length(); i++) {
560                            JSONObject jsonObject = jsonArray.getJSONObject(i);
561    
562                            String fieldName = jsonObject.getString("name");
563    
564                            jsonObject.put(
565                                    "readOnlyAttributes",
566                                    getStructureFieldReadOnlyAttributes(structure, fieldName));
567                    }
568    
569                    return jsonArray;
570            }
571    
572            protected int countFieldRepetition(
573                    String[] fieldsDisplayValues, String parentFieldName, int offset) {
574    
575                    int total = 0;
576    
577                    String fieldName = fieldsDisplayValues[offset];
578    
579                    for (; offset < fieldsDisplayValues.length; offset++) {
580                            String fieldNameValue = fieldsDisplayValues[offset];
581    
582                            if (fieldNameValue.equals(fieldName)) {
583                                    total++;
584                            }
585    
586                            if (fieldNameValue.equals(parentFieldName)) {
587                                    break;
588                            }
589                    }
590    
591                    return total;
592            }
593    
594            protected Map<String, Object> getFieldContext(
595                    PageContext pageContext, String portletNamespace, String namespace,
596                    Element dynamicElementElement, Locale locale) {
597    
598                    Map<String, Map<String, Object>> fieldsContext = getFieldsContext(
599                            pageContext, portletNamespace, namespace);
600    
601                    String name = dynamicElementElement.attributeValue("name");
602    
603                    Map<String, Object> fieldContext = fieldsContext.get(name);
604    
605                    if (fieldContext != null) {
606                            return fieldContext;
607                    }
608    
609                    Document document = dynamicElementElement.getDocument();
610    
611                    String[] availableLanguageIds =
612                            LocalizationUtil.getAvailableLanguageIds(document);
613    
614                    String defaultLanguageId = LocalizationUtil.getDefaultLanguageId(
615                            document);
616    
617                    String languageId = LocaleUtil.toLanguageId(locale);
618    
619                    if (!ArrayUtil.contains(availableLanguageIds, languageId)) {
620                            languageId = defaultLanguageId;
621                    }
622    
623                    Element metadataElement =
624                            (Element)dynamicElementElement.selectSingleNode(
625                                    "meta-data[@locale='" + languageId + "']");
626    
627                    fieldContext = new HashMap<String, Object>();
628    
629                    if (metadataElement != null) {
630                            for (Element metadataEntry : metadataElement.elements()) {
631                                    fieldContext.put(
632                                            metadataEntry.attributeValue("name"),
633                                            metadataEntry.getText());
634                            }
635                    }
636    
637                    for (Attribute attribute : dynamicElementElement.attributes()) {
638                            fieldContext.put(attribute.getName(), attribute.getValue());
639                    }
640    
641                    fieldContext.put("fieldNamespace", StringUtil.randomId());
642    
643                    fieldsContext.put(name, fieldContext);
644    
645                    return fieldContext;
646            }
647    
648            protected Map<String, Map<String, Object>> getFieldsContext(
649                    PageContext pageContext, String portletNamespace, String namespace) {
650    
651                    String fieldsContextKey =
652                            portletNamespace + namespace + "fieldsContext";
653    
654                    Map<String, Map<String, Object>> fieldsContext =
655                            (Map<String, Map<String, Object>>)pageContext.getAttribute(
656                                    fieldsContextKey);
657    
658                    if (fieldsContext == null) {
659                            fieldsContext = new HashMap<String, Map<String, Object>>();
660    
661                            pageContext.setAttribute(fieldsContextKey, fieldsContext);
662                    }
663    
664                    return fieldsContext;
665            }
666    
667            protected DDMFieldsCounter getFieldsCounter(
668                    PageContext pageContext, Fields fields, String portletNamespace,
669                    String namespace) {
670    
671                    String fieldsCounterKey = portletNamespace + namespace + "fieldsCount";
672    
673                    DDMFieldsCounter ddmFieldsCounter =
674                            (DDMFieldsCounter)pageContext.getAttribute(fieldsCounterKey);
675    
676                    if (ddmFieldsCounter == null) {
677                            ddmFieldsCounter = new DDMFieldsCounter();
678    
679                            pageContext.setAttribute(fieldsCounterKey, ddmFieldsCounter);
680                    }
681    
682                    return ddmFieldsCounter;
683            }
684    
685            protected Map<String, Object> getFreeMarkerContext(
686                    PageContext pageContext, String portletNamespace, String namespace,
687                    Element dynamicElementElement, Locale locale) {
688    
689                    Map<String, Object> freeMarkerContext = new HashMap<String, Object>();
690    
691                    Map<String, Object> fieldContext = getFieldContext(
692                            pageContext, portletNamespace, namespace, dynamicElementElement,
693                            locale);
694    
695                    Map<String, Object> parentFieldContext = new HashMap<String, Object>();
696    
697                    Element parentElement = dynamicElementElement.getParent();
698    
699                    if (parentElement != null) {
700                            parentFieldContext = getFieldContext(
701                                    pageContext, portletNamespace, namespace, parentElement,
702                                    locale);
703                    }
704    
705                    freeMarkerContext.put("fieldStructure", fieldContext);
706                    freeMarkerContext.put("namespace", namespace);
707                    freeMarkerContext.put("parentFieldStructure", parentFieldContext);
708                    freeMarkerContext.put("portletNamespace", portletNamespace);
709                    freeMarkerContext.put(
710                            "requestedLanguageDir", LanguageUtil.get(locale, "lang.dir"));
711                    freeMarkerContext.put("requestedLocale", locale);
712    
713                    return freeMarkerContext;
714            }
715    
716            protected URL getResource(String name) {
717                    Class<?> clazz = getClass();
718    
719                    ClassLoader classLoader = clazz.getClassLoader();
720    
721                    return classLoader.getResource(name);
722            }
723    
724            protected JSONArray getStructureFieldReadOnlyAttributes(
725                    DDMStructure structure, String fieldName) {
726    
727                    JSONArray jsonArray = JSONFactoryUtil.createJSONArray();
728    
729                    try {
730                            if (DDMStorageLinkLocalServiceUtil.getStructureStorageLinksCount(
731                                            structure.getStructureId()) > 0) {
732    
733                                    jsonArray.put("name");
734                            }
735                    }
736                    catch (Exception e) {
737                    }
738    
739                    return jsonArray;
740            }
741    
742            protected String processFTL(
743                            PageContext pageContext, Element element, String mode,
744                            boolean readOnly, Map<String, Object> freeMarkerContext)
745                    throws Exception {
746    
747                    String fieldNamespace = element.attributeValue(
748                            "fieldNamespace", _DEFAULT_NAMESPACE);
749    
750                    TemplateResource templateResource = _defaultTemplateResource;
751    
752                    Map<String, Object> fieldStructure =
753                            (Map<String, Object>)freeMarkerContext.get("fieldStructure");
754    
755                    boolean fieldReadOnly = GetterUtil.getBoolean(
756                            fieldStructure.get("readOnly"));
757    
758                    if ((fieldReadOnly && Validator.isNotNull(mode) &&
759                             StringUtil.equalsIgnoreCase(
760                                    mode, DDMTemplateConstants.TEMPLATE_MODE_EDIT)) ||
761                            readOnly) {
762    
763                            fieldNamespace = _DEFAULT_READ_ONLY_NAMESPACE;
764    
765                            templateResource = _defaultReadOnlyTemplateResource;
766                    }
767    
768                    String type = element.attributeValue("type");
769    
770                    String templateName = StringUtil.replaceFirst(
771                            type, fieldNamespace.concat(StringPool.DASH), StringPool.BLANK);
772    
773                    StringBundler resourcePath = new StringBundler(5);
774    
775                    resourcePath.append(_TPL_PATH);
776                    resourcePath.append(StringUtil.toLowerCase(fieldNamespace));
777                    resourcePath.append(CharPool.SLASH);
778                    resourcePath.append(templateName);
779                    resourcePath.append(_TPL_EXT);
780    
781                    String resource = resourcePath.toString();
782    
783                    URL url = getResource(resource);
784    
785                    if (url != null) {
786                            templateResource = new URLTemplateResource(resource, url);
787                    }
788    
789                    if (templateResource == null) {
790                            throw new Exception("Unable to load template resource " + resource);
791                    }
792    
793                    Template template = TemplateManagerUtil.getTemplate(
794                            TemplateConstants.LANG_TYPE_FTL, templateResource, false);
795    
796                    for (Map.Entry<String, Object> entry : freeMarkerContext.entrySet()) {
797                            template.put(entry.getKey(), entry.getValue());
798                    }
799    
800                    return processFTL(pageContext, template);
801            }
802    
803            /**
804             * @see com.liferay.taglib.util.ThemeUtil#includeFTL
805             */
806            protected String processFTL(PageContext pageContext, Template template)
807                    throws Exception {
808    
809                    HttpServletRequest request =
810                            (HttpServletRequest)pageContext.getRequest();
811    
812                    // FreeMarker variables
813    
814                    template.prepare(request);
815    
816                    // Tag libraries
817    
818                    HttpServletResponse response =
819                            (HttpServletResponse)pageContext.getResponse();
820    
821                    Writer writer = new UnsyncStringWriter();
822    
823                    // Portal JSP tag library factory
824    
825                    TemplateHashModel portalTaglib =
826                            FreeMarkerTaglibFactoryUtil.createTaglibFactory(
827                                    pageContext.getServletContext());
828    
829                    template.put("PortalJspTagLibs", portalTaglib);
830    
831                    // FreeMarker JSP tag library support
832    
833                    final Servlet servlet = (Servlet)pageContext.getPage();
834    
835                    GenericServlet genericServlet = null;
836    
837                    if (servlet instanceof GenericServlet) {
838                            genericServlet = (GenericServlet)servlet;
839                    }
840                    else {
841                            genericServlet = new GenericServlet() {
842    
843                                    @Override
844                                    public void service(
845                                                    ServletRequest servletRequest,
846                                                    ServletResponse servletResponse)
847                                            throws IOException, ServletException {
848    
849                                            servlet.service(servletRequest, servletResponse);
850                                    }
851    
852                            };
853    
854                            genericServlet.init(pageContext.getServletConfig());
855                    }
856    
857                    ServletContextHashModel servletContextHashModel =
858                            new ServletContextHashModel(
859                                    genericServlet, ObjectWrapper.DEFAULT_WRAPPER);
860    
861                    template.put("Application", servletContextHashModel);
862    
863                    HttpRequestHashModel httpRequestHashModel = new HttpRequestHashModel(
864                            request, response, ObjectWrapper.DEFAULT_WRAPPER);
865    
866                    template.put("Request", httpRequestHashModel);
867    
868                    // Merge templates
869    
870                    template.processTemplate(writer);
871    
872                    return writer.toString();
873            }
874    
875            protected void putMetadataValue(
876                    JSONObject jsonObject, String attributeName, String attributeValue,
877                    String type) {
878    
879                    if (type.equals(DDMImpl.TYPE_RADIO) ||
880                            type.equals(DDMImpl.TYPE_SELECT)) {
881    
882                            if (attributeName.equals("predefinedValue")) {
883                                    try {
884                                            jsonObject.put(
885                                                    attributeName,
886                                                    JSONFactoryUtil.createJSONArray(attributeValue));
887                                    }
888                                    catch (Exception e) {
889                                    }
890    
891                                    return;
892                            }
893                    }
894    
895                    jsonObject.put(attributeName, attributeValue);
896            }
897    
898            private static final String _DEFAULT_NAMESPACE = "alloy";
899    
900            private static final String _DEFAULT_READ_ONLY_NAMESPACE = "readonly";
901    
902            private static final String _TPL_EXT = ".ftl";
903    
904            private static final String _TPL_PATH =
905                    "com/liferay/portlet/dynamicdatamapping/dependencies/";
906    
907            private TemplateResource _defaultReadOnlyTemplateResource;
908            private TemplateResource _defaultTemplateResource;
909    
910    }