Interesting changes coming to Seam…(and RichFaces)
So what’s happening with Seam?. Read the comments. And an update to the original post.
So what’s happening with Seam?. Read the comments. And an update to the original post.
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
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.
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.
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.
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!
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
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?
To use JavaFX in enterprise, you need to be able to connect JavaFX to enterprise backend such as Java EE, Seam or Spring. Here is an example how to call Seam component from JavaFX using Exadel Flamingo.
Seam component (server side)
@Name("messageManager") public class MessageManager { public String callMe () { return "Seam component says: what's up"?; } |
JavaFX (client side)
public interface MessageManager { public String callMe (); } |
public class AppServiceFactory { public static MessageManager getMessageManager() { return (MessageManager) ServiceFactory.getService(MessageManager.class, "messageManager"); } } |
JavaFX script:
var reply : String; function call(): Void { ... reply = AppServiceFactory.getMessageManager().callMe(); ... } |
That’s it. Simple, easy and transparent. Seam is used the same way if you were building a JSF-based application.
This article is also posted on JavaLobby.com
This is a guest post by Anton Polyakov. Anton is Senior Developer at Exadel, he describes our experience building a JavaFX front end for a Seam booking application.
JavaFX is new tool set for developing and delivering Rich Internet Applications or RIAs. JavaFX 1.0 was released in December 2008, and JavaFX 1.2 was released in June 2009. As these new releases have rolled out, the JavaFX community has been growing fast. This growth has produced a large selection of resources, articles, blog posts, books, and extension projects.
Over this time, while JavaFX has been used extensively to provide “richness� in applications, it has been mostly “missing in action� for enterprise-level Web applications that would involve greater integration of JavaFX with the server side of the application. Remember, a Rich Internet Application is delivered from a server to the the client, but, more importantly, it continues to communicate with the server. The UI runs on the client while the application logic runs on the server.
We believe that for JavaFX to continue growing and compete against Flex and Silverlight, it should be acceptable by the enterprise for use in applications that take full advantage of both sides of Rich Internet Applications (Rich Enterprise Applications). Adobe and its community has done an excellent job demonstrating that Flex can be used to build real-world enterprise applications. The same needs to happen for JavaFX.
Exadel has been working with JavaFX for more than a year now. In June of 2008, we took the popular Jboss Seam hotel booking Web application and built a JavaFX UI on it as a replacement for the standard JSF UI. Back then, we used a prerelease version of JavaFX. (There was very little interest in JavaFX at that time.)
Fast forward to today. We took the same Seam booking application and updated the JavaFX UI to JavaFX 1.2. You can find the demo running here. For your local use, you can also download the file to run or a Maven project to build this application.
What we are going to do in the rest of this article is share our experience building this demo as an example of building an enterprise JavaFX applications. The task wasn’t easy (but then it wouldn’t have been as fun).
You can now view or download and deploy one of the first real enterprise JavaFX application. We took the popular Seam booking demo application and created JavaFX UI for it. The JavaFX side is connected to Seam via Flamingo RIA framework.

View online
You can view and run the application by going to this URL: http://demo.flamingo.exadel.com/booking/. You will also see JSF/RichFaces and Flex versions of the application. All instances are connected to the same Seam back-end. Once you register, you can use the same name/password information to login using any other user interface.
Download and run
You can also download, deploy and run this application on your machine. There are two ways you can do it:
Download the source and application (.ear). You will find instructions on how to deploy and build inside the zip file.
We are working on an article to tell you about our experience building an enterprise application with JavaFX. Lastly, yesterday we released new version of our JavaFX Studio plug-in for Eclipse. Get it here.
Have fun with JavaFX!
The following series shows how to connect JavaFX to enterprise server-side technologies. This series covers Seam.
A future series will cover how to connect JavaFX with Spring framework.