Home > Development > features
Anatomy of an Enterprise Flex RIA Part 3: The Project's Structure
Last installment we looked at the sample project we'll be discussing throughout the series. Now we're going to have a look at J2EE project structures and how Maven works with them.
Our project is intended to be deployed to a web platform. There is a Java specification for a deployable web application of this type, called a web archive. The deployment “artifact” is a ZIP file with a .war extension, so we call these archives WAR files. A WAR file has a certain structure with some specifications on a file called a deployment descriptor, named web.xml.
Figure 1 shows a sample web archive structure. The root of the archive is treated as the root of the web application, so any .html or other assets can go here—in this case, index.html. Also in the root is WEB-INF, which contains important files that won’t be available to a web user through the browser. WEB-INF contains a directory called classes, which is the root of the classpath of the Java classes available to the application. Also alongside classes is lib, which contains Java libraries that are added to the classpath from JARs. web.xml goes in the root of WEB-INF and tells the container (server) how to deploy the application.
Our project will be using EJB 3.0 as the persistence layer. The resources that make up the persistence part of the project will be packaged separately as a JAR, a regular Java archive. Theoretically, a persistence unit could be packaged with any number of applications that need to manage data in the same domain, which is why it’s kept in its own artifact. A persistence unit has a specified structure and descriptor file as well, called persistence.xml (see Figure 2).
A persistence unit is fairly simple inside. The package structure goes in the root alongside META-INF, which contains the descriptor file, persistence.xml.
We will deal with the data persistence part of our code as a separate project and have a separate artifact from the web part of the project. There is another type of specification for a type of archive that holds other archives. This is the Java Enterprise Edition (Java EE) specification for enterprise archives. This type of file is another .zip file, and it has an .ear extension and usually contains only the other archives in the root of the archive. So, we’ll put our .war and our .jar in our .ear for deployment. (I know, it sounds funny. Somebody on these specification committees must have had a sense of humor.) Figure 3 shows an example enterprise archive.
An enterprise archive is the simplest archive in terms of number of files. Typically, the root contains web archives. Sometimes JARs go in the root for inclusion in the classpath on the server. They could go in a separate lib directory if we wanted them to; it doesn’t matter because we can configure that in application.xml. By the way, application.xml goes in META-INF and describes how to load the other included artifacts.
The point of having these arcane specifications for archived files is that you can keep these separate projects by themselves during development, and then have a build tool produce the separate artifacts and combine them into one file which is a self-contained enterprise application with its own deployment instructions inside. This is much more convenient for someone who has to actually deploy these things to a production environment. Separate projects make development easier for developers with different tasks, and a single artifact makes deployment as easy as possible.
One thing to note: you can deploy WAR and EAR archives in their ZIPped, single-file form, or together as an unzipped directory. When deployed unzipped, they’re sometimes referred to as being exploded. In development environments, these archives are generally deployed in an exploded form to a local server. Our development Ant tasks will do that for us, as well as keep compiled resources in sync.
Maven Projects
Inside src is a directory for the main source of the project, called main. At the same level is a folder for test code, called test. The code goes in the main and test directories and is organized by the type of language—in this case, a java directory holds the Java code in the data project directory, and a java and flex directory in the web project. Maven is a code project management tool as well as a build automation tool. Maven has some opinions about how projects of the type we’re working with should be structured. Although all of the defaults can be configured separately, because we’re starting a new project I’ve followed Maven’s conventions, and you can see how they make sense.Just as Ant has a build file to describe the tasks that control our build, Maven has a file that lets developers describe and configure each project. This file is called pom.xml. POM stands for Project Object Model. Maven has an idea of a set of locations, variables, and steps in the build process that generalize all projects.
The pom.xml descriptor tells Maven some important settings for the project. First, it identifies the project with a name and other attributes. Then it could do one of many other things, such as configure certain plug-ins that work with Maven—for instance, the compiler plug-in, the testing plug-in, and so on.
Maven also has an extremely powerful dependency management feature. When Maven reads from the POM the list of dependencies, or libraries, that our project relies on, it downloads those libraries from a local repository, which is usually in a directory called .m2 and located in your home directory.
If it can’t find the library there, it downloads the library from any of a list of known repositories on the Web. It can read this list from a descriptor called settings.xml in your .m2 directory.
You may require a little explanation to understand just how powerful this feature is. If you’ve ever gone “JAR hunting” in Java, you know what I mean already. Let’s say our project needs a set of classes from Library A. That library depends on a certain version of Library B. Library B depends on Libraries C, D, and E. There’s no standard way to let you know that, so you have to hope that Libraries A and B have good documentation and tell you that they depend on these other libraries, and even if you’re lucky and they do tell you, you still have to hunt down all these projects and download the artifacts before you can compile your project. Otherwise, Java will complain.
All you’d need to do if you were using Maven, however, is to say that your project depended on “A”, and you’d be done, given the fact that “B”, “C”, “D”, and “E” all made Maven-friendly artifacts and had them posted to the standard Maven repositories. Luckily, most libraries you run into out there do just that.
If not, you can either put the libraries in Maven form in your local repository and share them with all the developers on your project, or use one of the proxy server solutions out there to run your own local Maven repository for your team.
We’re going to have work on projects from Maven’s point of view. One project will build the EJB 3.0 persistence unit, another will build the web archive with Flex and LCDS integrated, a third will build an .ear file to contain these two artifacts, and the fourth will act as a parent project to the other three. The following code shows the parent project’s POM and some of the customization we need to do to tell Maven where things are:
<project ...>
<modelVersion>4.0.0</modelVersion>
<groupId>lcds.examples.bookie</groupId>
<artifactId>bookieProject</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>pom</packaging>
<name>Bookie Example Parent Project</name>
<modules>
<module>bookie-data</module>
<module>bookie-ui</module>
<module>bookie-ear</module>
</modules>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.5</source>
<target>1.5</target>
</configuration>
</plugin>
</plugins>
</build>
</project>
First, modelVersion says to which version of the POM XML this document is written. It’s there in case some of Maven’s POM syntax or settings change later.
The next three attributes are the most important. In fact, they’re all a POM really needs to have to identify this project from other Maven projects.
groupId is a unique identifier for the group that’s building the project. This usually ends up being the company’s URL, but it may be something else unique to the company or organization. This identifier could span projects built by this group.
artifactId is the unique identifier for the project. In this case, the parent project is called bookieProject.
Next comes version, which is the version of the project and could be anything, but should be the major version or revision this project is building toward. If the version of the artifact this project produced was 4.1, that would go here. A Maven convention for cases when the project is unreleased and working toward Version 1 is to use 1.0-SNAPSHOT, which means that no version has been released yet and a lot of changes are happening; too many to pin down a version.
Maven uses these “big three” attributes to build artifacts. If the project produced a JAR file, the JAR file would be called <project name>.<version number>.jar and it would be placed in Maven repositories under a directory structure matching the groupId, artifactId, and version. For example, Figure 4 shows the repository structure for the MySQL drivers.
This is straight out of my local Maven repository, but of course, it mirrors the structure found on any Maven repository on the Web. For the MySQL library, the groupId is mysql and the artifactId is mysql-connector-java; in addition, three versions are shown: 3.1.12, 5.0.3, and 5.0.5. Notice also that the JAR is named in the form mentioned earlier, and that the project’s POM is stored here as well, alongside some hash files to make sure the files were downloaded without a glitch.
The POM file is stored in the repositories so that, among other things, Maven can check whether this library has any dependencies that it needs to get. The automated checking and downloading of all these dependencies up the chain, based on just a few configuration settings, is worth the price of admission alone.
Back to the parent POM, the packaging setting tells Maven how to package the project. In this case, in the parent project there is no artifact, so the packaging is pom, which means that we expect to have other projects in directories below this one. Those other projects are listed in the modules section under the name setting. We’ll see the POMs for the data and ui projects at the beginning of each of their respective sections, and the ear project’s POM in a bit.
After the modules section is a build section. This configures the build part of Maven’s project life cycle. Basically, we’re telling Maven to configure the compiler plug-in, which compiles Java, to consider source files to be 1.5 and to compile to Version 1.5 of Java. Because we configure this at the parent project’s setting, Maven keeps this setting for the Java compilation in each child project too.
Next installment we'll continue looking at how Maven projects are organized. You can always find the entire series here.






Is there an RSS feed specifically for this series?
You can find this series via the author's Atom feed:
http://www.insideria.com/tony_hillerson/atom.xml
Or, you can find all development related content in the Development Atom feed:
http://www.insideria.com/development/atom.xml
this series is sick. i am anticipating the fourth part like it is my first born. so boys, how bout daily posts?
Was there any particular reason you chose Flex/EJB3 over a Flex/Spring/Hib. stack?
@John - I chose EJB3 because I really liked the annotation style of describing the persistence layer instead of the separate xml descriptor style.
As you know, Hibernate annotations and EJB3 are similar. A lot of what I cover could be used with Sprint/Hibernate, just replace the persistence code with your preferred method. A good exercise for the reader :)
@Tony
ahhh, convention over configuration. Thanks for satisfying my curiosity.
Hi, I´ve extended the HibernateAssembler to avoid write xml mapping configuration files and use Hibernate/EJB3 annotations, I´ve called it AnnotationHibernateAssembler, it was very easy, need only to override one method, you can see here: http://tecav.blogspot.com
Saludos!