1 of 7
Follow @ObjectComputing
http://jnb.ociweb.com/jnb/jnbJun2007.html
1,541 followers
Tweet
RSS
Introduction
Historically, web services in Java have vexed developers with myriad specifications and complex solutions. Surrounded by legions of W3C specs, JSRs, and XML descriptors,
these developers endured complexity while other Java communities (such as EJB3, Seam and Guice) celebrate the elegance of Java 5 and beyond. Moreover, with the
success of the sleek REST school of web architecture, there is a fitting rallying cry: "hear our Java Simplification Request for web services! "
If only there were a world in which Java developers express web services in a compact manner, where tools assist with the mundane, "plumbing" details. This world is a far
cry from the status quo, and certainly appeals. For example, what if web services were as easy as:
@WebService
public class Concatenator {
@WebMethod
public String concatenate(String a, String b) {
return a + " " + b;
}
}
Welcome to the world of JSR 181: the above is a bona fide web service. JSR 181, "Web Services Metadata for Java", rescues downtrodden web services developers with a
simple, annotation-based development model for common web service tasks. Combined with a lightweight HTTP server in Java 6, JSR 181 enables rapid prototyping of web
services (WS) and brings WS development into the modern era of Java.
This article has two goals:
A bewildering mix of JSRs comprise the Java WS space, both in terms of volume and the subtle relationships among them. We almost need a JSR Modeling Language
(JML) to communicate! Defining JML is too ambitious, but the key JSRs are examined in a historical context, so as to set the stage for JSR 181.
Examples explore the JSR 181 development model.
It is assumed that the reader understands web services as an approach to distributed computing, and has a basic knowledge of web service constructs (e.g. WSDL, SOAP).
All examples require JDK 1.6.x.
JAX-RPC 1.x
JAX-RPC represents the first version of web services in Java. See the graphical overview below. Some key points:
The primary spec, JSR 101 ("Java APIs for XML-based RPC"), defines the APIs and conventions for the Java platform, including the WSDL/Java mapping, the SOAP
binding and SOAP handlers. Version 1.0 was released in mid-2002.
Due to scheduling concerns, the JAX-RPC team elected to define its own facilities to bind data between Java and XML. This was in addition to other, more generalized
data binding solutions.
The state-of-the-JVM in this timeframe was JDK 1.4. JSR 88 defines the general deployment API for J2EE. JSR 109 ("Implementing Enterprise Web Services")
implements this API for the WS space. Note that the best practice of the time was XML-based deployment descriptors: i.e. artifacts to describe web services at
deployment time.
Version 1.1 of JAX-RPC appeared in mid-2003 with support for the WS-I Basic Profile 1.0, to improve interoperability with other technologies.
JAX-WS 2.x
10-Jun-16 11:49 AM
2 of 7
http://jnb.ociweb.com/jnb/jnbJun2007.html
Though initially met with considerable excitement, there are problems with JAX-RPC 1.x: the implementation is complex and competing technologies/philosophies (e.g.
Apache Axis, REST) offer simplicity that is seductive, despite being non-standard. Also, new specs and standards render some of the machinery of JAX-RPC 1.x (e.g. data
binding) as obsolete. Most of all, since the release of JAX-RPC, the Java landscape itself underwent seismic shifts, particularly with respect to EJB.
Seismic Shifts
Initially, tools (e.g. XDoclet) assisted with the generation of deployment descriptors. Later, Java 5 brought the promise of annotations. In recent years, prominent authors
railed against the complexity of J2EE and EJB. Alternative frameworks (e.g. Ruby on Rails) introduced simple, Zen-like philosophies, such as "prefer convention over
configuration". All of these forces culimated in a shift against the explicit use of complex deployment time descriptors, and even XML configuration. EJB3, Seam and Guice
clearly reflect this shift.
JSR 224
For version 2 of WS in Java, the technology was renamed as JAX-WS 2.0. Just as JSR 109 is the primary spec for JAX-RPC, JSR 224 "Java API for XML-Based Web
Services", is the central document for JAX-WS. Some of the spec's stated goals pertain to evolving standards:
JAX-WS adds support for SOAP 1.2 in addition to SOAP 1.1.
JAX-WS will support WS-I Basic Profile 1.1 as it continues to evolve.
JAX-WS may support WSDL 2.0 in JAX-WS version 2.1+
However, the following goals are more interesting:
JAX-WS delegates data binding of Java/XML to JAXB 2.x (aka JSR 222).
JAX-WS "aligns with and complements" the annotations defined by JSR 181. That is, just as JAX-RPC/JSR 109 defines a deployment time facility for the Java/WSDL
mapping, JAX-WS works with JSR 181 to define a development time facility for this mapping, using Java 5 annotations (aka JSR 175).
See the graphical overview below. There are several themes here:
JAX-WS uses delegation to leverage facilities provided by the modern JDK (JAXB and annotations). This is classic division of labor. Note: the diagram shows JSRs, yet
we can loosely apply the OO ideas of composition and encapsulation.
Within the JAX-WS space itself, JSR 224 delegates some work to JSR 181. More on this coming up.
With development time annotations, clearly JAX-WS responds to the criticisms of JAX-RPC with respect to the complex, antiquated nature of deployment descriptors.
A Closer Look
The stage is set for JSR 181: let's dig in.
10-Jun-16 11:49 AM
3 of 7
http://jnb.ociweb.com/jnb/jnbJun2007.html
Example 1: Concatenator
Before listing all of the available annotations in JSR 181, we'll start small, to get a view of the landscape of the JAX-WS tools. The first example (available here) is a trivial
"string concatenation" service.
Server Side Concatenation
Let's begin with the service implementation bean in Java:
package com.ociweb.demo;
import javax.jws.WebService;
import javax.jws.WebMethod;
import javax.xml.ws.Endpoint;
@WebService
public class Concatenator {
@WebMethod
public String concatenate(String a, String b) {
return a + " " + b;
}
}
Note the annotations on this simple class, which clearly denote a web service and a "web method." Amazingly, we are done with development and can start testing the web
service! The JSR 181 processor will take care of the rest. To prove it, we write a main method to publish the service to the HTTP server contained in Java 6:
public static void main(String[] args) {
// e.g.
// publish.url = http://localhost:9998/concatservice
String publishUrl = System.getProperty("publish.url");
if( publishUrl != null & publishUrl.length() > 0 ) {
System.out.println("publishing service at: " + publishUrl);
Concatenator concatenator = new Concatenator();
Endpoint endpoint = Endpoint.publish(publishUrl,concatenator);
} else {
System.err.println("usage: Concatenator publishUrl");
}
}
The main method creates an instance of the SIB, and calls Endpoint.publish(). The first parameter, a URI, specifies the address and transport/protocol. The current
javadoc states that for a 'http:' URI, it is assumed that the SOAP 1.1/HTTP binding is used. The publish method uses a default configuration to create the necessary server
infrastructure for publication.
Ant takes care of the next steps (see build_server.xml for details):
Run the Java6 apt tool on the source code. The JSR 181 processor will generate the necessary artifacts; apt compiles the Java code as well.
Run the Concatenator.main() method.
Once the server is running, we can point a browser to http://localhost:9998/concatservice?wsdl:
10-Jun-16 11:49 AM
4 of 7
http://jnb.ociweb.com/jnb/jnbJun2007.html
Presto! With stunning ease, the web service is available, and follows these JSR 224 conventions:
The targetNamespace for the WSDL is the Java package, with reversed tokens.
The identifiers for service, port, binding and other WSDL elements follow the natural convention by decorating the original SIB name, Concatenator.
The schema types are published to the URI: http://localhost:9998/concatservice?xsd=1
If we point the browser to the URI of the schema types:
We see that the types follow a similar, logical convention. However, there's more: the JSR 181 processor generates these classes for us. In the example directory, you can
find the generated Java classes Concatenate and ConcatenateResponse. Note how they are annotated with JAXB meta-data. These classes are entirely inline with the
sophisticated JSR 224 conventions.
Client Side Concatenation
Here is the simple client class:
package com.ociweb.demo;
class Client {
public static void main(String args[]) {
// create service
ConcatenatorService service = new ConcatenatorService();
// get the port
Concatenator concatProxy = service.getConcatenatorPort();
// Invoke the remote method
String a = "Hello";
String b = "Web Services!";
String resultStr = concatProxy.concatenate(a,b);
System.out.println("result = " + resultStr);
}
}
This class simply uses a ConcatenatorService object to acquire a proxy for the web service operation, and then uses it with concatProxy.concatenate. Note there are no
annotations on this class: where do the other classes originate? The answer is another JAX-WS tool, wsimport. The Ant build on the client side works like this:
Use the wsimport tool to generate the client side support classes for the web service. The generation is predicated on the same WSDL URI shown earlier: wsimport
accepts the WSDL as input and generates/compiles the classes. This example uses a parameter to "keep" the generated classes for viewing.
Compile and run the Client class above
The output from the client is:
$ ant -f build_client.xml
Buildfile: build_client.xml
clean:
[delete] Deleting directory C:\measter\src\jsr181\ex1\client\classes
[delete] Deleting directory C:\measter\src\jsr181\ex1\client\generated
init:
[mkdir] Created dir: C:\measter\src\jsr181\ex1\client\classes
[mkdir] Created dir: C:\measter\src\jsr181\ex1\client\generated
10-Jun-16 11:49 AM
5 of 7
http://jnb.ociweb.com/jnb/jnbJun2007.html
build_client:
[javac] Compiling 1 source file to C:\measter\src\jsr181\ex1\client\classes
run_client:
[exec] result = Hello Web Services!
BUILD SUCCESSFUL
Total time: 11 seconds
Recap
Example 1 represents a complete round-trip from client to server for a trivial web service. Note the compact amount of code and how it concentrates on the business logic
for the task at hand. With JSR 181, Java WS development joins EJB3 in the modern era of annotations.
The Annotations
The last example demonstrates the JAX-WS tools. However, the annotations are the heart of JSR 181. The table below gives a broad look at the available annotations:
Annotation
@WebService
Description
Marks a class/interface as a web service
Allows overrides for outer WSDL attributes: targetNamespace, wsdlLocation, portName
@WebMethod
@Oneway
@SOAPBinding
@WebParam
@WebResult
javax.jws.WebService;
javax.jws.WebMethod;
javax.jws.soap.SOAPBinding;
javax.xml.ws.Endpoint;
@WebService(
name="myConcatenatorType",
serviceName="myConcatService",
targetNamespace="http://reversed.when.normally.reads"
)
@SOAPBinding(
style=SOAPBinding.Style.RPC
)
public class Concatenator {
// as before
}
10-Jun-16 11:49 AM
6 of 7
http://jnb.ociweb.com/jnb/jnbJun2007.html
This example (available here) uses the same structure and Ant tasks as Example 1. The server side exists entirely in Acme.java, which we analyze here. First, the legacy
record:
class OrderRecord {
// very poor design! assume "legacy" record
// estimate fields
public int numUnits;
public String customerId;
public float cost;
// order fields
public String orderCode;
public Date expectedArrival;
}
Here is the legacy interface, decorated with JSR 181 meta-data:
@WebService (
name="AcmeWebOrderInterface"
)
@SOAPBinding(style=SOAPBinding.Style.RPC)
interface LegacyInterface {
@WebMethod
@WebResult(name="Estimate")
OrderRecord getEstimate( String customerId, int numUnits );
@WebMethod
boolean placeOrder( @WebParam(mode=WebParam.Mode.INOUT)
Holder<OrderRecord> orderHolder );
@WebMethod
@Oneway
void confirmReceipt(String orderCode);
}
Recall in JAX-WS terminology, this interface is a Service Endpoint Interface (SEI). Note the following points:
The @WebService annotation overrides the name of the web service, as we don't want a legacy name to be published. Also, @SOAPBinding is overridden to be RPC
style.
The getEstimate method returns an OrderRecord, but we override the name to be "Estimate" in the WSDL.
The placeOrder uses an INOUT parameter: the OrderRecord comes in with populated "estimate" fields and should leave with all fields populated. Note that JAX-WS
enables INOUT params with the Holder<T> class.
@Oneway adds the self-titled semantic to the confirmReceipt method, as it consists of one input and neither output nor inout elements.
A stated goal of JSR 181 is to separate public contracts from private implementations; this dovetails with an Acme requirement. The following Service Implementation Bean
(SIB) demonstrates this:
// Note that this SIB defers meta-data information to the SEI
@WebService(
endpointInterface="com.ociweb.demo.LegacyInterface",
serviceName="AcmeWebService",
portName="AcmeWebOrderPort"
)
public class Acme implements LegacyInterface {
public OrderRecord getEstimate( String customerId, int numUnits ) {
OrderRecord record = new OrderRecord();
System.out.println("received estimate request. customerId = " + customerId);
record.numUnits = numUnits;
record.customerId = customerId;
record.cost = numUnits * 100.0f;
return record;
}
public boolean placeOrder( Holder<OrderRecord> orderHolder ) {
OrderRecord order = orderHolder.value;
final int arbitraryLimit = 10000;
int randomInt = (new Random()).nextInt(arbitraryLimit);
order.orderCode = Integer.toString(randomInt);
order.expectedArrival = new Date();
System.out.println("placing order with orderCode = " + order.orderCode);
return true;
}
public void confirmReceipt(String orderCode) {
// oneway methods should generally spawn a thread to do
// the business logic
System.out.println("writing confirmation to DB for: " + orderCode);
}
// arbitrary unit-test method -- not exposed to the web service
boolean testingMethod() { return true; }
}
10-Jun-16 11:49 AM
7 of 7
http://jnb.ociweb.com/jnb/jnbJun2007.html
That's it for the server! The client steps through the use case of getting an estimate, making an order and confirming receipt. As with Example 1, JSR 181 and JAX-WS
perform an astounding amount of heavy lifting.
In Production
As noted, the HTTP server in JDK 6 is not appropriate for production. In order to move Example 2 to a production enviroment, it is necessary to use a web/app server that
is enabled for JAX-WS. Here is a list of suitable application servers which are Java EE 5 compatible (and thus JAX-WS enabled). Note that Tomcat does not yet work out-ofthe-box: here are instructions to enable Tomcat for JAX-WS.
Even with the appropriate server, another aspect to consider is the generation of the JSR-109 deployment descriptors, especially as this is the major boon of JAX-WS. The
wsgen tool (here) performs this task: it accepts a SEI and generates the required artifacts for deployment and invocation.
JAX-WS RI
The reference implemenation (RI) for JAX-WS is located here. Here is a quick road-map regarding the RI:
Version 2.0 is bundled with Java 6, but exists as a separate download for Java 5. (Strictly speaking, it requires only the annotation support in Java 5.)
Version 2.0.1 existed only as an intermediate version to transition to version 2.1. However, due to a technical issue, version 2.1 required changes to the API and spec,
and is no longer available. At this writing, version 2.1.1 is the most current release.
Some highlights of new features in version 2.1.1:
Ant and Maven support for wsimport and wsgen tools.
Support for standards such as SOAP 1.2 and WS-I Basic Profile 1.1.
Extension support for the WS-* specs within the WSIT umbrella.
Summary
Java 5's original annotation facility was not a solution, but a promise. Eventually, the solutions poured in for EJB3, JAXB and other communities within Java.
Now, JAX-WS brings the same power of development time metadata to the WS space, leveraging annotations and JAXB. Moreover, JSR 181 acts as a facade pattern for
JAX-WS and brings remarkable simplicity for common WS tasks. Combined with the innate HTTP server in Java 6, WS developers finally enjoy simplicity and agility. The
woeful cry of a "Java Simplification Request" may well soar into a joyful (if grammatically incorrect) cheer: "we never met a data we didn't like!"
Example Notes
The examples in this article use Java 1.6.0, and Ant 1.6.x. It is assumed that Java and Ant are installed on the machine. The first example is inspired by a blog post by
Vivek Pandey.
10-Jun-16 11:49 AM