< Day Day Up > |
Hack 53 Check the Weather
Check the up-to-the-minute weather with an IRC bot that capitalizes on Web Services—a powerful way of getting current information. The exchange of information on the Web primarily takes place through the loading of web pages. Databases and applications can be used to provide dynamic information, but the result has typically been available only embedded in an HTML document. Web Services were created to better facilitate the exchange of information by providing more direct access to applications and their functions over the Web. Web Services have URLs, and by sending a message to the URL of a service, a user or application can directly call a function offered by the application providing the service. One example shown in this hack is to use a U.S. zip code to get the current temperature at that location. To do this using a Web Service, a message is sent to the service to tell it which zip code to look up. The service processes the request and sends back the current temperature at that location. When writing IRC bots, a lot of time is often spent developing the services a bot will offer. It is not uncommon for the author to have to write a lot of code to look up the weather, parse a web page to extract the actual data, and then format that into an IRC message. Using a Web Service to retrieve the same information requires only a few lines of code. The XMethods web site at http://www.xmethods.net lists many publicly available Web Services and describes how they are used. In this example, you will use the weather-temperature service listed in the XMethods Demo Services section of the homepage. This service is passed a U.S. zip code and returns the current temperature at that zip code. To write code that uses a Web Service, you need several pieces of information about the service. The first is the URL of the WSDL description of the service. WSDL (Web Service Description Language) is an XML standard used for describing services, the arguments they take, the format of those arguments, and what value is returned. Services listed on XMethods show the WSDL URL on each page. Figure 8-2 has the URL boxed to show where it is found. The XMethods weather-temperature WSDL description is at http://www.xmethods.net/sd/2001/TemperatureService.wsdl. Figure 8-2. The XMethods page describing a Web ServiceTo use the service, you will also need the name of the operation and the arguments for it. An operation is very much like a function call. To get the operation information, the WSDL for the service needs to be analyzed. You can do this by hand, but XMethods can automatically perform the analysis. The link to analyze the WSDL is shown circled in Figure 8-2. Figure 8-3 shows the WSDL analysis for the weather-temperature service. It shows that one operation is available for the service. By clicking the link to the operation, shown in the box in Figure 8-3, a full description of the operation is returned. Figure 8-3. An analysis of the WSDL for the weather-temperature serviceOn the operation description page, shown in Figure 8-4, the name of the operation is provided in the boxed area. This operation name is necessary to run the service. The operation name for the weather-temperature service is getTemp. Figure 8-4. The description of the single operation that is part of the weather-temperature serviceFinally, to use the operation, an input message that contains the arguments needs to be passed. To see the number and type of arguments, click the InputMsg link for the operation, shown in the circled area in Figure 8-4. Figure 8-5 shows the description of the input message that will contain the arguments for the operation. These are listed as Parts and, as shown in Figure 8-5, there is one part to the weather-temperature service. The name of this part is zipcode, and it is passed in as a string. Figure 8-5. The Input Message format information, provided by the XMethods siteIn this example, the zipcode is the only part of the input message. Other services will have several parts. For example, a currency conversion service (also provided by XMethods), will require the name of the country whose currency you want to convert and the name of the country that you want to convert to. When there are multiple parts to an input message, they must be kept in order. Returning to the screen shown in Figure 8-4, you will also see information about the output message. Following that link, you will see that the output has one part named return. The name of this part will also be needed later on. After reviewing the pages on XMethods, you will now have the following information about the weather-temperature service:
To use the getTemp operation and get a result back, you need to invoke the service. Instead of writing lots of networking and parsing code by hand, you can use the Apache Axis package for Web Services. Axis is a Java base for implementing Web Services. A full description of the application is at http://ws.apache.org/axis, and it can be downloaded from http://ws.apache.org/axis/download.cgi. Download the ZIP file of the binaries, and unzip the archive. The lib directory will contain several JAR files that you should add to your classpath. In the samples/client directory, the DynamicInvoker provides a simple framework for invoking Web Services. You should import samples.client.DynamicInvoker into your Java file. The Java class you will write will contain one static function (getTemperature) that will take a zip code as an argument, and return a String with the current temperature. import java.util.*; import samples.client.DynamicInvoker; public class WeatherService { public static String getTemperature(String zipcode) { // To do... } } Now, you need to take the information about the service and create variables to store them in. In addition to the WSDL location and the operation name, the DynamicInvoker requires a port name. This service does not require you to specify a port name, so you can use a null value there. static String wsdlLocation = "http://www.xmethods.net/sd/2001/TemperatureService.wsdl"; static String operationName= "getTemp"; static String outputName = "return"; static String portName = null; The final step before invoking the service is to create an argument list. Arguments are passed to the DynamicInvoker in a String array. The first value is the WSDL location, the second value is the operation name, and the subsequent values are the parts of the input message, listed in order. In our case, the only part of the input message is the zip code value, so it will be the third value in the String array, for example: String[] args = new String[] {wsdlLocation, operationName, "20742"}; With this information set up, invoking the function to get the result from the service requires only a few lines of code. The invoker is constructed, the method is invoked, and the result is retrieved. 8.4.1 The CodeThe final version of WeatherService.java looks like this: import java.util.*; import samples.client.DynamicInvoker; public class WeatherService { String wsdlLocation = "http://www.xmethods.net/sd/2001/TemperatureService.wsdl"; String operationName= "getTemp"; String outputName = "return"; String portName = null; public static String getTemperature(String zipcode) { String[] args = new String[] {wsdlLocation, operationName, zipcode}; try { DynamicInvoker invoker=new DynamicInvoker(wsdlLocation); HashMap map = invoker.invokeMethod(operationName, portName, args); return map.get(outputName).toString( ); }catch (Exception e){return null;} } } You now have a working piece of code to invoke a weather service. You can write a main method to call the getTemperature method and test it. The next step is to create a bot that will call this method with some user input. Since this is Java-based code, it will use the PircBot API [Hack #35] . You can assume that the onMessage method is overridden to accept input from users in a channel—we recommend that you add this to one of your existing PircBot-based bots, such as that presented in [Hack #35] . The rest of this step will just show how to handle requests from users in this context. The bot will allow user input that comes in the following format: WSBot, temperature 90210 You can use a StringTokenizer to parse the input. The getTemperature method will get called, and then the result will be sent to the channel. The following bit of code is placed inside the onMessage method: if (t.nextToken( ).toLowerCase( ).equals(getName( ).toLowerCase( ) + ",")) { try { String query = t.nextToken( ); if (query.equals("weather")) { String response = ""; String zip = t.nextToken( ); if (!zip.equals("")){ sendMessage(channel, "Just a moment while I look that up..."); String result = WeatherService.getTemperature(zip); response = "The temperature at " + zip + " is " + result + "."; } else { response = "Please enter a valid zip code."; } sendMessage(channel, response); } ... 8.4.2 Running the HackCompiling the bot is a bit more complicated than usual, as you will need to ensure that you have all of the Axis components in your classpath: % javac -classpath .:pircbot.jar: axis-1_1/lib/axis.jar:axis-1_1/lib/axis-ant.jar: axis-1_1/lib/commons-discovery.jar:axis-1_1/lib/commons-logging.jar: axis-1_1/lib/jaxrpc.jar:axis-1_1/lib/log4j-1.2.8.jar:axis-1_1/lib/saaj.jar: axis-1_1/lib/wsdl4j.jar *.java We recommended that you integrate this hack into one of your existing PircBot implementations. Depending on the name of your main class, you can then run the bot like so: % java -classpath .:pircbot.jar:axis-1_1/lib/axis.jar: axis-1_1/lib/axis-ant.jar: axis-1_1/lib/commons-discovery.jar:axis-1_1/lib/commons-logging.jar: axis-1_1/lib/jaxrpc.jar:axis-1_1/lib/log4j-1.2.8.jar:axis-1_1/lib/saaj.jar: axis-1_1/lib/wsdl4j.jar Main Replace Main with the correct name for your main class if it is different. Figure 8-6 shows the bot responding to weather queries on an IRC channel. Figure 8-6. The Web Service bot answering weather queries8.4.3 Hacking the HackWith this framework in place, you can easily add new features to any bot that uses Web Services. Essentially, only the WSDL location, operation name, and input message parts need to be changed. The code for invoking a service and calling the method from the bot interface remains almost identical. Take a gander at the translation Web service used in a similar manner in the next hack. —Jennifer Golbeck |
< Day Day Up > |