Donnerstag, 14. Juli 2011

Marrying JSF with Scala - Part2

View Controllers and Navigation

While part1 showed us how we can do managed beans in Javascript, we now will go a little bit deeper. In this part we will talk about view controllers and navigation implemented in Scala.

Short Introduction to ViewControllers

While JSF does not know the ViewController pattern, for JSF is everything a managed bean, it makes sense to name a certain set of managed beans ViewControllers.
Per definition in JSF a ViewController is a managed bean, which deals directly with the user interface interaction from the backend.

Such interactions are
  • Actions
  • Events
  • Listeners

  • etc...

A typical plain Java Viewcontroller

So a typical Java ViewController in a plain JSF environment looks like following.
@ManagedBean
@RequestScoped
public class TestViewController implements Serializable {
private static final String PAGE2 = "page2";
private static final String PAGE3 = "page3";
String value1 = "";
String value2 = "";
public String action1() {
return PAGE2;
}
public String action2() {
return PAGE3;
}
public void actionListener(ActionEvent myAction) {
//do something here
}
public String getValue1() {
return value1;
}
public void setValue1(String value1) {
this.value1 = value1;
}
public String getValue2() {
return value2;
}
public void setValue2(String value2) {
this.value2 = value2;
}
}
Everyone who has programmed JSF is familiar with those patterns.
 
Sidenote: there are frameworks which add dedicated view controllers with dedicated callbacks for postCreate, preRender
 

ViewController in Scala

The question now is, how does this look in Scala.
object TestViewController {
val PAGE1 = "page1"
val PAGE2 = "page2"
}
@ManagedBean
@RequestScoped
@serializable
class TestViewController {
import TestViewController._
var value1: String = ""
var value2: String = ""
def action1():String = PAGE1
def action2():String = PAGE2
def actionListener(myAction: ActionEvent) {
//Do something here
}
}
Again, this code is somewhat smaller thanks to the absence of setters and getters. However the structure of this class is not 1:1 translatable to Java due to following new construct:
object TestViewController {
val PAGE1 = "page1"
val PAGE2 = "page2"
}
 
So what is this object all about?
Scala does neither know static classes nor variables, instead it has singletons in its language core as companion pattern to classes. If a construct is defined via object instead of class, then the resulting object is a singleton. To make the code tighter, Scala also allows imports everywhere. Members of singletons can be imported simply by import <Singleton>._ so that we can call them directly in our code.
If you notice in our action callbacks we return the members of the singleton directly, like we would do it with static variables in Java.


MyFaces Codi Typesave Navigation

MyFaces Codi has an interesting feature, the so called typesave implicit navigation.

While JSF2 already eased the lives of developers by introducing an implicit navigation (aka return value of an action == page name if no navigation rule is given), MyFaces Codi goes one step further.
It maps pages to classes (page name must be the class name) and it allows the grouping of navigation elements in wrapper classes (follow this link for further reference).

While in my personal opinion, the class based navigation alone, it really shines once you add advanced codi features to it like the security handling or the View Controller extensions.
(For more Information please consult the MyFaces Codi documentation

Here is a small example:
public interface Wizard extends ViewConfig
{
@Page
public final class Page1 implements Wizard
{
}
@Page
public final class Page2 implements Wizard
{
}
}
@ManagedBean
public final class Login
{
public Class<? extends ViewConfig> goPage1() {
return Page1.class;
}
}
view raw gistfile1.txt hosted with ❤ by GitHub
This is a very basic example of two navigation cases
  • the first one points to /Wizard/Page1
  • the second one points to /Wizard/Page2
However to map this to scala we face a set of problems
  1. We don't have interfaces, we have mixins, but they do not map straight to the structures we need
  2. the interface classes are the same problem as the interfaces
So we have to find structures which Codi can follow but are buildable in Scala. Here we have the same example in Scala:
object Wizard extends ViewConfig {
@Page
object Page1 extends ViewConfig
@Page
object Page2 extends ViewConfig
def GO_PAGE1: Class[_] = Page1.getClass
def GO_PAGE2: Class[_] = Page2.getClass
}
@ManagedBean
class Login {
import Wizard._
def goPage1(): Class[_] = GO_PAGE1
}
view raw Wizard.scala hosted with ❤ by GitHub
Again we are able to map everything into singletons so we work with a set of objects instead of interfaces and interface classes.

That sums up part2 for now


Next week, I will talk about how to leverage Scalas very powerful trait feature to isolate common behavior.

Keine Kommentare:

Kommentar veröffentlichen