Tagged: JavaFX

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:

Exadel JavaFX Plug-in for Eclipse version 1.3.4 with Organize Imports

Exadel has released Exadel JavaFX Plug-in for Eclipse version 1.3.4. The biggest feature in this release is Organize Imports (just like in Java editor).

The class for Text node is missing, pressing Ctrl+Shift+O, will display the dialog where the correct class can be selected:

You can also invoke Organize Imports from the editor context menu (right-click anywhere in the editor and select Organize Imports).

JavaFX… does it have a future?

I don’t know any other technology that has ever gotten as much of a beating as JavaFX did last week (here, here, and pinata for developers.

JavaFX was first announced at JavaOne 2007 (that’s 3 years ago). Many predicted its death even before version 1.0 was released in December 2008, and many continue to call for its demise.

Last week also turned out to be the week where I presented Enterprise JavaFX at the Silicon Valley JavaFX JUG, and also the week that Steven Chin created a petition to open source JavaFX.

Don’t get me wrong, JavaFX is very far from perfect. It has it’s problems and challenges (listed below) and its future is hanging on life support right now, but let’s start with the good.

The good stuff

JavaFX Script is a very powerful language. In fact, it’s a DSL (Domain Specific Language) for creating rich user interfaces where the resulting application runs inside the Java virtual machine on the client. JavaFX Script might appear foreign at first (as probably any new programming language would) but after using it for a while you start realizing it’s power and ease of use. The JavaFX binding feature simplifies UI development even further by tracking model changes automatically. I have been working with JSF (JavaServer Faces) since its inception and I can tell you that using JavaFX Script to build the UI is probably simpler than using JSF. As JavaFX applications run inside the Java virtual machine which is very powerful, this allows us to build rather rich and sophisticated client applications.

The ugly stuff

As the mantra in real estate is: location, location, location. The mantra in JavaFX is: deployment, deployment, deployment. Unfortunately, this is where JavaFX has failed miserably. The original Java applets failed miserably in deployment and JavaFX (which was supposed to be the next applet technology or applets 2.0) has inherited the failed deployment with it. In other words, nothing has really changed since 1995. I don’t understand why Oracle (previously Sun) has allowed this to happen. I know that Oracle has some very smart people who could have fixed it a long time ago.

This is what happens most of the time. You click on a link to launch a JavaFX application as an applet inside the browser. Let’s assume that you already have the Java plug-in installed. The browser freezes for about 5 seconds. After the 5 or so seconds, you will see the a Java logo inside a dotted circle. The dotted circle is moving around as if to show the loading of the applet. The sad thing is that it’s just an animated GIF and doesn’t show the actual loading progress. Why is it so difficult to show some sort of progress status of the actual loading?

This is where it gets even more interesting. If you are lucky, you will see a rather scary security dialog (you have to click “yes”) and after that the application will appear. If you are not lucky, you will continue seeing the moving image (with the Java logo inside) forever or until you close the browser window. Nothing else will happen. No error message. No reason why the applet was loaded. Nothing. If you want to know why the applet failed to load, you have to launch the Java plug-in console and look for the exception/error there. Launching the console is not easy either. Try to explain this to a non-developer. Good luck. It’s also not uncommon for an applet that worked just a second ago to stop working on the next run for unknown reasons.

What I described above is the main reason JavaFX has failed so far. Deployment is still a disaster. If Oracle needs to know how deployment should work, it’s very easy. Just look at Flash. Make it as simple and transparent as running a Flash application. That’s it.

Do I have to learn a new language?

Some people say they don’t like JavaFX because they need to learn a new language. Well that’s just a bunch of hot air. First of all, any decent Java developer can pick up JavaFX Script in about 2 days. And, second, no one is complaining that they have to learn a new language (or scripting language) when they use Flex or Ruby or Scala or even JSF. All require you to learn something new. If you are developer (any kind) today, you have to learn new stuff all the time.

The stuff that’s getting better

Look at any major Java conference for the past two years and you will see at least one session that covers JavaFX. Judging by the blogosphere and Twitter, the JavaFX community is growing. People are posting examples, building custom components, and writing CSS tutorials. The developer community is there. People are trying JavaFX but no organization is building anything real world out there. A medal history application built with JavaFX was deployed during the 2010 Winter Olympics in Vancouver but I doubt many people remember it today. Just recently MLB.com deployed a fantasy baseball application. That’s it.

The argument that JavaFX is missing tools that bridge the designer and developer is a valid one.
JavaFX tooling is being developed. NetBeans has JavaFX Composer (a visual layout tool for building JavaFX applications). Exadel (my company) has been working on Exadel JavaFX Plug-in for Eclipse. Right now, our direction is to provide the most powerful source tools for JavaFX development. Also, IntelliJ just recently announced that it now offers JavaFX support.

The fact that JavaFX is missing many common controls is also a valid argument. New and more advanced controls are actually being developed by the Oracle JavaFX team. Furthermore, to help the community build 3rd-party components, JavaFX should be open sourced.

JavaFX in the enterprise

Enterprise applications such as rich and interactive dashboards and other rich graphical and content user interfaces are a very good candidates for using JavaFX. Enterprise JavaFX has been missing in action. 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. To help enterprises adopt JavaFX, Exadel has made the Flamingo framework available. Flamingo helps connect the JavaFX UI to enterprise back ends such as Java EE, Spring, and Seam. I personally tried to reach out to Sun and then Oracle on working together on enterprise JavaFX tooling, but, as you might have guessed, I never heard back.

Future?

There is still time to make JavaFX successful, but the time is running out. First, fix the deployment issue as soon as possible. Just start from scratch, don’t try to fix the current deployment system. Second, Oracle needs to make it very clear what its plans are for JavaFX (maybe at JavaOne 2010?). If Oracle doesn’t want or need JavaFX, then open source it and let the community drive it’s future. I think Oracle has 6-12 months at the most to try and revive JavaFX. If nothing happens by then (which would be about 4 years since the technology was announced), we just might as well close the door on JavaFX.

My 2 cents.

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!