MCS-378 Lab 4: Communication Middleware, Fall 2013

Due: December 12, 2013

Introduction

In this lab, you (and, optionally, a partner) will complete development of a client/server version of the "15 Puzzle" (sliding tile) application using JMS (Java Message Service) to transmit JSON (JavaScript Object Notation) messages from the clients through a queue to the server and from the server through a topic to the clients. I am providing the stand-alone (non-JMS) version of the program as well as the server side of the JMS version and a template of the client side. You are to complete the client side.

My instructions assume you will be doing this on the computer you have been issued, running the Ubuntu distribution of Linux. You can actually use any system that has a current version of Java EE 7; only the installation instructions are Ubuntu-specific.

Time-consuming but mindless preparation

To get Java EE 7 installed requires quite a few steps. Hopefully I've remembered to list them all here:

  1. Install Oracle Java 7 as described on the linked web page and also set the environment variables as described on that same page.

  2. Install the maven project management tool:

    sudo apt-get install maven
    
  3. Install some libraries that are needed by the updatetool for glassfish, the Java EE server:

    sudo apt-get install ia32-libs
    sudo apt-get install libjpeg62:i386
    
  4. Install the Java EE 7 Software Development Kit as described in the tutorial.

  5. Run the updatetool as as described in the tutorial. You should be able to do this using the following command in a shell:

    ~/glassfish4/bin/updatetool
    

    It is particularly important that you download the update for the Java EE 7 Tutorial. There were some changes in the JMS example software we'll be using. Working around the differences in the old version would be possible, but updating to the latest will save you grief.

    Note that if you set your shell's command search path as the tutorial suggests, you would be able to abbreviate the above command to just

    updatetool
    

    Similar abbreviation would be possible with other commands that I show below. I'm showing the full versions so that even if you don't set your search path, you'll be OK.

  6. If you like working within an integrated development environment (IDE), you might consider installing the NetBeans IDE as described in the tutorial, because it is the IDE that the tutorial describes. I haven't tried it out myself. Other IDEs such as Eclipse might also be options. I just edited the Java source files using a normal text editor (emacs) and ran the Maven build process from within a shell.

  7. The installation process normally will start up the GlassFish server, but you'll need to restart it every time you reboot. This is described in detail in the tutorial but the short version is to use this command in a shell:

    ~/glassfish4/bin/asadmin start-domain
    
  8. Create the resources for the tutorial's simple JMS examples. We'll be using those examples as a starting point, and for simplicity our puzzle program will use the same resources. In particular, our client and server will communicate through a queue called jms/MyQueue and a topic called jms/MyTopic. The directions for creating these resources are in the tutorial; a more full version of the commands follows:

    cd ~/glassfish4/docs/javaee-tutorial/examples/jms/simple/producer
    ~/glassfish4/bin/asadmin add-resources src/main/setup/glassfish-resources.xml 
    
  9. Build the simple JMS examples as described in the tutorial. Assuming you are doing this in the shell rather than with NetBeans or another IDE, the full version of the commands would be as follows:

    cd ~/glassfish4/docs/javaee-tutorial/examples/jms/simple
    mvn install
    
  10. Check that you can use the example programs to send and receive messages using the queue and topic as described in the tutorial. Note that these programs will be slow in starting up and will produce some extra informational messages at the start. For an example of the full version of the commands, here are the ones for running the producer:

    cd ~/glassfish4/docs/javaee-tutorial/examples/jms/simple/producer
    ~/glassfish4/glassfish/bin/appclient -client target/producer.jar queue 3
    

A possibly useful extension to a tutorial example program

Because I am providing a working server for the puzzle program, it is entirely possible that you could just test your client using this. If you want to see the messages, you can also use one of the consumer example programs from the tutorial. However, you might find it interesting to be able to manually send messages as well during the testing and debugging process. I know I found that helpful while working on the server side.

The example producer program has the limitation that it sends a specific format of message that is hardwired into it. Your program won't be interested in receiving messages saying "This is message 1 from the producer". Therefore, I have made a slight variant of the tutorial's producer, called flexproducer, which reads from the standard input (normally your keyboard) and sends each line of input as a message.

You can download this program as flexproducer.zip, unzip it, and then build and run it analogously to the tutorial's examples:

cd flexproducer
mvn package
~/glassfish4/glassfish/bin/appclient -client target/flexproducer-1.0.0.jar topic
Something to send.
More to send.
(control-D when done)

The puzzle application

You can download the puzzle application as puzzle.zip, unzip it, and build it using

cd puzzle
mvn package

After building the application in its supplied form you can run any of the following three commands:

~/glassfish4/glassfish/bin/appclient -client target/puzzle-1.0.0.jar
~/glassfish4/glassfish/bin/appclient -client target/puzzle-1.0.0.jar server
~/glassfish4/glassfish/bin/appclient -client target/puzzle-1.0.0.jar client

These run the stand-alone version of the program, the server, and the client. However, the client will report an error because the ModelProxy.java source file is just a template waiting for you to fill it in.

We will spend class time on November 26th on the structure and function of this program.

Suggested plan of work

Here is a suggested plan of work for what you need to do in ModelProxy.java:

  1. Delete the throwing of "Not yet written" errors from setModelListener and the ModelProxy constructor. Rebuild the puzzle package using the mvn package command. At this point, you ought to be able to start up a puzzle client as shown on the assignment web page. It will come up with all the tiles blank. If you push on the Initialize button or any of the blank tile buttons, you will set a "Not yet written" error. Exit from the client.

  2. In the body of initializeTiles, replace the throwing of a "Not yet written" error with a line of code that sends to the commands Destination the text

        ["init"]
    

    including the brackets and double quote marks. This is a one-element JSON array containing the string "init". You can find examples of sending text to a JMS Destination in both the puzzle's Listener class (the server side) and the Java EE tutorial's producer example (as well as my flexproducer variant). In order to make this possible, you will also need to add some instance variables to the ModelProxy class and put some code in the constructor to initialize these instance variables. Rebuild the puzzle package again and re-run it. Again it should come up with all tiles blank. But now if you press the Initialize button, you won't get an error. In another terminal window, run the Java EE tutorial's asynchconsumer program with the queue destination. You should see the ["init"] message that the client program should have queued up. If you click the button again, you should see the message again. If your client passes these tests, you can kill the asynchconsumer (using control-c) and rerun it with the topic command line argument instead of queue. Now in a third terminal window, run the puzzle server. Although the client tiles will remain blank, you should see using asynchconsumer that the server is retransmitting the initial board configuration each time you click on the Initialize button. Exit from the client after testing it. If these tests aren't passing work to get them to pass before moving on.

  3. Modify the pushTile method in the ModelProxy class analogously to initializeTiles. The message it sends should have this form

        ["push",0,3]
    

    for a push in the upper right corner (row 0, column 3). This is a three-element JSON array. Rebuild and run the puzzle client. You still should have blank tiles, but now if you push them you should be able to see in the asynchconsumer's output that the server is actually sliding the tiles appropriately. For example, pushing the upper right tile results in the first row now being ["1","2","3",""] and the last row being ["13","14","15","12"]. If this isn't working, you can get more insight into what is going wrong by killing off the puzzle server and the asynchconsumer and restarting the asynchconsumer with queue. That will show you whether your puzzle client is sending the correct command. As usual, get this portion of the work debugged before moving on.

  4. Fill in the setModelListener method with code that does two things: (a) records the ModelListener into an instance variable for later use, (b) transmits a ["send"] command to the commands destination analogously to the ["init"] command. If you rebuild and re-execute the client, you should be able to see that when it first starts up, it uses the ["send"] command to prompt the server to transmit its state.

  5. Change the ModelProxy constructor to set this ModelProxy to be the MessageListener for a consumer on the states Destination. You can find an example of this in the puzzle's Listener class (the server) as well as in the tutorial's asynchconsumer. If you re-build and re-execute the client, you should find that now whenever the sever (or flexproducer) sends a puzzle state to the topic, the "Not yet written" error is thrown by the onMessage method.

  6. Fill in the onMessage method with code to store the received state into an instance variable and invoke the ModelListener's onModelChanged method (assuming a non-null ModelListener has been set). Whenever the server transmits a puzzle state, you should see "Not yet written" being thrown by the get method because the GUI will call this method (16 times) in response to the onModelChanged invocation. (To further confirm that you are on the right track, you could put in some temporary code to print out the state.)

  7. Finally, you should fill in the get method with code to extract the relevant String from the instance variable where onMessage stashed away the incoming state. At this point, the client should be fully functional.

What you should turn in

You should email me a completed version of ModelProxy.java. If you want to do something that extends beyond this, I'd be happy to talk it over with you. However, I'd be satisfied with just a working version of this one class.


Instructor: Max Hailperin