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