Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

 

 

 

 

 

Span
stylefont-size:2em;font-weight:bold
JAX-RS : Redirection
 

 

 

 

 

Table of Contents

With RequestDispatcherProvider

...

Here are some examples. Lets assume we have a book.war web application deployed.

Code Block
xml
xml

<jaxrs:server id="bookservice1" address="/bookstore1">
    <jaxrs:serviceBeans>
      <bean class="org.apache.cxf.systest.jaxrs.BookStoreDispatch"/>
    </jaxrs:serviceBeans>		  
    <jaxrs:providers>
       <ref bean="dispatchProvider"/>
    </jaxrs:providers> 
</jaxrs:server>

<bean id="dispatchProvider" class="org.apache.cxf.jaxrs.provider.RequestDispatcherProvider">
      <property name="resourcePath" value="/book.html"/>
</bean>

...

Here is another example (omitting jaxrs:server declaration for brewity):

Code Block
xml
xml


<bean id="dispatchProvider" class="org.apache.cxf.jaxrs.provider.RequestDispatcherProvider">
      <property name="resourcePath" value="/book.jsp"/>
</bean>

The only difference from the previous example is that "/book.jsp" will be delegated to with the task of creating a view. This is a more interesting example and we presume that the resource method returns say an instance of the "org.bar.Book" bean:

Code Block
java
java

@Path("/books")
public Resource {
    @GET
    @Produces({"text/html", "application/xml"})
    @Path("{id}")
    public Book getBook(@PathParam("id") String id) {
        // return the book
    }
}

...

RequestDispatcherProvider will make an instance of Book available as an HttpServletRequest attribute named "org.bar.Book" by default. this can be customized. If a "beanName" property is set, for example to "book", then book.jsp will access a Book instance as a "book" attribute. If you have say 2 resource methods returning instances of different bean classes, possibly for different view handlers then a beanNames map property can be used, for example:

Code Block
xml
xml


<bean id="dispatchProvider" class="org.apache.cxf.jaxrs.provider.RequestDispatcherProvider">
      <property name="classResources">
          <map>
             <entry key="org.bar.Book"  value="/book.jsp"/>
             <entry key="org.bar.Customer"  value="/customer.jsp"/>
          </map>
      </property>
      <property name="beanNames">
          <map>
             <entry key="org.bar.Book"  value="book"/>
             <entry key="org.bar.Customer"  value="customer"/>
          </map>
      </property>
</bean>

...

Now, imagine a scenario like this: we have two resource methods returning a ReservationStatus bean. The first method returns a successful confirmation or uses Response.seeOther(...) to redirect to a method handling the failed reservation. So both methods return the same ReservationStatus bean but we will have two different views handling successful and failed reservations respectively. Here is one way to manage it:

Code Block
xml
xml

<bean id="reserveRegistrationViews" class="org.apache.cxf.jaxrs.provider.RequestDispatcherProvider">
         <property name="resourcePaths">
            <map>
              <entry key="/reservations/reserve/complete" value="/forms/reservationConfirm.jsp"/>
              <entry key="/reservations/reserve/failure" value="/forms/reservationFailure.jsp"/>
            </map>
         </property>
         <property name="beanName" value="data"/>
</bean>

...

Next, imagine a scenario like this: we have a single resource method accepting some data and the response view will need to be different depending on the status of the request processing. Using enumerations is the most effective option in this case:

Code Block
java
java

package resource;

public class Status {
    UPDATE_SUCCESS,
    UPDATE_FAILURE
}

@Path("/")
public class Resource {

  @PUT
  @Produces("text/html")
  public Response update(SomeData data) {
     if (update(data)) {
         return Response.ok(Status.UPDATE_SUCCESS).build();
     } else {
         return Response.ok(Status.UPDATE_FAILURE).build();  
     }
  } 
} 

Next, you may have a single JSP handler which will check whether it is Status.UPDATE_SUCCESS or Status.UPDATE_FAILURE and format the response accordingly. In this case a basic RequestDispatcherProvider configuration will do:

Code Block
xml
xml


<bean id="dispatchProvider" class="org.apache.cxf.jaxrs.provider.RequestDispatcherProvider">
      <property name="resourcePath" value="/updateStatus.jsp"/>
</bean>

Alternatively you may have a dedicated view handler dealing with the specific status, in this case either:

Code Block
xml
xml

<bean id="reserveRegistrationViews" class="org.apache.cxf.jaxrs.provider.RequestDispatcherProvider">
         <property name="classResources">
            <map>
              <entry key="resource.Status.UPDATE_SUCCESS" value="/forms/updateSuccess.jsp"/>
              <entry key="resource.Status.UPDATE_FAILURE" value="/forms/updateFailure.jsp"/>
            </map>
         </property>
</bean>

or, starting from CXF 2.7.1,

Code Block
xml
xml

<beans xmlns="http://www.springframework.org/schema/beans"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xmlns:util="http://www.springframework.org/schema/util"
      xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd">

<bean id="reserveRegistrationViews" class="org.apache.cxf.jaxrs.provider.RequestDispatcherProvider">
         <property name="enumResources">
            <map>
              <entry 
                 <key>
                    <util:constant static-field="resource.Status.UPDATE_SUCCESS"/>
                 </key> 
                 <value>/forms/updateSuccess.jsp</value>
              </entry>
              <entry 
                 <key>
                    <util:constant static-field="resource.Status.UPDATE_FAILURE"/>
                 </key> 
                 <value>/forms/updateFailure.jsp</value>
              </entry> 
            <map>
         </property>
</bean>
</beans>

...

Starting from CXF 2.6.1 it is possible to configure the provider to check if the current class has an associated view handler or not, for example:

Code Block
xml
xml

<bean id="viewHandler" class="org.apache.cxf.jaxrs.provider.RequestDispatcherProvider">
         <property name="dispatcherName" value=jsp""/>
         <property name="useClassNames" value="true"/>
</bean>

...

RequestDispatcherProvider also checks a "redirect.resource.path" property on the outbound message. If this property is set then it will try to find a RequestDispatcher available on a given path.

A new property, "includeResource" is available starting from CXF 3.0.4: RequestDispatcher.include() instead of RequestDispatcher.forward() will be used if this property is set to true.

Finally, a 'servletContextPath' property can be used to have some other ServletContext (as opposed to the current one) be used for RequestDispatcher look-ups. If set then the current ServletContext.getContext(servletContextPath) will be used to get the needed ServletContext.

...

To get RequestDispatcherProvider log the information about redirects, please set a 'logRedirects' property:

Code Block
xml
xml

<bean id="reserveRegistrationViews" class="org.apache.cxf.jaxrs.provider.RequestDispatcherProvider">
         <property name="logRedirects" value="true"/>
         <!-- other properties as needed --> 
</bean>

You will see the logging entry like this one:

Code Block
java
java

23-Jul-2012 11:26:13 org.apache.cxf.jaxrs.provider.RequestDispatcherProvider logRedirection

INFO: Setting an instance of "oauth2.common.ConsumerRegistration" as HttpServletRequest attribute "newClient" and redirecting the response to "/forms/registerAppConfirm.jsp"

...

If you have CXFServlet listening on "/" (thus effectively catching all the requests) and also would like to use RequestDispatcherProvider, then make sure that a 'dispatcherName' property is also set, for example:

Code Block
xml
xml

<bean id="dispatchProvider" class="org.apache.cxf.jaxrs.provider.RequestDispatcherProvider">
    <property name="dispatcherName" value="jsp"/>
    <property name="resourcePath" value="/WEB-INF/jsp/test.jsp"/>
</bean> 

...

Also if you have many public view handlers then rather than having a "dispatcherName" property set on every dispatcher bean, you can get it set only once on CXFServlet:

Code Block
xml
xml

<servlet>
        <servlet-name>RESTServlet</servlet-name>
        <servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class>
        <init-param>
    	   <param-name>redirects-list</param-name>
	   <param-value>/forms/.*</param-value>
	</init-param>
	<init-param>
    	   <param-name>redirect-servlet-name</param-name>
	   <param-value>jsp</param-value>
	</init-param>
	<load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>RESTServlet</servlet-name>
        <url-pattern>/*</url-pattern>
    </servlet-mapping>

...