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