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