Servlet Agents

 < Free Open Study > 



There are a number of common functions that can be performed by a servlet agent. We'll look at they can collect, cache, and aggregate information from web services. Not every agent will do all of these things, but every agent will do at least one.

Collecting Information

The web service we've created allows us to look up the exchange rate between two currencies. We'll implement a client for this web service that will act as an agent and will retrieve information from our service. The servlet then presents the data to the requesting browser:

click to expand

The client is the consumer of the information. The client can be any web browser or other program that generates an HTTP request. It could even be another agent. The agent acts as the middleman. In our case, the agent is a servlet that is both a client and a server. From the point of view of the browser, the agent acts as a server but from the point of view of the web service, the agent acts as a client. The server is where the agent goes to find what it needs to satisfy the client. The agent may go to a single server or to many servers to complete its task. The server is the fundamental provider of information.

Using a SOAP Service

The source code for our agent is:

    import java.io.*;    import java.net.*;    import java.util.*;    import javax.servlet.*;    import javax.servlet.http.*;    import org.apache.soap.*;    import org.apache.soap.rpc.*;    public class SoapClientServlet extends HttpServlet { 

The doPost() method starts building an HTML document as a response and calls the getExchangeRate() method:

    public void doPost (HttpServletRequest request,                        HttpServletResponse response)         throws ServletException, IOException {       PrintWriter out = response.getWriter();       out.println("<html>");       out.println("<head>");       out.println("</head>");       out.println("<body>");       out.println("Exchange rate for Japan is: " +                   getExchangeRate("JP") + " Yen/Dollar");           out.println("</body>");       out.println("</html>");       out.close();       } 

The getExchangeRate() method is where all of the interesting code appears. First, we get a connection to the service. The URL uses port 8088 to support the TcpTunnelGui program, which will allow us to monitor the request to, and responses from, our web service:

       private String getExchangeRate(String country) {         String rateString;         try {           URL url = new URL( "http://localhost:8088/soap/servlet/rpcrouter");           String encodingStyleURI = Constants.NS_URI_SOAP_ENC;           URLConnection connection = url.openConnection(); 

Then we create a instance of a SOAP Call object. The target URI must be set to the same value that was used for the id attribute of the service when it was deployed. We also need to tell it which method we want to execute:

           Call call = new Call();           call.setTargetObjectURI("urn:SoapExchangeRate");           call.setMethodName("getExchangeRate"); 

Then we can add the arguments we want pass to this method. We only have one argument but setParams() still requires a Vector:

           Vector params = new Vector();           call.setEncodingStyleURI(encodingStyleURI);           params.addElement(new Parameter("country", String.class,                                           country, null));           call.setParams (params); 

Now that the call has been built, we invoke the service. The invoke() method returns a Response object that can be used to get the result or examine any fault that has occurred. The result is extracted by retrieving the response as a Parameter:

           if (resp.generatedFault()) {             Fault fault = resp.getFault();             rateString = fault.getFaultString();           } else {             Parameter result = resp.getReturnValue ();             rateString = ((Double)result.getValue()).toString();           }         } catch(Exception e) {           rateString = e.getMessage();         }         return rateString;       }       public void doGet (HttpServletRequest request,                          HttpServletResponse response)           throws ServletException, IOException {         doPost( request, response );       }    } 

The TcpTunnelGui program, which is provided with the Apache SOAP distribution, is a Java-based proxy program that will allow us to monitor TCP traffic directed. It can be invoked with the following command:

    java -cp soap.jar org.apache.soap.util.net.TcpTunnelGui 8088 localhost 8080 

The arguments for TcpTunnelGui are:

  • The capture port (8088)

  • The target machine (localhost)

  • The target port (8080)

TcpTunnelGui is a good way to see what is happening within the protocol. All the examples in this chapter have all been written to use TcpTunnelGui on port 8088.

We're ready now to test our servlet agent. You should have a web application with the following files and directories:

    webservices/                WEB-INF/                        classes/                                SoapClientServlet                        lib/                            soap.jar 

Once this web application has been deployed, we can invoke our agent by navigating to http://localhost:8080/webservices/servlet/SoapClientServlet:

click to expand

The output from TcpTunnelGui shows the SOAP messages that were sent to and from our web service:

click to expand

It's very easy to alter our agent so that it uses a different web service. To allow the agent to access the web service deployed on Axis we just need to change the URL and target URI used in the getExchangeRate() method:

       private String getExchangeRate(String country) {         ...             URL url = new URL("http://localhost:8088/axis/ExchangeRate.jws");         ...             call.setTargetObjectURI("ExchangeRate ");         ...       } 

With another couple of quick changes we could use our agent to access an Exchange Rate service available from http://www.xmethods.com/:

    import java.io.*;    import java.net.*;    import java.util.*;    import javax.servlet.*;    import javax.servlet.http.*;    import org.apache.soap.*;    import org.apache.soap.rpc.*;    public class XMethodsClientServlet extends HttpServlet {      private String getExchangeRate(String country) {        String rateString;        try{          URL url = new URL("http://services.xmethods.net:9090/soap");          String encodingStyleURI = Constants.NS_URI_SOAP_ENC;          URLConnection connection = url.openConnection();          Call call = new Call();          call.setTargetObjectURI("urn:xmethods-CurrencyExchange");          call.setMethodName("getRate");          Vector params = new Vector();          call.setEncodingStyleURI(encodingStyleURI); 

This web service requires both country codes. To gain the same functionality we have in our ExchangeRate class we hard code the first country as the US:

          params.addElement(new Parameter("country1", String.class,                                          "us", null));          params.addElement(new Parameter("country2", String.class,                                          country, null));          call.setParams(params);          Response resp = call.invoke(url, "");          ...        return rateString;       }     public void doPost (HttpServletRequest request,                          HttpServletResponse response)          throws ServletException, IOException {        PrintWriter out = response.getWriter();        out.println("<html>");        out.println("<head>");        out.println("</head>");        out.println("<body>"); 

We also need to change the country code from "JP" to "japan" to fit the requirements of the XMethods web service:

        out.println("Exchange rate for Japan is: "+                    getExchangeRate("japan")+" Yen/Dollar");        out.println("</body>");        out.println("</html>");        out.close();     } 

Caching Information

An agent typically accesses services across the Internet. The performance associated with pulling information across the Internet varies from location to location and with the time of day. It may take 10 seconds or longer each time an agent goes to the Internet to get a specific piece of information but less than a second to get the same information from a local data store. If that same piece of information is requested 100 times, the total time the agent spends retrieving data from the Internet is 1000 seconds. However, if the agent caches the data the first time it retrieves the data, the agent will only spend 10 seconds for the first retrieval and then 1 second for each of the others.

An agent should cache its data when:

  • There is a high probability that the data it retrieves will be used again.

  • The data will not have aged before it is needed again. If the data changes rapidly then the data in the cache could be invalid.

  • There is a large difference between the time it takes to retrieve the data from its source location and the time it takes to get the data from the cache.

  • The data cannot be generated as quickly as it can be retrieved from the cache.

We also need to manage how much data is cached at any one time. The cost of the cache storage must not be out of proportion to the performance savings that the cache represents. For example, we might have an agent that finds and returns MP3 files. We might discover that 20 or so MP3 files are the most requested at any point in time. Maybe as much as 80% of the traffic to your agent is for those 20 files. Caching just those 20 files represents a storage tradeoff. We could cache everything that is asked for, but eventually we would have to start removing things from our cache because we would physically run out of storage space. What is sought is a trade-off between how much data is stored in the cache versus how frequently the data is used.

Next, we'll implement a simple cache for our Exchange Rate agent.

An Example Caching Agent

The source code for CacheServlet follows:

    import java.io.*;    import java.net.*;    import java.util.*;    import javax.servlet.*;    import javax.servlet.http.*;    public class CacheServlet extends HttpServlet { 

The doPost() method calls a static member component from the ExchangeRateCache class. The country is passed either as a parameter or from a form:

      public void doPost (HttpServletRequest request,                          HttpServletResponse response)          throws ServletException, IOException {        PrintWriter out = response.getWriter();        out.println("<html>");        out.println("<head>");        out.println("</head>");        out.println("<body>");        out.println("Exchange rate for Japan is: " +                    ExchangeRateCache.getExchangeRate("JP") + " Yen/Dollar");        out.println("</body>");        out.println("</html>");        out.close();      }    } 

The source code for the ExchangeRateCache class is shown next:

    import java.io.*;    import java.net.*;    import java.util.*;    import org.apache.soap.*;    import org.apache.soap.rpc.*;    public class ExchangeRateCache { 

The Hastable rate_table serves as the cache for previously retrieved exchange rates:

      private static Hashtable rate_table = new Hashtable(6); 

When we just need to get values from the cache, there is no need to synchronize access since the table is not being modified. This method first checks the cache and if the rate is found it immediately returns it. If not, it then invokes the synchronized method callExchangeRateService():

      public static String getExchangeRate(String country) {        String rateString = (String)rate_table.get(country);        if(rateString != null) {          return rateString + " (old)";        } else {          return callExchangeRateService(country);        }      } 

The callExchangeRateService() method also checks the cache first. The reason for this is that the previous caller might have put the value into the cache while the current caller was waiting for synchronization. There is no need to make two costly network calls if the value was already cached by the first caller. The rest of the method was implemented in SoapClientServlet:

      public static synchronized String callExchangeRateService(String country)      {        String rateString = (String)rate_table.get(country);        if(rateString != null) {          return rateString + " (got)";        }        try {          URL url = new URL("http://localhost:8088/soap/servlet/rpcrouter");          String encodingStyleURI = Constants.NS_URI_SOAP_ENC;          URLConnection connection = url.openConnection();          // Build the call.          Call call = new Call ();          call.setTargetObjectURI("urn:SoapExchangeRate");          call.setMethodName("getExchangeRate");          Vector params = new Vector ();          call.setEncodingStyleURI(encodingStyleURI);          params.addElement(new Parameter("country", String.class,                                          country, null));          call.setParams(params);          Response resp = call.invoke (url, "");          if (resp.generatedFault()) {            Fault fault = resp.getFault();            rateString = fault.getFaultString ();          } else {            Parameter result = resp.getReturnValue ();            rateString = ((Double)result.getValue()).toString();            rate_table.put(country, rateString);            return rateString + " (new)";            }          } catch(Exception e) {            rateString = e.getMessage();          }          return rateString;        }      } 

This is provided as a simple example of caching. In this case the cache is only cleared when the servlet container is reset. A more robust caching application would need to make provision for aging and expire cached values and would provide methods to invalidate cache entries or the entire cache. We could also pre-fill cache entries. For example if we knew that certain countries were always going to be hit, we could initialize those entries in the rate_table in the servlets init() method.

Once the servlet has been compiled and deployed, it can be accessed at http://localhost:8080/webservices/servlet/CacheServlet. The initial response will be:

click to expand

Later responses will show that the data was retrieved from the cache:

click to expand

If you have TcpTunnelGui running you will observe that the first time a request is made a SOAP service request is also made. For subsequent requests the SOAP service request is never made because the value is already in the cache.



 < Free Open Study > 



Professional Java Servlets 2.3
Professional Java Servlets 2.3
ISBN: 186100561X
EAN: 2147483647
Year: 2006
Pages: 130

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net