001
014
015 package com.liferay.portal.templateparser;
016
017 import com.liferay.portal.kernel.configuration.Filter;
018 import com.liferay.portal.kernel.io.unsync.UnsyncStringWriter;
019 import com.liferay.portal.kernel.log.Log;
020 import com.liferay.portal.kernel.log.LogFactoryUtil;
021 import com.liferay.portal.kernel.mobile.device.Device;
022 import com.liferay.portal.kernel.mobile.device.UnknownDevice;
023 import com.liferay.portal.kernel.portlet.PortletRequestModel;
024 import com.liferay.portal.kernel.template.StringTemplateResource;
025 import com.liferay.portal.kernel.template.Template;
026 import com.liferay.portal.kernel.template.TemplateConstants;
027 import com.liferay.portal.kernel.template.TemplateManagerUtil;
028 import com.liferay.portal.kernel.template.TemplateResource;
029 import com.liferay.portal.kernel.template.URLTemplateResource;
030 import com.liferay.portal.kernel.templateparser.TemplateNode;
031 import com.liferay.portal.kernel.templateparser.TransformException;
032 import com.liferay.portal.kernel.templateparser.TransformerListener;
033 import com.liferay.portal.kernel.util.Constants;
034 import com.liferay.portal.kernel.util.GetterUtil;
035 import com.liferay.portal.kernel.util.InstanceFactory;
036 import com.liferay.portal.kernel.util.LocaleUtil;
037 import com.liferay.portal.kernel.util.LocalizationUtil;
038 import com.liferay.portal.kernel.util.PortalClassLoaderUtil;
039 import com.liferay.portal.kernel.util.PropertiesUtil;
040 import com.liferay.portal.kernel.util.SetUtil;
041 import com.liferay.portal.kernel.util.StringBundler;
042 import com.liferay.portal.kernel.util.StringPool;
043 import com.liferay.portal.kernel.util.StringUtil;
044 import com.liferay.portal.kernel.util.Validator;
045 import com.liferay.portal.kernel.xml.Attribute;
046 import com.liferay.portal.kernel.xml.Document;
047 import com.liferay.portal.kernel.xml.DocumentException;
048 import com.liferay.portal.kernel.xml.Element;
049 import com.liferay.portal.kernel.xml.SAXReaderUtil;
050 import com.liferay.portal.model.Company;
051 import com.liferay.portal.security.permission.PermissionThreadLocal;
052 import com.liferay.portal.service.CompanyLocalServiceUtil;
053 import com.liferay.portal.theme.ThemeDisplay;
054 import com.liferay.portal.util.PropsUtil;
055 import com.liferay.portal.xsl.XSLTemplateResource;
056 import com.liferay.portal.xsl.XSLURIResolver;
057 import com.liferay.portlet.journal.util.JournalXSLURIResolver;
058 import com.liferay.portlet.portletdisplaytemplate.util.PortletDisplayTemplateConstants;
059 import com.liferay.taglib.util.VelocityTaglib;
060
061 import java.io.IOException;
062
063 import java.net.URL;
064
065 import java.util.ArrayList;
066 import java.util.HashMap;
067 import java.util.HashSet;
068 import java.util.List;
069 import java.util.Locale;
070 import java.util.Map;
071 import java.util.Set;
072
073
082 public class Transformer {
083
084 public Transformer(String errorTemplatePropertyKey, boolean restricted) {
085 Set<String> langTypes = TemplateManagerUtil.getSupportedLanguageTypes(
086 errorTemplatePropertyKey);
087
088 for (String langType : langTypes) {
089 String errorTemplateId = PropsUtil.get(
090 errorTemplatePropertyKey, new Filter(langType));
091
092 if (Validator.isNotNull(errorTemplateId)) {
093 _errorTemplateIds.put(langType, errorTemplateId);
094 }
095 }
096
097 _restricted = restricted;
098 }
099
100 public Transformer(
101 String transformerListenerPropertyKey, String errorTemplatePropertyKey,
102 boolean restricted) {
103
104 this(errorTemplatePropertyKey, restricted);
105
106 ClassLoader classLoader = PortalClassLoaderUtil.getClassLoader();
107
108 Set<String> transformerListenerClassNames = SetUtil.fromArray(
109 PropsUtil.getArray(transformerListenerPropertyKey));
110
111 for (String transformerListenerClassName :
112 transformerListenerClassNames) {
113
114 try {
115 if (_log.isDebugEnabled()) {
116 _log.debug(
117 "Instantiating transformer listener " +
118 transformerListenerClassName);
119 }
120
121 TransformerListener transformerListener =
122 (TransformerListener)InstanceFactory.newInstance(
123 classLoader, transformerListenerClassName);
124
125 _transformerListeners.add(transformerListener);
126 }
127 catch (Exception e) {
128 _log.error(e, e);
129 }
130 }
131 }
132
133 public String doTransform(
134 ThemeDisplay themeDisplay, Map<String, String> tokens,
135 String viewMode, String languageId, Document document,
136 PortletRequestModel portletRequestModel, String script,
137 String langType)
138 throws Exception {
139
140 return transform(
141 themeDisplay, tokens, viewMode, languageId, document,
142 portletRequestModel, script, langType, true);
143 }
144
145 public String transform(
146 ThemeDisplay themeDisplay, Map<String, Object> contextObjects,
147 String script, String langType)
148 throws Exception {
149
150 if (Validator.isNull(langType)) {
151 return null;
152 }
153
154 long companyId = 0;
155 long companyGroupId = 0;
156 long scopeGroupId = 0;
157 long siteGroupId = 0;
158
159 if (themeDisplay != null) {
160 companyId = themeDisplay.getCompanyId();
161 companyGroupId = themeDisplay.getCompanyGroupId();
162 scopeGroupId = themeDisplay.getScopeGroupId();
163 siteGroupId = themeDisplay.getSiteGroupId();
164 }
165
166 String templateId = String.valueOf(contextObjects.get("template_id"));
167
168 templateId = getTemplateId(
169 templateId, companyId, companyGroupId, scopeGroupId);
170
171 Template template = getTemplate(templateId, script, langType);
172
173 UnsyncStringWriter unsyncStringWriter = new UnsyncStringWriter();
174
175 try {
176 prepareTemplate(themeDisplay, template);
177
178 if (contextObjects != null) {
179 for (String key : contextObjects.keySet()) {
180 template.put(key, contextObjects.get(key));
181 }
182 }
183
184 template.put("company", getCompany(themeDisplay, companyId));
185 template.put("companyId", companyId);
186 template.put("device", getDevice(themeDisplay));
187
188 String templatesPath = getTemplatesPath(companyId, scopeGroupId);
189
190 template.put(
191 "permissionChecker",
192 PermissionThreadLocal.getPermissionChecker());
193 template.put(
194 "randomNamespace",
195 StringUtil.randomId() + StringPool.UNDERLINE);
196 template.put("scopeGroupId", scopeGroupId);
197 template.put("siteGroupId", siteGroupId);
198 template.put("templatesPath", templatesPath);
199
200
201
202 template.put("groupId", scopeGroupId);
203 template.put("journalTemplatesPath", templatesPath);
204
205 mergeTemplate(template, unsyncStringWriter, false);
206 }
207 catch (Exception e) {
208 throw new TransformException("Unhandled exception", e);
209 }
210
211 return unsyncStringWriter.toString();
212 }
213
214 public String transform(
215 ThemeDisplay themeDisplay, Map<String, String> tokens,
216 String viewMode, String languageId, Document document,
217 PortletRequestModel portletRequestModel, String script,
218 String langType)
219 throws Exception {
220
221 return transform(
222 themeDisplay, tokens, viewMode, languageId, document,
223 portletRequestModel, script, langType, false);
224 }
225
226 protected Company getCompany(ThemeDisplay themeDisplay, long companyId)
227 throws Exception {
228
229 if (themeDisplay != null) {
230 return themeDisplay.getCompany();
231 }
232
233 return CompanyLocalServiceUtil.getCompany(companyId);
234 }
235
236 protected Device getDevice(ThemeDisplay themeDisplay) {
237 if (themeDisplay != null) {
238 return themeDisplay.getDevice();
239 }
240
241 return UnknownDevice.getInstance();
242 }
243
244 protected TemplateResource getErrorTemplateResource(String langType) {
245 try {
246 Class<?> clazz = getClass();
247
248 ClassLoader classLoader = clazz.getClassLoader();
249
250 String errorTemplateId = _errorTemplateIds.get(langType);
251
252 URL url = classLoader.getResource(errorTemplateId);
253
254 return new URLTemplateResource(errorTemplateId, url);
255 }
256 catch (Exception e) {
257 }
258
259 return null;
260 }
261
262 protected Template getTemplate(
263 String templateId, Map<String, String> tokens, String languageId,
264 Document document, String script, String langType)
265 throws Exception {
266
267 TemplateResource templateResource = null;
268
269 if (langType.equals(TemplateConstants.LANG_TYPE_XSL)) {
270 XSLURIResolver xslURIResolver = new JournalXSLURIResolver(
271 tokens, languageId);
272
273 templateResource = new XSLTemplateResource(
274 templateId, script, xslURIResolver, document.asXML());
275 }
276 else {
277 templateResource = new StringTemplateResource(templateId, script);
278 }
279
280 TemplateResource errorTemplateResource = getErrorTemplateResource(
281 langType);
282
283 return TemplateManagerUtil.getTemplate(
284 langType, templateResource, errorTemplateResource, _restricted);
285 }
286
287 protected Template getTemplate(
288 String templateId, String script, String langType)
289 throws Exception {
290
291 TemplateResource templateResource = new StringTemplateResource(
292 templateId, script);
293
294 TemplateResource errorTemplateResource = getErrorTemplateResource(
295 langType);
296
297 return TemplateManagerUtil.getTemplate(
298 langType, templateResource, errorTemplateResource, _restricted);
299 }
300
301 protected String getTemplateId(
302 String templateId, long companyId, long companyGroupId, long groupId) {
303
304 StringBundler sb = new StringBundler(5);
305
306 sb.append(companyId);
307 sb.append(StringPool.POUND);
308
309 if (companyGroupId > 0) {
310 sb.append(companyGroupId);
311 }
312 else {
313 sb.append(groupId);
314 }
315
316 sb.append(StringPool.POUND);
317 sb.append(templateId);
318
319 return sb.toString();
320 }
321
322 protected List<TemplateNode> getTemplateNodes(
323 ThemeDisplay themeDisplay, Element element)
324 throws Exception {
325
326 List<TemplateNode> templateNodes = new ArrayList<TemplateNode>();
327
328 Map<String, TemplateNode> prototypeTemplateNodes =
329 new HashMap<String, TemplateNode>();
330
331 List<Element> dynamicElementElements = element.elements(
332 "dynamic-element");
333
334 for (Element dynamicElementElement : dynamicElementElements) {
335 Element dynamicContentElement = dynamicElementElement.element(
336 "dynamic-content");
337
338 String data = StringPool.BLANK;
339
340 if (dynamicContentElement != null) {
341 data = dynamicContentElement.getText();
342 }
343
344 String name = dynamicElementElement.attributeValue(
345 "name", StringPool.BLANK);
346
347 if (name.length() == 0) {
348 throw new TransformException(
349 "Element missing \"name\" attribute");
350 }
351
352 String type = dynamicElementElement.attributeValue(
353 "type", StringPool.BLANK);
354
355 Map<String, String> attributes = new HashMap<String, String>();
356
357 if (dynamicContentElement != null) {
358 for (Attribute attribute : dynamicContentElement.attributes()) {
359 attributes.put(attribute.getName(), attribute.getValue());
360 }
361 }
362
363 TemplateNode templateNode = new TemplateNode(
364 themeDisplay, name, StringUtil.stripCDATA(data), type,
365 attributes);
366
367 if (dynamicElementElement.element("dynamic-element") != null) {
368 templateNode.appendChildren(
369 getTemplateNodes(themeDisplay, dynamicElementElement));
370 }
371 else if ((dynamicContentElement != null) &&
372 (dynamicContentElement.element("option") != null)) {
373
374 List<Element> optionElements = dynamicContentElement.elements(
375 "option");
376
377 for (Element optionElement : optionElements) {
378 templateNode.appendOption(
379 StringUtil.stripCDATA(optionElement.getText()));
380 }
381 }
382
383 TemplateNode prototypeTemplateNode = prototypeTemplateNodes.get(
384 name);
385
386 if (prototypeTemplateNode == null) {
387 prototypeTemplateNode = templateNode;
388
389 prototypeTemplateNodes.put(name, prototypeTemplateNode);
390
391 templateNodes.add(templateNode);
392 }
393
394 prototypeTemplateNode.appendSibling(templateNode);
395 }
396
397 return templateNodes;
398 }
399
400 protected String getTemplatesPath(long companyId, long groupId) {
401 StringBundler sb = new StringBundler(5);
402
403 sb.append(TemplateConstants.TEMPLATE_SEPARATOR);
404 sb.append(StringPool.SLASH);
405 sb.append(companyId);
406 sb.append(StringPool.SLASH);
407 sb.append(groupId);
408
409 return sb.toString();
410 }
411
412 protected Map<String, Object> insertRequestVariables(Element element) {
413 Map<String, Object> map = new HashMap<String, Object>();
414
415 if (element == null) {
416 return map;
417 }
418
419 for (Element childElement : element.elements()) {
420 String name = childElement.getName();
421
422 if (name.equals("attribute")) {
423 Element nameElement = childElement.element("name");
424 Element valueElement = childElement.element("value");
425
426 map.put(nameElement.getText(), valueElement.getText());
427 }
428 else if (name.equals("parameter")) {
429 Element nameElement = childElement.element("name");
430
431 List<Element> valueElements = childElement.elements("value");
432
433 if (valueElements.size() == 1) {
434 Element valueElement = valueElements.get(0);
435
436 map.put(nameElement.getText(), valueElement.getText());
437 }
438 else {
439 List<String> values = new ArrayList<String>();
440
441 for (Element valueElement : valueElements) {
442 values.add(valueElement.getText());
443 }
444
445 map.put(nameElement.getText(), values);
446 }
447 }
448 else {
449 List<Element> elements = childElement.elements();
450
451 if (!elements.isEmpty()) {
452 map.put(name, insertRequestVariables(childElement));
453 }
454 else {
455 map.put(name, childElement.getText());
456 }
457 }
458 }
459
460 return map;
461 }
462
463 protected void mergeTemplate(
464 Template template, UnsyncStringWriter unsyncStringWriter,
465 boolean propagateException)
466 throws Exception {
467
468 VelocityTaglib velocityTaglib = (VelocityTaglib)template.get(
469 PortletDisplayTemplateConstants.TAGLIB_LIFERAY);
470
471 if (velocityTaglib != null) {
472 velocityTaglib.setTemplate(template);
473 }
474
475 if (propagateException) {
476 template.doProcessTemplate(unsyncStringWriter);
477 }
478 else {
479 template.processTemplate(unsyncStringWriter);
480 }
481 }
482
483 protected void prepareTemplate(ThemeDisplay themeDisplay, Template template)
484 throws Exception {
485
486 if (themeDisplay == null) {
487 return;
488 }
489
490 template.prepare(themeDisplay.getRequest());
491 }
492
493 protected String transform(
494 ThemeDisplay themeDisplay, Map<String, String> tokens,
495 String viewMode, String languageId, Document document,
496 PortletRequestModel portletRequestModel, String script,
497 String langType, boolean propagateException)
498 throws Exception {
499
500
501
502 if (_log.isDebugEnabled()) {
503 _log.debug("Language " + languageId);
504 }
505
506 if (Validator.isNull(viewMode)) {
507 viewMode = Constants.VIEW;
508 }
509
510 if (_logTokens.isDebugEnabled()) {
511 String tokensString = PropertiesUtil.list(tokens);
512
513 _logTokens.debug(tokensString);
514 }
515
516 if (_logTransformBefore.isDebugEnabled()) {
517 _logTransformBefore.debug(document);
518 }
519
520 for (TransformerListener transformerListener : _transformerListeners) {
521
522
523
524 if (_logXmlBeforeListener.isDebugEnabled()) {
525 _logXmlBeforeListener.debug(document);
526 }
527
528 if (transformerListener != null) {
529 document = transformerListener.onXml(
530 document, languageId, tokens);
531
532 if (_logXmlAfterListener.isDebugEnabled()) {
533 _logXmlAfterListener.debug(document);
534 }
535 }
536
537
538
539 if (_logScriptBeforeListener.isDebugEnabled()) {
540 _logScriptBeforeListener.debug(script);
541 }
542
543 if (transformerListener != null) {
544 script = transformerListener.onScript(
545 script, document, languageId, tokens);
546
547 if (_logScriptAfterListener.isDebugEnabled()) {
548 _logScriptAfterListener.debug(script);
549 }
550 }
551 }
552
553
554
555 String output = null;
556
557 if (Validator.isNull(langType)) {
558 output = LocalizationUtil.getLocalization(
559 document.asXML(), languageId);
560 }
561 else {
562 long companyId = 0;
563 long companyGroupId = 0;
564 long articleGroupId = 0;
565
566 if (tokens != null) {
567 companyId = GetterUtil.getLong(tokens.get("company_id"));
568 companyGroupId = GetterUtil.getLong(
569 tokens.get("company_group_id"));
570 articleGroupId = GetterUtil.getLong(
571 tokens.get("article_group_id"));
572 }
573
574 long scopeGroupId = 0;
575 long siteGroupId = 0;
576
577 if (themeDisplay != null) {
578 companyId = themeDisplay.getCompanyId();
579 companyGroupId = themeDisplay.getCompanyGroupId();
580 scopeGroupId = themeDisplay.getScopeGroupId();
581 siteGroupId = themeDisplay.getSiteGroupId();
582 }
583
584 String templateId = tokens.get("template_id");
585
586 templateId = getTemplateId(
587 templateId, companyId, companyGroupId, articleGroupId);
588
589 Template template = getTemplate(
590 templateId, tokens, languageId, document, script, langType);
591
592 UnsyncStringWriter unsyncStringWriter = new UnsyncStringWriter();
593
594 try {
595 if (document != null) {
596 Element rootElement = document.getRootElement();
597
598 List<TemplateNode> templateNodes = getTemplateNodes(
599 themeDisplay, rootElement);
600
601 if (templateNodes != null) {
602 for (TemplateNode templateNode : templateNodes) {
603 template.put(templateNode.getName(), templateNode);
604 }
605 }
606
607 if (portletRequestModel != null) {
608 template.put("request", portletRequestModel.toMap());
609
610 if (langType.equals(TemplateConstants.LANG_TYPE_XSL)) {
611 Document requestDocument = SAXReaderUtil.read(
612 portletRequestModel.toXML());
613
614 Element requestElement =
615 requestDocument.getRootElement();
616
617 template.put("xmlRequest", requestElement.asXML());
618 }
619 }
620 else {
621 Element requestElement = rootElement.element("request");
622
623 template.put(
624 "request", insertRequestVariables(requestElement));
625
626 if (langType.equals(TemplateConstants.LANG_TYPE_XSL)) {
627 template.put("xmlRequest", requestElement.asXML());
628 }
629 }
630 }
631
632 template.put("articleGroupId", articleGroupId);
633 template.put("company", getCompany(themeDisplay, companyId));
634 template.put("companyId", companyId);
635 template.put("device", getDevice(themeDisplay));
636
637 String templatesPath = getTemplatesPath(
638 companyId, articleGroupId);
639
640 Locale locale = LocaleUtil.fromLanguageId(languageId);
641
642 template.put("locale", locale);
643
644 template.put(
645 "permissionChecker",
646 PermissionThreadLocal.getPermissionChecker());
647 template.put(
648 "randomNamespace",
649 StringUtil.randomId() + StringPool.UNDERLINE);
650 template.put("scopeGroupId", scopeGroupId);
651 template.put("siteGroupId", siteGroupId);
652 template.put("templatesPath", templatesPath);
653 template.put("viewMode", viewMode);
654
655
656
657 template.put("groupId", articleGroupId);
658 template.put("journalTemplatesPath", templatesPath);
659
660 mergeTemplate(template, unsyncStringWriter, propagateException);
661 }
662 catch (Exception e) {
663 if (e instanceof DocumentException) {
664 throw new TransformException(
665 "Unable to read XML document", e);
666 }
667 else if (e instanceof IOException) {
668 throw new TransformException("Error reading template", e);
669 }
670 else if (e instanceof TransformException) {
671 throw (TransformException)e;
672 }
673 else {
674 throw new TransformException("Unhandled exception", e);
675 }
676 }
677
678 output = unsyncStringWriter.toString();
679 }
680
681
682
683 for (TransformerListener transformerListener : _transformerListeners) {
684
685
686
687 if (_logOutputBeforeListener.isDebugEnabled()) {
688 _logOutputBeforeListener.debug(output);
689 }
690
691 output = transformerListener.onOutput(output, languageId, tokens);
692
693 if (_logOutputAfterListener.isDebugEnabled()) {
694 _logOutputAfterListener.debug(output);
695 }
696 }
697
698 if (_logTransfromAfter.isDebugEnabled()) {
699 _logTransfromAfter.debug(output);
700 }
701
702 return output;
703 }
704
705 private static final Log _log = LogFactoryUtil.getLog(Transformer.class);
706
707 private static final Log _logOutputAfterListener = LogFactoryUtil.getLog(
708 Transformer.class.getName() + ".OutputAfterListener");
709 private static final Log _logOutputBeforeListener = LogFactoryUtil.getLog(
710 Transformer.class.getName() + ".OutputBeforeListener");
711 private static final Log _logScriptAfterListener = LogFactoryUtil.getLog(
712 Transformer.class.getName() + ".ScriptAfterListener");
713 private static final Log _logScriptBeforeListener = LogFactoryUtil.getLog(
714 Transformer.class.getName() + ".ScriptBeforeListener");
715 private static final Log _logTokens = LogFactoryUtil.getLog(
716 Transformer.class.getName() + ".Tokens");
717 private static final Log _logTransformBefore = LogFactoryUtil.getLog(
718 Transformer.class.getName() + ".TransformBefore");
719 private static final Log _logTransfromAfter = LogFactoryUtil.getLog(
720 Transformer.class.getName() + ".TransformAfter");
721 private static final Log _logXmlAfterListener = LogFactoryUtil.getLog(
722 Transformer.class.getName() + ".XmlAfterListener");
723 private static final Log _logXmlBeforeListener = LogFactoryUtil.getLog(
724 Transformer.class.getName() + ".XmlBeforeListener");
725
726 private final Map<String, String> _errorTemplateIds =
727 new HashMap<String, String>();
728 private final boolean _restricted;
729 private final Set<TransformerListener> _transformerListeners =
730 new HashSet<TransformerListener>();
731
732 }