UNPKG

epubjs

Version:

Render ePub documents in the browser, across many devices

210 lines (197 loc) 25.4 kB
<?xml version="1.0" encoding="UTF-8" standalone="no"?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"><head><title>Implementing Web Services</title><link rel="stylesheet" href="core.css" type="text/css"/><meta name="generator" content="DocBook XSL Stylesheets V1.74.0"/></head><body><div class="sect1" title="Implementing Web Services"><div class="titlepage"><div><div><h1 class="title"><a id="learnjava3-CHP-15-SECT-6"/>Implementing Web Services</h1></div></div></div><p>Now that we’ve covered servlets and web applications in detail, we’d like to return to the topic of web services. In the previous chapter, we introduced the concept of a web service as an extension of the basic HTTP web transaction, using XML content for application-to-application communication instead of consumption by a web browser client. In that chapter, we showed how easy it is to invoke an RPC-style web service, by using client-side classes generated from a WSDL description file. In this section, we’ll show the other side of that equation and demonstrate how to implement and deploy a web service.</p><p>The world of web services has evolved quickly, as have the APIs, buzzwords, and hype. The appeal of this style of interapplication communication using simple web protocols has, to some extent, been tarnished by the design-by-committee approach of many standards bodies and competitors adding features and layers to the web services concept. The truth is that web services were originally simple and elegant when compared to more elaborate protocols, largely because they did not support all of the same semantics—state management, callbacks, transactions, authentication, and security. As these features are added, the complexity returned. We will not cover all aspects of web services in detail but instead focus on the basic RPC style that is appealing for a wide variety of simple applications.</p><p>In <a class="xref" href="ch14.html" title="Chapter 14. Programming for the Web">Chapter 14</a>, we walked through generating and running the client side of a web service (the weather service). In this chapter, we’ll build and deploy our own web service, a simple one that echoes parameters back to the client: <code class="literal">EchoService</code>. We’ll be using the built in JAX-WS APIs tools and services container to run this example, although you could deploy the service to Tomcat as well with some additional configuration and packaging into a WAR file.</p><div class="sect2" title="Defining the Service"><div class="titlepage"><div><div><h2 class="title"><a id="learnjava3-CHP-15-SECT-6.3"/>Defining the Service</h2></div></div></div><p><a id="I_indexterm15_id783919" class="indexterm"/>To build our client-side API in <a class="xref" href="ch14.html" title="Chapter 14. Programming for the Web">Chapter 14</a>, we began by downloading the WSDL description file for the (existing) weather service. The WSDL, again, is an XML file that describes the functions of the service and the types of arguments and return values they use. From this description, the <a id="I_indexterm15_id783934" class="indexterm"/><span class="emphasis"><em>wsimport</em></span> command was able to generate the client-side classes that we needed to invoke the service remotely from Java.</p><p>In creating our own web service, we have (at least) two choices. We could follow an analogous process, writing a WSDL document describing our service and using it to generate the necessary server-side framework. The <span class="emphasis"><em>wsimport</em></span> class that we used before can be used to generate the necessary, annotated service interface for us and we could implement it with our code. However, there is a much easier way: going code-first.</p><p>The <a id="I_indexterm15_id783956" class="indexterm"/><span class="emphasis"><em>wsgen</em></span> command complements <span class="emphasis"><em>wsimport</em></span> by adding the capability to read annotated Java classes and generate WSDL and related service classes for us. Even better, if we deploy our class using the built-in JAX-WS endpoint publisher, it will take care of generating all of this for us. This means that to test a simple web service, all we really have to do is write a service class that marks the class and service methods with the correct annotations and invoke the publisher. It really couldn’t get much easier.</p></div><div class="sect2" title="Our Echo Service"><div class="titlepage"><div><div><h2 class="title"><a id="learnjava3-CHP-15-SECT-6.4"/>Our Echo Service</h2></div></div></div><p><a id="idx10908" class="indexterm"/>We’ll create a simple service that echoes a few different kinds of values: an <code class="literal">int</code>, a <code class="literal">String</code>, and one of our own object types (a data holder object), <code class="literal">MyObject</code>. In the next section, we’ll examine the data types and how they are handled in more detail. Here is the code:</p><a id="I_15_tt963"/><pre class="programlisting"><code class="kn">package</code> <code class="n">learningjava</code><code class="o">.</code><code class="na">service</code><code class="o">;</code> <code class="kn">import</code> <code class="nn">javax.jws.*</code><code class="o">;</code> <code class="kn">import</code> <code class="nn">javax.xml.ws.Endpoint</code><code class="o">;</code> <code class="nd">@WebService</code> <code class="kd">public</code> <code class="kd">class</code> <code class="nc">Echo</code> <code class="o">{</code> <code class="nd">@WebMethod</code> <code class="kd">public</code> <code class="kt">int</code> <code class="nf">echoInt</code><code class="o">(</code> <code class="kt">int</code> <code class="n">value</code> <code class="o">)</code> <code class="o">{</code> <code class="k">return</code> <code class="n">value</code><code class="o">;</code> <code class="o">}</code> <code class="nd">@WebMethod</code> <code class="kd">public</code> <code class="n">String</code> <code class="nf">echoString</code><code class="o">(</code> <code class="n">String</code> <code class="n">value</code> <code class="o">)</code> <code class="o">{</code> <code class="k">return</code> <code class="n">value</code><code class="o">;</code> <code class="o">}</code> <code class="nd">@WebMethod</code> <code class="kd">public</code> <code class="n">MyObject</code> <code class="nf">echoMyObject</code><code class="o">(</code> <code class="n">MyObject</code> <code class="n">value</code> <code class="o">)</code> <code class="o">{</code> <code class="k">return</code> <code class="n">value</code><code class="o">;</code> <code class="o">}</code> <code class="kd">public</code> <code class="kd">static</code> <code class="kt">void</code> <code class="nf">main</code><code class="o">(</code> <code class="n">String</code><code class="o">[]</code> <code class="n">args</code> <code class="o">)</code> <code class="o">{</code> <code class="n">Endpoint</code> <code class="n">endpoint</code> <code class="o">=</code> <code class="n">Endpoint</code><code class="o">.</code><code class="na">publish</code><code class="o">(</code> <code class="s">"http://localhost:8080/echo"</code><code class="o">,</code> <code class="k">new</code> <code class="nf">Echo</code><code class="o">()</code> <code class="o">);</code> <code class="o">}</code> <code class="o">}</code> <code class="kd">public</code> <code class="kd">class</code> <code class="nc">MyObject</code> <code class="o">{</code> <code class="kt">int</code> <code class="n">intValue</code><code class="o">;</code> <code class="n">String</code> <code class="n">stringValue</code><code class="o">;</code> <code class="kd">public</code> <code class="nf">MyObject</code><code class="o">()</code> <code class="o">{</code> <code class="o">}</code> <code class="kd">public</code> <code class="nf">MyObject</code><code class="o">(</code> <code class="kt">int</code> <code class="n">i</code><code class="o">,</code> <code class="n">String</code> <code class="n">s</code> <code class="o">)</code> <code class="o">{</code> <code class="k">this</code><code class="o">.</code><code class="na">intValue</code> <code class="o">=</code> <code class="n">i</code><code class="o">;</code> <code class="k">this</code><code class="o">.</code><code class="na">stringValue</code> <code class="o">=</code> <code class="n">s</code><code class="o">;</code> <code class="o">}</code> <code class="kd">public</code> <code class="kt">int</code> <code class="nf">getIntValue</code><code class="o">()</code> <code class="o">{</code> <code class="k">return</code> <code class="n">intValue</code><code class="o">;</code> <code class="o">}</code> <code class="kd">public</code> <code class="kt">void</code> <code class="nf">setIntValue</code><code class="o">(</code> <code class="kt">int</code> <code class="n">intValue</code> <code class="o">)</code> <code class="o">{</code> <code class="k">this</code><code class="o">.</code><code class="na">intValue</code> <code class="o">=</code> <code class="n">intValue</code><code class="o">;</code> <code class="o">}</code> <code class="kd">public</code> <code class="n">String</code> <code class="nf">getStringValue</code><code class="o">()</code> <code class="o">{</code> <code class="k">return</code> <code class="n">stringValue</code><code class="o">;</code> <code class="o">}</code> <code class="kd">public</code> <code class="kt">void</code> <code class="nf">setStringValue</code><code class="o">(</code> <code class="n">String</code> <code class="n">stringValue</code> <code class="o">)</code> <code class="o">{</code> <code class="k">this</code><code class="o">.</code><code class="na">stringValue</code> <code class="o">=</code> <code class="n">stringValue</code><code class="o">;</code> <code class="o">}</code> <code class="o">}</code></pre><p>We’ve named our {[QUOTE-REPLACEMENT]}echo” methods individually to differentiate them because WSDL doesn’t really handle overloaded methods. (If we’d had a name collision, JAX-WS would give us a runtime warning and choose one for us.) We’ve placed these into a <code class="literal">learningjava.service</code> package because it will be easier to work with the tools that way. This package name will be used in the default <span class="emphasis"><em>namespace</em></span> and package name for generated client code. We could override the default using the <a id="I_indexterm15_id784050" class="indexterm"/><code class="literal">targetNamespace</code> attribute of the WebService annotation (and it would probably be wise to do so in order to keep your interface stable).</p><p>To deploy our web service, we use the JAX-WS <code class="literal">Endpoint</code> class <code class="literal">publish()</code> method. This method takes a URI string that indicates the desired host, port, and service path as well as an instance of our class. Obviously, the only host that will work in this arrangement is our local computer, which can normally be accessed by the name: “localhost.” Here, we ran the service on port 8080 under the path “/echo”.<a id="I_indexterm15_id784082" class="indexterm"/></p></div><div class="sect2" title="Using the Service"><div class="titlepage"><div><div><h2 class="title"><a id="learnjava3-CHP-15-SECT-6.7"/>Using the Service</h2></div></div></div><p><a id="idx10909" class="indexterm"/>After running the service, drive your web browser to the service URL to get a test page. If you are running the server on the same machine, the URL should be the same as the URI you passed to the <code class="literal">publish()</code> method. However, under some circumstances you may have to substitute “127.0.0.1” for “localhost.”</p><a id="I_programlisting15_id784117"/><pre class="programlisting"><code class="nl">http:</code><code class="c1">//localhost:8080/echo</code> <code class="nl">http:</code><code class="c1">//127.0.0.1:8080/echo</code></pre><p>You should see a description of the service similar to the one shown in <a class="xref" href="ch15s06.html#learnjava3-CHP-15-FIG-1" title="Figure 15-1. Web services description">Figure 15-1</a>. This tells you that the service is active and gives you its configuration information. You can click on the WSDL link to view the WSDL description file that was generated for our service. The WSDL URL should be your base service URL with “?wsdl” appended.</p><p>We can use the WSDL to generate a client and test our service, just as we did in <a class="xref" href="ch14.html" title="Chapter 14. Programming for the Web">Chapter 14</a>. In the following command, we’ve specified that the generated classes should go into a separate package, <code class="literal">learningjava.client.impl</code>, to avoid confusion between the generated classes and our original. We’ve also used the <code class="literal">-keep</code> option to retain the source code instead of just the compiled class files (you may want to look at them). The final argument is the URL for our generated WSDL, which you can copy from the test page as shown previously.</p><div class="figure-float"><div class="figure"><a id="learnjava3-CHP-15-FIG-1"/><div class="figure-contents"><div class="mediaobject"><a id="I_15_tt971"/><img src="httpatomoreillycomsourceoreillyimages1707647.png" alt="Web services description"/></div></div><p class="title">Figure 15-1. Web services description</p></div></div><a id="I_15_tt973"/><pre class="programlisting"><code class="o">%</code> <strong class="userinput"><code><code class="n">wsimport</code> <code class="o">-</code><code class="n">p</code> <code class="n">learningjava</code><code class="o">.</code><code class="na">client</code><code class="o">.</code><code class="na">impl</code> <code class="o">-</code><code class="n">keep</code> <code class="nl">http:</code><code class="c1">//localhost:8080/echo?wsdl</code></code></strong></pre><p>Next, we’ll create a small client that uses these generated classes to test the service:</p><a id="I_15_tt974"/><pre class="programlisting"><code class="kn">package</code> <code class="n">learningjava</code><code class="o">.</code><code class="na">client</code><code class="o">;</code> <code class="kn">import</code> <code class="nn">learningjava.client.impl.*</code><code class="o">;</code> <code class="kd">public</code> <code class="kd">class</code> <code class="nc">EchoClient</code> <code class="o">{</code> <code class="kd">public</code> <code class="kd">static</code> <code class="kt">void</code> <code class="nf">main</code><code class="o">(</code> <code class="n">String</code> <code class="o">[]</code> <code class="n">args</code> <code class="o">)</code> <code class="kd">throws</code> <code class="n">java</code><code class="o">.</code><code class="na">rmi</code><code class="o">.</code><code class="na">RemoteException</code> <code class="o">{</code> <code class="n">Echo</code> <code class="n">service</code> <code class="o">=</code> <code class="k">new</code> <code class="n">EchoService</code><code class="o">().</code><code class="na">getEchoPort</code><code class="o">();</code> <code class="kt">int</code> <code class="n">i</code> <code class="o">=</code> <code class="n">service</code><code class="o">.</code><code class="na">echoInt</code><code class="o">(</code> <code class="mi">42</code> <code class="o">);</code> <code class="n">System</code><code class="o">.</code><code class="na">out</code><code class="o">.</code><code class="na">println</code><code class="o">(</code> <code class="n">i</code> <code class="o">);</code> <code class="n">String</code> <code class="n">s</code> <code class="o">=</code> <code class="n">service</code><code class="o">.</code><code class="na">echoString</code><code class="o">(</code> <code class="s">"Hello!"</code> <code class="o">);</code> <code class="n">System</code><code class="o">.</code><code class="na">out</code><code class="o">.</code><code class="na">println</code><code class="o">(</code> <code class="n">s</code> <code class="o">);</code> <code class="n">MyObject</code> <code class="n">myObject</code> <code class="o">=</code> <code class="k">new</code> <code class="n">MyObject</code><code class="o">();</code> <code class="n">myObject</code><code class="o">.</code><code class="na">setIntValue</code><code class="o">(</code> <code class="mi">42</code> <code class="o">);</code> <code class="n">myObject</code><code class="o">.</code><code class="na">setStringValue</code><code class="o">(</code> <code class="s">"Foo!"</code> <code class="o">);</code> <code class="n">MyObject</code> <code class="n">myObj</code> <code class="o">=</code> <code class="n">service</code><code class="o">.</code><code class="na">echoMyObject</code><code class="o">(</code> <code class="n">myObject</code> <code class="o">);</code> <code class="n">System</code><code class="o">.</code><code class="na">out</code><code class="o">.</code><code class="na">println</code><code class="o">(</code> <code class="n">myObj</code><code class="o">.</code><code class="na">getStringValue</code><code class="o">()</code> <code class="o">);</code> <code class="o">}</code> <code class="o">}</code></pre><p>As you can infer from our code, <a id="I_indexterm15_id784213" class="indexterm"/><span class="emphasis"><em>wsimport</em></span> has generated an <code class="literal">EchoService</code> class that represents our service. Service classes may contain multiple service groups, so in order to get our <code class="literal">Echo</code> interface, we ask for the Echo “port” with <code class="literal">getEchoPort()</code>. (<span class="emphasis"><em>Port</em></span> is WSDL terminology for a service interface.)</p><p>Run the client, and it should bounce the values between the client and server and display them. And there we are! As we said in the introduction, the actual code required to implement and invoke our service is quite minimal and the fact that Java now bundles a simple web service container with the standard edition makes Java an ideal platform for working with web services.<a id="I_indexterm15_id784249" class="indexterm"/></p></div><div class="sect2" title="Data Types"><div class="titlepage"><div><div><h2 class="title"><a id="id960416"/>Data Types</h2></div></div></div><p><a id="idx10907" class="indexterm"/>As you might guess, because the data for our service has to be expressed as XML in a standard way, there are some limitations to the type of objects that can be transferred. JAX-WS and WSDL support most of the common Java data types and many standard classes directly. Actually, it would be more appropriate to say that JAXB—the Java XML binding API—supports these Java types, as JAX-WS uses JAXB for this aspect. We’ll talk more about Java XML data binding and XML Schemas in <a class="xref" href="ch24.html" title="Chapter 24. XML">Chapter 24</a>.</p><p>JAX-WS and JAXB can also decompose JavaBeans-compliant data classes composed of these standard types so that you can use your own classes, as we saw with the <code class="literal">MyObject</code> argument in our <code class="literal">Echo</code> service.</p><div class="sect3" title="Standard types"><div class="titlepage"><div><div><h3 class="title"><a id="learnjava3-CHP-15-SECT-6.5.1"/>Standard types</h3></div></div></div><p><a class="xref" href="ch15s06.html#learnjava3-CHP-15-TABLE-1" title="Table 15-1. Standard types">Table 15-1</a> summarizes the directly supported types (those types that map directly to W3C Schema types; see <a class="xref" href="ch24.html" title="Chapter 24. XML">Chapter 24</a> for more on XML mapping of Java types.</p><div class="table"><a id="learnjava3-CHP-15-TABLE-1"/><p class="title">Table 15-1. Standard types</p><div class="table-contents"><table summary="Standard types" style="border-collapse: collapse;border-top: 0.5pt solid ; border-bottom: 0.5pt solid ; "><colgroup><col/><col/></colgroup><thead><tr><th style="text-align: left"><p>Category</p></th><th style="text-align: left"><p>Types</p></th></tr></thead><tbody><tr><td style="text-align: left"><p>Primitives and their wrappers</p></td><td style="text-align: left"><p> <a id="I_indexterm15_id784368" class="indexterm"/> <code class="literal">boolean</code>, <a id="I_indexterm15_id784380" class="indexterm"/><code class="literal">Boolean</code>, <a id="I_indexterm15_id784390" class="indexterm"/><code class="literal">byte</code>, <a id="I_indexterm15_id784401" class="indexterm"/><code class="literal">Byte</code>, <a id="I_indexterm15_id784412" class="indexterm"/><code class="literal">short</code>, <a id="I_indexterm15_id784422" class="indexterm"/><code class="literal">Short</code>, <a id="I_indexterm15_id784433" class="indexterm"/><code class="literal">float</code>, <a id="I_indexterm15_id784444" class="indexterm"/><code class="literal">Float</code>, <a id="I_indexterm15_id784454" class="indexterm"/><code class="literal">int</code>, <a id="I_indexterm15_id784465" class="indexterm"/><code class="literal">Integer</code>, <a id="I_indexterm15_id784476" class="indexterm"/><code class="literal">long</code>, <a id="I_indexterm15_id784486" class="indexterm"/><code class="literal">Long</code>, <a id="I_indexterm15_id784497" class="indexterm"/><code class="literal">double</code>, <a id="I_indexterm15_id784508" class="indexterm"/><code class="literal">Double</code></p></td></tr><tr><td style="text-align: left"><p>Class types</p></td><td style="text-align: left"><p> <a id="I_indexterm15_id784529" class="indexterm"/> <code class="literal">java.lang.String</code>, <a id="I_indexterm15_id784541" class="indexterm"/><code class="literal">java.math.BigDecimal</code>, <a id="I_indexterm15_id784552" class="indexterm"/><code class="literal">java.math.BigInteger</code>, <a id="I_indexterm15_id784562" class="indexterm"/><a id="I_indexterm15_id784568" class="indexterm"/><a id="I_indexterm15_id784573" class="indexterm"/><a id="I_indexterm15_id784578" class="indexterm"/><a id="I_indexterm15_id784583" class="indexterm"/><code class="literal">java.util.Calendar</code>, <code class="literal">java.util.Date</code><code class="literal">, java.util.UUID, java.net.URI, java.awt.Image</code> (as byte [])</p></td></tr><tr><td style="text-align: left"><p>Collections</p></td><td style="text-align: left"><p> Array types, List types, Set types</p></td></tr></tbody></table></div></div><p>Maps and other complex collection types are not currently supported. To maintain the widest compatability for cross-platform web services, it’s best to stick with objects composed of simple data types and arrays or lists of those types.</p></div><div class="sect3" title="Value data objects"><div class="titlepage"><div><div><h3 class="title"><a id="learnjava3-CHP-15-SECT-6.5.2"/>Value data objects</h3></div></div></div><p>As we said, JAX-WS can also work with our own object types, although there are several requirements and a caveat to mention. First, to be able to be marshaled, our objects must contain only fields that are supported data types (or further compositions of those). Next, our objects must follow two JavaBeans design patterns. It must have a public, no-args constructor and, if it contains any nonpublic fields, they must have “getter” and “setter” accessor methods. <a class="xref" href="ch22.html" title="Chapter 22. JavaBeans">Chapter 22</a> provides more details about these issues.</p><p>Finally, unlike Java RMI, web services do not support the “behavior” or the real identity of our domain objects from end to end. When a Java client uses our WSDL document to generate implementation classes, they will be getting simple data-holder replicas of the classes we specify. These “value objects” will pass along all of the data content of our objects, but are not related to the originals in any other way. Our server-side implementation will, of course, receive the data in the form of our own “real” domain objects. That is why they need to have available constructors so that the server-side framework can create and populate them for us to consume.<a id="I_indexterm15_id784662" class="indexterm"/></p></div></div></div></body></html>