Several users of the Alagad Image Component, myself included, have run into an annoying limitation of Java on Unix platforms. These unfortunate people receive the, “This graphics environment can be used only in the software emulation mode” error on most calls to Image Component methods.
The problem is not with the Image Component, it stems from limitations of Java running on systems which do not have a mouse, keyboard or display. These systems are said to be “headless”. On Unix, the java.awt package requires you to have a full, and as far as I can tell, running X server installed.
As of Java 1.4.1, Sun added a work around for headless systems. By starting Java with “-Djava.awt.headless=true” argument you should be able to resolve the error message. Implementing this work around with the Alagad Image Component was originally documented here.
But, what if the work around doesn’t work for you? What then?! Rest assured, even I, the author of the Image Component, had a very hard time getting it to run on my RedHat Linux servers. (It’s a piece of cake on Windows!) I followed instructions linked above which were provided by Sun and Macromedia to no avail. So, I did a bit more research and found that that there are three typical solutions to the “headless” problem:
Solution 1: Start Java with “-Djava.awt.headless=true”. I tried this. It didn’t work for me. I tried everything I could think of to get this to work, but I had no luck whatsoever. In every single configuration I tried I still received the same errors in the same places about “software emulation mode”. I have read several accounts of this working for people, but it didn’t work for me. However, if you’re going down the headless road, stop here first and make sure it doesn’t work for you too. Instructions on how to implement this for ColdFusion can be found here.
Solution 2: Install Xvfb, a virtual X server.Xvfb is a virtual X server available from the XFree86 group. It is apparently a reasonably lightweight virtual framebuffer X server and provides the resources needed by Java (and not much more). The major drawback to this is actually having an X server, even it if is a virtual one, running on your server. The good thing is that it supposedly provides all the necessary resources for Java and the Alagad Image Component.
I’ve read good things about it. I’ve also read that the underlying graphics subsystem doesn’t do a very good job with font rendering. However, like the last solution, it didn’t work for me. I do suggest giving it a try though.To get it to work you’re supposed to install Xvfb. Xvfb can be downloaded from the XFree86.org website. I didn’t download mine from there; I downloaded an RPM file from RedHat. (I’m pretty sure it was also on my RedHat CDs, I simply didn’t think to look there.) Because it was an RPM, installation was a breeze.
On a related note, I tried this same solution on an extremely minimal RedHat installation (as in router-like, but with ColdFusion installed). I didn’t complete the install because the Xvfb RPM has many dependencies on other installed RPMs which have their own dependencies. It became too much for me to track down and I gave up.After installing the Xvfb RPM you need to start it. The command I used was:
Xvfb :0 -screen 0 1280x1024x32 &
This is supposed to create a virtual frame buffer on display zero which is 1280×1024 at 32 bit color. I then edited my /etc/rc.local file and added this command so that Xvfb would start up when my server reboots (which is more or less never!).Once you have Xvfb up and running you need to create an environment variable named “DISPLAY” which holds the display number for the system to use. This is where I think I went wrong. You might want to do more research as to what exactly this means and how to do it and have Java be aware you did it. I simply added a line in my /etc/profile file which made the variable permanent and across all terminal sessions. The line I added was:
DISPLAY=":0.0"
You will then need to call:
export DISPLAY
In my /etc/profile file there is a line which exports several variables and I just tacked DISPLAY on to the end.After this, I restarted ColdFusion and… I still had the exact same problem as before. Oh well. I don’t know if this will work for you or what it is I was doing wrong, but I do suggest you try it out. If you know something I don’t, please let me know.
Solution 3: Use Pure Java AWT (PJA). The last thing I tried, and the only thing that worked for me, was using Pure Java AWT or PJA. It seems that someone else out there thought that Java’s requirement for an X11 server was a little, well, odd. They decided to fix it and created an implementation of the java.awt package in pure Java. All you need to do to use it is download the package, extract it, point ColdFusion at it, and it just works! At least, it just worked for me.
The first thing I did was download pja_2.4.zip. Don’t do that! The PJA version 2.4 is the current production version but it doesn’t work with ColdFusion because ColdFusion comes with a 1.4.1 JRE. It seems that the java.awt package changed rather significantly from 1.4 to 1.4.1 and PJA 2.4 doesn’t support all the needed methods. However, there is a beta of the 2.5 version available here. I downloaded this and it simply works for me.
After downloading the ZIP version I extracted it to /usr/PJA. This created a directory /usr/PJA/lib which contains pja.jar. To get ColdFusion to use PJA I had to edit the jvm.config file which is located at {cf directory}/bin/jvm.config. There is a line in this file which reads something like (all on one line):
java.args=-server -Xmx512m -Dsun.io.useCanonCaches=false -Xbootclasspath/a:{application.home}/lib/webchartsJava2D.jar -XX:MaxPermSize=128m -XX:+UseParallelGC -Djava.awt.graphicsenv=com.gp.java2d.ExHeadlessGraphicsEnvironment
This needed to be changed. First, and this was a gotcha for me, I had to add the path to the pja.jar file and another file rt.jar onto the -Xbootclasspath attribute. (I honestly don’t know if rt.jar is required. I added it because it was in the instructions I was following without explanation. Now that it works I don’t want to change anything.) To add additional paths, separate them with a colon “:” like this (note the addition of /opt/coldfusionmx/runtime/jre/lib/rt.jar and /usr/PJA/lib/pja.jar) (all on one line):
-Xbootclasspath/a:{application.home}/lib/webchartsJava2D.jar:/opt/coldfusionmx/runtime/jre/lib/rt.jar:/usr/PJA/lib/pja.jar
This allows Java to find the pja.jar and rt.jar files at startup, which are needed to work as we want it to. (At first, I tried adding these paths to the the Java classpath and it kept not working for me. This was quite frustrating! Don’t let it happen to you!)After that was added I needed to delete the following chunk:
-Djava.awt.graphicsenv=com.gp.java2d.ExHeadlessGraphicsEnvironment
I replaced it with the following:
-Djava.awt.graphicsenv=com.eteks.java2d.PJAGraphicsEnvironment -Djava.awt.fonts=/usr/java/j2sdk1.4.0_03/jre/lib/fonts
This tells Java to use PJA for calls to the java.awt packages. It also tells java to look in the /usr/java/j2sdk1.4.0_03/jre/lib/fonts directory for fonts. You will probably want to find the fonts directory which is correct for you and use that. As a note, I used a directory from a different JRE on my system than the one provided with ColdFusion. This is because the ColdFusion version does not include a fonts directory. I chose a Java fonts directory because that’s what was in the examples I was following. This directory simply contains a set of TTF files so you might be able to point this somewhere else, if you want to. My ending java.args line looked like this (all on one line):
java.args=-server -Xmx512m -Dsun.io.useCanonCaches=false -Xbootclasspath/a:{application.home}/lib/webchartsJava2D.jar:/usr/PJA/lib/pja.jar -XX:MaxPermSize=128m -XX:+UseParallelGC -Djava.awt.graphicsenv=com.eteks.java2d.PJAGraphicsEnvironment -Djava.awt.fonts=/usr/java/j2sdk1.4.0_03/jre/lib/fonts
After saving my updated jvm.config, I restarted ColdFusion and, viola, the Alagad Image Component worked! Yay!
Since this, I’ve had no problems with any portion of this implementation. Yet. Granted, as of now, it has been less than one day. Additionally, the site I’m working with is under development so it’s not under any load yet. I do believe that this will work just fine.If you have any further suggestions or comments on this, please let me know!FYI: I found several resources. One in particular was a day saver. When I was trying to get Xvfb working with ColdFusion I Googled on “ColdFusion Xvfb” and found a link to an entry on Christian Cantrell’s blog. This talked about the exact problems I was having and linked to this site. I found several other sites which linked to the same location, but they all seemed to be being redirected somewhere else. Apparently, the page had been removed from the website. So, I went to the trusty old Way Back Machine and found this link which finally helped me solve my problem. Many thanks to the original author.
Comments on: "Coercing the Alagad Image Component to Work on Headless Systems" (7)
I wish i’d found this article sooner
My CF box can now "be all it can be"
Thanks 🙂
LikeLike
Thanks for your research and help with this. Our issue was related embedded fonts and styles within Flex 1.5 and PJA 2.5 made it all work.
Claude.
LikeLike
Doug, I’m a customer of your tag and had a chat with you by e-mail with some performance problems that I though was caused by AIC. First of all I’m glad to say it wasn’t.
But can you please tell me if any of your above solutions doesn’t trash cfchart tag functionality in CFMX 6.1?
LikeLike
What directories are required, is it only the /lib directory?
LikeLike
Paul – I don’t understand your question. Can you clarify or contact me off blog?
LikeLike
This seriously saved my life. It actually helped me fix a cfchart issue on a production server that was only related in the odd java requirement for X11. Thank you for this!
LikeLike
just adding the pja.jar to the classpath breaks the cfchart. i got it all working by adding -Dawt.toolkit=com.eteks.awt.PJAToolkit to the line
LikeLike