Uso de bibliotecas gráficas Java em ambiente servidor Unix/Linux

Entenda e soluciona erros do tipo Can"t connect to X11 window server em aplicações rodando em um servidor Java em sistema operacional Unix ou Linux.

Fundamentos

Aplicações rodando em um servidor Java EE podem precisar utilizar bibliotecas, frameworks componentes ou primitivas gráficas. Um caso típico é o processamento dinâmico de arquivos ou fluxos de dados de objetos gráficos como uma imagem, por exemplo, para a geração de um gráfico em um relatório, ou de um código de barras em um documento.

A maioria dos componentes gráficos pressupõe a existência de um ambiente gráfico (java.awt.GraphicsEnvironment), com dispositivo de exibição (tela), além de teclado e mouse. De fato, não faz sentido criar um componente gráfico desktop em Java como um Botão (Button) ou janela (Window, Frame, Dialog etc.) sem que o Java tenha um ambiente gráfico provendo as definições e configurações necessárias para a existência e exibição do componente.

Mas componentes gráficos mais genéricos como Canvas, Panel e Image podem ser criados sem existência de modo gráfico no ambiente de execução da VM Java.

Enquanto as aplicações Java desktop (Java SE) com interface gráfica (Swing, AWT etc.) requerem um ambiente gráfico para sua exibição onde a VM Java está executando, aplicações Java EE são processadas em uma VM Java no servidor, mas a exibição ocorre no lado cliente, em geral em um navegador web. Muitas vezes, um ambiente de execução servidor Java EE nem possui modo gráfico ativo.

Normalmente isso não faz diferença em sistemas Microsoft Windows, onde as primitivas do ambiente gráfico sempre estão presentes. Mas em sistemas operacionais como Unix/Linux, há diferenças no ambiente da execução da VM Java entre o modo gráfico interativo — onde há um servidor de ambiente gráfico X11 (X Window System, ver X.Org e XFree86) em execução — e o modo batch ou console não interativo (serviços ou processos daemon).

O ambiente servidor não interativo, sem dispositivos gráficos, é chamado no jargão técnico de modo “sem cabeça” ou “headless” em inglês.

Problema e solução

Para usar bibliotecas, componentes ou primitivas gráficas em ambiente servidor Unix/Linux, não interativo e sem modo gráfico, configure o Toolkit gráfico da VM Java para executar em modo “sem-cabeça”, ou Headless Mode, existente desde o J2SE 1.4.

Para isso, é necessário definir a propriedade de sistema java.awt.headless como true. Na linha de comando da execução Java, usa-se a opção -D conforme a seguir:

java -Djava.awt.headless=true

Alternativamente no código Java, no início da aplicação antes que o Tookit gráfico seja inicializado, pode-se executar:

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

Sem esta definição em servidores Unix/Linux, a tentativa de uso de componentes ou métodos gráficos deve gerar uma erro similar a:

Exception in thread "main" java.lang.InternalError:
Can"t connect to X11 window server
using ":0.0" as the value of the DISPLAY variable.
        at sun.awt.X11GraphicsEnvironment.initDisplay(Native Method)
        at sun.awt.X11GraphicsEnvironment.<clinit>
        at java.lang.Class.forName0(Native Method)
        at java.lang.Class.forName
        at java.awt.GraphicsEnvironment.getLocalGraphicsEnvironment
        at java.awt.Window.<init>
        at java.awt.Frame.<init>
        at java.awt.Frame.<init>
        at javax.swing.JFrame.<init>

Em Headless Mode, aplicações podem realizar as seguintes operações:

  • Criar componentes genéricos como Canvas, Panel, Image e outros componentes leves Swing que não sejam top-level;
  • Obter informação sobre fontes disponíveis, suas métricas e configurações;
  • Definir cor para renderização de texto e gráficos;
  • Criar e manipular imagens, bem como prepará-las para renderização;
  • Imprimir usando as classes java.awt.PrintJob, java.awt.print.*, javax.print.*;
  • Emitir um bipe de áudio.

Já a tentativa de criação ou uso de componentes ou primitivas que requerem obrigatoriamente um ambiente gráfico, em Headless Mode gera a seguinte exceção: java.awt.HeadlessException. Neste caso, verifique se a operação desejada realmente pode ser executada no servidor (em modo não interativo), ou se há outra forma de fazer a operação que não necessite do modo gráfico.

Referências