[ https://issues.apache.org/jira/browse/WICKET-6823?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=17187604#comment-17187604 ]
Martin Tzvetanov Grigorov commented on WICKET-6823: --------------------------------------------------- The discussion whether to change the order of the execution of the behaviors' afterRender() should be moved now to dev@. IMO it is too risky and we should leave it for Wicket 10 to experiment more with it. > Two instances of AbstractTransformerBehavior on the same component results in > incomplete output. > ------------------------------------------------------------------------------------------------ > > Key: WICKET-6823 > URL: https://issues.apache.org/jira/browse/WICKET-6823 > Project: Wicket > Issue Type: Bug > Components: wicket-core > Affects Versions: 8.9.0 > Reporter: Thorsten Schöning > Assignee: Sven Meier > Priority: Major > Attachments: multiple_abstract_transformer_behavior.zip > > > I'm using Wicket as a renderer for HTML-reports WITHOUT browser, web server > or requests, only by using ComponentRenderer. There are two implementations > of AbstractTransformerBehavior to update "colspan" attributes of table cells > and IDs of arbitrary HTML nodes. Both are used on the same component: > {noformat} > resultsCont.add(new DvResultsCont.ColSpanUpdater()); > resultsCont.add(new MkIdReplacer > ( > "th", "id", "td", "headers", > String.format("%d.%s", itemIdx, kindOfDetail) > )); > {noformat} > When only ONE of both behaviours is used, the page renders successfully and > it doesn't make any difference which one is used. If both of those are used > OTOH, the page seems to be rendered at all as well, but some rendered content > is simply missing in the overall output in the end. My component > "resultsCont" renders to a table, so the last markup I have is the following: > {noformat} > <table class="detailsMeters ui-expandable ui-expandable-collapsed missing"> > [...] > </table> > {noformat} > In theory, after that table there should be additional content like foots, > closing elements for HTML itself etc. So the current rendering is invalid. > It's important to note, though, that I don't get any exception, the output > simply seems to not contain all data. When enabling DEBUG logging during > rendering, the logs make pretty much clear that Wicket really tries to > continue rendering, but the output is simply missing. > As no exceptions are thrown and output seems to simply be ignored at some > point, I have the feeling the problem is in handling the response objects in > "AbstractTransformerBehavior". All of those assigned transformers to some > component are called before actually rendering anything and change the > response. "Component.java" contains the following code: > {noformat} > /** > * {@link Behavior#beforeRender(Component)} Notify all behaviors that are > assigned to this > * component that the component is about to be rendered. > */ > private void notifyBehaviorsComponentBeforeRender() > { > for (Behavior behavior : getBehaviors()) > { > if (isBehaviorAccepted(behavior)) > { > behavior.beforeRender(this); > } > } > } > {noformat} > Each call to "beforeRender" changes the response and all those changes are > done one after another. This means that the current request to render two > will be that one of the LAST applied transformer only. > {noformat} > @Override > public void beforeRender(Component component) > { > super.beforeRender(component); > final RequestCycle requestCycle = RequestCycle.get(); > // Temporarily replace the web response with a String response > originalResponse = requestCycle.getResponse(); > WebResponse origResponse = (WebResponse)((originalResponse instanceof > WebResponse) > ? originalResponse : null); > BufferedWebResponse tempResponse = newResponse(origResponse); > // temporarily set StringResponse to collect the transformed output > requestCycle.setResponse(tempResponse); > } > {noformat} > Only after all those changes to the current request, content is rendered and > transformed, using the current request AND changing it back to what each > individual transformer believes to be the original request. > {noformat} > @Override > public void afterRender(final Component component) > { > final RequestCycle requestCycle = RequestCycle.get(); > try > { > BufferedWebResponse tempResponse = > (BufferedWebResponse)requestCycle.getResponse(); > if (component instanceof Page && originalResponse instanceof > WebResponse) > { > tempResponse.writeMetaData((WebResponse) > originalResponse); > } > // Transform the data > CharSequence output = transform(component, > tempResponse.getText()); > originalResponse.write(output); > } > catch (Exception ex) > { > throw new WicketRuntimeException("Error while transforming the > output of component: " + > component, ex); > } > finally > { > // Restore the original response object > requestCycle.setResponse(originalResponse); > } > } > {noformat} > Because all transformers are executed in order at this stage, the FIRST > executed transformer works on the content of the request of the LAST one > which put requests into place. After applying its own transformation, it puts > its own original request in place and the next transformer works on that and > puts its own request into place etc. > So the problem seems to be that AFTER the first transformer executed > "afterReder", all subsequent ones are rendering into temporary responses of > former transformers and those results are never written to the original > response. It can't be, because only the first transformer has access to that > response at all, but is unaware of the results of later transformers. > So it needs to be decided if multiple transformers should be supported at all > and if so, how to do it best with proper chaining of results. In my opinion > it should be supported, as I have a valid use case and I couldn't find any > docs that multiple of those transformers don't work. It simply seems the > current implementation is too limited. -- This message was sent by Atlassian Jira (v8.3.4#803005)