Monthly Archives: February 2011

Injecting Security Principal (or any other custom component) into Jersey Resources with Guice

Recently I saw a post on a Jersey users mailing list (browse archive) asking for help with injection of a custom component into a Jersey resource. In particular, Jersey supports injection of a SecurityContext out of the box. Yet, the user wanted to directly inject custom security Principal rather than invoking the same SecurityContext.getUserPrincipal() getter all the time.

As you probably know, there is a jersey-guice module that provides a Jersey integration with Google Guice. Using Guice is an easy and elegant way how to extend injectable components in Jersey. Jersey already provided a very basic sample showing how to use Guice which I decided to update and extend to demonstrate how injecting a custom SecurityContext as well as Principal can be done.

First I have created a custom SecurityContext implementation:

public final class MySecurityContext implements SecurityContext {
 
    private static final class MyPrincipal implements Principal {
 
        @Override
        public String getName() {
            return "test-name";
        }
 
        @Override
        public String toString() {
            return "MyPrincipal{" + getName() + '}';
        }
    }
 
    @Override
    public Principal getUserPrincipal() {
        return new MyPrincipal();
    }
    // ... rest of the code omitted for clarity... 
}

To make sure that my custom implementation will get injected and used by Jersey components I had to bind my implementation to the SecurityContext interface. As described in the jersey-guice module documentation, this can be done by extending and implementing a custom GuiceServletContextListener class:

public class GuiceServletConfig extends GuiceServletContextListener {
 
    @Override
    protected Injector getInjector() {
        return Guice.createInjector(new ServletModule() {
 
            @Override
            protected void configureServlets() {
                // Bind classes and resources
                ...
                bind(SecurityContext.class).to(MySecurityContext.class);
                ...
 
                serve("/*").with(GuiceContainer.class);
            }
        });
    }
}

This custom servlet context listener is then registered in the web application’s web.xml config file:

<web-app version="2.5" ... >
    <listener>
        <listener-class>com.sun.jersey.samples.guice.GuiceServletConfig</listener-class>
    </listener>
    ...
</web-app>

Now that I have showed how to inject a custom implementation of the whole SecurityContext, I will add more code to enable direct injection of Principal instances. In order to do that I need to create a custom Guice Provider. I will make it servlet request-scoped to make sure I am injecting proper Provider instance. The resulting implementation is quite straightforward:

@RequestScoped
public final class PrincipalProvider implements Provider<Principal> {
 
    private SecurityContext sc;
 
    @Inject
    public PrincipalProvider(SecurityContext sc) {
        this.sc = sc;
    }
 
    @Override
    public Principal get() {
        return sc.getUserPrincipal();
    }
}

Now the only remaining thing is to update the custome guice servlet context listener implementation with a new binding:

public class GuiceServletConfig extends GuiceServletContextListener {
 
    @Override
    protected Injector getInjector() {
        return Guice.createInjector(new ServletModule() {
 
            @Override
            protected void configureServlets() {
                // Bind classes
                ...
                bind(Principal.class).toProvider(PrincipalProvider.class);
                bind(SecurityContext.class).to(MySecurityContext.class);
 
                serve("/*").with(GuiceContainer.class);
            }
        });
    }
}

With that, I can now inject the Principal directly into my Jersey resources. At the same time I can be sure that the my custom implementation of the SecurityContext will be used:

@Path("bound/perrequest")
@RequestScoped
public class PerRequestResource {
    ...
    private final SingletonComponent sc;
    private final Principal principal;
 
    //Create singleton component and inject into resource at construction as well as principal
    @Inject
    public PerRequestResource(SingletonComponent sc, Principal principal) {
        this.sc = sc;
        this.principal = principal;
    }
    ...
}

For the complete sample code, please download the guicefilter-webapp Jersey sample project.

JAX-RS 2.0 is moving

The JCP Expert Group for JAX-RS 2.0 API (JSR-339) has been formed recently. That means the real fun can start now. The main areas we plan to focus on include

  • improved alignment & support for JSR-330 injection
  • parameter validation
  • RESTful MVC architecture model definition
  • API for asynchronous processing support
  • and more…

Roberto has already created a corresponding project on java.net – http://jax-rs-spec.java.net/

Provided you have a java.net ID (if not, you can easily create a new one), you are invited to subscribe as an observer of the project as well as you can subscribe to the Users’ mailing list as well as other project mailing lists. Also feel free to browse through the new JAX-RS source code. We’re just starting so, right now the code is almost identical to the JAX-RS 1.1 code. This will change, though, I promise :)

We would like to get community involved as much as possible so I encourage you to send any feedback you might have to the users mailing list. We are looking forward to your input! Also, you may want to use our issue tracker to submit any bugs or issues that you may find or new feature requests you would like us to address in the next version of JAX-RS. I should perhaps mention that we made a deliberate decision not to include a version number or a JSR number in the project name – we plan to use the project infrastructure for all new versions of JAX-RS, so it makes sense to file any (reasonable) feature requests in the issue tracker – even if you believe that the feature would not be addressed in JAX-RS 2.0, it may still be addressed in a later specification release.

With that I conclude this initial JAX-RS 2.0 update. Stay tuned for more soon!

Tip: Finding Metro version you are using

Note: This tip works properly only with a Metro 2.1 build or higher

As part of the mavenization, project migration and consolidation efforts mentioned in my previous update on Metro 2.1 related changes we have also looked into the ways how we can improve the identification of Metro bits used by our users. We are still not completely done with the solution (e.g. I would like to see some convenient command line script or such available to our users)  yet at least the current Metro identification String provides much more relevant information compared to the past.

So how can you find out what Metro version are you running on? The identification string is located in both OSGi-fied as well as non OSGi-fied version of the Metro runtime jar, i.e. webservices-osgi.jar or webservices-rt.jar respectively and it is stored in the com/sun/xml/ws/util/version.properties file under the build-version key. To print the value of this property, you can use following (bash) command:

$ unzip -p webservices-osgi.jar com/sun/xml/ws/util/version.properties | grep build-version

or

$ unzip -p webservices-rt.jar com/sun/xml/ws/util/version.properties | grep build-version

You should see an output similar to this one:

build-version=Metro/2.1-b25 (trunk-6664; 2010-12-31T11:31:15+0000) JAXWS-RI/2.2.3-promoted-b06 JAXWS/2.2

What does this value mean? It may be obvious that this artifact belongs to

  • Metro 2.1-b25 version
  • built from the Metro/WSIT SVN trunk revision 6664
  • on Dec 31st, 2010
  • based on JAX-WS RI version 2.2.3-promoted-b06
  • which implements JAX-WS 2.2 API specification

Thus if you want to see what version of Metro is bundled in the build of GlassFish 3.1 (or later) that you are using, just cd <gf-install>/glassfish/modules directory and run the OSGi version of the above-mentioned command. I shall also note that this information is also available in all HTTP based client requests as a value of the HTTP User-Agent request message header and as such will be visible in any HTTP traffic monitoring tool or in Metro HTTP message dumps.