001
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
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 "
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
612 protected String processFTL(PageContext pageContext, Template template)
613 throws Exception {
614
615 HttpServletRequest request =
616 (HttpServletRequest)pageContext.getRequest();
617
618
619
620 template.prepare(request);
621
622
623
624 HttpServletResponse response =
625 (HttpServletResponse)pageContext.getResponse();
626
627 Writer writer = new UnsyncStringWriter();
628
629
630
631 TemplateHashModel portalTaglib =
632 FreeMarkerTaglibFactoryUtil.createTaglibFactory(
633 pageContext.getServletContext());
634
635 template.put("PortalJspTagLibs", portalTaglib);
636
637
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
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 }