X

Geertjan's Blog

  • August 7, 2005

Eating Web Services in NetBeans IDE 4.1

Geertjan Wielenga
Product Manager

A web service is a bundle of functionality that someone somewhere makes available over the Internet. The bundle of functionality is a component that conforms to standards that make it externally available. A WSDL file describes all the operations made available by the web service. If you want to interact with the web service, you have to comply with the WSDL file. The "you" interacting with the web service is called a "web service client". It consists of code that finds the web service, invokes operations on the web service, and handles returned data. Normally, this interaction is called "consumption". But, just for fun, and to make for a more interesting blog entry title, let's called it "eating" instead. In this blog entry, we'll first look at the main tools provided by NetBeans IDE 4.1 for the creation, development, compilation, and deployment of web service clients. Then, we'll create a client that eats a simple web service. (Okay, we've justified the blog entry title, and so this is the last time we'll use "eating".) The client will interact with a web service that returns quotations whenever the browser is refreshed. After that, being more comfortable with the process and the tools, we'll interact with a more complex web service -- it interprets a given piece of text and produces data on the incorrectly spelled words. Yes, a spell checker! Hurray. So, first, lets look at the tools.

Tools


For the creation of web service clients, NetBeans IDE 4.1 provides a client creation tool -- the Web Service Client wizard that generates code for looking up a web service. It also provides tools for developing the created web service client -- a work area consisting of nodes in the Projects window and a built-in client for testing and analyzing web services. These tools are part of the standard NetBeans IDE installation, they're available straight out of the box and no plug-ins are needed. Each will be looked at in turn below.

Creation.

First create a web application (Ctrl-Shift-N) and make sure that you specify the Sun Application Server as your target server, because the wscompile tool, used to compile web services, comes with this server only. Once you have the web application with the required server, right-click the project node, choose New > File/Folder and then choose Web Service > Web Service Client. In the Web Service Client wizard you specify the WSDL file that you want to interact with, click Retrieve WSDL to download it, and enter a package name.

Then you click Finish. Here's the magical wizard that provides all the wiring that web service interaction requires (click to enlarge):

In this case, we'll interact with a Quotation service. Whenever the service's operation is invoked, a quotation is returned. In fact, this is the simplest web service imaginable -- no arguments are passed at all, you'll just refresh the browser whenever you want to retrieve a new quotation. So, in the WSDL URL above, I entered the following URL:

http://www.seshakiran.com/QuoteService/QuotesService.asmx

Completing the Web Service Client wizard means that you've covered virtually everything covered in SOAP with Attachments API for Java chapter of the J2EE Tutorial for NetBeans IDE 4.1. Not bad, huh. Soon you'll see that you'll only need to code the relationships between the arguments required for the operations to be invoked, and Bob's your uncle.

Development.

After completing the Web Service Client wizard, using the WSDL file above, you see this in the Projects window:

This shows you that there is one operation (getQuote) with which you're able to interact. Double-click getQuote in the view above, and you'll see a very unexciting dialog box (because the web service is so simple -- the next web service we look at will result in a much more interesting view here). Now click on the Submit button! When you do so, the web service is contacted and the operation is invoked! How much coding have you done so far? Nothing. Nothing at all. You're using a built-in client that requires no coding on your part whatsoever. But the built-in client is useful for other reasons too, as you'll soon see. In the meantime, wait for the quotation to be retrieved, click on the Value at the bottom of the dialog box and you'll see something like the following (click to enlarge):

Whenever you click the Submit button, you'll get a new quotation. This isn't very exciting. We'll implement it in the application later, as one small part of a much more interesting application which will use a web service that checks the spelling of a given text, and returns the text, together with its mistakes, the number of mistakes, possible replacements for the mispelled words, and the number of suggested replacements. Obviously this is a far more complex web service. Access it in the same way as shown above for the Quotation service. Here's the WSDL URL to use:

http://ws.cdyne.com/SpellChecker/check.asmx

Since we've accessed the SpellChecker web service in the same application as where we already have the Quotation web service, this is the view you should see in the Projects window:

Now double-click the checkTextBody operation (we won't be using the suggestWord operation at all in this walk through). Enter a text for the bodyText argument and enter "0" for the licenseKey argument. (The latter argument is something like the default registration key required by the owners of the web service.) Throughout this walk through, the text "I spelll bootifully!" will be used. Now click Submit. One node will appear in the Results pane at the bottom. This is the node for the DocumentSummary object, specified by the WSDL file. Expand it. You'll see this (click to enlarge):

This is an extremely useful graphical representation of the WSDL file. It tells you that every DocumentSummary object contains an array of words, a string with a version number, the content that you entered, and the number of errors found. Does it really tell you that? No, it doesn't. Only the types and their values are shown. But if you dig deep into the Files window, you'll find the files that you have to plough through in order to understand what the values mean. (Yes, this is a problem, but more about that later.) Now expand the Words[] object, specified by the WSDL file. You'll see two new nodes -- one each for each of the wrong words that were identified. Expand one of these new nodes. You'll see this (click to enlarge):

This tells you that for each wrong word found, there is a list of suggested words, the value of the wrong word, and the number of suggested words. Does this really tell you that? No, again, you'd need to do a bit of guessing (for example, expand the java.lang.String[] node above and you'll see 11 suggested alternatives for the inccorrectly spelled word "spelll"). Apart from the guessing over here, you need to do a bit of digging in the Files window to see the files that are graphically represented here. This is unfortunate. You constantly need to switch between the view in the "Test Web Service Operation" dialog box and the Files view. The Files view is problematic too -- because you may have a very long package name, and getting to the generated files can be a frustrating process. In fact, this is where you can find them in the Files window:

The view in the "Test Web Service Operation" dialog box is excellent in that it shows you the relationship between the arguments that the operation requires (my explanations based on the illustrations above hint at for loops, for example). However, though the view is nice, the walk there is a bit circuitous (expand the nodes in the Projects window, double-click the operation, invoke the operation on the web service, and only then do you see the view that you set out to see). And, again, for details on these various operations, you need to make an uncomfortable journey through the Files window. As a consequence, I've set up my Projects window and Files window like this (with the Runtime window behind the Projects window because it relates to projects and the Favorites window behind the Files window because it relates to files):

This is kind of neat, but not ideal -- since there's now even less space for the Source Editor, which is, after all, the primary tool for interacting with your application.

Compilation and Deployment.


Finally, on the compilation and deployment side, we have the Sun Java System Application Server. Without the latter, you definitely can't compile your client -- in fact, you can't even create you client, because compilation is done as soon as the Web Service Client wizard is completed. Deployment, I have been told, can also be achieved via the Tomcat Web Server (via workaround and whatnot), or probably other servers, but I don't know this for 100% sure. Still, since the Sun Java System Application Server is available for free, why wouldn't you go ahead and use it, if in return you're able to access these cool web services? (If you're not convinced at how fun web services can be, have a look at my previous blog entries, specifically the one about searching for Shakespeare quotations.) By the way, for deployment, you might need to specify some proxy settings in the Sun Java System Application Server, if you're behind a firewall. The expert in this field is a colleague of mine in the States, Gregg Sporar. Read About that proxy server... for details.

Right, now that we've got everything nicely set up, and kind of know what we're dealing with, let's create an application that invokes some operations on our two web services.

Developing Web Service Clients.

So, we'll develop our two clients -- both within the same application. The first is just a warm up -- it's probably the world's simplest client interacting with the world's simplest web service. No arguments are passed, all that happens is that an operation is invoked that returns a quotation to display in the browser. The second sample is far more complex and shows you how the various development tools need to be used in concert to provide the required result -- a simple report displaying spelling errors in a given text.

A Very Simple Web Service Client.

First, right-click the project node in the Projects window, choose New > File/Folder and then choose Web > Servlet. Click Next. Name the servlet MyApplicationServlet and type mypackage.mysubpackage in the Package drop-down. Click Next. Note that the URL mapping for this servlet is /MyApplicationServlet and click Finish. The servlet opens in the Source Editor. Put your cursor inside the Source Editor, inside the processRequest method, right-click, and choose Web Service Client Resources > Call Web Service Operation. Click the getQuote operation in the "Select Operation to Invoke" dialog box and then click OK. Bits of code are now added to the servlet. Scroll to the bottom, and you'll see code that connects the client to the web service (much of the code is underlined in red -- ignore that, it's a bug that has no effect on the building and running of the application). At the top of the processRequest method you see a snippet of code that invokes the web service. Cut and paste it into the body tags of the processRequest method, and delete the lines that comment out the code (put your cursor in the line and press Ctrl-E to delete the whole line). The method now looks as follows:

 protected void processRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
out.println("<html>");
out.println("<head>");
out.println("<title>Servlet MyApplicationServlet</title>");
out.println("</head>");
out.println("<body>");
try {
getQuotesSoap().getQuote(/\* TODO enter operation arguments \*/);
} catch(java.rmi.RemoteException ex) {
// TODO handle remote exception
}
out.println("</body>");
out.println("</html>");
out.close();
}

Add String myReturnedQuotation = in front of the first line in the try/catch block and then type out.println(myReturnedQuotation); in the line below, so that the try/catch block is now like this:

 try {
String myReturnedQuotation = getQuotesSoap().getQuote(/\* TODO enter operation arguments \*/);
out.println(myReturnedQuotation);
} catch(java.rmi.RemoteException ex) {
// TODO handle remote exception
}

That's it! You're done! Since the operation doesn't need any arguments, you can deploy the application right away. Did you do any coding whatsoever? Yes, well, you declared a variable and specified that the returned quotation should be displayed on the page. Apart from that, nothing at all. I think that's pretty cool and this is why this is the world's simplest web service client. So, anyway, right-click the project node and choose Run Project. After a while, the application will deploy and display a blank JSP page in the IDE's default browser (by the way, if you want to change the default browser, go to Tools > Setup Wizard). In the URL at the top of the page, type the servlet's URL mapping (MyApplicationServlet). (By the way, you can also specify the URL mapping in the Run panel of the project's Project Properties dialog box, which you access by right-clicking the project node and choosing Properties.) Now you'll see something like this:

Now, every time you refresh your browser, a new quotation -- sometimes intelligent, sometimes inane -- is returned to the client and displayed in the browser. Yay -- you're done. Not so hard, was it? Next, let's take a look at how to interact with the SpellChecker web service.

A Slightly More Complex Web Service Client.

As pointed out earlier, we're going to have to do a lot of switching between the Projects window, the Files window, and the "Test Web Service Operation" dialog box. This is not very nice, but gets the job done. As before, put your cursor in the processRequest method (yes, in the same servlet as where you're accessing the Quotation web service), right-click, and choose Web Service Client Resources > Call Web Service Operation and this time click the checkTextBody operation in the "Select Operation to Invoke" dialog box. Click OK. (Here, I've noticed that you've got to be very careful where you put your cursor -- mine was inside the previously created try/catch block, which resulted in the new try/catch block being created inside of it. Probably a bug.) Put the new try/catch block below the old one -- and now let's begin our analysis.

First, recall this view (click to enlarge):

This is the outermost layer of the web service. Before we can do anything else, we need to deal with this layer. The highest node is called DocumentSummary. Dig back into the Files window, until you get here:

Now double-click the DocumentSummary.java node so that it opens in the Source Editor (and look at the nodes above as well). If you don't do this, how do you know what methods are made available by DocumentSummary.java? Once you've opened it in the Source Editor (accompanied by viewing its expanded nodes in the Files window), you can see that the corrected text returned by the SpellChecker service should be assigned to the DocumentSummary object. Once this is done, you can use its methods to interact with the corrected text:

  DocumentSummary doc = getCheckSoap().checkTextBody(text,"0"); 
String allcontent = doc.getBody();
int no_of_mistakes = doc.getMisspelledWordCount();
Words[] allwrongwords = doc.getMisspelledWord();

There's another method, called getVer, but we won't use that. On the other hand, if you were going to make your client implementation available, and really use it in a business setting, it might be useful to run through a condition to check if the web service's version is the one that you expect it to be -- and produce some kind of error or message when the versions differ -- because subsequent versions of the web service might clash with your client implementation.

Okay, now that we have the above values, we can iterate through all the wrong words returned, get the related values, and display them. How do I know I should do this? Because of this view:

There's a custom object (also called a 'native array') called Words[] (just as there was a custom object called DocumentSummary). Again, you need to dig into the Files window to see what the methods are that this object makes available:

Now, within the servlet's <body> tags, you need to loop through all the wrong words and then identify and display the current wrong word and its related details (number of suggestions and array of suggestions). To display each suggestion within the array of suggestions, you need to loop through this array too. So, here's what happens:

for (int i = 0; i < allwrongwords.length; i++) {
String onewrongword = allwrongwords[i].getWord();
int onewordsuggestioncount = allwrongwords[i].getSuggestionCount();
String[] allsuggestions = allwrongwords[i].getSuggestions();
out.println("<hr><p><b>Wrong word:</b><font color='red'> " + onewrongword + "</font>");
out.println("<p><b>" + onewordsuggestioncount + " suggestions:</b><br>")suggestions:</b><br>");
for (int k = 0; k < allsuggestions.length; k++) {
String onesuggestion = allsuggestions[k];
out.println(onesuggestion);
}
}

To round things off, you can provide a summary at the end:

out.println("<font color='red'><b>Summary:</b> " + no_of_mistakes + " mistakes ("); 
for (int i = 0; i < allwrongwords.length; i++) {
String onewrongword = allwrongwords[i].getWord();
out.println(onewrongword);
}
out.println(").");
out.println("</font>");

At the top of the report, you might want to display all the content. That's also possible thanks to the variables you defined right at the start:

out.println("<hr><b>Your text:</b> \\"" + allcontent + "\\"" + "<p>");

Anyway, many variations are possible. Once you can access the methods you need, you can loop through the returned data quite easily and do pretty much whatever you like with it. You'll need a JSP page to pass the text you want to correct on to the servlet:

<form name="Test" method="post" action="SpellCheckServlet">
<P><font color='red'>Enter the text you want to check:</font></P>
<P>
<textarea rows="20" name="TextArea1" cols="62" ID="Textarea1"></textarea></P>
<P>
<p><input type="submit" value="Spell Check" name="spellcheckbutton">
</form>

So, this is my entire processRequest method (minus all the error handling). I've added a lot of explanatory comments in the code, hopefully they'll be of help:

protected void processRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
//Get content from JSP:
String TextArea1 = request.getParameter("TextArea1");
//Invoke the operation on the web service that does the spell check.
//As arguments, send the content and the key. In other words, this
//is where all the REAL work happens!!!
DocumentSummary doc = getCheckSoap().checkTextBody(TextArea1,"0");
//From the retrieved document summary,
//identify all the content, correct and incorrect, of text:
String allcontent = doc.getBody();
//From the retrieved document summary,
//identify the number of wrongly spelled words:
int no_of_mistakes = doc.getMisspelledWordCount();
//From the retrieved document summary,
//identify the array of wrongly spelled words:
Words[] allwrongwords = doc.getMisspelledWord();
out.println("<html>");
out.println("<head>");
out.println("<title>Spell Checker Report</title>");
out.println("</head>");
out.println("<body>");
//Display <h1> header:
out.println("<h2><font color='red'>Spell Checker Report</font></h2>");
//Display the content between quotation marks:
out.println("<hr><b>Your text:</b> \\"" + allcontent + "\\"" + "<p>");
//For every array of wrong words, identify the wrong word, the number of suggestions, and
//the array of suggestions. Then display the wrong word and the number of suggestions and
//then, for the array of suggestions belonging to the current wrong word, display each
//suggestion.
for (int i = 0; i < allwrongwords.length; i++) {
String onewrongword = allwrongwords[i].getWord();
int onewordsuggestioncount = allwrongwords[i].getSuggestionCount();
String[] allsuggestions = allwrongwords[i].getSuggestions();
out.println("<hr><p><b>Wrong word:</b><font color='red'> " + onewrongword + "</font>");
out.println("<p><b>" + onewordsuggestioncount + " suggestions:</b><br>");
for (int k = 0; k < allsuggestions.length; k++) {
String onesuggestion = allsuggestions[k];
out.println(onesuggestion);
}
}
//Display line after each array of wrong words:
out.println("<hr>");
//Summarize by providing the number of errors and display them:
out.println("<font color='red'><b>Summary:</b> " + no_of_mistakes + " mistakes (");
for (int i = 0; i < allwrongwords.length; i++) {
String onewrongword = allwrongwords[i].getWord();
out.println(onewrongword);
}
out.println(").");
out.println("</font>");
out.println("</body>");
out.println("</html>");
out.close();
}

You'll notice that I've left out the call to the Quotation service, but that's not hard to add. Anyway, once I deployed the whole application (right-click the project and choose Run Project and when you run into problems remember that proxy server...), this is the first thing I saw (i.e., the JSP page (click to enlarge)):

And when I clicked "Spell Check", this nice report was produced:

Of course, this is a very simple client. (On the other hand, the web service itself is really cool, it responds almost instantaneously, even when I sent it a text that amounted to 20,000 words!) You'd really want an interface where the user can select a suggested correct word and have the application replace the incorrect word with the suggested word. You'd also want to be able to add and edit words to the dictionary and various other things. In fact, someone has implemented the WSDL file in exactly that way. Click http://www.cdyne.com/SpellChecker/ to see for yourself. (I think it's pretty cool that the same WSDL file can be used in a very wide variety of ways, so long as the underlying operations and arguments are respected. There's freedom, but there's also discipline.)

I hope this overview has been useful and that someone out there can do something with it. As you can see, NetBeans IDE 4.1 provides a lot of useful tools for consuming web services. I have three suggestions for extending the usability of the features, however. Anyone that's gone through all of the above steps and instructions will probably share my need for the following:

  • Display custom objects in the Projects window (currently have to dig in Files window). Maybe they, as well as the operations made available by the web service, could be displayed in the Navigator (or whatever will replace it in the future).

  • Make the structure of the web service more accessible -- currently it's hidden away in the Test Web Service Operation dialog box. I'd like to be able to choose a menu option or something, or at least a node much higher up in the Projects window, to see the structure of the web service.

  • Ability to delete/hide non-needed operations. Or show which ones are used, which ones aren't. At some stage there may be quite a lot of web services integrated in an application -- some way of sorting and organizing, prioritizing, hiding, etc of the web services and their operations would be useful.

Two final things -- firstly, what's especially exciting about having an IDE handle web services in this way is that you don't have to deal with the nuts and bolts of SOAP (which is not easy). Secondly, something I haven't heard anyone else comment on is that web service technology is ideal for learning Java. If you're a relative beginner to the Java language, what better than to have a half-finished application (the web service) for which you have to create the other half (the client)? This situation forces you to sit down and think about what is needed and how to respond to the requirements set by the web service. Having an IDE to guide you through everything, on top of that, makes the whole experience even better. When everything's up and running, you can dig into the code and try and work out how all the plumbing interacts.

In the next releases of NetBeans IDE, the above tools will also be available for non-web applications. You'll be able to use the Web Service Client wizard to create web service clients in J2SE applications. You'll also be able to call a web service operation directly from a JSP page. In short, I think this is a really cool technology and that NetBeans IDE is definitely on the right path when it comes to supporting the consumption of web services.

Join the discussion

Comments ( 1 )
  • shilpa pawar Tuesday, October 11, 2005
    i have problem with this url
    problem: unable to make client for that url in VB.Net its genrate a proxy class successfuly but accesaing of function is not proper
    please help
Please enter your name.Please provide a valid email address.Please enter a comment.CAPTCHA challenge response provided was incorrect. Please try again.