J2EE 1.4 APIs

Download Report

Transcript J2EE 1.4 APIs

J2EE 1.4 APIs For
Web Services
Michael D. Thomas
[email protected]
Agenda







Quick Tour Of J2EE APIs
Service Oriented Architecture
SOAP & WSDL: The 10 minute guide
JAX-RPC
SAAJ
JAXP
JAXR
A Simple Example





Company has web app that looks up invoices
The customers like it
Customer wants to pass the data automatically to
another application
Typical situation for a web service
Will do it with:
1.
2.
3.
Straight XML (JAXP)
SAAJ: Wrapper around SOAP and HTTP
JAX-RPC: Uses SOAP and WSDL, but you never have
to see it
Invoice Screen
Invoice App Structure
Invoice JSP
<html>
<head>
<title>Invoice</title>
</head>
<body bgcolor="white">
<%@ page language="java"
import="org.ibiblio.mdthomas.ws.autopartssupplier.*" %>
<jsp:useBean id="invoiceHelper"
scope="request"
class="org.ibiblio.mdthomas.ws.autopartssupplier.InvoiceHelper"/>
<jsp:setProperty name=”invoiceHelper”
property=”*”/>
<%
InvoiceBean invoice = invoiceHelper.getInvoiceById();
CustomerBean customer = invoice.getCustomer();
InvoiceItemBean items[] = invoice.getInvoiceItems();
%>
Continued . . . .
Invoice JSP
<% for (int i=0; i<items.length;i++) { %>
<tr>
<td><%= items[i].getName() %></td>
<td><%= items[i].getProductId() %></td>
<td><%= items[i].getQuantity() %></td>
<td align="right">
<%= items[i].getPerItemPrice() %>
</td>
<td align="right">
<%= items[i].getTotalLineItemPrice() %>
</td>
</tr>
<% } %>
Continued . . . .
Invoice Helper
package org.ibiblio.mdthomas.ws.autopartssupplier;
import java.rmi.Remote;
import java.rmi.RemoteException;
public class InvoiceHelper {
long id;
InvoiceBusinessDelegate invoiceBusinessDelegate;
public InvoiceHelper () {
invoiceBusinessDelegate =
BusinessDelegateFactory.getInvoiceBusinessDelegate();}
public void setInvoiceId (long id) {
this.id = id; }
public long getInvoiceId() {
return id;}
public InvoiceBean getInvoiceById() {
return invoiceBusinessDelegate.getInvoiceById(this.id);}
public InvoiceBean getInvoiceById(long id) {
return invoiceBusinessDelegate.getInvoiceById(id);}
}
InvoiceBean (incomplete)
package org.ibiblio.mdthomas.ws.autopartssupplier;
public class InvoiceBean implements Serializable {
private CustomerBean customer;
private InvoiceItemBean invoiceItems[];
private long invoiceId;
private float total;
private float shippingCharge;
private float subTotal;
public InvoiceBean() {}
public float getTotal() {
return total;}
public void setTotal(float total) {
this.total = total;}
public void setCustomer(CustomerBean customer) {
this.customer = customer;}
public CustomerBean getCustomer() {
return customer;
}
public InvoiceItemBean[] getInvoiceItems() {
return invoiceItems;}
public void setInvoiceItems(InvoiceItemBean items[])
this.invoiceItems = items;}
}
{
New XML Architecture
XML Invoice
XML Invoice JSP
<?xml version="1.0"?>
<ordering:invoice
xmlns:ordering="http://www.tinasautoparts.com/xmlns/orders">
<%@ page language="java"
import="org.ibiblio.mdthomas.ws.autopartssupplier.*" %>
<jsp:useBean id="invoiceHelper"
scope="request"
class="org.ibiblio.mdthomas.ws.autopartssupplier.InvoiceHelper"
/>
<jsp:setProperty name="invoiceHelper" property="*"/>
<%
InvoiceBean invoice = invoiceHelper.getInvoiceById();
CustomerBean customer = invoice.getCustomer();
InvoiceItemBean items[] = invoice.getInvoiceItems();
%>
<ordering:invoiceId>
<%= invoice.getInvoiceId() %>
</ordering:invoiceId>
Continued . . .
“Web Services” Requestor
public static void main(String[] args) throws Exception {
long invoiceId = 0;
if (args.length>0) {
invoiceId = Long.parseLong(args[0]);}
// Create the URL and encode the invoiceId param
String base =
"http://localhost:8080/jsp-examples/ch03/invoiceAsXml.jsp?";
String invoiceParam = "invoiceId="+invoiceId+"&";
URL invoiceURL = new URL(base+invoiceParam);
// Connect to the URL
URLConnection conn = invoiceURL.openConnection();
conn.connect();
// Get the result and create the XML
InputStream invoiceStream = conn.getInputStream();
DocumentBuilderFactory dbf =
DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
Document doc = db.parse(invoiceStream);
// Handle the XML
handleXML(doc);
}
“Web Services” Requestor
private static void handleXML(Document doc) {
float invoiceTotal = 0f;
int totalQuantities = 0;
float shippingCharge =0f;
Element docRoot = doc.getDocumentElement();
NodeList children = docRoot.getChildNodes();
for (int i=0;i<children.getLength();i++) {
Node node = children.item(i);
System.out.println("node name: "+node.getNodeName());
short nodeType = node.getNodeType();
if (node.getNodeName().equals("ordering:customer")) {
Element customerElement = (Element)node;
NodeList nodeList =
customerElement.getElementsByTagName("ordering:customerName");
Element customerNameElem = (Element)nodeList.item(0);
Node customerNameText = customerNameElem.getFirstChild();
String customerName = customerNameText.getNodeValue();
System.out.println("Customer name: "+customerName);
}
Continued . . .
Basic XML Web Services
Issues



Satisfies the business requirement
Not standards based – doesn’t use SOAP or
WSDL
Had to handle HTTP directly
SAAJ & SOAP Approach






Uses SOAP standard
Similar to previous example, but requestor
handles SOAP details
SOAP: data (Body) and meta-data (Header)
Contained in a SOAP envelope
Can attach data outside of the SOAP
envelope
SAAJ: handles HTTP requests, wraps JAXP
in SOAP specific nature (like JDOM)
SOAP Request
POST /invoice-jaxrpc/invoice HTTP/1.1
Content-Type: text/xml; charset="utf-8"
Content-Length: 246
SOAPAction: ""
Cache-Control: no-cache
Pragma: no-cache
User-Agent: Java/1.4.2
Host: localhost:9090
Accept: text/html, text/xml, image/gif, image/jpeg, *; q=.2, */*; q=.2
Connection: keep-alive
<SOAP-ENV:Envelope
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP-ENV:Body>
<getInvoiceById
xmlns="http://www.ibiblio.org/mdthomas/invoice/types">
<long_1 xmlns="">9845</long_1>
</getInvoiceById>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
SOAP Request
POST /invoice-jaxrpc/invoice HTTP/1.1
Content-Type: text/xml; charset="utf-8"
Content-Length: 246
SOAPAction: ""
Cache-Control: no-cache
Pragma: no-cache
User-Agent: Java/1.4.2
Host: localhost:9090
Accept: text/html, text/xml, image/gif, image/jpeg, *; q=.2, */*; q=.2
Connection: keep-alive
<SOAP-ENV:Envelope
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP-ENV:Body>
<getInvoiceById
xmlns="http://www.ibiblio.org/mdthomas/invoice/types">
<long_1 xmlns="">9845</long_1>
</getInvoiceById>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
SOAP Request
POST /invoice-jaxrpc/invoice HTTP/1.1
Content-Type: text/xml; charset="utf-8"
Content-Length: 246
SOAPAction: ""
Cache-Control: no-cache
Pragma: no-cache
User-Agent: Java/1.4.2
Host: localhost:9090
Accept: text/html, text/xml, image/gif, image/jpeg, *; q=.2, */*; q=.2
Connection: keep-alive
<SOAP-ENV:Envelope
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP-ENV:Body>
<getInvoiceById
xmlns="http://www.ibiblio.org/mdthomas/invoice/types">
<long_1 xmlns="">9845</long_1>
</getInvoiceById>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
SOAP Response (incomplete)
HTTP/1.1 200 OK
X-Powered-By: Servlet/2.4
SOAPAction: ""
Content-Type: text/xml; charset="utf-8"
Transfer-Encoding: chunked
Date: Sun, 23 Nov 2003 16:00:17 GMT
Server: Sun-Java-System/JWSDP-1.3
<?xml version="1.0" encoding="UTF-8"?>
<env:Envelope xmlns:env="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:enc="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:ns0="http://www.ibiblio.org/mdthomas/invoice/types">
<env:Body>
<ns0:getInvoiceByIdResponse>
<result>
<customer>
data
</customer>
<invoiceId>9845</invoiceId>
<invoiceItem>
data
</invoiceItem>
continued…
SAAJ Provider
public class InvoiceSAAJProvider extends HttpServlet {
MessageFactory messageFactory;
public void doPost (HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/xml");
response.setBufferSize(8192);
OutputStream out = response.getOutputStream();
try {
// initialize the messageFactory
messageFactory = MessageFactory.newInstance();
// Get the requested invoice
long invoiceId = getInvoiceId(request);
InvoiceHelper invoiceHelper = new InvoiceHelper();
InvoiceBean invoice = invoiceHelper.getInvoiceById(invoiceId);
// Create the SOAP output message
SOAPMessage outputMessage = createOutputSOAPMessage(invoice);
// Write the output SOAP message to the response output stream
outputMessage.writeTo(out);
} catch (Exception ex) {
ex.printStackTrace();
}
out.close();
}
SAAJ Provider
private long getInvoiceId(HttpServletRequest request) throws
SOAPException, IOException {
// create the input SOAP message from the request's inputStream
MimeHeaders mimeHeaders = getMimeHeaders(request);
InputStream inputStream = request.getInputStream();
SOAPMessage inputMessage =
messageFactory.createMessage(mimeHeaders,inputStream);
// get the SOAP body
SOAPPart inputPart = inputMessage.getSOAPPart();
SOAPEnvelope inputEnvelope = inputPart.getEnvelope();
SOAPBody inputBody = inputMessage.getSOAPBody();
// get the invoice id as a String
Name getInvName = inputEnvelope.createName("getInvoiceById",
null,
"http://www.ibiblio.org/mdthomas/invoice/types");
Iterator it = inputBody.getChildElements(getInvName);
SOAPElement getInvoiceElem = (SOAPElement)it.next();
Name idName = inputEnvelope.createName("long_1"));
it = getInvoiceElem.getChildElements(idName);
SOAPElement invoiceIdElem = (SOAPElement)it.next();
// convert to a long and return
String invoiceIdStr = invoiceIdElem.getValue();
long invoiceId = Long.parseLong(invoiceIdStr);
return invoiceId;
}
Creating output
private SOAPMessage createOutputSOAPMessage(InvoiceBean invoice)
throws SOAPException {
// Create a message
SOAPMessage outputMessage = messageFactory.createMessage();
SOAPPart outputSoapPart = outputMessage.getSOAPPart();
SOAPEnvelope outputEnvelope = outputSoapPart.getEnvelope();
outputEnvelope.addNamespaceDeclaration("ns0",
"http://www.ibiblio.org/mdthomas/invoice/types");
// Get the SOAP header from the message and remove it
SOAPHeader header = outputMessage.getSOAPHeader();
header.detachNode();
// Get the SOAP body from the message
SOAPBody body = outputMessage.getSOAPBody();
// Add the top level elements
Name responseName = outputEnvelope.createName(
"getInvoiceByIdResponse",
"ns0",
null);
SOAPElement invoiceElem = body.addBodyElement(responseName);
SOAPElement resultElem = invoiceElem.addChildElement("result");
// add the invoice id
SOAPElement invoiceIdElem = resultElem.addChildElement("invoiceId");
long invoiceId = invoice.getInvoiceId();
invoiceIdElem.addTextNode(String.valueOf(invoiceId));
Creating output (incomplete)
//add invoice items
InvoiceItemBean items[] = invoice.getInvoiceItems();
for (int i=0;i<items.length;i++) {
SOAPElement invoiceItemElem =
resultElem.addChildElement("invoiceItems");
SOAPElement nameElem = invoiceItemElem.addChildElement("name");
String name = items[i].getName();
nameElem.addTextNode(name);
SOAPElement perItemPriceElem =
invoiceItemElem.addChildElement("perItemPrice");
float perItemPrice = items[i].getPerItemPrice();
perItemPriceElem.addTextNode(String.valueOf(perItemPrice));
SOAPElement totalLineItemPriceElem =
invoiceItemElem.addChildElement( "totalLineItemPrice");
float totalLineItemPrice = items[i].getTotalLineItemPrice();
totalLineItemPriceElem.addTextNode(
String.valueOf(totalLineItemPrice));
SOAPElement quantityElem =
invoiceItemElem.addChildElement("quantity");
int qty = items[i].getQuantity();
quantityElem.addTextNode(String.valueOf(qty));
}
Creating output (incomplete)
// save and return
outputMessage.saveChanges();
return outputMessage;
}
SAAJ Requestor
public static SOAPMessage createSOAPRequest(long
invoiceId)
throws SOAPException {
// Create message factory
MessageFactory messageFactory =
MessageFactory.newInstance();
// Create a message
SOAPMessage message =
messageFactory.createMessage();
SOAPPart soapPart = message.getSOAPPart();
SOAPEnvelope envelope = soapPart.getEnvelope();
SAAJ Requestor
// Get the SOAP header from the message and remove it
SOAPHeader header = message.getSOAPHeader();
header.detachNode();
// Get the SOAP body from the message
SOAPBody soapBody = message.getSOAPBody();
// create the outer invoice element
Name getInvoiceName =
envelope.createName("getInvoiceById",
null,
"http://ibiblio.org/invoice/types");
SOAPBodyElement getInvoiceElem =
soapBody.addBodyElement(getInvoiceName);
SAAJ Requestor
// create the invoice parameter
Name invoiceIdName =
envelope.createName("long_1",null,"");
SOAPElement invoiceIdElem =
getInvoiceElem.addChildElement(invoiceIdName);
invoiceIdElem.addNamespaceDeclaration("","");
invoiceIdElem.addTextNode(String.valueOf(invoiceId));
message.saveChanges();
return message;
}
SAAJ Code Problems





Compliant with SOAP…
Still haven’t done anything with WSDL
Lots and lots of XML creation and parsing
Absolutely no error checking – not even
simple type checking
Have to handle all interoperability problems
JAX-RPC
JAX-RPC Provider Runtime
JAX-RPC Requestor Runtime
Requestor
Application
Logic
Generated
Code
Servant
Service
Endpoint
Interface
Generated
Code
Stubs
HTTP Client
Ties
SOAP
HTTP Server
Provider
Application
Logic
JAX-RPC Service Endpoint
Interface
package org.ibiblio.mdthomas.ws.autopartssupplier;
import java.rmi.Remote;
import java.rmi.RemoteException;
public interface InvoiceWebService extends Remote
{
public InvoiceBean getInvoiceById(long id)
throws RemoteException;
}
JAX-RPC Servant
public class InvoiceHelper
implements InvoiceWebService {
// existing code
}
Run the tools



SEI-to-WSDL tool and WSDL-to-SEI tool are
required by JAX-RPC specification
Wscompile and wsdeploy with the Java Web
Services Development Pack from Sun
Java2WSDL with Apache Axis
Web Service “home page”
Web Service WSDL
JAX-RPC Requestor
public static void main(String[] args) {
try {
// Get the web service port
InvoiceWebService_Service wsDef =
new InvoiceWebService_Service_Impl();
InvoiceWebService_PortType stub =
wsDef.getInvoiceWebServicePort();
// Create the input parameter
GetInvoiceById idWrapper = new GetInvoiceById(1000);
// Make the remote call to the web service
GetInvoiceByIdResponse invoiceWrapper =
stub.getInvoiceById(idWrapper);
// Unwrap the result
InvoiceBean invoice = invoiceWrapper.getResult();
// Print some data
CustomerBean customer = invoice.getCustomer();
System.out.println("Customer: "+customer.getName());
InvoiceItemBean items[] = invoice.getInvoiceItems();
for (int i=0;i<items.length;i++) {
System.out.println("item name: "+items[i].getName());
}
} catch (Exception ex) {
ex.printStackTrace();
}
}
JAX-RPC Requestor
public static void main(String[] args) {
try {
// Get the web service port
InvoiceWebService_Service wsDef =
new InvoiceWebService_Service_Impl();
InvoiceWebService_PortType stub =
wsDef.getInvoiceWebServicePort();
// Create the input parameter
GetInvoiceById idWrapper = new GetInvoiceById(1000);
// Make the remote call to the web service
GetInvoiceByIdResponse invoiceWrapper =
stub.getInvoiceById(idWrapper);
// Unwrap the result
InvoiceBean invoice = invoiceWrapper.getResult();
// Print some data
CustomerBean customer = invoice.getCustomer();
System.out.println("Customer: "+customer.getName());
InvoiceItemBean items[] = invoice.getInvoiceItems();
for (int i=0;i<items.length;i++) {
System.out.println("item name: "+items[i].getName());
}
} catch (Exception ex) {
ex.printStackTrace();
}
.NET C# Requestor

Generate C# requestor based on WSDL:
>wsdl.exe /language:CS /protocol:SOAP \
http://localhost:8080/invoice/jaxrpc/invoice?WSDL

Entry point:
public getInvoiceByIdResponse getInvoiceById(
[System.Xml.Serialization.XmlElementAttribute("getInvoiceById",
Namespace="http://www.ibiblio.org/mdthomas/invoice/types")]
getInvoiceById getInvoiceById1) {
object[] results = this.Invoke("getInvoiceById",
new object[] {getInvoiceById1});
return ((getInvoiceByIdResponse)(results[0]));
}
.NET C# Requestor
class JAXClient {
[STAThread]
static void Main(string[] args) {
// Create the stub
InvoiceWebService service = new InvoiceWebService();
// Set the endpoint
if (args.Length == 1)
service.Url = args[0];
else
service.Url = "http://localhost:8080/invoice-jaxrpc/invoice";
// create and send the request
getInvoiceById idWrapper = new getInvoiceById();
idWrapper.long_1 = 1000;
getInvoiceByIdResponse responseWrapper = service.getInvoiceById(idWrapper);
// Receive and process the result
InvoiceBean invoice = responseWrapper.result;
Console.WriteLine("Invoice id: "+invoice.invoiceId);
CustomerBean customer = invoice.customer;
Console.WriteLine("Customer: "+customer.name);
for (int i=0;i<invoice.invoiceItems.Length;i++) {
Console.WriteLine("item name: "+invoice.invoiceItems[i].name);
}
}
}
Web Services Architecture





Web Services as a presentation layer
technology
Service Oriented Architecture (SOA) & Web
Services
Message Exchange Patterns (MEPs)
RPC centric vs. Document centric
approaches
Relevant SOAP & WSDL details
Web Services And
Presentation Layer
Web Services And
Presentation Layer
Fallacies Of Distributed
Computing (Peter Deutch)
• The
network is reliable
• Latency is zero
• Bandwidth is infinite
• The network is secure
• Topology doesn’t change
• There is one administrator
• Transport cost is zero
• The network is homogeneous
Waldo On Distributed
Computing
“…work in distributed object-oriented systems
that is based on a model that ignores or
denies [the differences between local and
remote objects] is doomed to failure, and
could easily lead to an industry-wide rejection
of the notion of distributed object-based
systems."
-- Jim Waldo et al, “A Note on Distributed
Computing,” 1994
Local objects are different than
remote objects

Local objects are different than remote
objects because:




Different address spaces (by reference vs. by
copy)
Latency
Partial failure
Concurrency
Service Oriented Architecture
(SOA)






Services have network interfaces
Service providers and consumers are loosely
coupled
Interfaces are coarse grained
Location is transparent
Services can be looked up in a registry
Consumer can bind to a provider at runtime
SOA applied to EJBs


EJBs do distributed computing
J2EE patterns that promote SOA tenets:


Session Façade pattern with Value Objects for
“bind” and “execute”
Service Locator pattern for “find”
SOA Applied to EJBs
HttpServlet
«uses»
PresentationProcessor
«JavaBean»
ValueObject
BusinessDelegate
«returns»
ServiceLocator
«locates»
«returns»
SessionFacadeRemote
«proxy for»
«SessionEJB»
SessionFacade
«local access»
Servlet Container JVM
«EntityEJB»
EntityBean
EJB Container JVM
SOA Applied To Web Services
UDDIProxy
WebServicesRequestor
WebServiceProvider
BusinessLogicObject
Find WSDL
SOAP Request
Execute Business Logic
Create
ProviderValueObject
Read
SOAP Response (Value Obj. as XML)
Create
RequestorValueObject
Read
Message Exchange Patterns


Message Exchange Patterns (MEPs): how
messages are exchanged
There are really two:




Request-response
One way
WSDL defines two others, notification and
solicit response, which aren’t supported by
J2EE and aren’t widely used
Code to MEPs, not to the underlying protocol
Request-response over HTTP
One way MEP over HTTP
Request-response MEP over
SMTP
RPC Centric vs. Document
Centric




RPC Centric: Web services transmit objects
as XML
Document Centric: Web services transmit
XML documents. Applications on either end
create and parse XML documents
RPC is more closely associated with the
request-response MEP
Document centric is more closely associated
with the one way MEP
Document Centric Approach
RPC Centric Approach
RPC vs. Doc and J2EE







JAX-RPC is an RPC centric approach
JAXM is document centric
SAAJ is low-level – document centric by default
Document centric is best when you are really
dealing with documents – newsfeeds for example
Doesn’t make sense to change XML to objects
back to XML again
Usually, you want to deal with objects, not XML
However:


Business tends to think in documents (P.O., Invoice)
Documents are more naturally coarse grained
WSDL & SOAP


SOAP wire-line protocol
SOAP envelope, body and headers:








Body: Just transporting the data
Header: Meta-data. Higher standards use headers
Envelope: just a container
WSDL describes the web service
Similar to Java method signatures
WSDL is very interesting
Helps to understand WSDL to do JAX-RPC
Can go a long way with JAX-RPC without knowing
anything about SOAP
WSDL compared to Java
WSDL Type
(Java Value
Object Type)
WSDL Message
(Java Parameter)
WSDL Operation
(Java Method)
WSDL Type
(Java Value
Object Type)
WSDL Message
(Java Parameter)
WSDL Operation
(Java Method)
WSDL Port Type
(Java Interface)
WSDL
Service
Operation
Message
1
*
*
1
*
1
PortType
1
Type
«uses»
XSD Type
1
*
*
«specifies»
Port
Binding
«uses»
Style
SOAP:Binding
«specifies»
1
1
1
*
1
SOAP:Address
*
1
1
Encoding
URI
Literal XML
SOAP Section 5 Encoding
Document Style
RPC Style
Interoperability Challenges
Interoperability is the chief challenge of web
services
 Tools generating SOAP, WSDL, UDDI, etc. need to
be interoperable
 A more complex variation of the “Browser Wars” of
the 1990’s
 Web Services Interoperability (WS-I) dedicated to
Interoperability
 WS-I Basic Profile 1.0 declares an interoperable
web services platform

WS-I Basic Profile
 WS-I
Basic Profile 1.0:
SOAP 1.1
 WSDL 1.1
 Must use HTTP binding, should use HTTP 1.1
 XML Schema Part 1, Part 2
 May use HTTPS
 SOAP messages should use document/literal

 Similar
to the J2EE certification program
JAX-RPC
• Big
selling point: Never have to program against
SOAP
• Big value add: Generated code (not the APIs)
• Addresses interoperability problems because the
code generators can adhere to WS-I Basic Profile
1.0
• Uses Façade and Value Object patterns
• RPC-centric, though you can start with defined
WSDL and XSD
• Tends to use request-response MEP, but can
work with one-way MEP
JAX-RPC
JAX-RPC Provider Runtime
JAX-RPC Requestor Runtime
Requestor
Application
Logic
Servant
Service
Endpoint
Interface
Service
Endpoint
Interface
Message Handlers
Custom
Type
Handlers
Message Handlers
Stubs
HTTP Client
Provider
Application
Logic
Ties
SOAP
HTTP Server
Custom
Type
Handlers
JAX-RPC Interoperability
JAX-RPC
Requestor
JAX-RPC
Provider
Non JAX-RPC
Requestor
Non JAX-RPC
Provider
JAX-RPC SEI-first Provider
Development
Service Endpoint Interface first – web services
enabling existing Java code
1. Define a Service Endpoint Interface
2. Implement the Servant – ties to business
logic
3. Generate WSDL with JAX-RPC
4. Create WAR
5. Deploy to servlet container
JAX-RPC SEI-first Provider
Development
<?xml version="1.0" encoding="UTF-8"?>
<configuration
xmlns="http://java.sun.com/xml/ns/jax-rpc/ri/config">
<service name="InvoiceWebService"
targetNamespace="http://www.ibiblio.org/mdthomas/invoice"
typeNamespace="http://www.ibiblio.org/mdthomas/invoice/types"
packageName="org.ibiblio.mdthomas.ws.autopartssupplier">
<interface
name="org.ibiblio.mdthomas.ws.autopartssupplier.InvoiceWebService"/>
</service>
</configuration>
JAX-RPC Requestor
Development
1.
2.
3.





Point at the WSDL file
Generate stubs
Code against the stubs
Stubs mirror the WSDL entities
The SEI is generated for the requestor side
Value objects are generated
SEI and value objects are usually in a different
package
Can generate a JAX-RPC Requestor against
non JAX-RPC generated WSDL documents
JAX-RPC Requestor
Development
<?xml version="1.0" encoding="UTF-8"?>
<configuration
xmlns="http://java.sun.com/xml/ns/jax-rpc/ri/config">
<wsdl location="InvoiceWebService.wsdl"
packageName="invoicestub"/>
</configuration>
JAX-RPC WSDL-first
Development
1.
2.
3.
4.
5.
6.
Point to the WSDL
Generate SEI, value objects
Code Servant
Generate Ties
Create WAR
Deploy to servlet container
WSDL generated Java






WSDL supersets Java in several areas
Can define multiple OUT and IN/OUT parameters
JAX-RPC uses holder objects for these
Can define one-way operations
WSDL can do stronger typing than Java (e.g.,
regular expression facets)
Headers can be mapped as “explicit context” to an
SEI call – a header will be passed to the SEI
method as a parameter
Service Endpoint Interfaces
(SEIs)
1.
2.
3.
4.

Must extend java.rmi.Remote
Every method must throw RemoteException
No constant declarations
Parameters and return types must be valid
JAX-RPC types
#4 is the big one
JAX-RPC Types






XML (and thus web services) is data-centric not
object-centric
Valid JAX-RPC types are what could be
considered “value types”
Java primitives and primitive wrappers (int,
Integer, long, Long, etc.)
Some standard Java classes (e.g., String, Date)
Java value types (method-less Java classes or,
roughly, JavaBeans)
Arrays
JAX-RPC Standard Types







java.lang.String
java.math.BigInteger
java.math.BigDecimal
java.util.Calendar
java.util.Date
java.xml.namespace.QName
java.net.URI
Value Object Types





Default no object constructor
Must not implement Remote
Methods are not mapped to the transmitted
XML
Java Bean properties and public, non-final,
non-static fields are mapped
Fields/properties can be any valid JAX-RPC
type
Value Object
public class PersonValueType {
public String name;
public Date birthDate;
public boolean smoker;
public String sex;
public int cholestrolLevel;
public URI webSite;
public PersonValueType mom;
public PersonValueType dad;
public PersonValueType children[];
}
Exceptions & SOAP Faults




Can declare exceptions in an SEI
Will declare an equivalent fault in the WSDL
file
Exception will be thrown on the requestor
when a fault is received
Exceptions in the SEI must not extend
RuntimeException
JAX-RPC Polymorphism




Subtypes of a declared return type can be
returned
Must tell the code generation tool about the
sub-types if they don’t appear elsewhere in
the SEI
WSDL supports extensible types
Can downcast in the JAX-RPC requestor
code
Handlers


JAX-RPC message handlers give you a way
to access a SOAP message before or after
its ultimate processing
Handler interface has three methods:



handleRequest
handleResponse
handleFault
JAX-RPC Handlers
Requestor
App.
Handler
1
Handler
4
Network
Handler
2
Handler
3
Servant
ServletEndpointInterface


ServletEndpointInterface provides access to the
underlying servlet context
Can use it inside a JAX-RPC servant to:




Get/set values to an HTTPSession
Interface with HTTP authentication
Get resources
Be careful:


SOAP is designed to be transport (i.e., HTTP)
independent (but WS-I says its okay to use HTTP
cookies)
The requestor must support cookies and behave
correctly! (Not the same as assuming a web browser
will behave correctly)
ServletEndpointContext
public class HttpAccessServant implements HttpAccess, ServiceLifecycle
{
ServletEndpointContext context;
public void init(Object o) {
context = (ServletEndpointContext)o;
}
public void destroy() {
}
public void setHttpSessionAttribute(String key, String val)
throws RemoteException {
HttpSession session = context.getHttpSession();
session.setAttribute(key,val);
}
}
2.1 Stateless Session Beans
and Web Services




EJB 2.1 specifies that Stateless Session
Beans may declare a SEI
Similar to a remote component interface
EJB container is a JAX-RPC runtime –
manages requests to the SEI
One step simpler than a servlet based SEI
that accesses the Stateless Session Bean
through a Session Façade pattern
Differences Between Servlet JAXRPC & EJB Container JAX-RPC



Different network architecture: May not want
outside HTTP connections to the EJB
Container
Differences in transport implementation
EJB 2.1 does not require that the EJB
container support HTTP sessions
Static vs. Dynamic Requestors




Static proxy: Use stubs generated by WSDL-toJava tool at compile time
Dynamic proxy: Use proxy created at runtime,
though SEI is generated at compile time
Dynamic Invocation Interface (DII): Completely
dynamic. Signature of web service and WSDL
doesn’t need to be known until runtime
Requestors and providers are usually
somewhat coupled at compile time, even if you
use DII
Apache Axis



Axis is a web services engine
Implements JAX-RPC 1.1, SAAJ 1.2
specification
Axis details beyond J2EE standards:




JWS deployment – similar to JSP
WSDD for deploying web services
Currently, some weaknesses in supporting
WS-I Basic Profile (e.g., document/literal)
Should be addressed soon
SAAJ




SAAJ is a wrapper for XML parsing and can
handle HTTP calls
SAAJ provides convenience methods for
accessing the SOAP envelope, headers and
body
Similar to JDOM
Can bridge to W3C DOM APIs
JAXM & Messaging





JAXM is an asynchronous, queue-based
messaging API
Not part of J2EE 1.4
Uses queues on either side
Doesn’t provide WSDL facilities
Can be used in conjunction with JAXB to
convert to objects
JAXR






JAXR – API for XML registries
Generic: Can be used with any XML registry
Support for UDDI and ebXML
Has support for querying and for publishing
Publishing requires authentication
Can set up your own “private” UDDI registries
that act as a naming service
Conclusions







JAX-RPC: quickest solution for synchronous, RPC
style web services and for service-enabling
existing code
RPC model isn’t always best – if it’s too fine
grained it violates SOA
SOA – coarse grained, loosely coupled interfaces
JAXP – Avoid if possible. Use JAXB/Castor to
translate into an object model
JAXM – Good for message style services
SOAP & WSDL – WSDL is more interesting
JAXR – Used for access to XML Registries (i.e.,
UDDI)