-
Notifications
You must be signed in to change notification settings - Fork 2
How to use GWT for RPC
Here's a brief overview for using GWT to send information to and from the central game server:
The basic idea behind GWT is that it uses a call/response model (i.e. HTTP requests) to send object information over the network. In order for a client to receive information, it must first make a request for it (in other words, the server cannot actively "push" information up to the client at will). So, every procedure call using GWT's RPC (remote procedure call) framework must somehow start on the client side.
For this project, there are three important files which GWT uses to define these requests. These files are:
- SimpleSimulator.java (found in com.client)
- SimpleSimulatorAsync.java (found in com.client)
- SimpleSimulatorImpl.java (found in com.server)
The first two files are just interfaces which specify how the remote methods are called. The third file actually specifies the implementation of these methods and contains all of the data which exists on the server-side execution of the program (you can see that it contains a Controller, which itself contains a GameModel object).
If you want to add your own remote method, it's pretty straightforward. As an example, let's say we want to make a method that increments a number on the server and then returns the number to the client. First, we define the method in SimpleSimulator.java. I'm going to make it take an argument, just for teaching's sake:
// increments the server's number and returns it to the client
int incrementNumber( String playerName ); Next, we define the method again in SimpleSimulatorAsync.java. This definition, however, includes an asynchronous callback routine that the client executes when the server finishes processing the request and returns the result. Here is the implementation:
void incrementNumber( String playerName, AsyncCallback<Integer> callback);Note that this method's return type is void. The AsyncCallback is what actually performs the "returning" action. Usually this callback is defined anonymously on the client-side. Also note that we still process the playerName argument. If we had more arguments, we must list them in the same order that they appear in the method header we defined in SimpleSimulator.java.
Now, we implement the server-side behavior of the remote method. We do this in SimpleSimulatorImpl.java. Let's suppose that there exists an instance variable in SimpleSimulatorImpl.java which is our special number:
private int theNumber = 0;Now we can have it increment whenever a player makes a remote call to the incrementNumber method. One possible implementation could be:
public Integer incrementNumber( String playerName ) {
// We could do something here with playerName if we wanted to
return ++theNumber;
}We can now successfully increment the number on the server! However, once this action is performed, it is likely that the client will want to do something with the number that it receives back. This is where we create our callback routine. Right now, we have everything set up so that the ClientModel class contains an instance of SimpleSimulator, which is instantiated at the top of ClientModel:
simpleSimulator = GWT.create(SimpleSimulator.class);Here, simpleSimulator is what we use to make these remote calls, as well as define what to do when the request succeeds or fails. Here is one possible implementation, using "ABCDEFG" as our playerName. Note that the anonymous AsyncCallback class is parameterized according to the return type of the RPC.
simpleSimulator.incrementNumber("ABCDEFG", new AsyncCallback<Integer>() {
@Override
// If the request fails, we might want to deal with it in a certain way.
// Usually it's a good idea to try again (such as scheduling another request
// later on).
public void onFailure(Throwable caught) {
Console.log("Request failed!");
}
@Override
// The onSuccess method is run when the request is successfully processed
// Here, the number that gets returned from the server is passed in as an
// argument to the onSuccess method. Let's just have it print the
// returned number to the console.
public void onSuccess(Integer number) {
Console.log("We incremented the number, which is now " + number);
}
});And that's it! We can use simpleSimulator's methods to communicate with the server at any time. We can stick one of these calls inside of an event listener, or put them inside of a timer, or whatever you want to do. One thing to note is that GWT won't let you send just any piece of data to/from the server. There are a few restrictions on whether or not you can send user-defined classes to the server. These restrictions are:
- The class must implement java.io.Serializable
- The class must have a zero-argument constructor (it doesn't have to do anything though).
- The class must be located in com.shared (or in any subpackage of com.shared).
- All data within the class must be GWT compliant.
Here is an example of a GWT compliant class:
// Must be in com.shared
package com.shared.foo.bar;
import java.io.Serializable;
// Must implement Serializable
public class Foo implements Serializable {
public int bar;
public String baz;
// Zero argument constructor required
public Foo() {}
public Foo( int i, String s ) {
this.bar = i;
this.baz = s;
}
// And then we can put our methods and stuff down here...
}And that's pretty much all you need to know to use GWT for this project. Have fun!
- Sean