Wednesday, August 23, 2017

Dynamically adding an interceptor to a build-in CDI bean

In Java EE's CDI, beans can be augmented via 2 artefacts; Decorators and Interceptors.

Decorators are typically owned by the application code and can decorate a bean that's shipped by the container (build-in beans) or a library.

Interceptors are typically shipped by a library and can be applied (bound) to a bean that's owned by the application.

So how do you bind a library shipped interceptor to a library shipped/build-in bean? In CDI 1.2 and before this wasn't really possible, but in CDI 2.0 we can take advantage of the new InterceptionFactory to do just this. It's not entirely trivial yet, but it's doable. In this article we'll demonstrate how to apply the @RememberMe interceptor binding from the new Java EE 8 Security spec to a build-in bean of type HttpAuthenticationMechanism, which is from the Security spec as well.

First we configure our authentication mechanism by means of the following annotation:

@BasicAuthenticationMechanismDefinition(
    realmName="foo"
)

 

This will cause the container to enable a build-in bean with interface type HttpAuthenticationMechanism, but having an unknown (vendor specific) implementation.

Next we'll definite an alternative for this bean via a CDI producer:

@Alternative
@Priority(500)
@ApplicationScoped
public class ApplicationInit {
    
    @Produces
    public HttpAuthenticationMechanism produce(InterceptionFactory<HttpAuthenticationMechanismWrapper> interceptionFactory, BeanManager beanManager) {
        return ...
    }
Note that perhaps somewhat counter intuitively the @Alternative annotation is put on the bean hosting the producer method, not on the producer method itself.

A small challenge here is to obtain the bean with type HttpAuthenticationMechanism that would have been chosen by the CDI runtime had our producer not been there. For a decorator this is easy as CDI makes that exact bean injectable via the @Decorated qualifier. Here we'll have to do this manually. One way is to get all the beans of type HttpAuthenticationMechanism from the bean manager (this will include both alternatives and non-alternatives), filter ourselves from that set and then let the bean manager resolve the set to the one that would be chosen for injection. We then create a reference for that chosen bean.

The following shows this in code:

HttpAuthenticationMechanism mechanism =
    createRef(
        beanManager.resolve(
            beanManager.getBeans(HttpAuthenticationMechanism.class)
                       .stream()
                       .filter(e -> !e.getBeanClass().equals(ApplicationInit.class))
                       .collect(toSet())), 
            beanManager);

 

With createRef being defined as:

HttpAuthenticationMechanism createRef(Bean<?> bean, BeanManager beanManager) {
    return (HttpAuthenticationMechanism) 
        beanManager.getReference(
            bean, 
            HttpAuthenticationMechanism.class, 
            beanManager.createCreationalContext(bean));
}

 

We now have an instance to the bean to which we like to apply the interceptor binding. Unfortunately, there's a somewhat peculiar and very nasty note in the CDI spec regarding the method that creates a proxy with the required interceptor attached:

If the provided instance is an internal container construct (such as client proxy), non-portable behavior results.

Since the HttpAuthenticationMechanism is a client proxy (it's application scoped by spec definition) we have no choice but to introduce some extra ceremony here and that's by providing a wrapper ourselves. The interceptor will be applied to the wrapper then, and the wrapper will delegate to the actual HttpAuthenticationMechanism instance:

 

HttpAuthenticationMechanismWrapper wrapper = 
    new HttpAuthenticationMechanismWrapper(mechanism);

 

Having our HttpAuthenticationMechanism instance ready, we can now dynamically configure an annotation instance. Such instance can be created via CDI's provided AnnotationLiteral helper type:

interceptionFactory.configure().add(
    new RememberMeAnnotationLiteral(
        86400, "",       // cookieMaxAgeSeconds
        false, "",       // cookieSecureOnly
        true, "",        // cookieHttpOnly
        "JREMEMBERMEID", // cookieName
        true, ""         // isRememberMe
    )
);

 

Finally, we create the above mentioned new proxy with the configured interceptor binding applied to it using the interception factory's createInterceptedInstance method and return this from our producer method:

return interceptionFactory.createInterceptedInstance(
    new HttpAuthenticationMechanismWrapper(wrapper));

 

A full example can be found in the Java EE 8 samples project.

Note that there's a small caveat here; if the Interceptor needs access to the interceptor bindings (which is almost always the case when the binding has attributes), you can't just inspect the target type as one would usually do in CDI 1.2 and earlier code. The interceptor binding annotation is not physically present on the type. At the moment it's not entirely clear how to obtain these in a portable way. The interceptors in the Java EE Security RI (Soteria) uses an RI specific way for now.

The example was tested on Payara Server 5, of which a snapshot can be downloaded from the snapshot repository. An initial alpha will be released very soon, but in the mean time the latest version can be downloaded here:
payara-5.0.0.173-SNAPSHOT.zip.

Arjan Tijms

Thursday, August 17, 2017

Extensionless URLs with JSF 2.3

An extensionless URL is a URL without a final suffix like .xhtml, .html, .jsp, etc. Such a suffix is seen as technical "clutter" that's hard to remember for humans. Servers often need it though to route a request to the right controller.

JSF, a Java EE MVC framework, has supported extensionless URLs for some time via PrettyFaces (now merged to the general Rewrite framework) and OmniFaces. Both of these solutions used various workarounds to trick JSF into working with extensionless URLs.

Though JSF 2.3 does, unfortunately, still not support extensionless URLs fully out of the box via e.g. a single parameter, it can provide support for it by basically combining the new support for exact mapping and the API for obtaining a list of all view resources. Additionally combining this with the Servlet 3.1 feature for dynamically adding Servlet mappings and some JDK8 streaming and lambdas, makes it possible to enable extensionless support with just 2 statements (albeit somewhat long statements):

@WebListener
public class MappingInit implements ServletContextListener {
    
    @Override
    public void contextInitialized(ServletContextEvent sce) {
        FacesContext context = FacesContext.getCurrentInstance();
        
        sce.getServletContext()
           .getServletRegistrations()
           .values()
           .stream()
           .filter(e -> e.getClassName().equals(FacesServlet.class.getName()))
           .findAny()
           .ifPresent(
               reg -> context.getApplication()
                             .getViewHandler()
                             .getViews(context, "/", RETURN_AS_MINIMAL_IMPLICIT_OUTCOME)
                             .forEach(e -> reg.addMapping(e)));
    }
}

What the above code does is finding the existing FacesServlet, then getting all views for the entire application in a form that happens to be exactly suitable for extensionless URLs, and then adding each of them as mapping to the FacesServlet we previously found.

After adding the above shown WebListener to an application, its view can be requested via URLs like example.com/login, example.com/users/all etc.

The example was tested on Payara Server 5, of which a snapshot can be downloaded from the snapshot repository. An initial alpha will be released very soon, but in the mean time the latest version can be downloaded here:
payara-5.0.0.173-SNAPSHOT.zip.

Arjan Tijms

Tuesday, August 15, 2017

Dynamic beans in CDI 2.0

A while ago we wrote about CDIs ability to dynamically add Bean<T> instances to the CDI runtime.

A Bean<T> is a kind of factory for beans, that makes types available for injection, lookup via the bean manager, or by referencing them in expression language. CDI producers (via the @Produces annotation) fulfil a somewhat similar role, but they essentially only make the "create instance" method dynamic; the rest (like scope, types, etc) is more or less static. A programmatically added Bean<T> essentially makes all those aspects dynamic.

As the previous article showed, dynamically adding such Bean<T> is a bit more work and it's quite verbose, as well as a little complex as the developer has to find out what to return as a default for various methods that are not directly of interest.

CDI 2.0 has addressed some of the above issues by providing a very convenient builder that not only makes creating a Bean<T> instance far less verbose, but also takes away most of the guesswork. The following shows an example:

public class CdiExtension implements Extension {

    public void afterBean(final @Observes AfterBeanDiscovery afterBeanDiscovery) {
        afterBeanDiscovery
            .addBean()
            .scope(ApplicationScoped.class)
            .types(MyBean.class)
            .id("Created by " + CdiExtension.class)
            .createWith(e -> new MyBeanImpl("Hi!"));
    }
}

The above makes a bean available for injection into MyBean injection points and with the @ApplicationScoped scope, backed by a MyBeanImpl class.

A fully working example is provided in the Java EE 8 Samples project.

The example was tested on Payara Server 5, of which a snapshot can be downloaded from the snapshot repository. An initial alpha will be released very soon, but in the mean time the latest version can be downloaded here:
payara-5.0.0.173-SNAPSHOT.zip.

Arjan Tijms