Simulating CDI’s Session and Request Scope in a J2SE app

We’re currently considering refactoring the Naked Objects framework to use JSR-330 (dependency injection) and EE-oriented big brother, JSR-299 (CDI). Using vanilla JSR-330 is a no-brainer, but there are also some nice features in JSR-299 that we’d like to exploit (such as events and decorators). The snag? The Naked Objects must also run transparently in J2SE environments.

Now JSR-299 (at least, the Weld reference implementation) can run on J2SE, but it isn’t possible to use beans that are annotated as either @SessionScoped or @RequestScoped… not surprising really, because there is no HttpSession or HttpServletRequest to hook into. On the other hand, at least in the Naked Objects framework in a J2SE context, we do have the ability to map these concepts onto its own internal lifecycle … eg, for a client-side app, the user is always in deemed to be running in one long session.

How, then, to setup contexts for these scopes, and make them automatically active when running in J2SE?

First, let’s look at the code we want to run:

package org.nakedobjects.experiments.cdi;

import java.util.List;
import javax.enterprise.context.RequestScoped;
import javax.enterprise.event.Observes;
import org.jboss.weld.environment.se.bindings.Parameters;
import org.jboss.weld.environment.se.events.ContainerInitialized;

@RequestScoped
public class HelloWorld {
    public static void main(String[] args) {
        // bootstrap
        org.jboss.weld.environment.se.StartMain.main(new String[]{"JSR","299"});
    }
    public void printHello(@Observes ContainerInitialized event, @Parameters List<String> args) {
        System.out.println("Hello " + args);
        System.out.flush();
    }
}

Because this is a CDI bean, we need an empty META-INF/beans.xml.

The above class would print out “Hello [JSR, 299]” if annotated as @ApplicationScoped, but not with it being annotated as @RequestScoped. What we therefore need to do is write an extension. It’s a bit hacky, but it works:

package org.jboss.weld.manager; // required for visibility to BeanManagerImpl#getContexts()

import java.lang.annotation.Annotation;

import javax.enterprise.context.RequestScoped;
import javax.enterprise.context.SessionScoped;
import javax.enterprise.event.Observes;
import javax.enterprise.inject.spi.AfterDeploymentValidation;
import javax.enterprise.inject.spi.BeanManager;
import javax.enterprise.inject.spi.Extension;

import org.jboss.weld.context.AbstractThreadLocalMapContext;
import org.jboss.weld.context.beanstore.HashMapBeanStore;

public class WeldServletScopesSupportForSe implements Extension {

 public void afterDeployment(@Observes AfterDeploymentValidation event,
   BeanManager beanManager) {

  setContextActive(beanManager, SessionScoped.class);
  setContextActive(beanManager, RequestScoped.class);
 }

 private void setContextActive(BeanManager beanManager,
   Class<? extends Annotation> cls) {
  BeanManagerImpl beanManagerImpl = (BeanManagerImpl) beanManager;
  AbstractThreadLocalMapContext context = (AbstractThreadLocalMapContext) beanManagerImpl
    .getContexts().get(cls).get(0);
  context.setBeanStore(new HashMapBeanStore());
  context.setActive(true);
 }
}

Like all Weld extensions, this needs to be registered in META-INF/services, in this case in a file called javax.enterprise.inject.spi.Extension containing the fully-qualified class name.

Now, when we run the application, the session and request scopes will both be set up, and our HelloWorld bean will fire.

For developers writing apps in Naked Objects they will need to include a dependency to an additional module, if deploying a client (-t client or a server on a non-web backend (-t server with socket-level remoting, say). For the latter, we’ll need to include some smarts to figure out whether we are running in a webapp or not, and only set up the Contexts if we determine that we’re not (eg can’t find javax.servlet classes on the classpath.

If you want to try out the code, you can check it out using

svn co https://nakedobjects.svn.sourceforge.net/svnroot/nakedobjects/framework/trunk/experiments .

Reference: Simulating CDI’s Session and Request Scope in a J2SE app from our JCG partner Dan Haywood at the Dan Haywood blog.

Related Articles :

Related Whitepaper:

Functional Programming in Java: Harnessing the Power of Java 8 Lambda Expressions

Get ready to program in a whole new way!

Functional Programming in Java will help you quickly get on top of the new, essential Java 8 language features and the functional style that will change and improve your code. This short, targeted book will help you make the paradigm shift from the old imperative way to a less error-prone, more elegant, and concise coding style that’s also a breeze to parallelize. You’ll explore the syntax and semantics of lambda expressions, method and constructor references, and functional interfaces. You’ll design and write applications better using the new standards in Java 8 and the JDK.

Get it Now!  

Leave a Reply


seven + 4 =



Java Code Geeks and all content copyright © 2010-2014, Exelixis Media Ltd | Terms of Use | Privacy Policy
All trademarks and registered trademarks appearing on Java Code Geeks are the property of their respective owners.
Java is a trademark or registered trademark of Oracle Corporation in the United States and other countries.
Java Code Geeks is not connected to Oracle Corporation and is not sponsored by Oracle Corporation.

Sign up for our Newsletter

20,709 insiders are already enjoying weekly updates and complimentary whitepapers! Join them now to gain exclusive access to the latest news in the Java world, as well as insights about Android, Scala, Groovy and other related technologies.

As an extra bonus, by joining you will get our brand new e-books, published by Java Code Geeks and their JCG partners for your reading pleasure! Enter your info and stay on top of things,

  • Fresh trends
  • Cases and examples
  • Research and insights
  • Two complimentary e-books