Web Services Tools: An Evaluation

Watch out for the potholes

When you’re planning a vacation, the first thing you decide is where you want to go. Then you figure out exactly how you’re going to get there and by what route. If you’re reading this article, you have some interest in Web services and you might have even decide that you need to build a Web service. What you might not have decided is which "vision" -- Microsoft .NET or Java 2 Enterprise Edition (J2EE) -- for Web service construction you will use, and what tool you will use to build your Web service.

Let’s assume that you aren't married to either .NET or J2EE. You can bring in the hardware you need, be it Wintel or otherwise, and your biggest concern is getting up and running quickly. Let’s also assume that you have, or can hire, programmers with either Java (specifically Enterprise Java Beans) or Win32 (specifically .NET) skills. If this is the case then you want a tool that will allow your developers to build a Web service from scratch, with a minimum of hassle. There is nothing worse than building complex distributed applications from the ground up with no help from the development tool.

We looked at two development tools that have special features built-in to help you build Web services. Microsoft’s Visual Studio.NET is the .NET follow-on to its popular Visual Studio line of tools. Sun’s Forte for Java 3.0, Enterprise Edition is the latest Java development tool from the inventors of the Java standard itself.

In order to test these products we set out with a simple (we thought) goal of building a Web service that could deliver XML data to a wide range of clients. We exported the data from our MS Outlook contacts database, and created a database to base our application on. For our Visual Studio.NET testing, we created the database table in Microsoft Access 97, and for our Forte testing we created the database table in the Pointbase Java database that is included with Forte.

We wanted to be able to retrieve contacts based on the Full Name or the Company Name, as well as retrieving all of the contacts. Ideally, the data would be returned complete with an XML schema so that client applications would know what they had received as output from the Web service.

Before we started this process we had used previous versions of both tools to build non-Web service applications, our level of experience with the tools was approximately the same.

Visual Studio.NET

We called Microsoft’s PR agency and they sent us a copy of the release candidate for Visual Studio.NET. We installed the product on a system running Windows XP Professional. Aside from the product, the .NET framework and some extensions for Internet Information Server (IIS) had to be installed.

There is a tight integration between Visual Studio.NET and IIS and this is one of the things we liked most about VS.NET. Also, there is a tight integration with Microsoft SQL Server 7.0 or later, but unfortunately not version 6.5, which is what we have setup and running. This is why we used Access.

VS.NET allows you to build your Web service in Visual C++, Visual Basic, or Microsoft’s new Java clone, Visual C#. We chose to use C# since it is very similar to Java and, in our opinion, easier to write than C++ code. Although you are locked into the Wintel platform, you are not locked into the programming language and these three languages can interoperate with each other. What this means is that you can build your Web service with, for instance, Visual C++, and a client to access the Web service with Visual Basic. We find this to be an advantage, especially if you don’t have a problem working in an all Microsoft world. No matter which language you chose there is a project template for creating a Web service that you can use to jump-start your development effort.

We created a Visual C# project with the ASP.NET Web service template and got to work. Our next step was to create a database connection for our Access database. We did this through the Server Explorer. If we had SQL Server 7.0 running, the server would have been displayed and we wouldn’t have had to create a connection manually.

Once our database connection was defined and connected, we could drag a database table onto the Design workspace for our Web service, and Active Data Objects (ADO) objects for the Connection and Data Adapter were automatically created for us. The most important thing to note here is the Data Adapter, which allows us to create a Data Set. The Data Set is an object representation of our database table and allows us to easily access the data we need. More importantly, if we return a Data Set from a Web service method, XML code for the data, and the schema, is automatically generated when our method is called.

Now that we have generated our Connection, Data Adapter, and Data Set objects, we are ready to define our Web service’s methods.

This is easy enough to do using the Class View of the IDE. By right clicking on the Web service class and choosing Add/Method, a dialog box is displayed that lets us define the method and it’s parameters. The easiest method we need is findAll, which returns all of the contacts from the database. The other two methods, findByName and findByCompany, can be similarly defined with the addition of string parameters for respectively, name and company. The only drawback of the dialog box is that it doesn’t give you a way to specify that this is a Web method or an ordinary method. To make this a Web method you have to go into the Code View of your Web service and preface the method definition with the [WebMethod] directive. If you don’t do this, your methods won’t be exposed through the Web Services Definition Language file.

Once these three methods are defined, we have a properly defined Web service, which will in fact work, but doesn’t actually do anything. If we build the project now and execute it, another feature of VS.NET that we like is highlighted. When you build a Web service application successfully, the Web service is deployed to the Web server, along with an ASP.NET test application that exposes the web service’s methods. With this test application you can open up a browser and test your Web service immediately.

We did just that and saw our three methods, we could invoke, and see the XML output, which wasn’t very interesting, since our methods return null Data Sets at the moment.

To get our methods to return actual data from the table, we have to do a little programming. Basically, with the dataset predefined, all we have to do is give it a database query to retrieve the proper data, and execute the fill method of the dataset. This easily accomplished by creating an oleDbCommand for each of our methods. This task is easily accomplished by dragging and dropping an oleDbCommand object from the tool palette onto the workspace. We then use the Query Builder to graphically build the proper SQL query (or write the SQL query by hand).

Once the right command is setup, it only takes three lines of code to retrieve the data, as illustrated below:

[WebMethod]
public DataSet findAll()
{
DataSetContacts ds = new DataSetContacts();
oleDbDataAdapter1.SelectCommand = oleDbCommandAll;
oleDbDataAdapter1.Fill(ds);
return ds;
}

By returning a Data Set from the method, the server automatically transforms the data into XML and adds a schema, to boot. Now, any client can access the Web service and parse the returned XML data as needed. We find this to be invaluable, as creating XML from the returned data could be a real pain.

Obviously every Web service that you write will not be this simple, but I think you get the idea. One thing that is always a pain when developing server-side Web applications is debugging. VS.NET makes this very easy with full source code debugging integrated into the IDE. We were able to step through the code, set breakpoints, and examine variables, with no trouble whatsoever.

Overall, our experience with Visual Studio.NET was positive. We are looking forward to playing around with it some more, including the utility that generates SOAP client stub code and the behavior of Data Sets with tables that have foreign key references.

Forte for Java 3.0, Enterprise Edition

We have used Forte for Java in the past for developing GUI applications, but this is the first time we have used the Enterprise Edition. The Enterprise Edition includes all of the features of the Community Edition and adds the capability to work with Enterprise Java Beans (EJB). This is very important since the Sun Open Network Environment (ONE) uses EJB as the base on which to build Web services. This is not to say you can’t develop a Web service without using EJB, but it turns out to be much easier if you use them.

We started by creating a project to hold our Web service. Unlike VS.NET, Forte does not have a template for a Web service. You create a generic project and add objects into the project. The first thing we needed to do was create an EJB for access to our data. We created a Java package to group our classes in called Web. We used the EJB Wizard to create an EJB entity bean.

There are two types of entity beans. If you want to write the database access code yourself, you would create a bean with Bean Managed Persistence (BMP). If you want the EJB container (most likely a Java application server) to handle the database access, you would create a bean with Container Managed Persistence (CMP). We chose to let the container handle the persistence and created a CMP entity bean.

For CMP beans, the wizard will ask for a database table to base the bean on. We created a connection to our Pointbase database, and used that to give the wizard information about our database schema. The wizard correctly identified our table columns and created the bean based on them.

When you create an EJB, the wizard creates four objects. The home interface, the remote interface, the bean, and a logical representation of the bean. If you create new methods and fields through the logical bean, the real bean and the interfaces will be updated appropriately. If you modify the real bean, you’re on your own. We exclusively worked through the logical bean.

By default, a method to find records in the database table by the primary key is created. Since our primary key is fullname, and that’s one of the ways we want to be able to retrieve data, we were one third of the way done. We had to create two other methods for retrieving all of the contacts and retrieving the contacts by company name manually.

With CMP this is very easy. To create the more complicated findByCompany method we drilled down through the tree view of our project until we reached the Finder Methods leaf of the logical bean and chose New Finder Method from the popup menu. We set the name and added a string parameter to hold the company name.

Now here is the beauty of using a CMP EJB as the basis for your Web service. For simple Web service methods that only access the database, you don’t have to write any code. Well, you have to write a SQL query to retrieve the data from the database table, but you would have to do that anyway for your EJB to work in the first place. Therefore, we edited the properties of the logical bean finder methods so that they contained the valid SQL queries, and moved on.

If you are developing your EJB from scratch, specifically for your Web service, now is a good time to test your EJB. Forte lets you create a test application for your EJB, complete with HTML pages that let you access the methods of your EJB. We created a test application for our EJB and confirmed that we could indeed access the database.

The next step was to create the Web service itself. This is a three-step process. First, you create the Web service. This is done from the project explorer by choosing New/Web Services/Web Service. The only information the wizard requires is a name for the Web service. While exploring the property sheet of the Web service we noticed a place to set the application type. There were two choices, ESP (Sun’s Enterprise Service Presentation protocol) and SOAP, but the choice for SOAP was grayed out. We hope that you will have the choice of creating SOAP applications in the near future.

The next thing you have to do is define the Web service’s methods. You can do this by hand, or you can use an EJB as the input for the process. Obviously we wanted to use our newly created EJB as the input, so we chose Generate Operations from EJB from the Web service’s context menu. One thing we don’t like about Forte is that, in many cases for flexibility, it gives you enough rope to hang yourself. Generating the Web service’s operations from your EJB is one of these cases.

You are asked to choose the EJB, EJB module or package containing an EJB to use for creating the methods. The IDE does not limit you to choosing only valid choices, in fact, everything in all the mounted filesystems is displayed. There are three things that can happen. First, you can choose something completely out of the question and the IDE will tell you to choose something else, second, you can choose the right object, and third, you can choose a potentially valid object that will not work in the end. The last choice is the one that concerns us.

We started by choosing the logical EJB, and it seemed to work, but when we got around to compiling the Web service, an object reference error was generated. We couldn’t find any way to fix it at this stage, so we went back a step and tried to use the remote interface, which looked like it worked, but didn’t generate the right methods. Finally, we chose the home interface of our EJB and although an object reference error was generated, it was easily fixed.

We wish there were more documentation on the whole process. There is a PDF help file on building Web services, but it is incomplete at best. Actually, the only way we figured out the whole process was to examine the Dining Guide tutorial, which has example code similar to what we were doing. I guess, in the end, we would like to feed the IDE an EJB, and have it create a default Web service for us, with default methods. We could then tweak it to be exactly how we wanted it.

Our final step before packaging the Web service for deployment was to make sure the methods were returning the correct XML code. We noticed that there was no detail data being included in the default XML output, but also noticed the Expand choice in the leaf node of the XML operation’s tree view. We selected Expand and the class that encapsulated our detail data was queried and the data returned from the Get methods of the ContactDetail class was added.

The XML tags created by the wizards are rough, so you may want to change them with the XML operation editor inside the IDE. Also, by default, no XML schema is generated for the XML data returned from the Web service’s methods. We couldn’t find any way to do this automatically, and it wasn’t intuitively obvious how to do it manually. This is a big drawback that is most likely solved by registering a schema in the ESP repository, or through something like UDDI.

Once all of this is done you have to generate and compile the Web service. At this time Forte also checks the validity of your Web service, and if everything is OK, you are ready to package and deploy your Web service.

To do this you have to create a J2EE application. This is easily done through a three-step process in the GUI. First, we created an EJB module for our EJB. Next, we created an empty J2EE application, and finally, we added the EJB module and the Web service to the J2EE application. This adds a number of things to your J2EE application, most importantly, a Web Archive (WAR) file. A context for your application is created called defaultContext, which you can change. We changed our context to TestWebService so that we could access our Web service test application by the URL http://localhost:8000/TestWebService.

We fired up a browser, entered the URL for our test application, and were presented with a simple HTML page with a form that allowed us to test each of the three methods. We tested all three and they worked perfectly. We also accessed our Web service directly through the Komodo servlet. This servlet waits for requests and routes them to the proper Web service and returns XML data. To access the Web service directly, we used the URL http://localhost:8000/TestWebService/komodo?rootElement=AllContactsXMO. This accessed the operation that returned all of the contacts from our database. The XML returned could be processed anyway you wanted.

After going through the Web service development process with both of these tools, we arrived at a few conclusions.

If you already using Enterprise Java Beans for database access and business rule programming, you will do all right with Forte for Java. Many of the problems we ran into during the process had more to do with our unfamiliarity with EJB programming than any inherent flaw in Forte. We do think that Forte could make the Web service development process easier, and we are sure that Sun will make improvements along those lines in future versions of Forte for Java, Enterprise Edition.

We have also concluded that if you are starting from scratch and do not have any EJB lying around to handle database access, building a Web service with Visual Studio.NET will be far easier and quicker. We also think that if everything doesn’t go right with your Forte development process and you have to resort to debugging, you’re in trouble. This is not the case with Visual Studio.NET. The tight integration between the VS.NET IDE and Internet Information Server makes debugging a breeze. Furthermore, SOAP clients, as well as, GET and POST HTTP methods can access Web services created by VS.NET. This is not the case with Forte whose web services can be accessed through Sun’s proprietary ESP protocol or through the Komodo servlet and HTTP. Sun is working on a module for Forte that will let you create SOAP Web services, but it was not available at the time of this article.