001    /**
002     * Copyright (c) 2000-2012 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.template.Template;
024    import com.liferay.portal.kernel.template.TemplateContextType;
025    import com.liferay.portal.kernel.template.TemplateManager;
026    import com.liferay.portal.kernel.template.TemplateManagerUtil;
027    import com.liferay.portal.kernel.template.TemplateResource;
028    import com.liferay.portal.kernel.template.URLTemplateResource;
029    import com.liferay.portal.kernel.util.ArrayUtil;
030    import com.liferay.portal.kernel.util.CharPool;
031    import com.liferay.portal.kernel.util.GetterUtil;
032    import com.liferay.portal.kernel.util.HtmlUtil;
033    import com.liferay.portal.kernel.util.LocaleUtil;
034    import com.liferay.portal.kernel.util.LocalizationUtil;
035    import com.liferay.portal.kernel.util.StringBundler;
036    import com.liferay.portal.kernel.util.StringPool;
037    import com.liferay.portal.kernel.util.StringUtil;
038    import com.liferay.portal.kernel.util.Validator;
039    import com.liferay.portal.kernel.util.WebKeys;
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.theme.ThemeDisplay;
048    import com.liferay.portal.util.PortalUtil;
049    import com.liferay.portlet.dynamicdatamapping.model.DDMStructure;
050    import com.liferay.portlet.dynamicdatamapping.model.DDMTemplate;
051    import com.liferay.portlet.dynamicdatamapping.model.DDMTemplateConstants;
052    import com.liferay.portlet.dynamicdatamapping.service.DDMStorageLinkLocalServiceUtil;
053    import com.liferay.portlet.dynamicdatamapping.service.DDMStructureServiceUtil;
054    import com.liferay.portlet.dynamicdatamapping.service.DDMTemplateServiceUtil;
055    import com.liferay.portlet.dynamicdatamapping.storage.Field;
056    import com.liferay.portlet.dynamicdatamapping.storage.Fields;
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.Serializable;
067    import java.io.Writer;
068    
069    import java.net.URL;
070    
071    import java.util.HashMap;
072    import java.util.List;
073    import java.util.Locale;
074    import java.util.Map;
075    
076    import javax.servlet.GenericServlet;
077    import javax.servlet.Servlet;
078    import javax.servlet.ServletException;
079    import javax.servlet.ServletRequest;
080    import javax.servlet.ServletResponse;
081    import javax.servlet.http.HttpServletRequest;
082    import javax.servlet.http.HttpServletResponse;
083    import javax.servlet.jsp.PageContext;
084    
085    /**
086     * @author Bruno Basto
087     * @author Eduardo Lundgren
088     * @author Brian Wing Shun Chan
089     * @author Marcellus Tavares
090     */
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 namespace, String mode, boolean readOnly, Locale locale)
112                    throws Exception {
113    
114                    HttpServletRequest request =
115                            (HttpServletRequest)pageContext.getRequest();
116    
117                    ThemeDisplay themeDisplay = (ThemeDisplay)request.getAttribute(
118                            WebKeys.THEME_DISPLAY);
119    
120                    String portletId = PortalUtil.getPortletId(request);
121    
122                    String portletNamespace = PortalUtil.getPortletNamespace(portletId);
123    
124                    Map<String, Object> freeMarkerContext = getFreeMarkerContext(
125                            element, locale);
126    
127                    freeMarkerContext.put("portletNamespace", portletNamespace);
128                    freeMarkerContext.put("namespace", namespace);
129    
130                    Map<String, Object> fieldStructure =
131                            (Map<String, Object>)freeMarkerContext.get("fieldStructure");
132    
133                    int valuesSize = 1;
134    
135                    if (fields != null) {
136                            freeMarkerContext.put("fields", fields);
137    
138                            String name = element.attributeValue("name");
139    
140                            Field field = fields.get(name);
141    
142                            if (field != null) {
143                                    List<Serializable> values = field.getValues(
144                                            themeDisplay.getLocale());
145    
146                                    valuesSize = values.size();
147                            }
148                    }
149    
150                    StringBuffer sb = new StringBuffer(valuesSize);
151    
152                    for (int i = 0; i < valuesSize; i++) {
153                            fieldStructure.put("repeatableIndex", String.valueOf(i));
154    
155                            String childrenHTML = getHTML(
156                                    pageContext, element, fields, namespace, mode, readOnly,
157                                    locale);
158    
159                            fieldStructure.put("children", childrenHTML);
160    
161                            sb.append(
162                                    processFTL(
163                                            pageContext, element, mode, readOnly, freeMarkerContext));
164                    }
165    
166                    return sb.toString();
167            }
168    
169            public String getFieldHTMLByName(
170                            PageContext pageContext, long classNameId, long classPK,
171                            String fieldName, int repeatableIndex, Fields fields,
172                            String namespace, String mode, boolean readOnly, Locale locale)
173                    throws Exception {
174    
175                    String xsd = getXSD(classNameId, classPK);
176    
177                    Document document = SAXReaderUtil.read(xsd);
178    
179                    String xPathExpression =
180                            "//dynamic-element[@name=".concat(
181                                    HtmlUtil.escapeXPathAttribute(fieldName)).concat("]");
182    
183                    XPath xPathSelector = SAXReaderUtil.createXPath(xPathExpression);
184    
185                    Node node = xPathSelector.selectSingleNode(document.getRootElement());
186    
187                    Element element = (Element)node.asXPathResult(node.getParent());
188    
189                    if (repeatableIndex > 0) {
190                            element.addAttribute(
191                                    "repeatableIndex", String.valueOf(repeatableIndex));
192                    }
193    
194                    return getFieldHTML(
195                            pageContext, element, fields, namespace, mode, readOnly, locale);
196            }
197    
198            public String getHTML(
199                            PageContext pageContext, DDMStructure ddmStructure, Fields fields,
200                            String namespace, boolean readOnly, Locale locale)
201                    throws Exception {
202    
203                    return getHTML(
204                            pageContext, ddmStructure.getXsd(), fields, namespace, readOnly,
205                            locale);
206            }
207    
208            public String getHTML(
209                            PageContext pageContext, DDMTemplate ddmTemplate, Fields fields,
210                            String namespace, boolean readOnly, Locale locale)
211                    throws Exception {
212    
213                    return getHTML(
214                            pageContext, ddmTemplate.getScript(), fields, namespace,
215                            ddmTemplate.getMode(), readOnly, locale);
216            }
217    
218            public String getHTML(
219                            PageContext pageContext, Element element, Fields fields,
220                            Locale locale)
221                    throws Exception {
222    
223                    return getHTML(
224                            pageContext, element, fields, StringPool.BLANK, null, false,
225                            locale);
226            }
227    
228            public String getHTML(
229                            PageContext pageContext, Element element, Fields fields,
230                            String namespace, String mode, boolean readOnly, Locale locale)
231                    throws Exception {
232    
233                    List<Element> dynamicElementElements = element.elements(
234                            "dynamic-element");
235    
236                    StringBundler sb = new StringBundler(dynamicElementElements.size());
237    
238                    for (Element dynamicElementElement : dynamicElementElements) {
239                            sb.append(
240                                    getFieldHTML(
241                                            pageContext, dynamicElementElement, fields, namespace, mode,
242                                            readOnly, locale));
243                    }
244    
245                    return sb.toString();
246            }
247    
248            public String getHTML(
249                            PageContext pageContext, Element element, Locale locale)
250                    throws Exception {
251    
252                    return getHTML(pageContext, element, null, locale);
253            }
254    
255            public String getHTML(
256                            PageContext pageContext, String xml, Fields fields, Locale locale)
257                    throws Exception {
258    
259                    return getHTML(pageContext, xml, fields, StringPool.BLANK, locale);
260            }
261    
262            public String getHTML(
263                            PageContext pageContext, String xml, Fields fields,
264                            String namespace, boolean readOnly, Locale locale)
265                    throws Exception {
266    
267                    return getHTML(
268                            pageContext, xml, fields, namespace, null, readOnly, locale);
269            }
270    
271            public String getHTML(
272                            PageContext pageContext, String xml, Fields fields,
273                            String namespace, Locale locale)
274                    throws Exception {
275    
276                    return getHTML(pageContext, xml, fields, namespace, false, locale);
277            }
278    
279            public String getHTML(
280                            PageContext pageContext, String xml, Fields fields,
281                            String namespace, String mode, boolean readOnly, Locale locale)
282                    throws Exception {
283    
284                    Document document = SAXReaderUtil.read(xml);
285    
286                    return getHTML(
287                            pageContext, document.getRootElement(), fields, namespace, mode,
288                            readOnly, locale);
289            }
290    
291            public String getHTML(PageContext pageContext, String xml, Locale locale)
292                    throws Exception {
293    
294                    return getHTML(pageContext, xml, null, locale);
295            }
296    
297            public JSONArray getJSONArray(DDMStructure structure, String xsd)
298                    throws PortalException, SystemException {
299    
300                    JSONArray jsonArray = null;
301    
302                    if (Validator.isNull(xsd)) {
303                            jsonArray = getJSONArray(structure.getDocument());
304                    }
305                    else {
306                            jsonArray = getJSONArray(xsd);
307                    }
308    
309                    addStructureFieldAttributes(structure, jsonArray);
310    
311                    return jsonArray;
312            }
313    
314            public JSONArray getJSONArray(Document document) throws PortalException {
315                    return getJSONArray(document.getRootElement());
316            }
317    
318            public JSONArray getJSONArray(Element element) throws PortalException {
319                    JSONArray jsonArray = JSONFactoryUtil.createJSONArray();
320    
321                    Document document = element.getDocument();
322    
323                    String defaultLocale = LocalizationUtil.getDefaultLocale(
324                            document.asXML());
325    
326                    List<Element> dynamicElementElements = element.elements(
327                            "dynamic-element");
328    
329                    for (Element dynamicElementElement : dynamicElementElements) {
330                            JSONObject jsonObject = JSONFactoryUtil.createJSONObject();
331                            JSONObject localizationMapJSONObject =
332                                    JSONFactoryUtil.createJSONObject();
333    
334                            for (Attribute attribute : dynamicElementElement.attributes()) {
335                                    jsonObject.put(attribute.getName(), attribute.getValue());
336                            }
337    
338                            jsonObject.put("id", dynamicElementElement.attributeValue("name"));
339    
340                            String type = jsonObject.getString("type");
341    
342                            List<Element> metadataElements = dynamicElementElement.elements(
343                                    "meta-data");
344    
345                            for (Element metadataElement : metadataElements) {
346                                    if (metadataElement == null) {
347                                            continue;
348                                    }
349    
350                                    String locale = metadataElement.attributeValue("locale");
351    
352                                    JSONObject localeMap = JSONFactoryUtil.createJSONObject();
353    
354                                    for (Element metadataEntryElement :
355                                                    metadataElement.elements()) {
356    
357                                            String attributeName = metadataEntryElement.attributeValue(
358                                                    "name");
359                                            String attributeValue = metadataEntryElement.getTextTrim();
360    
361                                            putMetadataValue(
362                                                    localeMap, attributeName, attributeValue, type);
363    
364                                            if (defaultLocale.equals(locale)) {
365                                                    putMetadataValue(
366                                                            jsonObject, attributeName, attributeValue, type);
367                                            }
368                                    }
369    
370                                    localizationMapJSONObject.put(locale, localeMap);
371                            }
372    
373                            jsonObject.put("localizationMap", localizationMapJSONObject);
374    
375                            JSONArray hiddenAttributesJSONArray =
376                                    JSONFactoryUtil.createJSONArray();
377    
378                            if (type.equals(DDMImpl.TYPE_CHECKBOX)) {
379                                    hiddenAttributesJSONArray.put("required");
380                            }
381    
382                            if (type.equals(DDMImpl.TYPE_DDM_FILEUPLOAD)) {
383                                    hiddenAttributesJSONArray.put("predefinedValue");
384                            }
385    
386                            hiddenAttributesJSONArray.put("readOnly");
387    
388                            jsonObject.put("hiddenAttributes", hiddenAttributesJSONArray);
389    
390                            String key = "fields";
391    
392                            if (type.equals(DDMImpl.TYPE_RADIO) ||
393                                    type.equals(DDMImpl.TYPE_SELECT)) {
394    
395                                    key = "options";
396                            }
397    
398                            jsonObject.put(key, getJSONArray(dynamicElementElement));
399    
400                            jsonArray.put(jsonObject);
401                    }
402    
403                    return jsonArray;
404            }
405    
406            public JSONArray getJSONArray(String xml)
407                    throws PortalException, SystemException {
408    
409                    try {
410                            return getJSONArray(SAXReaderUtil.read(xml));
411                    }
412                    catch (DocumentException de) {
413                            throw new SystemException();
414                    }
415            }
416    
417            public String getXSD(long classNameId, long classPK)
418                    throws PortalException, SystemException {
419    
420                    if ((classNameId <= 0) || (classPK <= 0)) {
421                            return null;
422                    }
423    
424                    long ddmStructureClassNameId = PortalUtil.getClassNameId(
425                            DDMStructure.class);
426    
427                    long ddmTemplateClassNameId = PortalUtil.getClassNameId(
428                            DDMTemplate.class);
429    
430                    if (classNameId == ddmStructureClassNameId) {
431                            DDMStructure structure = DDMStructureServiceUtil.getStructure(
432                                    classPK);
433    
434                            return structure.getCompleteXsd();
435                    }
436                    else if (classNameId == ddmTemplateClassNameId) {
437                            DDMTemplate template = DDMTemplateServiceUtil.getTemplate(classPK);
438    
439                            return template.getScript();
440                    }
441    
442                    return null;
443            }
444    
445            protected JSONArray addStructureFieldAttributes(
446                    DDMStructure structure, JSONArray jsonArray) {
447    
448                    for (int i = 0; i < jsonArray.length(); i++) {
449                            JSONObject jsonObject = jsonArray.getJSONObject(i);
450    
451                            String fieldName = jsonObject.getString("name");
452    
453                            jsonObject.put(
454                                    "readOnlyAttributes",
455                                    getStructureFieldReadOnlyAttributes(structure, fieldName));
456                    }
457    
458                    return jsonArray;
459            }
460    
461            protected Map<String, Object> getFieldContext(
462                    Element dynamicElementElement, Locale locale) {
463    
464                    Document document = dynamicElementElement.getDocument();
465    
466                    String[] availableLocales = LocalizationUtil.getAvailableLocales(
467                            document.asXML());
468    
469                    String defaultLanguageId = LocalizationUtil.getDefaultLocale(
470                            document.asXML());
471    
472                    String languageId = LocaleUtil.toLanguageId(locale);
473    
474                    if (!ArrayUtil.contains(availableLocales, languageId)) {
475                            languageId = defaultLanguageId;
476                    }
477    
478                    Element metadataElement =
479                            (Element)dynamicElementElement.selectSingleNode(
480                                    "meta-data[@locale='" + languageId + "']");
481    
482                    Map<String, Object> field = new HashMap<String, Object>();
483    
484                    if (metadataElement != null) {
485                            for (Element metadataEntry : metadataElement.elements()) {
486                                    field.put(
487                                            metadataEntry.attributeValue("name"),
488                                            metadataEntry.getText());
489                            }
490                    }
491    
492                    for (Attribute attribute : dynamicElementElement.attributes()) {
493                            field.put(attribute.getName(), attribute.getValue());
494                    }
495    
496                    return field;
497            }
498    
499            protected Map<String, Object> getFreeMarkerContext(
500                    Element dynamicElementElement, Locale locale) {
501    
502                    Map<String, Object> freeMarkerContext = new HashMap<String, Object>();
503    
504                    Map<String, Object> fieldContext = getFieldContext(
505                            dynamicElementElement, locale);
506    
507                    Map<String, Object> parentFieldContext = new HashMap<String, Object>();
508    
509                    Element parentElement = dynamicElementElement.getParent();
510    
511                    if (parentElement != null) {
512                            parentFieldContext = getFieldContext(parentElement, locale);
513                    }
514    
515                    freeMarkerContext.put("fieldStructure", fieldContext);
516                    freeMarkerContext.put("parentFieldStructure", parentFieldContext);
517                    freeMarkerContext.put("requestedLocale", locale);
518    
519                    return freeMarkerContext;
520            }
521    
522            protected URL getResource(String name) {
523                    Class<?> clazz = getClass();
524    
525                    ClassLoader classLoader = clazz.getClassLoader();
526    
527                    return classLoader.getResource(name);
528            }
529    
530            protected JSONArray getStructureFieldReadOnlyAttributes(
531                    DDMStructure structure, String fieldName) {
532    
533                    JSONArray jsonArray = JSONFactoryUtil.createJSONArray();
534    
535                    try {
536                            if (DDMStorageLinkLocalServiceUtil.getStructureStorageLinksCount(
537                                            structure.getStructureId()) > 0) {
538    
539                                    jsonArray.put("name");
540                            }
541                    }
542                    catch (Exception e) {
543                    }
544    
545                    return jsonArray;
546            }
547    
548            protected String processFTL(
549                            PageContext pageContext, Element element, String mode,
550                            boolean readOnly, Map<String, Object> freeMarkerContext)
551                    throws Exception {
552    
553                    String fieldNamespace = element.attributeValue(
554                            "fieldNamespace", _DEFAULT_NAMESPACE);
555    
556                    TemplateResource templateResource = _defaultTemplateResource;
557    
558                    Map<String, Object> fieldStructure =
559                            (Map<String, Object>)freeMarkerContext.get("fieldStructure");
560    
561                    boolean fieldReadOnly = GetterUtil.getBoolean(
562                            fieldStructure.get("readOnly"));
563    
564                    if ((fieldReadOnly && Validator.isNotNull(mode) &&
565                             mode.equalsIgnoreCase(
566                                    DDMTemplateConstants.TEMPLATE_MODE_EDIT)) || readOnly) {
567    
568                            fieldNamespace = _DEFAULT_READ_ONLY_NAMESPACE;
569    
570                            templateResource = _defaultReadOnlyTemplateResource;
571                    }
572    
573                    String type = element.attributeValue("type");
574    
575                    String templateName = StringUtil.replaceFirst(
576                            type, fieldNamespace.concat(StringPool.DASH), StringPool.BLANK);
577    
578                    StringBundler resourcePath = new StringBundler(5);
579    
580                    resourcePath.append(_TPL_PATH);
581                    resourcePath.append(fieldNamespace.toLowerCase());
582                    resourcePath.append(CharPool.SLASH);
583                    resourcePath.append(templateName);
584                    resourcePath.append(_TPL_EXT);
585    
586                    String resource = resourcePath.toString();
587    
588                    URL url = getResource(resource);
589    
590                    if (url != null) {
591                            templateResource = new URLTemplateResource(resource, url);
592                    }
593    
594                    if (templateResource == null) {
595                            throw new Exception("Unable to load template resource " + resource);
596                    }
597    
598                    Template template = TemplateManagerUtil.getTemplate(
599                            TemplateManager.FREEMARKER, templateResource,
600                            TemplateContextType.STANDARD);
601    
602                    for (Map.Entry<String, Object> entry : freeMarkerContext.entrySet()) {
603                            template.put(entry.getKey(), entry.getValue());
604                    }
605    
606                    return processFTL(pageContext, template);
607            }
608    
609            /**
610             * @see com.liferay.taglib.util.ThemeUtil#includeFTL
611             */
612            protected String processFTL(PageContext pageContext, Template template)
613                    throws Exception {
614    
615                    HttpServletRequest request =
616                            (HttpServletRequest)pageContext.getRequest();
617    
618                    // FreeMarker variables
619    
620                    template.prepare(request);
621    
622                    // Tag libraries
623    
624                    HttpServletResponse response =
625                            (HttpServletResponse)pageContext.getResponse();
626    
627                    Writer writer = new UnsyncStringWriter();
628    
629                    // Portal JSP tag library factory
630    
631                    TemplateHashModel portalTaglib =
632                            FreeMarkerTaglibFactoryUtil.createTaglibFactory(
633                                    pageContext.getServletContext());
634    
635                    template.put("PortalJspTagLibs", portalTaglib);
636    
637                    // FreeMarker JSP tag library support
638    
639                    final Servlet servlet = (Servlet)pageContext.getPage();
640    
641                    GenericServlet genericServlet = null;
642    
643                    if (servlet instanceof GenericServlet) {
644                            genericServlet = (GenericServlet)servlet;
645                    }
646                    else {
647                            genericServlet = new GenericServlet() {
648    
649                                    @Override
650                                    public void service(
651                                                    ServletRequest servletRequest,
652                                                    ServletResponse servletResponse)
653                                            throws IOException, ServletException {
654    
655                                            servlet.service(servletRequest, servletResponse);
656                                    }
657    
658                            };
659    
660                            genericServlet.init(pageContext.getServletConfig());
661                    }
662    
663                    ServletContextHashModel servletContextHashModel =
664                            new ServletContextHashModel(
665                                    genericServlet, ObjectWrapper.DEFAULT_WRAPPER);
666    
667                    template.put("Application", servletContextHashModel);
668    
669                    HttpRequestHashModel httpRequestHashModel = new HttpRequestHashModel(
670                            request, response, ObjectWrapper.DEFAULT_WRAPPER);
671    
672                    template.put("Request", httpRequestHashModel);
673    
674                    // Merge templates
675    
676                    template.processTemplate(writer);
677    
678                    return writer.toString();
679            }
680    
681            protected void putMetadataValue(
682                    JSONObject jsonObject, String attributeName, String attributeValue,
683                    String type) {
684    
685                    if (type.equals(DDMImpl.TYPE_RADIO) ||
686                            type.equals(DDMImpl.TYPE_SELECT)) {
687    
688                            if (attributeName.equals("predefinedValue")) {
689                                    try {
690                                            jsonObject.put(
691                                                    attributeName,
692                                                    JSONFactoryUtil.createJSONArray(attributeValue));
693                                    }
694                                    catch (Exception e) {
695                                    }
696    
697                                    return;
698                            }
699                    }
700    
701                    jsonObject.put(attributeName, attributeValue);
702            }
703    
704            private static final String _DEFAULT_NAMESPACE = "alloy";
705    
706            private static final String _DEFAULT_READ_ONLY_NAMESPACE = "readonly";
707    
708            private static final String _TPL_EXT = ".ftl";
709    
710            private static final String _TPL_PATH =
711                    "com/liferay/portlet/dynamicdatamapping/dependencies/";
712    
713            private TemplateResource _defaultReadOnlyTemplateResource;
714            private TemplateResource _defaultTemplateResource;
715    
716    }