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