Modern enterprise applications are built using several components connected to one another, each providing a specific functionality. Components that perform similar functions are generally grouped into layers. These layers are further organized as a stack where components in a higher layer use the services of components in a lower layer. A component in a given layer will generally use the functionality of other components in its own layer or the layers below it. The diagram below shows a popular layer structure for an enterprise application.
Note that layers are simply logical groupings of components that make up an application. How these layers are actually deployed on physical machines, however, can vary widely depending on several factors. In the simplest case, all the layers can reside on one machine. In a slightly more complex scenario, the presentation layer can reside on one machine, the business and data access layers on a second machine, and the database on a third machine. More elaborate scenarios are possible; for example, a high traffic web site can deploy the presentation layer on a web farm consisting of tens of machines.
Now that we understand the basic concepts behind modern enterprise applications, let's discuss how AndroMDA implements these concepts. AndroMDA takes as its input a business model specified in the Unified Modeling Language (UML) and generates significant portions of the layers needed to build a Java application. AndroMDA's ability to automatically translate high-level business specifications into production quality code results in significant time savings when implementing Java applications. The diagram below maps various application layers to Java technologies supported by AndroMDA.
In addition to the concepts discussed previously, it is important to understand how data propagates between various layers of an application. Follow along the diagram above as we start from the bottom up.
As you know, relational databases store data as records in tables. The data access layer fetches these records from the database and transforms them into objects that represent entities in the business domain. Hence, these objects are called business entities.
Going one level up, the data access layer passes the entities to the business layer where business logic is performed.
The last thing to discuss is the propagation of data between the business layer and the presentation layer, for which there are two schools of thought. Some people recommend that the presentation layer should be given direct access to business entities. Others recommend just the opposite, i.e. business entities should be off limits to the presentation layer and that the business layer should package necessary information into so-called "value objects" and transfer these value objects to the presentation layer. Let's look at the pros and cons of these two approaches.
The first approach (entities only, no value objects) is simpler to implement. You do not have to create value objects or write any code to transfer information between entities and value objects. In fact, this approach will probably work well for simple, small applications where the the presentation layer and the service layer run on the same machine. However, this approach does not scale well for larger and more complex applications. Here's why:
Value objects provide a solution for all these problems. Yes, they require you to write a little extra code; but in return, you get a bullet-proof business layer that communicates efficiently with the presentation layer. You can think of a value object as a controlled view into one or more entities relevant to your client application. Note that AndroMDA provides some basic support for translation between entities and value objects, as you will see in the tutorial.
Another key concept of AndroMDA-generated applications is the strong association between service methods (i.e., operations exposed by a service) and Hibernate sessions. But before we introduce this concept, we must lay out some ground work. The Hibernate session is a runtime object that allows an application to create, read, update and delete entities in the data store. As long as the session is "open", these entities are attached to the session and you can navigate from one entity to another using relationships between them. If a related entity is not yet in memory, Hibernate will automatically pull it in for you (this is called "lazy loading"). However as soon you close the Hibernate session, the entities that exist in memory are considered to be "detached"; i.e. Hibernate no longer knows about them. You are free to hold references to such entities, but Hibernate will no longer pull in associated entities if they don't exist in memory already. If you accidentally try to access such associated entities, you will get a Hibernate LazyInitializationException.
Now that we understand this background material, let us discuss the relationship between a service method and a Hibernate session. When a client application calls a service method, a new Hibernate session is opened automatically -- you do not have to write any code to do this. Similarly, when the service method exits, the associated Hibernate session is closed automatically. In other words, the lifespan of a Hibernate session is bounded by the beginning and ending of a service method call. Consequently, entities are attached to Hibernate session for the entire duration of the service call, but are detached from this session as soon as the service call ends. As a result, if your service method returns raw entities, the client must be extra careful not to access related entities that are not in memory already. You can avoid all this mess by following the recommendation in the earlier section; that is, transfer all relevant information into value objects while the session is still open, and pass these value objects back to your caller as a return value. In general, think of a service method as a logical transactional boundary - do everything you need to do within the method and then return the results as value objects.
Another implication of the strong association between a service method and a Hibernate session is that client applications should not try to bypass the service layer and interact directly with the lower layers. You may be able to brute force your way into one data access object, but sooner or later you will get into trouble!
Now that you understand the basic tenets of AndroMDA, let's describe the sample application we will implement in this tutorial. Click here to get started.