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