If you took a look at my previous post GWT and NetBeans you should know how to set up the bare minimum for a GWT project in NetBeans. In this post, we are going to see how to consume a free online web service LyricsWikia from our GWT project. The SOAP based LyricsWikia web service allows you to search their database to return song lyrics for a given song title, album or music artist.
You can use another web service of your choice instead of LyricsWikia if you prefer, just do some googling for free web services. Some examples are Amazon (AWS), weather services, YouTube, post-code/location finders etc.
Normally when I consume web services in NetBeans, I go for JAX-WS style because it is the successor to JAX-RPC. Unfortunately in this case the WSDL we are going to use is old and is an RPC style one. So to accomodate this you need to do the following:
Open NetBeans (I’m using 6.8) and select Tools –> Plugins then navigate to the Available Plugins tab. Check JAX-RPC Web Services and install. We’ll get back to the web service later, for now we need to set up the project. If you haven’t done so already, you need to create a GWT project in NetBeans, see this post GWT and NetBeans for how to set up a basic project. The first thing we are going to do to extend this project is create a GWT RPC Service. Using this architecture the GWT client side code will call the GWT server side code using asynchronous RPC calls. The GWT server side code will act as a web service client and consume the web service, then it will return the results to our GWT client side code for presentation in the browser.
In your NetBeans project go to New –> GWT RPC Service… and make the service name something really original like GwtRpcService. Make sure the Create Usage Example Class checkbox is checked, this will make our life easier. Next, have a look at the generated classes. In the com.client package you should now have GWTRPCService.java, GWTRPCServiceAsync.java and GWTRPCServiceUsageExample.java. In the com.server package you should now have GWTRPCServiceImpl.java. An RPC service method has been created for us myMethod(String s) we will modify this method to something more suitable for our requirements.
Open GWTRPCService.java and replace:
public String myMethod(String s);
public String getLyrics(String artist, String song);
Open GWTRPCServiceAsync.java and replace:
public void myMethod(String s, AsyncCallback<String> callback);
with:
public void getLyrics(String artist, String song, AsyncCallback<String> callback);
Open GWTRPCServiceImpl.java and replace:
public String myMethod(String s) {
// Do something interesting with 's' here on the server.
return "Server says: " + s;
}
with:
public String getLyrics(String artist, String song)
{
return null;
}
I’m not going to go into great detail about what we just did because you can google that yourself, basically we have an RPC service method getLyrics(…) and we will be calling this method asynchronously. In the implementation class we don’t just want to return null, we want to call a suitable LyricsWikia web service operation and return the result.
OK next problem. The LyricsWikia WSDL will not work out of the box for us Java heads. You might think, oh great example. But this is reality. In my experience this happens a lot and small changes need to be made to get things working in your preferred IDE – or more specifically whatever you are using to generate client stubs. To overcome this, we need to download the WSDL to our local machine and make a couple of changes then use this local version to generate our client stubs instead of the URL for the deployed WSDL.
Get the LyricsWikia WSDL here. If you are are using Safari like me and you browse to this you might think this doesn’t look like a WSDL. It must be the way Safari renders WSDL files or something but I had to go View –> View Source then Select All, Copy and Paste the selection into a text editor and Save it. I saved the file as LyricsWikia.wsdl.
Open LyricsWikia.wsdl and replace:
<xsd:attribute ref="SOAP-ENC:arrayType" wsdl:arrayType="AlbumResult[]"/>
with:
<xsd:attribute ref="SOAP-ENC:arrayType" wsdl:arrayType="tns:AlbumResult[]"/>
Replace:
<xsd:attribute ref="SOAP-ENC:arrayType" wsdl:arrayType="AlbumData[]"/>
with:
<xsd:attribute ref="SOAP-ENC:arrayType" wsdl:arrayType="tns:AlbumData[]"/>
Save the file.
In the NetBeans project go to New –> Web Service Client… Select Local File and browse to the local copy of the WSDL that we just edited. Specify a Package name, I will use com.lyricsWikia. For this particular web service, the client style must be JAX-RPC Style. Select Finish.
In NetBeans 6.8, if I try and build the project at this point, I will see the following error message:
../nbproject/build-impl.xml:422: taskdef class com.sun.xml.rpc.tools.ant.Wscompile cannot be found BUILD FAILED (total time: 0 seconds)
Well that is not cool. To fix it, in the NetBeans Files view locate your projects root folder –> nbproject folder –> project.properties and right click Edit.
Replace:
wscompile.classpath=${wscompile.tools.classpath}:${j2ee.platform.wscompile.classpath}
with:
wscompile.classpath=${wscompile.tools.classpath}:${j2ee.platform.wscompile.classpath}:${javac.classpath}
If you open GWTRPCServiceUsageExample.java and comment out the following line of code you should now be able to build the project successfully:
getService().myMethod(txtUserInput.getText(), callback);
It’s now time to implement our getLyrics(…) method now that we have generated our web service client stubs (they should be visible under Generated Sources (jax-rpc)).
Open GWTRPCServiceImpl.java and replace:
public String getLyrics(String artist, String song)
{
return null;
}
with:
public String getLyrics(String artist, String song)
{
LyricWiki service = new LyricWiki_Impl();
LyricWikiPortType port = null;
String lyrics = "";
try
{
port = service.getLyricWikiPort();
((Stub)port)._setProperty(javax.xml.rpc.Stub.ENDPOINT_ADDRESS_PROPERTY, "http://lyrics.wikia.com/server.php");
}
catch(ServiceException ex)
{
ex.printStackTrace();
}
boolean exists = false;
try
{
exists = port.checkSongExists(artist, song);
if(exists)
{
LyricsResult result = port.getSong(artist, song);
lyrics = result.getLyrics();
}
else
{
lyrics = "Sorry, no lyrics available";
}
}
catch(RemoteException ex)
{
ex.printStackTrace();
}
return lyrics;
}
You will also need to add the following import statements to the top of the class:
import com.lyricsWikia.LyricWiki; import com.lyricsWikia.LyricWikiPortType; import com.lyricsWikia.LyricWiki_Impl; import com.lyricsWikia.LyricsResult; import java.rmi.RemoteException; import javax.xml.rpc.ServiceException; import javax.xml.rpc.Stub;
We are nearly done. Now, we just need to modify our GWT client side code to call our RPC service method. We will create a very simple form that allows the user to pass in a music artist and a song title as a parameter and press a button to retrieve the lyrics.
Modify GWTRPCServiceUsageExample.java so it looks like this:
package com.client;
import com.google.gwt.core.client.GWT;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.TextBox;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.user.client.ui.TextArea;
/**
* Example class using the GWTRPCService service.
*
* @author nes
*/
public class GWTRPCServiceUsageExample extends VerticalPanel {
private TextArea txtAreaServerReply = new TextArea();
private TextBox txtArtistInput = new TextBox();
private TextBox txtSongInput = new TextBox();
private Button btnSend = new Button("Get Lyrics!");
public GWTRPCServiceUsageExample() {
add(new Label("Music Artist: "));
add(txtArtistInput);
add(new Label("Song: "));
add(txtSongInput);
add(btnSend);
txtAreaServerReply.setSize("500px", "500px");
add(txtAreaServerReply);
// Create an asynchronous callback to handle the result.
final AsyncCallback<String> callback = new AsyncCallback<String>() {
public void onSuccess(String result) {
txtAreaServerReply.setText(result);
}
public void onFailure(Throwable caught) {
txtAreaServerReply.setText("Communication failed");
}
};
// Listen for the button clicks
btnSend.addClickHandler(new ClickHandler(){
public void onClick(ClickEvent event) {
// Make remote call. Control flow will continue immediately and later
// 'callback' will be invoked when the RPC completes.
getService().getLyrics(txtArtistInput.getText(), txtSongInput.getText(), callback);
}
});
}
public static GWTRPCServiceAsync getService() {
// Create the client proxy. Note that although you are creating the
// service interface proper, you cast the result to the asynchronous
// version of the interface. The cast is always safe because the
// generated proxy implements the asynchronous interface automatically.
return GWT.create(GWTRPCService.class);
}
}
Modify codenesEntryPoint.java (or your entry point class) so it looks like this:
package com.client;
import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.user.client.ui.RootPanel;
/**
* Main entry point.
*
* @author nes
*/
public class testEntryPoint implements EntryPoint {
/**
* Creates a new instance of testEntryPoint
*/
public testEntryPoint() {
}
/**
* The entry point method, called automatically by loading a module
* that declares an implementing class as an entry-point
*/
public void onModuleLoad() {
RootPanel.get().add(new GWTRPCServiceUsageExample());
}
}
Now Build, Deploy and Run the project. If you are having any problems check your Glassfish server log for errors or debug the project in NetBeans. To debug the project in NetBeans, GWT Development Mode needs a browser plugin. You can also use Firebug (Mozilla plugin) to debug inside your browser.
Note. The LyricsWikia web service will only return a small portion of the song lyrics if they are available. This is due to licensing restrictions/fair use policy.


First of all, amazing post. I was searching for this for along time.
By i have a question:
If the WSDL is JAX-WS, not JAX-RPC, and the return from the AsyncCallback callback is a List ?
How can i pass the Java class created by the WSDL ( to Java ) to the client side ?
I will give an example:
After doing the “Web Service Client” with JAX-WS, it generated my stubs from the wsdl. Now i drag and droped my getPostalAddress ( from the to the “Web Service References”, choosed the Endpoint ) to GWTRPCServiceImpl.java :
public PostalAddressPostalAddressWithCountType getPostalAddress(java.lang.Integer entity, java.lang.Integer contact, java.lang.Integer id, java.lang.Boolean primary, java.lang.Integer limit, java.lang.Integer offset, java.lang.String agent) {
org.postaladdress.pa.PostalAddressPortType port = service.getPostalAddressHttpSoap11Endpoint();
return port.getPostalAddress(entity, contact, id, primary, limit, offset, agent);
}
Now the problem is , because the return from port.getPostalAddress(entity, contact, id, primary, limit, offset, agent) comes with JAXBElement ‘s, how can i passed to the client side. I created and Java Class on the Server side but the compiler tells me that are incompatable.
Help?
My WSDL : http://dl.dropbox.com/u/6197079/postal_address.wsdl
My generated stub : http://dl.dropbox.com/u/6197079/stub_postal_address.txt
Thanks Vitor,
It looks like there are some possible options for you outlined in this GWT Issue. I haven’t tried them however so I don’t know if it can be done. I just create my own serializable client/server shared objects and use them to pass the web service response back to the client (so transfer what you need from the returned wsimport object to your own object and return that instead). I realise this isn’t ideal but it hasn’t been a major problem for my projects so far.
this is a great tutorial!!! i cant wait try it out
The content of this article is OK, but why oh why did you render the source code examples with shadows? This is horrible
It wasn’t deliberate, my syntax highlighter was inheriting text-shadow CSS from my theme. Fixed.
Thanks for this post this is very close to my requirment,
But im using eclipse and can not understand where to change the wscompile.classpath=..
setting.
Please give a solution for eclipse
Hi Minhaj,
I will try to reproduce the problem you are having in Eclipse when I get some spare time.
In the mean time maybe have a look in your build.xml file to see if that gives you any leads on where to configure the wscompile.classpath setting in Eclipse.
Best of luck.
Great post, it looks like what I want to do. But I have a question: The HTTP request is asynchronous itself. How do you make it look like a synchronous call? I’m making a RequestBuilder call from my RPC implementation class, and I thought I would need to use the callback defined in the class to my RPC service, but from the implementation code, I don’t see how I could access the callback. How do I handle the 2 levels of asynchronous calls?
Hi Kim,
I’m not sure I’m following you, let me know if I am on the wrong track.
I haven’t used RequestBuilder before but I had a quick look here http://code.google.com/webtoolkit/doc/2.0/FAQ_Server.html#How_do_I_make_a_call_to_the_server_if_I_am_not_using_GWT_RPC? and it appears to be an alternative way for GWT client side code to communicate with a server (alternative to GWT RPC).
So when you say “I’m making a RequestBuilder call from my RPC implementation class” – it sounds like you are using RequestBuilder in an RPC service implementation which seems odd, If you are using RequestBuilder wouldn’t you make the POST/GET client side? Can you clarify your architecture for me?
What do you mean by “how do you make it look like a synchronous call?”