FAQ
History |
Previous Home Next |
Search
Feedback |
DividerJAXM Distributor Service
The JAXM distributor service and the Coffee Break have made arrangements regarding their exchange of XML documents. These arrangements include what kinds of messages they will send, the form of those messages, and what kind of JAXM messaging they will do. If they had agreed to do one-way messaging, they would also have had to use messaging providers that talk to each other and had to use the same profile. In this scenario, the parties have agreed to use request-response messaging, so a messaging provider is not needed.
The Coffee Break server sends two kinds of messages:
- Requests for current wholesale coffee prices
- Customer orders for coffee
The JAXM coffee supplier responds with two kinds of messages:
- Current price lists
- Order confirmations
All of the messages they send conform to an agreed-upon XML structure, which is specified in a DTD for each kind of message. This allows them to exchange messages even though they use different document formats internally.
The four kinds of messages exchanged by the Coffee Break server and the JAXM distributor are specified by the following DTDs:
request-prices.dtd
price-list.dtd
coffee-order.dtd
confirm.dtd
These DTDs may be found at
<INSTALL>
/j2eetutorial
/examples/cb/jaxm/dtdsThe
dtds
directory also contains a sample of what the XML documents specified in the DTDs might look like. The corresponding XML files for each of the DTDs are as follows:
request-prices.xml
price-list.xml
coffee-order.xml
confirm.xml
Because of the DTDs, both parties know ahead of time what to expect in a particular kind of message and can therefore extract its content using the JAXM API.
Code for the server application is in the directory:
<INSTALL>
/j2eetutorial
/examples/cb/jaxm/serviceJAXM Service
The JAXM coffee distributor, the JAXM server in this scenario, provides the response part of the request-response paradigm. When JAXM messaging is being used, the server code is a servlet. The core part of each servlet is made up of three
javax.servlet.HttpServlet
methods:init
,doPost
, andonMessage
. Theinit
anddoPost
methods set up the response message, and theonMessage
method gives the message its content.Returning the Price List
This section takes you through the servlet
PriceListServlet
. This servlet creates the message with the current price list that is returned to the methodcall
, invoked inPriceListRequest
.Any servlet extends a
javax.servlet
class. Being part of a Web application, this servlet extendsHttpServlet
. It first creates a staticMessageFactory
object that will be used later to create theSOAPMessage
object that is returned. Then it declares theMessageFactory
objectmsgFactory
, which will be used to create aSOAPMessage
object that has the headers and content of the original request message.public class PriceListServlet extends HttpServlet { MessageFactory msgFactory;Every servlet has an
init
method. Thisinit
method initializes the servlet with the configuration information that the application server passed to it. Then it simply initializesmsgFactory
with the default implementation of theMessageFactory
class.public void init(ServletConfig servletConfig) throws ServletException { super.init(servletConfig); try { // Initialize it to the default. msgFactory = MessageFactory.newInstance(); } catch (SOAPException ex) { throw new ServletException( "Unable to create message factory" + ex.getMessage()); } }The next method defined in
PriceListServlet
isdoPost
, which does the real work of the servlet by calling theonMessage
method. (TheonMessage
method is discussed later in this section.) the application server passes thedoPost
method two arguments. The first argument, theHttpServletRequest
objectreq
, holds the content of the message sent inPriceListRequest
. ThedoPost
method gets the content fromreq
and puts it in theSOAPMessage
objectmsg
so that it can pass it to theonMessage
method. The second argument, theHttpServletResponse
objectresp
, will hold the message generated by executing the methodonMessage
.In the following code fragment,
doPost
calls the methodsgetHeaders
andputHeaders
, defined immediately afterdoPost
, to read and write the headers inreq
. It then gets the content ofreq
as a stream and passes the headers and the input stream to the methodMessageFactory.createMessage
. The result is that theSOAPMessage
objectmsg
contains the request for a price list. Note that in this case,msg
does not have any headers because the message sent inPriceListRequest
did not have any headers.public void doPost( HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { try { // Get all the headers from the HTTP request. MimeHeaders headers = getHeaders(req); // Get the body of the HTTP request. InputStream is = req.getInputStream(); // Now internalize the contents of the HTTP request and // create a SOAPMessage SOAPMessage msg = msgFactory.createMessage(headers, is);Next, the code declares the
SOAPMessage
objectreply
and populates it by calling the methodonMessage
.SOAPMessage reply = null; reply = onMessage(msg);If
reply
has anything in it, its contents are saved, the status ofresp
is set to OK, and the headers and content ofreply
are written toresp
. Ifreply
is empty, the status ofresp
is set to indicate that there is no content.if (reply != null) { // Need to call saveChanges because we're going to use the // MimeHeaders to set HTTP response information. These // MimeHeaders are generated as part of the save. if (reply.saveRequired()) { reply.saveChanges(); } resp.setStatus(HttpServletResponse.SC_OK); putHeaders(reply.getMimeHeaders(), resp); // Write out the message on the response stream. OutputStream os = resp.getOutputStream(); reply.writeTo(os); os.flush(); } else resp.setStatus(HttpServletResponse.SC_NO_CONTENT); } catch (Exception ex) { throw new ServletException( "JAXM POST failed " + ex.getMessage()); } }The methods
getHeaders
andputHeaders
are not standard methods in a servlet the wayinit
,doPost
, andonMessage
are. The methoddoPost
callsgetHeaders
and passes it theHttpServletRequest
objectreq
that the application server passed to it. It returns aMimeHeaders
object populated with the headers fromreq
.static MimeHeaders getHeaders(HttpServletRequest req) { Enumeration enum = req.getHeaderNames(); MimeHeaders headers = new MimeHeaders(); while (enum.hasMoreElements()) { String headerName = (String)enum.nextElement(); String headerValue = req.getHeader(headerName); StringTokenizer values = new StringTokenizer( headerValue, ","); while (values.hasMoreTokens()) { headers.addHeader(headerName, values.nextToken().trim()); } } return headers; }The
doPost
method callsputHeaders
and passes it theMimeHeaders
objectheaders
, which was returned by the methodgetHeaders
. The method putHeaders writes the headers inheaders
tores
, the second argument passed to it. The result is thatres
, the response that the application server will return to the methodcall
, now contains the headers that were in the original request.static void putHeaders(MimeHeaders headers, HttpServletResponse res) { Iterator it = headers.getAllHeaders(); while (it.hasNext()) { MimeHeader header = (MimeHeader)it.next(); String[] values = headers.getHeader(header.getName()); if (values.length == 1) res.setHeader(header.getName(), header.getValue()); else { StringBuffer concat = new StringBuffer(); int i = 0; while (i < values.length) { if (i != 0) concat.append(','); concat.append(values[i++]); } res.setHeader(header.getName(), concat.toString()); } } }The method
onMessage
is the application code for responding to the message sent byPriceListRequest
and internalized intomsg
. It uses the staticMessageFactory
objectfac
to create theSOAPMessage
objectmessage
and then populates it with the distributor's current coffee prices.The method
doPost
invokesonMessage
and passes itmsg
. In this case,onMessage
does not need to usemsg
because it simply creates a message containing the distributor's price list. TheonMessage
method inConfirmationServlet (
Returning the Order Confirmation), on the other hand, uses the message passed to it to get the order ID.public SOAPMessage onMessage(SOAPMessage msg) { SOAPMessage message = null; try { message = fac.createMessage(); SOAPPart part = message.getSOAPPart(); SOAPEnvelope envelope = part.getEnvelope(); SOAPBody body = envelope.getBody(); Name bodyName = envelope.createName("price-list", "PriceList", "http://sonata.coffeebreak.com"); SOAPBodyElement list = body.addBodyElement(bodyName); Name coffeeN = envelope.createName("coffee"); SOAPElement coffee = list.addChildElement(coffeeN); Name coffeeNm1 = envelope.createName("coffee-name"); SOAPElement coffeeName = coffee.addChildElement(coffeeNm1); coffeeName.addTextNode("Arabica"); Name priceName1 = envelope.createName("price"); SOAPElement price1 = coffee.addChildElement(priceName1); price1.addTextNode("4.50"); Name coffeeNm2 = envelope.createName("coffee-name"); SOAPElement coffeeName2 = coffee.addChildElement(coffeeNm2); coffeeName2.addTextNode("Espresso"); Name priceName2 = envelope.createName("price"); SOAPElement price2 = coffee.addChildElement(priceName2); price2.addTextNode("5.00"); Name coffeeNm3 = envelope.createName("coffee-name"); SOAPElement coffeeName3 = coffee.addChildElement(coffeeNm3); coffeeName3.addTextNode("Dorada"); Name priceName3 = envelope.createName("price"); SOAPElement price3 = coffee.addChildElement(priceName3); price3.addTextNode("6.00"); Name coffeeNm4 = envelope.createName("coffee-name"); SOAPElement coffeeName4 = coffee.addChildElement(coffeeNm4); coffeeName4.addTextNode("House Blend"); Name priceName4 = envelope.createName("price"); SOAPElement price4 = coffee.addChildElement(priceName4); price4.addTextNode("5.00"); message.saveChanges(); } catch(Exception e) { e.printStackTrace(); } return message; } }Returning the Order Confirmation
ConfirmationServlet
creates the confirmation message that is returned to thecall
method that is invoked inOrderRequest
. It is very similar to the code inPriceListServlet
except that instead of building a price list, itsonMessage
method builds a confirmation with the order number and shipping date.The
onMessage
method for this servlet uses theSOAPMessage
object passed to it by thedoPost
method to get the order number sent inOrderRequest
. Then it builds a confirmation message with the order ID and shipping date. The shipping date is calculated as today's date plus two days.public SOAPMessage onMessage(SOAPMessage message) { SOAPMessage confirmation = null; try { //retrieve the orderID element from the message received SOAPBody sentSB = message.getSOAPPart(). getEnvelope().getBody(); Iterator sentIt = sentSB.getChildElements(); SOAPBodyElement sentSBE = (SOAPBodyElement)sentIt.next(); Iterator sentIt2 = sentSBE.getChildElements(); SOAPElement sentSE = (SOAPElement)sentIt2.next(); //get the text for orderID to put in confirmation String sentID = sentSE.getValue(); //create the confirmation message confirmation = fac.createMessage(); SOAPPart sp = confirmation.getSOAPPart(); SOAPEnvelope env = sp.getEnvelope(); SOAPBody sb = env.getBody(); Name newBodyName = env.createName("confirmation", "Confirm", "http://sonata.coffeebreak.com"); SOAPBodyElement confirm = sb.addBodyElement(newBodyName); //create the orderID element for confirmation Name newOrderIDName = env.createName("orderId"); SOAPElement newOrderNo = confirm.addChildElement(newOrderIDName); newOrderNo.addTextNode(sentID); //create ship-date element Name shipDateName = env.createName("ship-date"); SOAPElement shipDate = confirm.addChildElement(shipDateName); //create the shipping date Date today = new Date(); long msPerDay = 1000 * 60 * 60 * 24; long msTarget = today.getTime(); long msSum = msTarget + (msPerDay * 2); Date result = new Date(); result.setTime(msSum); String sd = result.toString(); shipDate.addTextNode(sd); confirmation.saveChanges(); } catch (Exception ex) { ex.printStackTrace(); } return confirmation; }
FAQ
History |
Previous Home Next |
Search
Feedback |
All of the material in The J2EE Tutorial for the Sun ONE Platform is copyright-protected and may not be published in other works without express written permission from Sun Microsystems.