Results 1 to 3 of 3

Thread: How can I do "runtime composition" with tiles and spring mvc?

  1. #1
    Join Date
    Aug 2012
    Posts
    3

    Default How can I do "runtime composition" with tiles and spring mvc?

    Hi,

    I have a the following requirement and am trying to figure out how to make this happen in spring mvc and tiles.

    1. A user should be able to assemble a final page layout by picking or ore more page elements from a library of page element templates.
    2. A user should be able to specify the order of page elements rendered on the page.

    So, I am thinking of having various jsp pages as the page elements and a master template with a body tiles attribute which will render all the elements the user chooses to have rendered. I saw tiles has the List Attribute capability through which I would be able to populate the body attribute multiple jsps.

    http://tiles.apache.org/2.2/framewor...ttributes.html

    However, since the user has control over what goes in the page, the tiles definition happens at runtime by the user. That means I need a runtime way of expressing what jsps goes into the body tag and in what order.

    Tiles seems to have a "runtime composition" capability through the tiles container API to do the above:
    http://tiles.apache.org/2.2/framewor...d/runtime.html

    Per the examples I have tried the following in my spring mvc controller. I have also configured to use a mutable container in my TilesConfigurer.

    Code:
    @RequestMapping(method = RequestMethod.GET, value = "/")
    	public ModelAndView index(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception {
    		
    		MutableTilesContainer container = (MutableTilesContainer) ServletUtil.getCurrentContainer(request,
    				request.getSession().getServletContext());
    					
    		ListAttribute tiles = new ListAttribute();		
    		Attribute attr = new Attribute("/WEB-INF/views/element_xyz.jspx");
    		tiles.add(attr);			
    		
    		attr = new Attribute("/WEB-INF/views/element_abc.jspx");
    		tiles.add(attr);
    				
    		AttributeContext context = container.startContext(request, response);		
    		context.putAttribute("body", tiles);
    		//don't call container.render(...) since spring mvc does that for me
    		//don't call container.stopContext(...) since spring mvc does that for me
    		
    		mv.setViewName("universaltask/index");
    		mv.getModelMap().put("app_name", "My App");
    		return mv;
    	}
    The above fails with the following error or other very similar messages depending on the renderer:

    org.apache.tiles.impl.InvalidTemplateException: Cannot render a template that is not a string: [/WEB-INF/views/element_xyz.jspx]
    at org.apache.tiles.renderer.impl.TemplateAttributeRe nderer.write(TemplateAttributeRenderer.java:46)
    at org.apache.tiles.renderer.impl.AbstractBaseAttribu teRenderer.render(AbstractBaseAttributeRenderer.ja va:106)
    at org.apache.tiles.impl.BasicTilesContainer.render(B asicTilesContainer.java:670)
    at org.apache.tiles.impl.BasicTilesContainer.render(B asicTilesContainer.java:336)
    at org.apache.tiles.template.InsertAttributeModel.ren derAttribute(InsertAttributeModel.java:210)
    at org.apache.tiles.template.InsertAttributeModel.end (InsertAttributeModel.java:126)
    at org.apache.tiles.jsp.taglib.InsertAttributeTag.doT ag(InsertAttributeTag.java:311)
    at org.apache.jsp.WEB_002dINF.layouts.default_jspx._j spx_meth_tiles_insertAttribute_1(org.apache.jsp.WE B_002dINF.layouts.default_jspx:144)
    at org.apache.jsp.WEB_002dINF.layouts.default_jspx._j spService(org.apache.jsp.WEB_002dINF.layouts.defau lt_jspx:70)
    at org.apache.jasper.runtime.HttpJspBase.service(Http JspBase.java:109)
    at javax.servlet.http.HttpServlet.service(HttpServlet .java:820)
    at org.apache.jasper.servlet.JspServletWrapper.servic e(JspServletWrapper.java:389)
    at org.apache.jasper.servlet.JspServlet.serviceJspFil e(JspServlet.java:486)
    at org.apache.jasper.servlet.JspServlet.service(JspSe rvlet.java:380)
    at javax.servlet.http.HttpServlet.service(HttpServlet .java:820)
    at org.eclipse.jetty.servlet.ServletHolder.handle(Ser vletHolder.java:538)
    at org.eclipse.jetty.servlet.ServletHandler.doHandle( ServletHandler.java:478)
    at org.eclipse.jetty.server.handler.ScopedHandler.han dle(ScopedHandler.java:119)
    at org.eclipse.jetty.security.SecurityHandler.handle( SecurityHandler.java:517)
    at org.eclipse.jetty.server.session.SessionHandler.do Handle(SessionHandler.java:225)
    at org.eclipse.jetty.server.handler.ContextHandler.do Handle(ContextHandler.java:937)
    at org.eclipse.jetty.servlet.ServletHandler.doScope(S ervletHandler.java:406)
    at org.eclipse.jetty.server.session.SessionHandler.do Scope(SessionHandler.java:183)
    at org.eclipse.jetty.server.handler.ContextHandler.do Scope(ContextHandler.java:871)
    at org.eclipse.jetty.server.handler.ScopedHandler.han dle(ScopedHandler.java:117)
    at org.eclipse.jetty.server.Dispatcher.forward(Dispat cher.java:284)
    at org.eclipse.jetty.server.Dispatcher.forward(Dispat cher.java:115)
    Last edited by canterburry; Aug 22nd, 2012 at 07:36 PM.

  2. #2
    Join Date
    Aug 2012
    Posts
    3

    Default

    Ok...figured it out...here is a sample controller:

    Code:
    @RequestMapping(method = RequestMethod.GET, value = "/")
    	public ModelAndView index(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception {
    		
    		TilesContainer container = ServletUtil.getCurrentContainer(request,
    				request.getSession().getServletContext());
    		
    		AttributeContext attributeContext = container.startContext(request, response);
    		
    		ListAttribute tiles = new ListAttribute();
    		tiles.setRenderer("template");
    		tiles.add(new Attribute("/WEB-INF/views/element_xyz.jspx"));
    		tiles.add(new Attribute("/WEB-INF/views/element_abc.jspx"));		
    		attributeContext.putAttribute("items", tiles, true);
    		
    		mv.setViewName("universaltask/index");
    		mv.getModelMap().put("app_name", "My App");
    		return mv;
    	}
    Here is the template code:

    Code:
    <?xml version="1.0" encoding="UTF-8" standalone="no"?>
    <div xmlns:jsp="http://java.sun.com/JSP/Page"
    	xmlns:spring="http://www.springframework.org/tags"
    	xmlns:tiles="http://tiles.apache.org/tags-tiles"
    	xmlns:jstl="http://java.sun.com/jstl/core_rt"
    	xmlns:util="urn:jsptagdir:/WEB-INF/tags/util" version="2.0">
    	<jsp:directive.page contentType="text/html;charset=UTF-8" />
    	<jsp:output omit-xml-declaration="yes" />
    	<tiles:useAttribute id="list" name="items" classname="java.util.List" />
    	<jstl:forEach var="item" items="${list}">
    		<tiles:insertAttribute value="${item}" flush="true" />
    		<br />
    	</jstl:forEach>
    </div>

  3. #3
    Join Date
    Aug 2012
    Posts
    3

    Thumbs up Further question about your solution.

    Good job, canterburry , I referenced your codes and they worked well.

    But as a beginner of both spring and tiles for two days, I still get questions to ask.

    In my project, I have two types of Attributions to insert . I used your code which worked fine , however I would like to make these attibutions more complex, in one attibution I want to add a spring tag <from:input /> and in another one I would like to have a drop-down box. But I have no idea about how to make these two jsp files work, the moment I wrote any codes like <form:input / > or <tiles: getAsString/>, (with the tag libraries), I got syntax errors from the server.

    So, could you post any sample about how to write these jsp files which will be inserted into the template at the runtime and how to pass value(Object, Data) into/from them?

    like in your case , the files "element_xyz.jspx" and "element_abc.jspx".


    Thank you so much if you can reply me.

    Quote Originally Posted by canterburry View Post
    Ok...figured it out...here is a sample controller:

    Code:
    @RequestMapping(method = RequestMethod.GET, value = "/")
    	public ModelAndView index(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception {
    		
    		TilesContainer container = ServletUtil.getCurrentContainer(request,
    				request.getSession().getServletContext());
    		
    		AttributeContext attributeContext = container.startContext(request, response);
    		
    		ListAttribute tiles = new ListAttribute();
    		tiles.setRenderer("template");
    		tiles.add(new Attribute("/WEB-INF/views/element_xyz.jspx"));
    		tiles.add(new Attribute("/WEB-INF/views/element_abc.jspx"));		
    		attributeContext.putAttribute("items", tiles, true);
    		
    		mv.setViewName("universaltask/index");
    		mv.getModelMap().put("app_name", "My App");
    		return mv;
    	}
    Here is the template code:

    Code:
    <?xml version="1.0" encoding="UTF-8" standalone="no"?>
    <div xmlns:jsp="http://java.sun.com/JSP/Page"
    	xmlns:spring="http://www.springframework.org/tags"
    	xmlns:tiles="http://tiles.apache.org/tags-tiles"
    	xmlns:jstl="http://java.sun.com/jstl/core_rt"
    	xmlns:util="urn:jsptagdir:/WEB-INF/tags/util" version="2.0">
    	<jsp:directive.page contentType="text/html;charset=UTF-8" />
    	<jsp:output omit-xml-declaration="yes" />
    	<tiles:useAttribute id="list" name="items" classname="java.util.List" />
    	<jstl:forEach var="item" items="${list}">
    		<tiles:insertAttribute value="${item}" flush="true" />
    		<br />
    	</jstl:forEach>
    </div>

Tags for this Thread

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •