Maven by Example
7.8. The Simple Command Module

The simple-command project is a command-line version of the
simple-webapp. It is a utility that relies on the same dependencies:
simple-persist and simple-weather. Instead of interacting with
this application via a web browser, you would run the simple-command
utility from the command-line.
POM for simple-command.
<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-command</artifactId>
<packaging>jar</packaging>
<name>Simple Command Line Tool</name>
<build>
<finalName>${project.artifactId}</finalName>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.5</source>
<target>1.5</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<testFailureIgnore>true</testFailureIgnore>
</configuration>
</plugin>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>hibernate3-maven-plugin</artifactId>
<version>2.1</version>
<configuration>
<components>
<component>
<name>hbm2ddl</name>
<implementation>annotationconfiguration</implementation>
</component>
</components>
</configuration>
<dependencies>
<dependency>
<groupId>hsqldb</groupId>
<artifactId>hsqldb</artifactId>
<version>1.8.0.7</version>
</dependency>
</dependencies>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>org.sonatype.mavenbook.multispring</groupId>
<artifactId>simple-weather</artifactId>
<version>1.0</version>
</dependency>
<dependency>
<groupId>org.sonatype.mavenbook.multispring</groupId>
<artifactId>simple-persist</artifactId>
<version>1.0</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring</artifactId>
<version>2.0.7</version>
</dependency>
<dependency>
<groupId>hsqldb</groupId>
<artifactId>hsqldb</artifactId>
<version>1.8.0.7</version>
</dependency>
</dependencies>
</project>
This POM creates a JAR file which will contain the
org.sonatype.mavenbook.weather.Main class shown in
The Main Class for simple-command. In this POM we configure the Maven
Assembly plugin to use a built-in assembly descriptor named
jar-with-dependencies which creates a single JAR file containing all
the bytecode a project needs to execute including the bytecode from
the project you are building and all the bytecode from libraries your
project depends upons.
The Main Class for simple-command.
package org.sonatype.mavenbook.weather;
import java.util.List;
import org.apache.log4j.PropertyConfigurator;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.sonatype.mavenbook.weather.model.Location;
import org.sonatype.mavenbook.weather.model.Weather;
import org.sonatype.mavenbook.weather.persist.LocationDAO;
import org.sonatype.mavenbook.weather.persist.WeatherDAO;
public class Main {
private WeatherService weatherService;
private WeatherDAO weatherDAO;
private LocationDAO locationDAO;
public static void main(String[] args) throws Exception {
// Configure Log4J
PropertyConfigurator.configure(Main.class.getClassLoader().getResource(
"log4j.properties"));
// Read the Zip Code from the Command-line (if none supplied, use 60202)
String zipcode = "60202";
try {
zipcode = args[0];
} catch (Exception e) {
}
// Read the Operation from the Command-line (if none supplied use weather)
String operation = "weather";
try {
operation = args[1];
} catch (Exception e) {
}
// Start the program
Main main = new Main(zipcode);
ApplicationContext context =
new ClassPathXmlApplicationContext(
new String[] { "classpath:applicationContext-weather.xml",
"classpath:applicationContext-persist.xml" });
main.weatherService = (WeatherService) context.getBean("weatherService");
main.locationDAO = (LocationDAO) context.getBean("locationDAO");
main.weatherDAO = (WeatherDAO) context.getBean("weatherDAO");
if( operation.equals("weather")) {
main.getWeather();
} else {
main.getHistory();
}
}
private String zip;
public Main(String zip) {
this.zip = zip;
}
public void getWeather() throws Exception {
Weather weather = weatherService.retrieveForecast(zip);
weatherDAO.save( weather );
System.out.print(new WeatherFormatter().formatWeather(weather));
}
public void getHistory() throws Exception {
Location location = locationDAO.findByZip(zip);
List<Weather> weathers = weatherDAO.recentForLocation(location);
System.out.print(new WeatherFormatter().formatHistory(location, weathers));
}
}
The Main class has a reference to WeatherDAO, LocationDAO, and
WeatherService. The static main() method in this class:
- Reads the Zip Code from the first command line argument
- Reads the Operation from the second command line argument. If the operation is "weather", the latest weather will be retrieved from the web service. If the operation is "history", the program will fetch historical weather records from the local database.
-
Loads a Spring
ApplicationContextusing two XML files loaded fromsimple-persistandsimple-weather -
Creates an instance of
Main -
Populates the
weatherService,weatherDAO, andlocationDAOwith beans from the SpringApplicationContext -
Runs the appropriate method
getWeather()orgetHistory()depending on the specified operation.
In the web application we use Spring VelocityViewResolver to render
a Velocity template. In the stand-alone implementation, we need to
write a simple class which renders our weather data with a Velocity
template. WeatherFormatter Renders Weather Data using a Velocity Template is a listing of the
WeatherFormatter, a class with two methods that render the weather
report and the weather history.
WeatherFormatter Renders Weather Data using a Velocity Template.
package org.sonatype.mavenbook.weather;
import java.io.InputStreamReader;
import java.io.Reader;
import java.io.StringWriter;
import java.util.List;
import org.apache.log4j.Logger;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.Velocity;
import org.sonatype.mavenbook.weather.model.Location;
import org.sonatype.mavenbook.weather.model.Weather;
public class WeatherFormatter {
private static Logger log = Logger.getLogger(WeatherFormatter.class);
public String formatWeather( Weather weather ) throws Exception {
log.info( "Formatting Weather Data" );
Reader reader =
new InputStreamReader( getClass().getClassLoader().
getResourceAsStream("weather.vm"));
VelocityContext context = new VelocityContext();
context.put("weather", weather );
StringWriter writer = new StringWriter();
Velocity.evaluate(context, writer, "", reader);
return writer.toString();
}
public String formatHistory( Location location, List<Weather> weathers )
throws Exception {
log.info( "Formatting History Data" );
Reader reader =
new InputStreamReader( getClass().getClassLoader().
getResourceAsStream("history.vm"));
VelocityContext context = new VelocityContext();
context.put("location", location );
context.put("weathers", weathers );
StringWriter writer = new StringWriter();
Velocity.evaluate(context, writer, "", reader);
return writer.toString();
}
}
The weather.vm template simply prints the zip code’s city, country, and region as well as the current temperature. The history.vm template prints the location and then iterates through the weather forecast records stored in the local database. Both of these templates are in ${basedir}/src/main/resources.
The weather.vm Velocity Template.
****************************************
Current Weather Conditions for:
${weather.location.city},
${weather.location.region},
${weather.location.country}
****************************************
* Temperature: ${weather.condition.temp}
* Condition: ${weather.condition.text}
* Humidity: ${weather.atmosphere.humidity}
* Wind Chill: ${weather.wind.chill}
* Date: ${weather.date}
The history.vm Velocity Template.
Weather History for:
${location.city},
${location.region},
${location.country}
#foreach( $weather in $weathers )
****************************************
* Temperature: $weather.condition.temp
* Condition: $weather.condition.text
* Humidity: $weather.atmosphere.humidity
* Wind Chill: $weather.wind.chill
* Date: $weather.date
#end
