JavaFX Online Game Prototype: Wish Tree (2)

Posted: under JavaFX Games, Wish Tree.
Tags: , , ,

Last week, I introduced a JavaFX prototype of an online game. Readers have been leaving all kinds of wishes on my Wish Tree. It is interesting to see there are more than 20 lucky stars hanging on the Wish Tree now. If you have not tried the program yet, you are encouraged to click on the screenshot on the right to take a look or make an online wish.

Let’s come back to the technical part of the program again. In part 1, we introduced the architecture of this online application and the JavaFX rich client. In this post, I will explain the details of the data exchange between the client and the server. For your convenience, I bring back the architectural figure as shown below:

click to start wish tree online program


Like any client/server system, the server provides data services to the client. Based on the requirement of the Wish Tree, we define two services provided by the server: getAllStars and saveStar.

Service name Parameters Notes
getAllStars none  
saveStar location, name, content, time, color, email for create, returns id
id, content, email for update


The first one getAllStars is for the client to retrieve the data of all the stars(wishes) in the database. The data of a star contains its (x,y) coordinates on the screen and its color. The wish information associated with a star is also returned. Such information includes the wisher’s name, email address, content of the wish and the time when the wish was made. Based on this data, the client restores the stars at the exact location where people hung them on the tree. In this way, every time you start the wish tree client, you always see your star staying at the same place.


The second service is saveStar. When a user creates a star on the tree, the data of the star is sent to the server and saved into the database. The id of the star is returned to the client for later update purpose. The id is nothing more than a unique identifier of each wish stored in the database. You can think of it as the primary key of a database table. We will re-use this service to update a wish. This is due to the fact that most of the handling logic is the same for create and update action. The service first checks whether the client has sent in an id as a request parameter. If id is included, then it is a request of update; otherwise, it is a request of create.


The sequence diagram of these services are depicted as below:




Now that we have a high level design of services, we can elaborate on the protocol between the client and the server. Since our application is stateless, a RESTful style of request and response should be good enough. Therefore, we use HTTP GET request for the getAllStars service and POST for the saveStar service. The format of the response data could be HTML, XML or JSON. Because JavaFX provides a PullParser class which can parse XML or JSON data, we choose JSON in our application. Below is a sample of the JSON response of the getAllStars service:

{
 "Star": {
   "id" : "102",
   "name" : "John Smith",
   "content" : "My first wish",
   "location" : "388.0_248.0",
   "email" : "j.smith@example.com",
   "time": "2009-08-21 16:38:37",
   "color": 3
 },
 "Star": {
   "id" : "108",
   "name" : "Homer Simpson",
   "content" : "This is another wish.",
   "location" : "188.0_228.0",
   "email" : "homer@simpson.com",
   "time": "2009-08-28 18:28:48",
   "color": 4
 }
}


Once we finalize the protocol between the client and the server, we can start to implement the code on both sides. In a large scale project, this usually results in two teams concurrently working on the code of the client and the server respectively. At the client side, the code to parse the above JSON data is in Main.fx :

var parser = PullParser {
    documentType: PullParser.JSON;

    onEvent: function(event: Event) {
      var content: String;
      var name: String;
      var id: String;
      var email: String;
      var color: Integer;
      var time: String;
      var location: String;

      // parse the JSON data and populate the object
      if(event.type == PullParser.END_VALUE) {

        if(event.name == "name") {
          star.name = event.text;
        }
        else if ( event.name == "content" ){
          star.wish = event.text;
        }
        else if ( event.name == "id" ){
          star.id = event.text;
         }
        else if ( event.name == "color" ){
          star.whichColor = event.integerValue;
        }
        else if ( event.name == "time" ){
          star.time = event.text;
        }
        else if ( event.name == "location" ) {
          var pos = event.text.indexOf( "_" );
          var x = event.text.substring(0,pos);
          var y = event.text.substring( pos+1 );

          star.translateX = Float.parseFloat(x);
          star.translateY = Float.parseFloat(y);
        }
        else if ( event.name == "Star" ){
          star.changeStatus();
          star.onMousePressed = handleClick;

          insert star after stage.scene.content[currentIndex++];
          star = Star {};
        }
      }
    }
  }


The JavaFX client uses the class HttpRequest to communicate with the server. HttpRequest allows us to use GET and POST method to send requests to the server. Usually, we only need to override some methods of this class. As shown in ServerConnector.fx below, we rewrote the onOutput and onInput functions to invoke the saveStar service from the server.

/*
 * ServerConnector.fx
 * @author Henry Zhang   http://www.javafxgame.com
 */
package wishtree;
import java.net.URLEncoder;
import java.io.*;
import javafx.io.http.*;

var baseURL = "http://localhost:8888/wishtree/";

public var serverURL1 = "{baseURL}getallstar.php";
var serverURL2 = "{baseURL}savestar.php";

public class ServerConnector extends HttpRequest {
  var star : Star = null;
  var paramString : String ;

  override var onOutput = function( os: java.io.OutputStream): Void {
        try {
            os.write(paramString.getBytes());
        } finally {
            os.close();
        }
    };

  override var onInput = function(is: java.io.InputStream) {
     try {
           var br = new BufferedReader( new InputStreamReader( is ) );
           var line: String;

           while ( ( line=br.readLine() ) != null )
           {
             if ( (star != null) and (star.id == "")  )
                star.id = line;
            }
        } finally {
            is.close();
        }
  };

public function saveStar( s: Star ) {
  if ( s.id.length() == 0 )
    star = s;

  paramString = encode("name", s.name);
  paramString += "&{encode("id", s.id)}&" ;
  paramString += encode("location", "{s.translateX}_{s.translateY}" );
  paramString += "&{encode("content", s.wish )}";
  paramString += "&{encode("email", s.email)}" ;
  paramString += "&{encode("time", s.time)}&" ;
  paramString += encode("color", "{s.whichColor}" );

  headers = [
        HttpHeader {
            name: HttpHeader.CONTENT_LENGTH;
            value: "{paramString.getBytes().length}";
        }
       ];

  method = POST;
  location = serverURL2;
  start();
 }
}

function encode( k: String, v:String): String {
    var result = URLEncoder.encode( k, "UTF-8");
    var value = URLEncoder.encode( v, "UTF-8");
    result += "={value}"
}


On the server side, the PHP code is quite straightforward. Basically, it gets the parameters from the request and convert them into SQL statement for MySQL database. After getting the data from MySQL, it returns the data in JSON format.


Finally, I would discuss how to tie up all the components together. First, we build the JavaFX client in NetBeans. The products are a jar file and a JNLP file. We modify attributes in the JNLP file to match the deployment environment. The most important is to set the correct value of the “codebase” attribute. Then we upload the jar and JNLP files to a folder on a web server. This folder should match the one specified in the codebase attribute. The next step is to deploy the PHP scripts, for simplicity, we just upload the scripts under the same folder where we put the jar. In the scripts, be sure to change the user name and password of the database. In your MySQL database, create a table to store the wish data. The last thing would be putting a link in a web page which contains the web start link to your JNLP file.


For source code, you can get it from the download page of this site. As shown in the architectural figure, there are codes of server side(Mysql and PHP) and client side(JavaFX), respectively. Be sure to read the file README.txt before you try the code.


If you have any questions, please leave comments.



Other JavaFX articles:

JavaFX Online Game Prototype: Wish Tree (1)

JavaFX Menu       Java Code Calls JavaFX APIs


Comments (3) Aug 28 2009

Hang a Lucky Star on a Wish Tree

Posted: under JavaFX Games, Wish Tree.
Tags: , , ,

It is a game like program for my kids, or say it is some fun for everyone. You can make a wish and place it on a Wish Tree. Hopefully, it will come true some time later. A star hanging on the tree denotes a wish. For phase I, I am building this wish tree as a standalone version. In Phase II, I will make an internet version, so that everyone can place wishes on the same tree.


Wish tree: http://www.javafxgame.com


When you click on the wish tree, a wish star appears and a dialog is shown to allow you to enter your name and your wish. Later on, if you click on the same star, you have a chance to modify your wish. My daughter likes it very much, she places all kinds of wishes( such as I want a Barbie) on the tree and really hope they will come true soon. You can have some fun by clicking on the below image to place your wish too. JDK1.5+ is required, JDK 1.6 U13+ is better:


Wish tree: http://www.javafxgame.com

click to start Wish Tree


The program utilizes the features of JavaFX effect classes. The source code can be downloaded here. I will write a few articles to explain how to create such an application.

Comments (1) Jun 18 2009