What this tutorial does, is walk you through the stages of creating a project which will let you connect to Java code on a server. You don't need to set anything else up for this to work if you are using Eclipse.
Unfortunately, there's no demo here since I can't run Java on this hosting service. At the end of this page there's a link where you can download the demo source code.
If at any point I seem to be stating the bleedin' obvious, then please just skip that bit, realising that you are one of the blessed. I try to bear in mind that it's only 'bleedin' obvious' when you know about it. (Most people think a mouse is an animal - I ask you!) And if I keep repeating myself, it's just because I've got children, a dog, elderly parents, voicedial, children and a dog.
One of the reasons for writing this site is that there was nothing out there for people like me who were experienced programmers but had never done Java before. It might all be obvious to Java programmers (it may not, I don't know) but I had no idea what I was doing when I first tried to get this working. Over the months it started to make sense, but if I'd had a page like this, it would have taken about half an hour. I hope I can explain it well enough for you to get the gist.
This demo is made up of five files. One of these isn't strictly necessary, but it will simplify things in more complicated applications, so I've included it.
Without the extra file, there are four elements to setting it all up, two for the client side, and two for the server. Obviously there is the Java program on the server and the Java(ish) code for the client side. There are two interfaces, one for the server-side code to use, and one for the client-side code to use. The GWT compiler straddles the gap between the two interfaces for you, so you don't have to worry about that.
All you need worry about is this:
GWT Code <===> InterfaceAsync <===> Interface <===> Server Code
As I said, there is one more element in the demo. I've split the GWT code into two sections as I do in larger apps. Since you may call a server service from more than one place, it makes sense to put the common code in a class of its own, and the program calls that from wherever.
It also makes sense to abstract away all the implementation-specific code so that if you have to use, say, use PHP and RequestBuilder instead for some reason, you just have to write one new class which does the same thing. Job done.
This is pretty central to the whole RPC thing. It's what your server application is supposed to comply with (and also what something that GWT creates when it compile has to conform to too, but you never see that).
All we are doing in this demo is trying to prove we can contact the server and get something back from it. In order to show how to pass information to the server and then get something back, we'll need an interface that allows us to send a string to it and get a string back.
I'm going to call the method on the server testRPC() and pass
it a string containing a message. The server app will return a confirmation
of what the message is, and when it got it, just so we can see it is all working
OK.
import com.google.gwt.user.client.rpc.RemoteService;
public interface RPCInterface extends RemoteService
{
public String testRPC(String message);
}
The asynchronous interface is the one that your client-side code will use. Your code will call the service but not wait for a reply (hence the 'asynchronous' of course). The reply will go somewhere else.
That 'somewhere else' is a method in the client-side code and you have to tell the
gizmo that does all the hard work where this method is. Since the calling code is
not going to deal with the callback, the return type of the calling must be
void. In order for the system to know where to send the result of the call,
the calling code passes it the routine.
So, in clientCallsTheServer you call methodOnTheServer
passing it (in our case) a string and a callbackMethod and then it
goes on its way without waiting for an answer.
Some time later, the callbackMethod is run with the result of the
call. Here's our asynchronous interface. It MUST have the same name as the
synchronous (server-side) interface, but with 'Async' tagged on the end. It must
also be in the same place as the synchronous interface, i.e. somewhere inside the
'client' bit of your project.
import com.google.gwt.user.client.rpc.AsyncCallback;
public interface RPCInterfaceAsync
{
public void testRPC(String message, AsyncCallback callback);
}
The service's only obligation is to implement the interface. Here as you can see, all we do is return the message we get given, but wrapped in a bit of bling. Dead easy.
Whereas all the other files, including both interfaces, are in the /public/ folder, this one needs to be on its lonesome in the /server/ folder.
import java.text.DateFormat;
import java.util.Date;
import com.google.gwt.user.server.rpc.RemoteServiceServlet;
import com.roughian.rpcjava.client.RPCInterface;
public class RPCImpl extends RemoteServiceServlet implements RPCInterface
{
private static final long serialVersionUID = 1L;
public String testRPC(String message)
{
Date now = new Date();
String dtm = DateFormat.getTimeInstance(DateFormat.MEDIUM).format(now);
return "Got the message '" + message +"' at " + dtm;
}
}
'The Abstraction Layer', huh? Well you and I know it's two lines of code and a couple of declarations, but it sounds good when you are trying to blind someone with science 'The forward pointers of the flugel indexing in the data abstraction layer of the remote services asynchronous interface's logical view were corrupted during the overnight offset reconstruction process. It's a known Microsoft problem. I don't know why you insist on having the damn stuff. Still it keeps me in overtime.'
We put the access-method-specific stuff here. You don't need to know what it is doing in order to use it, which is probably just as well. Google's description for the ServiceDefTarget (An interface implemented by client-side RPC proxy objects. Cast the object returned from GWT.create(Class) on a RemoteService should be cast to this interface to initialize the target URL for the remote service.) doesn't actually make grammatical sense, let alone anything else.
Personally, I just let it get on with it. I don't even try to understand it, if it works, that's fine with me. A bit like the wife. Ex-wife, actually - can't think why she left like that.
import com.google.gwt.core.client.GWT;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.rpc.ServiceDefTarget;
public class RPCService implements RPCInterfaceAsync
{
RPCInterfaceAsync service = (RPCInterfaceAsync) GWT.create(RPCInterface.class);
ServiceDefTarget endpoint = (ServiceDefTarget) service;
public RPCService()
{
endpoint.setServiceEntryPoint(GWT.getModuleBaseURL() + "rpc");
}
public void testRPC(String message, AsyncCallback callback)
{
service.testRPC(message, callback);
}
}
The upshot is that as long as we do the first three lines of code, we can then run our service method on the server and it will return the result to the callback routine.
The highlighted method above is all you need to copy and paste in order to create a new method - of course you have to define it in both interfaces as well, and create the method on the server-side. If you didn't abstract these methods into this file, you'd have to do all of it, every time. Instead, you can use just one line to call a method here.
We can now actually make a call to the server and get a response. First, we create an instance of the class above. In a production program you'd do this at a class level, or even at the application level.
We need to create the callback method, and we need to make the call. The important lines are highlighted in the following code box.
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.ClickListener;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.HasAlignment;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.google.gwt.user.client.ui.Widget;
public class RPCDemo extends Composite
{
VerticalPanel panel = new VerticalPanel();
public RPCDemo()
{
initWidget(panel);
panel.setHorizontalAlignment(HasAlignment.ALIGN_CENTER);
panel.setWidth("100%");
Button button = new Button("Test RPC", new ClickListener()
{
public void onClick(Widget sender)
{
while (panel.getWidgetCount() > 1)
panel.remove(1);
RPCService rpc = new RPCService();
rpc.testRPC("Hello", callback);
}
});
panel.add(button);
panel.setCellWidth(button, "100%");
}
AsyncCallback callback = new AsyncCallback()
{
public void onFailure(Throwable caught)
{
panel.add(new HTML("Failed:" + caught.getMessage()));
}
public void onSuccess(Object result)
{
while (panel.getWidgetCount() > 1)
panel.remove(1);
panel.add(new HTML((String) result));
}
};
}
If you want to try it out for yourself, here's the download link.