Changing Platform Rules

TechCrunch reports this morning that Facebook is changing the rules (again) for third party developers. They’ve done this a few times. So has Apple, on the iPhone platform – when they can be bothered to fully explain the rules in the first place.  Meanwhile, Motorola introduced Droid today – the new flagship Android 2.0 sliding keyboard phone.  Unlike Facebook and Apple, Android is an open platform, without Google guarding the gates for developers. And developers are already complaining that the in-market mix of Android 1.5, 1.6 and 2.0 is driving development costs towards an unsustainable endpoint.

All of this has got me thinking about the challenges of building applications on other people’s platforms.  Whatever users may say about Windows, Microsoft has always treated its ISV partners pretty well.  Lots of notice, and no arbitrary barriers to deployment (Apple) or random, substantive policy and feature swings (Facebook).

I have no deep insight here, but I’m curious – particularly in our area of healthcare informatics and public health, how much is platform instability (and profusion!) limiting the development of next-generation applications?  What’s required to justify an investment in these platforms?

As for Android – depending on what the reviews look like, I’ll probably get a Droid next week or the week after, despite my Sprint contract.  I’ve been fully fed up with Windows Mobile for a while, don’t like Blackberrys, and need a sliding keyboard. Hope the application developers keep up…

Side Adventures in JSF 2.0: Deploy the Hello World example in Tomcat.

In a previous post. I showed how to do the absolute bare minimum to get a CDI/Weld project running in Jetty. Jetty is my favorite container because when launched from maven, it automatically redeploys classes as you modify them without configuring my IDE.

However, in every Java job I’ve ever held, the final product is deployed to another container, such as Tomcat. Fortunately, the Tomcat web application is almost identical to Jetty. Just take the identical application, add a context.xml and deploy.

Create context.xml

#from your project home directory (where pom.xml lives)
touch src/main/webapp/META-INF/context.xml
<?xml version="1.0" encoding="UTF-8"?>
<Context>
	<Manager pathname="" /> <!-- disables storage of sessions across restarts -->
	<Resource name="BeanManager" auth="Container" type="javax.enterprise.inject.spi.BeanManager" 
		factory="org.jboss.weld.resources.ManagerObjectFactory" />
	<!-- Uncomment to enable injection into Servlet -->
	<!-- <Listener className="org.jboss.weld.environment.tomcat.WeldLifecycleListener"/> -->
</Context>

Now, build the project using the standard Maven way:

mvn clean package

In your target directory, you’ll find a war you can deploy using tomcat manager.

Automate Tomcat Deployments using Cargo

If you’re like me, you hate doing things more than once when a script can do the job for you. Simply add:

<!-- Cargo - deploys to Tomcat using command 'mvn clean package cargo:redeploy'. -->
<plugin>
	<groupId>org.codehaus.cargo</groupId>
	<artifactId>cargo-maven2-plugin</artifactId>
	<configuration>
		<container>
			<containerId>tomcat6x</containerId>
			<type>remote</type>
		</container>
		<configuration>
			<type>runtime</type>
			<properties>
				<!-- Declare a tomcat.user and tomcat.password in your settings file -->
				<cargo.remote.username>${tomcat.username}</cargo.remote.username>
				<cargo.remote.password>${tomcat.password}</cargo.remote.password>
				<!--defaults to localhost:8080-->
				<!--<cargo.hostname>localhost</cargo.hostname>-->
				<!--<cargo.servlet.port>8080</cargo.servlet.port>-->
			</properties>
		</configuration>
	</configuration>
</plugin>

If you have a settings.xml file in your .m2 directory, then add the tomcat.username and tomcat.password variables. If you don’t have one, create a file named settings.xml in ~/.m2/

touch ~/.m2/settings.xml

If you have not yet declared a settings.xml, use the one below to get started and add your manager username and password.

settings.xml

<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0 http://maven.apache.org/xsd/settings-1.0.0.xsd">
	<profiles>
		<profile>
			<id>default</id>
			<properties>
				<tomcat.username>(a valid tomcat user in 'manager' role)</tomcat.username>
				<tomcat.password>(the manager password)</tomcat.password>
			</properties>
		</profile>
	</profiles>
	<activeProfiles>
		<activeProfile>default</activeProfile>
	</activeProfiles>
</settings>

Ready to deploy

Now you can deploy to localhost:8080 using the command below.

mvn clean package cargo:redeploy

The host and port can be configured by setting cargo.hostname and cargo.servlet.port.

All Done

Now you can deploy your application to tomcat automatically.

Further Reading

Adventures in JSF 2.0: Hello World Tutorial using Maven 2, JSF 2, Facelets 2, and Weld

In the first of many posts regarding the recently finalized JSF 2.0, I will be showing you what you need to do to write a simple Hello World Application. Instead of traditional JSF backing beans, this application will use Weld, an open-source implementation of JSR-299: Contexts and Dependency Injection for the Java EE platform. JSR-299 will be part of the upcoming JEE 6 specification.

Prerequisites:

Install Sun’s JDK 6, the latest version of Maven (presently 2.2.1), and the IDE of your choice.  I use Eclipse, but GEdit or notepad would work just fine. For this demo, I’ll be using Jetty, so you won’t need to install a container of any sort.

Getting Started:

Create Empty Project

Our first step is to create an ordinary empty WAR project in Maven using the

archetype:generate

command in the directory of your choice.

cd ~/workspace #this can obviously be anywhere.
mvn archetype:generate -DinteractiveMode=n -DarchetypeArtifactId=maven-archetype-webapp -Dversion=0.0.1-SNAPSHOT -DgroupId=org.bogus -DartifactId=jsf2_tutorial

Unfortunately, the default Maven archetype falls short of what we need, so we need to make a few extra directories.  We need a java directory and the test java and resources directory. I’ve also added the commands that an eclipse user would use to generate an importable eclipse project. Netbeans and IntellJ users can simply import the pom.xml.

#create a few extra directories for the project.
mkdir jsf2_tutorial/src/test jsf2_tutorial/src/test/java jsf2_tutorial/src/test/resources jsf2_tutorial/src/main/java
cd jsf2_tutorial
#if you're using *NIX, you can create empty files with this command.
mkdir src/main/java/org/ src/main/java/org/bogus/ #need to create package first.
touch pom.xml src/main/webapp/WEB-INF/web.xml src/main/webapp/WEB-INF/beans.xml src/main/java/org/bogus/HelloWorld.java src/main/webapp/index.xhtml src/test/resources/jetty-env.xml

Overview

I was very impressed that a simple Hello World project can be created with as little as five artifacts.

  1. /pom.xml
  2. /src/main/webapp/WEB-INF/web.xml
  3. /src/main/webapp/WEB-INF/beans.xml
  4. /src/main/java/org/bogus/HelloWorld.java
  5. /src/main/webapp/index.xhtml
  6. /src/test/resources/jetty-env.xml (for Jetty users).

Writing the actual Code

pom.xml

The first step is to the pom.xml file. Afterwards it can be easily imported into any modern IDE.

<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>org.bogus</groupId>
	<artifactId>helloworld</artifactId>
	<packaging>war</packaging>
	<version>0.0.1-SNAPSHOT</version>
	<name>JSF 2.0 Tutorial</name>
	<repositories>
		<!-- As of October 2009, a few of the weld dependencies were not yet on the main maven repo.  We can add JBoss repo as it is updated more frequently.  -->
		<repository>
			<id>repository.jboss.org</id>
			<name>JBoss Repository</name>
			<url>http://repository.jboss.org/maven2</url>
			<releases>
				<enabled>true</enabled>
			</releases>
			<snapshots>
				<enabled>false</enabled>
			</snapshots>
		</repository>
	</repositories>
	<dependencies>
		<!-- Common -->
		<dependency>
			<groupId>javax.enterprise</groupId>
			<artifactId>cdi-api</artifactId>
			<scope>provided</scope>
			<version>1.0-CR1</version>
		</dependency>
 
		<dependency>
			<groupId>javax.annotation</groupId>
			<artifactId>jsr250-api</artifactId>
			<version>1.0</version>
		</dependency>
 
		<dependency>
			<groupId>javax.faces</groupId>
			<artifactId>jsf-api</artifactId>
			<version>2.0.0-RC</version>
		</dependency>
 
		<!-- Jetty-specific scopes and artifacts -->
		<dependency>
			<groupId>javax.faces</groupId>
			<artifactId>jsf-impl</artifactId>
			<scope>runtime</scope>
			<version>2.0.0-RC</version>
		</dependency>
 
		<dependency>
			<groupId>javax.servlet</groupId>
			<artifactId>jstl</artifactId>
			<version>1.2</version>
			<scope>runtime</scope>
		</dependency>
 
		<dependency>
			<groupId>org.jboss.weld.servlet</groupId>
			<artifactId>weld-servlet</artifactId>
			<version>1.0.0-CR1</version>
			<scope>runtime</scope>
		</dependency>
 
		<dependency>
			<groupId>org.glassfish.web</groupId>
			<artifactId>el-impl</artifactId>
			<version>2.1.2-b04</version>
			<scope>runtime</scope>
			<exclusions>
				<exclusion>
					<groupId>javax.el</groupId>
					<artifactId>el-api</artifactId>
				</exclusion>
			</exclusions>
		</dependency>
	</dependencies>
	<build>
		<finalName>jsf2</finalName>
		<plugins>
			<!-- Compiler plugin enforces Java 1.6 -->
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-compiler-plugin</artifactId>
				<configuration>
					<source>1.6</source>
					<target>1.6</target>
				</configuration>
			</plugin>
 
			<!-- Eclipse plugin enforces download of source and JavaDoc jars -->
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-eclipse-plugin</artifactId>
				<configuration>
					<wtpversion>2.0</wtpversion>
					<downloadSources>true</downloadSources>
					<downloadJavadocs>true</downloadJavadocs>
				</configuration>
			</plugin>
			<!-- Embedded Jetty (jetty:run) -->
			<plugin>
				<groupId>org.mortbay.jetty</groupId>
				<artifactId>maven-jetty-plugin</artifactId>
				<configuration>
					<!-- force friendly name instead of artifact name + version -->
					<contextPath>${build.finalName}</contextPath>
					<!-- Where the BeanManager is constructed.  This is where we'll later declare datasource. -->
					<jettyEnvXml>${basedir}/src/test/resources/jetty-env.xml</jettyEnvXml>
					<!-- This parameter will auto-deploy modified classes...my personal favorite Jetty feature. -->
					<scanIntervalSeconds>3</scanIntervalSeconds>
				</configuration>
			</plugin>
		</plugins>
	</build>
</project>

Now that your pom is complete, you can import it into the IDE of your choice. Eclipse requires users to either install m2eclipse or run:

mvn eclipse:eclipse

Boilerplate

web.xml

Since JSF 1.2, the web.xml page got a lot smaller. This is where convention over configuration pays off. Also, faces-config.xml is now optional!

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" version="2.5">
	<!-- Standard JSF 2.0 Configuration Paramters. -->
	<!-- No Joke!!...This is all you need now! -->
	<context-param>
		<param-name>javax.faces.DEFAULT_SUFFIX</param-name>
		<param-value>.xhtml</param-value>
	</context-param>
	<servlet>
		<servlet-name>Faces Servlet</servlet-name>
		<servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
		<load-on-startup>1</load-on-startup>
	</servlet>
	<servlet-mapping>
		<servlet-name>Faces Servlet</servlet-name>
		<url-pattern>*.jsf</url-pattern>
	</servlet-mapping>
 
	<!-- Weld Jetty Configuration parameters -->
	<listener>
		<listener-class>org.jboss.weld.environment.servlet.Listener</listener-class>
	</listener>
	<resource-env-ref>
		<description>Object factory for the CDI Bean Manager</description>
		<resource-env-ref-name>BeanManager</resource-env-ref-name>
		<resource-env-ref-type>javax.enterprise.inject.spi.BeanManager</resource-env-ref-type>
	</resource-env-ref>
</web-app>

beans.xml

In order to indicate to weld to initialize dependency injection, you’ll need to create an empty file named beans.xml. The mere presence of this file in your WEB-INF folder tells the container that your WEB-INF/classes folder is a bean deployment archive.

Application-Specific Code

HelloWorld.java

To confirm that Weld (A.K.A. JSR 299 or WebBeans) Dependency Injection works, we’re going to write an incredibly simple bean. In contrast to Spring, you don’t need to declare the package or bean. Simply adding the @Named annotations and declaring a scope is all that is needed to have your bean registered with the dependency injection container and visible to your facelets view pages.

package org.bogus;
 
import java.io.Serializable;
 
import javax.enterprise.context.SessionScoped;
import javax.inject.Named;
 
@Named //assigns this bean the name of "helloWorld"...its "de-caplitalized" class name
@SessionScoped  //creates one bean for each user session.
public class HelloWorld implements Serializable {
	private final String text = "Hello World!";
 
	public String getText() {
		return text;
	}
 
	private static final long serialVersionUID = 1L;
}

index.xhtml

Now we want to actually view the bean we created. Below is an incredibly simple xhtml/facelets page.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://java.sun.com/jsf/html">
<h:head>
	<title>JSF Demo</title>
</h:head>
<h:body>
	<h1>Does Weld Work?</h1>
	<!-- Your bean can be easily accessed via Expression Language -->
	<p>My weld-injected bean says: #{helloWorld.text}</p>
</h:body>
</html>

jetty-env.xml

Since we’re not using a full JEE container, we need to configure Jetty to prepare the BeanManager.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN"
   "http://jetty.mortbay.org/configure.dtd">
<Configure id="webAppCtx" class="org.mortbay.jetty.webapp.WebAppContext">
	<New id="appManager" class="org.mortbay.jetty.plus.naming.Resource">
		<Arg>
			<Ref id="webAppCtx" />
		</Arg>
		<Arg>BeanManager</Arg>
		<Arg>
			<New class="javax.naming.Reference">
				<Arg>javax.enterprise.inject.spi.BeanManager</Arg>
				<Arg>org.jboss.weld.resources.ManagerObjectFactory</Arg>
				<Arg />
			</New>
		</Arg>
	</New>
</Configure>

Start up Jetty

Jetty is an embedded servlet container that can be easily launched from Maven. Since we added that small snippet to the pom, we can simply type:

mvn war:inplace jetty:run

…and maven will download Jetty and run it with the configuration file we passed.

Test Your Application

Simply load http://localhost:8080/jsf/index.jsf

firefox http://localhost:8080/jsf/index.jsf

Screenshot of your application
If you see the hello world text, everything has worked. Now that you’ve confirmed your configuration is setup correctly, you can explore the more interesting features of Weld and JSF 2, which I’ll be covering in future posts.

Download the Code

The source code to this tutorial is available via subversion here

UPDATE: Tomcat Users

With the addition of a context.xml, this example runs perfectly on Tomcat.
Please see this article for details.

Further Reading

Many thanks to the JBoss staff on the forums who helped me get started in Weld. The artifacts in this article were modeled after their examples.

Duct Tape Programming: Macho?…Yes! Practical?…Rarely!

In http://www.joelonsoftware.com/items/2009/09/23.html, Joel Spolsky of the Joel on Software Blog advocates a practice he calls “Duct Tape Programming.” What he advocates actually is nothing new. It’s more commonly known as “Cowboy Coding.” I decided to post my response for public comment.

Joel’s article was amusing, but obviously balance is important.

I got the impression the Joel was rebelling against COM, C++, OOP, and general abstraction. I can’t say I personally share his view that complex technology is inherently bad. These features are sharp tools, much like the power tools today’s carpenter uses to build a house. Left in the hands of idiots, sharp tools cause problems. It doesn’t take too much imagination to see how assigning an idiot with a drinking problem and an addiction to cough syrup with the task of ripping boards (cutting lengthwise) with a table saw can cause problems. Likewise, letting someone write multi-threaded code who doesn’t have the skill necessary to handle it responsibly is a recipe for disaster.

Over-engineering is a serious threat to a business, especially since many engineers I have worked with can fairly be accused of over-engineering at some point or another in his or her career. However, there’s obviously a reason things like Object Oriented Programming exist… and it isn’t just because the entire software engineering profession isn’t as smart as Mr. Macho Duct Tape Cowboy.

Everyone reading this who has written code for a large company has seen what happens when duct tape programming gets taken too far.  You end up with a giant legacy system, written by two-dozen authors over multiple decades. The application performs poorly, is difficult to maintain, and no one has holistic knowledge of how the system works. You often find yourself spending 6 months training each engineer which touches the system on your internal proprietary duct tape patterns. Duct tape programming is fine and dandy until you ship something that’s broken or can’t be extended to fit your changing business needs — because it is a giant scary monolith and every simple change in one piece of functionality breaks another piece that was duct-taped on it 5 years ago.

OOP and standardization technologies that abstract complexity pay off when you have more developers that can fit comfortably in a small office and you realistically expect for a product to be handled in the future by people other than its original authors. They add complexity for the sake of compartmentalizing functionality so it can be distributed among different authors and can encourage documentation of the workings of each module.

My team pushes for modern standards and best practices so that we can hire a sharp developer who’s familiar with modern technology, and he can instantly understand most of what we’re doing. More often than not, we could have shipped whatever we were working on slightly faster if we ignored standardization and just did things the way we did them many years ago because it was familiar to us. However, the customer would pay the price when they asked someone other than us to maintain our quickly-shipped, duct-taped masterpiece.

Most professional developers write code for a company for the sake of delivering a quality application, a tool to enhance their business. You do the client no favor by saving them money on the initial delivery and costing them more down the road to keep the product running and relevant… unless you’re solely billing by the hour and are in a situation where they can never fire or sue you.

Clearly this is a complex problem that people are years from solving, but until the geniuses of the world get together and solve this once and for all, I personally think we’re best off balancing writing elegant, standards-compliant code with shipping things on time and not blindly adopting technology without fully understanding the consequences.