Category: Seam

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.

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!

Videos from JavaOne 2009

I knew these existed but somehow forgot to post them. These are videos of my presentations at JBoss booth at JavaOne 2009 in San Francisco. I think it would be more useful if the videos would switch more often to the slides I’m showing, but in case, enjoy!

RichFaces presentation
Part 1
Part 2
Part 3
Part 4

JavaFX with Seam presentation
Part 1
Part 2
Part 3

Seam component events

A very powerful feature in Seam that usually doesn’t get enough attention in my opinion is component-driven events. Seam component can raise or throw arbitrary event and any number of other Seam components can observe or listen to these events. This truly creates a loose coupled architecture. Components raise events and anyone who cares listens to the event. The components are not connected to each other in any way.

Let’s start with CourseManager component:

@Name("courseManager")
public class CourseManager {
 
   private String name; // setter and getter
 
   @Out(required=false)
   private String studentName;
 
   @Logger Log log;
 
   @RaiseEvent("courseDropped")
   public void drop() {
     studentName = name;
     log.info("course dropped");
   }
}

In component above when drop() method is invoked, courseDropped event will be raised via @RaiseEvent annotation. Once invocation is done, the component will outject studentName variable.

Although data can passed with the event, a better way is to use bijection in Seam. The name variable would most likely be submitted from a JSF page. Its value is assigned to studentName component variable and studentName is outjected after the method invokation. Anyone who is interested in this event can listen to it and also get the data associated with the event (via injection).
Continue reading

CITYTECH: enterprise application with JavaFX, Seam, and Exadel Flamingo

Great post by John Kraus from CITYTECH on how they used Exadel Flamingo to connect rich JavaFX UI to their existing Seam application. It’s good to see JavaFX slowly penetrating the enterprise. And with Flamingo, it becomes even simpler. Companies can leverage their existing services and easily connect them to JavaFX rich UI as CITYTECH did.

There are a number of interesting new features in Flamingo. There is now server-side push and off-line applications for JavaFX. There is also a connector for Google’s Android platform. I’m planning to blog about these technologies and more very soon. As for JavaFX tooling, we have been working on JavaFX plug-in for Eclipse. Try it out. The plug-in is going to be open source any day now.

Read blog post here

Hibernate Validator with JavaFX

One of the key features in Exadel Flamingo is that it allows you to use Hibernate Validator based validation on JavaFX UI side.

On the server you can have something like this:

@Entity
@Name ("message")
public class Message {
   @Id @GeneratedValue
   private Long id;
 
   @Length(min=3, max=40)
   private String text;
   ...
}

This is a simple entity and also a Seam component.

On the JavaFX side all you need to do is this:

var textBox : TextBox = TextBox {};
var errorText: String {};
...
errorText = FlamingoServiceFactory.getHessianEntityValidator().
                    validate("message.text", textBox.text);

message.text – message is Seam component name and text is component property. textBox.text is JavaFX node (widget) whose value we need to validate.

Simple… right?