2 ways to change key binding in “screen”

The unix program screen, by default, uses Ctrl-a as the key binding as the command character. This conflicts with my use of Ctrl-a to go to the beginning of line. Often I find myself pressing Ctrl-a Ctrl-d intending to go to the beginning of the line and delete some characters. However, this ends up detaching my screen session as Ctrl-a Ctrl-d is used to detach the existing screen. Needless to say that this got very annoying very quickly.

Screen gives you an easy way to change the command character from Ctrl-a to something else , say Ctrl-t.

Option 1

Add this entry to ~/.screenrc:

escape ^tt

You would almost always want this option because once you have added the setting to your screenrc file, it will work consistently on your machine and don’t have to remember to set it each time.

Option 2

Invoke screen with the -e option, like this:

screen -e^tt

This option is particularly useful in two cases:

  • If you are using a shared environment and don’t want change the default key binding
  • If you are attaching a detached session, and the detached session had a different key binding. Note that the detached session does not reload the .screenrc, so in that case this is the only option that you can use.
screen -e^tt -r

Java 7: New Feature – automatically close Files and resources in try-catch-finally

Try with resources is a new feature in Java 7 which lets us write more elegant code by automatically closing resources like FileInputStream at the end of the try-block.

Old Try Catch Finally

Dealing with resources like InputStreams is painful when it comes to the try-catch-finally blocks. You need to declare the resources outside the try so that they are is accessible from finally, then you must initialize the variable to null and check for non-null when closing the resource in finally.

  File file = new File("input.txt");

   InputStream is = null;

   try {
     is = new FileInputStream(file);

     // do something with this input stream
     // ...

   }
   catch (FileNotFoundException ex) {
     System.err.println("Missing file " + file.getAbsolutePath());
   }
   finally {
     if (is != null) {
       is.close();
     }
   }

Java 7: Try with resources

With Java 7, you can create one or more “resources” in the try statement. A “resources” is something that implements the java.lang.AutoCloseable interface. This resource would be automatically closed and the end of the try block.

File file = new File("input.txt");

try (InputStream is = new FileInputStream(file)) {
  // do something with this input stream
  // ...
}
catch (FileNotFoundException ex) {
  System.err.println("Missing file " + file.getAbsolutePath());
}

Exception handling

If both the (explicit) try block and the (implicit) resource handling code throw an exception, then the try block exception is the one which will be thrown. The resource handling exception will be made available via the Throwable.getSupressed() method of the thrown exception. Throwable.getSupressed() is a new method added to the Throwable class since 1.7 specifically for this purpose. If there were no suppressed exceptions then this will return an empty array.

Reference

http://download.java.net/jdk7/docs/technotes/guides/language/try-with-resources.html

New Java 7 Feature: String in Switch support

One of the new features added in Java 7 is the capability to switch on a String.

With Java 6, or less

 String color = "red";

 if (color.equals("red")) {
   System.out.println("Color is Red");
 } else if (color.equals("green")) {
   System.out.println("Color is Green");
 } else {
   System.out.println("Color not found");
 }

With Java 7:

 String color = "red";

 switch (color) {
 case "red":
   System.out.println("Color is Red");
   break;
 case "green":
   System.out.println("Color is Green");
   break;
 default:
   System.out.println("Color not found");
 }

Conclusion

The switch statement when used with a String uses the equals() method to compare the given expression to each value in the case statement and is therefore case-sensitive and will throw a NullPointerException if the expression is null. It is a small but useful feature which not only helps us write more readable code but the compiler will likely generate more efficient bytecode as compared to the if-then-else statement.

Installing Java 7 on Mac OS X

While you can download the binaries for Java 7 for Windows and Linux from here, the instructions for setting up Java 7 for Mac OS X are a lot more tedious.

Here are the official instructions for Mac OS X: http://wikis.sun.com/display/OpenJDK/Mac+OS+X+Port

You can follow the instructions line by line and get Java 7 installed on your machine. However, these are the things that might go wrong:

Missing binaries in /bin

The installation expects a bunch of binaries to be present in /bin. However, on my Mac OS X, these binaries were present in /usr/bin/. My workaround was to create symlinks in the /bin directories to make the build happy.

cd /bin/
ln -s /usr/bin/sed
ln -s /usr/bin/grep

Repeat the above for each binary that is reported missing in /bin.

Missing jni.h

Make sure that the version of XCode is 3.2.5 or more. I had a 3.2.4 version and that didn’t work.

Building JTReg did not work due to a known bug

It is mentioned in the JTReg build documentation but easy to miss it. The following does not work due to a know bug:

make -C make

Instead try this:

make -C make build

Wrong installation directory in the official instructions

The official instructions ask you to do this:

mkdir -p ~/Library/Java/JavaVirtualMachines
cp -R build/macosx-universal/j2sdk-bundle/1.7.0.jdk ~/Library/Java/JavaVirtualMachines

That didn’t work for me. Here’s what worked for me:

mkdir -p /System/Library/Java/JavaVirtualMachines
cp -R build/macosx-universal/j2sdk-bundle/1.7.0.jdk /System/Library/Java/JavaVirtualMachines

Finally, setting up env vars

The easiest way to make confirm that Java 7 is successfully installed is:

/usr/libexec/java_home --version 1.7

The output of the above should be:

/System/Library/Java/JavaVirtualMachines/1.7.0.jdk/Contents/Home

Then type ‘java -version’ against the above installation

/System/Library/Java/JavaVirtualMachines/1.7.0.jdk/Contents/Home/bin/java -version
openjdk version "1.7.0-internal"
OpenJDK Runtime Environment (build 1.7.0-internal-root_2011_03_16_17_41-b00)
OpenJDK 64-Bit Server VM (build 21.0-b03, mixed mode)

Since I use Java 1.6 on the same machine, I saved the 1.7 path as follows:

export JAVA7_HOME=/System/Library/Java/JavaVirtualMachines/1.7.0.jdk/Contents/Home

This lets me conveniently switch to Java7, when I need to, and back:

export JAVA_HOME=$JAVA7_HOME

Switch back:

export JAVA_HOME=$JAVA6_HOME

Using Java7

Simplest way to use test Java7 is via command line

export JAVA_HOME=$JAVA7_HOME
export PATH=$JAVA_HOME/bin:$PATH

Compile

javac Test.java

Run

java Test

JBoss Tools bug: SeamListener not found

Overview

If you use JBoss Tools Plugin for Eclipse to deploy apps to JBoss 5.1 container and get a “SeamListener not found”, this post provides a simple workaround.

I deployed a webapp to JBoss 5.1 container from Eclipse using JBoss Tools plugin. The app failed to start with the following error:

19:01:14,762 WARN  [JAXWSDeployerHookPreJSE] Cannot load servlet class: org.jboss.seam.servlet.SeamResourceServlet
19:01:14,787 INFO  [TomcatDeployment] deploy, ctxPath=/hcf
19:01:15,143 ERROR [[/hcf]] Error configuring application listener of class org.jboss.seam.servlet.SeamListener
java.lang.ClassNotFoundException: org.jboss.seam.servlet.SeamListener
 at java.net.URLClassLoader$1.run(URLClassLoader.java:202)
 at java.security.AccessController.doPrivileged(Native Method)
 at java.net.URLClassLoader.findClass(URLClassLoader.java:190)
 at java.lang.ClassLoader.loadClass(ClassLoader.java:307)
 at java.lang.ClassLoader.loadClass(ClassLoader.java:248)
 at org.jboss.web.tomcat.service.TomcatInjectionContainer.newInstance(TomcatInjectionContainer.java:262)
 at org.jboss.web.tomcat.service.TomcatInjectionContainer.newInstance(TomcatInjectionContainer.java:256)
 at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:3859)
 at org.apache.catalina.core.StandardContext.start(StandardContext.java:4393)
 at org.jboss.web.tomcat.service.deployers.TomcatDeployment.performDeployInternal(TomcatDeployment.java:310)
 at org.jboss.web.tomcat.service.deployers.TomcatDeployment.performDeploy(TomcatDeployment.java:142)
 at org.jboss.web.deployers.AbstractWarDeployment.start(AbstractWarDeployment.java:461)
 at org.jboss.web.deployers.WebModule.startModule(WebModule.java:118)
 at org.jboss.web.deployers.WebModule.start(WebModule.java:97)
 at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
 at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
 at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
 at java.lang.reflect.Method.invoke(Method.java:597)
 at org.jboss.mx.interceptor.ReflectedDispatcher.invoke(ReflectedDispatcher.java:157)
 at org.jboss.mx.server.Invocation.dispatch(Invocation.java:96)
 at org.jboss.mx.server.Invocation.invoke(Invocation.java:88)
 at org.jboss.mx.server.AbstractMBeanInvoker.invoke(AbstractMBeanInvoker.java:264)
 at org.jboss.mx.server.MBeanServerImpl.invoke(MBeanServerImpl.java:668)
 at org.jboss.system.microcontainer.ServiceProxy.invoke(ServiceProxy.java:206)
 at $Proxy38.start(Unknown Source)
 at org.jboss.system.microcontainer.StartStopLifecycleAction.installAction(StartStopLifecycleAction.java:42)
 at org.jboss.system.microcontainer.StartStopLifecycleAction.installAction(StartStopLifecycleAction.java:37)
 at org.jboss.dependency.plugins.action.SimpleControllerContextAction.simpleInstallAction(SimpleControllerContextAction.java:62)
 at org.jboss.dependency.plugins.action.AccessControllerContextAction.install(AccessControllerContextAction.java:71)
 at org.jboss.dependency.plugins.AbstractControllerContextActions.install(AbstractControllerContextActions.java:51)
 at org.jboss.dependency.plugins.AbstractControllerContext.install(AbstractControllerContext.java:348)
 at org.jboss.system.microcontainer.ServiceControllerContext.install(ServiceControllerContext.java:286)
 at org.jboss.dependency.plugins.AbstractController.install(AbstractController.java:1631)
 at org.jboss.dependency.plugins.AbstractController.incrementState(AbstractController.java:934)
 at org.jboss.dependency.plugins.AbstractController.resolveContexts(AbstractController.java:1082)
 at org.jboss.dependency.plugins.AbstractController.resolveContexts(AbstractController.java:984)
 at org.jboss.dependency.plugins.AbstractController.change(AbstractController.java:822)
 at org.jboss.dependency.plugins.AbstractController.change(AbstractController.java:553)
 at org.jboss.system.ServiceController.doChange(ServiceController.java:688)
 at org.jboss.system.ServiceController.start(ServiceController.java:460)
 at org.jboss.system.deployers.ServiceDeployer.start(ServiceDeployer.java:163)
 at org.jboss.system.deployers.ServiceDeployer.deploy(ServiceDeployer.java:99)
 at org.jboss.system.deployers.ServiceDeployer.deploy(ServiceDeployer.java:46)
 at org.jboss.deployers.spi.deployer.helpers.AbstractSimpleRealDeployer.internalDeploy(AbstractSimpleRealDeployer.java:62)
 at org.jboss.deployers.spi.deployer.helpers.AbstractRealDeployer.deploy(AbstractRealDeployer.java:50)
 at org.jboss.deployers.plugins.deployers.DeployerWrapper.deploy(DeployerWrapper.java:171)
 at org.jboss.deployers.plugins.deployers.DeployersImpl.doDeploy(DeployersImpl.java:1439)
 at org.jboss.deployers.plugins.deployers.DeployersImpl.doInstallParentFirst(DeployersImpl.java:1157)
 at org.jboss.deployers.plugins.deployers.DeployersImpl.doInstallParentFirst(DeployersImpl.java:1178)
 at org.jboss.deployers.plugins.deployers.DeployersImpl.install(DeployersImpl.java:1098)
 at org.jboss.dependency.plugins.AbstractControllerContext.install(AbstractControllerContext.java:348)
 at org.jboss.dependency.plugins.AbstractController.install(AbstractController.java:1631)
 at org.jboss.dependency.plugins.AbstractController.incrementState(AbstractController.java:934)
 at org.jboss.dependency.plugins.AbstractController.resolveContexts(AbstractController.java:1082)
 at org.jboss.dependency.plugins.AbstractController.resolveContexts(AbstractController.java:984)
 at org.jboss.dependency.plugins.AbstractController.change(AbstractController.java:822)
 at org.jboss.dependency.plugins.AbstractController.change(AbstractController.java:553)
 at org.jboss.deployers.plugins.deployers.DeployersImpl.process(DeployersImpl.java:781)
 at org.jboss.deployers.plugins.main.MainDeployerImpl.process(MainDeployerImpl.java:702)
 at org.jboss.system.server.profileservice.repository.MainDeployerAdapter.process(MainDeployerAdapter.java:117)
 at org.jboss.system.server.profileservice.hotdeploy.HDScanner.scan(HDScanner.java:362)
 at org.jboss.system.server.profileservice.hotdeploy.HDScanner.run(HDScanner.java:255)
 at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:441)
 at java.util.concurrent.FutureTask$Sync.innerRunAndReset(FutureTask.java:317)
 at java.util.concurrent.FutureTask.runAndReset(FutureTask.java:150)
 at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$101(ScheduledThreadPoolExecutor.java:98)
 at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.runPeriodic(ScheduledThreadPoolExecutor.java:181)
 at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:205)
 at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
 at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
 at java.lang.Thread.run(Thread.java:619)
19:01:15,196 ERROR [[/hcf]] Skipped installing application listeners due to previous error(s)
19:01:15,196 ERROR [StandardContext] Error listenerStart
19:01:15,196 ERROR [StandardContext] Context [/hcf] startup failed due to previous errors
19:01:15,201 ERROR [AbstractKernelController] Error installing to Start: name=jboss.web.deployment:war=/hcf state=Create mode=Manual requiredState=Installed
org.jboss.deployers.spi.DeploymentException: URL file:/C:/software/jboss-5.1.0.GA/server/default/tmp/5c4o12w-udpgi-gf7dk40e-1-gf7dli4l-9o/hcf.war/ deployment failed
 at org.jboss.web.tomcat.service.deployers.TomcatDeployment.performDeployInternal(TomcatDeployment.java:331)
 at org.jboss.web.tomcat.service.deployers.TomcatDeployment.performDeploy(TomcatDeployment.java:142)
 at org.jboss.web.deployers.AbstractWarDeployment.start(AbstractWarDeployment.java:461)
 at org.jboss.web.deployers.WebModule.startModule(WebModule.java:118)
 at org.jboss.web.deployers.WebModule.start(WebModule.java:97)
 at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
 at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
 at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
 at java.lang.reflect.Method.invoke(Method.java:597)
 at org.jboss.mx.interceptor.ReflectedDispatcher.invoke(ReflectedDispatcher.java:157)
 at org.jboss.mx.server.Invocation.dispatch(Invocation.java:96)
 at org.jboss.mx.server.Invocation.invoke(Invocation.java:88)
 at org.jboss.mx.server.AbstractMBeanInvoker.invoke(AbstractMBeanInvoker.java:264)
 at org.jboss.mx.server.MBeanServerImpl.invoke(MBeanServerImpl.java:668)
 at org.jboss.system.microcontainer.ServiceProxy.invoke(ServiceProxy.java:206)
 at $Proxy38.start(Unknown Source)
 at org.jboss.system.microcontainer.StartStopLifecycleAction.installAction(StartStopLifecycleAction.java:42)
 at org.jboss.system.microcontainer.StartStopLifecycleAction.installAction(StartStopLifecycleAction.java:37)
 at org.jboss.dependency.plugins.action.SimpleControllerContextAction.simpleInstallAction(SimpleControllerContextAction.java:62)
 at org.jboss.dependency.plugins.action.AccessControllerContextAction.install(AccessControllerContextAction.java:71)
 at org.jboss.dependency.plugins.AbstractControllerContextActions.install(AbstractControllerContextActions.java:51)
 at org.jboss.dependency.plugins.AbstractControllerContext.install(AbstractControllerContext.java:348)
 at org.jboss.system.microcontainer.ServiceControllerContext.install(ServiceControllerContext.java:286)
 at org.jboss.dependency.plugins.AbstractController.install(AbstractController.java:1631)
 at org.jboss.dependency.plugins.AbstractController.incrementState(AbstractController.java:934)
 at org.jboss.dependency.plugins.AbstractController.resolveContexts(AbstractController.java:1082)
 at org.jboss.dependency.plugins.AbstractController.resolveContexts(AbstractController.java:984)
 at org.jboss.dependency.plugins.AbstractController.change(AbstractController.java:822)
 at org.jboss.dependency.plugins.AbstractController.change(AbstractController.java:553)
 at org.jboss.system.ServiceController.doChange(ServiceController.java:688)
 at org.jboss.system.ServiceController.start(ServiceController.java:460)
 at org.jboss.system.deployers.ServiceDeployer.start(ServiceDeployer.java:163)
 at org.jboss.system.deployers.ServiceDeployer.deploy(ServiceDeployer.java:99)
 at org.jboss.system.deployers.ServiceDeployer.deploy(ServiceDeployer.java:46)
 at org.jboss.deployers.spi.deployer.helpers.AbstractSimpleRealDeployer.internalDeploy(AbstractSimpleRealDeployer.java:62)
 at org.jboss.deployers.spi.deployer.helpers.AbstractRealDeployer.deploy(AbstractRealDeployer.java:50)
 at org.jboss.deployers.plugins.deployers.DeployerWrapper.deploy(DeployerWrapper.java:171)
 at org.jboss.deployers.plugins.deployers.DeployersImpl.doDeploy(DeployersImpl.java:1439)
 at org.jboss.deployers.plugins.deployers.DeployersImpl.doInstallParentFirst(DeployersImpl.java:1157)
 at org.jboss.deployers.plugins.deployers.DeployersImpl.doInstallParentFirst(DeployersImpl.java:1178)
 at org.jboss.deployers.plugins.deployers.DeployersImpl.install(DeployersImpl.java:1098)
 at org.jboss.dependency.plugins.AbstractControllerContext.install(AbstractControllerContext.java:348)
 at org.jboss.dependency.plugins.AbstractController.install(AbstractController.java:1631)
 at org.jboss.dependency.plugins.AbstractController.incrementState(AbstractController.java:934)
 at org.jboss.dependency.plugins.AbstractController.resolveContexts(AbstractController.java:1082)
 at org.jboss.dependency.plugins.AbstractController.resolveContexts(AbstractController.java:984)
 at org.jboss.dependency.plugins.AbstractController.change(AbstractController.java:822)
 at org.jboss.dependency.plugins.AbstractController.change(AbstractController.java:553)
 at org.jboss.deployers.plugins.deployers.DeployersImpl.process(DeployersImpl.java:781)
 at org.jboss.deployers.plugins.main.MainDeployerImpl.process(MainDeployerImpl.java:702)
 at org.jboss.system.server.profileservice.repository.MainDeployerAdapter.process(MainDeployerAdapter.java:117)
 at org.jboss.system.server.profileservice.hotdeploy.HDScanner.scan(HDScanner.java:362)
 at org.jboss.system.server.profileservice.hotdeploy.HDScanner.run(HDScanner.java:255)
 at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:441)
 at java.util.concurrent.FutureTask$Sync.innerRunAndReset(FutureTask.java:317)
 at java.util.concurrent.FutureTask.runAndReset(FutureTask.java:150)
 at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$101(ScheduledThreadPoolExecutor.java:98)
 at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.runPeriodic(ScheduledThreadPoolExecutor.java:181)
 at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:205)
 at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
 at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
 at java.lang.Thread.run(Thread.java:619)
19:01:15,209 ERROR [AbstractKernelController] Error installing to Real: name=vfsfile:/C:/workspace/.metadata/.plugins/org.jboss.ide.eclipse.as.core/JBoss_5.1_Runtime_Server1286220891669/deploy/hcf.war/ state=PreReal mode=Manual requiredState=Real
org.jboss.deployers.spi.DeploymentException: URL file:/C:/software/jboss-5.1.0.GA/server/default/tmp/5c4o12w-udpgi-gf7dk40e-1-gf7dli4l-9o/hcf.war/ deployment failed
 at org.jboss.web.tomcat.service.deployers.TomcatDeployment.performDeployInternal(TomcatDeployment.java:331)
 at org.jboss.web.tomcat.service.deployers.TomcatDeployment.performDeploy(TomcatDeployment.java:142)
 at org.jboss.web.deployers.AbstractWarDeployment.start(AbstractWarDeployment.java:461)
 at org.jboss.web.deployers.WebModule.startModule(WebModule.java:118)
 at org.jboss.web.deployers.WebModule.start(WebModule.java:97)
 at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
 at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
 at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
 at java.lang.reflect.Method.invoke(Method.java:597)
 at org.jboss.mx.interceptor.ReflectedDispatcher.invoke(ReflectedDispatcher.java:157)
 at org.jboss.mx.server.Invocation.dispatch(Invocation.java:96)
 at org.jboss.mx.server.Invocation.invoke(Invocation.java:88)
 at org.jboss.mx.server.AbstractMBeanInvoker.invoke(AbstractMBeanInvoker.java:264)
 at org.jboss.mx.server.MBeanServerImpl.invoke(MBeanServerImpl.java:668)
 at org.jboss.system.microcontainer.ServiceProxy.invoke(ServiceProxy.java:206)
 at $Proxy38.start(Unknown Source)
 at org.jboss.system.microcontainer.StartStopLifecycleAction.installAction(StartStopLifecycleAction.java:42)
 at org.jboss.system.microcontainer.StartStopLifecycleAction.installAction(StartStopLifecycleAction.java:37)
 at org.jboss.dependency.plugins.action.SimpleControllerContextAction.simpleInstallAction(SimpleControllerContextAction.java:62)
 at org.jboss.dependency.plugins.action.AccessControllerContextAction.install(AccessControllerContextAction.java:71)
 at org.jboss.dependency.plugins.AbstractControllerContextActions.install(AbstractControllerContextActions.java:51)
 at org.jboss.dependency.plugins.AbstractControllerContext.install(AbstractControllerContext.java:348)
 at org.jboss.system.microcontainer.ServiceControllerContext.install(ServiceControllerContext.java:286)
 at org.jboss.dependency.plugins.AbstractController.install(AbstractController.java:1631)
 at org.jboss.dependency.plugins.AbstractController.incrementState(AbstractController.java:934)
 at org.jboss.dependency.plugins.AbstractController.resolveContexts(AbstractController.java:1082)
 at org.jboss.dependency.plugins.AbstractController.resolveContexts(AbstractController.java:984)
 at org.jboss.dependency.plugins.AbstractController.change(AbstractController.java:822)
 at org.jboss.dependency.plugins.AbstractController.change(AbstractController.java:553)
 at org.jboss.system.ServiceController.doChange(ServiceController.java:688)
 at org.jboss.system.ServiceController.start(ServiceController.java:460)
 at org.jboss.system.deployers.ServiceDeployer.start(ServiceDeployer.java:163)
 at org.jboss.system.deployers.ServiceDeployer.deploy(ServiceDeployer.java:99)
 at org.jboss.system.deployers.ServiceDeployer.deploy(ServiceDeployer.java:46)
 at org.jboss.deployers.spi.deployer.helpers.AbstractSimpleRealDeployer.internalDeploy(AbstractSimpleRealDeployer.java:62)
 at org.jboss.deployers.spi.deployer.helpers.AbstractRealDeployer.deploy(AbstractRealDeployer.java:50)
 at org.jboss.deployers.plugins.deployers.DeployerWrapper.deploy(DeployerWrapper.java:171)
 at org.jboss.deployers.plugins.deployers.DeployersImpl.doDeploy(DeployersImpl.java:1439)
 at org.jboss.deployers.plugins.deployers.DeployersImpl.doInstallParentFirst(DeployersImpl.java:1157)
 at org.jboss.deployers.plugins.deployers.DeployersImpl.doInstallParentFirst(DeployersImpl.java:1178)
 at org.jboss.deployers.plugins.deployers.DeployersImpl.install(DeployersImpl.java:1098)
 at org.jboss.dependency.plugins.AbstractControllerContext.install(AbstractControllerContext.java:348)
 at org.jboss.dependency.plugins.AbstractController.install(AbstractController.java:1631)
 at org.jboss.dependency.plugins.AbstractController.incrementState(AbstractController.java:934)
 at org.jboss.dependency.plugins.AbstractController.resolveContexts(AbstractController.java:1082)
 at org.jboss.dependency.plugins.AbstractController.resolveContexts(AbstractController.java:984)
 at org.jboss.dependency.plugins.AbstractController.change(AbstractController.java:822)
 at org.jboss.dependency.plugins.AbstractController.change(AbstractController.java:553)
 at org.jboss.deployers.plugins.deployers.DeployersImpl.process(DeployersImpl.java:781)
 at org.jboss.deployers.plugins.main.MainDeployerImpl.process(MainDeployerImpl.java:702)
 at org.jboss.system.server.profileservice.repository.MainDeployerAdapter.process(MainDeployerAdapter.java:117)
 at org.jboss.system.server.profileservice.hotdeploy.HDScanner.scan(HDScanner.java:362)
 at org.jboss.system.server.profileservice.hotdeploy.HDScanner.run(HDScanner.java:255)
 at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:441)
 at java.util.concurrent.FutureTask$Sync.innerRunAndReset(FutureTask.java:317)
 at java.util.concurrent.FutureTask.runAndReset(FutureTask.java:150)
 at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$101(ScheduledThreadPoolExecutor.java:98)
 at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.runPeriodic(ScheduledThreadPoolExecutor.java:181)
 at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:205)
 at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
 at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
 at java.lang.Thread.run(Thread.java:619)
19:01:15,229 WARN  [HDScanner] Failed to process changes
org.jboss.deployers.client.spi.IncompleteDeploymentException: Summary of incomplete deployments (SEE PREVIOUS ERRORS FOR DETAILS):

*** DEPLOYMENTS IN ERROR: Name -> Error

vfsfile:/C:/workspace/.metadata/.plugins/org.jboss.ide.eclipse.as.core/JBoss_5.1_Runtime_Server1286220891669/deploy/hcf.war/ -> org.jboss.deployers.spi.DeploymentException: URL file:/C:/software/jboss-5.1.0.GA/server/default/tmp/5c4o12w-udpgi-gf7dk40e-1-gf7dli4l-9o/hcf.war/ deployment failed

DEPLOYMENTS IN ERROR:
 Deployment "vfsfile:/C:/workspace/.metadata/.plugins/org.jboss.ide.eclipse.as.core/JBoss_5.1_Runtime_Server1286220891669/deploy/hcf.war/" is in error due to the following reason(s): org.jboss.deployers.spi.DeploymentException: URL file:/C:/software/jboss-5.1.0.GA/server/default/tmp/5c4o12w-udpgi-gf7dk40e-1-gf7dli4l-9o/hcf.war/ deployment failed

 at org.jboss.deployers.plugins.deployers.DeployersImpl.checkComplete(DeployersImpl.java:993)
 at org.jboss.deployers.plugins.deployers.DeployersImpl.checkComplete(DeployersImpl.java:939)
 at org.jboss.deployers.plugins.main.MainDeployerImpl.checkComplete(MainDeployerImpl.java:873)
 at org.jboss.system.server.profileservice.repository.MainDeployerAdapter.checkComplete(MainDeployerAdapter.java:128)
 at org.jboss.system.server.profileservice.hotdeploy.HDScanner.scan(HDScanner.java:369)
 at org.jboss.system.server.profileservice.hotdeploy.HDScanner.run(HDScanner.java:255)
 at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:441)
 at java.util.concurrent.FutureTask$Sync.innerRunAndReset(FutureTask.java:317)
 at java.util.concurrent.FutureTask.runAndReset(FutureTask.java:150)
 at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$101(ScheduledThreadPoolExecutor.java:98)
 at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.runPeriodic(ScheduledThreadPoolExecutor.java:181)
 at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:205)
 at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
 at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
 at java.lang.Thread.run(Thread.java:619)

This seemed to be a bug, as the above class is contained in the jboss-seam.jar, which I included in the classpath via the following maven snippet

<dependency>
 <groupId>org.jboss.seam</groupId>
 <artifactId>jboss-seam</artifactId>
 <version>2.2.0.GA</version>
 </dependency>

I confirmed that the jar was not present in the deployed app, by going to the “Server” tab in eclipse and right-clicking on my app and “Explore”. The explore option launched a new window and listed the actual deployed app. I confirmed that the jboss-seam.jar was not present. Your deployment directory will be something like this:

C:\workspace\.metadata\.plugins\org.jboss.ide.eclipse.as.core\JBoss_5.1_Runtime_Server1286220891669\deploy\hcf.war

Upon Googling, I found that this is due to a known bug in JBoss Tools.

This issue has apparently been fixed in 3.2.0 M1.

Here “hcf” is the name of my app.

Workaround

By hit and trial, I found a simple workaround. After you deploy your webapp, simply copy the missing jar to the “lib” directory of the deployed app and restart Jboss.

Wrong location

You will find the file ‘jboss-seam-2.2.0.GA.jar’ in this directory.

C:\workspace\.metadata\.plugins\org.jboss.ide.eclipse.as.core\JBoss_5.1_Runtime_Server1286220891669\deploy\hcf.war

Correct location

C:\workspace\.metadata\.plugins\org.jboss.ide.eclipse.as.core\JBoss_5.1_Runtime_Server1286220891669\deploy\hcf.war\WEB-INF\lib

Move the seam jar from the wrong location to the correct location. Restart Jboss after moving the file, and the error should go away.

Securing a JBoss web application

This articles describes how to secure a Java web application in JBoss using BASIC authentication.

Step1: Edit web.xml in your application

Edit the web.xml file in your webapp at the following location.

WEB-INF/web.xml

Edit your web.xml and put the following contents (generally towards the bottom of the file)

<web-app>
....

 <security-constraint>
  <web-resource-collection>
   <web-resource-name>All resources</web-resource-name>
   <description>Protects all resources</description>
   <url-pattern>/*</url-pattern>
  </web-resource-collection>

  <auth-constraint>
   <role-name>myrole</role-name>
  </auth-constraint>
 </security-constraint>

 <security-role>
  <role-name>myrole</role-name>
 </security-role>

 <login-config>
  <auth-method>BASIC</auth-method>
  <realm-name>Authorized access only.</realm-name>
 </login-config>
</web-app>

This is a way of telling the container to restrict all URLs to any user with the role ‘myrole‘.

Step 2: Create jboss-web.xml in your application

Edit or create the jboss-web.xml file in your webapp at the following location.

WEB-INF/jboss-web.xml

Put the following contents:

<jboss-web>
 <security-domain>java:/jaas/myappname</security-domain>
</jboss-web>

This tells JBoss to use application policy ‘myappname’ for this application.

Step 3: Create Application policy on JBoss server

We now need to define the application policy ‘myappname‘ on JBoss server.

Edit the login-config.xml file in the JBoss server directory at the following location.

jboss/server/default/conf/login-config.xml

Edit the contents of login-config.xml and add an application policy as follows:

<policy>
...

<!-- application policy for myappname -->
<application-policy name="myappname">
 <authentication>
  <login-module code="org.jboss.security.auth.spi.UsersRolesLoginModule" flag="required">
   <module-option name="usersProperties">props/users.properties</module-option>
   <module-option name="rolesProperties">props/roles.properties</module-option>
  </login-module>
 </authentication>
</application-policy>
</policy>

This tells JBoss to user ‘UsersRolesLoginModule’ which uses property files to store users and roles.

Step 4: Create users on JBoss server

Now we create a new user with the role ‘myrole’.

Create a new User

Edit the users.properties file used by your application policy in Step 3.

jboss/server/default/conf/props/users.properties

Add a line to create a new user as follows.

myuser=mypassword

Roles

Finally, we assign the role ‘myrole’ to the user ‘myuser’. Edit the following file

Create a new role

Edit the roles.properties file used by your application policy in Step 3.

jboss/server/default/conf/props/roles.properties

Add a line to create a assign the role ‘myrole’ to ‘myuser’ as follows.

myuser=myrole

Test your settings

Restart the JBoss server and deploy your application. When you access your application, you should see a basic authentication popup.

If your setup is correct, you should be able to login using ‘myuser’ and ‘mypassword’ as defined in the Step 4.

Conclusion

This approach is equivalent to defining users, passwords and roles in tomcat-users.xml. While this is an easy approach and helps you get started, a real production web application should not store its passwords unencrypted on disk. We used BASIC authentication in this example. For production quality applications, you should use DIGEST, FORM or CLIENT-CERT.

Access to www.w3.org DTDs blocked from Java

I was trying to parse an XML file with Java JAXB. The XML file had the following header at the beginning of the file.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE appspec [
 <!ENTITY % HTMLlat1 PUBLIC
 "-//W3C//ENTITIES Latin 1 for XHTML//EN"
 "http://www.w3.org/TR/xhtml1/DTD/xhtml-lat1.ent">
 <!ENTITY % HTMLspec PUBLIC
 "-//W3C//ENTITIES Special for XHTML//EN"
 "http://www.w3.org/TR/xhtml1/DTD/xhtml-special.ent">
 %HTMLlat1;
 %HTMLspec;
]>

The program failed with the following error:
Server returned HTTP response code: 500 for URL: http://www.w3.org/TR/xhtml1/DTD/xhtml-lat1.ent

Full stacktrace:

[ERROR] BUILD ERROR
[INFO] ------------------------------------------------------------------------
[INFO] Could not read the xml, make sure that it is a valid xml and it validates against the schema

Server returned HTTP response code: 500 for URL: http://www.w3.org/TR/xhtml1/DTD/xhtml-lat1.ent
[INFO] ------------------------------------------------------------------------
[DEBUG] Trace
org.apache.maven.lifecycle.LifecycleExecutionException: Could not read the xml, make sure that it is a valid xml and it validates against the schema
        at org.apache.maven.lifecycle.DefaultLifecycleExecutor.executeGoals(DefaultLifecycleExecutor.java:719)
        at org.apache.maven.lifecycle.DefaultLifecycleExecutor.executeStandaloneGoal(DefaultLifecycleExecutor.java:569)
        at org.apache.maven.lifecycle.DefaultLifecycleExecutor.executeGoal(DefaultLifecycleExecutor.java:539)
        at org.apache.maven.lifecycle.DefaultLifecycleExecutor.executeGoalAndHandleFailures(DefaultLifecycleExecutor.java:387)
        at org.apache.maven.lifecycle.DefaultLifecycleExecutor.executeTaskSegments(DefaultLifecycleExecutor.java:284)
        at org.apache.maven.lifecycle.DefaultLifecycleExecutor.execute(DefaultLifecycleExecutor.java:180)
        at org.apache.maven.DefaultMaven.doExecute(DefaultMaven.java:328)
        at org.apache.maven.DefaultMaven.execute(DefaultMaven.java:138)
        at org.apache.maven.cli.MavenCli.main(MavenCli.java:362)
        at org.apache.maven.cli.compat.CompatibleMain.main(CompatibleMain.java:60)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
        at java.lang.reflect.Method.invoke(Method.java:597)
        at org.codehaus.classworlds.Launcher.launchEnhanced(Launcher.java:315)
        at org.codehaus.classworlds.Launcher.launch(Launcher.java:255)
        at org.codehaus.classworlds.Launcher.mainWithExitCode(Launcher.java:430)
        at org.codehaus.classworlds.Launcher.main(Launcher.java:375)
Caused by: org.apache.maven.plugin.MojoExecutionException: Could not read the xml, make sure that it is a valid xml and it validates against the schema
        at org.clickframes.mavenplugin.ClickframesGenPlugin.readProject(ClickframesGenPlugin.java:246)
        at org.clickframes.mavenplugin.ClickframesGenPlugin.execute(ClickframesGenPlugin.java:126)
        at org.apache.maven.plugin.DefaultPluginManager.executeMojo(DefaultPluginManager.java:490)
        at org.apache.maven.lifecycle.DefaultLifecycleExecutor.executeGoals(DefaultLifecycleExecutor.java:694)
        ... 17 more
Caused by: javax.xml.bind.UnmarshalException
 - with linked exception:
[java.io.IOException: Server returned HTTP response code: 500 for URL: http://www.w3.org/TR/xhtml1/DTD/xhtml-lat1.ent]
        at com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal0(UnmarshallerImpl.java:197)
        at com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal(UnmarshallerImpl.java:174)
        at com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal(UnmarshallerImpl.java:225)
        at org.clickframes.AppspecJaxbWrapper.readAppspecType(AppspecJaxbWrapper.java:53)
        at org.clickframes.AppspecReader.readProject(AppspecReader.java:54)
        at org.clickframes.mavenplugin.ClickframesGenPlugin.readProject(ClickframesGenPlugin.java:244)
        ... 20 more
Caused by: java.io.IOException: Server returned HTTP response code: 500 for URL: http://www.w3.org/TR/xhtml1/DTD/xhtml-lat1.ent
        at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1313)
        at com.sun.org.apache.xerces.internal.impl.XMLEntityManager.setupCurrentEntity(XMLEntityManager.java:677)
        at com.sun.org.apache.xerces.internal.impl.XMLEntityManager.startEntity(XMLEntityManager.java:1315)
        at com.sun.org.apache.xerces.internal.impl.XMLEntityManager.startEntity(XMLEntityManager.java:1252)
        at com.sun.org.apache.xerces.internal.impl.XMLDTDScannerImpl.startPE(XMLDTDScannerImpl.java:722)
        at com.sun.org.apache.xerces.internal.impl.XMLDTDScannerImpl.skipSeparator(XMLDTDScannerImpl.java:2069)
        at com.sun.org.apache.xerces.internal.impl.XMLDTDScannerImpl.scanDecls(XMLDTDScannerImpl.java:2032)
        at com.sun.org.apache.xerces.internal.impl.XMLDTDScannerImpl.scanDTDInternalSubset(XMLDTDScannerImpl.java:377)
        at com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl$DTDDriver.dispatch(XMLDocumentScannerImpl.java:1141)
        at com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl$DTDDriver.next(XMLDocumentScannerImpl.java:1090)
        at com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl$PrologDriver.next(XMLDocumentScannerImpl.java:977)
        at com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl.next(XMLDocumentScannerImpl.java:648)
        at com.sun.org.apache.xerces.internal.impl.XMLNSDocumentScannerImpl.next(XMLNSDocumentScannerImpl.java:140)
        at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanDocument(XMLDocumentFragmentScannerImpl.java:511)
        at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:808)
        at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:737)
        at com.sun.org.apache.xerces.internal.parsers.XMLParser.parse(XMLParser.java:119)
        at com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.parse(AbstractSAXParser.java:1205)
        at com.sun.org.apache.xerces.internal.jaxp.SAXParserImpl$JAXPSAXParser.parse(SAXParserImpl.java:522)
        at com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal0(UnmarshallerImpl.java:195)
        ... 25 more
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 34 seconds
[INFO] Finished at: Fri Oct 29 17:18:58 EDT 2010
[INFO] Final Memory: 17M/177M
[INFO] ------------------------------------------------------------------------

The program complained about not being able to download the file from www.w3.org. I tried to view the file in Firefox and was able to view it successfully. My hypothesis at that point was that w3.org is allowing Firefox but blocking Java. I confirmed that using wget and manually setting the User-Agent.

Using wget with User-Agent set to Firefox

You can set the user-agent using the -U option in wget

wget http://www.w3.org/TR/xhtml1/DTD/xhtml-lat1.ent -U "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.2.10) Gecko/20100914 Firefox/3.6.10"
--11:24:08--  http://www.w3.org/TR/xhtml1/DTD/xhtml-lat1.ent
Resolving www.w3.org... 128.30.52.37
Connecting to www.w3.org|128.30.52.37|:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 11775 (11K) [application/xml-external-parsed-entity]
Saving to: `xhtml-lat1.ent'
100%[======================================================================================================================>] 11,775      --.-K/s   in 0.07s
11:24:08 (157 KB/s) - `xhtml-lat1.ent' saved [11775/11775]

Using wget with User-Agent set to Java

wget http://www.w3.org/TR/xhtml1/DTD/xhtml-lat1.ent -U "Java/1.6.0_20"
--11:24:17--  http://www.w3.org/TR/xhtml1/DTD/xhtml-lat1.ent
Resolving www.w3.org... 128.30.52.37
Connecting to www.w3.org|128.30.52.37|:80... connected.
HTTP request sent, awaiting response... 500 Server Error
11:24:48 ERROR 500: Server Error.

The above verified that www.w3.org was blocking the request from Java.

Conclusion

W3.org blocks requests to certain resources originating from the Java program, identified by the User-Agent header ‘Java/1.6.0_20′. This is a known issue. The URLs have been deliberately blocked by w3.org due to ‘abusive’ use by Java programs. Read the full story here: W3C’s Excessive DTD Traffic.

The bottom line is that you, or your program, should download and cache a copy of this resource and not hit w3.org with a request to the same static resource over and over. Respect the Expiry date HTTP header.

Java Expiry Date header

Overview

One of the tricks to creating snappy and fast loading web pages is to set the correct ‘Expiry-date’ header on your web pages and static resources like images, CSS and Javascript files. By setting an expiration date in the future, you can tell the browser to cache the resource locally in the browser cache. This article discusses how to speed up your Java webapp by setting optimal expiration date to leverage browser caching.

An example of expiry date header is as follows:

Expires: Wed, 27 Oct 2010 19:02:24 EDT

The easiest way to set expiry date in Java webapps is via a servlet filter. Servlet filters are Java classes which extend the class javax.servlet.Filter. Servlet filters are an elegant way to intercept each request and do something useful, add a HTTP header in this case.

I wrote a Servlet filter which can be used to set the expiry date on any page in your webapp. You can use this servlet filter to set the expiry date header without writing any Java code in your project. You can also select which pages to set the expiry date and the age of the page via a properties file.

1. Download the code for expiration date filter and add it to your project

Download the file PageExpiryFilter.java and add it to your project.

2. Add a Servlet Filter to web.xml, and map it to all URLs

<filter>
 <filter-name>PageExpiryFilter</filter-name>
  <filter-class>com.vineetmanohar.web.PageExpiryFilter</filter-class>
 </filter>

 <filter-mapping>
  <filter-name>PageExpiryFilter</filter-name>
  <url-pattern>/*</url-pattern>
 </filter-mapping>

3. Create ‘expires.property’ file in src/main/resources

Create the following file:

src/main/resources/expires.properties

You can set expiry date for all or some paths in your webapp by simply creating entries in this file

The format for each line is:

Format:
Resource Path = freshness interval for this resource

Pattern:
<full regex of the resource> = <number><unit>

Valid values for Unit:

  • m for minute
  • h for hour
  • d for day
  • w for week
  • M for month

Important

  1. Order in the properties file is important. The first rule which matches is applied and no more rules are checked.
  2. If no rules match, expiry date is not set.
  3. The path of the resource relative to the application root is matched against the regex. So if you app baseurl is http://foobar/somewebapp, the path for resource http://foobar/somewebapp/images/logo.png will be /images/logo.png.

Example 1:

^/css/.*  = 30d
^/js/.*   = 15d
^.*\.png$ = 2M
  • The first line specifies, all content starting with /css expires in 30 days from current date.
  • The second line specifies, all content starting with /js expires in 15 days from current date.
  • The third line specifies, all content ending with .png expires in 15 days from current date.
  • For those less familiar with regular expression, ^ denotes the beginning of the line and $ denotes the end of line. See full regex reference.

Example 2: For pages which don’t change a lot, you may want to set a smaller expiry date, says 4 hours. This is merely an example, you should examine the nature of your webapp before choosing the age of the page.

^/home/content/ = 4h

Example 3: Depending on how aggressive you want to be, you may want to set a default expiry date for all pages. This might not be suitable in all cases where pages change often and you want the browser to always load the latest page. Don’t use this if you don’t understand it completely.

.* = 1h

How to check Expiry Date header via a browser

Viewing Page Expiry Header in Firebug

Viewing HTTP Headers for www.cnn.com in Firebug

There are many tools that let you check HTTP header values. My personal favorite is Firebug, which is a Firefox plugin. Once you have firebug open, go to the “Net” console, and view your page. You should see a GET or POST request as a row on the console. Expand that row, and go to the “Headers” tab. You should see all the headers, including the “Expires” headers if present.

The following screenshot is Firefug’s Net console displaying HTTP headers from www.cnn.com. Notice that the expiry date is for www.cnn.com home page is only 1 minute. This lets the browser cache the page for 1 minute, and re-fetch the page after 1 minute. While this is suitable for cnn.com where content might change every minute, you should decide the expiry date for your website depending on how often the content changes.

I highly recommend getting Firebug and looking at the expiry date of your webapp. Firebug also shows what gets downloaded each time you request a page and what is loaded from cache. This may help you determine your requirements, for example, if you notice a static resource (javascript file or css file) getting downloaded in each request, you might want to add an expiry date header for that resource.

Conclusion

Setting an expiration date in the future lets user’s browser cache pages locally and results in fast loading pages and increased end user satisfaction. The technique described in this article lets Java webapps very easily set expiration date without writing any Java code. However, keep in mind that setting a long expiration date might not be the right thing to do in many cases, e.g. where freshness of content is important, or there are security implications.

References

Spring Quartz code snippets for beginners

Overview

Some applications need to run periodic jobs in the background. On linux/unix systems, background processes can be run using the “cronjob” scheduling service. In Java web applications, you can add scheduling to any app in 4 simple steps using Spring and Quartz. This article outlines the steps needed for scheduling, with code snippets required for each step.

Step 1: web.xml

To initialize Spring in your webapp, add this snippet to your web.xml file. If you are already using Spring, you probably already have this in your web.xml.

<!-- Initialize Spring -->
<listener>
 <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

Step 2: applicationContext.xml snippet

There are 3 concepts when configuring your scheduled jobs:

1) The Job: the java code that you want to run in the background periodically

2) A Trigger: a trigger adds scheduling information to your job. There are different types of triggers (e.g. SimpleTrigger, CronTrigger). They differ in the way you specify scheduling information. For example, CronTrigger takes a cronexpression, whereas SimpleTrigger takes a repeatInterval.

3) The Scheduler: this is the actual service which runs in the background and invokes ‘triggers’. You can register multiple triggers with this service.

Add this snippet to your spring xml file.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"
 "http://www.springframework.org/dtd/spring-beans.dtd">
<beans>

 <!-- The 'Scheduler': quartz scheduler -->
 <bean id="schedulerFactoryBean" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
  <!-- list of triggers registered with the scheduler -->
  <property name="triggers">
   <list>
    <!-- Trigger1: JobExample using CronTrigger -->
    <bean id="jobDetailTrigger" class="org.springframework.scheduling.quartz.CronTriggerBean">
     <!-- job class -->
     <property name="jobDetail">
      <bean class="org.springframework.scheduling.quartz.JobDetailBean">
       <!-- CHANGE THIS to the actual implementation class (see step 4)  -->
       <property name="jobClass" value="com.vineetmanohar.example.quartz.JobExample" />
      </bean>
     </property>

     <!-- job schedule: every 5 minutes: CHANGE THIS -->
     <property name="cronExpression" value="0 0/30 * * * ?" />
    </bean>

    <!-- Trigger2: JobExample2 using SimpleTrigger -->
    <bean class="org.springframework.scheduling.quartz.SimpleTriggerBean">
     <property name="jobDetail">
      <bean>
       <!-- CHANGE THIS to the actual implementation class (see step 4)  -->
       <property name="jobClass" value="com.vineetmanohar.example.quartz.JobExample2" />
      </bean>
     </property>
    
     <!-- wait 4 minutes after startup -->
     <property name="startDelay" value="240000" />
    
     <!-- every 1 min (60 sec) -->
     <property name="repeatInterval" value="60000" />
    </bean>
   </list>
  </property>
 </bean>

</beans>

Step 3: pom.xml snippet

If you are using maven, add this to your pom.xml to add spring and quartz dependency to your project.

<project>
 <dependencies>
  <dependency>
   <groupId>org.opensymphony.quartz</groupId>
   <artifactId>quartz</artifactId>
   <version>1.6.1</version>
  </dependency>
 
  <dependency>
   <groupId>org.springframework</groupId>
   <artifactId>spring-context</artifactId>
   <version>2.5</version>
  </dependency>

  <dependency>
   <groupId>org.springframework</groupId>
   <artifactId>spring-context-support</artifactId>
   <version>2.5</version>
  </dependency>
 </dependencies>
</project>

Step 4: Java code snippet

Finally, write the actual implementation. Make sure that job class you specified in step 2 points to this file.

package com.vineetmanohar.example.quartz.JobExample;

import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.springframework.scheduling.quartz.QuartzJobBean;

public class JobExample extends QuartzJobBean {
  protected void executeInternal(JobExecutionContext ctx) throws JobExecutionException {
   System.out.println("Job invoked at : " + new java.util.Date());

   // TODO: implement the job here
 }
}

Cron expression

The format of cron expression is <Seconds> <Minutes> <Hours> <Day-of-Month> <Month> <Day-of-Week> <Year (optional field)>. For example:

Every 30 minutes

0 0/30 * * * ?

See full reference documentation here.

Java Barcode API

QR Code "9780201750799"

QR Code for "9780201750799"

Overview

Originally Barcodes were 1D representation of data using width and spacing of bars. Common bar code types are UPC barcodes which are seen on product packages. There are 2D barcodes as well (they are still called Barcodes even though they don’t use bars). A common example of 2D bar code is QR code (shown on right) which is commonly used by mobile phone apps. You can read history and more info about Barcodes on Wikipedia.

There is an open source Java library called ‘zxing’ (Zebra Crossing) which can read and write many differently types of bar codes formats. I tested zxing and it was able to read a barcode embedded in the middle of a 100 dpi grayscale busy text document!

This article demonstrates how to use zxing to read and write bar codes from a Java program.

Getting the library

It would be nice if the jars where hosted in a maven repo somewhere, but there is no plan to do that (see Issue 88). Since I could not find the binaries available for download, I decided to download the source code and build the binaries, which was actually quite easy.

The source code of the library is available on Google Code. At the time of writing, 1.6 is the latest version of zxing.

1. Download the release file ZXing-1.6.zip (which contains of mostly source files) from here.
2. Unzip the file in a local directory
3. You will need to build 2 jar files from the downloaded source: core.jar, javase.jar

Building core.jar

cd zxing-1.6/core
mvn install

This will install the jar in your local maven repo. Though not required, you can also deploy it to your company’s private repo by using mvn:deploy or by manually uploading it to your maven repository.

There is an ant script to build the jar as well.

Building javase.jar

Repeat the same procedure to get javase.jar

cd zxing-1.6/javase
mvn install

Including the libraries in your project

If you are using ant, add the core.jar and javase.jar to your project’s classpath.

If you are using maven, add the following to your pom.xml.

<dependencies>
 <dependency>
  <groupId>com.google.zxing</groupId>
  <artifactId>core</artifactId>
  <version>1.6-SNAPSHOT</version>
 </dependency>
 
 <dependency>
  <groupId>com.google.zxing</groupId>
  <artifactId>javase</artifactId>
  <version>1.6-SNAPSHOT</version>
 </dependency>
<dependencies>

Once you have the jars included in your project’s classpath, you are now ready to read and write barcodes from java!

Reading a Bar Code from Java

You can read the bar code by first loading the image as an input stream and then calling this utility method.

InputStream barCodeInputStream = new FileInputStream("file.jpg");
BufferedImage barCodeBufferedImage = ImageIO.read(barCodeInputStream);

LuminanceSource source = new BufferedImageLuminanceSource(barCodeBufferedImage);
BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source));
Reader reader = new MultiFormatReader();
Result result = reader.decode(bitmap);

System.out.println("Barcode text is " + result.getText());

Writing a Bar Code from Java

You can encode a small text string as follows:

String text = "98376373783"; // this is the text that we want to encode

int width = 400;
int height = 300; // change the height and width as per your requirement

// (ImageIO.getWriterFormatNames() returns a list of supported formats)
String imageFormat = "png"; // could be "gif", "tiff", "jpeg" 

BitMatrix bitMatrix = new QRCodeWriter().encode(text, BarcodeFormat.QR_CODE, width, height);
MatrixToImageWriter.writeToStream(bitMatrix, imageFormat, new FileOutputStream(new File("qrcode_97802017507991.png")));

In the above example, the bar code for “97802017507991″ is written to the file “qrcode_97802017507991.png” (click to see the output).

JavaDocs and Documentation

The Javadocs are part of the downloaded zip file. You can find a list of supported bar code formats in the Javadocs. Open the following file to see the javadocs.

zxing-1.6/docs/javadoc/index.html

Reference

Get Adobe Flash playerPlugin by wpburn.com wordpress themes