Page 1 of 2 12 LastLast
Results 1 to 10 of 14

Thread: Sitemesh with Velocity Decorators

  1. #1
    Join Date
    Nov 2004
    Posts
    24

    Default Sitemesh with Velocity Decorators

    Hi,

    I was using Spring + Sitemesh + Velocity, but my decoratorators were JSPs. Some months ago the Sitemesh project has released the support to Velocity decorators.
    So, I've tested the new Sitemesh Servlet in my Spring based system, but it is not working. The new Sitemesh servlet is cacthing all http requests and don't pass it to Spring Controllers...

    Does someone know how to use Spring + Sitemesh + Velocity decorators?

    Best Regards,

    Franklin Samir
    http://www.portaljava.com.br

  2. #2
    Join Date
    Aug 2004
    Location
    Denver
    Posts
    249

    Default

    It should work just fine. For an example, check out Equinox and install the "spring-velocity" option in the "extras" folder.

  3. #3
    Join Date
    Nov 2004
    Posts
    24

    Default

    Hi Matt,

    thank you, your exemple is working for me.
    My way was not workign because I wasn't using a sufix after my controlers path.
    I was using something like that:
    http://localhost:8080/sys/action/user/add

    Now I'm using:
    http://localhost:8080/sys/user/add.add

    Best regards,

    Franklin Samir

  4. #4
    Join Date
    Nov 2004
    Posts
    24

    Default

    Matt,

    I found I little problem. The includes in my decorator, are not loading my macros. The decorator.vm and the pages in $body has access to the macro.vm. But the pages inlcuded by the decorator.vm, do not.
    Algo, the included pages recognize the velocity templates. Just the macros are not beeing recognized.
    That is my velocityConfig:
    Code:
    	<bean id="velocityConfig" class="org.springframework.web.servlet.view.velocity.VelocityConfigurer">
    		<property name="resourceLoaderPath">
    			<value>/</value>
    		</property>
    		<property name="velocityProperties">
    			<props>
    				<prop key="velocimacro.library">/modules/macros.vm</prop>
    				<prop key="velocimacro.permissions.allow.inline">true</prop>
    				<prop key="velocimacro.permissions.allow.inline.to.replace.global">false</prop>
    				<prop key="velocimacro.permissions.allow.inline.local.scope">false</prop>
    				<prop key="velocimacro.context.localscope">false</prop>
    				<prop key="input.encoding">ISO-8859-1</prop>
    				<prop key="output.encoding">ISO-8859-1</prop>
    				<prop key="directive.foreach.counter.name">count</prop>
    				<prop key="directive.foreach.counter.initial.value">1</prop>
    				<prop key="velocimacro.library.autoreload">true</prop>
    			</props>
    		</property>
    	</bean>
    	<bean id="veloctyViewResolver"
    		class="org.springframework.web.servlet.view.velocity.VelocityViewResolver">
    		<property name="cache"><value>false</value></property>
    		<property name="prefix"><value></value></property>
    		<property name="suffix"><value>.htm</value></property>
    		<property name="requestContextAttribute"><value>rc</value></property>
    		<property name="exposeSpringMacroHelpers"><value>true</value></property> 
    		<property name="dateToolAttribute"><value>date</value></property>
    	</bean>
    And that's my decorator.vm:
    Code:
    <TD colspan="3">
    	#parse&#40;"/modules/Main/header.htm"&#41;
       </TD>
       </TR>
       <TR>
    	<TD width="140" valign="top">
    	 #parse&#40;"/modules/Main/menu.htm"&#41;
    	 <br>
    	</TD>
    	<TD valign="top" align="left">							
    	 $body
    	</TD>
    	<TD valign="top" align="left">
    	</TD>
       </TR>
    Do you have a suggestion to fix it?

    I think it is occuring because the included pages aren't passing by any Spring class, they are beeing loaded just by the velocity-sitemesh Servlet, and my macros are defined just in the Spring configs.

    Kind regards,
    Franklin Samir

  5. #5
    Join Date
    May 2005
    Posts
    23

    Default

    i'm having the same issue (i have a side bar that always displays some summary information about the user that is stored in the SecurityContext created by acegi on authentication) - the problem is that the context is only used to render the template specifed by the View class and then it is thrown away.

    i got around this by sub-classing the VelocityDecoratorServlet like this:

    Code:
      /**
        * @see org.apache.velocity.tools.view.servlet.VelocityViewServlet#handleRequest&#40;javax.servlet.http.HttpServletRequest,
        *      javax.servlet.http.HttpServletResponse,
        *      org.apache.velocity.context.Context&#41;
        */
       @Override public Template handleRequest&#40;HttpServletRequest request,
          HttpServletResponse response, Context context&#41; throws Exception
       &#123;
          Authentication auth = SecurityContextHolder.getContext&#40;&#41;.getAuthentication&#40;&#41;;
          
          if &#40;auth != null&#41;
          &#123;
             context.put&#40;"user", auth.getPrincipal&#40;&#41;&#41;;
          &#125;
          
          return super.handleRequest&#40;request, response, context&#41;;
       &#125;
    it works, but now i'm having the same problem w/ some of the velocity-tools (ie: NumberTool) - i don't want to have to edit this servlet every time i need to stick something extra into the context so my decorators can use it.

    i'll post back once i've looked into this further - if anyone else has dealt w/ this before, i'd like to hear your suggestions.
    -jae

  6. #6
    Join Date
    May 2005
    Posts
    23

    Default

    ok - i'm not really seeing an elegate solution around this problem. sitemesh redispatches the decorator back to the VelocityDecoratorServlet, so there isn't a simple way to carry along any context that was created inside the VelocityView class.

    it appears that the best way to handle this situation is to subclass the VelocityDecoratorServlet and populate the context w/ any values that you want available to all of your decorators.

    however, what i don't like about this is i loose the ability to leverage spring's handling of the locale when creating instances of velocity-tools, etc.

    i could go back and duplicate that code (subclassing the tools to pass in locale, etc), but that seems rather wasteful to me.

    i'm thinking that i will subclass both the VelocityViewResolver and the VelocityView so that i can expose a method off the VelocityViewResolver that will give me the same initial VelocityContext that is used inside the VelocityView class. after that, i'll look up the view resolver inside my subclassed VelocityDecoratorServlet and chain it w/ the one passed via the method input.

    does this seem like an acceptable solution? do the spring folks have another recommendation?
    -jae

  7. #7
    Join Date
    May 2005
    Posts
    23

    Default

    after spending some more time investigating this last night, i believe this is the solution we both want: http://www.jroller.com/page/timosinko/20050124

    i'm curious to see just how much of that implementation is still required in the latest version of sitemesh, and will probably look to see how difficult it would be to just add it as native functionality and submit it as a patch.

    i have a pretty good handle on what's going on (the english one the site is a bit bad), so if you have questions, feel free to ask.
    -jae

  8. #8
    Join Date
    May 2005
    Posts
    23

    Default

    it seems that the integration is proving to be more difficult then i expected - i can get everything to render, but the output from the applyDecorator method is ending up at the top of the template instead of the the place in the template where the $decorator.applyDecorator reference was found.

    there seems to be some issue w/ the requests and dispatchers that i am unable to track down and unfortunately i don't have the time to continue on trying to track it down.

    i found this in jira at opensymphony: http://jira.opensymphony.com/browse/...ator=printable

    sources are attached (although they need to be cleaned up to string the confluence specifics) that create a custom velocity directive that will provide the applyDecorator functionality.

    from the looks of it, you still have to build a velocity context that exposes data that should be available, so it seems as if my original idea will accomplish the same thing.
    -jae

  9. #9
    Join Date
    May 2005
    Posts
    23

    Default

    b/c i can't get enough of this topic, i figured out a workable solution for this...

    i created a controller in spring that duplicates all the functionality of the VelocityDecoratorServlet and i just map this pattern:

    **/*.vm

    to that controller and define a url mapping for *.vm to be handled by the DispatcherServlet.

    the only "issue" w/ the solution is that you need resolve against a known template and then override the template location to that of the decorator. the reason for this is that right now, the VelocityViewResolver throws an exception if it can't find the template, instead of returning null so the next resolver can be tried.

    the code for the controller is below, feel free to use if you'd like.

    Code:
    import com.opensymphony.module.sitemesh.Decorator;
    import com.opensymphony.module.sitemesh.Factory;
    import com.opensymphony.module.sitemesh.HTMLPage;
    import com.opensymphony.module.sitemesh.RequestConstants;
    import com.opensymphony.module.sitemesh.util.OutputConverter;
    
    import net.sf.acegisecurity.Authentication;
    import net.sf.acegisecurity.context.SecurityContextHolder;
    
    import org.springframework.mock.web.MockServletConfig;
    
    import org.springframework.web.servlet.ModelAndView;
    import org.springframework.web.servlet.View;
    import org.springframework.web.servlet.ViewResolver;
    import org.springframework.web.servlet.mvc.AbstractController;
    import org.springframework.web.servlet.view.AbstractUrlBasedView;
    
    import java.io.IOException;
    import java.io.StringWriter;
    
    import javax.servlet.ServletContext;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    
    /**
     * controller to handle processing of sitemesh decorator templates
     *
     * @version $Revision$, $Date$
     */
    public class DecoratorController extends AbstractController
    &#123;
    
       /**
        * @see org.springframework.web.servlet.mvc.AbstractController#handleRequestInternal&#40;javax.servlet.http.HttpServletRequest,
        *      javax.servlet.http.HttpServletResponse&#41;
        */
       @Override protected ModelAndView handleRequestInternal&#40;
          HttpServletRequest request, HttpServletResponse response&#41; throws Exception
       &#123;
          ModelAndView mav = new ModelAndView&#40;&#41;;
    
          addRequired&#40;request, response, mav&#41;;
    
          HTMLPage htmlPage =
             &#40;HTMLPage&#41; request.getAttribute&#40;RequestConstants.PAGE&#41;;
    
          String template = null;
    
          if &#40;htmlPage == null&#41;
          &#123;
             addNullPage&#40;mav&#41;;
             template = request.getServletPath&#40;&#41;;
          &#125;
          else
          &#123;
             addPage&#40;mav, htmlPage&#41;;
    
             Factory factory = Factory.getInstance&#40;new Config&#40;getServletContext&#40;&#41;&#41;&#41;;
             Decorator decorator =
                factory.getDecoratorMapper&#40;&#41;.getDecorator&#40;request, htmlPage&#41;;
    
             template = decorator.getPage&#40;&#41;;
          &#125;
    
          mav.setView&#40;resolveView&#40;template&#41;&#41;;
    
          return mav;
       &#125;
    
       /**
        * add "null" page attributes
        *
        * <p>these attributes are added if a &#123;@link
        * com.opensymphony.module.sitemesh.Page&#125; object was not found in the
        * request</p>
        */
       private void addNullPage&#40;ModelAndView mav&#41;
       &#123;
          mav.addObject&#40;"title", "Title?"&#41;;
          mav.addObject&#40;"body", "<p>Body?</p>"&#41;;
          mav.addObject&#40;"head", "<!-- head -->"&#41;;
       &#125;
    
       /**
        * add page attributes
        *
        * <p>these attributes are added if a &#123;@link
        * com.opensymphony.module.sitemesh.Page&#125; object was found in the request</p>
        */
       private void addPage&#40;ModelAndView mav, HTMLPage htmlPage&#41; throws IOException
       &#123;
          mav.addObject&#40;"title", OutputConverter.convert&#40;htmlPage.getTitle&#40;&#41;&#41;&#41;;
    
          &#123;
             StringWriter buffer = new StringWriter&#40;&#41;;
             htmlPage.writeBody&#40;OutputConverter.getWriter&#40;buffer&#41;&#41;;
             mav.addObject&#40;"body", buffer.toString&#40;&#41;&#41;;
          &#125;
    
          &#123;
             StringWriter buffer = new StringWriter&#40;&#41;;
             htmlPage.writeHead&#40;OutputConverter.getWriter&#40;buffer&#41;&#41;;
             mav.addObject&#40;"head", buffer.toString&#40;&#41;&#41;;
          &#125;
    
          mav.addObject&#40;"page", htmlPage&#41;;
       &#125;
    
       /**
        * add required attributes
        *
        * <p>this attributes should exist reguardless of whether or not a &#123;@link
        * com.opensymphony.module.sitemesh.Page&#125; object was found in the request</p>
        */
       private void addRequired&#40;HttpServletRequest request,
          HttpServletResponse response, ModelAndView mav&#41;
       &#123;
          // add base path, request and response
          mav.addObject&#40;"base", request.getContextPath&#40;&#41;&#41;;
          mav.addObject&#40;"req", request&#41;;
          mav.addObject&#40;"res", response&#41;;
       &#125;
    
       /**
        * resolve the view
        */
       private View resolveView&#40;String template&#41; throws Exception
       &#123;
          ViewResolver viewResolver =
             &#40;ViewResolver&#41; getApplicationContext&#40;&#41;.getBean&#40;"viewResolver"&#41;;
    
          /*
           * XXX&#58; if the view resolver can't find the template, it throws an
           * exception, so we lookup a dummy template that we know exists, and then
           * override the url w/ that of the decorator's location.
           */
          View view = viewResolver.resolveViewName&#40;"dummy", null&#41;;
          &#40;&#40;AbstractUrlBasedView&#41; view&#41;.setUrl&#40;template&#41;;
    
          return view;
       &#125;
    
       /**
        * allows direct use of the &#123;@link javax.servlet.ServletContext&#125; when looking
        * up a &#123;@link com.opensymphony.module.sitemesh.Factory&#125; instance
        *
        * @version $Revision$, $Date$
        */
       static private class Config extends com.opensymphony.module.sitemesh.Config
       &#123;
    
          /** servlet context */
          private ServletContext ctx;
    
          /**
           * create a new Config object.
           *
           * @param ctx ServletContext object
           */
          public Config&#40;ServletContext ctx&#41;
          &#123;
             super&#40;new MockServletConfig&#40;ctx&#41;&#41;;
             this.ctx = ctx;
          &#125;
    
          /**
           * @see com.opensymphony.module.sitemesh.Config#getServletContext&#40;&#41;
           */
          @Override public ServletContext getServletContext&#40;&#41;
          &#123;
             return this.ctx;
          &#125;
       &#125;
    &#125;
    -jae

  10. #10
    Join Date
    May 2005
    Location
    California, US
    Posts
    735

    Default

    Someone just posted this on the mailing list; not sure if there's anything there useful for you: http://wiki.apache.org/jakarta-veloc...yAndSpringTips

Similar Threads

  1. Replies: 3
    Last Post: Jan 12th, 2011, 03:24 AM
  2. FreeMarker vs Velocity
    By Martin Kersten in forum Architecture
    Replies: 8
    Last Post: May 30th, 2005, 09:21 AM
  3. Velocity OutOfMemoryError during UnitTests
    By camach in forum Container
    Replies: 2
    Last Post: May 26th, 2005, 05:28 PM
  4. Spring + SiteMesh + Velocity?
    By chrisrbailey in forum Web
    Replies: 3
    Last Post: Jan 20th, 2005, 08:15 PM
  5. how can i get Data in sitemesh decorators?
    By qiao_lei1980@hotmail.com in forum Web
    Replies: 2
    Last Post: Oct 12th, 2004, 06:32 AM

Posting Permissions

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