[ Team LiB ] Previous Section Next Section

Recipe 25.2 Accessing the Tomcat JNDI Resource from a Servlet

Problem

You want to access a JNDI object with a servlet using Tomcat's JNDI implementation.

Solution

Use the javax.naming classes in the servlet's init( ) method to look up a JNDI object. Then use the object in a service method like doGet( ).

Discussion

A servlet can access a JavaBean as a JNDI registered resource after you have:

  1. Developed the JavaBean class and stored it in WEB-INF/classes or in a JAR in WEB-INF/lib.

  2. Changed the server configuration file and web.xml as described in Recipe 25.1, in order to bind the object to the Tomcat JNDI tree.

Example 25-4 creates a javax.naming.InitialContext in its init( ) method, then looks up a JavaBean: com.jspservletcookbook.StockPriceBean. This bean is bound to the JNDI implementation under the name "bean/pricebean." The init( ) method is called only when the servlet container creates a servlet instance, so the servlet has access to one instance of StockPriceBean.

Example 25-4. Using a Tomcat JNDI object from a servlet
package com.jspservletcookbook;    

import java.io.IOException;  
import java.io.PrintWriter;   

import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;  

import javax.servlet.*;
import javax.servlet.http.*;

public class BeanServlet extends HttpServlet {

    private StockPriceBean spbean;

  public void init( ) throws ServletException {
        
      Context env = null;
        
      try{
           
          env = (Context) new InitialContext( ).lookup("java:comp/env");

          spbean = (StockPriceBean) env.lookup("bean/pricebean");
             
          //close the InitialContext, unless the code will use it for
          //another look up
          env.close( );
             
          if (spbean == null)
              throw new ServletException(
              "bean/pricebean is an unknown JNDI object");
             
      } catch (NamingException ne) { 
        
          try{ env.close( );} catch (NamingException nex) { }
            
          throw new ServletException(ne);

      }//try
      

  }//init
    
  public void doGet(HttpServletRequest request, 
    HttpServletResponse response)
    throws ServletException, java.io.IOException {
    
      //set the MIME type of the response, "text/html"
      response.setContentType("text/html");
    
      //use a PrintWriter to send text data to the client 
      java.io.PrintWriter out = response.getWriter( );
    
      //Begin assembling the HTML content
      out.println("<html><head>");
    
      out.println("<title>Stock Price Fetcher</title></head><body>");
      out.println("<h2>Please submit a valid stock symbol</h2>");
   
      //make sure method="POST" so that the servlet service method
      //calls doPost in the response to this form submit
      out.println(
        "<form method=\"POST\" action =\"" + request.getContextPath( ) +
            "/namingbean\" >");

      out.println("<table border=\"0\"><tr><td valign=\"top\">");
      out.println("Stock symbol: </td>  <td valign=\"top\">");
      out.println("<input type=\"text\" name=\"symbol\" size=\"10\">");
      out.println("</td></tr><tr><td valign=\"top\">");

      out.println(
      "<input type=\"submit\" value=\"Submit Info\"></td></tr>");

      out.println("</table></form>");
      out.println("</body></html>");
    
} //doGet
     
  public void doPost(HttpServletRequest request, 
    HttpServletResponse response)
    throws java.io.IOException{
       
      String symbol;//this will hold the stock symbol

      float price = 0f;
    
      symbol = request.getParameter("symbol");
    
      boolean isValid = (symbol == null || symbol.length( ) < 1) ?
      false : true;

      //set the MIME type of the response, "text/html"
      response.setContentType("text/html");
    
      //use a PrintWriter send text data to the client 
      java.io.PrintWriter out = response.getWriter( );
    
      //Begin assembling the HTML content
      out.println("<html><head>");
      out.println("<title>Latest stock value</title></head><body>");
    
      if ((! isValid) || spbean == null){
          out.println(
          "<h2>Sorry, the stock symbol parameter was either "+
          "empty or null</h2>");
        
      } else {
    
          out.println("<h2>Here is the latest value of "+ symbol +"</h2>");
          spbean.setSymbol(symbol);
          price = spbean.getLatestPrice( );
          out.println( (price==0?
            "The symbol is probably invalid." : ""+price) );
      }
      out.println("</body></html>");
  }//doPost
}//BeanServlet

Example 25-4 calls close( ) on the InitialContext to free up any resources this object is using, since the code does not use it again to initiate a lookup. Then the servlet uses the bean object to access a live stock quote in its doGet( ) method. The servlet first calls the bean's setter method setSymbol( ) to notify the bean about which stock symbol it is looking up.

Example 25-5 shows the bean that Tomcat has stored as a JNDI object (it's the same bean used in Example 25-4). Chapter 26 explains this bean, which "scrapes" a stock price off of a web page. Chapter 26 covers the bean's details; the methods this chapter's servlet uses are setSymbol( ) and getLatestPrice( ). The bean handles all the details of downloading the stock price.

Example 25-5. The bean that is stored as a JNDI object
package com.jspservletcookbook;  

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URL;
import java.net.MalformedURLException;

import javax.swing.text.html.HTMLEditorKit.ParserCallback;
import javax.swing.text.MutableAttributeSet;
import javax.swing.text.html.parser.ParserDelegator;

public class StockPriceBean {

    private static final String urlBase =  
      "http://finance.yahoo.com/q?d=t&s=";
    private BufferedReader webPageStream = null;
    private URL stockSite = null;
    private ParserDelegator htmlParser = null;
    private MyParserCallback callback = null;
    private String htmlText = "";
    private String symbol = "";
    private float stockVal = 0f;

  public StockPriceBean( ) {}//no-arguments constructor for the bean
    
  public void setSymbol(String symbol){
      this.symbol = symbol;
  }
    
  public String getSymbol( ){
      return symbol;
    }

//Inner class provides the callback   
class MyParserCallback extends ParserCallback {
      
    private boolean lastTradeFlag = false;
    private boolean boldFlag = false;
  public MyParserCallback( ){
      if (stockVal != 0)
          stockVal = 0f;
  }
        
  public void handleStartTag(javax.swing.text.html.HTML.Tag t,
    MutableAttributeSet a,int pos) {
        if (lastTradeFlag && (t == javax.swing.text.html.HTML.Tag.B )){
            boldFlag = true;
        }
  }//handleStartTag

  public void handleText(char[] data,int pos){
      htmlText  = new String(data);
      if (htmlText.indexOf("No such ticker symbol.") != -1){
          throw new IllegalStateException(
              "Invalid ticker symbol in handleText( ) method.");
      }  else if (htmlText.equals("Last Trade:")){
          lastTradeFlag = true;
       } else if (boldFlag){
                
           try{
               stockVal = new Float(htmlText).floatValue( );
            } catch (NumberFormatException ne) {
                    
                try{
                    //tease out any commas in the number using NumberFormat
                    java.text.NumberFormat nf = java.text.NumberFormat.
                    getInstance( );
                    Double f = (Double) nf.parse(htmlText);
                    stockVal =  (float) f.doubleValue( );
                } catch (java.text.ParseException pe){
                    throw new IllegalStateException(
                      "The extracted text " + htmlText + 
                        " cannot be parsed as a number!");
                }//inner try

           }//outer try
            lastTradeFlag = false;
            boldFlag = false;
            
       }//if
  } //handleText
}//MyParserCallback

  public float getLatestPrice( ) throws IOException,MalformedURLException {

      stockSite = new URL(urlBase + symbol);
      webPageStream = new BufferedReader(new InputStreamReader(stockSite.
       openStream( )));
      htmlParser = new ParserDelegator( );
      callback = new MyParserCallback( );//ParserCallback

      synchronized(htmlParser){
          htmlParser.parse(webPageStream,callback,true);
      }//sychronized
       
      //reset symbol
      setSymbol("");
      return stockVal;

  }//getLatestPrice
}//StockPriceBean

The ParserDelegator.parse( ) method is synchronized and therefore designed to only allow one thread at a time to parse the web page and pull out the stock quote.


Figure 25-1 shows the web page form generated by the servlet's doGet( ) method. The user enters a stock symbol into this form, then submits the form to the servlet's doPost( ) method.

Figure 25-1. Enter a stock symbol for a live stock price
figs/jsjc_2501.gif

Figure 25-2 shows the stock information that the JNDI object found for the servlet.

Figure 25-2. The servlet's doPost( ) method generates a live stock quote using a JNDI object
figs/jsjc_2502.gif

See Also

Recipe 25.1 on configuring a JNDI object with Tomcat; Recipe 25.3 on accessing the Tomcat JNDI object from a JSP; Chapter 21 on accessing DataSources with JNDI; Chapter 26 on harvesting web information.

    [ Team LiB ] Previous Section Next Section