Hello.
I understand now why a filter may be a better solution to set the
request attribute and force Tiles to use include calls. This let the
ViewPreparer available for specific Tiles needs.
I think It's likely impossible anyway in portlets, since, for what I
know, there's no standard way to get the servlet request from the
portlet requests (action, render), and attributes set on these seem to
be local and not visible from Tiles... Furthermore, as you say, this
should be done on every portlet, and thus tedious !
The last point I want to check is the way a pure servlet filter will be
activated depending on the portlet container or the application server,
and the possible interferences between distinct portlet web applications...
About Spring MVC : I'm not sure, and perhaps recent versions provide
better integration with Portlet 2.0. I've read things about new
annotations to map events, for example, to controllers, and I've had a
look to the 3.1, and nothing of that appear... I have to look at it better.
Thanks again.
Regards.
Ephemeris Lappis
Le 15/08/2012 18:53, Nicolas LE BAS a écrit :
On 12-08-14 05:35 PM, Ephemeris Lappis wrote:
Spring MVC [...]. For information, its poor support for
Portlet 2.0 makes it a limited candidate for me...
Really? According to the spring guys, it is designed specifically for
Portlet 2.0. Just out of curiosity, what makes you think it's so poor?
Not that I'm suggesting it as an alternative; Tiles with Spring MVC
Portlet will have that same bug we're discussing here anyway...
The ViewPreparer workaround seems to work, but I'm not completely
convinced that it will do it in all cases.
I don't understand what you mean about the dispatcher servlet and why I
should prefer the filter alternative. Does it work better, particularly
for portlet applications ?
Let's look at an example:
<tiles-definitions>
<definition name="def1" template="/layout1.jsp">
<put-attribute name="content" value="/content1.jsp"/>
<put-attribute name="data" value="/data1.jsp"/>
</definition>
<definition name="def2" template="/layout2.jsp">
<put-attribute name="content" value="/content2.jsp"/>
<put-attribute name="data" value="/data2.jsp"/>
</definition>
<definition name="def11" extends="def1">
<put-attribute name="content" value="/content11.jsp"/>
</definition>
</tiles-definitions>
And let's say we're calling
portletContext.getRequestDispatcher("/def11.tiles").include(request,response);
The execution flow goes as follow:
- The platform maps /def11.tiles to TilesDispatchServlet (*.tiles)
- TilesDispatcherServlet finds out the appropriate definition and
calls TilesContainer.render("def11", request, response);
- The TilesContainer sets the tiles attributes
(/content11.jsp,/data1.jsp) and forwards to the template
(/layout1.jsp). Here is the bug: we want it to include the template
instead.
- The template includes the attributes.
As a workaround in order to force Tiles into including the template,
we just have to set the appropriate attribute before the forwarding
happens:
request.setAttribute(ServletUtil.FORCE_INCLUDE_ATTRIBUTE_NAME,
Boolean.TRUE);
This can happen at 3 times that I can think of:
1. in the Portlet, before we call requestDispatcher.include, by
setting the attribute on the RenderRequest. But this has to be done in
every portlet.
2. in a ServletFilter mapped to *.tiles (same as
TilesDispatchServlet), that will be called before the execution flow
reaches TilesDispatchServlet.
3. in a ViewPreparer attached to the definition, that will be called
before the template is processed. But this has to be declared on every
root definition (def1 and def2, def11 will inherit it from def1).
Additionally, if you declare another ViewPreparer on def11 for some
reason, it will replace the inherited "force-include" ViewPreparer for
this specific definition.
Therefore 2. is the cleanest workaround IMHO. If you call Tiles only
from portlets, you want the fix to be applied once and for all,
without polluting your actual business code.
Thanks for your help and advices.
Thanks for your comments and insight!
Nick.