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