Sunday, March 23, 2014

Review of Java EE and HTML5 Enterprise Application Development

I recently had the pleasure of reading through the book Java EE and HTML5 Enterprise Application Development by John Brock, Arun Gupta and Geertjan Wielenga.

First, a comment on file formats.  I use Linux at home.  I had the most trouble trying to get setup to actually read the book.  The format used is only compatible with Adobe Digital Editions, which only works on Mac and Windows.  I ended up getting a VM to do the reading on.  Little bit of a pain if you're like me and use a tablet for a decent amount of reading.

The book takes the approach of wanting to build HTML5 applications, leveraging the Java server side as an API type server, with both REST APIs and WebSockets in use, and a front end based on Knockout and low level jQuery to process API calls.  The backend is using your stereotypical Java EE stack of JPA, EJB and JAX-RS, plus WebSocket support.  The way used in this book serves as an entry point for someone new to a lot of the technology and how to use them; it doesn't focus on changes over time in these specs or some of the new features.  It's a bottom up approach for being able to expose your database over an API.

Probably the most confusing part of the book, and it may be because of different authors, is the crossing of example types.  In the JPA and JAX-RS chapters, we use a book and author example.  In the WebSocket chapter the authors use a board and tic tac toe example.  I believe the consistent use of a fluid example is the best thing to do in a technical book.  A good example of that is Continuous Enterprise Development by Andrew Lee Rubinger and Aslak Knutsen.

The chapter on application security is probably the best of the book, in my opinion.  It goes through what you need to do not just server side but also client side to secure your web applications.  For those new to this programming paradigm, it's some good information on some of the key differences versus traditional server side rendered web applications (JSF, Struts, etc).

The content of the book is brought about in an introductory manner.  If you're new to these technologies, it's a good read to get up to speed on how they work.  The JPA spec has only changed a little bit in 2.0 and 2.1, so if you're already familiar with how things worked previously, it's not a huge change.  JAX-RS is a newer spec, in its 2.0 release already and shows how declarative it can be.  Hidden in the REST chapter you'll find some interesting pieces on CDI, Transactions and Bean Validation.  These other technologies really help build the bridge across all of the technology.

Wednesday, February 26, 2014

Announcing Hammock

I'd like to introduce the world to Hammock

Hammock is based on my last blog post, creating a light weight service to run JAX-RS resources over a minimalistic configuration.

Binaries are currently up on Sonatype OSS (I hope they sync to MVN central shortly): https://oss.sonatype.org/index.html#nexus-search;quick~ws.ament.hammock

Github: https://github.com/johnament/hammock

What is Hammock?

Hammock is a light weight integration between JBoss RestEasy, Undertow and Weld.  Leveraging Weld SE, it provides automatic resource scanning and minimal binding code to launch a web container (Undertow) running the basic services to launch a full JAX-RS application.

Getting Started

Getting started with Hammock is simple.  Add a reference to the project in your pom.xml:


  ws.ament.hammock
  hammock-core
  0.0.1


Add your REST Resource class:

@Path("/echo")
@RequestScoped
public class EchoResource {
    @GET
    @Produces("text/plain")
    public String greet() {
        return "hello";
    }
}

Implement the configuration, for application (via @ApplicationConfig)

@ApplicationConfig
@ApplicationScoped
public class ApplicationConfigBean implements WebServerConfiguration {
    @Override
    public int getPort() {
        return 8080;
    }
    @Override
    public String getContextRoot() {
        return "/api";
    }
    @Override
    public Collection getProviderClasses() {
        return Collections.EMPTY_LIST;
    }
    @Override
    public Collection getResourceClasses() {
        return Collections.singleton(EchoResource.class);
    }
    @Override
    public String getBindAddress() {
        return "0.0.0.0";
    }
}

You can optionally also do this for a management interface as well (via @ManagementConfig).  The resources tied to each of these configurations would then be launched when you start your application.

Starting your app can be done manually via Weld SE, or by using their built in class, org.jboss.weld.environment.se.StartMain .

Sunday, January 19, 2014

Bridging Netty, RestEasy and Weld

As you likely know, RestEasy already supports an embedded container for Netty.  RestEasy also supports CDI injection, but only for enterprise use cases (e.g. part of the Java EE spec or using Weld Servlet).  In the case of Netty, it's almost possible, except that the lack of a ServletContext seems to throw it off.

In addition, in many use cases you may want to translate each incoming request into a CDI RequestScope.  This requires some custom handling of each request, before passing it down to RestEasy for processing.  This allows you to properly scope all of your objects, though you cannot use a session scoped object (since there would be no active session).

The code is pretty simple to do this.  You can find details on my github repository: https://github.com/johnament/resteasy-netty-cdi

First, define your endpoint.  In my test case, I added a very simple one:

@Path("/")
@RequestScoped
public class TestEndpoint {
    @GET
    public String echo() {
        return "pong";
    }
}

Next, we need some code to initialize the server.  I added this directly in my test, but I would imagine most people would want to initialize it elsewhere.

CDINettyJaxrsServer netty = new CDINettyJaxrsServer();
        ResteasyDeployment rd = new ResteasyDeployment();
        rd.setActualResourceClasses(paths.getResources());
        rd.setInjectorFactoryClass(CdiInjectorFactory.class.getName());
        netty.setDeployment(rd);
        netty.setPort(8087);
        netty.setRootResourcePath("");
        netty.setSecurityDomain(null);
        netty.start();

As you can see in the test, I am using a custom CdiNettyJaxrsServer, which is what enables me for CDI integration.  The only thing different about mine versus the normal one is what RequestDispatcher I use.  The RequestDispatcher is what RestEasy provides to handle the incoming requests and what the response looks like.  It's very low level.  I decided this was the exact point I wanted to start the CDI RequestScope.  So my RequestDispatcher looks like this

public class CDIRequestDispatcher extends RequestDispatcher
{
    public CDIRequestDispatcher(SynchronousDispatcher dispatcher, ResteasyProviderFactory providerFactory,
                                SecurityDomain domain) {
        super(dispatcher,providerFactory,domain);
    }
    public void service(HttpRequest request, HttpResponse response, boolean handleNotFound) throws IOException
    {
        BoundRequestContext requestContext = CDI.current().select(BoundRequestContext.class).get();
        Map<String,Object> requestMap = new HashMap<String,Object>();
        requestContext.associate(requestMap);
        requestContext.activate();
        try {
            super.service(request,response,handleNotFound);
        }
        finally {
            requestContext.invalidate();
            requestContext.deactivate();
            requestContext.dissociate(requestMap);
        }
    }
}

So whenever a request comes in, I start the context (using Weld's BoundRequestContext) and on completion I end it.  I also created a custom CdiInjectorFactory for Netty.  This alleviates a bug in the base one that depends on a ServletContext being available (throughs a NullPointerException).  It's just a simplified version of the injector factory

    protected BeanManager lookupBeanManager()
    {
        BeanManager beanManager = null;
        beanManager = lookupBeanManagerCDIUtil();
        if(beanManager != null)
        {
            log.debug("Found BeanManager via CDI Util");
            return beanManager;
        }
        throw new RuntimeException("Unable to lookup BeanManager.");
    }

You'll also notice in my test code I'm using a CDI Extension - LoadPathsExtension.  This simply sits on the classpath and listens as Weld initializes.

LoadPathsExtension paths = CDI.current().select(LoadPathsExtension.class).get();

For each ProcessAnnotatedType it observes, it checks if Path is present.  If Path is present, it adds it to a local list of all resources.

public void checkForPath(@Observes ProcessAnnotatedType pat) {
        if(pat.getAnnotatedType().isAnnotationPresent(Path.class)) {
            logger.info("Discovered resource "+pat.getAnnotatedType().getJavaClass());
            resources.add(pat.getAnnotatedType().getJavaClass());
        }
    }

This makes scanning for Paths possible, which is done by the container for RestEasy.  In the Netty deployment, you need to always maintain your list of resources.

LoadPathsExtension paths = CDI.current().select(LoadPathsExtension.class).get();
        CDINettyJaxrsServer netty = new CDINettyJaxrsServer();
        ResteasyDeployment rd = new ResteasyDeployment();
        rd.setActualResourceClasses(paths.getResources());

Finally, we start the actual test which uses the JAX-RS client API to make a request to a specific resource.

        Client c = ClientBuilder.newClient();
        String result = c.target("http://localhost:8087").path("/").request("text/plain").accept("text/plain").get(String.class);
        Assert.assertEquals("pong", result);