Announcement Announcement Module
Collapse
No announcement yet.
Chaining view resolvers(InternalResourceViewResolver,AjaxUrlBase dViewResolver )prob. Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Chaining view resolvers(InternalResourceViewResolver,AjaxUrlBase dViewResolver )prob.

    Hi,

    I am using Spring WebFlow to extend my web application's functionality so that I can use both SpringMVC as well as SpringWebFlow.

    Problem I am running into is I can not chain view resolvers.
    For Web Flow I configured

    Code:
      <bean id="tilesViewResolver"   class="org.springframework.js.ajax.AjaxUrlBasedViewResolver">
    		<property name="order"><value>0</value></property>
    		<property name="viewClass" value="org.springframework.webflow.mvc.view.FlowAjaxTilesView"/>
    </bean>
    
    <bean id="viewResolver"	
    class="org.springframework.web.servlet.view.InternalResourceViewResolver">
    		<property name="order"><value>1</value></property>
    		<property name="prefix" value="/WEB-INF/jsp/" />
    		<property name="suffix" value=".jsp" />
    	</bean>
    
       <bean id="viewFactoryCreator"		 class="org.springframework.webflow.mvc.builder.MvcViewFactoryCreator">
    		<property name="viewResolvers">
    			<list>
    				<ref bean="tilesViewResolver" />
    				<ref bean="viewResolver" />				
    			</list>
    		</property>
    	</bean>
    Both AjaxUrlBasedViewResolver and InternalResourceViewResolver extend from UrlBasedViewResolver.

    Documentation of "UrlBasedViewResolver" says:-

    " When chaining ViewResolvers, a UrlBasedViewResolver always needs
    to be last, as it will attempt to resolve any view name, no matter whether
    the underlying resource actually exists."
    As both Resolvers extend from same UrlBasedViewResolver proper chaining of view resolvers in my case can not be possible.

    Any suggestions how can I chain these resolvers.

    Thanks

  • #2
    Doesn't order work?

    Code:
    <property name="order" value="1"/>

    Comment


    • #3
      No order does not works in this case. as in documentation of UrlBasedViewResolver says
      When chaining ViewResolvers, a UrlBasedViewResolver always needs
      to be last, as it will attempt to resolve any view name, no matter whether
      the underlying resource actually exists.



      Code:
         <property name="order" value="1"/>
      Any how I tried <property name="order" value="1"/> but with out any success.
      It tries to use viewresolver that is used first in list of viewresolvers.

      Comment


      • #4
        As stated by the documentation which you yourself quoted the UrlBased one needs to be last. In your case BOTH ViewResolvers are UrlBasedViewResolvers you can only have 1 UrlBasedViewResolver.

        Any suggestions how can I chain these resolvers.
        You cannot.

        You will need to use another ViewResolver in combination with the AjaxUrl one.

        Comment


        • #5
          thanks for ur quick reply

          Comment


          • #6
            I came up with my own subclass of UrlBasedViewResolver so that I could have proper ViewResolver chaining. To the spring team : UrlBasedViewResolver should allow chaining properly. Why it doesn't is beyond me and the way it's currently implemented is flat out stupid :

            Code:
            public class UrlBasedViewResolver extends org.springframework.web.servlet.view.UrlBasedViewResolver {
            
            	@Override
            	protected boolean canHandle(String viewName, Locale locale) {
            		String[] viewNames = getViewNames();
            		return (viewNames != null ? PatternMatchUtils.simpleMatch(viewNames, viewName) : getWebApplicationContext().getResource(getPrefix() + viewName + getSuffix()).exists());
            	}
            
            }

            Comment


            • #7
              UrlBasedViewResolver should allow chaining properly. Why it doesn't is beyond me and the way it's currently implemented is flat out stupid
              In your code you make 2 assumptions we cannot make

              1. Always provide a list of views generated/handled by this ViewResolver (not very nice is it)
              2. As a fallback assume that the view is loadable with the current ResourceLoader (is going to fail miserably if you use something like tiles, velocity of freemarker which either don't have actual files or load files with a different strategy).

              So your 'fix' breaks more then it fixes... There is no 100% way of checking for all supported view strategies if a URL based view is actually there...

              Comment


              • #8
                Hi Marten,

                To address your concerns :

                1. The views list can be empty (and in the case of my projects, it always is), leaving it up to the controller to dynamically determine which file should be loaded (which is already the behaviour in the Spring UrlBasedViewResolver implementation anyway).
                2. The Spring implementation of the resolver already assumes that the file that would be dynamically determined exists, my implementation just checks this assumption first and lets view resolution continue rather than letting the resolver fail and show an exception to the user.

                You're right in that there is no 100% way of checking all supported view strategies, but in the case where you know you're loading JSPs from files along a path, there's nothing wrong with the workaround I've provided. It certainly doesn't "break" anything.

                Comment


                • #9
                  This is how I make my Velocity View Resolver Chainable. If a velocity template cannot be found for a view name, it returns null so the chaining falls through to the other view resolver. This is how I'm mixing tile/jsp views and velocity views.

                  Note, the ResourceHelper is a utility class that essentially attempts to do a:

                  Code:
                  InputStream is = Thread.currentThread().getContextClassLoader().getResourceAsStream(resourcePath);
                  It will throw an exception if the resource does not exist. The code below has a obvious performanant flaw in that it always attempts to resolve view resources, even if it previously tried and they didn't exist. In my case, this is for a very low volume web application so I don't really care but an obvious improvement would be to add a local cache for failed view resolutions so they fall through immediately rather than having the classloader repeatedly try to load resources that we know aren't there.

                  Code:
                  public class ChainableVelocityViewResolver extends VelocityViewResolver
                  {
                      private static final Logger LOG = LoggerFactory.getLogger(ChainableVelocityViewResolver.class);
                      /**
                       * Only return views for specific view names
                       */
                      public View resolveViewName(String viewName, Locale locale)
                          throws Exception 
                      {
                          if (LOG.isDebugEnabled())
                          {
                              LOG.debug("Resolving view: " + viewName);
                          }
                          
                          String resourceName = this.getPrefix() + viewName + this.getSuffix();
                          
                          // See if resource exists
                          try
                          {
                              ResourceHelper.getResource(resourceName);
                              // If no exception, the resource exists
                              return super.resolveViewName(viewName, locale);
                          }
                          catch (IllegalStateException e)
                          {
                              return null;
                          }
                      }
                  }
                  Last edited by chudak; Dec 3rd, 2008, 09:12 AM.

                  Comment


                  • #10
                    Actually, the great thing about the change I made to UrlBasedViewResolver is that it gets to make use of its parent class' caching.

                    Comment


                    • #11
                      UrlBasedViewResovlers should allow you to specify if they can be chainable

                      1. Always provide a list of views generated/handled by this ViewResolver (not very nice is it)
                      2. As a fallback assume that the view is loadable with the current ResourceLoader (is going to fail miserably if you use something like tiles, velocity of freemarker which either don't have actual files or load files with a different strategy).
                      So in situations where you are pulling from files out of the resource path - you can make those assumptions.

                      Why not expose a parameter on the UrlBasedViewResolver that is something like:

                      viewsAreFileBacked or some other flag (with a better name than that) - set to be false by default - that when true enables the UrlBasedViewResolvers to chain.

                      The insistence that you can't make those assumptions causes everyone I know of to immediately subclass and override the view resolver to allow it to chain - because in most situations you CAN chain the view resolvers - except in the limited situations you are talking about.

                      Comment


                      • #12
                        Fallback View Resolver (Similar to chain)

                        Chaining View Resolver using order property helps you in Spring 3 but in 2.5 you have to handle it somewhat differently.

                        Because when we configure the multimple InternalResourceviewResolver in Spring 2.5,(which in in turn is UrlBasedViewResolver) I consider only the first bean (ViewResolver) occurance or bean with order 1 to resolve view and do not pass it to the next view resolver bean with higer order.

                        I think this could help you in many ways

                        package com.util;

                        import java.util.Locale;

                        import org.springframework.web.servlet.View;
                        import org.springframework.web.servlet.view.InternalResou rceViewResolver;

                        public class FallbackJstlViewResolver extends InternalResourceViewResolver {

                        private InternalResourceViewResolver mFallBackViewResolver ;

                        public View resolveViewName(String pViewName , Locale pLocale)throws Exception{
                        System.out.println("ChainableJstlViewResolver "+pViewName+" "+pLocale);

                        View lView =null;

                        String lResourecePath = getPrefix()+pViewName+getSuffix();
                        if (!getApplicationContext().getResource(lResourecePa th).exists()){
                        System.out.println("Inside If : "+lResourecePath+"Not found");
                        if (mFallBackViewResolver == null){
                        System.out.print("No fall back view resolver configured");
                        lView = super.resolveViewName(pViewName, pLocale);
                        }else{
                        System.out.print("Resolving view using fallback view resolver");
                        lView = mFallBackViewResolver.resolveViewName(pViewName, pLocale);
                        }

                        }else{
                        System.out.println("Inside Else");
                        lView = super.resolveViewName(pViewName, pLocale);

                        }
                        System.out.println(lResourecePath);
                        return lView;
                        }

                        public void setFallBackViewResolver(InternalResourceViewResolv er pFallBackViewResolver){
                        mFallBackViewResolver = pFallBackViewResolver;
                        }
                        }


                        -------------------Bean Configuration ----------------------

                        <bean id="ClientView" class="com.util.FallbackJstlViewResolver">
                        <property name="viewClass" value="org.springframework.web.servlet.view.JstlVi ew"/>
                        <property name="prefix" value="/jsps/client1/"/>
                        <property name="suffix" value=".jsp"/>
                        <property name="fallBackViewResolver" ref="ProductView"/>
                        <property name="order" value="1"/>
                        </bean>

                        <bean id="ProductView" class="org.springframework.web.servlet.view.Intern alResourceViewResolver">
                        <property name="viewClass" value="org.springframework.web.servlet.view.JstlVi ew"/>
                        <property name="prefix" value="/jsps/"/>
                        <property name="suffix" value=".jsp"/>
                        <property name="order" value="2"/>
                        </bean>
                        Last edited by prashanthjoshi; Sep 22nd, 2009, 11:58 PM.

                        Comment

                        Working...
                        X