Showing posts with label java ee 6. Show all posts
Showing posts with label java ee 6. Show all posts

Sunday, April 17, 2011

Running CDI Source on JBoss AS 6

For those unaware, last month an initiative called CDI Source was announced by Rick Hightower. It looks like their goals are pretty similar to Seam, a tool I've been using for a few years now; and most recently started actually contributing to!

I was curious yesterday (mostly because it was pouring here all day) to see what had come of it, and happened to notice they were first tackling CDI & Spring interoperability. Not a bad move I thought, Spring already has all of the add-ons you would be looking for (arguably too many), so being able to bring that in to a CDI enabled application makes a lot of sense. I would still argue that Spring really needs to be able to delegate down to an underlying CDI implementation in these cases, mostly for performance reasons.

I decided to clone their repositories. They have two currently, one is their underlying beancontainer and another for examples (they also host a resin plugin for maven, but out of scope..). When I cloned and started digging in to it, I found some things that were cool (tests worked out of the box) and some things I didn't like (platform dependence). I built the main project, no issue. I built the example spring app, had an issue there - tests didn't run. So I rebuilt without tests, generated a WAR file. I then tried to deploy it to JBoss AS 6. No luck, talk about nearly killing a VM. I deployed to a stopped JBoss instance, and attempted to start up, received a lot of classloader based errors (missing XAManager, base classloader setup wrong, etc). Never fun, though reminded me of the issues I have in Seam JMS :-)

When I dug into the code, I found a few problems. The biggest I saw was due to all of the extra dependencies that Spring pulls in, deployment to a full application server (as it always used to be) was going to be a challenge. I tried marking dependencies as provided, but no luck. Still were being pulled in for some reason. So I decided to pull out the pre-maven rule book and ripping out libraries under WEB-INF/lib. I was able to string the list down to these:

  • aopalliance-1.0.jar
  • aspectjrt-1.6.11.M2.jar
  • aspectjweaver-1.6.11.M2.jar
  • beancontainer-api-1.0-SNAPSHOT.jar
  • commons-beanutils-1.8.0.jar
  • commons-collections-3.1.jar
  • commons-dbcp-1.3.jar
  • commons-digester-2.0.jar
  • commons-fileupload-1.2.1.jar
  • commons-pool-1.5.4.jar
  • dom4j-1.6.1.jar
  • flexjson-2.1.jar
  • jcl-over-slf4j-1.6.1.jar
  • joda-time-1.6.jar
  • slf4j-api-1.6.1.jar
  • slf4j-log4j12-1.6.1.jar
  • spring-aop-3.0.5.RELEASE.jar
  • spring-asm-3.0.5.RELEASE.jar
  • spring-aspects-3.0.5.RELEASE.jar
  • spring-beans-3.0.5.RELEASE.jar
  • springbridge-1.0-SNAPSHOT.jar
  • spring-context-3.0.5.RELEASE.jar
  • spring-context-support-3.0.5.RELEASE.jar
  • spring-core-3.0.5.RELEASE.jar
  • spring-expression-3.0.5.RELEASE.jar
  • spring-jdbc-3.0.5.RELEASE.jar
  • spring-js-resources-2.2.1.RELEASE.jar
  • spring-orm-3.0.5.RELEASE.jar
  • spring-tx-3.0.5.RELEASE.jar
  • spring-web-3.0.5.RELEASE.jar
  • spring-webmvc-3.0.5.RELEASE.jar
  • tiles-api-2.2.1.jar
  • tiles-core-2.2.1.jar
  • tiles-jsp-2.2.1.jar
  • tiles-servlet-2.2.1.jar
  • tiles-template-2.2.1.jar
Yep, had to shrink it down to 36 libraries. Still a lot of libraries in place. Attempting to deploy this resulted in some Weld errors, resolving around injection targets. I figured they were incorrectly creating injection targets in the code, and confirmed that in their SpringIntegrationExtention class, they were making beans that were also injection targets, for some reason. When I removed this code, the application deployed fine. I still can't run the application correctly due to a tiles error (see here) but at least it deploys fine now.

As of this morning, I saw that Rick had also been working on it, and made essentially the same change I did to the code to make it work with Weld.

Sunday, March 14, 2010

Writing a Property Loader in Java EE 6 and Testing it using Arquillian

So, like most people, I'm interested in Java EE 6, and the new CDI framework that comes with it. I see it as a huge time saver and seems to fit in well with the whole ecosystem of Java EE (not to mention, it also knocks Spring down a little, a plus in my book).

We're beginning to adopt Java EE 6 at work. A big application has been running for a few weeks already and now we have a couple of smaller applications that are likely to run with our live site (one being a search engine). I'm not aiming this article to be an intro to Weld, CDI or Java EE 6; I would expect anyone reading this to be at least familiar with the concepts.

Something that's big for us is testing, and allowing the application to be configurable. We definitely push the separation between development and administration and I have been ensuring that all applications match that mindset. As a result, loading property files is a typical use case for us. I was looking at how we've been doing it, and decided that it should be much simpler if we had a producer method to produce property files. Some of our files reside in the deployment archives, most on the file system; and we usually like to make it a system property to configure where to read the files from. Below is some sample code explaining how to implement a Property Loader in CDI

First, the qualifier; it only takes one argument the value.

@Qualifier
@Retention(RUNTIME)
@Target({METHOD, FIELD, PARAMETER, TYPE})
public @interface ConfiguredBy {
@Nonbinding public String value();
}


We use Nonbinding on the value so that there's only one producer necessary; since the value is essentially an argument to what we want to produce, and what it gets attached to is the Produced object. For the sake of my code, I only support producing instances of java.util.Properties.

Here's what the Producer method looks like (and yell if you don't like my code; note that the real version would be cleaner assuming you had an injectable SLF4J Logger).

   @Produces @ConfiguredBy("")
/**
* Produces a java.util.Properties object based on the qualifier ConfiguredBy
* and the injection point.
*
* Behavior is as follows:
* - the value can be a System property or a path.
* - If it's a system property, we convert it to the value of that property first
*
* - Then we check to see if the value now is an absolute path or a classpath entry
* - We try both.
*/
public Properties produceProperties(InjectionPoint ip) {
Properties p = new Properties();
String value = ip.getAnnotated().getAnnotation(ConfiguredBy.class).value();
System.out.println("Producing properties with value.... "+value);
if(value == null || value.equals("")) {
//if the given file is empty, we can't load it too well.
return p;
}
String propValue = System.getProperty(value);
if(propValue != null) {
value = propValue;
}

File f = new File(value);
if(f.exists() && !f.isDirectory()) {
//so it's on the file system, let's load it.
try{
FileInputStream fis = new FileInputStream(f);
p.load(fis);
} catch (IOException e) {
System.out.println("Problem reading the file, ignoring.");
}
}
//now we try to get it from the classpath, as a resource.
try{
InputStream is = this.getClass().getClassLoader().getResourceAsStream(value);
p.load(is);
} catch (Exception e) {
System.out.println("Problem reading the file, ignoring.");
}
return p;
}
So what this code allows us to do is attempt to load a file based on a System property, and it can exist on the file system or as a resource in the class loader.

Now here's the fun part, how to test this using Arquillian. For those that don't know, Arquillian is a new tool from JBoss designed to help testing software in a container. As of this post, they support Glassfish V3, Weld SE, JBoss AS 5.1 and JBoss AS 6.0. It looks like they also support OpenEJB; but I'm not sure what version. I was able to run my tests on this class using the Weld SE container using JUnit. They also support TestNG; but I've historically always leaned towards JUnit.

Here's an example of a testing class, in this case I use a System property to find the location of a file in the classpath.

First, the maven dependencies.


<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.7</version>
<scope>test</scope>
</dependency>

<dependency>
<groupId>org.jboss.weld</groupId>
<artifactId>weld-se</artifactId>
<version>1.0.1-Final</version>
</dependency>

<dependency>
<groupId>org.jboss.arquillian.container</groupId>
<artifactId>arquillian-weld-embedded</artifactId>
<version>1.0.0-SNAPSHOT</version>
<scope>test</scope>
</dependency>

<dependency>
<groupId>org.jboss.arquillian</groupId>
<artifactId>arquillian-junit</artifactId>
<version>1.0.0-SNAPSHOT</version>
<scope>test</scope>
</dependency>


In order to test a system property, I needed to add it explicitly in the surefire plugin in maven:


<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.5</version>
<configuration>
<systemPropertyVariables>
<propertyProducerTestSystemProperty.file>META-INF/test1.properties</propertyProducerTestSystemProperty.file>
</systemPropertyVariables>
</configuration>
</plugin>


My test1.properties file, located in src/test/resources/META-INF/, was simply:


key1=value2
key2=value2
key3=something
key4=key4

My test case class was then very simple to write. This is all I had to do to test my producer method, create an injection point!


@RunWith(Arquillian.class)
public class PropertyProducerTestSystemProperty {

@Deployment
public static JavaArchive createDeployment() {
return Archives.create("test.jar", JavaArchive.class)
.addClass(PropertyProducer.class)
.addClass(ConfiguredBy.class)
.addManifestResource("META-INF/test1.properties",
ArchivePaths.create("test1.properties"))
.addManifestResource(
"META-INF/beans.xml",
ArchivePaths.create("beans.xml"));
}

@Inject @ConfiguredBy("propertyProducerTestSystemProperty.file")
Properties properties;

@Test
public void testPropertySize() {
Assert.assertEquals(4,properties.size());
}
@Test
public void testPropertyContains() {
Assert.assertFalse(properties.containsKey("search.url.base"));

}
@Test
public void testPropertyValue() {
Assert.assertEquals("something", properties.getProperty("key3"));
}

}

The createDeployment method, since it's annotated @Deployment signifies the files that will be included in the test - what the container will need to deploy. Note that there's no code in my code that has a direct dependency on how it's tested - switching from Weld SE to Glassfish is simply done in maven. Also note that they have more robush ways of testing in the examples, but it's beyond the scope of this topic.

For each test case, the injection point will get processed and injected; and you can verify that the tests pass.

If you want to give this a try, you can clone the source from my google code site, tadcdicomps and then click on the Source tab. this is the properties project under hg. To run the tests, I have a Test Suite that has multiple test classes in it, the command I ran after building was

mvn test -Dtest=PropertiesTestSuite

Enjoy!