Maven by Example

7.4. The Simple Weather Module

The next module we’re going to examine could be considered something of a “service.” The Simple Weather module is the module that contains all of the logic necessary to retrieve and parse the data from the Yahoo! Weather RSS feed. Although Simple Weather contains three Java classes and one JUnit test, it is going to present a single component, WeatherService, to both the Simple Web Application and the Simple Command-line Utility. Very often an enterprise project will contain several API modules that contain critical business logic or logic that interacts with external systems. A banking system might have a module that retrieves and parses data from a third-party data provider, and a system to display sports scores might interact with an XML feed that presents real-time scores for basketball or soccer. In simple-weather Module POM, this module encapsulates all of the network activity and XML parsing that is involved in the interaction with Yahoo! Weather. Other modules can depend on this module and simply call out to the <methodname role="keep-together">retrieveForecast()+ method on WeatherService, which takes a zip code as an argument and which returns a Weather object.

simple-weather Module POM. 

<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
                             http://maven.apache.org/maven-v4_0_0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.sonatype.mavenbook.multispring</groupId>
        <artifactId>simple-parent</artifactId>
        <version>1.0</version>
    </parent>
    <artifactId>simple-weather</artifactId>
    <packaging>jar</packaging>

    <name>Simple Weather API</name>

    <dependencies>
        <dependency>
            <groupId>org.sonatype.mavenbook.multispring</groupId>
            <artifactId>simple-model</artifactId>
            <version>1.0</version>
        </dependency>
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.14</version>
        </dependency>
        <dependency>
            <groupId>dom4j</groupId>
            <artifactId>dom4j</artifactId>
            <version>1.6.1</version>
        </dependency>
        <dependency>
            <groupId>jaxen</groupId>
            <artifactId>jaxen</artifactId>
            <version>1.1.1</version>
        </dependency>
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-io</artifactId>
            <version>1.3.2</version>
            <scope>test</scope>
        </dependency>
    </dependencies>
</project>

The simple-weather POM extends the simple-parent POM, sets the packaging to jar, and then adds the following dependencies:

org.sonatype.mavenbook.multispring:simple-model:1.0
simple-weather parses the Yahoo! Weather RSS feed into a Weather object. It has a direct dependency on simple-model.
log4j:log4j:1.2.14
simple-weather uses the Log4J library to print log messages.
dom4j:dom4j:1.6.1 and jaxen:jaxen:1.1.1
Both of these dependencies are used to parse the XML returned from Yahoo! Weather.
org.apache.commons:commons-io:1.3.2 (scope=test)
This test-scoped dependency is used by the YahooParserTest.

Next is the WeatherService class, shown in WeatherService Class. This class is going to look very similar to the WeatherService class from The WeatherService Class. Although the WeatherService is the same, there are some subtle differences in this chapter’s example. This version’s retrieveForecast() method returns a Weather object, and the formatting is going to be left to the applications that call WeatherService. The other major change is that the YahooRetriever and YahooParser are both bean properties of the WeatherService bean.

WeatherService Class. 

package org.sonatype.mavenbook.weather;

import java.io.InputStream;

import org.sonatype.mavenbook.weather.model.Weather;

public class WeatherService {

    private YahooRetriever yahooRetriever;
    private YahooParser yahooParser;

    public WeatherService() {
    }

    public Weather retrieveForecast(String zip) throws Exception {
        // Retrieve Data
        InputStream dataIn = yahooRetriever.retrieve(zip);

        // Parse DataS
        Weather weather = yahooParser.parse(zip, dataIn);

        return weather;
    }

    public YahooRetriever getYahooRetriever() {
        return yahooRetriever;
    }

    public void setYahooRetriever(YahooRetriever yahooRetriever) {
        this.yahooRetriever = yahooRetriever;
    }

    public YahooParser getYahooParser() {
        return yahooParser;
    }

    public void setYahooParser(YahooParser yahooParser) {
        this.yahooParser = yahooParser;
    }

}

Finally, in this project we have an XML file that is used by the Spring Framework to create something called an ApplicationContext. First, some explanation: both of our applications, the web application and the command-line utility, need to interact with the WeatherService class, and they both do so by retrieving an instance of this class from a Spring ApplicationContext using the name weatherService. Our web application uses a Spring MVC controller that is associated with an instance of WeatherService, and our command-line utility loads the WeatherService from an ApplicationContext in a static main() function. To encourage reuse, we’ve included an applicationContext-weather.xml file in src/main/resources, which is available on the classpath. Modules that depend on the simple-weather module can load this application context using the ClasspathXmlApplicationContext in the Spring Framework. They can then reference a named instance of the WeatherService named weatherService.

Spring Application Context for the simple-weather Module. 

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
                           http://www.springframework.org/schema/beans/spring-beans-2.0.xsd"
       default-lazy-init="true">

    <bean id="weatherService"
          class="org.sonatype.mavenbook.weather.WeatherService">
        <property name="yahooRetriever" ref="yahooRetriever"/>
        <property name="yahooParser" ref="yahooParser"/>
    </bean>

    <bean id="yahooRetriever"
          class="org.sonatype.mavenbook.weather.YahooRetriever"/>

    <bean id="yahooParser"
          class="org.sonatype.mavenbook.weather.YahooParser"/>
</beans>

This document defines three beans: yahooParser, yahooRetriever, and weatherService. The weatherService bean is an instance of WeatherService, and this XML document populates the yahooParser and yahooRetriever properties with references to the named instances of the corresponding classes. Think of this applicationContext-weather.xml file as defining the architecture of a subsystem in this multi-module project. Projects like simple-webapp and simple-command can reference this context and retrieve an instance of WeatherService which already has relationships to instances of YahooRetriever and YahooParser.