Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Jersey Guice JSP how to?

Tags:

I'm using tomcat 6, jersey 1.8 with jersey guice and guice 3. I'm having problem using JSP with my setup. I have a "Status" servlet served as a simple servlet configured by web.xml, a jersey servlet configured by GuiceFilter which returns a jsp view response (jsp is /diff/index.jsp) to render the result as in:

Viewable view = new Viewable("/diff/index.jsp", null); 
Response response = Response.ok().entity(view).build(); 
return response;

It all works perfectly with simple Jersey, once I'm trying to have it with Guice integration the JSP fails and I'm getting a 404 response with "The requested resource (/diff/index.jsp) is not available."

Using the debugger I can see that the JSPTemplateProcessor as called and got a RequestDispatcher with a StandardWrapper that has "isJspServlet = true" and "jspFile = null".

The web.xml looks like this:

  <servlet>
        <display-name>Status Page</display-name>
        <servlet-name>Status</servlet-name>
        <servlet-class>my.BaseStatusPage</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>

    <servlet-mapping>
        <servlet-name>Status</servlet-name>
        <url-pattern>/Status/*</url-pattern>
    </servlet-mapping>

   <filter>
        <filter-name>guiceFilter</filter-name>
        <filter-class>com.google.inject.servlet.GuiceFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>guiceFilter</filter-name>
        <url-pattern>/REST/*</url-pattern>
    </filter-mapping>
    <listener>
        <listener-class>my.GuiceServletConfig</listener-class>
    </listener>

=====================

GuiceServletConfig:

public class GuiceServletConfig extends GuiceServletContextListener { 

  @Override 
  protected Injector getInjector() { 
    return Guice.createInjector(new JerseyServletModule() { 

      @Override 
      protected void configureServlets() { 
        bind(DiffPage.class);// the jersey servlet 

        Map<String, String> params = new HashMap<String, String>(); 
        params.put(PROPERTY_PACKAGES, "my"); 
        params.put(PROPERTY_WEB_PAGE_CONTENT_REGEX, ".*\\.jsp"); 
        params.put(FEATURE_REDIRECT, "true"); 
        params.put(FEATURE_IMPLICIT_VIEWABLES, "true"); 
        params.put(RESOURCE_CONFIG_CLASS, "com.sun.jersey.api.core.PackagesResourceConfig"); 

        serve("/REST/*").with(GuiceContainer.class, params); 
      } 
    }); 
  } 

=====================

Having GuiceContainer as a filter made the servlets served from the web.xml fail. Adding a jsp servlet in web.xml didn't do much good.

Btw, I've read the thread from Jul 25, 2010 at the jersey mailing list but it didn't work for me.

Help appreciated Thanks, Eishay

-- Appendix -- I find myself calling JSP from the business logic code. Ugly but works:

  protected Response renderJsp(HttpServletRequest request,
      HttpServletResponse response, ServletConfig servletConfig) {
    request.setAttribute("org.apache.catalina.jsp_file", "/diff/index.jsp");
    Class jspServletClazz;
    try {
      jspServletClazz = forName("org.apache.jasper.servlet.JspServlet");
      Object jspServlet = jspServletClazz.getConstructor().newInstance();
      jspServletClazz.getMethod("init", ServletConfig.class).invoke(jspServlet,
          servletConfig);
      jspServletClazz.getMethod("service", HttpServletRequest.class,
          HttpServletResponse.class).invoke(jspServlet, request, response);
    } catch (Exception e) {
      throw new RuntimeException(e);
    }
    return Response.ok().build();
  }
like image 224
Eishay Smith Avatar asked Aug 26 '11 00:08

Eishay Smith


1 Answers

The problem is due to configuring Guice to "serve" requests "with" a Servlet: The Servlet blocks the request chain and prevents requests such as static content and jsp calls from being passed onwards to the default handlers.

The solution is to configure Guice to "filter" requests "through" a Filter instead:

web.xml

<listener>
    <listener-class>my.guice.config.package.GuiceServletConfig</listener-class>
</listener>

<filter>
    <filter-name>guiceFilter</filter-name>
    <filter-class>com.google.inject.servlet.GuiceFilter</filter-class>
</filter>

<filter-mapping>
    <filter-name>guiceFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

Note this is a filter configuration as opposed to a servlet configuration.

GuiceServletConfig

public class GuiceServletConfig extends GuiceServletContextListener {

    @Override
    protected Injector getInjector() {
        return Guice.createInjector(new JerseyServletModule() {

            @Override
            protected void configureServlets() {

                /* Bindings */
                bind(JerseyResource.class);

                /* Parameters*/
                Map<String, String> params = new HashMap<String, String>(); 
                params.put(JSP_TEMPLATES_BASE_PATH, "/WEB-INF/jsp"); 
                params.put(FEATURE_FILTER_FORWARD_ON_404, "true");

                filter("/*").through(GuiceContainer.class, params);
            } 
        });
    }
}

Note the use of filter().through(); instead of serve().with();.

This allows static and jsp requests (and includes!) to be passed onto the next link in the filter chain, and eventually to the default content handlers.

Also note the use above of the more recent ServletContainer.FEATURE_FILTER_FORWARD_ON_404 option as an alternative to the more complex ServletContainer.PROPERTY_WEB_PAGE_CONTENT_REGEX option for when you're happy with the default locations for your static content.

You can still use the other options listed in the original question.

For the next step, you can also refer to this question specifically involving a problem I had with adding Guice AOP into this configuration to work alongside Guice Dependency Injection, Jersey REST Services, Static Content (JavaScript, CSS, Images) and returning JSP Viewables.

like image 60
Kynth Avatar answered Sep 28 '22 11:09

Kynth