The Java EE 5 Tutorial

Returning the Price List

This section takes you through the servlet PriceListServlet. This servlet creates the message containing the current price list that is returned to the method call, invoked in PriceListRequest.

Any servlet extends a javax.servlet class. Being part of a web application, this servlet extends HttpServlet. It first creates a static MessageFactory object that will be used later to create the SOAPMessage object that is returned.

public class PriceListServlet extends HttpServlet {
    static final Logger logger =
        Logger.getLogger("com.sun.cb.saaj.PriceListServlet");
    static MessageFactory messageFactory = null;

    static {
        try {
            messageFactory = MessageFactory.newInstance();
        } catch (Exception ex) {
            logger.severe("Exception: " + ex.toString());
        }
     };

Every servlet has an init method. This init method initializes the servlet with the configuration information that the Application Server passed to it.

public void init(ServletConfig servletConfig)
        throws ServletException {
    super.init(servletConfig);
}

The next method defined in PriceListServlet is doPost, which does the real work of the servlet by calling the onMessage method. (The onMessage method is discussed later in this section.) The Application Server passes the doPost method two arguments. The first argument, the HttpServletRequest object req, holds the content of the message sent in PriceListRequest. The doPost method gets the content from req and puts it in the SOAPMessage object msg so that it can pass it to the onMessage method. The second argument, the HttpServletResponse object resp, will hold the message generated by executing the method onMessage.

In the following code fragment, doPost calls the methods getHeaders and putHeaders, defined immediately after doPost, to read and write the headers in req. It then gets the content of req as a stream and passes the headers and the input stream to the method MessageFactory.createMessage. The result is that the SOAPMessage object msg contains the request for a price list. Note that in this case, msg does not have any headers because the message sent in PriceListRequest 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 = messageFactory.createMessage(headers, is);

Next, the code declares the SOAPMessage object reply and populates it by calling the method onMessage.

        SOAPMessage reply = null;
        reply = onMessage(msg);

If reply has anything in it, its contents are saved, the status of resp is set to OK, and the headers and content of reply are written to resp. If reply is empty, the status of resp 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
            logger.info("Reply message:");
            OutputStream os = resp.getOutputStream();
            reply.writeTo(os);
            os.flush();
        } else {
            resp.setStatus(HttpServletResponse.SC_NO_CONTENT);
        }
    } catch (Exception ex) {
        throw new ServletException( "SAAJ POST failed: " + ex.getMessage());
    }
}

The methods getHeaders and putHeaders are not standard methods in a servlet, as init, doPost, and onMessage are. The method doPost calls getHeaders and passes it the HttpServletRequest object req that the Application Server passed to it. It returns a MimeHeaders object populated with the headers from req.

static MimeHeaders getHeaders(HttpServletRequest req) {

    Enumeration headerNames = req.getHeaderNames();
    MimeHeaders headers = new MimeHeaders();

    while (headerNames.hasMoreElements()) {
        String headerName = (String)headerNames.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 calls putHeaders and passes it the MimeHeaders object headers, which was returned by the method getHeaders. The method putHeaders writes the headers in headers to res, the second argument passed to it. The result is that res, the response that the Application Server will return to the method call, 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 by PriceListRequest and internalized into msg. It uses the static MessageFactory object messageFactory to create the SOAPMessage object message and then populates it with the supplier’s current coffee prices.

The method doPost invokes onMessage and passes it msg. In this case, onMessage does not need to use msg because it simply creates a message containing the supplier’s price list. The onMessage method in ConfirmationServlet (see 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 = messageFactory.createMessage();

        SOAPBody body = message.getSOAPBody();

        QName bodyName =
             new QName("http://sonata.coffeebreak.com", "price-list", "PriceList");
        SOAPBodyElement list = body.addBodyElement(bodyName);

        QName coffeeN = new QName("coffee");
        SOAPElement coffee = list.addChildElement(coffeeN);

        QName coffeeNm1 = new QName("coffee-name");
        SOAPElement coffeeName = coffee.addChildElement(coffeeNm1);
        coffeeName.addTextNode("Arabica");

        QName priceName1 = new QName("price");
        SOAPElement price1 = coffee.addChildElement(priceName1);
        price1.addTextNode("4.50");

        QName coffeeNm2 = new QName("coffee-name");
        SOAPElement coffeeName2 = coffee.addChildElement(coffeeNm2);
        coffeeName2.addTextNode("Espresso");

        QName priceName2 = new QName("price");
        SOAPElement price2 = coffee.addChildElement(priceName2);
        price2.addTextNode("5.00");

        QName coffeeNm3 = new QName("coffee-name");
        SOAPElement coffeeName3 = coffee.addChildElement(coffeeNm3);
        coffeeName3.addTextNode("Dorada");

        QName priceName3 = new QName("price");
        SOAPElement price3 = coffee.addChildElement(priceName3);
        price3.addTextNode("6.00");

        QName coffeeNm4 = snew QName("coffee-name");
        SOAPElement coffeeName4 = coffee.addChildElement(coffeeNm4);
        coffeeName4.addTextNode("House Blend");

        QName priceName4 = new QName("price");
        SOAPElement price4 = coffee.addChildElement(priceName4);
        price4.addTextNode("5.00");

        message.saveChanges();

    } catch(Exception e) {
        logger.severe("onMessage: Exception: " + e.toString());
    }
    return message;
}