users@jersey.java.net

Re: [Jersey] more about resource filters

From: Paul Sandoz <Paul.Sandoz_at_oracle.com>
Date: Fri, 30 Jul 2010 10:15:50 +0200

Hi Brian,

On Jul 29, 2010, at 8:02 PM, Brian Moseley wrote:

> a few more questions about resource filters:
>
> when a filter is applied to a resource class via @ResourceFilters, is
> the filter instance obtained from the IoC container, or is it
> instantiated directly? signs point to the latter - I'm using Spring,
> and my filter class has a field annotated with @Autowired. at runtime
> that field is null, ie the dependency was not injected.
>

The former, so injection should work if ResourceFilter classes
referenced in the @ResourceFilters annotation are spring managed.


> by snooping around in the code of various filters included in Jersey,
> it looks like @Context is supported for filter factories at least.
> presuming that is also true for filters themselves,

Only when used with @ResourceFilters otherwise it is the
responsibility of the ResourceFilterFactory to return instances of
ResourceFilters.


> then I could
> inject the servlet context, use it to find the Spring application
> context, and look up the bean myself, but obviously I'd prefer not to
> have to do that.
>
> also, I find that @ResourceFilters isn't recognized by the runtime if
> I apply it to a trait and mix that trait into my resource class. the
> annotation is only recognized when I apply it directly to the resource
> class. is this by design or have I uncovered a bug?
>

It may be a restriction on annotation visibility with traits. I
presume that the runtime operating on such Spring-based traits needs
to understand how to "dive into" a trait to search for what is
required rather than operating directly on the annotations returned
via the reflection API?

In this respect you may be better off using a ResourceFilterFactory
that operates directory on the annotation you have defined, kind of
like RolesAllowedResourceFilterFactory (see end of email).


> I've searched a lot and haven't found many resources describing how
> resource filters work other than the javadoc for the
> com.sun.jersey.api.container.filter package and a few messages on this
> list. has more been written about them elsewhere?
>

Unfortunately that is it, it's all in the JavaDoc for the package and
the classes. Then the next best place is code for
ResourceFilterFactory implementations.

Paul.

public class RolesAllowedResourceFilterFactory implements
ResourceFilterFactory {

     private @Context SecurityContext sc;

     private class Filter implements ResourceFilter,
ContainerRequestFilter {

         private final boolean denyAll;
         private final String[] rolesAllowed;

         protected Filter() {
             this.denyAll = true;
             this.rolesAllowed = null;
         }

         protected Filter(String[] rolesAllowed) {
             this.denyAll = false;
             this.rolesAllowed = (rolesAllowed != null) ?
rolesAllowed : new String[] {};
         }

         // ResourceFilter

         public ContainerRequestFilter getRequestFilter() {
             return this;
         }

         public ContainerResponseFilter getResponseFilter() {
             return null;
         }

         // ContainerRequestFilter

         public ContainerRequest filter(ContainerRequest request) {
             if (!denyAll) {
                 for (String role : rolesAllowed) {
                     if (sc.isUserInRole(role))
                         return request;
                 }
             }

             throw new
WebApplicationException(Response.Status.FORBIDDEN);
         }
     }

     public List<ResourceFilter> create(AbstractMethod am) {
         // DenyAll on the method take precedence over RolesAllowed
and PermitAll
         if (am.isAnnotationPresent(DenyAll.class))
             return Collections.<ResourceFilter>singletonList(new
Filter());

         // RolesAllowed on the method takes precedence over PermitAll
         RolesAllowed ra = am.getAnnotation(RolesAllowed.class);
         if (ra != null)
             return Collections.<ResourceFilter>singletonList(new
Filter(ra.value()));

         // PermitAll takes precedence over RolesAllowed on the class
         if (am.isAnnotationPresent(PermitAll.class))
             return null;

         // RolesAllowed on the class takes precedence over PermitAll
         ra = am.getResource().getAnnotation(RolesAllowed.class);
         if (ra != null)
             return Collections.<ResourceFilter>singletonList(new
Filter(ra.value()));

         // No need to check whether PermitAll is present.
         return null;
     }
}