[an error occurred while processing this directive]
> developer > web app development
Building Web Services with jBroker Web and Apache Tomcat
by Erik Dasque, Product Manager, Novell
Date Created: 2001-08-21 13:26:00.000
  Introduction
  Novell exteNd Web Service Model
  Let's Get Started
  Creating a Web Service from a Simple Java Class
  Web Services Wizards
  Deploying and Testing
  Conclusion

introduction
Let's face it, I'm not a great developer. My friends make fun of my code at parties; they mock the fact that my code is "read only" and that I use French for my variable names. (What's wrong with for (boucle=0;boucle<100;boucle++)anyway?) Nevertheless, and thankfully, what I'm about to show you doesn't require much code prowess as my intent is to make the following Java class available as a Web service.




/**

   * @(#)SimpleService.java

   *

   */





public class SimpleService



   {



   public String getStringMessage()



   { return "This web service works !"; }





   public int getInt()



   { return 42; }





   public int echoInt(int c)



   { return c;}



   }
Novell exteNd Web Service Model
Familiar model

  • Separate implementation and definition
  • Definition in Java instead of a new language
  • No additional configuration files since class generation is derived from the remote object
  • Industry standards


But beyond its use of a standard service-oriented, Java architecture, the SilverStream Web service solution offers the following benefits:

  • A dispatcher based on one servlet per Web service to provide better performance, controlled access and scalability.
  • A SOAP 1.1 compliant engine sitting on top of HTTP with fast SOAP message construction and parsing, and an XML stream parser that is eight to 10 times faster than the Apache Soap Server 2.x.
  • Support for collection classes, elements, basic types and complex types such as arrays.
  • An efficient registry-based type mapper that holds information about Java types and their XML mappings for use in Marshalling/DeMarshalling and handling non-supported complex types.
  • Easy deployment in a standard J2EE archive (WAR) for J2EE-compliant application servers, including Tomcat, Sun RI and the SilverStream Application Server.


A wizard-based stub / tie / servlet wrapper / ... creation from SilverStream eXtend Workbench.

Novell exteNd Workbench also provides tools including a test-bed UDDI local server, a UDDI browser, and a WSDL editor to help service producers and consumers discover and publish Web services.
Let's Get Started
After downloading and installing Apache Tomcat (you can just as easily use SilverStream Application Server or any other J2EE compliant application server), Novell exteNd Workbench (Novell's J2EE and Web service development and deployment Integrated Service Environment), jBroker Web (the SOAP engine and associated compilers rmi2soap, rmi2wsdl, wsdl2java) and adding jbroker-web.jar (found in JBroker Web install lib directory) to Apache Tomcat classpath (an easy way to do this is to copy the .jar file to Tomcat lib directory) we're ready to get started.

First, we'll create a project within Novell exteNd Workbench.

Because Web services are served via servlet wrappers that understand SOAP exchange, we'll need to create a WAR file. To do this in SilverStream eXtend Workbench, use the "new project" file and select a WAR project (Web Archive).



Besides having bad coding habits, I'm a bit lazy; notice this sets up our project so that the archive location will be right in the Tomcat WebApps directory (understand WAR files and extracted directories), in this case C:\DevApps\jakarta-tomcat-3.2.2\webapps. This way after we've built our project and WAR archive, Tomcat will extract the files from the WAR file at startup and deploy them automatically. Should they need to be redeployed, we'll only need to remove the directory it created and restart Tomcat.

With this newly created project, we have an empty WAR archive that is saved from the default XML descriptor, which as of yet doesn't contain a servlet or JSP definition (but it will soon).

First, however, we need to make sure that our project classpath contains the proper files as follows:

  • Using Project::Project Settings::Classpath we'll add the jbroker-web.jar archive to our project classpath (in this case pointing to C:\jbrokerWeb10-beta\lib\jbroker-web.jar.
Creating a Web Service from a Simple Java Class
As stated previously, we will use the Java class found at the beginning of this article and enable it as a Web service. If you have an existing Java class, you can easily add it to the project archive (Project::Add to Project::File) at the following location: WEB-INF/classes/nameOfTheClass.class (that's where WAR files store their individual class files).

In this case, let's create a new Java class (File::New::Java file). Check "use wizard" whether you want to code your own implementation or paste the code found at the beginning of the article. If you are pasting the code found at the beginning of the article, name your class "SimpleService." Finally, remember to add the file to the archive with the following prefix: (WEB-INF/classes).



After pasting and compiling the Java code using keyboard shortcut F7 (hopefully this will compile without errors), we'll start launch the Web service wizard (File::New:WebService).

We'll use the first option, "Generate objects to use an existing Web service," to create client classes that call an existing Web service. We'll then need to provide the wizard with a WSDL file that describes that service. (This first option can also be used to create a Web service, clients, wrapper, etc. that implement a WSDL file.)



In our case we will use the second option available, "Generate objects to create a new Web service." On the second pane of that wizard, we'll be able to select the Java object that will be the basis of our Web service from the classes available in this project. Of course we'll select SimpleService by double clicking it. By default the wizard will point to the existing classes directory for our project. Here it used C:\DWB_Projects\SimpleWebService_Project\build\SimpleWebService-classes\WEB-INF\classes to populate the list. But you can choose a different class location, jar or directory, and even filter the listed classes (all classes / remote / non remote only). The class that we're using contains three public methods. In some cases you may not want to expose all of your public methods (method modifiers, a Java construct), instead you may want to restrict exposure to a few of them. Here we'll expose echoInt(), getStringMessage()and getInt().In order to do that, we'll simply double click on each of the method signatures, moving them to the selected method list. In the next pane, we'll be able to select the "generations" options for the wizard. In this case, we'll want to do the following:

  • Generate stubs (This will take care of the client stub and test client generation.)
  • Generate tie-based skeletons (A SilverStream implementation of a Web service can optionally include a SOAP tie class generated by the Web service wizard. The tie class supports delegation. If you already have an implementation class for a Web service, you can extend a tie class and add code to your subclass that sets the target for delegation to be your implementation class. This design model is particularly useful if you want an existing implementation object to support multiple protocols. For example, if you already have a remote object that supports IIOP calls, you may want to use delegation to allow that object to support SOAP as well.)
  • Generate skeletons (This will be generated anyway if tie-based skeletons are generated because they inherit from the earlier.)
  • Generate a WSDL file (This will be created from the signature of the selected method in the initial class and the SOAP options selected in the current panel.)


Web Services Wizards
The Web service wizard runs the following compilers:

  • The remote interface generator creates a Java remote interface (an interface that extends java.rmi.Remote) from an existing Java class or JavaBeans component. This remote interface is then used as input to the other compilers.
  • The rmi2soap compiler transforms Java remote interfaces into SOAP stubs and skeletons.
  • The rmi2wsdl compiler transforms Java remote interfaces into WSDL documents.
  • The wsdl2java compiler transforms WSDL documents into Java remote interfaces. (This one is not used for "Generate objects to create a new Web service," but it is the main compiler for "Generate objects to use an existing Web service.")




These compilers can also be invoked independently from the command line, batch commands, third-party development tools, or directly via their API.

Note that we'll need to adjust the service binding in the panel to point to the correct URL. With Tomcat running on port 8080, we should change it to http://localhost:8080/SimpleWebService/SimpleService.

As can be seen in the project archive layout view in the WEB-INF/classes directory, seven classes have been generated including two abstracts, one interface and four implementations (one SimpleService_TIE inheriting from servlet through _SimpleService_REMOTE_ServiceTieSkeleton and _SimpleService_REMOTE_ServiceSkeleton). A servlet and servlet-mapping have been added to the web.xml WAR deployment descriptor (found in WEB-INF) named SimpleService and pointing to "SimpleService," which becomes http://localhost:8080/SimpleWebService/SimpleService.

Also note, the SimpleService_REMOTE.wsdl file the wizard generated through the rmi2wsdl compiler can be found in the root of the archive. After deployment, if you point your browser to http://localhost:8080/SimpleWebService/SimpleService, you will be able to see the file. To deploy it you will first need to build and archive (shift F7). This will build your SimpleService.war, and after restarting Tomcat you can point your browser to that url,which will confirm that your Web archive has been read and extracted by Tomcat. (Before restarting Tomcat, make sure you've deleted any existing SimpleService directory from your Tomcat WebApps directory. In our case, we deleted C:\DevApps\jakarta-tomcat-3.2.2\webapps.)
Deploying and Testing
That first test passed, so now we can uncomment the bold code in the process method from SimpleService_CLIENT and change echoInt(int) to echoInt(42). The result will be as follows:




   public void process(String[] args)



   {



   try



   {



   SimpleService_REMOTE remote = getRemote(args);





   

        // The following code has been generated for your testing convenience. In

        // order to successfully test your Web Service, you must uncomment one or

        // more of these lines and supply meaningful arguments where necessary.

        // Once you have modified the test method(s) below, compile this class and

        // execute it from a command line with your class path set appropriately.

   



   System.out.println("Test Result = " + remote.getStringMessage());



   System.out.println("Test Result = " + remote.echoInt(42));



   }



   catch (Exception _e)



   {



   System.out.println("*** Error Executing Generated    Test Client ***");



   _e.printStackTrace();



   }



   }



After compiling the file (F7), we should be able to run it by selecting "Project::Run Web Service Client class :Run."



This will show whether the client correctly executed, and will call the SOAP service running on the Tomcat server, which we can see by running an HTTP tunnel utility.

On a side note, you may want to look at the code that was generated for that test client as it illustrates the use of the familiar RMI model for Web service invocation on the client-side (i.e. RMI-over-SOAP, which we will explore in a future article).


public SimpleService_REMOTE getRemote(String[]args) throws Exception
{

   String lookup = "xmlrpc:soap:SimpleService_REMOTE";

	 // JNDI lookup for the client stub (must be in the client classpath)

   InitialContext ctx = new InitialContext();

 	// the remote returned is ready to be used as if

	// the client application was directly talking to the remote object

   return (SimpleService_REMOTE)ctx.lookup(lookup);

}

Conclusion
In a few easy steps we've created a Web service, starting with a Java class from which we wanted two methods. While those methods were simple, Web-service enabling any Java class or session EJB is not much more complex. Minor annoyances like complex data types (even though jBroker Web automatically maps basic Java types, most java.lang and java.math types, date, remote, map, set, list, arrays and elements), session handling for Web services, and Web services flow might appear in your Web services journey, but we'll cover those in future articles or exteNd Webinars.