Tuesday, August 24, 2010

Untangling Java EE 6 - a broad conceptual overview

WARNING

This document was written by someone who's only learning Java EE 6. On one hand, I remember the frustrations clearly and still encounter issues of understanding (and bugs) regularly, so I'm in a good position to think about how a newbie needs to have things explained. On the other hand, a bunch of this is probably wrong because my own understanding is still developing. Beware.

This is also a work in progress. It's been published for comment and review, and isn't a fully edited and checked final work.

If you're coming from Spring, rather than starting with Java EE cold, you should start here.

Java EE 6

Java EE 6 is not a product you can download and install. It is a specification that describes how implementing software should behave. It refers to many sub-specifications for particular features, each of which has one or more implementations in software. Some of these implementations can be used outside a full Java EE 6 environment as standalone products.

There are a few different application servers availible that provide full Java EE 6 environments by collecting and integrating the implementations of the various Java EE 6 components into a product. These products have their own features, administration tools, etc as well as support for the Java EE 6 spec.

Unsurprisingy, when you are trying to get a handle on how it all works, it's very confusing. The fact that most Java EE 6 documentation and tutorials refer to Java EE 5 with the assumption that you're an existing Java EE 5 user upgrading to Java EE 6 doesn't help.

Here I'll try to provide an overview of how it all fits together, helping you decode the names and figure out what's what.

Java EE 6 isn't a downloadable, installable product

The first thing to understand is that Java EE 6 isn't a piece of software. It's a client interface specification (API) describing what services an environment (the "container" or application server) provides to software running within that environment, and how those services should behave. It's also a server specification that partly specifies now those services should work and what they should do.

Consequently, you can't "install" Java EE 6, you can only install an implementation of it like an application server.

There is one piece of concrete code for Java EE 6: the API JARs. The Java EE 6 api and Java EE 6 Web Profile API jars contain Java interfaces that let you compile code to use Java EE 6 services and features. They do not contain implementations of those features, and do not require a particular implementation; that's the job of the particular Java EE 6 container/app server you use.

The parts of the Java EE 6 spec

As already noted, the Java EE 6 spec is composed of many parts.Some of them will be familiar, like JavaMail and JDBC, while others like EJB 3.1, CDI, JNDI and JAX-RS will be unfamiliar to you. Java SE is availible in the Java EE environment, so most of what you are used to in Java SE should remain unchanged, but the way you use it is completely different.

There is a list of the technologies used in Java EE 6 here:
http://www.oracle.com/technetwork/java/javaee/tech/index.html
Most of those technologies can be used outside a full Java EE 6 environment, and were developed as individual specifications under the Java Community Process (JCP), usually alongside a reference implementation of the specification being developed.

Application servers (containers) that support the Java EE 6 spec promise to provide implementations of all the various sub-specs in Java EE 6 for an application's use.

Application servers and containers

Application servers like Glassfish and JBoss AS implement the Java EE 6 spec, providing applications with a managed container they can run in to use all the Java EE 6 services. You can think of the container as a lot like the operating system and JVM a Java SE applicatoin runs within - it's outside the application, but provides services and facilities that enable the application to work.

The app server takes responsibility for making the spec's requirements happen, so user code just has to use the Java EE 6 interfaces.

There are also containers like Tomcat and Jetty that do not implement the full Java EE 6 spec. It is possible to use most of the technologies used by Java EE 6 within such containers by installing implementations of them in the container or bundling them with your application. This is why you will see references to using Tomcat or Jetty with technologies like JSF2 that are also part of Java EE 6.

The vendor of a full Java EE 6 applicaton server like Glassfish or JBoss AS application server vendor doesn't implement all of Java EE 6 directly either. Most of the Java EE 6 implementation provided by an app server is in separate products bundled with the server to provide an implementation of each individual Java EE 6 sub-spec. The server vendor chooses the implementation to use for each sub-spec, and provides the code to load them and integrate them into the full environment. Some specs (like EJB 3.1) will be implemented directly by the server vendor and won't be a separate product or package, though they'll generally still be a module within the application server.

For example, Glassfish 3 (an application server) supports java EE 6 (the spec), including support for CDI (a sub-spec) using JBoss Weld (an implementation of the CDI spec). Glassfish also supports EJB 3.1 (another sub-spec) as a core part of the Glassfish server, rather than via 3rd party code.

You will have noticed that Glassfish uses a component, JBoss Weld, from a competing application server vendor. That's commonplace, so you shouldn't assume that because a component was developed by Oracle, Apache, JBoss, etc it's only used in their application server.

A list of servers, specs, and implementations of those specs can be found at the end of this article.

Using Java EE 6 in applications

Applications written for Java EE 6 are compiled and bundled into a package (an ejb jar, a war, or an ear file: see later) that is deployed to the application server. Deployment involves loading the application archive after copying it to the server if required, scanning it for deployment descriptors like web.xml, and setting it up in the container's environment so it can be accessed. Depending on the application, that might involve enabling web service listeners, adding servlets to the container's HTTP namespace, etc.

Applications do not have to use all the features of Java EE 6, and can choose to only "see" features they use. Instead of having the full Java EE 6 API JARs on the compile-time classpath, they can include only the API JARs for the sub-specs they want to use. For example, an application might choose to use the Servlet API and the JPA 2.0 API, but not bother with the EJB 3.1 API or JavaServer Faces. To do that, it omits the full Java EE 6 API JARs from the classpath, and instead includes the API JARs for the sub-specs of interest. You will see this a lot in example code - for example, JavaServer Faces (JSF) projects often use the JSF API and Servlet API jars rather than the Java EE 6 API jars.

Even if you include the full JAva EE 6 API JARs, many features won't affect you (or activate at all) unless you use them by putting their annotations in your code, configuring them in web.xml, etc.

Because you don't have to use all of Java EE 6, it's quite possible to build an application that'll deploy and run in regular containers as well as full Java EE 6 application servers. Such an application generally requires additional software to be installed in the non-EE container to support the features it needs, or has to bundle the implementations with the application.

Java EE 6 can be extended

Just as you don't have to use all of Java EE 6 in applications, it's common to add additional components to extend the capabilities of the application server. Some of these components are regular class libraries, but some of them are container components that use servlet filters or other EE features to extend the capabilities of the container its self.

For example, instead of using the Java EE 6 standard web interface toolkit, it's fairly common to use one of the innumerable other toolkits like Wicket, Tapestry, Struts, etc instead, while still running within a Java EE 6 application server container.

It's also common to include extensions to Java EE 6 functionality. For example, there are JSF 2.0 extensions like RichFaces and PrimeFaces that add new features and new components to the existing JSF 2.0 implementation.

One key extension is SeamFaces, which seeks to address some of the more painful limitations of JSF2, like the inability to inject resources into a @FacesConverter. SeamFaces is a work in progress and wasn't at release quality at time of writing; see the project page for details on its status.

Pitfalls

There are some holes in the current Java EE 6 spec, and some areas of confusion where the required behaviour isn't particularly clear. These will be discussed in detail in separate documents.

  • @FacesConverter can't be a managed bean and isn't subject to injection. See SeamFaces (above).
  • Multiple dependency injection implementations exist in the core spec.
    • JSF2 provides basic dependency injection support, liftime and scoping, EL naming, etc. These live in the javax.faces.bean package.
    • The CDI spec provides a more complete dependency injection (@Inject), lifetime and scoping, and EL naming system using different facilities that *mostly* interoperate with JSF2's. The annotations live in the javax.enterprise.context and javax.enterprise.inject packages.
    • EJB 3 has its own injection via @javax.ejb.EJB
    The JSF2 features are not clearly deprecated and it's not always clear how they will interact with CDI or old-style EJB interaction. A separate document will discuss CDI and JSF2 injection and scoping.

There are also a few things that, while not JSF issues as such, are likely to bite you if you don't know about them, and aren't particularly well documented:

  • @PersistenceContext(type=PersistenceContextType.EXTENDED), ie an extended persistence context, can only be used within a @Stateful session bean. In other contexts, like a POJO, you'll get odd errors from within the runtime, like (in Glassfish 3) a NullPointerException from com.sun.enterprise.container.common.impl.EntityManagerWrapper.

Thinking Java EE 6

There are some really big differences between how a Java EE 6 application is constructed and how a Java SE application is constructed. Many of these stem from the container-managed nature of Java EE, where you provide a set of interacting components that run in the container, rather than a whole "program" with dedicated flow control from start to finish. Adapting to Java EE is a lot like adapting to event-driven programming for someone used to the imperative programming model - it's brain-bending, but worth it. You have to relax the idea that you dedicate the flow of execution through your code, and instead get used to providing a set of services that interact via events, messages, and the actions of client code.

Even object lifetimes and object instantiation are largely out of your hands. Most of your objects will be container-managed, with lifetime and scope controlled by the container and linked to the user request or session. The objects they interact with will be injected, rather than obtained from a factory or directly created. It's the container that's responsible for selecting or creating an instance of an object to inject, not your code.

You will hear terms like "dependency injection" and "inversion of control" thrown about, but they won't mean much to you until you start using Java EE in practice. Once you wrap your brain around it then, just like event-driven programming, it becomes an obvious and sensible way to do things and lets you just forget about problems you used to obsess about. Mostly, anyway.

Where to go from here

Start with the excellent Java EE 6 tutorial. Don't forget about the Java EE 6 API documentation and the other resources availible on Oracle's Java EE 6 page either.

It can be helpful to grab the spec for a given Java EE 6 technology from the JSRs linked from here.

There's a good tutorial on JavaServer Faces here. Avoid the JSF specification, as unlike most of the surprisingly well written JSR specs it's an unreadable monstrosity that will only confuse you.

Names and acronyms galore

One of the big challenges of understanding Java EE 6 is figuring out what all the names, acronyms and code annotations mean and how the inter-relate.

This short guide will attempt to untangle things for you. (It's currently very incomplete, though, and should probably move to a separate post.)

Containers
- full Java EE 6 app servers
-- Glassfish 3
--- Uses Mojarra (JSF2 and JSP), Weld (CDI)
-- JBoss AS 6 (prerelease)
--- Uses Mojarra (JSF2 and JSP), Weld (CDI)
- Java EE 5 containers
-- Glassfish 2
-- JBoss AS 5
-- Geronimo (built on Tomcat / Jetty)
-- WebSphere
-- WebLogic
-- Etc etc. See wikipedia "comparison of application servers"
- non-EE applicatoin containers / servlet engines
-- Tomcat
-- Jetty

Technologies used in Java EE 6 with widespread competing implementations
- CDI
-- JBoss Weld (RI)
-- Apache OpenWebBeans
- JSF2
-- Mojarra (RI)
-- Apache MyFaces
- JPA2
-- Apache OpenJPA
-- Oracle TopLink Essentials
-- JBoss Hibernate 
-- EclipseLink

Commonly used add-ons
- JSF2 extensions and component libraries
-- RichFaces
-- IceFaces
-- PrimeFaces
-- PrettyFaces
- Non-JPA persistence
-- Direct use of JDBC
-- iBatis / MyBatis

Other names to place:
- Apache Felix (OSGi)
- JBoss Seam 2 and 3
- Spring

Other references
- Wikipedia "Java EE version history"

A separate post will be dedicated to associating commonly used EE annotations with the specifying JSRs and implementations of those JSRs. Things like @ManagedBean, @Named, @SessionScoped, @RequestScoped, @ApplicationScoped (both CDI and JSF versions), @Local, @Remote, @Stateless, @Stateful, @Singleton, @Inject, @Resource, @EJB, @PersistenceContext, etc. Particular attention needs to be paid to areas of overlapping functionality and the differences between the options: JSF scoped beans vs CDI scoped beans vs EJBs in lifetime management, for example.

2 comments:

  1. Fantastic article.......Thanks Craig .... this article cleared up a lot of terminology/spec relate confusion that i had about JEE6 ...

    ReplyDelete
  2. Fantastic article

    I just started learning Java EE 6 too, and it can be frustating because there are so many (sometimes seemingly unrelated) terms to know. But your article explains the concept in an easily understood way.

    Thanks man!!!

    ReplyDelete