23. JAX-WS Web Services

Objectives

In this chapter you will learn:

• What a web service is.

• How to publish and consume web services in Netbeans.

• The elements that comprise services, such as service descriptions and classes that implement web services.

• How to create client desktop and web applications that invoke web service methods.

• The important part that XML and the Simple Object Access Protocol (SOAP) play in enabling web services.

• How to use session tracking in web services to maintain client-state information.

• How to connect to databases from web services.

• How to pass objects of user-defined types to and return them from a web service.

A client is to me a mere unit, a factor in a problem.

Sir Arthur Conan Doyle

They also serve who only stand and wait.

John Milton

...if the simplest things of nature have a message that you understand, rejoice, for your soul is alive.

Eleonora Duse

Protocol is everything.

Francoise Giuliani

Outline

23.1   Introduction

23.2   Java Web Services Basics

23.3   Creating, Publishing, Testing and Describing a Web Service

23.3.1   Creating a Web Application Project and Adding a Web Service Class in Netbeans

23.3.2   Defining the HugeInteger Web Service in Netbeans

23.3.3   Publishing the HugeInteger Web Service from Netbeans

23.3.4   Testing the HugeInteger Web Service with GlassFish Application Server’s Tester Web Page

23.3.5   Describing a Web Service with the Web Service Description Language (WSDL)

23.4   Consuming a Web Service

23.4.1   Creating a Client in Netbeans to Consume the HugeInteger Web Service

23.4.2   Consuming the HugeInteger Web Service

23.5   SOAP

23.6   Session Tracking in Web Services

23.6.1   Creating a Blackjack Web Service

23.6.2   Consuming the Blackjack Web Service

23.7   Consuming a Database-Driven Web Service from a Web Application

23.7.1   Creating the Reservation Database

23.7.2   Creating a Web Application to Interact with the Reservation Web Service

23.8   Passing an Object of a User-Defined Type to a Web Service

23.9   Wrap-Up

23.1 Introduction

This chapter introduces web services, which promote software portability and reusability in applications that operate over the Internet. A web service is a software component stored on one computer that can be accessed via method calls by an application (or other software component) on another computer over a network. Web services communicate using such technologies as XML and HTTP. Several Java APIs facilitate web services. In this chapter, we use the JAX-WS Java APIs, which are based on the Simple Object Access Protocol (SOAP)—an XML-based protocol that allows web services and clients to communicate, even if the client and the web service are written in different languages. There are other web services technologies, such as Representational State Transfer (REST), which we do not cover in this chapter. REST is a network architecture that uses the web’s traditional request/response mechanisms such as GET and POST requests. In Java, the JAXRS APIs are used to implement REST-based web services. For information on SOAP-based and REST-based web services, visit our Web Services Resource Centers:

www.deitel.com/WebServices/

www.deitel.com/RESTWebServices/

These Resource Centers include information on designing and implementing web services in many languages, and information about web services offered by companies such as Google, Amazon and eBay. You’ll also find many additional tools for publishing and consuming web services. For more information about REST-based Java web services, check out the Jersey project:

jersey.dev.java.net/

To learn more the basics of XML, see the following tutorials:

www.deitel.com/articles/xml_tutorials/20060401/XMLBasics/

www.deitel.com/articles/xml_tutorials/20060401/XMLStructuringData/

and visit our XML Resource Center:

www.deitel.com/XML/

Business-to-Business Transactions

Web services have important implications for business-to-business (B2B) transactions. They enable businesses to conduct transactions via standardized, widely available web services rather than relying on proprietary applications. Web services and SOAP are platform and language independent, so companies can collaborate via web services without worrying about the compatibility of their hardware, software and communications technologies. Companies such as Amazon, Google, eBay, PayPal and many others are using web services to their advantage by making their server-side applications available to partners via web services.

By purchasing web services and using extensive free web services that are relevant to their businesses, companies can spend less time developing new applications and can create innovative new applications. E-businesses can use web services to provide their customers with enhanced shopping experiences. Consider an online music store. The store’s website links to information about various CDs, enabling users to purchase the CDs, to learn about the artists, to find more titles by those artists, to find other artists’ music they may enjoy, and more. Another company that sells concert tickets provides a web service that displays upcoming concert dates for various artists and allows users to buy tickets. By consuming the concert-ticket web service on its site, the online music store can provide an additional service to its customers, increase its site traffic and perhaps earn a commission on concert-ticket sales. The company that sells concert tickets also benefits from the business relationship by selling more tickets and possibly by receiving revenue from the online music store for the use of the web service.

Any Java programmer with a knowledge of web services can write applications that “consume” web services. The resulting applications would call web service methods of objects running on servers that could be thousands of miles away.

Netbeans

Netbeans is one of the many tools that enable programmers to “publish” and/or “consume” web services. We demonstrate how to use Netbeans to implement web services using the JAX-WS APIs and how to invoke them from client applications. For each example, we provide the web service’s code, then present a client application that uses the web service. Our first examples build web services and client applications in Netbeans. Then we demonstrate web services that use more sophisticated features, such as manipulating databases with JDBC and manipulating class objects. For information on downloading and installing the Netbeans and the GlassFish v2 UR2 server, see Section 21.1.

23.2 Java Web Services Basics

A web service normally resides on a server. The application (i.e., the client) that accesses the web service sends a method call over a network to the remote machine, which processes the call and returns a response over the network to the application. This kind of distributed computing is beneficial in many applications. For example, a client application without direct access to a database on a remote server might be able to retrieve the data via a web service. Similarly, an application lacking the processing power to perform specific computations could use a web service to take advantage of another system’s superior resources.

In Java, a web service is implemented as a class. In previous chapters, all the pieces of an application resided on one machine. The class that represents the web service resides on a server—it’s not part of the client application.

Making a web service available to receive client requests is known as publishing a web service; using a web service from a client application is known as consuming a web service. An application that consumes a web service consists of two parts—an object of a service endpoint interface (SEI) class (sometimes called a proxy class) for interacting with the web service and a client application that consumes the web service by invoking methods on the object of the service endpoint interface. The client code invokes methods on the service endpoint interface object, which handles the details of passing method arguments to and receiving return values from the web service on the client’s behalf. This communication can occur over a local network, over the Internet or even with a web service on the same computer. The web service performs the corresponding task and returns the results to the service endpoint interface object, which then returns the results to the client code. Figure 23.1 depicts the interactions among the client code, the SEI object and the web service. As you’ll soon see, Netbeans creates these service endpoint interface classes for you.

Fig. 23.1. Interaction between a web service client and a web service.

Image

Requests to and responses from web services created with JAX-WS (one of many different web service frameworks) are typically transmitted via SOAP. Any client capable of generating and processing SOAP messages can interact with a web service, regardless of the language in which the web service is written. We discuss SOAP in Section 23.5.

23.3 Creating, Publishing, Testing and Describing a Web Service

The following subsections demonstrate how to create, publish and test a HugeInteger web service that performs calculations with positive integers up to 100 digits long (maintained as arrays of digits). Such integers are much larger than Java’s integral primitive types can represent (though the Java API does provide class BigInteger for arbitrary precision integers). The HugeInteger web service provides methods that take two “huge integers” (represented as Strings) and determine their sum, their difference, which is larger, which is smaller, or whether the two numbers are equal. These methods will be services available to other applications via the web—hence the term web services.

23.3.1 Creating a Web Application Project and Adding a Web Service Class in Netbeans

When you create a web service in Netbeans, you focus on the web service’s logic and let the IDE handle the web service’s infrastructure. To create a web service in Netbeans, you first create a Web Application project. Netbeans uses this project type for web services that are invoked by other applications.

Creating a Web Application Project in Netbeans

To create a web application, perform the following steps:

1. Select File > New Project to open the New Web Application dialog.

2. Select Java Web from the dialog’s Categories list, then select Web Application from the Projects list. Click Next >.

3. Specify the name of your project (HugeInteger) in the Project Name field and specify where you’d like to store the project in the Project Location field. You can click the Browse button to select the location. Click Next >.

4. Select GlassFish v2 from the Server drop-down list and Java EE 5 from the Java EE Version drop-down list.

5. Click Finish to dismiss the New Web Application dialog.

This creates a web application that will run in a web browser, similar to the projects used in Chapters 21 and 22.

Adding a Web Service Class to a Web Application Project

Perform the following steps to add a web service class to the project:

1. In the Projects tab in Netbeans, right click the HugeInteger project’s node and select New > Web Service... to open the New Web Service dialog.

2. Specify HugeInteger in the Web Service Name field.

3. Specify com.deitel.java.hugeinteger in the Package field.

4. Click Finish to dismiss the New Web Service dialog.

The IDE generates a sample web service class with the name you specified in Step 2. You can find this class in the Projects tab under the project’s Web Services node. In this class, you’ll define the methods that your web service makes available to client applications. When you eventually build your application, the IDE will generate other supporting files (which we’ll discuss shortly) for your web service.

23.3.2 Defining the HugeInteger Web Service in Netbeans

Figure 23.2 contains the HugeInteger web service’s code. You can implement this code yourself in the HugeInteger.java file created in Section 23.3.1, or you can simply replace the code in HugeInteger.java with a copy of our code from this example’s folder. You can find this file in the project’s srcjavacomdeiteljavahugeinteger folder. The book’s examples can be downloaded from www.deitel.com/books/javafp/.

Fig. 23.2. HugeInteger web service that performs operations on large integers.

Image

Image

Image

Image

Image

Image

Lines 5–7 import the annotations used in this example. By default, each new web service class created with the JAX-WS APIs is a POJO (plain old Java object), meaning that—unlike prior web services APIs—you do not need to extend a class or implement an interface to create a web service. When you deploy a web application containing a class that uses the @WebService annotation, the server (GlassFish in our case) recognizes that the class implements a web service and creates all the server-side artifacts that support the web service—that is, the framework that allows the web service to wait for client requests and respond to those requests once the service is deployed on an application server. Popular application servers that support Java web services include GlassFish (glassfish.dev.java.net), Apache Tomcat (tomcat.apache.org), BEA Weblogic Server (www.bea.com) and JBoss Application Server (www.jboss.org/products/jbossas). We use GlassFish in this chapter.

Lines 9–11 contain a @WebService annotation (imported at line 5) with properties name and serviceName. The @WebService annotation indicates that class HugeInteger implements a web service. The annotation is followed by a set of parentheses containing optional annotation attributes. The annotation’s name attribute (line 10) specifies the name of the service endpoint interface class that will be generated for the client. The annotation’s serviceName attribute (line 11) specifies the service name, which is also the name of the class that the client uses to obtain a service endpoint interface object. If the serviceName attribute is not specified, the web service’s name is assumed to be the java class name followed by the word Service. Netbeans places the @WebService annotation at the beginning of each new web service class you create. You can then add the name and serviceName properties in the parentheses following the annotation.

Line 14 declares the constant MAXIMUM that specifies the maximum number of digits for a HugeInteger (i.e., 100 in this example). Line 15 creates the array that stores the digits in a huge integer. Lines 18–40 declare method toString, which returns a String representation of a HugeInteger without any leading 0s. Lines 43–52 declare static method parseHugeInteger, which converts a String into a HugeInteger. The web service’s methods add, subtract, bigger, smaller and equals use parseHugeInteger to convert their String arguments to HugeIntegers for processing.

HugeInteger methods add, subtract, bigger, smaller and equals are tagged with the @WebMethod annotation (lines 55, 81, 117, 133 and 141) to indicate that they can be called remotely. Any methods that are not tagged with @WebMethod are not accessible to clients that consume the web service. Such methods are typically utility methods within the web service class. Note that the @WebMethod annotations each use the operationName attribute to specify the method name that is exposed to the web service’s client. If the operationName is not specified, it is set to the actual Java method’s name.

Common Programming Error 23.1

Image

Failing to expose a method as a web method by declaring it with the @WebMethod annotation prevents clients of the web service from accessing the method. There is one exception—if none of the class’s methods are declared with the @WebMethod annotation, then all the public methods of the class will be exposed as web methods.

Common Programming Error 23.2

Image

Methods with the @WebMethod annotation cannot be static. An object of the web service class must exist for a client to access the service’s web methods.

Each web method in class HugeInteger specifies parameters that are annotated with the @WebParam annotation (e.g., lines 56–57 of method add). The optional @WebParam attribute name indicates the parameter name that is exposed to the web service’s clients.

Lines 55–78 and 81–102 declare HugeInteger web methods add and subtract. We assume for simplicity that add does not result in overflow (i.e., the result will be 100 digits or fewer) and that subtract’s first argument will always be larger than the second. The subtract method calls method borrow (lines 105–114) when it is necessary to borrow 1 from the next digit to the left in the first argument—that is, when a particular digit in the left operand is smaller than the corresponding digit in the right operand. Method borrow adds 10 to the appropriate digit and subtracts 1 from the next digit to the left. This utility method is not intended to be called remotely, so it is not tagged with @WebMethod.

Lines 117–130 declare HugeInteger web method bigger. Line 123 invokes method subtract to calculate the difference between the numbers. If the first number is less than the second, this results in an exception. In this case, bigger returns false. If subtract does not throw an exception, then line 124 returns the result of the expression

!difference.matches( "^[0]+$" )

This expression calls String method matches to determine whether the String difference matches the regular expression "^[0]+$", which determines whether the String consists only of one or more 0s. The symbols ^ and $ indicate that matches should return true only if the entire String difference matches the regular expression. We then use the logical negation operator (!) to return the opposite boolean value. Thus, if the numbers are equal (i.e., their difference is 0), the preceding expression returns false—the first number is not greater than the second. Otherwise, the expression returns true.

Lines 133–146 declare methods smaller and equals. Method smaller returns the result of invoking method bigger (line 137) with the arguments reversed—if first is less than second, then second is greater than first. Method equals invokes methods bigger and smaller (line 145). If either bigger or smaller returns true, line 145 returns false, because the numbers are not equal. If both methods return false, the numbers are equal and line 145 returns true.

23.3.3 Publishing the HugeInteger Web Service from Netbeans

Now that we’ve created the HugeInteger web service class, we’ll use Netbeans to build and publish (i.e., deploy) the web service so that clients can consume its services. Netbeans handles all the details of building and deploying a web service for you. This includes creating the framework required to support the web service. Right click the project name (HugeInteger) in the Netbeans Projects tab to display the popup menu shown in Fig. 23.3. To determine if there are any compilation errors in your project, select the Build option. When the project compiles successfully, you can select Deploy to deploy the project to the server you selected when you set up the web application in Section 23.3.1. If the code in the project has changed since the last build, selecting Deploy also builds the project. Selecting Run executes the web application. If the web application was not previously built or deployed, this option performs these tasks first. Note that both the Deploy and Run options also start the application server (in our case GlassFish) if it is not already running. To ensure that all source-code files in a project are recompiled during the next build operation, you can use the Clean or Clean and Build options. If you have not already done so, select Deploy now. [Note: You can also publish a web service using a standard Java SE 6 application. For more information, see the article today.java.net/pub/a/today/2007/07/03/jax-ws-web-services-without-ee-containers.html.]

Fig. 23.3. A portion of the popup menu that appears when you right click a project name in the Netbeans Projects tab.

Image

23.3.4 Testing the HugeInteger Web Service with GlassFish Application Server’s Tester Web Page

The next step is to test the HugeInteger web service. We previously selected the GlassFish application server to execute this web application. This server can dynamically create a web page for testing a web service’s methods from a web browser. To enable this capability:

1. Right click the project name (HugeInteger) in the Netbeans Projects tab and select Properties from the popup menu to display the Project Properties dialog.

2. Click Run under Categories to display the options for running the project.

3. In the Relative URL field, type /HugeIntegerService?Tester.

4. Click OK to dismiss the Project Properties dialog.

The Relative URL field specifies what should happen when the web application executes. If this field is empty, then the web application’s default JSP displays when you run the project. When you specify /HugeIntegerService?Tester in this field, then run the project, the GlassFish application server builds the Tester web page and loads it into your web browser. Figure 23.4 shows the Tester web page for the HugeInteger web service.

Fig. 23.4. Tester web page created by GlassFish for the HugeInteger web service.

Image

You can also display the Tester web page by expanding the project’s Web Services folder in the Projects window, right clicking the HugeInteger node in that folder and selecting Test Web Service.

Once you’ve deployed the web service, you can also type the URL

http://localhost:8080/HugeInteger/HugeIntegerService?Tester

in your web browser to view the Tester web page. Note that HugeIntegerService is the name (specified in line 11 of Fig. 23.2) that clients, including the Tester web page, use to access the web service.

To test HugeInteger’s web methods, type two positive integers into the text fields to the right of a particular method’s button, then click the button to invoke the web method and see the result. Figure 23.5 shows the results of invoking HugeInteger’s add method with the values 99999999999999999 and 1. Note that the number 99999999999999999 is larger than primitive type long can represent.

Fig. 23.5. Testing HugeInteger’s add method.

(a) Invoking the HugeInteger web service’s add method.

Image

(b) Results of calling the add method with “99999999999999999” and “1”.

Image

Note that you can access the web service only when the application server is running. If Netbeans launches the application server for you, it will automatically shut it down when you close Netbeans. To keep the application server up and running, you can launch it independently of Netbeans before you deploy or run web applications in Netbeans. See the GlassFish Quick Start Guide at glassfish.dev.java.net/downloads/quickstart/index.html for information on starting and stopping the server manually.

Testing the HugeInteger Web Service from Another Computer

If your computer is connected to a network and allows HTTP requests, then you can test the web service from another computer on the network by typing the following URL (where host is the hostname or IP address of the computer on which the web service is deployed) into a browser on another computer:

http://host:8080/HugeInteger/HugeIntegerService?Tester

Note to Windows XP and Windows Vista Users

For security reasons, computers running Windows XP or Windows Vista do not allow HTTP requests from other computers by default. To allow other computers to connect to your computer using HTTP, perform the following steps on Windows XP:

1. Select Start > Control Panel to open your system’s Control Panel window, then double click Windows Firewall to view the Windows Firewall settings dialog.

2. In the Windows Firewall dialog, click the Exceptions tab, then click Add Port... and add port 8080 with the name GlassFish.

3. Click OK to dismiss the Windows Firewall settings dialog.

To allow other computers to connect to your Windows Vista computer using HTTP, perform the following steps:

1. Open the Control Panel, switch to Classic View and double click Windows Firewall to open the Windows Firewall dialog.

2. In the Windows Firewall dialog click the Change Settings... link.

3. In the Windows Firewall dialog, click the Exceptions tab, then click Add Port... and add port 8080 with the name GlassFish.

4. Click OK to dismiss the Windows Firewall settings dialog.

You may also be asked to unblock java.exe the first time you run the GlassFish server.

23.3.5 Describing a Web Service with the Web Service Description Language (WSDL)

Once you implement a web service and deploy it on an application server, a client application can consume the web service. To do so, however, the client must know where to find the web service and must be provided with a description of how to interact with it—that is, what methods are available, what parameters they expect and what each method returns. For this, JAX-WS uses the Web Service Description Language (WSDL)—a standard XML vocabulary for describing web services in a platform-independent manner.

You do not need to understand WSDL to take advantage of it—the GlassFish application server generates a web service’s WSDL dynamically for you, and client tools can parse the WSDL to help create the client-side service endpoint interface class that a client uses to access the web service. Since the WSDL is created dynamically, clients always receive a deployed web service’s most up-to-date description. To view the WSDL for the HugeInteger web service (Fig. 23.6), enter the following URL in your browser:

http://localhost:8080/HugeInteger/HugeIntegerService?WSDL

Fig. 23.6. A portion of the .wsdl file for the HugeInteger web service.

Image

or click the WSDL File link in the Tester web page (shown in Fig. 23.4).

Accessing the HugeInteger Web Service’s WSDL from Another Computer

Eventually, you’ll want clients on other computers to use your web service. Such clients need access to the web service’s WSDL, which they would access with the following URL:

http://host:8080/HugeInteger/HugeIntegerService?WSDL

where host is the hostname or IP address of the computer on which the web service is deployed. As we discussed in Section 23.3.4, this will work only if your computer allows HTTP connections from other computers—as is the case for publicly accessible web and application servers.

23.4 Consuming a Web Service

Now that we’ve defined and deployed our web service, we can consume it from a client application. A web service client can be any type of application or even another web service. You enable a client application to consume a web service by adding a web service reference to the application. This process defines the service endpoint interface class that allows the client to access the web service.

23.4.1 Creating a Client in Netbeans to Consume the HugeInteger Web Service

In this section, you’ll use Netbeans to create a client Java desktop GUI application, then you’ll add a web service reference to the project so the client can access the web service. When you add the web service reference, the IDE creates and compiles the client-side artifacts—the framework of Java code that supports the client-side service endpoint interface class. The client then calls methods on an object of the service endpoint interface class, which uses the rest of the artifacts to interact with the web service.

Creating a Desktop Application Project in Netbeans

Before performing the steps in this section, ensure that the HugeInteger web service has been deployed and that the GlassFish application server is running (see Section 23.3.3). Perform the following steps to create a client Java desktop application in Netbeans:

1. Select File > New Project... to open the New Project dialog.

2. Select Java from the Categories list and Java Application from the Projects list, then click Next >.

3. Specify the name UsingHugeInteger in the Project Name field and uncheck the Create Main Class checkbox. Later, you’ll add a subclass of JFrame that contains a main method.

4. Click Finish to create the project.

Adding a Web Service Reference to an Application

Next, you’ll add a web service reference to your application so that it can interact with the HugeInteger web service. To add a web service reference, perform the following steps.

1. Right click the project name (UsingHugeInteger) in the Netbeans Projects tab and select New > Web Service Client... from the popup menu to display the New Web Service Client dialog (Fig. 23.7).

Fig. 23.7. New Web Service Client dialog.

Image

2. In the WSDL URL field, specify the URL http://localhost:8080/HugeInteger/HugeIntegerService?WSDL (Fig. 23.7). This URL tells the IDE where to find the web service’s WSDL description. [Note: If the GlassFish application server is located on a different computer, replace localhost with the hostname or IP address of that computer.] The IDE uses this WSDL description to generate the client-side artifacts that compose and support the service endpoint interface. Note that the New Web Service Client dialog enables you to search for web services in several locations. Many companies simply distribute the exact WSDL URLs for their web services, which you can place in the WSDL URL field.

3. Click Finish to create the web service reference and dismiss the New Web Service Client dialog.

In the Netbeans Projects tab, the UsingHugeInteger project now contains a Web Service References folder with the HugeInteger web service’s service endpoint interface (Fig. 23.8). Note that the service endpoint interface’s name is listed as HugeIntegerService, as we specified in line 11 of Fig. 23.2.

Fig. 23.8. Netbeans Project tab after adding a web service reference to the project.

Image

When you specify the web service you want to consume, Netbeans accesses the web service’s WSDL information and copies it into a file in your project (named HugeIntegerService.wsdl in this example). You can view this file by double clicking the HugeIntegerService node in the project’s Web Service References folder or from the Files tab by expanding the nodes in the UsingHugeInteger project’s xml-resources folder (Fig. 23.9). If the web service changes, the client-side artifacts and the client’s copy of the WSDL file can be regenerated by right clicking the HugeIntegerService node shown in Fig. 23.8 and selecting Refresh Client.

Fig. 23.9. Locating the HugeIntegerService.wsdl file in the Netbeans Files tab.

Image

You can view the IDE-generated client-side artifacts by selecting the Netbeans Files tab and expanding the UsingHugeInteger project’s build folder as shown in Fig. 23.10.

Fig. 23.10. Viewing the HugeInteger web service’s client-side artifacts generated by Netbeans.

Image

23.4.2 Consuming the HugeInteger Web Service

For this example, we use a GUI application to interact with the HugeInteger web service. To build the client application’s GUI, you must first add a subclass of JFrame to the project. To do so, perform the following steps:

1. Right click the project name in the Netbeans Project tab and select New > JFrame Form... to display the New JFrame Form dialog.

2. Specify UsingHugeIntegerJFrame in the Class Name field.

3. Specify com.deitel.java.hugeintegerclient in the Package field.

4. Click Finish to close the New JFrame Form dialog.

Next, use the Netbeans GUI design tools to build the GUI shown in the sample screen captures at the end of Fig. 23.11. The GUI consists of a label, two text fields, five buttons and a text area.

Fig. 23.11. Client desktop application for the HugeInteger web service.

Image

Image

Image

Image

Image

Image

Image

Image

Image

The application in Fig. 23.11 uses the HugeInteger web service to perform computations with positive integers up to 100 digits long. To save space, we do not show the Netbeans autogenerated initComponents method, which contains the code that creates the GUI components, positions them and registers their event handlers. To view the complete source code, open the UsingHugeIntegerJFrame.java file in this example’s folder under srcjavacomdeiteljavahugeintegerclient. Netbeans places the GUI component instance-variable declarations at the end of the class (lines 317–326). Java allows instance variables to be declared anywhere in a class’s body as long as they are placed outside the class’s methods. We continue to declare our own instance variables at the top of the class.

Lines 5–6 import the classes HugeInteger and HugeIntegerService that enable the client application to interact with the web service. Notice that we do not have import declarations for most of the GUI components used in this example. When you create a GUI in Netbeans, it uses fully qualified class names (such as javax.swing.JFrame in line 9), so import declarations are unnecessary.

Line 12 declares a variable of type HugeInteger that will refer to the service endpoint interface object. Line 22 in the constructor creates an object of type HugeIntegerService. Line 23 uses this object’s getHugeIntegerPort method to obtain the HugeInteger service endpoint interface object that the application uses to invoke the web service’s methods.

Lines 156–157, 180–181, 204–205, 231–232 and 258–259 in the various JButton event handlers invoke the HugeInteger web service’s web methods. Note that each call is made on the local service endpoint interface object that is referenced by hugeIntegerProxy. This object then communicates with the web service on the client’s behalf.

The user enters two integers, each up to 100 digits long. Clicking a JButton causes the application to invoke a web method to perform the corresponding task and return the result. Our client application cannot process 100-digit numbers directly. Instead it passes String representations of these numbers to the web service’s web methods, which perform tasks for the client. The client application then uses the return value of each operation to display an appropriate message. [Note: For simplicity in this example, we assume that the first number in a subtraction operation is larger than the second.]

23.5 SOAP

SOAP (Simple Object Access Protocol) is a platform-independent protocol that uses XML to facilitate remote procedure calls, typically over HTTP. SOAP is one common protocol for passing information between web service clients and web services. The protocol that transmits request-and-response messages is also known as the web service’s wire format or wire protocol, because it defines how information is sent “along the wire.”

Each request and response is packaged in a SOAP message (also known as a SOAP envelope)—an XML “wrapper” containing the information that a web service requires to process the message. SOAP messages are written in XML so that they are platform independent. Many firewalls—security barriers that restrict communication among networks—are configured to allow HTTP traffic to pass through so that clients can browse websites on web servers behind firewalls. Thus, XML and HTTP enable computers on different platforms to send and receive SOAP messages with few limitations.

The wire format used to transmit requests and responses must support all data types passed between the applications. Web services also use SOAP for the many data types it supports. SOAP supports primitive types (e.g., int) and their wrapper types (e.g., Integer), as well as Date, Time and others. SOAP can also transmit arrays and objects of user-defined types (as you’ll see in Section 23.8). For more SOAP information, visit www.w3.org/TR/soap/.

When a program invokes a web method, the request, the arguments and any other relevant information are packaged in a SOAP message and sent to the server on which the web service resides. The web service processes the SOAP message’s contents (contained in a SOAP envelope), which specify the method that the client wishes to invoke and the method’s arguments. This process of interpreting a SOAP message’s contents is known as parsing a SOAP message. After the web service receives and parses a request, the proper method is called with any specified arguments, and the response is sent back to the client in another SOAP message. The client-side service endpoint interface parses the response, which contains the result of the method call, and returns the result to the client application.

Figure 23.5 used the HugeInteger web service’s Tester web page to show the result of invoking HugeInteger’s add method with the values 99999999999999999 and 1. The Tester web page also shows the SOAP request and response messages (which were not previously shown). Figure 23.12 shows the SOAP messages in the Tester web page from Fig. 23.5 after the calculation. In the request message from Fig. 23.12, the text

<ns2:add xmlns:ns2="http://hugeinteger.java.deitel.com/">
      <first>99999999999999999</first>
      <second>1</second>
</ns2:add>

Fig. 23.12. SOAP messages for the HugeInteger web service’s add method as shown by the GlassFish application server’s Tester web page.

Image

specifies the method to call (add), the method’s arguments (first and second) and the arguments’ values (99999999999999999 and 1). Similarly, the text

<ns2:addResponse xmlns:ns2="http://hugeinteger.java.deitel.com/">
      <return>100000000000000000</return>
</ns2:addResponse>

from the response message in Fig. 23.12 specifies the return value of method add. As with the WSDL for a web service, the SOAP messages are generated for you automatically, so you don’t need to understand the details of SOAP or XML to take advantage of it when publishing and consuming web services.

23.6 Session Tracking in Web Services

Section 21.7 described the advantages of using session tracking to maintain client-state information so you can personalize the users’ browsing experiences. Now we’ll incorporate session tracking into a web service. Suppose a client application needs to call several methods from the same web service, possibly several times each. In such a case, it can be beneficial for the web service to maintain state information for the client, thus eliminating the need for client information to be passed between the client and the web service multiple times. For example, a web service that provides local restaurant reviews could store the client user’s street address during the initial request, then use it to return personalized, localized results in subsequent requests. Storing session information also enables a web service to distinguish between clients.

23.6.1 Creating a Blackjack Web Service

Our next example is a web service that assists you in developing a blackjack card game. The Blackjack web service (Fig. 23.13) provides web methods to shuffle a deck of cards, deal a card from the deck and evaluate a hand of cards. After presenting the web service, we use it to serve as the dealer for a game of blackjack (Fig. 23.14). The Blackjack web service uses an HttpSession object to maintain a unique deck of cards for each client application. Several clients can use the service at the same time, but web method calls made by a specific client use only the deck of cards stored in that client’s session. Our example uses the following blackjack rules:

Two cards each are dealt to the dealer and the player. The player’s cards are dealt face up. Only the first of the dealer’s cards is dealt face up. Each card has a value. A card numbered 2 through 10 is worth its face value. Jacks, queens and kings each count as 10. Aces can count as 1 or 11—whichever value is more beneficial to the player (as we’ll soon see). If the sum of the player’s two initial cards is 21 (i.e., the player was dealt a card valued at 10 and an ace, which counts as 11 in this situation), the player has “blackjack” and immediately wins the game—if the dealer does not also have blackjack (which would result in a “push”—i.e., a tie). Otherwise, the player can begin taking additional cards one at a time. These cards are dealt face up, and the player decides when to stop taking cards. If the player “busts” (i.e., the sum of the player’s cards exceeds 21), the game is over, and the player loses. When the player is satisfied with the current set of cards, the player “stands” (i.e., stops taking cards), and the dealer’s hidden card is revealed. If the dealer’s total is 16 or less, the dealer must take another card; otherwise, the dealer must stand. The dealer must continue taking cards until the sum of the dealer’s cards is greater than or equal to 17. If the dealer exceeds 21, the player wins. Otherwise, the hand with the higher point total wins. If the dealer and the player have the same point total, the game is a “push,” and no one wins. Note that the value of an ace for a dealer depends on the dealer’s other card(s) and the casino’s house rules. A dealer typically must hit for totals of 16 or less and must stand for totals of 17 or more. However, for a “soft 17”—a hand with a total of 17 with one ace counted as 11—some casinos require the dealer to hit and some require the dealer to stand (we require the dealer to stand). Such a hand is known as a “soft 17” because taking another card cannot bust the hand.

Fig. 23.13. Blackjack web service that deals cards and evaluates hands.

Image

Image

Image

Image

Fig. 23.14. Blackjack game that uses the Blackjack web service.

Image

Image

Image

Image

Image

Image

Image

Image

Image

Image

Image

Image

Image

Image

a) Dealer and player hands after the user clicks the Deal JButton.

Image

b) Dealer and player hands after the user clicks Hit twice, then clicks Stand. In this case, the result is a push.

Image

c) Dealer and player hands after the user clicks Stand based on the initial hand. In this case, the player wins.

Image

d) Dealer and player hands after the user is dealt blackjack.

Image

e) Dealer and player hands after the dealer is dealt blackjack.

Image

The web service (Fig. 23.13) stores each card as a String consisting of a number, 113, representing the card’s face (ace through king, respectively), followed by a space and a digit, 03, representing the card’s suit (hearts, diamonds, clubs or spades, respectively). For example, the jack of clubs is represented as "11 2" and the two of hearts as "2 0". To create and deploy this web service, follow the steps that we presented in Sections 23.3.223.3.3 for the HugeInteger service.

Session Tracking in Web Services

A client of the Blackjack web service first calls method shuffle (lines 40–71) to shuffle the deck of cards and place the deck into an HttpSession object that is specific to that client. To use session tracking in a web service, you must include code for the resources that maintain the session-state information. In the past, you had to write the sometimes tedious code to create these resources. JAX-WS, however, handles this for you via the @Resource annotation. This annotation enables tools like Netbeans to “inject” support objects into your class, thus allowing you to focus on your business logic rather than the support code. The server is responsible for initializing the support objects. The concept of using annotations to add code that supports your classes is known as dependency injection. Annotations such as @WebService, @WebMethod and @WebParam also perform dependency injection.

Line 20 injects a WebServiceContext object into your class. A WebServiceContext object enables a web service to access and maintain information such as session state for a specific request. As you look through the code in Fig. 23.13, you’ll notice that we never explicitly create the WebServiceContext object—that code is injected into the class by the @Resource annotation. Line 21 declares a variable of interface type MessageContext that the web service will use to obtain an HttpSession object for the current client. Line 22 declares the HttpSession variable that the web service will use to manipulate the session-state information.

Line 44 in method shuffle uses the WebServiceContext object that was injected in line 20 to obtain a MessageContext object. Lines 45–46 then use the MessageContext object’s get method to obtain the HttpSession object for the current client. Method get receives a constant indicating what to get from the MessageContext. In this case, the constant MessageContext.SERVLET_REQUEST indicates that we’d like to get the HttpServletRequest object for the current client. We then call the HttpServletRequest method getSession to obtain the HttpSession object.

Lines 49–70 generate an ArrayList representing a deck of cards, shuffle the deck and store the deck in the client’s session object. Lines 51–53 generate Strings in the form "face suit" to represent each possible card in the deck. Lines 59–67 shuffle the deck by swapping each card with another card selected at random. Line 70 uses HttpSession method setAttribute to insert the ArrayList in the session object to maintain the deck between method calls from a particular client.

Lines 25–37 define method dealCard as a web method. Lines 30–31 use the session object to obtain the "deck" session attribute that was stored in line 70 of method shuffle. Method getAttribute takes as a parameter a String that identifies the Object to obtain from the session state. The HttpSession can store many Objects, provided that each has a unique identifier. Note that method shuffle must be called before method dealCard is called the first time for a client—otherwise, an exception occurs at line 33, because getAttribute returns null at lines 30–31. After obtaining the user’s deck, dealCard gets the top card from the deck (line 33), removes it from the deck (line 34) and returns the card’s value as a String (line 36). Without using session tracking, the deck of cards would need to be passed back and forth with each method call. Session tracking makes the dealCard method easy to call (it requires no arguments) and eliminates the overhead of sending the deck over the network multiple times.

Method getHandValue (lines 74–116) determines the total value of the cards in a hand by trying to attain the highest score possible without going over 21. Recall that an ace can be counted as either 1 or 11, and all face cards count as 10. This method does not use the session object, because the deck of cards is not used in this method.

As you’ll soon see, the client application maintains a hand of cards as a String in which each card is separated by a tab character. Line 78 tokenizes the hand of cards (represented by hand) into individual cards by calling String method split and passing to it a String containing the delimiter characters (in this case, just a tab). Method split uses the delimiter characters to separate tokens in the String. Lines 83–103 count the value of each card. Lines 86–87 retrieve the first integer—the face—and use that value in the switch statement (lines 89–102). If the card is an ace, the method increments variable aceCount. We discuss how this variable is used shortly. If the card is an 11, 12 or 13 (jack, queen or king), the method adds 10 to the total value of the hand (line 97). If the card is anything else, the method increases the total by that value (line 100).

Because an ace can have either of two values, additional logic is required to process aces. Lines 106–113 of method getHandValue process the aces after all the other cards. If a hand contains several aces, only one ace can be counted as 11. The condition in line 109 determines whether counting one ace as 11 and the rest as 1 will result in a total that does not exceed 21. If this is possible, line 110 adjusts the total accordingly. Otherwise, line 112 adjusts the total, counting each ace as 1.

Method getHandValue maximizes the value of the current cards without exceeding 21. Imagine, for example, that the dealer has a 7 and receives an ace. The new total could be either 8 or 18. However, getHandValue always maximizes the value of the cards without going over 21, so the new total is 18.

23.6.2 Consuming the Blackjack Web Service

The blackjack application in Fig. 23.14 keeps track of the player’s and dealer’s cards, and the web service tracks the cards that have been dealt. The constructor (lines 34–83) sets up the GUI (line 36), changes the window’s background color (line 40) and creates the Blackjack web service’s service endpoint interface object (lines 46–47). In the GUI, each player has 11 JLabels—the maximum number of cards that can be dealt without automatically exceeding 21 (i.e., four aces, four twos and three threes). These JLabels are placed in an ArrayList of JLabels (lines 59–82), so we can index the ArrayList during the game to determine the JLabel that will display a particular card image.

With JAX-WS, the client application must indicate whether it wants to allow the web service to maintain session information. Lines 50–51 in the constructor perform this task. We first cast the service endpoint interface object to interface type BindingProvider. A BindingProvider enables the client to manipulate the request information that will be sent to the server. This information is stored in an object that implements interface RequestContext. The BindingProvider and RequestContext are part of the framework that is created by the IDE when you add a web service client to the application. Next, we invoke the BindingProvider’s getRequestContext method to obtain the RequestContext object. Then we call the RequestContext’s put method to set the property

BindingProvider.SESSION_MAINTAIN_PROPERTY

to true. This enables the client side of the session-tracking mechanism, so that the web service knows which client is invoking the service’s web methods.

Method gameOver (lines 195–233) displays all the dealer’s cards, shows the appropriate message in statusJLabel and displays the final point totals of both the dealer and the player. Method gameOver receives as an argument a member of the GameStatus enumeration (defined in lines 25–31). The enumeration represents whether the player tied, lost or won the game; its four members are PUSH, LOSE, WIN and BLACKJACK.

When the player clicks the Deal JButton, method dealJButtonActionPerformed (lines 543–602) clears all of the JLabels that display cards or game status information. Next, the deck is shuffled (line 559), and the player and dealer receive two cards each (lines 562–573). Lines 580–581 then total each hand. If the player and the dealer both obtain scores of 21, the program calls method gameOver, passing GameStatus.PUSH (line 586). If only the dealer has 21, the program passes GameStatus.LOSE to method gameOver (line 590). If only the player has 21 after the first two cards are dealt, the program passes GameStatus.BLACKJACK to method gameOver (line 594).

If dealJButtonActionPerformed does not call gameOver, the player can take more cards by clicking the Hit JButton, which calls hitJButtonActionPerformed in lines 605–628. Each time a player clicks Hit, the program deals the player one more card (line 609) and displays it in the GUI (line 613). If the player exceeds 21, the game is over and the player loses (line 621). If the player has exactly 21, the player is not allowed to take any more cards (line 625), and method dealerPlay is called (line 626).

Method dealerPlay (lines 86–139) displays the dealer’s cards, then deals cards to the dealer until the dealer’s hand has a value of 17 or more (lines 110–108). If the dealer exceeds 21, the player wins (line 116); otherwise, the values of the hands are compared, and gameOver is called with the appropriate argument (lines 122–133).

Clicking the Stand JButton indicates that a player does not want to be dealt another card. Method standJButtonActionPerformed (lines 631–638) disables the Hit and Stand buttons, enables the Deal button, then calls method dealerPlay.

Method displayCard (lines 142–192) updates the GUI to display a newly dealt card. The method takes as arguments an integer index for the JLabel in the ArrayList that must have its image set and a String representing the card. An empty String indicates that we wish to display the card face down. If method displayCard receives a String that’s not empty, the program extracts the face and suit from the String and uses this information to display the correct image. The switch statement (lines 167–181) converts the number representing the suit to an integer and assigns the appropriate character to variable suitLetter (h for hearts, d for diamonds, c for clubs and s for spades). The character in suitLetter is used to complete the image’s filename (lines 184–186). You must add the folder blackjack_images to your project so that lines 152–154 and 184–186 can access the images properly. To do so, copy the folder blackjack_images from this chapter’s examples folder and paste it into the project’s srccomdeiteljavalackjackclient folder.

In this example, you learned how to set up a web service to support session handling so that you could keep track of each client’s session state. You also learned how to indicate from a desktop client application that it wishes to take part in session tracking. You’ll now learn how to access a database from a web service and how to consume a web service from a client web application.

23.7 Consuming a Database-Driven Web Service from a Web Application

Our prior examples accessed web services from desktop applications created in Netbeans. However, we can just as easily use them in web applications created with Netbeans. In fact, because web-based businesses are becoming increasingly prevalent, it is common for web applications to consume web services. In this section, we present an airline reservation web service that receives information regarding the type of seat a customer wishes to reserve and makes a reservation if such a seat is available. Later in the section, we present a web application that allows a customer to specify a reservation request, then uses the airline reservation web service to attempt to execute the request.

23.7.1 Creating the Reservation Database

In this example, our web service uses a Reservation database containing a single table named Seats to locate a seat matching a client’s request. To build the Reservation database, review the steps presented in Section 22.2.1 for building the AddressBook database. This chapter’s examples directory contains the Seats.sql SQL script to build the seats table and populate it with sample data. The sample data is shown in Fig. 23.15.

Fig. 23.15. Data from the seats table.

Image

Creating the Reservation Web Service

You can now create a web service that uses the Reservation database (Fig. 23.16). The airline reservation web service has a single web method—reserve (lines 26–78)—which searches the Seats table to locate a seat matching a user’s request. The method takes two arguments—a String representing the desired seat type (i.e., "Window", "Middle" or "Aisle") and a String representing the desired class type (i.e., "Economy" or "First"). If it finds an appropriate seat, method reserve updates the database to make the reservation and returns true; otherwise, no reservation is made, and the method returns false. Note that the statements at lines 34–39 and lines 44–48 that query and update the database use objects of JDBC types ResultSet and PreparedStatement.

Fig. 23.16. Airline reservation web service.

Image

Image

Image

Software Engineering Observation 23.1

Image

Using PreparedStatements to create SQL statements is highly recommended to secure against so-called SQL injection attacks in which executable code is inserted SQL code. The site www.owasp.org/index.php/Preventing_SQL_Injection_in_Java provides a summary of SQL injection attacks and ways to mitigate against them.

Our database contains four columns—the seat number (i.e., 110), the seat type (i.e., Window, Middle or Aisle), the class type (i.e., Economy or First) and a column containing either 1 (true) or 0 (false) to indicate whether the seat is taken. Lines 34–39 retrieve the seat numbers of any available seats matching the requested seat and class type. This statement fills the resultSet with the results of the query

SELECT "number"
FROM "seats"
WHERE ("taken" = 0AND ("type" = typeAND ("class" = yclass)

The parameters type and class in the query are replaced with values of method reserve’s seatType and classType parameters. When you use the Netbeans tools to create a database table and its columns, the Netbeans tools automatically place the table and column names in double quotes. For this reason, you must place the table and column names in double quotes in the SQL statements that interact with the Reservation database.

If resultSet is not empty (i.e., at least one seat is available that matches the selected criteria), the condition in line 42 is true and the web service reserves the first matching seat number. Recall that ResultSet method next returns true if a nonempty row exists, and positions the cursor on that row. We obtain the seat number (line 44) by accessing resultSet’s first column (i.e., resultSet.getInt(1)—the first column in the row). Then lines 45–48 configure a PreparedStatement and execute the SQL:

UPDATE  "seats"
SET "taken" = 1
WHERE ("number" = number)

which marks the seat as taken in the database. The parameter number is replaced with the value of seat. Method reserve returns true (line 49) to indicate that the reservation was successful. If there are no matching seats, or if an exception occurred, method reserve returns false (lines 52, 57, 62 and 75) to indicate that no seats matched the user’s request.

23.7.2 Creating a Web Application to Interact with the Reservation Web Service

This section presents a ReservationClient web application that consumes the Reservation web service. The application allows users to select seats based on class ("Economy" or "First") and location ("Aisle", "Middle" or "Window"), then submit their requests to the airline reservation web service. If the database request is not successful, the application instructs the user to modify the request and try again. The application presented here was built using the techniques presented in Chapters 2122. We assume that you’ve already read those chapters, and thus know how to build a web application’s GUI, create event handlers and add properties to a web application’s session bean (Section 21.7.2).

Reserve.jsp

Reserve.jsp (Fig. 23.17) defines two DropDownLists and a Button. The seatTypeDropDown (lines 23–28) displays all the seat types from which users can select. The classTypeDropDownList (lines 29–35) provides choices for the class type. When the user makes a selection from each of these, corresponding event handlers store the selected values in the session bean. We added seatType and classType properties to the session bean for this purpose. Users click the reserveButton (lines 36–40) to submit requests after making selections from the DropDownLists. The page also defines three Labels—instructionLabel (lines 18–22) to display instructions, successLabel (lines 41–44) to indicate a successful reservation and errorLabel (lines 45–49) to display a message if there are no seats that match the user’s selection. The page bean file (Fig. 23.18) contains the event handlers for seatTypeDropDown, classTypeDropDown and reserveButton.

Fig. 23.17. JSP that allows a user to select a seat.

Image

Image

a) Selecting a seat:

Image

b) Seat reserved successfully:

Image

c) Attempting to reserve another window seat in economy when there are no such seats available:

Image

d) No seats match the requested seat type and class:

Image

Fig. 23.18. Page bean for seat reservation client.

Image

Image

Image

Image

Reserve.java

Figure 23.18 contains the page bean code that provides the logic for Reserve.jsp. As discussed in Section 21.5.2, the class that represents the page’s bean extends AbstractPageBean. When the user selects a value in one of the DropDownLists, the corresponding event handler—seatTypeDropDown_processValueChange (lines 199–204) or classTypeDropDown_processValueChange (lines 207–212)—is called to set the session properties seatType and classType, which we added to the web application’s session bean. The values of these properties are used as the arguments in the call to the web service’s reserve method. When the user clicks Reserve in the JSP, the event handler reserveButton_action (lines 215–248) executes. Lines 219–221 use the service endpoint interface object (created in lines 40–41) to invoke the web service’s reserve method, passing the selected seat type and class type as arguments. If reserve returns true, lines 225–230 hide the GUI components in the JSP and display the successLabel (line 229) to thank the user for making a reservation; otherwise, lines 234–239 ensure that the GUI components remain displayed and display the errorLabel (line 239) to notify the user that the requested seat type is not available and instruct the user to try again.

23.8 Passing an Object of a User-Defined Type to a Web Service

The web methods we’ve demonstrated so far each receive and return only primitive values or Strings. Web services also can receive and return objects of user-defined types—known as custom types. This section presents an EquationGenerator web service that generates random arithmetic questions of type Equation. The client is a math-tutoring desktop application in which the user selects the type of mathematical question to attempt (addition, subtraction or multiplication) and the skill level of the user—level 1 uses one-digit numbers in each question, level 2 uses two-digit numbers and level 3 uses three-digit numbers. The client passes this information to the web service, which then generates an Equation consisting of random numbers with the proper number of digits. The client application receives the Equation, displays the sample question to the user in a Java application, allows the user to provide an answer and checks the answer to determine whether it is correct.

Serialization of User-Defined Types

We mentioned earlier that all types passed to and from SOAP web services must be supported by SOAP. How, then, can SOAP support a type that is not even created yet? Custom types that are sent to or from a web service are serialized into XML format. This process is referred to as XML serialization. The process of serializing objects to XML and deserializing objects from XML is handled for you automatically.

Requirements for User-Defined Types Used with Web Methods

A class that is used to specify parameter or return types in web methods must meet several requirements:

1. It must provide a public default or no-argument constructor. When a web service or web service consumer receives an XML serialized object, the JAX-WS framework must be able to call this constructor when deserializing the object (i.e., converting it from XML back to a Java object).

2. Instance variables that should be serialized in XML format must have public set and get methods to access the private instance variables (recommended), or the instance variables must be declared public (not recommended).

3. Non-public instance variables that should be serialized must provide both set and get methods (even if they have empty bodies); otherwise, they’re not serialized.

Any instance variable that is not serialized simply receives its default value (or the value provided by the no-argument constructor) when an object of the class is deserialized.

Common Programming Error 23.3

Image

A runtime error occurs if an attempt is made to deserialize an object of a class that does not have a default or no-argument constructor.

Defining Class Equation

Figure 23.19 defines class Equation. Lines 18–31 define a constructor that takes three arguments—two ints representing the left and right operands and a String that represents the arithmetic operation to perform. The constructor sets the leftOperand, rightOperand and operationType instance variables, then calculates the appropriate result. The no-argument constructor (lines 13–16) calls the three-argument constructor (lines 18–31) and passes default values. We do not use the no-argument constructor explicitly, but the XML serialization mechanism uses it when objects of this class are deserialized. Because we provide a constructor with parameters, we must explicitly define the no-argument constructor in this class so that objects of the class can be passed to or returned from web methods.

Fig. 23.19. Class Equation that stores information about an equation.

Image

Image

Image

Image

Class Equation defines methods getLeftHandSide and setLeftHandSide (lines 41–44 and 77–80); getRightHandSide and setRightHandSide (lines 47–50 and 83–86); getLeftOperand and setLeftOperand (lines 53–56 and 89–92); getRightOperand and setRightOperand (lines 59–62 and 95–98); getReturnValue and setReturnValue (lines 65–68 and 101–104); and getOperationType and setOperationType (lines 71–74 and 107–110). The client of the web service does not need to modify the values of the instance variables. However, recall that a property can be serialized only if it has both a get and a set accessor, or if it is public. So we provided set methods with empty bodies for each of the class’s instance variables. Method getLeftHandSide (lines 41–44) returns a String representing everything to the left of the equals (=) sign in the equation, and getRightHandSide (lines 47–50) returns a String representing everything to the right of the equals (=) sign. Method getLeftOperand (lines 53–56) returns the integer to the left of the operator, and getRightOperand (lines 59–62) returns the integer to the right of the operator. Method getResultValue (lines 65–68) returns the solution to the equation, and getOperationType (lines 71–74) returns the operator in the equation. The client in this example does not use the rightHandSide property, but we included it so future clients can use it.

Creating the EquationGenerator Web Service

Figure 23.20 presents the EquationGenerator web service, which creates random, customized Equations. This web service contains only method generateEquation (lines 18–31), which takes two parameters—the mathematical operation (one of "+", "-" or "*") and an int representing the difficulty level (1–3).

Fig. 23.20. Web service that generates random equations.

Image

Testing the EquationGenerator Web Service

Figure 23.21 shows the result of testing the EquationGenerator service with the Tester web page. In part (b), note that the web method’s return value is XML encoded. However, this example differs from previous ones in that the XML specifies the values for all the data of the returned XML serialized object. The service endpoint interface class receives this return value and deserializes it into an object of class Equation, then passes it to the client.

Fig. 23.21. Testing a web method that returns an XML serialized Equation object.

(a) Using the EquationGenerator web service‘s Tester web page to generate an Equation.

Image

(b) Result of generating an Equation.

Image

Note that an Equation object is not being passed between the web service and the client. Rather, the information in the object is being sent as XML-encoded data. Clients created using Java will take the information and create a new Equation object. Clients created on other platforms, however, may use the information differently. Readers creating clients on other platforms should check the web services documentation for the specific platform they are using, to see how their clients may process custom types.

Details of the EquationGenerator Web Service

Let’s examine web method generateEquation more closely. Lines 23–24 of Fig. 23.20 define the upper and lower bounds of the random numbers that the method uses to generate an Equation. To set these limits, the program first calls static Math method pow. Variable minimum’s value is determined by raising 10 to a power one less than difficulty (line 23). This calculates the smallest number with difficulty digits. If difficulty is 1, minimum is 1; if difficulty is 2, minimum is 10; and if difficulty is 3, minimum is 100. To calculate the value of maximum (the upper bound for numbers used to form an Equation), the program raises 10 to the power of the specified difficulty argument (line 24). If difficulty is 1, maximum is 10; if difficulty is 2, maximum is 100; and if difficulty is 3, maximum is 1000.

Lines 28–30 create and return a new Equation object consisting of two random numbers and the String operation received by generateEquation. Random method nextInt returns an int that is less than the specified upper bound. Method generateEquation generates operand values that are greater than or equal to minimum but less than maximum (i.e., a number with difficulty number of digits).

Consuming the EquationGenerator Web Service

The Math Tutor application (Fig. 23.22) uses the EquationGenerator web service. The application calls the web service’s generateEquation method to create an Equation object. The tutor then displays the left-hand side of the Equation and waits for user input. Lines 12–13 declare instance variables of types EquationGenerator and Equation that we use to interact with the web service.

Fig. 23.22. Math tutoring application.

Image

Image

Image

Image

Image

Image

After displaying an equation, the application waits for the user to enter an answer. The default setting for the difficulty level is One-digit numbers, but the user can change this by choosing a level from the Choose level JComboBox. Clicking any of the levels invokes levelJComboBoxItemStateChanged (lines 170–175), which sets the variable difficulty to the level selected by the user. Although the default setting for the question type is Addition, the user also can change this by selecting an operation from the Choose operation JComboBox. Doing so invokes operationJComboBoxItemStateChanged (lines 156–167), which sets the String operation to the appropriate mathematical symbol.

When the user clicks the Generate Equation JButton, method generateButtonActionPerformed (lines 178–192) invokes the EquationGenerator web service’s generateEquation (line 183) method, which returns an Equation object. After receiving the Equation object from the web service, the handler obtains the Equation’s correct answer (line 184) and lefthand side, then displays the left-hand side in equationJLabel (line 185) and enables the checkAnswerJButton so that the user can submit an answer. When the user clicks the Check Answer JButton, method checkAnswerJButtonActionPerformed (lines 195–219) determines whether the user provided the correct answer.

23.9 Wrap-Up

This chapter introduced JAX-WS web services, which promote software portability and reusability in applications that operate over the Internet. You learned that a web service is a software component stored on one computer that can be accessed by an application (or other software component) on another computer over a network, communicating via such technologies as XML, SOAP and HTTP. We discussed several benefits of this kind of distributed computing—e.g., clients can access data on remote machines, clients lacking the processing power to perform specific computations can leverage remote machines’ resources and entirely new types of innovative applications can be developed.

We explained how Netbeans and the JAX-WS APIs facilitate the creation and consumption of web services. We showed how to set up projects and files in these tools and how the tools manage the web service infrastructure necessary to support the web services you create. You learned how to define web services and web methods, as well as how to consume them both from Java desktop applications and from web applications. After explaining the mechanics of web services with our HugeInteger example, we demonstrated more sophisticated web services that use session tracking and access databases. We also explained XML serialization and showed how to pass objects of user-defined types to web services and return them from web services.

The next chapter discusses formatting output with method System.out.printf and with class Formatter.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset