001
014
015 package com.liferay.portlet.dynamicdatamapping.util;
016
017 import com.liferay.portal.kernel.freemarker.FreeMarkerContext;
018 import com.liferay.portal.kernel.freemarker.FreeMarkerEngineUtil;
019 import com.liferay.portal.kernel.freemarker.FreeMarkerVariablesUtil;
020 import com.liferay.portal.kernel.io.unsync.UnsyncStringWriter;
021 import com.liferay.portal.kernel.json.JSONArray;
022 import com.liferay.portal.kernel.json.JSONException;
023 import com.liferay.portal.kernel.json.JSONFactoryUtil;
024 import com.liferay.portal.kernel.json.JSONObject;
025 import com.liferay.portal.kernel.util.ArrayUtil;
026 import com.liferay.portal.kernel.util.CharPool;
027 import com.liferay.portal.kernel.util.GetterUtil;
028 import com.liferay.portal.kernel.util.LocaleUtil;
029 import com.liferay.portal.kernel.util.LocalizationUtil;
030 import com.liferay.portal.kernel.util.StringBundler;
031 import com.liferay.portal.kernel.util.StringPool;
032 import com.liferay.portal.kernel.util.StringUtil;
033 import com.liferay.portal.kernel.util.Validator;
034 import com.liferay.portal.kernel.xml.Attribute;
035 import com.liferay.portal.kernel.xml.Document;
036 import com.liferay.portal.kernel.xml.DocumentException;
037 import com.liferay.portal.kernel.xml.Element;
038 import com.liferay.portal.kernel.xml.SAXReaderUtil;
039 import com.liferay.portal.util.PortalUtil;
040 import com.liferay.portlet.dynamicdatamapping.model.DDMStructure;
041 import com.liferay.portlet.dynamicdatamapping.model.DDMTemplate;
042 import com.liferay.portlet.dynamicdatamapping.model.DDMTemplateConstants;
043 import com.liferay.portlet.dynamicdatamapping.storage.Fields;
044 import com.liferay.util.freemarker.FreeMarkerTaglibFactoryUtil;
045
046 import freemarker.ext.servlet.HttpRequestHashModel;
047 import freemarker.ext.servlet.ServletContextHashModel;
048
049 import freemarker.template.ObjectWrapper;
050 import freemarker.template.TemplateHashModel;
051
052 import java.io.IOException;
053 import java.io.Writer;
054
055 import java.util.HashMap;
056 import java.util.List;
057 import java.util.Locale;
058 import java.util.Map;
059
060 import javax.servlet.GenericServlet;
061 import javax.servlet.Servlet;
062 import javax.servlet.ServletException;
063 import javax.servlet.ServletRequest;
064 import javax.servlet.ServletResponse;
065 import javax.servlet.http.HttpServletRequest;
066 import javax.servlet.http.HttpServletResponse;
067 import javax.servlet.jsp.PageContext;
068
069
074 public class DDMXSDImpl implements DDMXSD {
075
076 @Override
077 public String getHTML(
078 PageContext pageContext, DDMStructure ddmStructure, Fields fields,
079 String namespace, boolean readOnly, Locale locale)
080 throws Exception {
081
082 return getHTML(
083 pageContext, ddmStructure.getXsd(), fields, namespace, readOnly,
084 locale);
085 }
086
087 @Override
088 public String getHTML(
089 PageContext pageContext, DDMTemplate ddmTemplate, Fields fields,
090 String namespace, boolean readOnly, Locale locale)
091 throws Exception {
092
093 return getHTML(
094 pageContext, ddmTemplate.getScript(), fields, namespace,
095 ddmTemplate.getMode(), readOnly, locale);
096 }
097
098 public String getHTML(
099 PageContext pageContext, Element element, Fields fields,
100 Locale locale)
101 throws Exception {
102
103 return getHTML(
104 pageContext, element, fields, StringPool.BLANK, null, false,
105 locale);
106 }
107
108 public String getHTML(
109 PageContext pageContext, Element element, Fields fields,
110 String namespace, String mode, boolean readOnly, Locale locale)
111 throws Exception {
112
113 StringBundler sb = new StringBundler();
114
115 HttpServletRequest request =
116 (HttpServletRequest)pageContext.getRequest();
117
118 String portletId = PortalUtil.getPortletId(request);
119
120 String portletNamespace = PortalUtil.getPortletNamespace(portletId);
121
122 List<Element> dynamicElementElements = element.elements(
123 "dynamic-element");
124
125 for (Element dynamicElementElement : dynamicElementElements) {
126 FreeMarkerContext freeMarkerContext = getFreeMarkerContext(
127 dynamicElementElement, locale);
128
129 freeMarkerContext.put("portletNamespace", portletNamespace);
130 freeMarkerContext.put("namespace", namespace);
131
132 if (fields != null) {
133 freeMarkerContext.put("fields", fields);
134 }
135
136 Map<String, Object> field =
137 (Map<String, Object>)freeMarkerContext.get("fieldStructure");
138
139 String childrenHTML = getHTML(
140 pageContext, dynamicElementElement, fields, namespace, mode,
141 readOnly, locale);
142
143 field.put("children", childrenHTML);
144
145 String fieldNamespace = dynamicElementElement.attributeValue(
146 "fieldNamespace", _DEFAULT_NAMESPACE);
147
148 String defaultResourcePath = _TPL_DEFAULT_PATH;
149
150 boolean fieldReadOnly = GetterUtil.getBoolean(
151 field.get("readOnly"));
152
153 if ((fieldReadOnly && Validator.isNotNull(mode) &&
154 mode.equalsIgnoreCase(
155 DDMTemplateConstants.TEMPLATE_MODE_EDIT)) || readOnly) {
156
157 fieldNamespace = _DEFAULT_READ_ONLY_NAMESPACE;
158
159 defaultResourcePath = _TPL_DEFAULT_READ_ONLY_PATH;
160 }
161
162 String type = dynamicElementElement.attributeValue("type");
163
164 String templateName = StringUtil.replaceFirst(
165 type, fieldNamespace.concat(StringPool.DASH), StringPool.BLANK);
166
167 StringBundler resourcePath = new StringBundler(5);
168
169 resourcePath.append(_TPL_PATH);
170 resourcePath.append(fieldNamespace.toLowerCase());
171 resourcePath.append(CharPool.SLASH);
172 resourcePath.append(templateName);
173 resourcePath.append(_TPL_EXT);
174
175 sb.append(
176 processFTL(
177 pageContext, freeMarkerContext, resourcePath.toString(),
178 defaultResourcePath));
179 }
180
181 return sb.toString();
182 }
183
184 public String getHTML(
185 PageContext pageContext, Element element, Locale locale)
186 throws Exception {
187
188 return getHTML(pageContext, element, null, locale);
189 }
190
191 @Override
192 public String getHTML(
193 PageContext pageContext, String xml, Fields fields, Locale locale)
194 throws Exception {
195
196 return getHTML(pageContext, xml, fields, StringPool.BLANK, locale);
197 }
198
199 @Override
200 public String getHTML(
201 PageContext pageContext, String xml, Fields fields,
202 String namespace, boolean readOnly, Locale locale)
203 throws Exception {
204
205 return getHTML(
206 pageContext, xml, fields, namespace, null, readOnly, locale);
207 }
208
209 @Override
210 public String getHTML(
211 PageContext pageContext, String xml, Fields fields,
212 String namespace, Locale locale)
213 throws Exception {
214
215 return getHTML(pageContext, xml, fields, namespace, false, locale);
216 }
217
218 public String getHTML(
219 PageContext pageContext, String xml, Fields fields,
220 String namespace, String mode, boolean readOnly, Locale locale)
221 throws Exception {
222
223 Document document = SAXReaderUtil.read(xml);
224
225 return getHTML(
226 pageContext, document.getRootElement(), fields, namespace, mode,
227 readOnly, locale);
228 }
229
230 @Override
231 public String getHTML(PageContext pageContext, String xml, Locale locale)
232 throws Exception {
233
234 return getHTML(pageContext, xml, null, locale);
235 }
236
237 @Override
238 public JSONArray getJSONArray(Document document) throws JSONException {
239 return getJSONArray(document.getRootElement());
240 }
241
242 @Override
243 public JSONArray getJSONArray(Element element) throws JSONException {
244 JSONArray jsonArray = JSONFactoryUtil.createJSONArray();
245
246 Document document = element.getDocument();
247
248 String defaultLocale = LocalizationUtil.getDefaultLocale(
249 document.asXML());
250
251 List<Element> dynamicElementElements = element.elements(
252 "dynamic-element");
253
254 for (Element dynamicElementElement : dynamicElementElements) {
255 JSONObject jsonObject = JSONFactoryUtil.createJSONObject();
256 JSONObject localizationMapJSONObject =
257 JSONFactoryUtil.createJSONObject();
258
259 for (Attribute attribute : dynamicElementElement.attributes()) {
260 jsonObject.put(attribute.getName(), attribute.getValue());
261 }
262
263 jsonObject.put("id", dynamicElementElement.attributeValue("name"));
264
265 String type = jsonObject.getString("type");
266
267 List<Element> metadataElements = dynamicElementElement.elements(
268 "meta-data");
269
270 for (Element metadataElement : metadataElements) {
271 if (metadataElement == null) {
272 continue;
273 }
274
275 String locale = metadataElement.attributeValue("locale");
276
277 JSONObject localeMap = JSONFactoryUtil.createJSONObject();
278
279 for (Element metadataEntryElement :
280 metadataElement.elements()) {
281
282 String attributeName = metadataEntryElement.attributeValue(
283 "name");
284 String attributeValue = metadataEntryElement.getTextTrim();
285
286 putMetadataValue(
287 localeMap, attributeName, attributeValue, type);
288
289 if (defaultLocale.equals(locale)) {
290 putMetadataValue(
291 jsonObject, attributeName, attributeValue, type);
292 }
293 }
294
295 localizationMapJSONObject.put(locale, localeMap);
296 }
297
298 jsonObject.put("localizationMap", localizationMapJSONObject);
299
300 JSONArray hiddenAttributesJSONArray =
301 JSONFactoryUtil.createJSONArray();
302
303 if (type.equals(DDMImpl.TYPE_CHECKBOX)) {
304 hiddenAttributesJSONArray.put("required");
305 }
306
307 if (type.equals(DDMImpl.TYPE_DDM_FILEUPLOAD)) {
308 hiddenAttributesJSONArray.put("predefinedValue");
309 }
310
311 hiddenAttributesJSONArray.put("readOnly");
312
313 jsonObject.put("hiddenAttributes", hiddenAttributesJSONArray);
314
315 String key = "fields";
316
317 if (type.equals(DDMImpl.TYPE_RADIO) ||
318 type.equals(DDMImpl.TYPE_SELECT)) {
319
320 key = "options";
321 }
322
323 jsonObject.put(key, getJSONArray(dynamicElementElement));
324
325 jsonArray.put(jsonObject);
326 }
327
328 return jsonArray;
329 }
330
331 @Override
332 public JSONArray getJSONArray(String xml)
333 throws DocumentException, JSONException {
334
335 return getJSONArray(SAXReaderUtil.read(xml));
336 }
337
338 protected Map<String, Object> getFieldContext(
339 Element dynamicElementElement, Locale locale) {
340
341 Document document = dynamicElementElement.getDocument();
342
343 String xml = document.asXML();
344
345 String[] availableLocales = LocalizationUtil.getAvailableLocales(xml);
346
347 String defaultLanguageId = LocalizationUtil.getDefaultLocale(xml);
348
349 String languageId = LocaleUtil.toLanguageId(locale);
350
351 if (!ArrayUtil.contains(availableLocales, languageId)) {
352 languageId = defaultLanguageId;
353 }
354
355 Element metadataElement =
356 (Element)dynamicElementElement.selectSingleNode(
357 "meta-data[@locale='" + languageId + "']");
358
359 Map<String, Object> field = new HashMap<String, Object>();
360
361 if (metadataElement != null) {
362 for (Element metadataEntry : metadataElement.elements()) {
363 field.put(
364 metadataEntry.attributeValue("name"),
365 metadataEntry.getText());
366 }
367 }
368
369 for (Attribute attribute : dynamicElementElement.attributes()) {
370 field.put(attribute.getName(), attribute.getValue());
371 }
372
373 return field;
374 }
375
376 protected FreeMarkerContext getFreeMarkerContext(
377 Element dynamicElementElement, Locale locale) {
378
379 FreeMarkerContext freeMarkerContext =
380 FreeMarkerEngineUtil.getWrappedStandardToolsContext();
381
382 Map<String, Object> fieldContext = getFieldContext(
383 dynamicElementElement, locale);
384
385 Map<String, Object> parentFieldContext = new HashMap<String, Object>();
386
387 Element parentElement = dynamicElementElement.getParent();
388
389 if (parentElement != null) {
390 parentFieldContext = getFieldContext(parentElement, locale);
391 }
392
393 freeMarkerContext.put("fieldStructure", fieldContext);
394 freeMarkerContext.put("parentFieldStructure", parentFieldContext);
395
396 return freeMarkerContext;
397 }
398
399
402 protected String processFTL(
403 PageContext pageContext, FreeMarkerContext freeMarkerContext,
404 String resourcePath, String defaultResourcePath)
405 throws Exception {
406
407 if (!FreeMarkerEngineUtil.resourceExists(resourcePath)) {
408 resourcePath = defaultResourcePath;
409 }
410
411 HttpServletRequest request =
412 (HttpServletRequest)pageContext.getRequest();
413
414
415
416 FreeMarkerVariablesUtil.insertVariables(freeMarkerContext, request);
417
418
419
420 HttpServletResponse response =
421 (HttpServletResponse)pageContext.getResponse();
422
423 Writer writer = new UnsyncStringWriter();
424
425
426
427 TemplateHashModel portalTaglib =
428 FreeMarkerTaglibFactoryUtil.createTaglibFactory(
429 pageContext.getServletContext());
430
431 freeMarkerContext.put("PortalJspTagLibs", portalTaglib);
432
433
434
435 final Servlet servlet = (Servlet)pageContext.getPage();
436
437 GenericServlet genericServlet = null;
438
439 if (servlet instanceof GenericServlet) {
440 genericServlet = (GenericServlet)servlet;
441 }
442 else {
443 genericServlet = new GenericServlet() {
444
445 @Override
446 public void service(
447 ServletRequest servletRequest,
448 ServletResponse servletResponse)
449 throws IOException, ServletException {
450
451 servlet.service(servletRequest, servletResponse);
452 }
453
454 };
455
456 genericServlet.init(pageContext.getServletConfig());
457 }
458
459 ServletContextHashModel servletContextHashModel =
460 new ServletContextHashModel(
461 genericServlet, ObjectWrapper.DEFAULT_WRAPPER);
462
463 freeMarkerContext.put("Application", servletContextHashModel);
464
465 HttpRequestHashModel httpRequestHashModel = new HttpRequestHashModel(
466 request, response, ObjectWrapper.DEFAULT_WRAPPER);
467
468 freeMarkerContext.put("Request", httpRequestHashModel);
469
470
471
472 FreeMarkerEngineUtil.mergeTemplate(
473 resourcePath, freeMarkerContext, writer);
474
475 return writer.toString();
476 }
477
478 protected void putMetadataValue(
479 JSONObject jsonObject, String attributeName, String attributeValue,
480 String type) {
481
482 if (type.equals(DDMImpl.TYPE_RADIO) ||
483 type.equals(DDMImpl.TYPE_SELECT)) {
484
485 if (attributeName.equals("predefinedValue")) {
486 try {
487 jsonObject.put(
488 attributeName,
489 JSONFactoryUtil.createJSONArray(attributeValue));
490 }
491 catch (Exception e) {
492 }
493
494 return;
495 }
496 }
497
498 jsonObject.put(attributeName, attributeValue);
499 }
500
501 private static final String _DEFAULT_NAMESPACE = "alloy";
502
503 private static final String _DEFAULT_READ_ONLY_NAMESPACE = "readonly";
504
505 private static final String _TPL_DEFAULT_PATH =
506 "com/liferay/portlet/dynamicdatamapping/dependencies/alloy/text.ftl";
507
508 private static final String _TPL_DEFAULT_READ_ONLY_PATH =
509 "com/liferay/portlet/dynamicdatamapping/dependencies/readonly/" +
510 "default.ftl";
511
512 private static final String _TPL_EXT = ".ftl";
513
514 private static final String _TPL_PATH =
515 "com/liferay/portlet/dynamicdatamapping/dependencies/";
516
517 }