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