Adding the methods in the plugin interface sounds the right thing to do.
It's indeed also needed by the FileUploadPlugin since using endRendering
was cleaning up to quickly.
Ludovic
Sergiu Dumitriu wrote:
Hi devs,
There's a blocker issue preventing the finalization of the
SkinExtensions implementation
(
http://dev.xwiki.org/xwiki/bin/view/Design/SkinExtensions). To explain
a bit what the problem is:
- skin extensions are javascript or css pseudo-files, which are included
("linked to") in generated XHTML pages
- a skin extension is "requested" by some code using, for example,
$xwiki.jsx.use("XWiki.RightsManagement"); while generating the content,
the jsx plugin builds a list of used extensions
- after the whole page is parsed, the generated content must also
include the links to the needed extensions
The problem is that these links must be placed in the head part of the
HTML, which is generated before the body, where the extensions are
actually pulled in. This means that sometime after the parsing is done,
and before sending the response to the client, some code must insert
those links in the response. My dilemma was where...
One solution was to use the new notification mechanism to send some
parsing events that would allow listeners to change the content when the
parsing was done. Vincent opposed, so I dropped the idea.
Another solution would have been to write a Filter that would intercept
the response and insert the links, but the problem is that the filter is
isolated, without access to the context, the xwiki object, or the
jsx/ssx plugins. The component manager _could_ be a solution, but for
the moment it still needs the context, which is not available.
Another solution is to just modify Utils.parseTemplate, but this is not
elegant. It is more like a patchy workaround that would increase the
messiness of the code even more, so I'm against it.
Another solution could have been the existing plugin.endRendering, but
it is called many times during a request, and only when rendering with
Radeox, not when parsing, so it would not be called for the whole
template (so the html header would be left out).
The best solution I could come so far is to add two methods to the
PluginInterface, beginParsing and endParsing, called before and after
parsing the resulting template. This is generic enough, as it can be
used by other plugins, there's no code targeting exactly the jsx and ssx
plugins, it is extensible enough to allow other type of extensions to be
added (link extensions?), and except the StrutsActions which cannot be
added dynamically (at least not yet) it allows the SkinExtensions
implementation to be completely pluggable.
So, beginParsing will be called in com.xpn.xwiki.web.Utils.parseTemplate
before parsing the template that generates the response, and it allows
plugins to initialize some per-request variables. endParsing will be
called in the same method, right after generating the response, and will
allow plugins to change the resulting response or cleanup resources. The
signature of these methods would be:
public void beginParsing(XWikiContext context)
public String endParsing(String content, XWikiContext context)
endParsing could also be used by the FileUploadPlugin to cleanup the
resources (see
http://fisheye2.cenqua.com/browse/xwiki/xwiki-platform/core/trunk/xwiki-cor…
).
Now, the thing that I don't like is that this changes a public
interface, used by many plugins. It is good that most plugins extend
DefaultPlugin, as there is only one place where these methods must be
implemented, so the impact on existing plugins should be minimal. I also
don't like that the plugin interface contains so many methods, but that
is an acknowledged problem and it will be solved when everything would
be a component. Until then, these two methods seem to me like they
should already be there, given the other rendering-related methods.
Any other (better) solutions I didn't see? Objections to this change?
Thanks,