Saturday, November 10, 2012

Getting started with Spring Shell

I thought I'd write up a quick getting-started guide for Spring Shell. Spring Shell is the new Spring portfolio project that helps you in building easy to use command line interfaces for whatever commands you provide. Commands can really be anything. For instance, on most projects the developers end up writing a bunch of tools and utilities automating tedious tasks such as setting up a database schema, scanning through log files or doing some code generation. All of these would be perfect examples for what a Spring Shell command can be. Using Spring Shell to house all of your tooling and utility commands in a coherent shell makes them self documenting and easier to use for other developers on the team.

Let's setup a trivial Spring Shell application to get started. In follow-up posts I'll cover more advanced Spring Shell functionality. I'll be using Maven in this example because I think that's what most people are familiar with (Spring Shell itself is built with Gradle).

Here's the POM for the spring-shell-demo project (available on GitHub):

<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>
 <groupId>com.ervacon</groupId>
 <artifactId>spring-shell-demo</artifactId>
 <packaging>jar</packaging>
 <version>1.0-SNAPSHOT</version>
 <name>Spring Shell Demo</name>

 <properties>
  <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
 </properties>

 <repositories>
  <!-- see https://jira.springsource.org/browse/SHL-52 -->
  <repository>
   <id>ext-release-local</id>
   <url>http://repo.springsource.org/simple/ext-release-local/</url>
  </repository>
 </repositories>

 <dependencyManagement>
  <dependencies>
   <dependency>
    <groupId>org.springframework.shell</groupId>
    <artifactId>spring-shell</artifactId>
    <version>1.0.0.RELEASE</version>
   </dependency>
  </dependencies>
 </dependencyManagement>
 
 <dependencies>
  <dependency>
   <groupId>org.springframework.shell</groupId>
   <artifactId>spring-shell</artifactId>
  </dependency>
 </dependencies>
 
 <build>
  <plugins>
   <!-- copy all dependencies into a lib/ directory -->
   <plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-dependency-plugin</artifactId>
    <version>2.1</version>
    <executions>
     <execution>
      <id>copy-dependencies</id>
      <phase>prepare-package</phase>
      <goals>
       <goal>copy-dependencies</goal>
      </goals>
      <configuration>
       <outputDirectory>${project.build.directory}/lib</outputDirectory>
       <overWriteReleases>true</overWriteReleases>
       <overWriteSnapshots>true</overWriteSnapshots>
       <overWriteIfNewer>true</overWriteIfNewer>
      </configuration>
     </execution>
    </executions>
   </plugin>
   
   <!-- make the jar executable by adding a Main-Class and Class-Path to the manifest -->
   <plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-jar-plugin</artifactId>
    <version>2.3.1</version>
    <configuration>
     <archive>
      <manifest>
       <addClasspath>true</addClasspath>
       <classpathPrefix>lib/</classpathPrefix>
       <mainClass>org.springframework.shell.Bootstrap</mainClass>
      </manifest>
     </archive>
    </configuration>
   </plugin>
  </plugins>
 </build>

</project>

There's quite a bit going on in this POM. First thing to note is the declaration of the ext-release-local SpringSource repository. This is needed to be able to resolve one of Spring Shell's dependencies: JLine (check SHL-52 for more background info). Hopefully this will no longer be necessary in future versions of Spring Shell. Next there's a dependency on Spring Shell itself. No surprise there. Finally, the POM customizes the build by copying all dependencies into a lib/ directory and adding a Main-Class and Class-Path property to the manifest of the generated jar file. Doing this produces the following directory structure in your target folder:

target/
 spring-shell-demo-1.0-SNAPSHOT.jar
 lib/
  all dependencies
You can simply package this up and distribute your shell. It will be fully self-contained and launching it is trivial:
java -jar spring-shell-demo-1.0-SNAPSHOT.jar

Hold on there, we're getting ahead of ourselves. Before launching the shell let's first add an echo command that just prints its input text back out to the console. Here's the code, which lives in the com.ervacon.ssd package:

@Component
public class DemoCommands implements CommandMarker {

 @CliCommand(value = "echo", help = "Echo a message")
 public String echo(
   @CliOption(key = { "", "msg" }, mandatory = true, help= "The message to echo") String msg) {
  return msg;
 }
}

As you can see, a Spring Shell command is just a @CliCommand annotated method on a Java class tagged with the CommandMarker interface. Our echo method takes a single argument which will be a mandatory @CliOption for the command. By using both the empty string and msg as keys for the option, you'll be able to invoke the command both as echo test and echo --msg test. The method simply returns the message: Spring Shell will make sure it gets printed to the console.

Alright, we've got our command implemented! We still have to tell Spring Shell about it. Since Spring Shell is Spring based, adding a command simply means defining a Spring bean. On start up, Spring Shell will automatically load the application context defined in classpath:/META-INF/spring/spring-shell-plugin.xml. You typically setup component scanning and simply mark your command classes as @Components, making development of new commands trivial since the shell will automatically detect them. Here's the application context definition:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xmlns:context="http://www.springframework.org/schema/context"
 xsi:schemaLocation="
  http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
  http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd">

 <context:component-scan base-package="com.ervacon.ssd" />

</beans>

And that's it! We're ready to build and launch our shell:

mvn package
java -jar target/spring-shell-demo-1.0-SNAPSHOT.jar

Thursday, October 25, 2012

More mud: SimpleDateFormat and the Gregorian calendar

I spent another few hours wading through mud at work the other day, SimpleDateFormat related mud this time around. You would assume "yyyy/MM/dd HH:mm z" to be a pretty solid date format for representing a timestamp with minute precision:
  • yyyy/MM/dd: the date, e.g. "2012/10/23"
  • HH:mm: the time in 24-hour format, e.g. "18:32"
  • z: the timezone, e.g. "CET"
This date format can be used to store dates in a text file (or any other textual format for that matter, e.g. XML). Let's go one step further and always use UTC as the time zone for the dates stored in our text file. That avoids all confusion when parsing the file again: all dates are expressed in UTC. Here's a bit of code that does what we need: it takes an input Date object and formats it as a UTC date string, it then parses that UTC date again and verifies that the input and output are the same.
Date input = new Date(-62135773200000L); // "0001/01/01 00:00 CET"

SimpleDateFormat utc = new SimpleDateFormat("yyyy/MM/dd HH:mm z");
utc.setTimeZone(TimeZone.getTimeZone("UTC"));

String str = utc.format(input);

Date output = utc.parse(str);

if (input.equals(output)) {
 System.out.println("Equal!");
} else {
 System.out.println(input + " != " + output);
}
For most dates this would print Equal!. However, I used a special date in the code above: midnight on January 1st of the year 1 expressed in CET. The output on my machine is:
Sat Jan 01 00:00:00 CET 1 != Sun Jan 01 00:00:00 CET 2
What!? Year 1 became 2? Let's look at the string produced by the date formatting:
0001/12/31 23:00 UTC
The time becomes 23:00 UTC because CET is one hour ahaid of UTC. To understand why the day jumped to December 31st of the year 1, you have to realize that the Gregorian calendar, on which UTC and CET are based, does not have a year 0. This means the timeline looks like this (BC is Before Christ, AD is Anno Domini, the era indicator in SimpleDateFormat terms):
..., 2 BC, 1 BC, 1 AD, 2 AD, ...

The date formatting assumes January first of the year 1 to be AD. To move from midnight CET to 23:00 UTC, we end up in the previous day: December 31st of the year 1 BC. However, our date format does not encode the era (BC / AD), so when the date is parsed, year 1 is again assumed to be AD, which leads to the rather surprising result that year 1 AD becomes year 2 AD after the UTC to CET time adjustment.

Luckily fixing the problem is easier than understanding it! You simply need to add the era indicator to the date format pattern: "yyyy/MM/dd HH:mm z G", and the above code will work as expected.

PS: This problem popped up during an XStream version upgrade. Check XSTR-556 and XSTR-711 in the XStream JIRA for more information.

Wednesday, January 4, 2012

Spring bean definition profiles and web.xml

Spring 3.1 was released a few weeks ago. One of the interesting new features is the first-class support for bean definition profiles: you can define beans as part of a profile and than activate that profile if required. Bean definitions that are part of a profile that has not been activated are simply skipped.

Last week, I spent a few days upgrading our application to Spring 3.1 and updating it to make use of bean definition profiles. As most other sizable Spring based apps, we had devised our own configuration switching system based on a combination of Maven resource filtering and XML <import/> elements containing ${placeholders}. This works well enough but it would obviously be better to directly use the bean definition profile feature of Spring 3.1, if only because it's better documented.

By default, the list of active bean definition profiles will be determined by looking at a spring.profiles.active property. Out-of-the-box, a Spring WebApplicationContext will setup a PropertySources list containing the servlet config parameters, servlet context parameters, JNDI properties, system properties and environment variables, in that order. This implies that you can define the spring.profiles.active property in any of those locations, the most obvious one being servlet context parameters in web.xml:
<context-param>
 <param-name>spring.profiles.active</param-name>
 <param-value>foo-profile, bar-profile</param-value>
</context-param>
We wanted to use Maven profiles to switch between Spring bean definition profiles, so the initial idea was to simply do Maven resource filtering on web.xml:
<context-param>
 <param-name>spring.profiles.active</param-name>
 <param-value>${spring.profiles.active}</param-value>
</context-param>
It turns out doing resource filtering on web.xml leads you to a world of pain:
  • The Jetty plugin for Maven assumes the web.xml is static and simply uses the one in the source folder. You can explicitly tell it to use the web.xml from the target folder (using the <webXml> config element), but that results in other problems: by default resource filtering does not process the src/main/webapp directory. Of course you can specify filtering for that directory in your POM, but that again given problems: the Maven war plugin will overwrite the filtered web.xml with a copy from the source folder while packaging the web application. You can fix this by adding a <webResources> definition to your POM for the war plugin. Clearly this situation is far from ideal: it's complex and requires an explicit mvn package just to be able to do mvn jetty:run.
  • Idem ditto for Tomcat.
  • Eclipse WTP also directly uses the web.xml from the sources folder. Maybe there are ways around this, but I have no idea how that would work.

In the end we decided to forgo Maven resource filtering on web.xml and simply use an application specific properties file:
spring.profiles.active=${spring.profiles.active}
To get Spring to pick up this additional properties file, we simply add a property source to the application context using an ApplicationContextInitializer:
public class MyAppCtxInitializer
  implements ApplicationContextInitializer<ConfigurableApplicationContext> {
 public void initialize(ConfigurableApplicationContext applicationContext) {
  try {
   applicationContext.getEnvironment().getPropertySources()
     .addLast(new ResourcePropertySource("classpath:/myapp.properties"));
  } catch (IOException e) {
   // properties file cannot be found: ignore and just continue without these properties
   logger.info("Unable to load fallback properties: " + e.getMessage());
  }
 }
}

This approach avoids all the downsides of doing filtering on web.xml (web.xml is now completely static and mvn package no longer required). The only negative aspect is that it introduced an application specific properties file instead of simply relying on standard Spring conventions.

Sunday, December 25, 2011

Good code and good wine

I've discussed the "What is good code?" question before. This is such a broad topic that people come up with all kinds of interesting analogies to describe beneficial traits of good code. For instance, Uncle Bob often compares good code to a good book: it's important to have a good story (design/architecture), introduce key characters (concepts) at appropriate times and so on. Another interesting analogy that I've heard is that good code is like a leather glove: over time it becomes more flexible in areas where it needs to be flexible and more rigid in places that need more rigidity, exactly the way good code should behave and evolve (I'm not sure where I first heard this analogy and who I should credit for it).

Another analogy I (? -- I've never heard it before so I'll be so bold as to take credit myself) came up with recently is comparing good code with good wine. An important characteristic of good wine, maybe even the most important one, is that it tastes good. Likewise, good code needs to function properly and deliver the required functionality. However, as wine aficionados will tell you, tasting good is not the only important trait of a good wine: great wine also has things like an interesting texture, a complex taste palette and so on (not being a wine connaisseur myself, I won't dwell on it). Similarly, having a functional program doesn't imply good source code. Good code needs to exhibit extra characteristics such as flexibility, testability, adhering to the principle of least astonishment and so on.

I'd love to hear about more analogies used to describe good code!

Thursday, November 24, 2011

JDK8 and the future of JVM based languages

Last week at Devoxx 2011 I attended a number of sessions covering new JVM based programming languages such as Kotlin and Ceylon. Of course there were also a number of sessions talking about the usual suspects: Groovy, Scala and JRuby.

There were also a considerable amount of talks covering JDK8 and how that's shaping up. I got the strong impression that Oracle certainly doesn't want to see JDK8 turn into another multi-year debacle. Progress on JDK8 (vitual extension functions, closures, ...) seems impressive and I got a real sense of direction and focus from those involved.

I've been following the whole other languages on the JVM movement that has been going on the last couple of years with interest, but mostly as a by-stander: I'm not a hard-core, opinionated programming language expert like some. However, if I look at the input I gathered at Devoxx I can't help but make a few observations:
  • Although some of the new JVM languages have interesting ideas and are definately a step up from Java, they didn't trigger that aha-erlebnis I had when I first started using Java 1.02 after having used C.
  • The infectuation with dynamic typing seems to be largely over: everybody is back in agreement that strong static typing is the way to go.
  • Scale can't get any love and seems destined to remain an interesting language experiment.
  • Oracle is on somewhat of a mission to deliver JDK8 sooner rather than later.
All of this makes me wonder if Java's successor will actually be Java itself, but in it's 8th incarnation, and whether or not Java 8 will effectively blow all new contenders out of the water? I'm looking forward to seeing how this unfolds!

Friday, October 28, 2011

Java puzzler

Take a look at the following piece of code:
package test;

import java.util.Date;

public class Test {

 public static String format(Date date) {
  return String.valueOf(date);
 }

 public static String format(long millis) {
  return format(new Date(millis));
 }

 public static String format(Instant instant) {
  return format(instant == null ? null : instant.getMillis());
 }

 public static class Instant {

  private long millis;

  public Instant(long millis) {
   this.millis = millis;
  }

  public long getMillis() {
   return millis;
  }
 }

 public static void main(String[] args) {
  Instant instant = null;
  format(instant);
 }
}
Any idea what the output will be? Turns out this throws a NullPointerException:
Exception in thread "main" java.lang.NullPointerException
 at test.Test.format(Test.java:16)
 at test.Test.main(Test.java:34)
Interesting. Line 16 is clearly fishy: The idea is that if the instant is null, the format(Date) method should be called, while format(long) should be called otherwise. It turns out things are much more contrived at the bytecode level (use javap -c):
public static java.lang.String format(test.Test$Instant);
  Code:
   0: aload_0
   1: ifnonnull 8
   4: aconst_null
   5: goto 15
   8: aload_0
   9: invokevirtual #35; //Method test/Test$Instant.getMillis:()J
   12: invokestatic #41; //Method java/lang/Long.valueOf:(J)Ljava/lang/Long;
   15: invokevirtual #46; //Method java/lang/Long.longValue:()J
   18: invokestatic #49; //Method format:(J)Ljava/lang/String;
   21: areturn
This actually translates to the following Java code, which clearly explains the NullPointerException:
public static String format(Instant instant) {
 return format((instant != null ? Long.valueOf(instant.getMillis()) : null).longValue());
}
Sometimes autoboxing can really rear its ugly head!

Sunday, September 4, 2011

Surprise of the day

Well what do you know! It turns out Microsoft was a bigger contributor to Linux kernel version 3.0 than Canonical, as LWN reports. Probably a bit of a fluke but an interesting statistic nonetheless!