PageRenderTime 4857ms CodeModel.GetById 32ms RepoModel.GetById 2ms app.codeStats 0ms

/src/main/java/org/rythmengine/template/TemplateBase.java

http://github.com/greenlaw110/Rythm
Java | 1962 lines | 1318 code | 198 blank | 446 comment | 300 complexity | 76fc96e7b2407e4e5b8e42e051fbebcc MD5 | raw file

Large files files are truncated, but you can click here to view the full file

  1. /*
  2. * Copyright (C) 2013-2016 The Rythm Engine project
  3. * for LICENSE and other details see:
  4. * https://github.com/rythmengine/rythmengine
  5. */
  6. package org.rythmengine.template;
  7. /*-
  8. * #%L
  9. * Rythm Template Engine
  10. * %%
  11. * Copyright (C) 2017 - 2021 OSGL (Open Source General Library)
  12. * %%
  13. * Licensed under the Apache License, Version 2.0 (the "License");
  14. * you may not use this file except in compliance with the License.
  15. * You may obtain a copy of the License at
  16. *
  17. * http://www.apache.org/licenses/LICENSE-2.0
  18. *
  19. * Unless required by applicable law or agreed to in writing, software
  20. * distributed under the License is distributed on an "AS IS" BASIS,
  21. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  22. * See the License for the specific language governing permissions and
  23. * limitations under the License.
  24. * #L%
  25. */
  26. import com.alibaba.fastjson.JSON;
  27. import com.alibaba.fastjson.JSONArray;
  28. import org.rythmengine.Rythm;
  29. import org.rythmengine.RythmEngine;
  30. import org.rythmengine.Sandbox;
  31. import org.rythmengine.conf.RythmConfiguration;
  32. import org.rythmengine.exception.FastRuntimeException;
  33. import org.rythmengine.exception.RythmException;
  34. import org.rythmengine.extension.ICodeType;
  35. import org.rythmengine.extension.II18nMessageResolver;
  36. import org.rythmengine.internal.IEvent;
  37. import org.rythmengine.internal.RythmEvents;
  38. import org.rythmengine.internal.TemplateBuilder;
  39. import org.rythmengine.internal.compiler.ClassReloadException;
  40. import org.rythmengine.internal.compiler.TemplateClass;
  41. import org.rythmengine.logger.ILogger;
  42. import org.rythmengine.logger.Logger;
  43. import org.rythmengine.utils.*;
  44. import java.io.*;
  45. import java.lang.reflect.Array;
  46. import java.lang.reflect.Modifier;
  47. import java.util.*;
  48. import java.util.concurrent.ConcurrentHashMap;
  49. import java.util.concurrent.ConcurrentLinkedDeque;
  50. /**
  51. * The base class of template implementation. It provides a set of
  52. * protected methods which is handy to use in template authoring
  53. */
  54. public abstract class TemplateBase extends TemplateBuilder implements ITemplate {
  55. /**
  56. * The logger
  57. */
  58. protected static final ILogger __logger = Logger.get(TemplateBase.class);
  59. /**
  60. * The rythm engine that run this template
  61. */
  62. protected transient RythmEngine __engine = null;
  63. /**
  64. * The template class
  65. */
  66. private transient TemplateClass __templateClass = null;
  67. /**
  68. * Set template class and template code type to this template instance
  69. * <p/>
  70. * <p>Not to be called in user application or template</p>
  71. *
  72. * @param templateClass
  73. */
  74. public void __setTemplateClass(TemplateClass templateClass) {
  75. this.__templateClass = templateClass;
  76. }
  77. public void __prepareRender(ICodeType type, Locale locale, RythmEngine engine) {
  78. TemplateClass tc = __templateClass;
  79. __ctx.init(this, type, locale, tc, engine);
  80. Class<? extends TemplateBase> c = getClass();
  81. Class<?> pc = c.getSuperclass();
  82. if (TemplateBase.class.isAssignableFrom(pc) && !Modifier.isAbstract(pc.getModifiers())) {
  83. try {
  84. TemplateClass ptc = engine.classes().getByClassName(pc.getName());
  85. if (null != ptc) {
  86. __parent = (TemplateBase) ptc.asTemplate(engine);
  87. } else {
  88. throw new RuntimeException("Cannot find template class for parent class: " + pc);
  89. }
  90. //__parent.__setTemplateClass(__engine().classes.getByClassName(pc.getName()));
  91. } catch (Exception e) {
  92. throw new RuntimeException(e);
  93. }
  94. }
  95. if (null != __parent) {
  96. __parent.__ctx.init(__parent, type, locale, tc, engine);
  97. }
  98. }
  99. /**
  100. * Return {@link org.rythmengine.utils.S#INSTANCE String helper instance}. Could be used in
  101. * template authoring. For example:
  102. * <p/>
  103. * <pre><code>
  104. * {@literal @}if (s().empty(userRight)){
  105. * {@literal @}return
  106. * }
  107. * </code></pre>
  108. */
  109. protected S s() {
  110. return S.INSTANCE;
  111. }
  112. private Writer w;
  113. private OutputStream os;
  114. @Override
  115. public ITemplate __setWriter(Writer writer) {
  116. if (null == writer) throw new NullPointerException();
  117. if (null != os) throw new IllegalStateException("Cannot set writer to template when outputstream is presented");
  118. if (null != this.w)
  119. throw new IllegalStateException("Cannot set writer to template when an writer is presented");
  120. this.w = writer;
  121. return this;
  122. }
  123. @Override
  124. public ITemplate __setOutputStream(OutputStream os) {
  125. if (null == os) throw new NullPointerException();
  126. if (null != w) throw new IllegalStateException("Cannot set output stream to template when writer is presented");
  127. if (null != this.os)
  128. throw new IllegalStateException("Cannot set output stream to template when an outputstream is presented");
  129. this.os = os;
  130. return this;
  131. }
  132. /**
  133. * Stores render args of this template. The generated template source code
  134. * will also declare render args as separate protected field while keeping
  135. * a copy inside this Map data structure
  136. */
  137. protected Map<String, Object> __renderArgs = new ConcurrentHashMap<String, Object>();
  138. /**
  139. * Return the {@link RythmEngine engine} running this template
  140. *
  141. * @return the engine running the template
  142. */
  143. public RythmEngine __engine() {
  144. return null == __engine ? Rythm.engine() : __engine;
  145. }
  146. /**
  147. * Used for Java extension/transformer
  148. *
  149. * @return the template
  150. */
  151. protected ITemplate __template() {
  152. return this;
  153. }
  154. /**
  155. * Invoke a tag. Usually should not used directly in user template
  156. *
  157. * @param line
  158. * @param name
  159. */
  160. protected void __invokeTag(int line, String name) {
  161. __engine.invokeTemplate(line, name, this, null, null, null);
  162. }
  163. /**
  164. * Invoke a tag. Usually should not used directly in user template
  165. *
  166. * @param line
  167. * @param name
  168. * @param ignoreNonExistsTag
  169. */
  170. protected void __invokeTag(int line, String name, boolean ignoreNonExistsTag) {
  171. __engine.invokeTemplate(line, name, this, null, null, null, ignoreNonExistsTag);
  172. }
  173. /**
  174. * Invoke a tag. Usually should not used directly in user template
  175. *
  176. * @param line
  177. * @param name
  178. * @param params
  179. */
  180. protected void __invokeTag(int line, String name, ITag.__ParameterList params) {
  181. __engine.invokeTemplate(line, name, this, params, null, null);
  182. }
  183. /**
  184. * Invoke a tag. Usually should not used directly in user template
  185. *
  186. * @param line
  187. * @param name
  188. * @param params
  189. * @param ignoreNonExistsTag
  190. */
  191. protected void __invokeTag(int line, String name, ITag.__ParameterList params, boolean ignoreNonExistsTag) {
  192. __engine.invokeTemplate(line, name, this, params, null, null, ignoreNonExistsTag);
  193. }
  194. /**
  195. * Invoke a tag. Usually should not used directly in user template
  196. *
  197. * @param line
  198. * @param name
  199. * @param params
  200. * @param body
  201. */
  202. protected void __invokeTag(int line, String name, ITag.__ParameterList params, ITag.__Body body) {
  203. __engine.invokeTemplate(line, name, this, params, body, null);
  204. }
  205. /**
  206. * Invoke a tag. Usually should not used directly in user template
  207. *
  208. * @param line
  209. * @param name
  210. * @param params
  211. * @param body
  212. * @param ignoreNoExistsTag
  213. */
  214. protected void __invokeTag(int line, String name, ITag.__ParameterList params, ITag.__Body body, boolean ignoreNoExistsTag) {
  215. __engine.invokeTemplate(line, name, this, params, body, null, ignoreNoExistsTag);
  216. }
  217. /**
  218. * Invoke a tag. Usually should not used directly in user template
  219. *
  220. * @param line
  221. * @param name
  222. * @param params
  223. * @param body
  224. * @param context
  225. */
  226. protected void __invokeTag(int line, String name, ITag.__ParameterList params, ITag.__Body body, ITag.__Body context) {
  227. __engine.invokeTemplate(line, name, this, params, body, context);
  228. }
  229. /**
  230. * Invoke a tag. Usually should not used directly in user template
  231. *
  232. * @param line
  233. * @param name
  234. * @param params
  235. * @param body
  236. * @param context
  237. * @param ignoreNonExistsTag
  238. */
  239. protected void __invokeTag(int line, String name, ITag.__ParameterList params, ITag.__Body body, ITag.__Body context, boolean ignoreNonExistsTag) {
  240. __engine.invokeTemplate(line, name, this, params, body, context, ignoreNonExistsTag);
  241. }
  242. /* to be used by dynamic generated sub classes */
  243. private String layoutContent = "";
  244. // store the current template section content
  245. private Map<String, String> layoutSections = new ConcurrentHashMap<String, String>();
  246. // store the parent default section content
  247. private Map<String, String> layoutSections0 = new ConcurrentHashMap<String, String>();
  248. private Map<String, Object> renderProperties = new ConcurrentHashMap<String, Object>();
  249. /**
  250. * The parent template (layout template)
  251. */
  252. protected TemplateBase __parent = null;
  253. /**
  254. * Construct a template instance
  255. */
  256. public TemplateBase() {
  257. super();
  258. }
  259. /**
  260. * Render another template from this template. Could be used in template authoring.
  261. * For example:
  262. * <p/>
  263. * <pre><code>
  264. * {@literal @}args String customTemplate, Map<String, Object> customParams
  265. * {@literal @}{ Object renderResult = render(customTemplate, customParams);
  266. * }
  267. * <p class="customer_content">@renderResult</p>
  268. * </code></pre>
  269. *
  270. * @param template
  271. * @param args
  272. * @return render result
  273. */
  274. protected RawData __render(String template, Object... args) {
  275. if (null == template) return new RawData("");
  276. return S.raw(__engine.sandbox().render(template, args));
  277. }
  278. /**
  279. * Render another template from within this template. Using the renderArgs
  280. * of this template.
  281. *
  282. * @param template
  283. * @return render result as {@link org.rythmengine.utils.RawData}
  284. * @see #__render(String, Object...)
  285. */
  286. protected RawData __render(String template) {
  287. if (null == template) return new RawData("");
  288. return S.raw(__engine.sandbox().render(template, __renderArgs));
  289. }
  290. /**
  291. * Set layout content. Should not be used in user application or template
  292. *
  293. * @param body
  294. */
  295. protected final void __setLayoutContent(String body) {
  296. layoutContent = body;
  297. }
  298. /**
  299. * Add layout section. Should not be used in user application or template
  300. *
  301. * @param name
  302. * @param section
  303. */
  304. private void __addLayoutSection(String name, String section, boolean def) {
  305. Map<String, String> m = def ? layoutSections0 : layoutSections;
  306. if (m.containsKey(name)) return;
  307. m.put(name, section);
  308. }
  309. private StringBuilder tmpOut = null;
  310. private String section = null;
  311. private TextBuilder tmpCaller = null;
  312. /**
  313. * Start a layout section. Not to be used in user application or template
  314. *
  315. * @param name
  316. */
  317. protected void __startSection(String name) {
  318. if (null == name) throw new NullPointerException("section name cannot be null");
  319. if (null != tmpOut) throw new IllegalStateException("section cannot be nested");
  320. tmpCaller = __caller;
  321. __caller = null;
  322. tmpOut = __buffer;
  323. __buffer = new StringBuilder();
  324. section = name;
  325. }
  326. /**
  327. * End a layout section. Not to be used in user application or template
  328. */
  329. protected void __endSection() {
  330. __endSection(false);
  331. }
  332. /**
  333. * End a layout section with a boolean flag mark if it is a default content or not.
  334. * Not to be used in user application or template
  335. *
  336. * @param def
  337. */
  338. protected void __endSection(boolean def) {
  339. if (null == tmpOut && null == tmpCaller) throw new IllegalStateException("section has not been started");
  340. __addLayoutSection(section, __buffer.toString(), def);
  341. __buffer = tmpOut;
  342. __caller = tmpCaller;
  343. tmpOut = null;
  344. tmpCaller = null;
  345. }
  346. /**
  347. * Print a layout section by name. Not to be used in user application or template
  348. *
  349. * @param name
  350. */
  351. protected void __pLayoutSection(String name) {
  352. String s = layoutSections.get(name);
  353. if (null == s) s = layoutSections0.get(name);
  354. else {
  355. String s0 = layoutSections0.get(name);
  356. if (s0 == null) s0 = "";
  357. s = s.replace("\u0000\u0000inherited\u0000\u0000", s0);
  358. }
  359. p(s);
  360. }
  361. /**
  362. * Print default section content inside child template
  363. * section content.
  364. *
  365. * @param name
  366. */
  367. protected void __pLayoutSectionInherited(String name) {
  368. p("\u0000\u0000inherited\u0000\u0000");
  369. }
  370. /**
  371. * Get a section content as {@link org.rythmengine.utils.RawData} by name. Not to be used in user application or template
  372. *
  373. * @param name
  374. * @return section data by name
  375. */
  376. protected RawData __getSection(String name) {
  377. return S.raw(layoutSections.get(name));
  378. }
  379. /**
  380. * Get layout content as {@link org.rythmengine.utils.RawData}. Not to be used in user application or template
  381. *
  382. * @return layout content
  383. */
  384. protected RawData __getSection() {
  385. return S.raw(S.isEmpty(layoutContent) ? layoutSections.get("__CONTENT__") : layoutContent);
  386. }
  387. /**
  388. * Print the layout content. Not to be used in user application or template
  389. */
  390. protected void __pLayoutContent() {
  391. p(__getSection());
  392. }
  393. private void addAllLayoutSections(Map<String, String> sections) {
  394. if (null != sections) layoutSections.putAll(sections);
  395. }
  396. private void addAllRenderProperties(Map<String, Object> properties) {
  397. if (null != properties) renderProperties.putAll(properties);
  398. }
  399. /**
  400. * Not to be used in user application or template
  401. *
  402. * @return a <code>TemplateBase</code>
  403. */
  404. protected TemplateBase __internalClone() {
  405. try {
  406. return (TemplateBase) super.clone();
  407. } catch (CloneNotSupportedException e) {
  408. throw new RuntimeException();
  409. }
  410. }
  411. /**
  412. * Not to be used in user application or template
  413. *
  414. * @param engine the rythm engine
  415. * @param caller the caller template
  416. * @return cloned template
  417. */
  418. @Override
  419. public ITemplate __cloneMe(RythmEngine engine, ITemplate caller) {
  420. if (null == engine) throw new NullPointerException();
  421. TemplateBase tmpl = __internalClone();
  422. if (tmpl.__parent != null) {
  423. tmpl.__parent = (TemplateBase) tmpl.__parent.__cloneMe(engine, caller);
  424. }
  425. tmpl.__engine = engine;
  426. //tmpl.__templateClass = __templateClass;
  427. tmpl.__ctx = new __Context();
  428. //if (null != buffer) tmpl.__buffer = buffer;
  429. if (null != __buffer) tmpl.__buffer = new StringBuilder();
  430. tmpl.__renderArgs = new ConcurrentHashMap<String, Object>(__renderArgs.size());
  431. //tmpl.layoutContent = "";
  432. tmpl.layoutSections = new ConcurrentHashMap<String, String>();
  433. tmpl.layoutSections0 = new ConcurrentHashMap<String, String>();
  434. tmpl.renderProperties = new ConcurrentHashMap<String, Object>();
  435. //tmpl.section = null;
  436. //tmpl.tmpCaller = null;
  437. //tmpl.tmpOut = null;
  438. //tmpl.__logTime = __logTime;
  439. //tmpl.w = null;
  440. //tmpl.os = null;
  441. if (null != caller) {
  442. tmpl.__caller = (TextBuilder) caller;
  443. Map<String, Object> callerRenderArgs = new HashMap<String, Object>(((TemplateBase) caller).__renderArgs);
  444. Map<String, Class> types = tmpl.__renderArgTypeMap();
  445. for (Map.Entry<String, Object> entry : callerRenderArgs.entrySet()) {
  446. if (tmpl.__renderArgs.containsKey(entry.getKey())) continue;
  447. Object o = entry.getValue();
  448. if (null == o || __isDefVal(o)) continue;
  449. Class<?> c = types.get(entry.getKey());
  450. if (null == c || c.isAssignableFrom(o.getClass())) {
  451. tmpl.__setRenderArg(entry.getKey(), o);
  452. }
  453. }
  454. }
  455. tmpl.__setUserContext(engine.renderSettings.userContext());
  456. return tmpl;
  457. }
  458. /**
  459. * Not to be used in user application or template
  460. */
  461. protected void __internalInit() {
  462. __loadExtendingArgs();
  463. __init();
  464. }
  465. /**
  466. * the implementation of this method is to be generated by {@link org.rythmengine.internal.CodeBuilder}.
  467. * Not to be used in user application or template
  468. */
  469. protected void __setup() {
  470. }
  471. /**
  472. * the implementation of this method is to be generated by {@link org.rythmengine.internal.CodeBuilder}.
  473. * Not to be used in user application or template
  474. */
  475. protected void __loadExtendingArgs() {
  476. }
  477. /**
  478. * the implementation of this method is to be generated by {@link org.rythmengine.internal.CodeBuilder}.
  479. * Not to be used in user application or template
  480. */
  481. @Override
  482. public void __init() {
  483. }
  484. private boolean __logTime() {
  485. return false;
  486. }
  487. /**
  488. * Get the template class of this template. Not to be used in user application or template
  489. *
  490. * @param useCaller
  491. * @return a <code>TemplateClass</code>
  492. */
  493. public TemplateClass __getTemplateClass(boolean useCaller) {
  494. TemplateClass tc = __templateClass;
  495. if (useCaller && null == tc) {
  496. TemplateBase caller = __caller();
  497. if (null != caller) return caller.__getTemplateClass(true);
  498. }
  499. return tc;
  500. }
  501. /**
  502. * Render to binary output stream. This method is usually called from API defined in
  503. * {@link RythmEngine}
  504. *
  505. * @param os
  506. */
  507. @Override
  508. public final void render(OutputStream os) {
  509. __setOutputStream(os);
  510. render();
  511. }
  512. /**
  513. * Render to character based writer. This method is usually called from API defined in
  514. * {@link RythmEngine}
  515. *
  516. * @param w
  517. */
  518. @Override
  519. public final void render(Writer w) {
  520. __setWriter(w);
  521. render();
  522. }
  523. /**
  524. * Trigger render events.
  525. * <p>Not an API for user application</p>
  526. *
  527. * @param event
  528. * @param engine
  529. */
  530. protected void __triggerRenderEvent(IEvent<Void, ITemplate> event, RythmEngine engine) {
  531. event.trigger(engine, this);
  532. }
  533. /**
  534. * Render and return result in String. This method is usually called from API defined in
  535. * {@link RythmEngine}
  536. */
  537. @Override
  538. public final String render() {
  539. RythmEngine engine = __engine();
  540. boolean engineSet = RythmEngine.set(engine);
  541. try {
  542. long l = 0l;
  543. boolean logTime = __logTime();
  544. if (logTime) {
  545. l = System.currentTimeMillis();
  546. }
  547. __triggerRenderEvent(RythmEvents.ON_RENDER, engine);
  548. __setup();
  549. if (logTime) {
  550. __logger.debug("< preprocess [%s]: %sms", getClass().getName(), System.currentTimeMillis() - l);
  551. l = System.currentTimeMillis();
  552. }
  553. try {
  554. String s = __internalRender();
  555. return s;
  556. } finally {
  557. __triggerRenderEvent(RythmEvents.RENDERED, engine);
  558. if (logTime) {
  559. __logger.debug("<<<<<<<<<<<< [%s] total render: %sms", getClass().getName(), System.currentTimeMillis() - l);
  560. }
  561. }
  562. } catch (ClassReloadException e) {
  563. engine.restart(e);
  564. return render();
  565. } finally {
  566. if (engineSet) {
  567. RythmEngine.clear();
  568. }
  569. }
  570. }
  571. private String secureCode = null;
  572. @Override
  573. public ITemplate __setSecureCode(String secureCode) {
  574. if (null == secureCode) return this;
  575. this.secureCode = secureCode;
  576. if (null != __parent) {
  577. __parent.__setSecureCode(secureCode);
  578. }
  579. return this;
  580. }
  581. private Writer w_ = null;
  582. /**
  583. * Set output file path
  584. *
  585. * @param path
  586. */
  587. protected void __setOutput(String path) {
  588. try {
  589. w_ = new BufferedWriter(new FileWriter(path));
  590. } catch (Exception e) {
  591. throw new FastRuntimeException(e.getMessage());
  592. }
  593. }
  594. /**
  595. * Set output file
  596. *
  597. * @param file
  598. */
  599. protected void __setOutput(File file) {
  600. try {
  601. w_ = new BufferedWriter(new FileWriter(file));
  602. } catch (Exception e) {
  603. throw new FastRuntimeException(e.getMessage());
  604. }
  605. }
  606. /**
  607. * Set output stream
  608. *
  609. * @param os
  610. */
  611. protected void __setOutput(OutputStream os) {
  612. w_ = new OutputStreamWriter(os);
  613. }
  614. /**
  615. * Set output writer
  616. *
  617. * @param w
  618. */
  619. protected void __setOutput(Writer w) {
  620. w_ = w;
  621. }
  622. private static final ThreadLocal<Boolean> cce_ = new ThreadLocal<Boolean>() {
  623. @Override
  624. protected Boolean initialValue() {
  625. return false;
  626. }
  627. };
  628. private void handleThrowable(Throwable e) {
  629. StackTraceElement[] stackTrace = e.getStackTrace();
  630. String msg = null;
  631. for (StackTraceElement se : stackTrace) {
  632. String cName = se.getClassName();
  633. if (cName.contains(TemplateClass.CN_SUFFIX)) {
  634. // is it the embedded class?
  635. if (cName.indexOf("$") != -1) {
  636. cName = cName.substring(0, cName.lastIndexOf("$"));
  637. }
  638. TemplateClass tc = __engine.classes().getByClassName(cName);
  639. if (null == tc) {
  640. continue;
  641. }
  642. if (null == msg) {
  643. msg = e.getMessage();
  644. if (S.isEmpty(msg)) {
  645. msg = "Rythm runtime exception caused by " + e.getClass().getName();
  646. }
  647. }
  648. RythmException re = new RythmException(__engine, e, tc, se.getLineNumber(), -1, msg);
  649. int lineNo = re.templateLineNumber;
  650. String key = tc.getKey().toString();
  651. int i = key.indexOf('\n');
  652. if (i == -1) i = key.indexOf('\r');
  653. if (i > 0) {
  654. key = key.substring(0, i - 1) + "...";
  655. }
  656. if (key.length() > 80) key = key.substring(0, 80) + "...";
  657. if (lineNo != -1) {
  658. StackTraceElement[] newStack = new StackTraceElement[stackTrace.length + 1];
  659. newStack[0] = new StackTraceElement(tc.name(), "", key, lineNo);
  660. System.arraycopy(stackTrace, 0, newStack, 1, stackTrace.length);
  661. re.setStackTrace(newStack);
  662. } else {
  663. Throwable t = e.getCause();
  664. while (null != t) {
  665. stackTrace = t.getStackTrace();
  666. for (StackTraceElement se0 : stackTrace) {
  667. RythmException re0 = new RythmException(__engine, t, tc, se0.getLineNumber(), -1, msg);
  668. if (re0.templateLineNumber > -1) {
  669. re.templateLineNumber = re0.templateLineNumber;
  670. break;
  671. } else {
  672. if (t!=null)
  673. t = t.getCause();
  674. }
  675. }
  676. }
  677. }
  678. throw re;
  679. }
  680. }
  681. throw (e instanceof RuntimeException ? (RuntimeException) e : new RuntimeException(e));
  682. }
  683. /**
  684. * Not to be used in user application or template
  685. */
  686. protected void __internalBuild() {
  687. w_ = null; // reset output destination
  688. try {
  689. long l = 0l;
  690. if (__logTime()) {
  691. l = System.currentTimeMillis();
  692. }
  693. final String code = secureCode;
  694. Sandbox.enterRestrictedZone(code);
  695. try {
  696. __internalInit();
  697. build();
  698. } finally {
  699. __finally();
  700. Sandbox.leaveCurZone(code);
  701. }
  702. if (__logTime()) {
  703. __logger.debug("<<<<<<<<<<<< [%s] build: %sms", getClass().getName(), System.currentTimeMillis() - l);
  704. }
  705. } catch (RythmException e) {
  706. throw e;
  707. } catch (Throwable e) {
  708. handleThrowable(e);
  709. }
  710. if (null != w_) {
  711. try {
  712. IO.writeContent(toString(), w_);
  713. w_ = null;
  714. } catch (Exception e) {
  715. Logger.error(e, "failed to write template content to output destination");
  716. }
  717. }
  718. }
  719. protected boolean __hasParent() {
  720. return null != __parent && __parent != this;
  721. }
  722. /**
  723. * Not to be used in user application or template
  724. */
  725. protected String __internalRender() {
  726. __internalBuild();
  727. if (__hasParent()) {
  728. __parent.__setLayoutContent(toString());
  729. __parent.addAllLayoutSections(layoutSections);
  730. __parent.addAllRenderProperties(renderProperties);
  731. __parent.__setRenderArgs(__renderArgs);
  732. //__parent.__renderArgs.putAll(__renderArgs);
  733. return __parent.render();
  734. } else {
  735. return toString();
  736. }
  737. }
  738. /**
  739. * The {@link org.rythmengine.internal.CodeBuilder} will generate the
  740. * implementation of this method usually
  741. *
  742. * @return this template as a {@link org.rythmengine.utils.TextBuilder}
  743. */
  744. @Override
  745. public TextBuilder build() {
  746. return this;
  747. }
  748. /**
  749. * Template could rewrite this method to make sure operation get called after template
  750. * rendered even in the case there are exception thrown out
  751. */
  752. protected void __finally() {}
  753. private Map<String, Object> userCtx;
  754. @Override
  755. public Map<String, Object> __getUserContext() {
  756. return null == userCtx ? Collections.EMPTY_MAP : userCtx;
  757. }
  758. @Override
  759. public ITemplate __setUserContext(Map<String, Object> context) {
  760. this.userCtx = context;
  761. return this;
  762. }
  763. /**
  764. * Return render arg type in array. Not to be used in user application or template
  765. */
  766. protected Class[] __renderArgTypeArray() {
  767. return null;
  768. }
  769. /**
  770. * Return render arg name by position
  771. *
  772. * @param i
  773. * @return render argument name by position
  774. */
  775. protected String __renderArgName(int i) {
  776. return null;
  777. }
  778. /**
  779. * Return render arg type in Map. Not to be used in user application or template
  780. *
  781. * @return render args types mapped by name
  782. */
  783. protected Map<String, Class> __renderArgTypeMap() {
  784. return Collections.emptyMap();
  785. }
  786. @Override
  787. public ITemplate __setRenderArgs(Map<String, Object> args) {
  788. __renderArgs = args;
  789. return this;
  790. }
  791. @Override
  792. public ITemplate __setRenderArg(JSONWrapper jsonData) {
  793. if (jsonData.isArray()) {
  794. setJSONArray(jsonData.getArray());
  795. } else {
  796. setJSONObject(jsonData.getObject());
  797. }
  798. return this;
  799. }
  800. private void setJSONArray(List<Object> jsonArray) {
  801. Class[] types = __renderArgTypeArray();
  802. int paraNo = jsonArray.size();
  803. if (types.length == 1 && types[0].equals(List.class)) {
  804. Map<String, Class> typeMap = __renderArgTypeMap();
  805. String vn = __renderArgName(0);
  806. Class c = typeMap.get(vn + "__0");
  807. if (null == c) {
  808. // an array type
  809. c = typeMap.get(vn);
  810. }
  811. Object p = JSON.parseArray(jsonArray.toString(), c);
  812. __setRenderArg(vn, p);
  813. } else {
  814. for (int i = 0; i < types.length; ++i) {
  815. if (i >= paraNo) break;
  816. Object o = jsonArray.get(i);
  817. Class c = types[i];
  818. Object p;
  819. if (o instanceof List) {
  820. p = JSON.parseArray(o.toString(), c);
  821. } else {
  822. p = JSON.parseObject(o.toString(), c);
  823. }
  824. __setRenderArg(i, p);
  825. }
  826. }
  827. }
  828. private void setJSONObject(Map<String, Object> jsonObject) {
  829. Map<String, Class> types = __renderArgTypeMap();
  830. for (Map.Entry<String, Object> entry : jsonObject.entrySet()) {
  831. if (types.containsKey(entry.getKey())) {
  832. Class c = types.get(entry.getKey());
  833. Object o = entry.getValue();
  834. Object p;
  835. if (o instanceof List) {
  836. Map<String, Class> typeMap = __renderArgTypeMap();
  837. //String vn = nm;
  838. Class c0 = typeMap.get(entry.getKey() + "__0");
  839. boolean isArray = false;
  840. if (null == c0) {
  841. // an array type
  842. isArray = true;
  843. c0 = typeMap.get(entry.getKey());
  844. }
  845. if (isArray) {
  846. JSONArray l = (JSONArray) o;
  847. //try {
  848. Class c1 = c0.getComponentType();
  849. int size = l.size();
  850. Object a = Array.newInstance(c1, size);
  851. for (int i = 0; i < size; ++i) {
  852. Object el = l.get(i);
  853. el = JSON.parseObject(el.toString(), c1);
  854. Array.set(a, i, el);
  855. }
  856. //}
  857. p = a;
  858. } else {
  859. p = JSON.parseArray(o.toString(), c0);
  860. }
  861. } else {
  862. String s = o.toString();
  863. if (String.class.equals(c)) {
  864. p = s;
  865. } else {
  866. p = JSON.parseObject(s, c);
  867. }
  868. }
  869. __setRenderArg(entry.getKey(), p);
  870. }
  871. }
  872. }
  873. /**
  874. * Set render arg from {@link org.rythmengine.template.ITag.__ParameterList tag params}
  875. * Not to be used in user application or template
  876. *
  877. * @param params
  878. * @return this template instance
  879. */
  880. protected TemplateBase __setRenderArgs0(ITag.__ParameterList params) {
  881. for (int i = 0; i < params.size(); ++i) {
  882. ITag.__Parameter param = params.get(i);
  883. if (null != param.name) __setRenderArg(param.name, param.value);
  884. else __setRenderArg(i, param.value);
  885. }
  886. return this;
  887. }
  888. @Override
  889. public ITemplate __setRenderArgs(Object... args) {
  890. return this;
  891. }
  892. @Override
  893. public ITemplate __setRenderArg(String name, Object arg) {
  894. __renderArgs.put(name, arg);
  895. return this;
  896. }
  897. /**
  898. * alias of {@link #__setRenderArg(String, Object)}
  899. *
  900. * @param name
  901. * @param arg
  902. * @return this template instance
  903. */
  904. protected final TemplateBase __set(String name, Object arg) {
  905. __setRenderArg(name, arg);
  906. return this;
  907. }
  908. /**
  909. * Return caller of the template when this template is
  910. * invoked as a {@link ITag tag}
  911. *
  912. * @return caller template
  913. */
  914. protected final TemplateBase __caller() {
  915. return null == __caller ? null : (TemplateBase) __caller;
  916. }
  917. @Override
  918. public <T> T __getRenderArg(String name) {
  919. Object val = __renderArgs.get(name);
  920. //if (null == val) return null;
  921. if (null != __caller) {
  922. if (!__isDefVal(val)) return (T) val;
  923. else return caller().__getRenderArg(name);
  924. } else {
  925. return (T) val;
  926. }
  927. }
  928. protected final static <T> T __get(Map<String, Object> map, String name, Class<T> cls) {
  929. Object o = map.get(name);
  930. return (null != o) ? (T) o : __transNull(cls);
  931. }
  932. protected final <T> T __get(String name, Class<T> cls) {
  933. Object o = __get(name);
  934. return (null != o) ? (T) o : __transNull(cls);
  935. }
  936. protected final static <T> T __safeCast(Object o, Class<T> cls) {
  937. return (null != o) ? (T) o : __transNull(cls);
  938. }
  939. protected final static <T> T __transNull(Class<T> cls) {
  940. if (null == cls) return null;
  941. if (cls.equals(String.class)) {
  942. return (T) "";
  943. }
  944. if (cls.equals(Integer.class)) {
  945. return (T) Integer.valueOf(0);
  946. } else if (cls.equals(Boolean.class)) {
  947. return (T) Boolean.valueOf(false);
  948. } else if (cls.equals(Double.class)) {
  949. return (T) Double.valueOf(0);
  950. } else if (cls.equals(Float.class)) {
  951. return (T) Float.valueOf(0);
  952. } else if (cls.equals(Long.class)) {
  953. return (T) Long.valueOf(0);
  954. } else if (cls.equals(Short.class)) {
  955. return (T) Short.valueOf((short) 0);
  956. } else if (cls.equals(Byte.class)) {
  957. return (T) Byte.valueOf((byte) 0);
  958. } else if (cls.equals(Character.class)) {
  959. return (T) Character.valueOf((char) 0);
  960. }
  961. return null;
  962. }
  963. protected final static boolean __isDefVal(Object o) {
  964. if (null == o) return true;
  965. if (o instanceof String) return ("".equals(o));
  966. if (o instanceof Boolean) return (Boolean.valueOf(false).equals(o));
  967. if (o instanceof Integer) return (Integer.valueOf(0).equals(o));
  968. if (o instanceof Double) return (Double.valueOf(0).equals(o));
  969. if (o instanceof Float) return (Float.valueOf(0).equals(o));
  970. if (o instanceof Long) return (Long.valueOf(0).equals(o));
  971. if (o instanceof Short) return (Short.valueOf((short) 0).equals(o));
  972. if (o instanceof Byte) return (Byte.valueOf((byte) 0).equals(o));
  973. if (o instanceof Character) return (Character.valueOf((char) 0).equals(o));
  974. return false;
  975. }
  976. /**
  977. * Alias of {@link #__getRenderArg(String)}
  978. *
  979. * @param name
  980. * @param <T>
  981. * @return a render argument
  982. */
  983. protected final <T> T __get(String name) {
  984. return __getRenderArg(name);
  985. }
  986. /**
  987. * Get render arg and do type cast to the class specified
  988. *
  989. * @param name
  990. * @param c
  991. * @param <T>
  992. * @return a render argument
  993. */
  994. protected final <T> T __getAs(String name, Class<T> c) {
  995. Object o = __getRenderArg(name);
  996. if (null == o) return null;
  997. return (T) o;
  998. }
  999. /**
  1000. * Get render property by name. And do type case by the left value of the expression.
  1001. * <p/>
  1002. * <p>If no property found by name then return the default value specified</p>
  1003. *
  1004. * @param name
  1005. * @param def
  1006. * @param <T>
  1007. * @return a render property
  1008. */
  1009. protected final <T> T __getRenderProperty(String name, T def) {
  1010. Object o = __renderArgs.get(name);
  1011. return (T) (__isDefVal(o) ? def : o);
  1012. }
  1013. /**
  1014. * Get render property by name. This is usually called by <code>@get()</code> directive in teh layout template.
  1015. *
  1016. * @param name
  1017. * @param <T>
  1018. * @return a render property
  1019. * @see #__setRenderProperty(String, Object)
  1020. */
  1021. protected final <T> T __getRenderProperty(String name) {
  1022. return (T) __getRenderProperty(name, null);
  1023. }
  1024. /**
  1025. * Get render property by name and do type cast to the specified default value.
  1026. * If the render property cannot be found by name, then return the default value
  1027. *
  1028. * @param name
  1029. * @param def
  1030. * @param <T>
  1031. * @return a render property
  1032. * @see #__getRenderProperty(String)
  1033. */
  1034. protected final <T> T __getRenderPropertyAs(String name, T def) {
  1035. Object o = __getRenderProperty(name, def);
  1036. return null == o ? def : (T) o;
  1037. }
  1038. /**
  1039. * Set render property by name. This is pass value from sub (content) template
  1040. * to parent (layout) template Usually this is invoked by <code>@set()</code>
  1041. * directive in the sub template
  1042. *
  1043. * @param name
  1044. * @param val
  1045. * @see #__getRenderProperty(String)
  1046. * @see #__getRenderProperty(String, Object)
  1047. */
  1048. protected final void __setRenderProperty(String name, Object val) {
  1049. //__renderArgs.put(name, val);
  1050. __setRenderArg(name, val);
  1051. }
  1052. /**
  1053. * Handle template execution exception. Not to be called in user application or template
  1054. *
  1055. * @param e
  1056. */
  1057. protected final void __handleTemplateExecutionException(Exception e) {
  1058. try {
  1059. if (!RythmEvents.ON_RENDER_EXCEPTION.trigger(__engine(), F.T2(this, e))) {
  1060. throw e;
  1061. }
  1062. } catch (RuntimeException e0) {
  1063. throw e0;
  1064. } catch (Exception e1) {
  1065. throw new RuntimeException(e1);
  1066. }
  1067. }
  1068. @Override
  1069. public ITemplate __setRenderArg(int position, Object arg) {
  1070. return this;
  1071. }
  1072. /**
  1073. * The render context
  1074. */
  1075. protected __Context __ctx = null;//new __Context();
  1076. public ICodeType __curCodeType() {
  1077. return __ctx.currentCodeType();
  1078. }
  1079. public Locale __curLocale() {
  1080. return __ctx.currentLocale();
  1081. }
  1082. public Escape __curEscape() {
  1083. return __ctx.currentEscape();
  1084. }
  1085. private boolean appendToBuffer() {
  1086. return null != __parent || (null == w && null == os);
  1087. }
  1088. private boolean appendToWriter() {
  1089. return (null == __parent && null != w);
  1090. }
  1091. private boolean appendToOutputStream() {
  1092. return (null == __parent && null != os);
  1093. }
  1094. @Override
  1095. protected void __append(StrBuf wrapper) {
  1096. if (appendToBuffer()) {
  1097. super.__append(wrapper);
  1098. }
  1099. if (null == os && null == w) return;
  1100. if (appendToOutputStream()) {
  1101. try {
  1102. os.write(wrapper.toBinary());
  1103. } catch (IOException e) {
  1104. throw new RuntimeException(e);
  1105. }
  1106. } else if (appendToWriter()) {
  1107. try {
  1108. w.write(wrapper.toString());
  1109. } catch (IOException e) {
  1110. throw new RuntimeException(e);
  1111. }
  1112. }
  1113. }
  1114. @Override
  1115. protected void __append(Object o) {
  1116. String oStr = o.toString();
  1117. if (appendToBuffer()) super.__append(oStr);
  1118. if (null == os && null == w) return;
  1119. StrBuf wrapper = new StrBuf(oStr);
  1120. if (appendToOutputStream()) {
  1121. try {
  1122. os.write(wrapper.toBinary());
  1123. } catch (IOException e) {
  1124. throw new RuntimeException(e);
  1125. }
  1126. } else if (appendToWriter()) {
  1127. try {
  1128. w.write(wrapper.toString());
  1129. } catch (IOException e) {
  1130. throw new RuntimeException(e);
  1131. }
  1132. }
  1133. }
  1134. @Override
  1135. protected void __append(char c) {
  1136. if (appendToBuffer()) super.__append(c);
  1137. if (null == os && null == w) return;
  1138. if (appendToOutputStream()) {
  1139. try {
  1140. os.write(c);
  1141. } catch (IOException e) {
  1142. throw new RuntimeException(e);
  1143. }
  1144. } else if (appendToWriter()) {
  1145. try {
  1146. w.write(c);
  1147. } catch (IOException e) {
  1148. throw new RuntimeException(e);
  1149. }
  1150. }
  1151. }
  1152. @Override
  1153. protected void __append(int i) {
  1154. if (appendToBuffer()) super.__append(i);
  1155. if (null == os && null == w) return;
  1156. if (appendToOutputStream()) {
  1157. StrBuf wrapper = new StrBuf(String.valueOf(i));
  1158. try {
  1159. os.write(wrapper.toBinary());
  1160. } catch (IOException e) {
  1161. throw new RuntimeException(e);
  1162. }
  1163. } else if (appendToWriter()) {
  1164. try {
  1165. w.write(String.valueOf(i));
  1166. } catch (IOException e) {
  1167. throw new RuntimeException(e);
  1168. }
  1169. }
  1170. }
  1171. @Override
  1172. protected void __append(long l) {
  1173. if (appendToBuffer()) super.__append(l);
  1174. if (null == os && null == w) return;
  1175. if (appendToOutputStream()) {
  1176. StrBuf wrapper = new StrBuf(String.valueOf(l));
  1177. try {
  1178. os.write(wrapper.toBinary());
  1179. } catch (IOException e) {
  1180. throw new RuntimeException(e);
  1181. }
  1182. } else if (appendToWriter()) {
  1183. try {
  1184. w.write(String.valueOf(l));
  1185. } catch (IOException e) {
  1186. throw new RuntimeException(e);
  1187. }
  1188. }
  1189. }
  1190. @Override
  1191. protected void __append(float f) {
  1192. if (appendToBuffer()) super.__append(f);
  1193. if (null == os && null == w) return;
  1194. if (appendToOutputStream()) {
  1195. StrBuf wrapper = new StrBuf(String.valueOf(f));
  1196. try {
  1197. os.write(wrapper.toBinary());
  1198. } catch (IOException e) {
  1199. throw new RuntimeException(e);
  1200. }
  1201. } else if (appendToWriter()) {
  1202. try {
  1203. w.write(String.valueOf(f));
  1204. } catch (IOException e) {
  1205. throw new RuntimeException(e);
  1206. }
  1207. }
  1208. }
  1209. @Override
  1210. protected void __append(double d) {
  1211. if (appendToBuffer()) super.__append(d);
  1212. if (null == os && null == w) return;
  1213. if (appendToOutputStream()) {
  1214. StrBuf wrapper = new StrBuf(String.valueOf(d));
  1215. try {
  1216. os.write(wrapper.toBinary());
  1217. } catch (IOException e) {
  1218. throw new RuntimeException(e);
  1219. }
  1220. } else if (appendToWriter()) {
  1221. try {
  1222. w.write(String.valueOf(d));
  1223. } catch (IOException e) {
  1224. throw new RuntimeException(e);
  1225. }
  1226. }
  1227. }
  1228. @Override
  1229. protected void __append(boolean b) {
  1230. if (appendToBuffer()) super.__append(b);
  1231. if (null == os && null == w) return;
  1232. if (appendToOutputStream()) {
  1233. StrBuf wrapper = new StrBuf(String.valueOf(b));
  1234. try {
  1235. os.write(wrapper.toBinary());
  1236. } catch (IOException e) {
  1237. throw new RuntimeException(e);
  1238. }
  1239. } else if (appendToWriter()) {
  1240. try {
  1241. w.write(String.valueOf(b));
  1242. } catch (IOException e) {
  1243. throw new RuntimeException(e);
  1244. }
  1245. }
  1246. }
  1247. // ---- overwrite TemplateBuilder methods
  1248. /*
  1249. * make it public because ITag.Body will need it
  1250. */
  1251. @Override
  1252. public Escape __defaultEscape() {
  1253. return __ctx.currentEscape();
  1254. }
  1255. @Override
  1256. public final TemplateBase pe(Object o) {
  1257. return (TemplateBase) super.pe(o);
  1258. }
  1259. @Override
  1260. public final TemplateBase pe(Object o, Escape escape) {
  1261. return (TemplateBase) super.pe(o, escape);
  1262. }
  1263. protected final Class __getClass(int o) {
  1264. return int.class;
  1265. }
  1266. protected final Class __getClass(boolean o) {
  1267. return boolean.class;
  1268. }
  1269. protected final Class __getClass(char o) {
  1270. return char.class;
  1271. }
  1272. protected final Class __getClass(long o) {
  1273. return long.class;
  1274. }
  1275. protected final Class __getClass(float o) {
  1276. return float.class;
  1277. }
  1278. protected final Class __getClass(double o) {
  1279. return double.class;
  1280. }
  1281. protected final Class __getClass(byte o) {
  1282. return byte.class;
  1283. }
  1284. protected final Class __getClass(Object o) {
  1285. if (null == o) return Void.TYPE;
  1286. return o.getClass();
  1287. }
  1288. protected final Object __eval(String expr) {
  1289. Map<String, Object> ctx = new ConcurrentHashMap<String, Object>(__renderArgs);
  1290. ctx.putAll(itrVars());
  1291. try {
  1292. Object retval = __engine().eval(expr, this, ctx);
  1293. return retval;
  1294. } catch (RuntimeException e) {
  1295. __logger.warn(e, "error evaluate expression: %s", expr);
  1296. return null;
  1297. }
  1298. }
  1299. // --- debugging interface
  1300. protected static void __log(String msg, Object... args) {
  1301. __logger.info(msg, args);
  1302. }
  1303. protected static void __debug(String msg, Object... args) {
  1304. __logger.debug(msg, args);
  1305. }
  1306. protected static void __info(String msg, Object... args) {
  1307. __logger.info(msg, args);
  1308. }
  1309. protected static void __warn(String msg, Object... args) {
  1310. __logger.error(msg, args);
  1311. }
  1312. protected static void __warn(Throwable t, String msg, Object... args) {
  1313. __logger.error(t, msg, args);
  1314. }
  1315. protected static void __error(String msg, Object... args) {
  1316. __logger.error(msg, args);
  1317. }
  1318. protected static void __error(Throwable t, String msg, Object... args) {
  1319. __logger.error(t, msg, args);
  1320. }
  1321. protected boolean __logTime = false;
  1322. private II18nMessageResolver i18n = null;
  1323. protected String __i18n(String key, Object... args) {
  1324. if (i18n == null) {
  1325. i18n = __engine().conf().i18nMessageResolver();
  1326. }
  1327. return i18n.getMessage(TemplateBase.this, key, args);
  1328. }
  1329. private Deque<F.T2<String, Object>> itrVars = new ConcurrentLinkedDeque<>();
  1330. protected void __pushItrVar(String name, Object val) {
  1331. itrVars.push(F.T2(name, val));
  1332. }
  1333. protected void __popItrVar() {
  1334. itrVars.poll();
  1335. }
  1336. private Map<String, Object> itrVars() {
  1337. if (itrVars.isEmpty()) return Collections.EMPTY_MAP;
  1338. if (itrVars.size() == 1) return itrVars.peek().asMap();
  1339. Deque<F.T2<String, Object>> tmp = new ConcurrentLinkedDeque<>();
  1340. Map<String, Object> m = new ConcurrentHashMap<String, Object>();
  1341. Deque<F.T2<String, Object>> vs = itrVars;
  1342. while (!vs.isEmpty()) {
  1343. F.T2<String, Object> var = vs.pop();
  1344. tmp.push(var);
  1345. String k = var._1;
  1346. if (!m.containsKey(k)) {
  1347. m.put(k, var._2);
  1348. }
  1349. }
  1350. while (!tmp.isEmpty()) {
  1351. vs.push(tmp.pop());
  1352. }
  1353. return m;
  1354. }
  1355. /**
  1356. * The helper class to facilitate generating code for the "for" loop in
  1357. * the template source
  1358. *
  1359. * @param <T>
  1360. */
  1361. protected static class __Itr<T> implements Iterable<T> {
  1362. protected Object _o = null;
  1363. protected int _size = -1;
  1364. protected Iterator<T> iterator = null;
  1365. protected int cursor = 0;
  1366. private static final Iterator nullIterator = new Iterator() {
  1367. @Override
  1368. public boolean hasNext() {
  1369. return false;
  1370. }
  1371. @Override
  1372. public Object next() {
  1373. throw new NoSuchElementException();
  1374. }
  1375. @Override
  1376. public void remove() {
  1377. return;
  1378. }
  1379. };
  1380. private static final __Itr EMPTY_ITR = new __Itr() {
  1381. @Override
  1382. public int size() {
  1383. return 0;
  1384. }
  1385. @Override
  1386. public Iterator iterator() {
  1387. return nullIterator;
  1388. }
  1389. };
  1390. private __Itr() {
  1391. }
  1392. private __Itr(Object o) {
  1393. //this._o = o;
  1394. if (o.getClass().isArray()) {
  1395. _size = Array.getLength(o);
  1396. iterator = new Iterator<T>() {
  1397. @Override
  1398. public boolean hasNext() {
  1399. return cursor < _size;
  1400. }
  1401. @Override
  1402. public T next() {
  1403. if (!hasNext()) {
  1404. throw new NoSuchElementException();
  1405. }
  1406. return (T) Array.get(_o, cursor++);
  1407. }
  1408. @Override
  1409. public void remove() {
  1410. throw new UnsupportedOperationException();
  1411. }
  1412. };
  1413. } else {
  1414. String s = o.toString();
  1415. if (S.isEmpty(s)) {
  1416. _o = "";
  1417. _size = 0;
  1418. iterator = Collections.EMPTY_LIST.iterator();
  1419. return;
  1420. }
  1421. List<String> seps = new ArrayList<String>();
  1422. RythmEngine engine = RythmEngine.get();
  1423. RythmConfiguration conf = engine.conf();
  1424. if ("zh".equals(conf.locale().getLanguage())) {
  1425. seps.addAll(Arrays.asList("\n,、,,,;,。,:".split(",")));
  1426. } else {
  1427. seps.add("\n");
  1428. }
  1429. seps.addAll(Arrays.asList(";^,^:^_^-".split("\\^")));
  1430. for (String sep : seps) {
  1431. if (s.contains(sep)) {
  1432. List<String> ls = Arrays.asList(s.split(sep));
  1433. List<String> ls0 = new ArrayList<String>();
  1434. for (String s0 : ls) {
  1435. ls0.add(s0.trim());
  1436. }

Large files files are truncated, but you can click here to view the full file