Design an MVC framework using annotations

Annotations can help decouple your application components

1 2 Page 2
Page 2 of 2

Dynamic MVC binding

A problem for frameworks that depend on XML binding (or some other sort of declarative binding based upon configuration files) is static binding rules. Dynamic variations are not possible, thus the developer generally resolves to use redundant binding information coupled with some decision algorithm that uses the correct bind each time.

To circumvent this problem, the Stamps framework provides two ways to change the binding at runtime. First, views and models can be registered and deregistered with the dispatcher in the same way event listeners are associated with GUI widgets. This allows specific views to be notified only when they are needed. For example, a monitoring console associated with an application, which can be bound to the object it is monitoring, is used only when the user requests it.

Second, the @ModelDependent annotation provides two elements, runtimeModel() and runtimeProperty(), which specify that the binding with a specific model and its dispatched events will be decided at runtime. If one of the two settings is true, then the respective key (modelKey or propertyKey) will be the method invoked on the view to obtain the value to be used. An example: A view responsible for showing the contents of one of a set of news channels (each news channel is a model). The view then depends on the user input to identify the channel to bind to.

An example of such a situation follows:

                        // This method is invoked to display all the messages of one news channel
   @ModelDependent(modelKey = "dynamicChannel", propertyKey = "allmessages" , runtimeModel = true)
   public void setAllMessages(java.util.List<String> messages) {
      // Updates the user interface
   }
   public String getDynamicChannel() {
      // Returns the channel requested by the user
   }
                   

Additional annotations

Since the world is not perfect, additional annotations have been defined to help deal with real-world cases. @Namespace allows the developer to subdivide the model domain into different parts for better manageability of the whole. Since a single dispatcher can handle multiple models, conflicts in model keys may happen. Therefore, it proves useful to isolate groups of models and related views into different domains belonging to a single namespace, so that they will not interfere with each other.

The @Transform annotation allows on-the-fly object transformations from the objects contained in the model events to those accepted by the receiving views. Thus, the framework can be adapted to existing code without modification. The annotation accepts a single parameter that is resolved in a registry of available transformations (defined as implementations of a specific interface).

The @Refreshable annotation allows model properties to be tagged to support the discussed dynamic joining and leaving of views. Using this annotation, the framework is able to handle both static and dynamic MVC layouts, with different views bound to the model at different times.

To understand @Refreshable's usage, we must go back to the monitoring console example. This console (which, in MVC terms, is a view) would be dynamically bound and unbound to the model depending on user needs. The @Refreshable annotation can be used to keep the console informed about the model state when connected to it. When a view connects to the framework, it must be updated on the current model state. Therefore, the dispatcher scans the model for @Refreshable annotations and generates the same events the view would commonly receive from the model itself. Such events are then dispatched using the binding mechanism discussed earlier.

Distributed MVC networks

The dispatcher has a great burden on its shoulders and is responsible for all heavy-duty message-passing involved in the event-propagation cycle:

  • The model causes an event, which specifies some sort of change it has undergone. The dispatcher(s) handling that model is notified.
  • The dispatcher scans all its registered views, looking for @ModelDependent annotations, which specify the changes the view wants notification of, and the methods to be invoked on the view for every model event that has occurred.
  • If needed, transformations are applied to the event data.
  • The view methods are invoked with the parameters extracted from the raised event, and the view updates itself.

On the other side, when a new view registers to the dispatcher:

  • The view tells the dispatcher about the modelKey, which identifies the model it will be attached to (whose events will be responsible for populating the view).
  • If needed, the dispatcher scans the model looking for @Refreshable annotations and uses them to produce fake model events that will bring the view up to date.
  • These events are dispatched using the above sequence, and the view is updated.

All this work involves neither the view nor the model; they both stand at their respective ends of the communication line. It doesn't matter whether the messages are transmitted within a local JVM or between multiple JVMs located on remote hosts. Simply changing the logic within the dispatcher is all that is needed to transform local applications into client-server ones, leaving both the model and the view code unaffected. A sample setup is shown in the following image.

Figure 4. A MVC setup on a distributed network. Click on thumbnail to view full-sized image.

In the above image, the single dispatcher has been replaced with one transmitter (an instance of it.battlehorse.stamps.impl.BroadcastDispatcher), which stays on the same host as the model, and one (or more) receiver, (it.battlehorse.stamps.impl.FunnelDispatcher), located on the same host as the view. The Stamps framework's default implementation uses a messaging layer built upon JGroups, a toolkit for reliable multicast communication that works as a network transport mechanism (but different ones may be implemented and used), obtaining a reliable, multiprotocol, and failure-aware communication.

With a single change in the initial setup of our application (the dispatcher), we have moved from a single-user standalone application into a multiple-user distributed one. The framework can notify numerous listener interfaces when the model joins or leaves the network (think of a communication failure), so that remote views can take the appropriate responses—for example, showing a warning message to the user. The framework also offers utility methods that help to convert local controllers into remote ones.

Conclusions and summary

Many elements remain for exploration, such as the way to design controllers that are as equally generic as the dispatchers—at the moment, the framework assumes the common controller-model coupling, since the former needs to know how to drive the latter. Future developments are directed toward supporting different types of views, such as using a browser, network-aware applets, and Java-to-JavaScript communication

The discussed Stamps library shows how to achieve loose coupling between views and models in an MVC layout and how this framework can leverage Java annotations to separate the binding information from the actual application components. Having isolated the binding logic allows you to physically separate the components and provides both a local and a client-server setup without modifying the application logic or presentation layer. These objectives provide insight into the possibilities offered by combining a solid design pattern like MVC with the powerful metadata offered by annotations.

Riccardo Govonihas been working since 2003 as a J2EE developer for a financial services company in the northern part of Italy. There, he develops Web front ends for legacy banking systems, database management, and heavy-duty data processing tasks. Govoni has strong experience in J2EE multitier applications and detailed knowledge of Java GUI libraries such as Swing and SWT. He has a master's degree in physics. Govoni spends his spare time Googling around, looking for the latest Java news, or discussing new project ideas with friends and (sometimes) his girlfriend's dog.

Learn more about this topic

This story, "Design an MVC framework using annotations" was originally published by JavaWorld.

Copyright © 2005 IDG Communications, Inc.

1 2 Page 2
Page 2 of 2