epubjs
Version:
Render ePub documents in the browser, across many devices
210 lines (197 loc) • 25.4 kB
HTML
<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>