Last modified by Thomas Mortagne on 2023/08/14 11:01



We have various macros which would need to cache intermediary result (script macros) or event the full result (code macro, message macros, etc.) of execution somewhere and while each macro could have its own caching system, dealing with invalidation can be tricky.

So one possibility to make all that a lot simpler would be to add a new step between the parsing and the execution of a XDOM. After you parse the source into a XDOM, you would go through a new API similar to transformations but dedicated to only do transformations which don't depend on the context so that you can cache the result of this "compilation" and reuse it every time you need to execute a XDOM. By doing that we delegate the cache storage and invalidation to a higher level which currently already does it for the parsed XDOM (the XWikiDocument stored in the document cache, the XDOM cached in the various wiki components like wiki macros, panels, ui extensions, generic wiki components, etc.).

How should a compiled XDOM looks like ?

It should stay as close as possible to the source XDOM to make easier to reuse existing tools (like the rendering transformation API). What should cover well the need is to simply add a new generic "Object data" field to the MacroBlock (or even any Block ?).

How to compile a XDOM ?

The simplest would be to reproduce the Transformation system but with Compiler components. There would mostly work the same way (you can configure several compilers, have priority, there would be a MacroCompiler, etc.) with one main difference: no context.

So how exactly does a Macro component can compile ?

A new Object compile(P parameters, String content, MacroCompilerContext context) (MacroCompilerContext would only contain stable contextual information like the current Block and the XDOM but maybe it's not even needed) would be added to org.xwiki.rendering.macro.Macro. The macro would preprocess everything it can preprocess without relying on variable contextual information and return a custom Object. The MacroCompiler would then inject this compiled data to the MacroBlock.

When the Macro#execute is called the macro can reach the pre compiled data using MacroBlock#getData() or do things from scratch if no data exists in the XDOM (not compiled XDOM).

Compiled data type

While the idea is to let each macro store any kind of compiled data (there is a huge difference between what the code macro and the velocity macro produce as compiled data and nothing in common) it's still nice to standardize which type of data a macro should produce in some common use cases:

  • a macro which content is just standard wiki content: the macro should compile it into a WikiContent which expose a getBlocks(). The reason to not return directly List<Blocks> is that the macro might also want to compile more things which it's putting around that content. Having this standard WikiContent can be very interesting for code which navigate a XDOM to find some elements like links (for example to find back links), if it's executed on a compiled XDOM it can very easily find a lot more elements which used to be blackboxed as String content of MacroBlock



Get Connected