3/17/2010

Simple Asynchronous methods in EJB 3.1

EJB 3.1 introduced a simple mechanism for asynchronous invocation. This post presents such an example with a Singleton session bean and its JUnit test case. 2 styles of asynchronous EJB invocations are used:

(1) fire-and-forget asynchronous methods having void return type.

(2) retrieve-result-later asynchronous methods having Future<?> return type.

package test;

import java.util.concurrent.Future;
import javax.ejb.Asynchronous;
import javax.ejb.AsyncResult;
import javax.ejb.Singleton;

@Singleton
@Asynchronous
public class AsyncBean {
@Asynchronous //this line can be omitted
public void ignoreResult(int a, int b) {
// the client doesn't care what happens here
}

@Asynchronous //this line can be omitted
public Future<Integer> longProcessing(int a, int b) {
return new AsyncResult<Integer>(a * b);
}
}
Since the class is annotated with @Asynchronous, all business methods are asynchronous. The method-level @Asynchronous is therefore redundant, and kept there for illustration purpose.
package test;

import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import javax.ejb.embeddable.EJBContainer;
import javax.naming.Context;
import junit.framework.TestCase;

public class AsyncBeanTest extends TestCase {
private EJBContainer container;
private Context namingContext;
private AsyncBean asyncBean;

@Override
protected void setUp() throws Exception {
super.setUp();
container = EJBContainer.createEJBContainer();
namingContext = container.getContext();
asyncBean = (AsyncBean) namingContext.lookup("java:global/testApp/AsyncBean");
}

@Override
protected void tearDown() throws Exception {
super.tearDown();
container.close();
}

public final void testIgnoreResult() {
asyncBean.ignoreResult(0, 0); // fire and forget
System.out.println("Proceed without waiting for the async method result.");
}

public final void testLongProcessing() throws InterruptedException, ExecutionException {
Future<Integer> futureResult = asyncBean.longProcessing(8, 9);
System.out.println("Proceed to other tasks and check async method result later.");
Integer intResult = futureResult.get();
System.out.println("The prior async method returned " + intResult);
}
}
I've tested this example with GlassFish V3 in its embedded mode. It should work with any Java EE 6 application servers as well. The configureation (classpath, outputDir, etc) and how to run it are the same as EJB Lite testing with JUnit and embeddable container.

3/10/2010

How to trim ant property string value

When writing ant build files, I often need to trim the string value of an ant property. But I couldn't find a simple task to do that. So I wrote the following ant macrodef for this purpose. In short, it saves the property value into a temp file, trims lines while moving the file, and loads the file back into a new property.

<?xml version="1.0" encoding="UTF-8"?>
<project basedir="." default="trim" name="test">
<target name="trim">
<trim input="${text}" property="text.trimmed" />
<echo message="original text='${text}'" />
<echo message="trimmed text='${text.trimmed}'" />
</target>

<macrodef name="trim">
<attribute name="input" />
<attribute name="property" />
<sequential>
<tempfile property="temp.file" />
<echo file="${temp.file}" message="@{input}" />
<move file="${temp.file}" tofile="${temp.file}.2">
<filterchain>
<trim/>
</filterchain>
</move>
<loadfile property="@{property}" srcFile="${temp.file}.2" />
<delete file="${temp.file}.2" failonerror="false" />
</sequential>
</macrodef>

</project>
To run this target:
/tmp > ant -Dtext=' a b c '
Buildfile: build.xml

trim:
[move] Moving 1 file to /tmp
[delete] Deleting: /tmp/null1355243589.2
[echo] original text=' a b c '
[echo] trimmed text='a b c'

BUILD SUCCESSFUL
Total time: 0 seconds
The ant macro named trim declares the trim operation, while the trim target shows an example of calling the trim macro.

There are other solutions to achive the same result, e.g., write a custom ant task, or use ant-contrib tasks. But the advantage of this sample is that it only uses built-in ant tasks and no other library jars are needed.