Source code for accessing weather.com XML data feed from Java

Posted January 2nd, 2007 by

Table of contents
Overview
How to use the source code
Getting a Partner Id and License Key
Download source code, etc.
Dependencies

Overview – easy access to weather data from Java

If you’ve ever wanted to access weather reports from your desktop applications, widgets, or web applications, I’ve got some source code that will make it easier than ever to access this weather data from a Java API. There are a couple of ways to get access to weather data:

  • You can access weather.com’s XML data feed (version 2.0). By passing some key-value pairs to this service, using HTTP GET, you can get a set of XML documents that contain the reponse to your query. You have to pass the location and the kind of weather forecast data that you want to this service, and it will give you back an XML document. There’s also a service that allows you to lookup location Ids for addresses. Weather.com provides a DTD and user guide to help you parse the response from the service, and create requests, etc. It’s simple, but tedious to make the queries and parse the response; it would be much easier if a set of Java classes are provided.
  • NOAA also provides a SOAP based web service that will give you detailed weather data, and it’s free for use by the public – our tax dollars are funding it :). However, you have to use SOAP and XSDs, and if you are comfortable with web services then it will give you what you need.

In this article, I will provide an overview of the source code that I’ve written to allow you to parse this weather information in Java. I’ve provided some classes that allow you to very easily query the weather.com XML data feed for current weather information that’s transformed into a set of Javabeans that contain weather forecast information that you requested.

How to use the source code

The classes that are provided allow you to get weather information by simply using a WeatherGateway class and invoking methods on it to:

  • Given a city name, resolve it to a weather.com location Id (zip codes in the US can be used as location Ids). A city name can resolve to more than one location Id, and if this is the case, a list of location Ids is provided to you to choose from (in a SearchLocations Javabean class).
  • Given a location Id, you can look up the weather for this location. You can choose to get current conditions, or detailed forecast reports for days to come, you can configure all this by calling different methods and passing different parameters. The response is a WeatherReport Javabean class that holds all the weather data that you asked for.
  • To see how to use the code, a sample class called TestWeatherGateway is provided, which allows you to test all the various methods that are available and see what the response is. Download the code and run this class and see the output on your command prompt/console, and it you will see the structure of this bean. You can get more details on it by reading the weather.com Guide on their XML data structure (which you can download once you sign up with them, instructions provided in the next section)
  • To make your life easy, all the error codes generated by the weather.com service are also parsed and thrown as Exceptions (WeatherError exception class) when you use the WeatherGateway class. All the weather.com errors are encapsulated in WeatherError.ErrorTypes, and any networking issues are reported as an IOException.
  • Also, the WeatherGateway class caches the responses of URIs that weather.com responded to without any errors, as weather.com has some guidelines around how often you should query these services. You can read more about this in the Weather.com XML data feed guide, once you sign up on their website (instructions are provided in the next section).
 1: package weather_service;
 2:
 3: import weather_service.weatherprovider.DefaultWeatherConfigurationBean;
 4: import weather_service.weatherprovider.WeatherConfigurationIF;
 5: import weather_service.weatherprovider.WeatherError;
 6: import weather_service.weatherprovider.WeatherGateway;
 7: import weather_service.weatherprovider.locationdatamodel.SearchLocations;
 8: import weather_service.weatherprovider.weatherdatamodel.WeatherReport;
 9:
 10: import java.io.IOException;
 11:
 12: /**
 13: * This class tests all the functionality provided by the WeatherGateway class
 14: */
 15: public class TestWeatherGateway {
 16:
 17: public static String partnerID = "";
 18: public static String licenseKey = "";
 19:
 20: public static void main(String[] args) {
 21: TestWeatherGateway gateway = new TestWeatherGateway();
 22:
 23: //:::::::::::::::::::::::::::::::::::::::::::::::
 24: // testing "search" service
 25: //:::::::::::::::::::::::::::::::::::::::::::::::
 26: System.out.println("\n:: looking up location '' :: should throw WeatherError exception");
 27: gateway.testSearchService("");
 28:
 29: System.out.println("\n:: looking up location 20166 :: should work ok");
 30: gateway.testSearchService("20166");
 31:
 32: System.out.println("\n:: looking up location 20166x :: should work ok, and return empty SearchLocations");
 33: gateway.testSearchService("20166x");
 34:
 35: System.out.println("\n:: looking up location amsterdam :: should work ok, and return multiple SearchLocations");
 36: gateway.testSearchService("amsterdam");
 37:
 38: System.out.println("\n:: looking up location amsterdam :: should work ok, and return multiple SearchLocations");
 39: gateway.testSearchService("la jolla ");
 40:
 41: //:::::::::::::::::::::::::::::::::::::::::::::::
 42: // testing "local" service
 43: //:::::::::::::::::::::::::::::::::::::::::::::::
 44: System.out.println("\n:: checking 20166x weather :: WeatherError exception should be thrown");
 45: gateway.testLocalService("20166x", DefaultWeatherConfigurationBean.defaultWeatherServer);
 46:
 47: System.out.println("\n:: checking 20166 weather :: should work ok ");
 48: gateway.testLocalService("20166", DefaultWeatherConfigurationBean.defaultWeatherServer);
 49:
 50: System.out.println("\n:: checking BGXX0014 weather :: should work ok");
 51: gateway.testLocalService("BGXX0014", DefaultWeatherConfigurationBean.defaultWeatherServer);
 52:
 53: System.out.println("\n:: checking \"\" weather :: WeatherError exception should be thrown");
 54: gateway.testLocalService("", DefaultWeatherConfigurationBean.defaultWeatherServer);
 55:
 56: System.out.println("\n:: checking invalid locationID weather :: WeatherError exception should be thrown");
 57: gateway.testLocalService("asdfadf", DefaultWeatherConfigurationBean.defaultWeatherServer);
 58:
 59: System.out.println("\n:: checking invalid server weather :: IOException should be thrown ");
 60: gateway.testLocalService("asdfadf", "http://afdjalkfjefi");
 61: }
 62:
 63: public void testSearchService( String where ){
 64: WeatherGateway gateway = WeatherGateway.getDefaultInstance();
 65:
 66: try {
 67: SearchLocations locations = gateway.searchForLocations( where );
 68:
 69: System.out.printf(":::: SearchLocations ::::\n%s\n::::\n", locations);
 70:
 71: } catch (WeatherError e) {
 72: System.out.printf("---- Exception reported from parsing weather/response, %s ----\n", e);
 73: } catch (IOException e) {
 74: System.out.printf("---- Network connection problem or invalid server address, %s ----\n", e);
 75: }
 76: }
 77:
 78: public void testLocalService(String locationID, String weatherServer) {
 79: WeatherConfigurationIF config = new DefaultWeatherConfigurationBean(
 80: weatherServer, partnerID, licenseKey);
 81: WeatherGateway gateway = new WeatherGateway(config);
 82:
 83: // multiple calls to exercise the cache
 84: for (int i = 0; i < 1; ++i) {
 85: try {
 86:
 87: WeatherReport weather = gateway.getFullForecast(locationID, 3);
 88:
 89: System.out.printf(":::: WeatherReport ::::\n%s\n::::\n", weather);
 90:
 91: } catch (IOException e) {
 92: System.out.printf("---- Network connection problem or invalid server address, %s ----\n", e);
 93: return;
 94: } catch (WeatherError e){
 95: System.out.printf("---- Exception reported from parsing weather/response, %s ----\n", e);
 96: return;
 97: }
 98: }
 99: }
 100:
 101: }//end class TestWeatherGateway

Getting a License Key and Partner Id from weather.com

Weather.com requires that you sign up with them to use this service. Once you sign up at: http://www.weather.com/services/xmloap.html, you will get an SDK that explains the XML data format that they use and the HTTP GET query string/URI that they use. They will also give you PNG files that are icons for the different weather conditions that are reported. They also require that you use the License Key and Partner Id that they give you to make HTTP GET calls to their service. The code that I provide allows you to specify this License Key and Partner Id (however, for testing puposes, you can run the code as is, while you are waiting for weather.com to email you the SDK + license key + partner id, once you sign up).

Downloading source code and classes

The source code and classes are available for download here: weather_service.jar. Feel free to use the code as you see fit, and modify it to your heart’s content. If you want to use this code in environments where there will be lots of multithreaded access to it, then you should make WeatherGateway threadsafe (the WeatheReport cache, and access to HttpClient) – but this is left as an exercise for the reader. You can also implement multithreaded connection handler for HttpClient, and further improve multithreaded access to the gateway (don’t forget to call shutdown on the connection handler when you are ready to destroy the object) – again left as an exercise for the reader.

Dependencies

There are quite a few dependencies that the source code has on a variety of open source projects:

  • JDOM – this is the XML parser used to parse the XML document from weather.com.
  • Jakarta Commons Lang – ToStringBuilder is used to generate toString() methods for all the beans.
  • Jakarta Commons HttpClient – HttpClient is used to actually perform the HTTP communications with weather.com
  • Jakarta Commons Codec – Base64 encoder is used to encode the key-value pairs sent to the HTTP GET methods on weather.com
  • Jakarta Commons Logging – this is used to generate some debug messages in the code
  • Jakarta Commons IO – needed by some of the other Jakarta Commons modules.

Don’t worry, the weather_service.jar file has all these dependencies included under the lib/ folder. I haven’t included the weather.com SDK (manual and PNG icons) since the license requires that you get it from weather.com directly. Here is a link to the DTD of the XML document that’s sent back from weather.com – refer to the manual to get more details.

Enjoy!


Comments are closed.