3

I need to dynamically generate some images from a Java servlet-based application. I wanted to make the layout somewhat more maintainable than just using hard-coded positions and Graphics2D.drawString so I thought I would use AWT/Swing layouts for that.

This works fine on my Windows development machine (create JFrame, add components, .pack() frame, render by passing a BufferedImage to component.paint(); note that I'm not calling .setVisible(true)). (Note - the only reason I use a JFrame is to have something to call .pack() on, otherwise I could probably do with something more lightweight.)

However it fails on my Elastic Beanstalk managed AWS EC2 Tomcat7 machine with java.awt.HeadlessException.

java.awt.HeadlessException
    at java.awt.GraphicsEnvironment.checkHeadless(GraphicsEnvironment.java:173)
    at java.awt.Window.<init>(Window.java:477)
    at java.awt.Frame.<init>(Frame.java:419)
    at javax.swing.JFrame.<init>(JFrame.java:218)

First question (obsolete): Does this have a chance of working without installing X11 on it? If yes, what should I set "java.awt.headless" to? If I use "true" then it will fail where it currently fails. If I use "false" will it now fail in some other place where the native code will actually try to use the windowing system?

Second question: How do I set this "java.awt.headless" property (for an EBS environment)?

Because so far I've:

Added the following in my .ebextensions / .config:

option_settings:
  - namespace:  aws:elasticbeanstalk:container:tomcat:jvmoptions
     option_name:  Djava.awt.headless
     value:  false

Edited /etc/tomcat7/tomcat7.conf and put the following there:

JAVA_OPTS="-Djava.awt.headless=false"

Despite that after a redeployment / Tomcat restart it seems the JVM option passed to tomcat is "java.awt.headless=true":

[ec2-user@ip-address ~]$ sudo ps aux | grep headless
tomcat    7200 12.6 45.4 1406724 276604 ?      Sl   23:02   0:47 /usr/lib/jvm/jre/bin/java -DPARAM3= -DPARAM4= -DPARAM1=production_worker.properties -DPARAM2= -DJDBC_CONNECTION_STRING= -DPARAM5= -DAWS_SECRET_KEY= -DAWS_ACCESS_KEY_ID= -XX:MaxPermSize=64m -Xmx512m -Xms512m -classpath :/usr/share/tomcat7/bin/bootstrap.jar:/usr/share/tomcat7/bin/tomcat-juli.jar:/usr/share/java/commons-daemon.jar -Dcatalina.base=/usr/share/tomcat7 -Dcatalina.home=/usr/share/tomcat7 -Djava.awt.headless=true -Djava.endorsed.dirs= -Djava.io.tmpdir=/var/cache/tomcat7/temp -Djava.util.logging.config.file=/usr/share/tomcat7/conf/logging.properties -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager org.apache.catalina.startup.Bootstrap start

And furthermore despite that my code still doesn't find the property as being set at all:

log.error("java.awt.headless=", System.getProperty("java.awt.headless"));

This outputs:

2013-01-14 22:13:17,421 +0000 [http-bio-8080-exec-4] ERROR ServiceImpl:45  - java.awt.headless=

Edit - I also had

System.setProperty("java.awt.headless", "false");

but this also didn't seem to help.

Edit2 - I did away with the JFrame, and just instantiated a JPanel instead. This now makes it render in a headless environment.

However, I cannot figure out how to do layouts properly. I keep calling doLayout on my different layouts, and something.setSize(something.getPreferredSize()) on my components, but the results are overlapping or invisible labels anyway. All because I'm no longer calling JFrame.pack() (as there is no JFrame to call it on).

So third question - how do I ensure my JPanel is laid out properly without a JFrame to call .pack() on?

Edit3 - The answer to third question is by calling panel.addNotify(); panel.setSize(panel.getPreferredSize()); panel.validate(); This is thanks to Andrew Thomson:

When creating a BufferedImage from a JPanel (w/o a JFrame), can I also use a layout manager?

Community
  • 1
  • 1
John M
  • 1,469
  • 17
  • 41
  • 2
    please be more careful with citations - I'm pretty sure that @Andrew never suggested `panel.notify` – kleopatra Jan 15 '13 at 12:18
  • 1
    Looking at the implementation of `addNotify(..)`, it reserves system resources. What is really needed is calling `doLayout(..)` recursively, like in [this answer](https://stackoverflow.com/a/4154510/1143274). – Evgeni Sergeev Oct 12 '18 at 20:19

0 Answers0