Exadel Flamingo now supports CDI and Bean Validation for JavaFX

Exadel Flamingo now has support for CDI (JSR299) and Bean Validation (JSR303). You can try the features from a nightly build.

The following features are supported so far:

  • Calling CDI bean methods
  • Support for EL (Expression Language). Bind to values and invoke methods with EL in JavaFX
  • CDI conversations
  • Bean Validation (JSR303)

To download a nightly build, go to http://exadel.org/flamingo and click on Nightly builds on the right.

To get started with JavaFX and CDI/Bean Validation, you can look at these examples as reference. The client side code is the same, the only difference is instead of Seam components, you now use CDI beans on the server (and the appropriate annotations).

We are also planning to add CDI events. If there is anything else we should add, please let us know.

RichFaces workshop in Germany

I will be presenting and teaching a RichFaces workshop in Nuremberg, Germany during Herbstcampus conference, September 12 – September 15, 2010.

With the upcoming RichFaces 4 release, the workshop will cover RichFaces version 4. This is a great opportunity to learn standard JSF 2 Ajax features and how RichFaces 4 advanced features, tags, customization and richness add on top of JSF 2. RichFaces 4 is a major upgrade. A lot of core functionality is being rewritten to make RichFaces faster and better. Many components are being rewritten to make them simpler, perform faster and consistent across board.

Discount
Get 25% discount by using this URL. Alternatively, you can use this booking code: ceHioRcpiD.

RichFaces workshop (full day)
Sunday, September 12, 2010
More info >>

I also have two general sessions.

Ajax Applications with JSF and the two New RichFaces 4
Monday, September 13, 2010
More info >>

Enterprise Applications with JavaFX and Flamingo
Tuesday, September 14, 2010
More info >>

As a reminder, we are also doing a webinar on September 8, 2010:
Ajax Applications with JSF 2 and the New RichFaces 4
Register >>

New Exadel Flamingo 2.2.0 is now on exadel.org

After months of promising we have finally moved Exadel Flamingo to exadel.org and released version 2.2.0. exadel.org is our community site for hosting open source projects. Flamingo is a light weight framework for connecting rich web and mobile user interfaces to enterprise back end.


Click on image to enlarge

Flamingo connects Seam, Spring, and Java EE 6 (soon via CDI/JSR299) with the following user interfaces:

  • JavaFX
  • Flash
  • iPhone/Android
  • Swing
  • JavaME

Version 2.2.0 is updated with Hessian 4 and JavaFX 1.3 support.

Server-side components, methods or services can be easily invoked from the above listed clients with minimal code. Flamingo provides the following features:

  • CRUD tools
  • Server-side integration
    • Calling server components/beans
    • Context variable binding/updating
    • Conversation support
    • Validation (Hibernate Validator)
    • EL support (Expression Language)
  • Server-side push
  • Client push (off line applications)


Click image to enlarge

As you can see from the image above, no matter what client you are using, invoking a method in your enterprise applications looks very similar which allows for great reuse.

How to get started?

  • Download Flamingo from http://exadel.org/flamingo.
  • The following are good resources to get started or learn more about Flamingo.
  • Check out the recent Enterprise JavaFX and Seam series. This series shows most server integration features in separate post and easy to follow examples.
  • We want to hear your feedback, please use project Jira or the forum to report bugs or any features you would like to see.

Enterprise JavaFX with Seam and Flamingo – complete edition

I wrote a series of posts on how to connect JavaFX to a server running with Seam framework. Client-server communication is realized with the help of Flamingo framework. Here is the complete series:

Seam conversations from JavaFX

This post covers starting/stopping Seam conversations from JavaFX. See other posts in this series:

Calling Seam component from JavaFX
Invoking Hibernate Validator from JavaFX
Binding to server-side context variable from JavaFX
Using Expression Language (EL) in JavaFX to communicate with server

Server side

Seam component:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
@Name ("wizard")
@Scope (ScopeType.CONVERSATION)
public class Wizard {
   @In Conversation conversation;
 
   public String info (){
	return "Id: "+conversation.getId() +", active: "+conversation.isLongRunning();	   
   }
   @Begin
   public void start (){
	// do something	
   }
   @Conversational
   public String nextStep (){
	return "Id: "+conversation.getId() +", active: "+conversation.isLongRunning();
   }
   @End
   public void end (){
       // do something		
   }
}

Above is a pretty simple Seam component with conversation scope. It has method to start the conversation (@Begin) and end the conversation (@End). It also has nextStep() annotated with @Conversation, that means that the method can only be invoked within a long running conversation.

Client side

Component interface:

public interface Wizard {
   public void end();
   public void start();
   public String nextStep ();
   public String info ();
}

JavaFX script:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
CookieHandler.setDefault(new CookieManager(null, CookiePolicy.ACCEPT_ALL));
FXServiceFactory.URL = "http://localhost:8080/server-javafx/seam/resource/hessian/";
var wizardService = WizardServiceFactory.getWizardService();
 
def red: RadialGradient = RadialGradient{  
    centerX: 8, centerY: 8, radius: 12, proportional: false   
    stops: [  
    Stop {offset: 0.0 color: Color.WHITE}, 
    Stop {offset: 1.0 color: Color.RED}
    ]
} 
def green: RadialGradient = RadialGradient{  
    centerX: 8, centerY: 8, radius: 12, proportional: false   
    stops: [  
    Stop {offset: 0.0 color: Color.WHITE}, 
    Stop {offset: 1.0 color: Color.GREEN}
    ]
} 
var light = Circle {
    centerX: 10 centerY: 10 radius: 10 stroke: Color.BLACK 
    fill: bind if (longRunning) green else red    
}
var infoButton:Button = Button {
    text : "Info"
    style : "-fx-font-size: x-large"
    action: function () {
        var newInfo = wizardService.info();
        insert newInfo into info;
    }
}
var longRunningOnly:Button = Button {
    text : "Only if active"
    style : "-fx-font-size: x-large"
    action: function () {
        try {
            var newInfo = wizardService.nextStep();
            insert newInfo into info;
        }
        catch (exception: Exception) {
            Alert.inform("Not active conversation");
        }
    }
}
var longRunning = false;
var convButton:Button = Button {
    style : "-fx-font-size: x-large"
    text : bind 
    if (longRunning) "Stop" else "Start"
    action: function () {
        if (longRunning==false){
            wizardService.start();
            longRunning = true;
            var newInfo = wizardService.info();
            insert newInfo into info;
        }
        else if (longRunning==true) {
            wizardService.end();
            longRunning = false;
            var newInfo = wizardService.info();
            insert newInfo into info;
        }
    }
}
var info = [wizardService.info()];
var list:VBox = VBox {
    content: {
        VBox {
            content :  bind for (item in info){
                Text {
                    content: item
                    style : "-fx-font-size: x-large"
                }
            }
        }
    }
} 
Stage {
    title: "Application"
    width: 450 height: 400
    scene: Scene {
        fill: LinearGradient {
            endX: 0.0
            stops: [Stop { offset: 0.0 color: Color.LIGHTGRAY }
            Stop { offset: 1.0 color: Color.GRAY }]
        }
        content: [ 
        VBox {
            spacing : 4
            content: [
            HBox {
                spacing: 4
                content: [
                infoButton, convButton, light, longRunningOnly
                ]
            }, 
            list	
            ]
        }
        ]
    }
};

Line 3: we get reference to WizardService and now can call all methods in the interface.
Lines 23-30: info button which returns the current conversation status
Lines 31-43: button that calls a method which should be called only when a long running conversation is active. If clicked outside of a long running conversation, an error dialog will be shown
Lines 45-63: button that starts/stops the conversation

Notice that nothing special needs to be done when using conversations, it is just a simple component method invocation.

No long running conversation:

Long running conversation:

Trying to invoke a method with @Conversation outside of a long running conversation:

That’s it.

Using Expression Language (EL) in JavaFX to communicate with server

This post shows how to use Expression Language (EL) from JavaFX to communicate with a server using Exadel Flamingo. See my previous posts on Enterprise JavaFX: calling Seam component from JavaFX, invoking Hibernate Validator from JavaFX, and binding to server-side context variable from JavaFX.

Seam component:

@Name ("helloAndTime")
@Scope(ScopeType.SESSION)
public class HelloAndTime {
 
   private Date lastAccessTime;
 
   public Date getCurrentTime() {
	return new Date();
   }
   public String sayHello(String name) {
	lastAccessTime = getCurrentTime();
	return "Hello " + name;
   }
   public Date getLastAccessTime() {
	return lastAccessTime;
   }
}

JavaFX script:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
def expressionService: ExpressionService = {
   var returnValue: ExpressionService = null;
   try {
      CookieHandler.setDefault(new CookieManager(null, CookiePolicy.ACCEPT_ALL));
      FXServiceFactory.URL = "http://localhost:8080/server-javafx/seam/resource/hessian/";
      returnValue = FXServiceFactory.getService(ExpressionService.class, 
                        ExpressionService.NAME) as ExpressionService;
    } catch (exception: Exception) {
        Alert.inform(exception.getMessage());
    }
    returnValue
}
 
var userName: String = "Enter name";
var serverAnswer: String;
var serverTime: Date;
var lastAccessTime: String;
var poller = Timeline {
   repeatCount: Timeline.INDEFINITE;
   keyFrames: [
   KeyFrame {
      time: 1s;						
      action: function () {
          serverTime = expressionService.getValue("helloAndTime.currentTime") 
                                   as Date;
      }
  }
 ]
}
poller.playFromStart();
 
var stage: Stage;
stage = Stage {
    title: "EL-Expression Sample"
    width:  420 	
    height: 400
    scene: Scene {
        fill: LinearGradient {
            endX: 0.0
            stops: [Stop { offset: 0.0 color: Color.LIGHTGRAY }
            Stop { offset: 1.0 color: Color.GRAY }]
        }
        stylesheets: [ "{__DIR__}style.css" ]
        content: VBox {
            translateX: 5
            translateY: 5
            spacing: 10
            content: [
               TextBox {
                  text: bind userName with inverse
               }, 
               Button  {
                  text: "Say Hello"
                  style : "-fx-font-size: large"
                  action: function() {
                  var classes: Class[] = String.class;
                  serverAnswer = expressionService.
                      invokeMethod("helloAndTime.sayHello", String.class, classes, userName) 
                         as String;
                  lastAccessTime = String.valueOf(expressionService.
                      getValue("helloAndTime.lastAccessTime") as Date);
                  }
               }, 
               Text {
                  content: bind "Server says: {serverAnswer}"
                  styleClass: "text"
               }, 
               Text {
                  content: bind "Last access time: {lastAccessTime}"
                  styleClass: "text"
               }, 
               Text {
                  content: bind "Current server time: {serverTime}"
                  styleClass: "text"
               }
            ]
        }
    }
    onClose: function() {
        poller.stop();
        FX.exit();
    }
}

Line 6: we get a reference to ExpressionService instance. This class gives us all the functionality to work with EL from JavaFX.
Line 24: we bind to currentTime property in helloAndTime component (bean). The syntax we use is helloAndTime.currentTime. If you are have are familiar with JSF then you would expect this format: #{helloAndTime.currentTime}. Due to JavaFX syntanx we can’t use {} brackets. I think helloAndTime.currentTime is just as simple.
Line 57: we invoked a method
Line 60: we bind to now another property: helloAndTime.lastAccessTime

When using EL, we don’t have to create an interface for the remote component as we did in calling Seam component from JavaFX. On the other hand, the compiler can’t check that such method actually exits. When using an interface, the compiler will complain if we try to invoke a method that’s not in the interface.

Result:

That’s it.

Binding to server-side context variable from JavaFX

In addition to calling methods and Hibernate Validator, it’s also very simple to bind to a context variable and update it from JavaFX. A context variable is any variable inside a scope on the server.

Server

Seam component:

@Name ("shop")
@Scope (ScopeType.SESSION)
public class Store {
 
   IceCream iceCream; // getter and setter
 
   @Create
   public void init (){
	iceCream = new IceCream();
	iceCream.setName("Best ice cream");
	iceCream.setFlavors(2);	
   }
}

Model:

@Entity
@Name ("icecream")
public class IceCream implements java.io.Serializable{
 
   @Max(value=5, message="Sorry, you can't have more than {value} flavors")
   private Integer flavors;
 
   private String name;
 
   // getters and setters
}

Client

Model:

public class IceCream implements java.io.Serializable{
   private String name;
   private Integer flavors;
   // setters and getters
}

BindingManager interface:

public interface BindingManager {
   public String commit(String componentName, Object value);
   public Object getObject(String name);
}
public class IceCreamServiceFactory {
   public static BindingManager getBindingManager() {
	return (BindingManager) FXServiceFactory.getService(BindingManager.class,
		"com.exadel.flamingo.service.binding.bindingManager");
   }
   public static String commit (String componentName, Object value){
	return getBindingManager().commit(componentName, value);
   }
   public static IceCream getIceCream (String componentName){
	return (IceCream)getBindingManager().getObject(componentName);
   }
}

JavaFX script:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
CookieHandler.setDefault(new CookieManager(null,CookiePolicy.ACCEPT_ALL));
FXServiceFactory.URL = "http://localhost:8080/server-javafx/seam/resource/hessian/";
 
FX.println("Getting ice cream from server");
var iceCream = IceCreamServiceFactory.getIceCream('shop.iceCream');
FX.println ("  {iceCream}");
 
iceCream.setName ("Gelato");
iceCream.setFlavors(4);
 
FX.println("Starting commit");
IceCreamServiceFactory.commit("shop.iceCream", iceCream);
FX.println("Getting ice cream from the server after update");
FX.println ("   {IceCreamServiceFactory.getIceCream('shop.iceCream')}");

Line 5: Getting ice cream from the server (binding to context variable)
Line 8-9: Making changes to ice cream
Line 12: Committing changes to the server
Line 14: Getting the updated object from the server

Output:

Getting ice cream from server
  Name: Best ice cream, flavors: 2
Starting commit
Getting ice cream from the server after update
   Name: Gelato, flavors: 4

That’s it.

Invoking Hibernate Validator from JavaFX

I showed how to call a Seam component with Flamingo from JavaFX. In this post I show how to invoke Hibernate Validator from JavaFX with Flamingo:

Entity (and Seam component):

@Entity
@Name ("icecream")
public class IceCream {
 
   @Id @GeneratedValue
   private Long id;
 
   @Max(value=5, message="Sorry, you can't have more than {value} flavors")
   private Integer flavors;
 
   // getters and setters
}

JavaFX script (most interesting stuff is happening lines 17-21):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
FXServiceFactory.URL = "http://localhost:8080/server-javafx/seam/resource/hessian/";
 
var message:String;
var textBox:TextBox = TextBox {
    columns: 15  
}
var label:Label = Label {
    text : "How many flavors:"   
    style:"-fx-font-weight:bold"
}
var errorMessage:Label = Label {
    text: bind message
    style : "-fx-text-fill:red; -fx-font-weight:bold" 
}
var button:Button = Button {
    text: "Click"
    action : function () {
       var ev = FXServiceFactory.getService(EntityValidator.class, 
       		"com.exadel.flamingo.service.validator.entityValidator")
       		as (EntityValidator);      
       message = ev.validate ("icecream.flavors", textBox.text)
    } 
}
 
Stage {
    title: "Application"
    width: 250 height: 100
    scene: Scene {
        content: [ 
        VBox {
            spacing: 5
            content:[
            label, 
            HBox {
                spacing: 5
                content: [
                   textBox, 
                   errorMessage
                ] 
            }            
            button
            ]
        }
        ]
    }
};

Result:

That’s it.

Calling Seam component from JavaFX

We very close to moving Flamingo and Fiji to exadel.org. It will probably (finally) happen next week. I just wanted to show how simple it is to call a Seam component from JavaFX using Flamingo:

Seam component (server):

@Name ("currentTime")
public class CurrentTime {
   public Date currentTime () {
	return (new java.util.Date());
   }
}

Service interface (client):

public interface CurrentTime {
   public Date currentTime ();
}

JavaFX script (client):

FXServiceFactory.URL = "http://localhost:8080/server-javafx/seam/resource/hessian/";
var ct = (FXServiceFactory.getService(CurrentTime.class,"currentTime") as CurrentTime);
var now = ct.currentTime();
FX.println(now);

That’s it!

Presenting at Silicon Valley JavaFX User Group: Enterprise JavaFX

I will be presenting Enterprise JavaFX at the Silicon Valley JavaFX User Group on Wednesday, July 14, 2010.

The event starts at 7pm (PT) and is broadcast live here. To sign for the event (even if attending remotely), please click here.

Next Page »