Help

Built with Seam

You can find the full source code for this website in the Seam package in the directory /examples/wiki. It is licensed under the LGPL.

You have a regular Servlet and you want to integrate it in your Seam application - or you want to serve some XML or binary data without any JSF actions or interference.

Regular Servlet in web.xml

You can map a servlet as usual in web.xml to a URL pattern. When that servlet is called, however, it also acts like a regular servlet. That means you won't have access to any Seam components through Component.instance() lookup. This basically means there is no integration.

Wrapping the call in Seam contexts

You can wrap the processing of the request in your servlet, so that Seam contexts are available. Pick one:

  1. You can map the <web:context-filter/> in components.xml to wrap all calls on a particular URL pattern, see reference documentation.
  2. You can wrap a call manually in a particular Servlet:
class MyServlet extends HttpServlet {

    protected void service(final HttpServletRequest request, final HttpServletResponse response)
            throws ServletException, IOException {

        new ContextualHttpServletRequest(request) {
            @Override
            public void process() throws Exception {
                doWork(request, response);
            }
        }.run();
    }

    private void doWork(HttpServletRequest request, HttpServletResponse response) {
        Component.getInstance(...);
    }

}

Serving the content as a Seam resource

An alternative solution is the SeamResourceServlet. That servlet is enabled anyway in almost all Seam applications (check your web.xml and the documentation) and it can act as a router for HTTP requests. All you have to do is extend the class AbstractResource and you can handle HTTP requests:

@Scope(APPLICATION)
@Name("myResource")
@BypassInterceptors
public class MyResource extends AbstractResource {

    @Override
    public String getResourcePath() {
        return "/myresource"
    }


    @Override
    public void getResource(final HttpServletRequest request, final HttpServletResponse response)
            throws ServletException, IOException {

        new ContextualHttpServletRequest(request) {
            @Override
            public void process() throws IOException {
                doWork(request, response);
            }
        }.run();
    }

    private void doWork(HttpServletRequest request, HttpServletResponse response) {
        Component.getInstance(...);
    }
}

Most applications map the SeamResourceServlet to the URL pattern /seam/resource. The class above would then be available under the path /seam/resource/myresource and all HTTP requests on that path will be handled by the getResource() method.

The advantage of this approach is that you can write more modular systems, you can create new resources without changing your web.xml. Many of Seam's (internal) integration adapters are implemented as AbstractResources.

Note that the MyResource class is not a real Seam component and can not be a real Seam component, despite having an @Name annotation. It's like half-a-component, the name only being used for installation of the class at startup time. The scope is always APPLICATION, this is a thread-safe class.

The @BypassInterceptors is a) required so that Seam doesn't proxy the class on startup and b) so that you immediately see that you can not use @In or @Restrict or any other Seam functionality on fields and methods of that class. Only inside the dowWork() method are all Seam contexts available and you can start calling - usually through a first Component.getInstance() lookup - real Seam components.

What about transactions?

Seam starts a transaction when a JSF request hits the server. It does not do that when a simple HTTP request hits your servlet, or your Seam resource. You can execute the request inside a transaction:

  • Programmatically, calling Transaction.instance().begin() and handling it yourself in your doWork() method.
  • Declaratively, calling a Seam component that is marked @Transactional in your doWork() method after looking it up with Component.getInstance(). Seam's transaction interceptor will start a transaction for that method call and commit it when the call returns.