May 17, 2015

RESTful JSF with POST-redirect-GET (part 2 of 5)


Pages: 1 2 3 4 5

CRUD

The foundation of REST really is an object oriented CRUD design. This will help us think in nouns rather than in verbs (as the verbs are fixed, it’s the nouns which are specified by the business requirements).

Design

For any business entity, we will have its respective CRUD service (backend logic) and its respective CRUD controller (frontend logic). Taking advantage of Java inheritance and generics, we actually need to build one service and one controller only, and deriving the concrete subclasses will typically be trivial.

For the service, we only need to come up with nice method names for the four CRUD actions.
Create: #save(T)
Read:   #findById(Long) / #findAll()
Update: #save(T)
Delete: #delete(Long)
Note that #find(Long) works with the entity id. We will always GET the entity by id. There’s also a #findAll() method.

For the controller (JSF backing bean) however, we need to think in JSF terms. For DRY reasons, we will use the same backing bean for both the master and the  detail view. For the former, the controller needs a list of all entities of the respective type; for the latter, the controller needs a singular reference to the current entity. Then, we add the backing bean action methods to the classes. These are basically just matches for the respective service CRUD methods. Note that the controller : service relationship is 1 : 1. Thus we can implement an abstract service property for a controller.

For technical reasons, we will later be forced to add some helper properties / methods to the controller. We will do so as we need them.

Implementation

For the sake of this tutorial and to simplify portability and testability, I’ve implemented the service as a pure @SessionScoped CDI bean-based mock, using a Map as the entity storage (no efforts were made for thread-safety or the like!). Actually, implementing a true persistent service may be even easier given the simplicity of Java EE’s entity manager facility.

Note how, through sensible use of inheritance / generics, the concrete implementation of a CRUD service is literally empty. This is a highly DRY compliant design. As an example, here’s the concrete PaymentService:
@SessionScoped
public class PaymentService extends BaseService<Payment> implements Serializable{
    // mocked lazy loading
    public List<Payment> findByCustomer(Long customerId) {
        ...
    }
}
For more details, take a look at the source code of BaseService.

The controller implements the properties and methods discussed earlier. We will take a look at the latter when we build the actual functionality. I implement the concrete controllers as JSF @ManagedBeans just to emphasize that they are for use with JSF exclusively. Implementing them as CDI beans of course is a valid option as well.

I will start with a @ViewScoped implementation: The bean’s lifespan is then bound to a single navigation step in the UI. This is a good tradeoff for simplicity / memory consumption for a REST-based implementation. We will examine this later on in more details.

Note again that a concrete controller only needs to provide a reference to its service (only a concrete subclass can CDI-@Inject a service) and a new entity, apart from any controller-specific business logic which should be sparse. Again, remember that the business logic resides in the domain model. We’re still running DRY.

As an example, here’s the concrete CustomerController:
@ManagedBean
@RequestScoped
public class CustomerController extends BaseController<Customer> implements Serializable {
    @Inject
    private CustomerService service;

    @Override
    protected CustomerService getService() {
        return service;
    }

    @Override
    protected Customer createNewEntity() {
        return new Customer();
    }
    
    // JSF validator implementation
    public boolean isCompanyEmptyWhenUnemployed(...) {
        ...
    }
}
For more details, take a look at the source code of BaseController.

RESTful navigation

Design

Remember that building a RESTful interface is actually building a state machine. It’s a good idea to sketch the complete state transition diagram prior to building it as this will prevent any future surprises. I have done so for this example application:

I’ll explain the coloring in a bit.

I’ve used the convention that the master view is called list.xhtml and the detail view is called edit.xhtml and that they are placed in a subfolder named after the respective entity type in plural. You could use any convention you like; the important part is that (a) you have one and (b) you stick to it.

In above diagram (a slightly modified version of a UML state machine diagram), each state transition is described by the origin, the HTTP verb, the controller method involved, and the outcome.

Because we can only use the REST verbs GET and POST, their meaning is mapped as follows:
Create: POST
Read:   GET
Update: POST
Delete: POST
The diagram makes it clear that GET operations can be started from anywhere; those URLs are thus eligible for bookmarking. POST operations always redirect to the GET operation they point at in the diagram (POST => GET); that’s the actual use case of “POST-redirect-GET” as mentioned in this article’s title.

A note on the usage of GET parameters for the edit view:
  • For CRUD Read operations, we only need the entity’s id.
  • If the id is omitted, CRUD Create intend is assumed.
  • For the special case of /payments/edit.xhtml CRUD Create, we need to provide the id of the customer entity the newly created payment entity is bound to. Remember that navigation is stateless. We have to provide this information and the only way to do it is through the GET parameters.
Whenever a view is opened with illegal parameters (an id which doesn’t match any entity), the user is redirected back to the list view and an error message is shown.

In the very last section of this article, we will also use PrettyFaces so as to use “real” RESTful URLs.

Transaction boundaries: designing page flows and parent-child-relations

It is critical to understand that in a RESTful application, due to the stateless nature of its page navigation, each operation is ACID and lives within its own transaction boundary. This has important consequences for page flows and parent-child relationships.

Note that according to the diagram, the list of payments of a customer is shown in the customer’s edit.xhtml view; there is no separate payments list.xhtml view. More importantly, payments can be edited independently of the customer they belong to. That’s why on the customer edit view, the action buttons are placed below the main input components rather than at the very end of the page, below the payments table.

For the application user, this means that after he clicks on a payment, opens it, edits it, and saves it, the saves are immediately persisted in the backend. He does thus not have the opportunity to make a couple of changes to a customer’s payments (which would be stored in some magic temporary scope), then come back to the customer and finally click on “save” to persist all of them. This would actually violate the whole idea of a stateless page navigation. Remember that the user can access the payment’s edit view from anywhere. He can click “save” and then go anywhere else. How should the application keep track of intermediate changes? How is the users supposed to “commit” a couple of changes? The answer simply is: There is no such opportunity. Each operation must be ended with either a “commit” or a “rollback” because each operation is CRUD and lives within its own transaction boundary.

Of course, you can still build such “temporary changes” functionality as part of your application. However, you would do so by using AJAX calls rather than page navigation. If for instance, the payments were editable in an “inline edit” <dataTable> in customer’s edit view, backed by a @ViewScoped controller, ACID would be assured as the user could only exit the view either by committing or rolling back his changes to the customer entity as well as to its associated payments entities.

Span of transaction boundaries is a business decision. For the demo application, I decided that I will have pure RESTful navigation only, thus in the example case, the payments’ transaction boundary is independent of their customer’s transaction boundary.

The very same thing also prominently applies to another common navigation element: page flows, i.e. mult-page wizards. We don’t have those in the example application, thus I will only quickly cover the basics here.

Image you had a wizard consisting of step 1, step 2, and step finish, and each step requires completion of the former, and only the finish step will commit the wizard’s work. Then you cannot model navigation with GET, as the user could jump in and out at any point in the navigation procedure, and ACID is violated:

Instead, you’d implement the wizard with POST without redirect, and keep track of the progress as a server-side state:
Here, you can even use proper POST navigation, but without redirect and thus without URL rewrite. For the user, it looks like he stays on the same page, but the page’s content is replaced with new input components every time he clicks “next” at the bottom of one of the wizard pages.

If you thus need such “stateful navigation” within your REST application you must use either AJAX or POST without redirect. For the end user, the application’s behavior should make it very clear whether a change is committed or not.

Pages: 1 2 3 4 5