Help is available by sending an email to csf-support@mit.edu
Have any suggestion on how improve this wiki?  Please give us your feedback at csf-support@mit.edu

Quick Links to:

Overview

The Education Systems framework for developing Java-based web applications can seem bewildering to a new developer. Indeed, some of us who have worked with the framework for a while still find ourselves scratching our heads from time to time. So I hope this document will serve as a place for newbies to come and learn about how we put web apps together, and also for old hands to remind themselves about some of the dusty, forgotten corners of the framework.

First things first - what is the architecture, design pattern, or structure we follow for our web apps? There's no pithy phrase that captures it all, but here are the essentials:

- Code is written in Java (6)
- JSPs are used for the front-end views
- Oracle database houses the data
- Spring MVC for the web layer
- Spring framework provides the app "container"
- Hibernate talks to the database

We use a fairly standard layered structure for the Java code in the web apps. Conceptually this structure is:
UI Layer -> Service Layer -> Data Access Layer

We also have a Domain component that contains data-holding objects. These domain objects can live in any of the other three layers and are typically passed up or down between the layers.

This diagram illustrates these layers:

Web App Java Layers

UI Layer

This layer consists mostly of Spring MVC Controllers, and is identified by the "web" package name in most of our web apps. Controllers are all about web input and output. They handle input from the user's browser (requests for retrieval of data, form submissions, etc), coordinate processing of the input requests, and send back information to the user's browser.

There should be no "business logic" or "business rules" implemented in a controller. Controllers will typically call services to do business logic.

Controllers should not use DAOs (see Data Access Later below) directly.

We use Spring's @Controller annotation to configure controllers as Spring beans. You may see some older controller classes configured as beans via XML, but new code should always use the annotation.

Note that we configure controllers with Spring's default "singleton" scope. This means that there is only one instance of the class in the web application; all users will use the same cached instance of the controller. We must therefore make sure that controllers are coded in a thread-safe way - no state should be kept in instance variables. In fact, instance variables should only be other Spring beans, injected by the Spring container.

Service Layer

This is where the business logic is implemented. Any code that implements a business function (e.g. "drop a class", "change a grade") should be in a service class.

Service classes should be configured as Spring beans using the @Service annotation.

Service classes should never call any UI Layer (controller) methods. They should also never have any logic that is related to the UI. If you find yourself thinking of writing a service method called "convertGradeDescriptionToHTML", a (imaginary!) warning bell should go off and you should place this code in the UI layer. One way to help think about this is to imagine the service being used in an app with a second non-web (i.e. non-HTML) interface - a REST interface perhaps, or a Swing interface. If there's something in your service code that would not apply to the second interface (our convertGradeDescriptionToHTML method for example), then this is a sign that the code shouldn't be in the service layer, but up in the appropriate UI layer.

As with the controller classes, services are configured as Spring singleton beans, so should be coded to be thread-safe.

All services are coded as an interface and an implementing class (e.g. RegistrationService for the interface, RegistrationServiceImpl for the class). This is helpful in unit testing of classes that use our service class (controllers, other services), allowing us to inject mock implementations of our service class into the class under test.

Data Access Layer

This is where the Data Access Objects (DAOs) live. A DAO's purpose is to provide a relatively fine-grained set of basic data operations (e.g. get data from the database, update data, etc.).

There should be no business logic or business rules in a DAO - just pure data access. Thinking about alternate DAO implementations may be helpful here. For example, if a DAO contains code like "If the student is a freshman, load this data, otherwise load that data", it's on the wrong track. This is business-related logic and belongs in the service layer.

Once again, DAOs are singleton Spring beans, so thread-safety is important.

DAOs are coded as interface & class pairs. You will find the DAO interfaces in a "dao" package, and their Hibernate implementations in a sub-package "dao/hibernate". Naming conventions are (for example) RegistrationDAO for the interface and HibernateRegistrationDAO for the class. Again, the use of the interface helps with unit testing, allowing us to test service classes by using mock DAOs that do not need to connect to the database.

One very important consideration for DAOs. You will see many DAOs in the framework that extend Spring's HibernateDaoSupport class and use Spring's related HibernateTemplate. DO NOT USE THIS METHOD FOR WRITING NEW DAOs! This style has been deprecated by Spring for at least 5 years in favor of DAOs as plain POJOs, and use of the Hibernate Session API. Now, with Spring 3.1 beginning to support Hibernate 4, these helper classes have been dropped from the Spring framework. When we upgrade our framework to Hibernate 4, we will need to rewrite code that uses these helper classes. So from now on we should stay away from these deprecated classes. In a nutshell, DAOs should be POJOs and should contain a private instance variable of type SessionFactory. The session factory should be injected by Spring, and DAOs should use the getCurrentSession() method on the factory object to obtain the Hibernate Session, and perform data access using the Session API.

  • No labels