This is an automated email from the ASF dual-hosted git repository.
mridulpathak pushed a commit to branch trunk
in repository https://gitbox.apache.org/repos/asf/ofbiz-framework.git
The following commit(s) were added to refs/heads/trunk by this push:
new c0513fb2f8 Improved: FtlWriter calls every macro through one constant
template (OFBIZ-13675)
c0513fb2f8 is described below
commit c0513fb2f8bf5f627bb438607f525e32f1553fbc
Author: Mridul Pathak <[email protected]>
AuthorDate: Wed Oct 14 00:10:16 2026 +0530
Improved: FtlWriter calls every macro through one constant template
(OFBIZ-13675)
FtlWriter built the call to a macro as text,
<@name?with_args($args$name)/>, and compiled a new template for every call, so
the compiled text still depended on the macro name. It now sets the macro name
and the parameters as variables of the environment and includes a single
constant template that calls the macro held by that variable, only if the
variable is a macro. The template is compiled once and shared, and the new
processMacroCall method is the entry point for the macro calls o [...]
---
.../ofbiz/widget/renderer/macro/FtlWriter.java | 73 +++++++++++++++++-----
1 file changed, 58 insertions(+), 15 deletions(-)
diff --git
a/framework/widget/src/main/java/org/apache/ofbiz/widget/renderer/macro/FtlWriter.java
b/framework/widget/src/main/java/org/apache/ofbiz/widget/renderer/macro/FtlWriter.java
index 08545c275f..f06fe78742 100644
---
a/framework/widget/src/main/java/org/apache/ofbiz/widget/renderer/macro/FtlWriter.java
+++
b/framework/widget/src/main/java/org/apache/ofbiz/widget/renderer/macro/FtlWriter.java
@@ -47,6 +47,19 @@ import java.util.WeakHashMap;
public final class FtlWriter {
private static final String MODULE = FtlWriter.class.getName();
+ private static final String MACRO_NAME_VARIABLE = "$macro$";
+ private static final String MACRO_ARGS_VARIABLE = "$args$";
+
+ /**
+ * The only template text that is compiled to call a macro. The name of
the macro and its arguments are not part of
+ * the text: they are set as variables of the environment, so they are
data and are never parsed as template code.
+ * The macro is only called if the variable named by the macro name holds
a macro.
+ */
+ private static final String MACRO_CALL_TEMPLATE =
+ "<#if !(.vars[" + MACRO_NAME_VARIABLE + "]!false)?is_directive>"
+ + "<#stop \"Not a macro: \" + " + MACRO_NAME_VARIABLE + "></#if>"
+ + "<@.vars[" + MACRO_NAME_VARIABLE + "]?with_args(" +
MACRO_ARGS_VARIABLE + ") />";
+
private final DefaultObjectWrapper defaultObjectWrapper = new
DefaultObjectWrapperBuilder(FreeMarkerWorker.VERSION).build();
private final WeakHashMap<Appendable, Environment> environments = new
WeakHashMap<>();
private final Template macroLibrary;
@@ -77,9 +90,7 @@ public final class FtlWriter {
public void processFtlString(Appendable writer, Locale locale, String
ftlString) {
try {
final Environment environment = getEnvironment(writer, locale);
- environment.setVariable("visualTheme",
FreeMarkerWorker.autoWrap(visualTheme, environment));
- environment.setVariable("modelTheme",
- FreeMarkerWorker.autoWrap(visualTheme.getModelTheme(),
environment));
+ setThemeVariables(environment);
Reader templateReader = new StringReader(ftlString);
Template template = new Template(UUID.randomUUID().toString(),
templateReader,
FreeMarkerWorker.getDefaultOfbizConfig());
@@ -90,6 +101,33 @@ public final class FtlWriter {
}
}
+ /**
+ * Call a macro of the macro library and write the result to the
Appendable. The name of the macro and the
+ * parameters are passed to FreeMarker as data, never as template text.
+ *
+ * @param writer The Appendable to write the result of the macro to.
+ * @param locale The locale to render with, or null for the default
locale.
+ * @param macroName The name of the macro to call.
+ * @param parameters The parameters of the macro, by name.
+ */
+ public void processMacroCall(final Appendable writer, final Locale locale,
final String macroName,
+ final Map<String, Object> parameters) {
+ try {
+ final Environment environment = getEnvironment(writer, locale);
+ setThemeVariables(environment);
+ environment.setVariable(MACRO_NAME_VARIABLE,
defaultObjectWrapper.wrap(macroName));
+ environment.setVariable(MACRO_ARGS_VARIABLE,
defaultObjectWrapper.wrap(parameters));
+ environment.include(MacroCallTemplateHolder.TEMPLATE);
+ } catch (TemplateException | IOException e) {
+ Debug.logError(e, "Error rendering ftl macro: " + macroName,
MODULE);
+ }
+ }
+
+ private void setThemeVariables(final Environment environment) throws
TemplateException {
+ environment.setVariable("visualTheme",
FreeMarkerWorker.autoWrap(visualTheme, environment));
+ environment.setVariable("modelTheme",
FreeMarkerWorker.autoWrap(visualTheme.getModelTheme(), environment));
+ }
+
private Environment getEnvironment(Appendable writer, Locale locale)
throws TemplateException, IOException {
Environment environment = environments.get(writer);
if (environment == null) {
@@ -105,6 +143,22 @@ public final class FtlWriter {
return environment;
}
+ /**
+ * Holds the macro call template, which is compiled once, on first use,
and shared by all the instances.
+ */
+ private static final class MacroCallTemplateHolder {
+ private static final Template TEMPLATE = compile();
+
+ private static Template compile() {
+ try {
+ return new Template("ftlWriterMacroCall", new
StringReader(MACRO_CALL_TEMPLATE),
+ FreeMarkerWorker.getDefaultOfbizConfig());
+ } catch (IOException e) {
+ throw new IllegalStateException("Cannot compile the macro call
template", e);
+ }
+ }
+ }
+
/**
* Visitor for RenderableFtl objects that will process the contents of the
objects as FTL templates and write the
* results to the configured Appendable.
@@ -123,18 +177,7 @@ public final class FtlWriter {
@Override
public void visit(RenderableFtlMacroCall renderableFtlMacroCall,
Locale locale) {
- final String name = renderableFtlMacroCall.getName();
-
- try {
- final Environment environment = getEnvironment(writer, locale);
-
- environment.setVariable("$args$" + name,
-
defaultObjectWrapper.wrap(renderableFtlMacroCall.getParameters()));
-
- processFtlString(writer, locale,
String.format("<@%s?with_args($args$%s)/>", name, name));
- } catch (TemplateException | IOException e) {
- Debug.logError(e, "Error rendering ftl macro: " + name,
MODULE);
- }
+ processMacroCall(writer, locale, renderableFtlMacroCall.getName(),
renderableFtlMacroCall.getParameters());
}
@Override