Re: [FreeMarker-user] Better handling of template exceptions in web applications.
Generates text that depends on changing data (like dynamic HTML).
Brought to you by:
revusky
From: Daniel D. <dd...@fr...> - 2011-08-07 07:54:31
|
Sunday, August 7, 2011, 7:34:00 AM, Geoff Shuetrim wrote: > On 4 August 2011 20:02, Daniel Dekany <dd...@fr...> wrote: > Thursday, August 4, 2011, 2:56:04 AM, Geoff Shuetrim wrote: > >>> The suggestion to just set the buffer size to something big is a >>> lot simpler than trying to change the actual writer being used by >>> the response. I will try it out and see if the performance impact >>> of always using a large buffer is manageable. >> >> Assuming the implementators of the Servlet API wasn't lame, why would >> any other solution be more efficient? You have to buffer the output >> somewhere if you don't send it immediately. > > Only because, for the majority of pages, the huge buffer is not > necessary and so always allocating it is wasteful. I have been > using a buffering writer that is like String writer except that it > uses a different system for dynamically increasing buffer size. > Then you have small buffers being used for smaller pages and > infrequent buffer size increases for the large pages. What is > optimal should, in the end, depend on the distribution of web page sizes in the web application. I assume you are using a linked-list of fix sized arrays (let's call them chunks) for buffering, so there's no array re-allocation ever. The first chunk can be small and the later ones can be bigger. Then I don't think anyone would need a different buffer setup for each page. A further trick is that you can store the data in the buffer already encoded with the charset, which in Java means half the size usually. Anyway, the question is if Tomcat/Jetty does this or not... Maybe they didn't care and just use StringWriter (which is plain horrible in theory, as it keeps reallocating a single char[], even that synchronized as it uses the now deprecated StringBuffer). But maybe it doesn't mater in practice anyway... maybe in setups where such overhead could matter you don't use Tomcat/Jetty anyway. >>> One last warning to anyone else looking to use this approach when >>> they are also using Stripes layout tags: the template process method >>> is called every time a template is used by the layout system. That >>> means that if the template processing exception is thrown by one of >>> the content components used by a layout and not by the layout >>> itself, then any attempt to redirect the response in the >>> ServletExceptionHandler seems to be ignored. What I have found to >>> work is to send appropriate HTML content to the response writer when >>> the exception is encountered and then that content is included in >>> the layout instead of the content that would have been generated by >>> the template that triggered the exception. It is not ideal but I >>> cannot figure any way to get back to the original response and to redirect it. >> >> That's not good. Is it only so with FreeMarker? If Template.process >> fails, the exception should propagate up to the layout causing that to >> fail too... I guess... > > I think it would happen for JSP pages also. I was catching the > ServletException as soon as it was detected in the > Servlet.doGet/doPost methods and then dealing with it immediately by > attempting to perform the redirect to the error page. That was > failing. Now I am letting the exception propagate up as you describe > but even so, that is not sufficient. I also need to be: > > 1. Using the one buffering writer for all Template.process() calls, throughout the recursion. > 2. Only sending the content written to that buffer to the response > writer once I am sure that no ServletExceptions were raised through > the recursion process. That is being managed in the postTemplateProcess method. > 3. Keeping track of where I am at in the recursive set of > Template.process() calls, the writer being used for buffering the > results of template processing, and any ServletExceptions produced, > as attributes of the request. It works now but is a fair bit more complex than I had anticipated. Then I guess you are using the Servlet RequestDispatcher mechanism to invoke each "components" of the page. That's not necessary with FM of course, unless you must use it with a JSP Model-2 pattern to work together with some legacy framework (which is what FreemarkerServlet is for). > Regards > > Geoff S > > [snip] -- Best regards, Daniel Dekany |